Merge branch 'beta' into refactor/api-requests

This commit is contained in:
flx-sta 2024-10-04 16:53:40 -07:00
commit e620c68b56
421 changed files with 5903 additions and 5134 deletions

View File

@ -17,7 +17,12 @@ If you have the motivation and experience with Typescript/Javascript (or are wil
2. Run `npm run start:dev` to locally run the project in `localhost:8000` 2. Run `npm run start:dev` to locally run the project in `localhost:8000`
#### Linting #### Linting
We're using ESLint as our common linter and formatter. It will run automatically during the pre-commit hook but if you would like to manually run it, use the `npm run eslint` script. We're using ESLint as our common linter and formatter. It will run automatically during the pre-commit hook but if you would like to manually run it, use the `npm run eslint` script. To view the complete rules, check out the [eslint.config.js](./eslint.config.js) file.
### 📚 Documentation
You can find the auto-generated documentation [here](https://pagefaultgames.github.io/pokerogue/main/index.html).
For information on enemy AI, check out the [enemy-ai.md](./docs/enemy-ai.md) file.
For detailed guidelines on documenting your code, refer to the [comments.md](./docs/comments.md) file.
### ❔ FAQ ### ❔ FAQ

View File

@ -41,6 +41,11 @@ export default [
"keyword-spacing": ["error", { "before": true, "after": true }], // Enforces spacing before and after keywords "keyword-spacing": ["error", { "before": true, "after": true }], // Enforces spacing before and after keywords
"comma-spacing": ["error", { "before": false, "after": true }], // Enforces spacing after comma "comma-spacing": ["error", { "before": false, "after": true }], // Enforces spacing after comma
"import-x/extensions": ["error", "never", { "json": "always" }], // Enforces no extension for imports unless json "import-x/extensions": ["error", "never", { "json": "always" }], // Enforces no extension for imports unless json
"array-bracket-spacing": ["error", "always", { "objectsInArrays": false, "arraysInArrays": false }], // Enforces consistent spacing inside array brackets
"object-curly-spacing": ["error", "always", { "arraysInObjects": false, "objectsInObjects": false }], // Enforces consistent spacing inside braces of object literals, destructuring assignments, and import/export specifiers
"computed-property-spacing": ["error", "never" ], // Enforces consistent spacing inside computed property brackets
"space-infix-ops": ["error", { "int32Hint": false }], // Enforces spacing around infix operators
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF": 0 }], // Disallows multiple empty lines
} }
} }
] ]

1
package-lock.json generated
View File

@ -7,6 +7,7 @@
"": { "": {
"name": "pokemon-rogue-battle", "name": "pokemon-rogue-battle",
"version": "1.0.4", "version": "1.0.4",
"hasInstallScript": true,
"dependencies": { "dependencies": {
"@material/material-color-utilities": "^0.2.7", "@material/material-color-utilities": "^0.2.7",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",

View File

@ -853,14 +853,14 @@
"spriteSourceSize": { "x": 7, "y": 2, "w": 27, "h": 26 }, "spriteSourceSize": { "x": 7, "y": 2, "w": 27, "h": 26 },
"sourceSize": { "w": 40, "h": 30 } "sourceSize": { "w": 40, "h": 30 }
}, },
"981_2.png": { "981_2": {
"frame": { "x": 108, "y": 87, "w": 23, "h": 30 }, "frame": { "x": 108, "y": 87, "w": 23, "h": 30 },
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"spriteSourceSize": { "x": 9, "y": 0, "w": 23, "h": 30 }, "spriteSourceSize": { "x": 9, "y": 0, "w": 23, "h": 30 },
"sourceSize": { "w": 40, "h": 30 } "sourceSize": { "w": 40, "h": 30 }
}, },
"981_3.png": { "981_3": {
"frame": { "x": 246, "y": 86, "w": 23, "h": 30 }, "frame": { "x": 246, "y": 86, "w": 23, "h": 30 },
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,

View File

@ -14,7 +14,7 @@ export function initLoggedInUser(): void {
export function updateUserInfo(): Promise<[boolean, integer]> { export function updateUserInfo(): Promise<[boolean, integer]> {
return new Promise<[boolean, integer]>(resolve => { return new Promise<[boolean, integer]>(resolve => {
if (bypassLogin) { if (bypassLogin) {
loggedInUser = { username: "Guest", lastSessionSlot: -1, discordId: "", googleId: "", hasAdminRole: false}; loggedInUser = { username: "Guest", lastSessionSlot: -1, discordId: "", googleId: "", hasAdminRole: false };
let lastSessionSlot = -1; let lastSessionSlot = -1;
for (let s = 0; s < 5; s++) { for (let s = 0; s < 5; s++) {
if (localStorage.getItem(`sessionData${s ? s : ""}_${loggedInUser.username}`)) { if (localStorage.getItem(`sessionData${s ? s : ""}_${loggedInUser.username}`)) {
@ -37,7 +37,7 @@ export function updateUserInfo(): Promise<[boolean, integer]> {
}); });
return resolve([ true, 200 ]); return resolve([ true, 200 ]);
} }
pokerogueApi.account.getInfo().then(([accountInfo, status]) => { pokerogueApi.account.getInfo().then(([ accountInfo, status ]) => {
if (!accountInfo) { if (!accountInfo) {
resolve([ false, status ]); resolve([ false, status ]);
return; return;

View File

@ -1,57 +1,57 @@
import Phaser from "phaser"; import Phaser from "phaser";
import UI from "./ui/ui"; import UI from "#app/ui/ui";
import Pokemon, { EnemyPokemon, PlayerPokemon } from "./field/pokemon"; import Pokemon, { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon";
import PokemonSpecies, { allSpecies, getPokemonSpecies, PokemonSpeciesFilter } from "./data/pokemon-species"; import PokemonSpecies, { allSpecies, getPokemonSpecies, PokemonSpeciesFilter } from "#app/data/pokemon-species";
import { Constructor, isNullOrUndefined, randSeedInt } from "#app/utils"; import { Constructor, isNullOrUndefined, randSeedInt } from "#app/utils";
import * as Utils from "./utils"; import * as Utils from "#app/utils";
import { ConsumableModifier, ConsumablePokemonModifier, DoubleBattleChanceBoosterModifier, ExpBalanceModifier, ExpShareModifier, FusePokemonModifier, HealingBoosterModifier, Modifier, ModifierBar, ModifierPredicate, MultipleParticipantExpBonusModifier, overrideHeldItems, overrideModifiers, PersistentModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, TerastallizeModifier, TurnHeldItemTransferModifier } from "./modifier/modifier"; import { ConsumableModifier, ConsumablePokemonModifier, DoubleBattleChanceBoosterModifier, ExpBalanceModifier, ExpShareModifier, FusePokemonModifier, HealingBoosterModifier, Modifier, ModifierBar, ModifierPredicate, MultipleParticipantExpBonusModifier, overrideHeldItems, overrideModifiers, PersistentModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, TerastallizeModifier, TurnHeldItemTransferModifier } from "./modifier/modifier";
import { PokeballType } from "./data/pokeball"; import { PokeballType } from "#app/data/pokeball";
import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets, populateAnims } from "./data/battle-anims"; import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets, populateAnims } from "#app/data/battle-anims";
import { Phase } from "./phase"; import { Phase } from "#app/phase";
import { initGameSpeed } from "./system/game-speed"; import { initGameSpeed } from "#app/system/game-speed";
import { Arena, ArenaBase } from "./field/arena"; import { Arena, ArenaBase } from "#app/field/arena";
import { GameData } from "./system/game-data"; import { GameData } from "#app/system/game-data";
import { addTextObject, getTextColor, TextStyle } from "./ui/text"; import { addTextObject, getTextColor, TextStyle } from "#app/ui/text";
import { allMoves } from "./data/move"; import { allMoves } from "#app/data/move";
import { getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getLuckString, getLuckTextTint, getModifierPoolForType, getModifierType, getPartyLuckValue, ModifierPoolType, modifierTypes, PokemonHeldItemModifierType } from "./modifier/modifier-type"; import { getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getLuckString, getLuckTextTint, getModifierPoolForType, getModifierType, getPartyLuckValue, ModifierPoolType, modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
import AbilityBar from "./ui/ability-bar"; import AbilityBar from "#app/ui/ability-bar";
import { allAbilities, applyAbAttrs, applyPostBattleInitAbAttrs, BlockItemTheftAbAttr, ChangeMovePriorityAbAttr, DoubleBattleChanceAbAttr, PostBattleInitAbAttr } from "./data/ability"; import { allAbilities, applyAbAttrs, applyPostBattleInitAbAttrs, BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, PostBattleInitAbAttr } from "#app/data/ability";
import Battle, { BattleType, FixedBattleConfig } from "./battle"; import Battle, { BattleType, FixedBattleConfig } from "#app/battle";
import { GameMode, GameModes, getGameMode } from "./game-mode"; import { GameMode, GameModes, getGameMode } from "#app/game-mode";
import FieldSpritePipeline from "./pipelines/field-sprite"; import FieldSpritePipeline from "#app/pipelines/field-sprite";
import SpritePipeline from "./pipelines/sprite"; import SpritePipeline from "#app/pipelines/sprite";
import PartyExpBar from "./ui/party-exp-bar"; import PartyExpBar from "#app/ui/party-exp-bar";
import { trainerConfigs, TrainerSlot } from "./data/trainer-config"; import { trainerConfigs, TrainerSlot } from "#app/data/trainer-config";
import Trainer, { TrainerVariant } from "./field/trainer"; import Trainer, { TrainerVariant } from "#app/field/trainer";
import TrainerData from "./system/trainer-data"; import TrainerData from "#app/system/trainer-data";
import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
import { pokemonPrevolutions } from "./data/balance/pokemon-evolutions"; import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
import PokeballTray from "./ui/pokeball-tray"; import PokeballTray from "#app/ui/pokeball-tray";
import InvertPostFX from "./pipelines/invert"; import InvertPostFX from "#app/pipelines/invert";
import { Achv, achvs, ModifierAchv, MoneyAchv } from "./system/achv"; import { Achv, achvs, ModifierAchv, MoneyAchv } from "#app/system/achv";
import { Voucher, vouchers } from "./system/voucher"; import { Voucher, vouchers } from "#app/system/voucher";
import { Gender } from "./data/gender"; import { Gender } from "#app/data/gender";
import UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin"; import UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin";
import { addUiThemeOverrides } from "./ui/ui-theme"; import { addUiThemeOverrides } from "#app/ui/ui-theme";
import PokemonData from "./system/pokemon-data"; import PokemonData from "#app/system/pokemon-data";
import { Nature } from "./data/nature"; import { Nature } from "#app/data/nature";
import { FormChangeItem, pokemonFormChanges, SpeciesFormChange, SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger } from "./data/pokemon-forms"; import { FormChangeItem, pokemonFormChanges, SpeciesFormChange, SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger } from "#app/data/pokemon-forms";
import { FormChangePhase } from "./phases/form-change-phase"; import { FormChangePhase } from "#app/phases/form-change-phase";
import { getTypeRgb } from "./data/type"; import { getTypeRgb } from "#app/data/type";
import PokemonSpriteSparkleHandler from "./field/pokemon-sprite-sparkle-handler"; import PokemonSpriteSparkleHandler from "#app/field/pokemon-sprite-sparkle-handler";
import CharSprite from "./ui/char-sprite"; import CharSprite from "#app/ui/char-sprite";
import DamageNumberHandler from "./field/damage-number-handler"; import DamageNumberHandler from "#app/field/damage-number-handler";
import PokemonInfoContainer from "./ui/pokemon-info-container"; import PokemonInfoContainer from "#app/ui/pokemon-info-container";
import { biomeDepths, getBiomeName } from "./data/balance/biomes"; import { biomeDepths, getBiomeName } from "#app/data/balance/biomes";
import { SceneBase } from "./scene-base"; import { SceneBase } from "#app/scene-base";
import CandyBar from "./ui/candy-bar"; import CandyBar from "#app/ui/candy-bar";
import { Variant, variantData } from "./data/variant"; import { Variant, variantData } from "#app/data/variant";
import { Localizable } from "#app/interfaces/locales"; import { Localizable } from "#app/interfaces/locales";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import { InputsController } from "./inputs-controller"; import { InputsController } from "#app/inputs-controller";
import { UiInputs } from "./ui-inputs"; import { UiInputs } from "#app/ui-inputs";
import { NewArenaEvent } from "./events/battle-scene"; import { NewArenaEvent } from "#app/events/battle-scene";
import { ArenaFlyout } from "./ui/arena-flyout"; import { ArenaFlyout } from "#app/ui/arena-flyout";
import { EaseType } from "#enums/ease-type"; import { EaseType } from "#enums/ease-type";
import { BattleSpec } from "#enums/battle-spec"; import { BattleSpec } from "#enums/battle-spec";
import { BattleStyle } from "#enums/battle-style"; import { BattleStyle } from "#enums/battle-style";
@ -66,27 +66,27 @@ import { TimedEventManager } from "#app/timed-event-manager";
import { PokemonAnimType } from "#enums/pokemon-anim-type"; import { PokemonAnimType } from "#enums/pokemon-anim-type";
import i18next from "i18next"; import i18next from "i18next";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
import { battleSpecDialogue } from "./data/dialogue"; import { battleSpecDialogue } from "#app/data/dialogue";
import { LoadingScene } from "./loading-scene"; import { LoadingScene } from "#app/loading-scene";
import { LevelCapPhase } from "./phases/level-cap-phase"; import { LevelCapPhase } from "#app/phases/level-cap-phase";
import { LoginPhase } from "./phases/login-phase"; import { LoginPhase } from "#app/phases/login-phase";
import { MessagePhase } from "./phases/message-phase"; import { MessagePhase } from "#app/phases/message-phase";
import { MovePhase } from "./phases/move-phase"; import { MovePhase } from "#app/phases/move-phase";
import { NewBiomeEncounterPhase } from "./phases/new-biome-encounter-phase"; import { NewBiomeEncounterPhase } from "#app/phases/new-biome-encounter-phase";
import { NextEncounterPhase } from "./phases/next-encounter-phase"; import { NextEncounterPhase } from "#app/phases/next-encounter-phase";
import { PokemonAnimPhase } from "./phases/pokemon-anim-phase"; import { PokemonAnimPhase } from "#app/phases/pokemon-anim-phase";
import { QuietFormChangePhase } from "./phases/quiet-form-change-phase"; import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase";
import { ReturnPhase } from "./phases/return-phase"; import { ReturnPhase } from "#app/phases/return-phase";
import { SelectBiomePhase } from "./phases/select-biome-phase"; import { SelectBiomePhase } from "#app/phases/select-biome-phase";
import { ShowTrainerPhase } from "./phases/show-trainer-phase"; import { ShowTrainerPhase } from "#app/phases/show-trainer-phase";
import { SummonPhase } from "./phases/summon-phase"; import { SummonPhase } from "#app/phases/summon-phase";
import { SwitchPhase } from "./phases/switch-phase"; import { SwitchPhase } from "#app/phases/switch-phase";
import { TitlePhase } from "./phases/title-phase"; import { TitlePhase } from "#app/phases/title-phase";
import { ToggleDoublePositionPhase } from "./phases/toggle-double-position-phase"; import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase";
import { TurnInitPhase } from "./phases/turn-init-phase"; import { TurnInitPhase } from "#app/phases/turn-init-phase";
import { ShopCursorTarget } from "./enums/shop-cursor-target"; import { ShopCursorTarget } from "#app/enums/shop-cursor-target";
import MysteryEncounter from "./data/mystery-encounters/mystery-encounter"; import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
import { allMysteryEncounters, ANTI_VARIANCE_WEIGHT_MODIFIER, AVERAGE_ENCOUNTERS_PER_RUN_TARGET, BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT, MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT, mysteryEncountersByBiome, WEIGHT_INCREMENT_ON_SPAWN_MISS } from "./data/mystery-encounters/mystery-encounters"; import { allMysteryEncounters, ANTI_VARIANCE_WEIGHT_MODIFIER, AVERAGE_ENCOUNTERS_PER_RUN_TARGET, BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT, MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT, mysteryEncountersByBiome, WEIGHT_INCREMENT_ON_SPAWN_MISS } from "#app/data/mystery-encounters/mystery-encounters";
import { MysteryEncounterSaveData } from "#app/data/mystery-encounters/mystery-encounter-save-data"; import { MysteryEncounterSaveData } from "#app/data/mystery-encounters/mystery-encounter-save-data";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
@ -94,7 +94,7 @@ import HeldModifierConfig from "#app/interfaces/held-modifier-config";
import { ExpPhase } from "#app/phases/exp-phase"; import { ExpPhase } from "#app/phases/exp-phase";
import { ShowPartyExpBarPhase } from "#app/phases/show-party-exp-bar-phase"; import { ShowPartyExpBarPhase } from "#app/phases/show-party-exp-bar-phase";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import { ExpGainsSpeed } from "./enums/exp-gains-speed"; import { ExpGainsSpeed } from "#enums/exp-gains-speed";
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
@ -889,6 +889,9 @@ export default class BattleScene extends SceneBase {
} }
const pokemon = new EnemyPokemon(this, species, level, trainerSlot, boss, dataSource); const pokemon = new EnemyPokemon(this, species, level, trainerSlot, boss, dataSource);
if (Overrides.OPP_FUSION_OVERRIDE) {
pokemon.generateFusionSpecies();
}
overrideModifiers(this, false); overrideModifiers(this, false);
overrideHeldItems(this, pokemon, false); overrideHeldItems(this, pokemon, false);
@ -1261,7 +1264,7 @@ export default class BattleScene extends SceneBase {
const isEndlessFifthWave = this.gameMode.hasShortBiomes && (lastBattle.waveIndex % 5) === 0; const isEndlessFifthWave = this.gameMode.hasShortBiomes && (lastBattle.waveIndex % 5) === 0;
const isWaveIndexMultipleOfFiftyMinusOne = (lastBattle.waveIndex % 50) === 49; const isWaveIndexMultipleOfFiftyMinusOne = (lastBattle.waveIndex % 50) === 49;
const isNewBiome = isWaveIndexMultipleOfTen || isEndlessFifthWave || (isEndlessOrDaily && isWaveIndexMultipleOfFiftyMinusOne); const isNewBiome = isWaveIndexMultipleOfTen || isEndlessFifthWave || (isEndlessOrDaily && isWaveIndexMultipleOfFiftyMinusOne);
const resetArenaState = isNewBiome || [BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.currentBattle.battleType) || this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS; const resetArenaState = isNewBiome || [ BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER ].includes(this.currentBattle.battleType) || this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS;
this.getEnemyParty().forEach(enemyPokemon => enemyPokemon.destroy()); this.getEnemyParty().forEach(enemyPokemon => enemyPokemon.destroy());
this.trySpreadPokerus(); this.trySpreadPokerus();
if (!isNewBiome && (newWaveIndex % 10) === 5) { if (!isNewBiome && (newWaveIndex % 10) === 5) {
@ -1758,14 +1761,14 @@ export default class BattleScene extends SceneBase {
if (fromArenaPool) { if (fromArenaPool) {
return this.arena.randomSpecies(waveIndex, level, undefined, getPartyLuckValue(this.party)); return this.arena.randomSpecies(waveIndex, level, undefined, getPartyLuckValue(this.party));
} }
const filteredSpecies = speciesFilter ? [...new Set(allSpecies.filter(s => s.isCatchable()).filter(speciesFilter).map(s => { const filteredSpecies = speciesFilter ? [ ...new Set(allSpecies.filter(s => s.isCatchable()).filter(speciesFilter).map(s => {
if (!filterAllEvolutions) { if (!filterAllEvolutions) {
while (pokemonPrevolutions.hasOwnProperty(s.speciesId)) { while (pokemonPrevolutions.hasOwnProperty(s.speciesId)) {
s = getPokemonSpecies(pokemonPrevolutions[s.speciesId]); s = getPokemonSpecies(pokemonPrevolutions[s.speciesId]);
} }
} }
return s; return s;
}))] : allSpecies.filter(s => s.isCatchable()); })) ] : allSpecies.filter(s => s.isCatchable());
return filteredSpecies[Utils.randSeedInt(filteredSpecies.length)]; return filteredSpecies[Utils.randSeedInt(filteredSpecies.length)];
} }
@ -1885,14 +1888,14 @@ export default class BattleScene extends SceneBase {
case "battle_anims": case "battle_anims":
case "cry": case "cry":
if (soundDetails[1].startsWith("PRSFX- ")) { if (soundDetails[1].startsWith("PRSFX- ")) {
sound.setVolume(this.masterVolume*this.fieldVolume*0.5); sound.setVolume(this.masterVolume * this.fieldVolume * 0.5);
} else { } else {
sound.setVolume(this.masterVolume*this.fieldVolume); sound.setVolume(this.masterVolume * this.fieldVolume);
} }
break; break;
case "se": case "se":
case "ui": case "ui":
sound.setVolume(this.masterVolume*this.seVolume); sound.setVolume(this.masterVolume * this.seVolume);
} }
} }
} }
@ -2221,7 +2224,7 @@ export default class BattleScene extends SceneBase {
* *
*/ */
pushConditionalPhase(phase: Phase, condition: () => boolean): void { pushConditionalPhase(phase: Phase, condition: () => boolean): void {
this.conditionalQueue.push([condition, phase]); this.conditionalQueue.push([ condition, phase ]);
} }
/** /**
@ -2356,17 +2359,6 @@ export default class BattleScene extends SceneBase {
return false; return false;
} }
pushMovePhase(movePhase: MovePhase, priorityOverride?: integer): void {
const movePriority = new Utils.IntegerHolder(priorityOverride !== undefined ? priorityOverride : movePhase.move.getMove().priority);
applyAbAttrs(ChangeMovePriorityAbAttr, movePhase.pokemon, null, false, movePhase.move.getMove(), movePriority);
const lowerPriorityPhase = this.phaseQueue.find(p => p instanceof MovePhase && p.move.getMove().priority < movePriority.value);
if (lowerPriorityPhase) {
this.phaseQueue.splice(this.phaseQueue.indexOf(lowerPriorityPhase), 0, movePhase);
} else {
this.pushPhase(movePhase);
}
}
/** /**
* Tries to add the input phase to index before target phase in the phaseQueue, else simply calls unshiftPhase() * Tries to add the input phase to index before target phase in the phaseQueue, else simply calls unshiftPhase()
* @param phase {@linkcode Phase} the phase to be added * @param phase {@linkcode Phase} the phase to be added
@ -2498,7 +2490,7 @@ export default class BattleScene extends SceneBase {
} }
} }
return Promise.allSettled([this.party.map(p => p.updateInfo(instant)), ...modifierPromises]).then(() => resolve(success)); return Promise.allSettled([ this.party.map(p => p.updateInfo(instant)), ...modifierPromises ]).then(() => resolve(success));
} else { } else {
const args = [ this ]; const args = [ this ];
if (modifier.shouldApply(...args)) { if (modifier.shouldApply(...args)) {
@ -2818,7 +2810,7 @@ export default class BattleScene extends SceneBase {
return mods; return mods;
} }
const rand = Utils.randSeedInt(mods.length); const rand = Utils.randSeedInt(mods.length);
return [mods[rand], ...shuffleModifiers(mods.filter((_, i) => i !== rand))]; return [ mods[rand], ...shuffleModifiers(mods.filter((_, i) => i !== rand)) ];
}; };
modifiers = shuffleModifiers(modifiers); modifiers = shuffleModifiers(modifiers);
}, scene.currentBattle.turn << 4, scene.waveSeed); }, scene.currentBattle.turn << 4, scene.waveSeed);
@ -2978,7 +2970,7 @@ export default class BattleScene extends SceneBase {
keys.push(p.getBattleSpriteKey(true, true)); keys.push(p.getBattleSpriteKey(true, true));
keys.push("cry/" + p.species.getCryKey(p.formIndex)); keys.push("cry/" + p.species.getCryKey(p.formIndex));
if (p.fusionSpecies) { if (p.fusionSpecies) {
keys.push("cry/"+p.fusionSpecies.getCryKey(p.fusionFormIndex)); keys.push("cry/" + p.fusionSpecies.getCryKey(p.fusionFormIndex));
} }
}); });
// enemyParty has to be operated on separately from playerParty because playerPokemon =/= enemyPokemon // enemyParty has to be operated on separately from playerParty because playerPokemon =/= enemyPokemon
@ -2987,7 +2979,7 @@ export default class BattleScene extends SceneBase {
keys.push(p.getSpriteKey(true)); keys.push(p.getSpriteKey(true));
keys.push("cry/" + p.species.getCryKey(p.formIndex)); keys.push("cry/" + p.species.getCryKey(p.formIndex));
if (p.fusionSpecies) { if (p.fusionSpecies) {
keys.push("cry/"+p.fusionSpecies.getCryKey(p.fusionFormIndex)); keys.push("cry/" + p.fusionSpecies.getCryKey(p.fusionFormIndex));
} }
}); });
return keys; return keys;
@ -3135,7 +3127,7 @@ export default class BattleScene extends SceneBase {
* @param sessionDataEncounterType * @param sessionDataEncounterType
*/ */
private isWaveMysteryEncounter(newBattleType: BattleType, waveIndex: number, sessionDataEncounterType?: MysteryEncounterType): boolean { private isWaveMysteryEncounter(newBattleType: BattleType, waveIndex: number, sessionDataEncounterType?: MysteryEncounterType): boolean {
const [lowestMysteryEncounterWave, highestMysteryEncounterWave] = this.gameMode.getMysteryEncounterLegalWaves(); const [ lowestMysteryEncounterWave, highestMysteryEncounterWave ] = this.gameMode.getMysteryEncounterLegalWaves();
if (this.gameMode.hasMysteryEncounters && newBattleType === BattleType.WILD && !this.gameMode.isBoss(waveIndex) && waveIndex < highestMysteryEncounterWave && waveIndex > lowestMysteryEncounterWave) { if (this.gameMode.hasMysteryEncounters && newBattleType === BattleType.WILD && !this.gameMode.isBoss(waveIndex) && waveIndex < highestMysteryEncounterWave && waveIndex > lowestMysteryEncounterWave) {
// Base spawn weight is BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT/256, and increases by WEIGHT_INCREMENT_ON_SPAWN_MISS/256 for each missed attempt at spawning an encounter on a valid floor // Base spawn weight is BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT/256, and increases by WEIGHT_INCREMENT_ON_SPAWN_MISS/256 for each missed attempt at spawning an encounter on a valid floor
const sessionEncounterRate = this.mysteryEncounterSaveData.encounterSpawnChance; const sessionEncounterRate = this.mysteryEncounterSaveData.encounterSpawnChance;
@ -3201,7 +3193,7 @@ export default class BattleScene extends SceneBase {
} }
// See Enum values for base tier weights // See Enum values for base tier weights
const tierWeights = [MysteryEncounterTier.COMMON, MysteryEncounterTier.GREAT, MysteryEncounterTier.ULTRA, MysteryEncounterTier.ROGUE]; const tierWeights = [ MysteryEncounterTier.COMMON, MysteryEncounterTier.GREAT, MysteryEncounterTier.ULTRA, MysteryEncounterTier.ROGUE ];
// Adjust tier weights by previously encountered events to lower odds of only Common/Great in run // Adjust tier weights by previously encountered events to lower odds of only Common/Great in run
this.mysteryEncounterSaveData.encounteredEvents.forEach(seenEncounterData => { this.mysteryEncounterSaveData.encounteredEvents.forEach(seenEncounterData => {

View File

@ -497,7 +497,7 @@ function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], rand
} }
/* 1/3 chance for evil team grunts to be double battles */ /* 1/3 chance for evil team grunts to be double battles */
const evilTeamGrunts = [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]; const evilTeamGrunts = [ 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 ];
const isEvilTeamGrunt = evilTeamGrunts.includes(trainerTypes[rand]); const isEvilTeamGrunt = evilTeamGrunts.includes(trainerTypes[rand]);
if (trainerConfigs[trainerTypes[rand]].hasDouble && isEvilTeamGrunt) { if (trainerConfigs[trainerTypes[rand]].hasDouble && isEvilTeamGrunt) {
@ -527,34 +527,34 @@ export const classicFixedBattles: FixedBattleConfigs = {
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)), .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
[25]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [25]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_2, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_2, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.setCustomModifierRewards({ guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT], allowLuckUpgrades: false }), .setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], allowLuckUpgrades: false }),
[35]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [35]: 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)), .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)),
[55]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [55]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_3, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_3, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.setCustomModifierRewards({ guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT], allowLuckUpgrades: false }), .setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], allowLuckUpgrades: false }),
[62]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) [62]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.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)), .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)),
[64]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) [64]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.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)), .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)),
[66]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) [66]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.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.ROOD ], [ TrainerType.XEROSIC, TrainerType.BRYONY ], TrainerType.FABA, TrainerType.PLUMERIA, TrainerType.OLEANA, [ TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI ] ], true)), .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.ROOD ], [ TrainerType.XEROSIC, TrainerType.BRYONY ], TrainerType.FABA, TrainerType.PLUMERIA, TrainerType.OLEANA, [ TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI ]], true)),
[95]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [95]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_4, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_4, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.setCustomModifierRewards({ guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA], allowLuckUpgrades: false }), .setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false }),
[112]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) [112]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.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)), .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)),
[114]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) [114]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.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.ROOD ], [ TrainerType.XEROSIC, TrainerType.BRYONY ], TrainerType.FABA, TrainerType.PLUMERIA, TrainerType.OLEANA, [ TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI ] ], true, 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.ROOD ], [ 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(35) [ClassicFixedBossWaves.EVIL_BOSS_1]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.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 ])) .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 }), .setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false }),
[145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_5, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_5, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.setCustomModifierRewards({ guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA], allowLuckUpgrades: false }), .setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false }),
[ClassicFixedBossWaves.EVIL_BOSS_2]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) [ClassicFixedBossWaves.EVIL_BOSS_2]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.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 ])) .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 }), .setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA ], allowLuckUpgrades: false }),
[182]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [182]: 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 ])), .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 ])),
[184]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182) [184]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182)
@ -567,5 +567,5 @@ export const classicFixedBattles: FixedBattleConfigs = {
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.BLUE, [ TrainerType.RED, TrainerType.LANCE_CHAMPION ], [ TrainerType.STEVEN, TrainerType.WALLACE ], TrainerType.CYNTHIA, [ TrainerType.ALDER, TrainerType.IRIS ], TrainerType.DIANTHA, TrainerType.HAU, TrainerType.LEON, [ TrainerType.GEETA, TrainerType.NEMONA ], TrainerType.KIERAN ])), .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.BLUE, [ TrainerType.RED, TrainerType.LANCE_CHAMPION ], [ TrainerType.STEVEN, TrainerType.WALLACE ], TrainerType.CYNTHIA, [ TrainerType.ALDER, TrainerType.IRIS ], TrainerType.DIANTHA, TrainerType.HAU, TrainerType.LEON, [ TrainerType.GEETA, TrainerType.NEMONA ], TrainerType.KIERAN ])),
[195]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) [195]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_6, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_6, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT))
.setCustomModifierRewards({ guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT], allowLuckUpgrades: false }) .setCustomModifierRewards({ guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], allowLuckUpgrades: false })
}; };

View File

@ -1,5 +1,5 @@
import {Button} from "#enums/buttons"; import { Button } from "#enums/buttons";
import {SettingKeyboard} from "#app/system/settings/settings-keyboard"; import { SettingKeyboard } from "#app/system/settings/settings-keyboard";
const cfg_keyboard_qwerty = { const cfg_keyboard_qwerty = {
padID: "default", padID: "default",

View File

@ -1,4 +1,4 @@
import {Device} from "#enums/devices"; import { Device } from "#enums/devices";
/** /**
* Retrieves the key associated with the specified keycode from the mapping. * Retrieves the key associated with the specified keycode from the mapping.

View File

@ -1,5 +1,5 @@
import {SettingGamepad} from "../../system/settings/settings-gamepad"; import { SettingGamepad } from "../../system/settings/settings-gamepad";
import {Button} from "#enums/buttons"; import { Button } from "#enums/buttons";
/** /**
* Dualshock mapping * Dualshock mapping

View File

@ -1,5 +1,5 @@
import {SettingGamepad} from "../../system/settings/settings-gamepad"; import { SettingGamepad } from "../../system/settings/settings-gamepad";
import {Button} from "#enums/buttons"; import { Button } from "#enums/buttons";
/** /**
* Generic pad mapping * Generic pad mapping

View File

@ -1,5 +1,5 @@
import {SettingGamepad} from "#app/system/settings/settings-gamepad"; import { SettingGamepad } from "#app/system/settings/settings-gamepad";
import {Button} from "#enums/buttons"; import { Button } from "#enums/buttons";
/** /**
* Nintendo Pro Controller mapping * Nintendo Pro Controller mapping

View File

@ -1,5 +1,5 @@
import {SettingGamepad} from "../../system/settings/settings-gamepad"; import { SettingGamepad } from "../../system/settings/settings-gamepad";
import {Button} from "#enums/buttons"; import { Button } from "#enums/buttons";
/** /**
* 081f-e401 - UnlicensedSNES * 081f-e401 - UnlicensedSNES

View File

@ -1,5 +1,5 @@
import {SettingGamepad} from "../../system/settings/settings-gamepad"; import { SettingGamepad } from "../../system/settings/settings-gamepad";
import {Button} from "#enums/buttons"; import { Button } from "#enums/buttons";
/** /**
* Generic pad mapping * Generic pad mapping

View File

@ -162,7 +162,7 @@ export class BlockRecoilDamageAttr extends AbAttr {
} }
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]) { getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]) {
return i18next.t("abilityTriggers:blockRecoilDamage", {pokemonName: getPokemonNameWithAffix(pokemon), abilityName: abilityName}); return i18next.t("abilityTriggers:blockRecoilDamage", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName: abilityName });
} }
} }
@ -964,7 +964,7 @@ export class PostDefendPerishSongAbAttr extends PostDefendAbAttr {
} }
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
return i18next.t("abilityTriggers:perishBody", {pokemonName: getPokemonNameWithAffix(pokemon), abilityName: abilityName}); return i18next.t("abilityTriggers:perishBody", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName: abilityName });
} }
} }
@ -1268,7 +1268,7 @@ export class PokemonTypeChangeAbAttr extends PreAttackAbAttr {
if (pokemon.getTypes().some((t) => t !== moveType)) { if (pokemon.getTypes().some((t) => t !== moveType)) {
if (!simulated) { if (!simulated) {
this.moveType = moveType; this.moveType = moveType;
pokemon.summonData.types = [moveType]; pokemon.summonData.types = [ moveType ];
pokemon.updateInfo(); pokemon.updateInfo();
} }
@ -2814,7 +2814,7 @@ export class PreApplyBattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr {
constructor(immuneTagTypes: BattlerTagType | BattlerTagType[]) { constructor(immuneTagTypes: BattlerTagType | BattlerTagType[]) {
super(); super();
this.immuneTagTypes = Array.isArray(immuneTagTypes) ? immuneTagTypes : [immuneTagTypes]; this.immuneTagTypes = Array.isArray(immuneTagTypes) ? immuneTagTypes : [ immuneTagTypes ];
} }
applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean { applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean {
@ -3099,17 +3099,17 @@ function getAnticipationCondition(): AbAttrCondition {
// edge case for hidden power, type is computed // edge case for hidden power, type is computed
if (move.getMove().id === Moves.HIDDEN_POWER) { if (move.getMove().id === Moves.HIDDEN_POWER) {
const iv_val = Math.floor(((opponent.ivs[Stat.HP] & 1) const iv_val = Math.floor(((opponent.ivs[Stat.HP] & 1)
+(opponent.ivs[Stat.ATK] & 1) * 2 + (opponent.ivs[Stat.ATK] & 1) * 2
+(opponent.ivs[Stat.DEF] & 1) * 4 + (opponent.ivs[Stat.DEF] & 1) * 4
+(opponent.ivs[Stat.SPD] & 1) * 8 + (opponent.ivs[Stat.SPD] & 1) * 8
+(opponent.ivs[Stat.SPATK] & 1) * 16 + (opponent.ivs[Stat.SPATK] & 1) * 16
+(opponent.ivs[Stat.SPDEF] & 1) * 32) * 15/63); + (opponent.ivs[Stat.SPDEF] & 1) * 32) * 15 / 63);
const type = [ const type = [
Type.FIGHTING, Type.FLYING, Type.POISON, Type.GROUND, Type.FIGHTING, Type.FLYING, Type.POISON, Type.GROUND,
Type.ROCK, Type.BUG, Type.GHOST, Type.STEEL, Type.ROCK, Type.BUG, Type.GHOST, Type.STEEL,
Type.FIRE, Type.WATER, Type.GRASS, Type.ELECTRIC, Type.FIRE, Type.WATER, Type.GRASS, Type.ELECTRIC,
Type.PSYCHIC, Type.ICE, Type.DRAGON, Type.DARK][iv_val]; Type.PSYCHIC, Type.ICE, Type.DRAGON, Type.DARK ][iv_val];
if (pokemon.getAttackTypeEffectiveness(type, opponent) >= 2) { if (pokemon.getAttackTypeEffectiveness(type, opponent) >= 2) {
return true; return true;
@ -3644,7 +3644,7 @@ export class PostTurnHurtIfSleepingAbAttr extends PostTurnAbAttr {
if ((opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(Abilities.COMATOSE)) && !opp.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { if ((opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(Abilities.COMATOSE)) && !opp.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) {
if (!simulated) { if (!simulated) {
opp.damageAndUpdate(Utils.toDmgValue(opp.getMaxHp() / 8), HitResult.OTHER); opp.damageAndUpdate(Utils.toDmgValue(opp.getMaxHp() / 8), HitResult.OTHER);
pokemon.scene.queueMessage(i18next.t("abilityTriggers:badDreams", {pokemonName: getPokemonNameWithAffix(opp)})); pokemon.scene.queueMessage(i18next.t("abilityTriggers:badDreams", { pokemonName: getPokemonNameWithAffix(opp) }));
} }
hadEffect = true; hadEffect = true;
} }
@ -3755,8 +3755,8 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
*/ */
applyPostMoveUsed(dancer: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], simulated: boolean, args: any[]): boolean | Promise<boolean> { applyPostMoveUsed(dancer: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], simulated: boolean, args: any[]): boolean | Promise<boolean> {
// List of tags that prevent the Dancer from replicating the move // List of tags that prevent the Dancer from replicating the move
const forbiddenTags = [BattlerTagType.FLYING, BattlerTagType.UNDERWATER, const forbiddenTags = [ BattlerTagType.FLYING, BattlerTagType.UNDERWATER,
BattlerTagType.UNDERGROUND, BattlerTagType.HIDDEN]; BattlerTagType.UNDERGROUND, BattlerTagType.HIDDEN ];
// The move to replicate cannot come from the Dancer // The move to replicate cannot come from the Dancer
if (source.getBattlerIndex() !== dancer.getBattlerIndex() if (source.getBattlerIndex() !== dancer.getBattlerIndex()
&& !dancer.summonData.tags.some(tag => forbiddenTags.includes(tag.tagType))) { && !dancer.summonData.tags.some(tag => forbiddenTags.includes(tag.tagType))) {
@ -3767,7 +3767,7 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, target, move, true, true)); dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, target, move, true, true));
} else if (move.getMove() instanceof SelfStatusMove) { } else if (move.getMove() instanceof SelfStatusMove) {
// If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself // If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself
dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, [dancer.getBattlerIndex()], move, true, true)); dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, [ dancer.getBattlerIndex() ], move, true, true));
} }
} }
return true; return true;
@ -3784,9 +3784,9 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
*/ */
getTarget(dancer: Pokemon, source: Pokemon, targets: BattlerIndex[]) : BattlerIndex[] { getTarget(dancer: Pokemon, source: Pokemon, targets: BattlerIndex[]) : BattlerIndex[] {
if (dancer.isPlayer()) { if (dancer.isPlayer()) {
return source.isPlayer() ? targets : [source.getBattlerIndex()]; return source.isPlayer() ? targets : [ source.getBattlerIndex() ];
} }
return source.isPlayer() ? [source.getBattlerIndex()] : targets; return source.isPlayer() ? [ source.getBattlerIndex() ] : targets;
} }
} }
@ -4561,7 +4561,7 @@ export class BypassSpeedChanceAbAttr extends AbAttr {
const turnCommand = const turnCommand =
pokemon.scene.currentBattle.turnCommands[pokemon.getBattlerIndex()]; pokemon.scene.currentBattle.turnCommands[pokemon.getBattlerIndex()];
const isCommandFight = turnCommand?.command === Command.FIGHT; const isCommandFight = turnCommand?.command === Command.FIGHT;
const move = turnCommand?.move?.move ?allMoves[turnCommand.move.move] : null; const move = turnCommand?.move?.move ? allMoves[turnCommand.move.move] : null;
const isDamageMove = move?.category === MoveCategory.PHYSICAL || move?.category === MoveCategory.SPECIAL; const isDamageMove = move?.category === MoveCategory.PHYSICAL || move?.category === MoveCategory.SPECIAL;
if (isCommandFight && isDamageMove) { if (isCommandFight && isDamageMove) {
@ -4574,7 +4574,7 @@ export class BypassSpeedChanceAbAttr extends AbAttr {
} }
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
return i18next.t("abilityTriggers:quickDraw", {pokemonName: getPokemonNameWithAffix(pokemon)}); return i18next.t("abilityTriggers:quickDraw", { pokemonName: getPokemonNameWithAffix(pokemon) });
} }
} }
@ -4622,7 +4622,7 @@ async function applyAbAttrsInternal<TAttr extends AbAttr>(
simulated: boolean = false, simulated: boolean = false,
messages: string[] = [], messages: string[] = [],
) { ) {
for (const passive of [false, true]) { for (const passive of [ false, true ]) {
if (!pokemon?.canApplyAbility(passive)) { if (!pokemon?.canApplyAbility(passive)) {
continue; continue;
} }
@ -4872,7 +4872,7 @@ export function initAbilities() {
.attr(TypeImmunityHealAbAttr, Type.WATER) .attr(TypeImmunityHealAbAttr, Type.WATER)
.ignorable(), .ignorable(),
new Ability(Abilities.OBLIVIOUS, 3) new Ability(Abilities.OBLIVIOUS, 3)
.attr(BattlerTagImmunityAbAttr, [BattlerTagType.INFATUATED, BattlerTagType.TAUNT]) .attr(BattlerTagImmunityAbAttr, [ BattlerTagType.INFATUATED, BattlerTagType.TAUNT ])
.attr(IntimidateImmunityAbAttr) .attr(IntimidateImmunityAbAttr)
.ignorable(), .ignorable(),
new Ability(Abilities.CLOUD_NINE, 3) new Ability(Abilities.CLOUD_NINE, 3)
@ -5017,10 +5017,10 @@ export function initAbilities() {
new Ability(Abilities.CUTE_CHARM, 3) new Ability(Abilities.CUTE_CHARM, 3)
.attr(PostDefendContactApplyTagChanceAbAttr, 30, BattlerTagType.INFATUATED), .attr(PostDefendContactApplyTagChanceAbAttr, 30, BattlerTagType.INFATUATED),
new Ability(Abilities.PLUS, 3) new Ability(Abilities.PLUS, 3)
.conditionalAttr(p => p.scene.currentBattle.double && [Abilities.PLUS, Abilities.MINUS].some(a => p.getAlly().hasAbility(a)), StatMultiplierAbAttr, Stat.SPATK, 1.5) .conditionalAttr(p => p.scene.currentBattle.double && [ Abilities.PLUS, Abilities.MINUS ].some(a => p.getAlly().hasAbility(a)), StatMultiplierAbAttr, Stat.SPATK, 1.5)
.ignorable(), .ignorable(),
new Ability(Abilities.MINUS, 3) new Ability(Abilities.MINUS, 3)
.conditionalAttr(p => p.scene.currentBattle.double && [Abilities.PLUS, Abilities.MINUS].some(a => p.getAlly().hasAbility(a)), StatMultiplierAbAttr, Stat.SPATK, 1.5) .conditionalAttr(p => p.scene.currentBattle.double && [ Abilities.PLUS, Abilities.MINUS ].some(a => p.getAlly().hasAbility(a)), StatMultiplierAbAttr, Stat.SPATK, 1.5)
.ignorable(), .ignorable(),
new Ability(Abilities.FORECAST, 3) new Ability(Abilities.FORECAST, 3)
.attr(UncopiableAbilityAbAttr) .attr(UncopiableAbilityAbAttr)
@ -5138,7 +5138,7 @@ export function initAbilities() {
.conditionalAttr(pokemon => !!pokemon.status || pokemon.hasAbility(Abilities.COMATOSE), StatMultiplierAbAttr, Stat.SPD, 1.5), .conditionalAttr(pokemon => !!pokemon.status || pokemon.hasAbility(Abilities.COMATOSE), StatMultiplierAbAttr, Stat.SPD, 1.5),
new Ability(Abilities.NORMALIZE, 4) new Ability(Abilities.NORMALIZE, 4)
.attr(MoveTypeChangeAbAttr, Type.NORMAL, 1.2, (user, target, move) => { .attr(MoveTypeChangeAbAttr, Type.NORMAL, 1.2, (user, target, move) => {
return ![Moves.HIDDEN_POWER, Moves.WEATHER_BALL, Moves.NATURAL_GIFT, Moves.JUDGMENT, Moves.TECHNO_BLAST].includes(move.id); return ![ Moves.HIDDEN_POWER, Moves.WEATHER_BALL, Moves.NATURAL_GIFT, Moves.JUDGMENT, Moves.TECHNO_BLAST ].includes(move.id);
}), }),
new Ability(Abilities.SNIPER, 4) new Ability(Abilities.SNIPER, 4)
.attr(MultCritAbAttr, 1.5), .attr(MultCritAbAttr, 1.5),
@ -5184,7 +5184,7 @@ export function initAbilities() {
new Ability(Abilities.SLOW_START, 4) new Ability(Abilities.SLOW_START, 4)
.attr(PostSummonAddBattlerTagAbAttr, BattlerTagType.SLOW_START, 5), .attr(PostSummonAddBattlerTagAbAttr, BattlerTagType.SLOW_START, 5),
new Ability(Abilities.SCRAPPY, 4) new Ability(Abilities.SCRAPPY, 4)
.attr(IgnoreTypeImmunityAbAttr, Type.GHOST, [Type.NORMAL, Type.FIGHTING]) .attr(IgnoreTypeImmunityAbAttr, Type.GHOST, [ Type.NORMAL, Type.FIGHTING ])
.attr(IntimidateImmunityAbAttr), .attr(IntimidateImmunityAbAttr),
new Ability(Abilities.STORM_DRAIN, 4) new Ability(Abilities.STORM_DRAIN, 4)
.attr(RedirectTypeMoveAbAttr, Type.WATER) .attr(RedirectTypeMoveAbAttr, Type.WATER)
@ -5225,7 +5225,7 @@ export function initAbilities() {
.attr(PostDefendStealHeldItemAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT)) .attr(PostDefendStealHeldItemAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT))
.condition(getSheerForceHitDisableAbCondition()), .condition(getSheerForceHitDisableAbCondition()),
new Ability(Abilities.SHEER_FORCE, 5) new Ability(Abilities.SHEER_FORCE, 5)
.attr(MovePowerBoostAbAttr, (user, target, move) => move.chance >= 1, 5461/4096) .attr(MovePowerBoostAbAttr, (user, target, move) => move.chance >= 1, 5461 / 4096)
.attr(MoveEffectChanceMultiplierAbAttr, 0) .attr(MoveEffectChanceMultiplierAbAttr, 0)
.partial(), .partial(),
new Ability(Abilities.CONTRARY, 5) new Ability(Abilities.CONTRARY, 5)
@ -5234,7 +5234,7 @@ export function initAbilities() {
new Ability(Abilities.UNNERVE, 5) new Ability(Abilities.UNNERVE, 5)
.attr(PreventBerryUseAbAttr), .attr(PreventBerryUseAbAttr),
new Ability(Abilities.DEFIANT, 5) new Ability(Abilities.DEFIANT, 5)
.attr(PostStatStageChangeStatStageChangeAbAttr, (target, statsChanged, stages) => stages < 0, [Stat.ATK], 2), .attr(PostStatStageChangeStatStageChangeAbAttr, (target, statsChanged, stages) => stages < 0, [ Stat.ATK ], 2),
new Ability(Abilities.DEFEATIST, 5) new Ability(Abilities.DEFEATIST, 5)
.attr(StatMultiplierAbAttr, Stat.ATK, 0.5) .attr(StatMultiplierAbAttr, Stat.ATK, 0.5)
.attr(StatMultiplierAbAttr, Stat.SPATK, 0.5) .attr(StatMultiplierAbAttr, Stat.SPATK, 0.5)
@ -5320,7 +5320,7 @@ export function initAbilities() {
return move.category !== MoveCategory.STATUS return move.category !== MoveCategory.STATUS
&& (moveType === Type.DARK || moveType === Type.BUG || moveType === Type.GHOST); && (moveType === Type.DARK || moveType === Type.BUG || moveType === Type.GHOST);
}, Stat.SPD, 1) }, Stat.SPD, 1)
.attr(PostIntimidateStatStageChangeAbAttr, [Stat.SPD], 1), .attr(PostIntimidateStatStageChangeAbAttr, [ Stat.SPD ], 1),
new Ability(Abilities.MAGIC_BOUNCE, 5) new Ability(Abilities.MAGIC_BOUNCE, 5)
.ignorable() .ignorable()
.unimplemented(), .unimplemented(),
@ -5357,12 +5357,12 @@ export function initAbilities() {
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonTeravolt", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })) .attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonTeravolt", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }))
.attr(MoveAbilityBypassAbAttr), .attr(MoveAbilityBypassAbAttr),
new Ability(Abilities.AROMA_VEIL, 6) new Ability(Abilities.AROMA_VEIL, 6)
.attr(UserFieldBattlerTagImmunityAbAttr, [BattlerTagType.INFATUATED, BattlerTagType.TAUNT, BattlerTagType.DISABLED, BattlerTagType.TORMENT, BattlerTagType.HEAL_BLOCK]), .attr(UserFieldBattlerTagImmunityAbAttr, [ BattlerTagType.INFATUATED, BattlerTagType.TAUNT, BattlerTagType.DISABLED, BattlerTagType.TORMENT, BattlerTagType.HEAL_BLOCK ]),
new Ability(Abilities.FLOWER_VEIL, 6) new Ability(Abilities.FLOWER_VEIL, 6)
.ignorable() .ignorable()
.unimplemented(), .unimplemented(),
new Ability(Abilities.CHEEK_POUCH, 6) new Ability(Abilities.CHEEK_POUCH, 6)
.attr(HealFromBerryUseAbAttr, 1/3), .attr(HealFromBerryUseAbAttr, 1 / 3),
new Ability(Abilities.PROTEAN, 6) new Ability(Abilities.PROTEAN, 6)
.attr(PokemonTypeChangeAbAttr), .attr(PokemonTypeChangeAbAttr),
//.condition((p) => !p.summonData?.abilitiesApplied.includes(Abilities.PROTEAN)), //Gen 9 Implementation //.condition((p) => !p.summonData?.abilitiesApplied.includes(Abilities.PROTEAN)), //Gen 9 Implementation
@ -5375,7 +5375,7 @@ export function initAbilities() {
.attr(MoveImmunityAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.hasFlag(MoveFlags.BALLBOMB_MOVE)) .attr(MoveImmunityAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.hasFlag(MoveFlags.BALLBOMB_MOVE))
.ignorable(), .ignorable(),
new Ability(Abilities.COMPETITIVE, 6) new Ability(Abilities.COMPETITIVE, 6)
.attr(PostStatStageChangeStatStageChangeAbAttr, (target, statsChanged, stages) => stages < 0, [Stat.SPATK], 2), .attr(PostStatStageChangeStatStageChangeAbAttr, (target, statsChanged, stages) => stages < 0, [ Stat.SPATK ], 2),
new Ability(Abilities.STRONG_JAW, 6) new Ability(Abilities.STRONG_JAW, 6)
.attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.BITING_MOVE), 1.5), .attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.BITING_MOVE), 1.5),
new Ability(Abilities.REFRIGERATE, 6) new Ability(Abilities.REFRIGERATE, 6)
@ -5471,7 +5471,7 @@ export function initAbilities() {
new Ability(Abilities.STEELWORKER, 7) new Ability(Abilities.STEELWORKER, 7)
.attr(MoveTypePowerBoostAbAttr, Type.STEEL), .attr(MoveTypePowerBoostAbAttr, Type.STEEL),
new Ability(Abilities.BERSERK, 7) new Ability(Abilities.BERSERK, 7)
.attr(PostDefendHpGatedStatStageChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [Stat.SPATK], 1) .attr(PostDefendHpGatedStatStageChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [ Stat.SPATK ], 1)
.condition(getSheerForceHitDisableAbCondition()), .condition(getSheerForceHitDisableAbCondition()),
new Ability(Abilities.SLUSH_RUSH, 7) new Ability(Abilities.SLUSH_RUSH, 7)
.attr(StatMultiplierAbAttr, Stat.SPD, 2) .attr(StatMultiplierAbAttr, Stat.SPD, 2)
@ -5528,7 +5528,7 @@ export function initAbilities() {
.bypassFaint() .bypassFaint()
.partial(), .partial(),
new Ability(Abilities.CORROSION, 7) // TODO: Test Corrosion against Magic Bounce once it is implemented new Ability(Abilities.CORROSION, 7) // TODO: Test Corrosion against Magic Bounce once it is implemented
.attr(IgnoreTypeStatusEffectImmunityAbAttr, [StatusEffect.POISON, StatusEffect.TOXIC], [Type.STEEL, Type.POISON]) .attr(IgnoreTypeStatusEffectImmunityAbAttr, [ StatusEffect.POISON, StatusEffect.TOXIC ], [ Type.STEEL, Type.POISON ])
.partial(), .partial(),
new Ability(Abilities.COMATOSE, 7) new Ability(Abilities.COMATOSE, 7)
.attr(UncopiableAbilityAbAttr) .attr(UncopiableAbilityAbAttr)
@ -5545,7 +5545,7 @@ export function initAbilities() {
new Ability(Abilities.DANCER, 7) new Ability(Abilities.DANCER, 7)
.attr(PostDancingMoveAbAttr), .attr(PostDancingMoveAbAttr),
new Ability(Abilities.BATTERY, 7) new Ability(Abilities.BATTERY, 7)
.attr(AllyMoveCategoryPowerBoostAbAttr, [MoveCategory.SPECIAL], 1.3), .attr(AllyMoveCategoryPowerBoostAbAttr, [ MoveCategory.SPECIAL ], 1.3),
new Ability(Abilities.FLUFFY, 7) new Ability(Abilities.FLUFFY, 7)
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), 0.5) .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), 0.5)
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => user.getMoveType(move) === Type.FIRE, 2) .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => user.getMoveType(move) === Type.FIRE, 2)
@ -5671,11 +5671,11 @@ export function initAbilities() {
.bypassFaint() .bypassFaint()
.ignorable(), .ignorable(),
new Ability(Abilities.POWER_SPOT, 8) new Ability(Abilities.POWER_SPOT, 8)
.attr(AllyMoveCategoryPowerBoostAbAttr, [MoveCategory.SPECIAL, MoveCategory.PHYSICAL], 1.3), .attr(AllyMoveCategoryPowerBoostAbAttr, [ MoveCategory.SPECIAL, MoveCategory.PHYSICAL ], 1.3),
new Ability(Abilities.MIMICRY, 8) new Ability(Abilities.MIMICRY, 8)
.unimplemented(), .unimplemented(),
new Ability(Abilities.SCREEN_CLEANER, 8) new Ability(Abilities.SCREEN_CLEANER, 8)
.attr(PostSummonRemoveArenaTagAbAttr, [ArenaTagType.AURORA_VEIL, ArenaTagType.LIGHT_SCREEN, ArenaTagType.REFLECT]), .attr(PostSummonRemoveArenaTagAbAttr, [ ArenaTagType.AURORA_VEIL, ArenaTagType.LIGHT_SCREEN, ArenaTagType.REFLECT ]),
new Ability(Abilities.STEELY_SPIRIT, 8) new Ability(Abilities.STEELY_SPIRIT, 8)
.attr(UserFieldMoveTypePowerBoostAbAttr, Type.STEEL), .attr(UserFieldMoveTypePowerBoostAbAttr, Type.STEEL),
new Ability(Abilities.PERISH_BODY, 8) new Ability(Abilities.PERISH_BODY, 8)
@ -5758,7 +5758,7 @@ export function initAbilities() {
.attr(PostSummonStatStageChangeOnArenaAbAttr, ArenaTagType.TAILWIND) .attr(PostSummonStatStageChangeOnArenaAbAttr, ArenaTagType.TAILWIND)
.ignorable(), .ignorable(),
new Ability(Abilities.GUARD_DOG, 9) new Ability(Abilities.GUARD_DOG, 9)
.attr(PostIntimidateStatStageChangeAbAttr, [Stat.ATK], 1, true) .attr(PostIntimidateStatStageChangeAbAttr, [ Stat.ATK ], 1, true)
.attr(ForceSwitchOutImmunityAbAttr) .attr(ForceSwitchOutImmunityAbAttr)
.ignorable(), .ignorable(),
new Ability(Abilities.ROCKY_PAYLOAD, 9) new Ability(Abilities.ROCKY_PAYLOAD, 9)
@ -5847,7 +5847,7 @@ export function initAbilities() {
.attr(PreventBypassSpeedChanceAbAttr, (pokemon, move) => move.category === MoveCategory.STATUS) .attr(PreventBypassSpeedChanceAbAttr, (pokemon, move) => move.category === MoveCategory.STATUS)
.attr(MoveAbilityBypassAbAttr, (pokemon, move: Move) => move.category === MoveCategory.STATUS), .attr(MoveAbilityBypassAbAttr, (pokemon, move: Move) => move.category === MoveCategory.STATUS),
new Ability(Abilities.MINDS_EYE, 9) new Ability(Abilities.MINDS_EYE, 9)
.attr(IgnoreTypeImmunityAbAttr, Type.GHOST, [Type.NORMAL, Type.FIGHTING]) .attr(IgnoreTypeImmunityAbAttr, Type.GHOST, [ Type.NORMAL, Type.FIGHTING ])
.attr(ProtectStatAbAttr, Stat.ACC) .attr(ProtectStatAbAttr, Stat.ACC)
.attr(IgnoreOpponentStatStagesAbAttr, [ Stat.EVA ]) .attr(IgnoreOpponentStatStagesAbAttr, [ Stat.EVA ])
.ignorable(), .ignorable(),

View File

@ -19,6 +19,7 @@ import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase"; import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import { ShowAbilityPhase } from "#app/phases/show-ability-phase"; import { ShowAbilityPhase } from "#app/phases/show-ability-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { CommonAnimPhase } from "#app/phases/common-anim-phase";
export enum ArenaTagSide { export enum ArenaTagSide {
BOTH, BOTH,
@ -135,7 +136,7 @@ export class WeakenMoveScreenTag extends ArenaTag {
*/ */
apply(arena: Arena, args: any[]): boolean { apply(arena: Arena, args: any[]): boolean {
if (this.weakenedCategories.includes((args[0] as MoveCategory))) { if (this.weakenedCategories.includes((args[0] as MoveCategory))) {
(args[2] as Utils.NumberHolder).value = (args[1] as boolean) ? 2732/4096 : 0.5; (args[2] as Utils.NumberHolder).value = (args[1] as boolean) ? 2732 / 4096 : 0.5;
return true; return true;
} }
return false; return false;
@ -148,7 +149,7 @@ export class WeakenMoveScreenTag extends ArenaTag {
*/ */
class ReflectTag extends WeakenMoveScreenTag { class ReflectTag extends WeakenMoveScreenTag {
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) { constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
super(ArenaTagType.REFLECT, turnCount, Moves.REFLECT, sourceId, side, [MoveCategory.PHYSICAL]); super(ArenaTagType.REFLECT, turnCount, Moves.REFLECT, sourceId, side, [ MoveCategory.PHYSICAL ]);
} }
onAdd(arena: Arena, quiet: boolean = false): void { onAdd(arena: Arena, quiet: boolean = false): void {
@ -164,7 +165,7 @@ class ReflectTag extends WeakenMoveScreenTag {
*/ */
class LightScreenTag extends WeakenMoveScreenTag { class LightScreenTag extends WeakenMoveScreenTag {
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) { constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
super(ArenaTagType.LIGHT_SCREEN, turnCount, Moves.LIGHT_SCREEN, sourceId, side, [MoveCategory.SPECIAL]); super(ArenaTagType.LIGHT_SCREEN, turnCount, Moves.LIGHT_SCREEN, sourceId, side, [ MoveCategory.SPECIAL ]);
} }
onAdd(arena: Arena, quiet: boolean = false): void { onAdd(arena: Arena, quiet: boolean = false): void {
@ -180,7 +181,7 @@ class LightScreenTag extends WeakenMoveScreenTag {
*/ */
class AuroraVeilTag extends WeakenMoveScreenTag { class AuroraVeilTag extends WeakenMoveScreenTag {
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) { constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
super(ArenaTagType.AURORA_VEIL, turnCount, Moves.AURORA_VEIL, sourceId, side, [MoveCategory.SPECIAL, MoveCategory.PHYSICAL]); super(ArenaTagType.AURORA_VEIL, turnCount, Moves.AURORA_VEIL, sourceId, side, [ MoveCategory.SPECIAL, MoveCategory.PHYSICAL ]);
} }
onAdd(arena: Arena, quiet: boolean = false): void { onAdd(arena: Arena, quiet: boolean = false): void {
@ -512,15 +513,16 @@ class WaterSportTag extends WeakenMoveTypeTag {
} }
/** /**
* Arena Tag class for the secondary effect of {@link https://bulbapedia.bulbagarden.net/wiki/Plasma_Fists_(move) | Plasma Fists}. * Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Ion_Deluge_(move) | Ion Deluge}
* and the secondary effect of {@link https://bulbapedia.bulbagarden.net/wiki/Plasma_Fists_(move) | Plasma Fists}.
* Converts Normal-type moves to Electric type for the rest of the turn. * Converts Normal-type moves to Electric type for the rest of the turn.
*/ */
export class PlasmaFistsTag extends ArenaTag { export class IonDelugeTag extends ArenaTag {
constructor() { constructor(sourceMove?: Moves) {
super(ArenaTagType.PLASMA_FISTS, 1, Moves.PLASMA_FISTS); super(ArenaTagType.ION_DELUGE, 1, sourceMove);
} }
/** Queues Plasma Fists' on-add message */ /** Queues an on-add message */
onAdd(arena: Arena): void { onAdd(arena: Arena): void {
arena.scene.queueMessage(i18next.t("arenaTag:plasmaFistsOnAdd")); arena.scene.queueMessage(i18next.t("arenaTag:plasmaFistsOnAdd"));
} }
@ -988,7 +990,7 @@ class ImprisonTag extends ArenaTrapTag {
party?.forEach((p: PlayerPokemon | EnemyPokemon ) => { party?.forEach((p: PlayerPokemon | EnemyPokemon ) => {
p.addTag(BattlerTagType.IMPRISON, 1, Moves.IMPRISON, this.sourceId); p.addTag(BattlerTagType.IMPRISON, 1, Moves.IMPRISON, this.sourceId);
}); });
scene.queueMessage(i18next.t("battlerTags:imprisonOnAdd", {pokemonNameWithAffix: getPokemonNameWithAffix(this.source)})); scene.queueMessage(i18next.t("battlerTags:imprisonOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(this.source) }));
} }
} }
@ -1025,6 +1027,81 @@ class ImprisonTag extends ArenaTrapTag {
} }
} }
/**
* Arena Tag implementing the "sea of fire" effect from the combination
* of {@link https://bulbapedia.bulbagarden.net/wiki/Fire_Pledge_(move) | Fire Pledge}
* and {@link https://bulbapedia.bulbagarden.net/wiki/Grass_Pledge_(move) | Grass Pledge}.
* Damages all non-Fire-type Pokemon on the given side of the field at the end
* of each turn for 4 turns.
*/
class FireGrassPledgeTag extends ArenaTag {
constructor(sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.FIRE_GRASS_PLEDGE, 4, Moves.FIRE_PLEDGE, sourceId, side);
}
override onAdd(arena: Arena): void {
// "A sea of fire enveloped your/the opposing team!"
arena.scene.queueMessage(i18next.t(`arenaTag:fireGrassPledgeOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
}
override lapse(arena: Arena): boolean {
const field: Pokemon[] = (this.side === ArenaTagSide.PLAYER)
? arena.scene.getPlayerField()
: arena.scene.getEnemyField();
field.filter(pokemon => !pokemon.isOfType(Type.FIRE)).forEach(pokemon => {
// "{pokemonNameWithAffix} was hurt by the sea of fire!"
pokemon.scene.queueMessage(i18next.t("arenaTag:fireGrassPledgeLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
// TODO: Replace this with a proper animation
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.MAGMA_STORM));
pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / 8));
});
return super.lapse(arena);
}
}
/**
* Arena Tag implementing the "rainbow" effect from the combination
* of {@link https://bulbapedia.bulbagarden.net/wiki/Water_Pledge_(move) | Water Pledge}
* and {@link https://bulbapedia.bulbagarden.net/wiki/Fire_Pledge_(move) | Fire Pledge}.
* Doubles the secondary effect chance of moves from Pokemon on the
* given side of the field for 4 turns.
*/
class WaterFirePledgeTag extends ArenaTag {
constructor(sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.WATER_FIRE_PLEDGE, 4, Moves.WATER_PLEDGE, sourceId, side);
}
override onAdd(arena: Arena): void {
// "A rainbow appeared in the sky on your/the opposing team's side!"
arena.scene.queueMessage(i18next.t(`arenaTag:waterFirePledgeOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
}
override apply(arena: Arena, args: any[]): boolean {
const moveChance = args[0] as Utils.NumberHolder;
moveChance.value *= 2;
return true;
}
}
/**
* Arena Tag implementing the "swamp" effect from the combination
* of {@link https://bulbapedia.bulbagarden.net/wiki/Grass_Pledge_(move) | Grass Pledge}
* and {@link https://bulbapedia.bulbagarden.net/wiki/Water_Pledge_(move) | Water Pledge}.
* Quarters the Speed of Pokemon on the given side of the field for 4 turns.
*/
class GrassWaterPledgeTag extends ArenaTag {
constructor(sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.GRASS_WATER_PLEDGE, 4, Moves.GRASS_PLEDGE, sourceId, side);
}
override onAdd(arena: Arena): void {
// "A swamp enveloped your/the opposing team!"
arena.scene.queueMessage(i18next.t(`arenaTag:grassWaterPledgeOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
}
}
export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId: integer, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag | null { export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId: integer, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag | null {
switch (tagType) { switch (tagType) {
case ArenaTagType.MIST: case ArenaTagType.MIST:
@ -1043,8 +1120,8 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov
return new MudSportTag(turnCount, sourceId); return new MudSportTag(turnCount, sourceId);
case ArenaTagType.WATER_SPORT: case ArenaTagType.WATER_SPORT:
return new WaterSportTag(turnCount, sourceId); return new WaterSportTag(turnCount, sourceId);
case ArenaTagType.PLASMA_FISTS: case ArenaTagType.ION_DELUGE:
return new PlasmaFistsTag(); return new IonDelugeTag(sourceMove);
case ArenaTagType.SPIKES: case ArenaTagType.SPIKES:
return new SpikesTag(sourceId, side); return new SpikesTag(sourceId, side);
case ArenaTagType.TOXIC_SPIKES: case ArenaTagType.TOXIC_SPIKES:
@ -1076,6 +1153,12 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov
return new SafeguardTag(turnCount, sourceId, side); return new SafeguardTag(turnCount, sourceId, side);
case ArenaTagType.IMPRISON: case ArenaTagType.IMPRISON:
return new ImprisonTag(sourceId, side); return new ImprisonTag(sourceId, side);
case ArenaTagType.FIRE_GRASS_PLEDGE:
return new FireGrassPledgeTag(sourceId, side);
case ArenaTagType.WATER_FIRE_PLEDGE:
return new WaterFirePledgeTag(sourceId, side);
case ArenaTagType.GRASS_WATER_PLEDGE:
return new GrassWaterPledgeTag(sourceId, side);
default: default:
return null; return null;
} }

File diff suppressed because it is too large Load Diff

View File

@ -630,16 +630,16 @@ export const speciesStarterCosts = {
}; };
const starterCandyCosts: { passive: number; costReduction: [number, number]; egg: number; }[] = [ const starterCandyCosts: { passive: number; costReduction: [number, number]; egg: number; }[] = [
{ passive: 40, costReduction: [25, 60], egg: 30 }, // 1 Cost { passive: 40, costReduction: [ 25, 60 ], egg: 30 }, // 1 Cost
{ passive: 40, costReduction: [25, 60], egg: 30 }, // 2 Cost { passive: 40, costReduction: [ 25, 60 ], egg: 30 }, // 2 Cost
{ passive: 35, costReduction: [20, 50], egg: 25 }, // 3 Cost { passive: 35, costReduction: [ 20, 50 ], egg: 25 }, // 3 Cost
{ passive: 30, costReduction: [15, 40], egg: 20 }, // 4 Cost { passive: 30, costReduction: [ 15, 40 ], egg: 20 }, // 4 Cost
{ passive: 25, costReduction: [12, 35], egg: 18 }, // 5 Cost { passive: 25, costReduction: [ 12, 35 ], egg: 18 }, // 5 Cost
{ passive: 20, costReduction: [10, 30], egg: 15 }, // 6 Cost { passive: 20, costReduction: [ 10, 30 ], egg: 15 }, // 6 Cost
{ passive: 15, costReduction: [8, 20], egg: 12 }, // 7 Cost { passive: 15, costReduction: [ 8, 20 ], egg: 12 }, // 7 Cost
{ passive: 10, costReduction: [5, 15], egg: 10 }, // 8 Cost { passive: 10, costReduction: [ 5, 15 ], egg: 10 }, // 8 Cost
{ passive: 10, costReduction: [5, 15], egg: 10 }, // 9 Cost { passive: 10, costReduction: [ 5, 15 ], egg: 10 }, // 9 Cost
{ passive: 10, costReduction: [5, 15], egg: 10 }, // 10 Cost { passive: 10, costReduction: [ 5, 15 ], egg: 10 }, // 10 Cost
]; ];
/** /**

File diff suppressed because it is too large Load Diff

View File

@ -556,7 +556,7 @@ function logMissingMoveAnim(move: Moves, ...optionalParams: any[]) {
* @param encounterAnim one or more animations to fetch * @param encounterAnim one or more animations to fetch
*/ */
export async function initEncounterAnims(scene: BattleScene, encounterAnim: EncounterAnim | EncounterAnim[]): Promise<void> { export async function initEncounterAnims(scene: BattleScene, encounterAnim: EncounterAnim | EncounterAnim[]): Promise<void> {
const anims = Array.isArray(encounterAnim) ? encounterAnim : [encounterAnim]; const anims = Array.isArray(encounterAnim) ? encounterAnim : [ encounterAnim ];
const encounterAnimNames = Utils.getEnumKeys(EncounterAnim); const encounterAnimNames = Utils.getEnumKeys(EncounterAnim);
const encounterAnimFetches: Promise<Map<EncounterAnim, AnimConfig>>[] = []; const encounterAnimFetches: Promise<Map<EncounterAnim, AnimConfig>>[] = [];
for (const anim of anims) { for (const anim of anims) {
@ -774,9 +774,9 @@ export abstract class BattleAnim {
private getGraphicFrameData(scene: BattleScene, frames: AnimFrame[], onSubstitute?: boolean): Map<integer, Map<AnimFrameTarget, GraphicFrameData>> { private getGraphicFrameData(scene: BattleScene, frames: AnimFrame[], onSubstitute?: boolean): Map<integer, Map<AnimFrameTarget, GraphicFrameData>> {
const ret: Map<integer, Map<AnimFrameTarget, GraphicFrameData>> = new Map([ const ret: Map<integer, Map<AnimFrameTarget, GraphicFrameData>> = new Map([
[AnimFrameTarget.GRAPHIC, new Map<AnimFrameTarget, GraphicFrameData>() ], [ AnimFrameTarget.GRAPHIC, new Map<AnimFrameTarget, GraphicFrameData>() ],
[AnimFrameTarget.USER, new Map<AnimFrameTarget, GraphicFrameData>() ], [ AnimFrameTarget.USER, new Map<AnimFrameTarget, GraphicFrameData>() ],
[AnimFrameTarget.TARGET, new Map<AnimFrameTarget, GraphicFrameData>() ] [ AnimFrameTarget.TARGET, new Map<AnimFrameTarget, GraphicFrameData>() ]
]); ]);
const isOppAnim = this.isOppAnim(); const isOppAnim = this.isOppAnim();
@ -1093,9 +1093,9 @@ export abstract class BattleAnim {
private getGraphicFrameDataWithoutTarget(frames: AnimFrame[], targetInitialX: number, targetInitialY: number): Map<integer, Map<AnimFrameTarget, GraphicFrameData>> { private getGraphicFrameDataWithoutTarget(frames: AnimFrame[], targetInitialX: number, targetInitialY: number): Map<integer, Map<AnimFrameTarget, GraphicFrameData>> {
const ret: Map<integer, Map<AnimFrameTarget, GraphicFrameData>> = new Map([ const ret: Map<integer, Map<AnimFrameTarget, GraphicFrameData>> = new Map([
[AnimFrameTarget.GRAPHIC, new Map<AnimFrameTarget, GraphicFrameData>() ], [ AnimFrameTarget.GRAPHIC, new Map<AnimFrameTarget, GraphicFrameData>() ],
[AnimFrameTarget.USER, new Map<AnimFrameTarget, GraphicFrameData>() ], [ AnimFrameTarget.USER, new Map<AnimFrameTarget, GraphicFrameData>() ],
[AnimFrameTarget.TARGET, new Map<AnimFrameTarget, GraphicFrameData>() ] [ AnimFrameTarget.TARGET, new Map<AnimFrameTarget, GraphicFrameData>() ]
]); ]);
let g = 0; let g = 0;

View File

@ -363,7 +363,7 @@ export class RechargingTag extends BattlerTag {
super.onAdd(pokemon); super.onAdd(pokemon);
// Queue a placeholder move for the Pokemon to "use" next turn // Queue a placeholder move for the Pokemon to "use" next turn
pokemon.getMoveQueue().push({ move: Moves.NONE, targets: [] }); pokemon.getMoveQueue().push({ move: Moves.NONE, targets: []});
} }
/** Cancels the source's move this turn and queues a "__ must recharge!" message */ /** Cancels the source's move this turn and queues a "__ must recharge!" message */
@ -569,7 +569,7 @@ export class InterruptedTag extends BattlerTag {
super.onAdd(pokemon); super.onAdd(pokemon);
pokemon.getMoveQueue().shift(); pokemon.getMoveQueue().shift();
pokemon.pushMoveHistory({move: Moves.NONE, result: MoveResult.OTHER}); pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.OTHER });
} }
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
@ -1935,10 +1935,10 @@ export class RoostedTag extends BattlerTag {
modifiedTypes = currentTypes.filter(type => type !== Type.NORMAL); modifiedTypes = currentTypes.filter(type => type !== Type.NORMAL);
modifiedTypes.push(Type.FLYING); modifiedTypes.push(Type.FLYING);
} else { } else {
modifiedTypes = [Type.FLYING]; modifiedTypes = [ Type.FLYING ];
} }
} else { } else {
modifiedTypes = [...currentTypes]; modifiedTypes = [ ...currentTypes ];
modifiedTypes.push(Type.FLYING); modifiedTypes.push(Type.FLYING);
} }
pokemon.summonData.types = modifiedTypes; pokemon.summonData.types = modifiedTypes;
@ -1958,10 +1958,10 @@ export class RoostedTag extends BattlerTag {
if (this.isBaseFlying) { if (this.isBaseFlying) {
let modifiedTypes: Type[]; let modifiedTypes: Type[];
if (this.isBasePureFlying && !isCurrentlyDualType) { if (this.isBasePureFlying && !isCurrentlyDualType) {
modifiedTypes = [Type.NORMAL]; modifiedTypes = [ Type.NORMAL ];
} else { } else {
if (!!pokemon.getTag(RemovedTypeTag) && isOriginallyDualType && !isCurrentlyDualType) { if (!!pokemon.getTag(RemovedTypeTag) && isOriginallyDualType && !isCurrentlyDualType) {
modifiedTypes = [Type.UNKNOWN]; modifiedTypes = [ Type.UNKNOWN ];
} else { } else {
modifiedTypes = currentTypes.filter(type => type !== Type.FLYING); modifiedTypes = currentTypes.filter(type => type !== Type.FLYING);
} }
@ -2067,8 +2067,8 @@ export class StockpilingTag extends BattlerTag {
super.loadTag(source); super.loadTag(source);
this.stockpiledCount = source.stockpiledCount || 0; this.stockpiledCount = source.stockpiledCount || 0;
this.statChangeCounts = { this.statChangeCounts = {
[ Stat.DEF ]: source.statChangeCounts?.[ Stat.DEF ] ?? 0, [Stat.DEF]: source.statChangeCounts?.[Stat.DEF] ?? 0,
[ Stat.SPDEF ]: source.statChangeCounts?.[ Stat.SPDEF ] ?? 0, [Stat.SPDEF]: source.statChangeCounts?.[Stat.SPDEF] ?? 0,
}; };
} }
@ -2090,7 +2090,7 @@ export class StockpilingTag extends BattlerTag {
// Attempt to increase DEF and SPDEF by one stage, keeping track of successful changes. // Attempt to increase DEF and SPDEF by one stage, keeping track of successful changes.
pokemon.scene.unshiftPhase(new StatStageChangePhase( pokemon.scene.unshiftPhase(new StatStageChangePhase(
pokemon.scene, pokemon.getBattlerIndex(), true, pokemon.scene, pokemon.getBattlerIndex(), true,
[Stat.SPDEF, Stat.DEF], 1, true, false, true, this.onStatStagesChanged [ Stat.SPDEF, Stat.DEF ], 1, true, false, true, this.onStatStagesChanged
)); ));
} }
} }
@ -2267,7 +2267,7 @@ export class HealBlockTag extends MoveRestrictionBattlerTag {
* Uses DisabledTag's selectionDeniedText() message * Uses DisabledTag's selectionDeniedText() message
*/ */
override selectionDeniedText(pokemon: Pokemon, move: Moves): string { override selectionDeniedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:moveDisabled", { moveName: allMoves[move].name }); return i18next.t("battle:moveDisabledHealBlock", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name, healBlockName: allMoves[Moves.HEAL_BLOCK].name });
} }
/** /**
@ -2277,7 +2277,7 @@ export class HealBlockTag extends MoveRestrictionBattlerTag {
* @returns {string} text to display when the move is interrupted * @returns {string} text to display when the move is interrupted
*/ */
override interruptedText(pokemon: Pokemon, move: Moves): string { override interruptedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:disableInterruptedMove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name }); return i18next.t("battle:moveDisabledHealBlock", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name, healBlockName: allMoves[Moves.HEAL_BLOCK].name });
} }
override onRemove(pokemon: Pokemon): void { override onRemove(pokemon: Pokemon): void {
@ -2310,6 +2310,21 @@ export class TarShotTag extends BattlerTag {
} }
} }
/**
* Battler Tag implementing the type-changing effect of {@link https://bulbapedia.bulbagarden.net/wiki/Electrify_(move) | Electrify}.
* While this tag is in effect, the afflicted Pokemon's moves are changed to Electric type.
*/
export class ElectrifiedTag extends BattlerTag {
constructor() {
super(BattlerTagType.ELECTRIFIED, BattlerTagLapseType.TURN_END, 1, Moves.ELECTRIFY);
}
override onAdd(pokemon: Pokemon): void {
// "{pokemonNameWithAffix}'s moves have been electrified!"
pokemon.scene.queueMessage(i18next.t("battlerTags:electrifiedOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
}
/** /**
* Battler Tag that keeps track of how many times the user has Autotomized * Battler Tag that keeps track of how many times the user has Autotomized
* Each count of Autotomization reduces the weight by 100kg * Each count of Autotomization reduces the weight by 100kg
@ -2354,7 +2369,7 @@ export class SubstituteTag extends BattlerTag {
public sourceInFocus: boolean; public sourceInFocus: boolean;
constructor(sourceMove: Moves, sourceId: integer) { constructor(sourceMove: Moves, sourceId: integer) {
super(BattlerTagType.SUBSTITUTE, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE, BattlerTagLapseType.HIT], 0, sourceMove, sourceId, true); super(BattlerTagType.SUBSTITUTE, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE, BattlerTagLapseType.HIT ], 0, sourceMove, sourceId, true);
} }
/** Sets the Substitute's HP and queues an on-add battle animation that initializes the Substitute's sprite. */ /** Sets the Substitute's HP and queues an on-add battle animation that initializes the Substitute's sprite. */
@ -2378,7 +2393,7 @@ export class SubstituteTag extends BattlerTag {
onRemove(pokemon: Pokemon): void { onRemove(pokemon: Pokemon): void {
// Only play the animation if the cause of removal isn't from the source's own move // Only play the animation if the cause of removal isn't from the source's own move
if (!this.sourceInFocus) { if (!this.sourceInFocus) {
pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.SUBSTITUTE_REMOVE, [this.sprite]); pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.SUBSTITUTE_REMOVE, [ this.sprite ]);
} else { } else {
this.sprite.destroy(); this.sprite.destroy();
} }
@ -2402,13 +2417,13 @@ export class SubstituteTag extends BattlerTag {
/** Triggers an animation that brings the Pokemon into focus before it uses a move */ /** Triggers an animation that brings the Pokemon into focus before it uses a move */
onPreMove(pokemon: Pokemon): void { onPreMove(pokemon: Pokemon): void {
pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.SUBSTITUTE_PRE_MOVE, [this.sprite]); pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.SUBSTITUTE_PRE_MOVE, [ this.sprite ]);
this.sourceInFocus = true; this.sourceInFocus = true;
} }
/** Triggers an animation that brings the Pokemon out of focus after it uses a move */ /** Triggers an animation that brings the Pokemon out of focus after it uses a move */
onAfterMove(pokemon: Pokemon): void { onAfterMove(pokemon: Pokemon): void {
pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.SUBSTITUTE_POST_MOVE, [this.sprite]); pokemon.scene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.SUBSTITUTE_POST_MOVE, [ this.sprite ]);
this.sourceInFocus = false; this.sourceInFocus = false;
} }
@ -2530,8 +2545,8 @@ export class TormentTag extends MoveRestrictionBattlerTag {
return false; return false;
} }
override selectionDeniedText(_pokemon: Pokemon, move: Moves): string { override selectionDeniedText(pokemon: Pokemon, _move: Moves): string {
return i18next.t("battle:moveCannotBeSelected", { moveName: allMoves[move].name }); return i18next.t("battle:moveDisabledTorment", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
} }
} }
@ -2542,7 +2557,7 @@ export class TormentTag extends MoveRestrictionBattlerTag {
*/ */
export class TauntTag extends MoveRestrictionBattlerTag { export class TauntTag extends MoveRestrictionBattlerTag {
constructor() { constructor() {
super(BattlerTagType.TAUNT, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE], 4, Moves.TAUNT); super(BattlerTagType.TAUNT, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE ], 4, Moves.TAUNT);
} }
override onAdd(pokemon: Pokemon) { override onAdd(pokemon: Pokemon) {
@ -2559,12 +2574,12 @@ export class TauntTag extends MoveRestrictionBattlerTag {
return allMoves[move].category === MoveCategory.STATUS; return allMoves[move].category === MoveCategory.STATUS;
} }
override selectionDeniedText(_pokemon: Pokemon, move: Moves): string { override selectionDeniedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:moveCannotBeSelected", { moveName: allMoves[move].name }); return i18next.t("battle:moveDisabledTaunt", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name });
} }
override interruptedText(pokemon: Pokemon, move: Moves): string { override interruptedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:disableInterruptedMove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name }); return i18next.t("battle:moveDisabledTaunt", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name });
} }
} }
@ -2577,7 +2592,7 @@ export class ImprisonTag extends MoveRestrictionBattlerTag {
private source: Pokemon | null; private source: Pokemon | null;
constructor(sourceId: number) { constructor(sourceId: number) {
super(BattlerTagType.IMPRISON, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE], 1, Moves.IMPRISON, sourceId); super(BattlerTagType.IMPRISON, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE ], 1, Moves.IMPRISON, sourceId);
} }
override onAdd(pokemon: Pokemon) { override onAdd(pokemon: Pokemon) {
@ -2609,12 +2624,12 @@ export class ImprisonTag extends MoveRestrictionBattlerTag {
return false; return false;
} }
override selectionDeniedText(_pokemon: Pokemon, move: Moves): string { override selectionDeniedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:moveCannotBeSelected", { moveName: allMoves[move].name }); return i18next.t("battle:moveDisabledImprison", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name });
} }
override interruptedText(pokemon: Pokemon, move: Moves): string { override interruptedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:disableInterruptedMove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name }); return i18next.t("battle:moveDisabledImprison", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name });
} }
} }
@ -2650,7 +2665,7 @@ export class SyrupBombTag extends BattlerTag {
pokemon.scene.queueMessage(i18next.t("battlerTags:syrupBombLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); // Custom message in lieu of an animation in mainline pokemon.scene.queueMessage(i18next.t("battlerTags:syrupBombLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); // Custom message in lieu of an animation in mainline
pokemon.scene.unshiftPhase(new StatStageChangePhase( pokemon.scene.unshiftPhase(new StatStageChangePhase(
pokemon.scene, pokemon.getBattlerIndex(), true, pokemon.scene, pokemon.getBattlerIndex(), true,
[Stat.SPD], -1, true, false, true [ Stat.SPD ], -1, true, false, true
)); ));
return --this.turnCount > 0; return --this.turnCount > 0;
} }
@ -2803,14 +2818,16 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
case BattlerTagType.DISABLED: case BattlerTagType.DISABLED:
return new DisabledTag(sourceId); return new DisabledTag(sourceId);
case BattlerTagType.IGNORE_GHOST: case BattlerTagType.IGNORE_GHOST:
return new ExposedTag(tagType, sourceMove, Type.GHOST, [Type.NORMAL, Type.FIGHTING]); return new ExposedTag(tagType, sourceMove, Type.GHOST, [ Type.NORMAL, Type.FIGHTING ]);
case BattlerTagType.IGNORE_DARK: case BattlerTagType.IGNORE_DARK:
return new ExposedTag(tagType, sourceMove, Type.DARK, [Type.PSYCHIC]); return new ExposedTag(tagType, sourceMove, Type.DARK, [ Type.PSYCHIC ]);
case BattlerTagType.GULP_MISSILE_ARROKUDA: case BattlerTagType.GULP_MISSILE_ARROKUDA:
case BattlerTagType.GULP_MISSILE_PIKACHU: case BattlerTagType.GULP_MISSILE_PIKACHU:
return new GulpMissileTag(tagType, sourceMove); return new GulpMissileTag(tagType, sourceMove);
case BattlerTagType.TAR_SHOT: case BattlerTagType.TAR_SHOT:
return new TarShotTag(); return new TarShotTag();
case BattlerTagType.ELECTRIFIED:
return new ElectrifiedTag();
case BattlerTagType.THROAT_CHOPPED: case BattlerTagType.THROAT_CHOPPED:
return new ThroatChoppedTag(); return new ThroatChoppedTag();
case BattlerTagType.GORILLA_TACTICS: case BattlerTagType.GORILLA_TACTICS:

View File

@ -185,7 +185,7 @@ export abstract class Challenge {
*/ */
getDescription(overrideValue?: number): string { getDescription(overrideValue?: number): string {
const value = overrideValue ?? this.value; const value = overrideValue ?? this.value;
return `${i18next.t([`challenges:${this.geti18nKey()}.desc.${value}`, `challenges:${this.geti18nKey()}.desc`])}`; return `${i18next.t([ `challenges:${this.geti18nKey()}.desc.${value}`, `challenges:${this.geti18nKey()}.desc` ])}`;
} }
/** /**
@ -414,9 +414,9 @@ export class SingleGenerationChallenge extends Challenge {
} }
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean { applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean {
const generations = [pokemon.generation]; const generations = [ pokemon.generation ];
if (soft) { if (soft) {
const speciesToCheck = [pokemon.speciesId]; const speciesToCheck = [ pokemon.speciesId ];
while (speciesToCheck.length) { while (speciesToCheck.length) {
const checking = speciesToCheck.pop(); const checking = speciesToCheck.pop();
if (checking && pokemonEvolutions.hasOwnProperty(checking)) { if (checking && pokemonEvolutions.hasOwnProperty(checking)) {
@ -455,7 +455,7 @@ export class SingleGenerationChallenge extends Challenge {
trainerTypes = [ TrainerType.BRUNO, TrainerType.KOGA, TrainerType.PHOEBE, TrainerType.BERTHA, TrainerType.MARSHAL, TrainerType.SIEBOLD, TrainerType.OLIVIA, TrainerType.NESSA_ELITE, TrainerType.POPPY ]; trainerTypes = [ TrainerType.BRUNO, TrainerType.KOGA, TrainerType.PHOEBE, TrainerType.BERTHA, TrainerType.MARSHAL, TrainerType.SIEBOLD, TrainerType.OLIVIA, TrainerType.NESSA_ELITE, TrainerType.POPPY ];
break; break;
case 186: case 186:
trainerTypes = [ TrainerType.AGATHA, TrainerType.BRUNO, TrainerType.GLACIA, TrainerType.FLINT, TrainerType.GRIMSLEY, TrainerType.WIKSTROM, TrainerType.ACEROLA, Utils.randSeedItem([TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE]), TrainerType.LARRY_ELITE ]; trainerTypes = [ TrainerType.AGATHA, TrainerType.BRUNO, TrainerType.GLACIA, TrainerType.FLINT, TrainerType.GRIMSLEY, TrainerType.WIKSTROM, TrainerType.ACEROLA, Utils.randSeedItem([ TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE ]), TrainerType.LARRY_ELITE ];
break; break;
case 188: case 188:
trainerTypes = [ TrainerType.LANCE, TrainerType.KAREN, TrainerType.DRAKE, TrainerType.LUCIAN, TrainerType.CAITLIN, TrainerType.DRASNA, TrainerType.KAHILI, TrainerType.RAIHAN_ELITE, TrainerType.HASSEL ]; trainerTypes = [ TrainerType.LANCE, TrainerType.KAREN, TrainerType.DRAKE, TrainerType.LUCIAN, TrainerType.CAITLIN, TrainerType.DRASNA, TrainerType.KAHILI, TrainerType.RAIHAN_ELITE, TrainerType.HASSEL ];
@ -528,10 +528,10 @@ interface monotypeOverride {
*/ */
export class SingleTypeChallenge extends Challenge { export class SingleTypeChallenge extends Challenge {
private static TYPE_OVERRIDES: monotypeOverride[] = [ private static TYPE_OVERRIDES: monotypeOverride[] = [
{species: Species.CASTFORM, type: Type.NORMAL, fusion: false}, { species: Species.CASTFORM, type: Type.NORMAL, fusion: false },
]; ];
// TODO: Find a solution for all Pokemon with this ssui issue, including Basculin and Burmy // TODO: Find a solution for all Pokemon with this ssui issue, including Basculin and Burmy
private static SPECIES_OVERRIDES: Species[] = [Species.MELOETTA]; private static SPECIES_OVERRIDES: Species[] = [ Species.MELOETTA ];
constructor() { constructor() {
super(Challenges.SINGLE_TYPE, 18); super(Challenges.SINGLE_TYPE, 18);
@ -539,9 +539,9 @@ export class SingleTypeChallenge extends Challenge {
override applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean { override applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean {
const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex); const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex);
const types = [speciesForm.type1, speciesForm.type2]; const types = [ speciesForm.type1, speciesForm.type2 ];
if (soft && !SingleTypeChallenge.SPECIES_OVERRIDES.includes(pokemon.speciesId)) { if (soft && !SingleTypeChallenge.SPECIES_OVERRIDES.includes(pokemon.speciesId)) {
const speciesToCheck = [pokemon.speciesId]; const speciesToCheck = [ pokemon.speciesId ];
while (speciesToCheck.length) { while (speciesToCheck.length) {
const checking = speciesToCheck.pop(); const checking = speciesToCheck.pop();
if (checking && pokemonEvolutions.hasOwnProperty(checking)) { if (checking && pokemonEvolutions.hasOwnProperty(checking)) {
@ -606,9 +606,9 @@ export class SingleTypeChallenge extends Challenge {
overrideValue = this.value; overrideValue = this.value;
} }
const type = i18next.t(`pokemonInfo:Type.${Type[this.value - 1]}`); const type = i18next.t(`pokemonInfo:Type.${Type[this.value - 1]}`);
const typeColor = `[color=${TypeColor[Type[this.value-1]]}][shadow=${TypeShadow[Type[this.value-1]]}]${type}[/shadow][/color]`; const typeColor = `[color=${TypeColor[Type[this.value - 1]]}][shadow=${TypeShadow[Type[this.value - 1]]}]${type}[/shadow][/color]`;
const defaultDesc = i18next.t("challenges:singleType.desc_default"); const defaultDesc = i18next.t("challenges:singleType.desc_default");
const typeDesc = i18next.t("challenges:singleType.desc", {type: typeColor}); const typeDesc = i18next.t("challenges:singleType.desc", { type: typeColor });
return this.value === 0 ? defaultDesc : typeDesc; return this.value === 0 ? defaultDesc : typeDesc;
} }
@ -653,7 +653,7 @@ export class FreshStartChallenge extends Challenge {
pokemon.shiny = false; // Not shiny pokemon.shiny = false; // Not shiny
pokemon.variant = 0; // Not shiny pokemon.variant = 0; // Not shiny
pokemon.formIndex = 0; // Froakie should be base form pokemon.formIndex = 0; // Froakie should be base form
pokemon.ivs = [10, 10, 10, 10, 10, 10]; // Default IVs of 10 for all stats pokemon.ivs = [ 10, 10, 10, 10, 10, 10 ]; // Default IVs of 10 for all stats
return true; return true;
} }

View File

@ -3123,44 +3123,44 @@ export const trainerTypeDialogue: TrainerTypeDialogue = {
export const doubleBattleDialogue = { export const doubleBattleDialogue = {
"blue_red_double": { "blue_red_double": {
encounter: ["doubleBattleDialogue:blue_red_double.encounter.1"], encounter: [ "doubleBattleDialogue:blue_red_double.encounter.1" ],
victory: ["doubleBattleDialogue:blue_red_double.victory.1"] victory: [ "doubleBattleDialogue:blue_red_double.victory.1" ]
}, },
"red_blue_double": { "red_blue_double": {
encounter: ["doubleBattleDialogue:red_blue_double.encounter.1"], encounter: [ "doubleBattleDialogue:red_blue_double.encounter.1" ],
victory: ["doubleBattleDialogue:red_blue_double.victory.1"] victory: [ "doubleBattleDialogue:red_blue_double.victory.1" ]
}, },
"tate_liza_double": { "tate_liza_double": {
encounter: ["doubleBattleDialogue:tate_liza_double.encounter.1"], encounter: [ "doubleBattleDialogue:tate_liza_double.encounter.1" ],
victory: ["doubleBattleDialogue:tate_liza_double.victory.1"] victory: [ "doubleBattleDialogue:tate_liza_double.victory.1" ]
}, },
"liza_tate_double": { "liza_tate_double": {
encounter: ["doubleBattleDialogue:liza_tate_double.encounter.1"], encounter: [ "doubleBattleDialogue:liza_tate_double.encounter.1" ],
victory: [ "doubleBattleDialogue:liza_tate_double.victory.1"] victory: [ "doubleBattleDialogue:liza_tate_double.victory.1" ]
}, },
"wallace_steven_double": { "wallace_steven_double": {
encounter: [ "doubleBattleDialogue:wallace_steven_double.encounter.1"], encounter: [ "doubleBattleDialogue:wallace_steven_double.encounter.1" ],
victory: [ "doubleBattleDialogue:wallace_steven_double.victory.1"] victory: [ "doubleBattleDialogue:wallace_steven_double.victory.1" ]
}, },
"steven_wallace_double": { "steven_wallace_double": {
encounter: [ "doubleBattleDialogue:steven_wallace_double.encounter.1"], encounter: [ "doubleBattleDialogue:steven_wallace_double.encounter.1" ],
victory: [ "doubleBattleDialogue:steven_wallace_double.victory.1"] victory: [ "doubleBattleDialogue:steven_wallace_double.victory.1" ]
}, },
"alder_iris_double": { "alder_iris_double": {
encounter: [ "doubleBattleDialogue:alder_iris_double.encounter.1"], encounter: [ "doubleBattleDialogue:alder_iris_double.encounter.1" ],
victory: [ "doubleBattleDialogue:alder_iris_double.victory.1"] victory: [ "doubleBattleDialogue:alder_iris_double.victory.1" ]
}, },
"iris_alder_double": { "iris_alder_double": {
encounter: [ "doubleBattleDialogue:iris_alder_double.encounter.1"], encounter: [ "doubleBattleDialogue:iris_alder_double.encounter.1" ],
victory: [ "doubleBattleDialogue:iris_alder_double.victory.1"] victory: [ "doubleBattleDialogue:iris_alder_double.victory.1" ]
}, },
"marnie_piers_double": { "marnie_piers_double": {
encounter: [ "doubleBattleDialogue:marnie_piers_double.encounter.1"], encounter: [ "doubleBattleDialogue:marnie_piers_double.encounter.1" ],
victory: [ "doubleBattleDialogue:marnie_piers_double.victory.1"] victory: [ "doubleBattleDialogue:marnie_piers_double.victory.1" ]
}, },
"piers_marnie_double": { "piers_marnie_double": {
encounter: [ "doubleBattleDialogue:piers_marnie_double.encounter.1"], encounter: [ "doubleBattleDialogue:piers_marnie_double.encounter.1" ],
victory: [ "doubleBattleDialogue:piers_marnie_double.victory.1"] victory: [ "doubleBattleDialogue:piers_marnie_double.victory.1" ]
}, },
@ -3193,7 +3193,7 @@ export function initTrainerTypeDialogue(): void {
const trainerTypes = Object.keys(trainerTypeDialogue).map(t => parseInt(t) as TrainerType); const trainerTypes = Object.keys(trainerTypeDialogue).map(t => parseInt(t) as TrainerType);
for (const trainerType of trainerTypes) { for (const trainerType of trainerTypes) {
const messages = trainerTypeDialogue[trainerType]; const messages = trainerTypeDialogue[trainerType];
const messageTypes = ["encounter", "victory", "defeat"]; const messageTypes = [ "encounter", "victory", "defeat" ];
for (const messageType of messageTypes) { for (const messageType of messageTypes) {
if (Array.isArray(messages)) { if (Array.isArray(messages)) {
if (messages[0][messageType]) { if (messages[0][messageType]) {

View File

@ -48,7 +48,7 @@ export class EggHatchData {
seenCount: currDexEntry.seenCount, seenCount: currDexEntry.seenCount,
caughtCount: currDexEntry.caughtCount, caughtCount: currDexEntry.caughtCount,
hatchedCount: currDexEntry.hatchedCount, hatchedCount: currDexEntry.hatchedCount,
ivs: [...currDexEntry.ivs] ivs: [ ...currDexEntry.ivs ]
}; };
this.starterDataEntryBeforeUpdate = { this.starterDataEntryBeforeUpdate = {
moveset: currStarterDataEntry.moveset, moveset: currStarterDataEntry.moveset,

View File

@ -288,7 +288,7 @@ export class Egg {
public getEggTypeDescriptor(scene: BattleScene): string { public getEggTypeDescriptor(scene: BattleScene): string {
switch (this.sourceType) { switch (this.sourceType) {
case EggSourceType.SAME_SPECIES_EGG: case EggSourceType.SAME_SPECIES_EGG:
return this._eggDescriptor ?? i18next.t("egg:sameSpeciesEgg", { species: getPokemonSpecies(this._species).getName()}); return this._eggDescriptor ?? i18next.t("egg:sameSpeciesEgg", { species: getPokemonSpecies(this._species).getName() });
case EggSourceType.GACHA_LEGENDARY: case EggSourceType.GACHA_LEGENDARY:
return this._eggDescriptor ?? `${i18next.t("egg:gachaTypeLegendary")} (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(scene, this.timestamp)).getName()})`; return this._eggDescriptor ?? `${i18next.t("egg:gachaTypeLegendary")} (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(scene, this.timestamp)).getName()})`;
case EggSourceType.GACHA_SHINY: case EggSourceType.GACHA_SHINY:
@ -396,7 +396,7 @@ export class Egg {
break; break;
} }
const ignoredSpecies = [Species.PHIONE, Species.MANAPHY, Species.ETERNATUS]; const ignoredSpecies = [ Species.PHIONE, Species.MANAPHY, Species.ETERNATUS ];
let speciesPool = Object.keys(speciesStarterCosts) let speciesPool = Object.keys(speciesStarterCosts)
.filter(s => speciesStarterCosts[s] >= minStarterValue && speciesStarterCosts[s] <= maxStarterValue) .filter(s => speciesStarterCosts[s] >= minStarterValue && speciesStarterCosts[s] <= maxStarterValue)

File diff suppressed because it is too large Load Diff

View File

@ -152,7 +152,7 @@ export const ATrainersTestEncounter: MysteryEncounter =
tier: EggTier.ULTRA tier: EggTier.ULTRA
}; };
encounter.setDialogueToken("eggType", i18next.t(`${namespace}:eggTypes.epic`)); encounter.setDialogueToken("eggType", i18next.t(`${namespace}:eggTypes.epic`));
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.SACRED_ASH], guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ULTRA], fillRemaining: true }, [eggOptions]); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.SACRED_ASH ], guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ULTRA ], fillRemaining: true }, [ eggOptions ]);
return initBattleWithEnemyConfig(scene, config); return initBattleWithEnemyConfig(scene, config);
} }
) )
@ -174,7 +174,7 @@ export const ATrainersTestEncounter: MysteryEncounter =
tier: EggTier.GREAT tier: EggTier.GREAT
}; };
encounter.setDialogueToken("eggType", i18next.t(`${namespace}:eggTypes.rare`)); encounter.setDialogueToken("eggType", i18next.t(`${namespace}:eggTypes.rare`));
setEncounterRewards(scene, { fillRemaining: false, rerollMultiplier: -1 }, [eggOptions]); setEncounterRewards(scene, { fillRemaining: false, rerollMultiplier: -1 }, [ eggOptions ]);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} }
) )

View File

@ -195,7 +195,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
// Can't define stack count on a ModifierType, have to just create separate instances for each stack // Can't define stack count on a ModifierType, have to just create separate instances for each stack
// Overflow berries will be "lost" on the boss, but it's un-catchable anyway // Overflow berries will be "lost" on the boss, but it's un-catchable anyway
for (let i = 0; i < berryMod.stackCount; i++) { for (let i = 0; i < berryMod.stackCount; i++) {
const modifierType = generateModifierType(scene, modifierTypes.BERRY, [berryMod.berryType]) as PokemonHeldItemModifierType; const modifierType = generateModifierType(scene, modifierTypes.BERRY, [ berryMod.berryType ]) as PokemonHeldItemModifierType;
bossModifierConfigs.push({ modifier: modifierType }); bossModifierConfigs.push({ modifier: modifierType });
} }
}); });
@ -204,8 +204,8 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
// SpDef buff below wave 50, +1 to all stats otherwise // SpDef buff below wave 50, +1 to all stats otherwise
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ? const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ?
[Stat.SPDEF] : [ Stat.SPDEF ] :
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]; [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ];
// Calculate boss mon // Calculate boss mon
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
@ -215,9 +215,9 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
species: getPokemonSpecies(Species.GREEDENT), species: getPokemonSpecies(Species.GREEDENT),
isBoss: true, isBoss: true,
bossSegments: 3, bossSegments: 3,
moveSet: [Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.CRUNCH], moveSet: [ Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.CRUNCH ],
modifierConfigs: bossModifierConfigs, modifierConfigs: bossModifierConfigs,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}:option.1.boss_enraged`); queueEncounterMessage(pokemon.scene, `${namespace}:option.1.boss_enraged`);
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
@ -226,7 +226,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
], ],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
encounter.setDialogueToken("greedentName", getPokemonSpecies(Species.GREEDENT).getName()); encounter.setDialogueToken("greedentName", getPokemonSpecies(Species.GREEDENT).getName());
return true; return true;
@ -280,7 +280,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
setEncounterRewards(scene, { fillRemaining: true }, undefined, givePartyPokemonReviverSeeds); setEncounterRewards(scene, { fillRemaining: true }, undefined, givePartyPokemonReviverSeeds);
encounter.startOfBattleEffects.push({ encounter.startOfBattleEffects.push({
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.ENEMY], targets: [ BattlerIndex.ENEMY ],
move: new PokemonMove(Moves.STUFF_CHEEKS), move: new PokemonMove(Moves.STUFF_CHEEKS),
ignorePp: true ignorePp: true
}); });
@ -320,7 +320,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
Phaser.Math.RND.shuffle(berryTypesAsArray); Phaser.Math.RND.shuffle(berryTypesAsArray);
const randBerryType = berryTypesAsArray.pop(); const randBerryType = berryTypesAsArray.pop();
const berryModType = generateModifierType(scene, modifierTypes.BERRY, [randBerryType]) as BerryModifierType; const berryModType = generateModifierType(scene, modifierTypes.BERRY, [ randBerryType ]) as BerryModifierType;
applyModifierTypeToPlayerPokemon(scene, pokemon, berryModType); applyModifierTypeToPlayerPokemon(scene, pokemon, berryModType);
} }
} }
@ -355,7 +355,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
// Greedent joins the team, level equal to 2 below highest party member // Greedent joins the team, level equal to 2 below highest party member
const level = getHighestLevelPlayerPokemon(scene, false, true).level - 2; const level = getHighestLevelPlayerPokemon(scene, false, true).level - 2;
const greedent = new EnemyPokemon(scene, getPokemonSpecies(Species.GREEDENT), level, TrainerSlot.NONE, false); const greedent = new EnemyPokemon(scene, getPokemonSpecies(Species.GREEDENT), level, TrainerSlot.NONE, false);
greedent.moveset = [new PokemonMove(Moves.THRASH), new PokemonMove(Moves.BODY_PRESS), new PokemonMove(Moves.STUFF_CHEEKS), new PokemonMove(Moves.SLACK_OFF)]; greedent.moveset = [ new PokemonMove(Moves.THRASH), new PokemonMove(Moves.BODY_PRESS), new PokemonMove(Moves.STUFF_CHEEKS), new PokemonMove(Moves.SLACK_OFF) ];
greedent.passive = true; greedent.passive = true;
transitionMysteryEncounterIntroVisuals(scene, true, true, 500); transitionMysteryEncounterIntroVisuals(scene, true, true, 500);
@ -472,7 +472,7 @@ function doGreedentEatBerries(scene: BattleScene) {
*/ */
function doBerrySpritePile(scene: BattleScene, isEat: boolean = false) { function doBerrySpritePile(scene: BattleScene, isEat: boolean = false) {
const berryAddDelay = 150; const berryAddDelay = 150;
let animationOrder = ["starf", "sitrus", "lansat", "salac", "apicot", "enigma", "liechi", "ganlon", "lum", "petaya", "leppa"]; let animationOrder = [ "starf", "sitrus", "lansat", "salac", "apicot", "enigma", "liechi", "ganlon", "lum", "petaya", "leppa" ];
if (isEat) { if (isEat) {
animationOrder = animationOrder.reverse(); animationOrder = animationOrder.reverse();
} }
@ -496,7 +496,7 @@ function doBerrySpritePile(scene: BattleScene, isEat: boolean = false) {
// Animate Petaya berry falling off the pile // Animate Petaya berry falling off the pile
if (berry === "petaya" && sprite && tintSprite && !isEat) { if (berry === "petaya" && sprite && tintSprite && !isEat) {
scene.time.delayedCall(200, () => { scene.time.delayedCall(200, () => {
doBerryBounce(scene, [sprite, tintSprite], 30, 500); doBerryBounce(scene, [ sprite, tintSprite ], 30, 500);
}); });
} }
}); });

View File

@ -69,7 +69,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
isBoss: true isBoss: true
}], }],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
// Calculate the number of extra berries that player receives // Calculate the number of extra berries that player receives
// 10-40: 2, 40-120: 4, 120-160: 5, 160-180: 7 // 10-40: 2, 40-120: 4, 120-160: 5, 160-180: 7
@ -193,11 +193,11 @@ export const BerriesAboundEncounter: MysteryEncounter =
// Defense/Spd buffs below wave 50, +1 to all stats otherwise // Defense/Spd buffs below wave 50, +1 to all stats otherwise
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ? const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ?
[Stat.DEF, Stat.SPDEF, Stat.SPD] : [ Stat.DEF, Stat.SPDEF, Stat.SPD ] :
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]; [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ];
const config = scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]; const config = scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0];
config.pokemonConfigs![0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON]; config.pokemonConfigs![0].tags = [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ];
config.pokemonConfigs![0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => { config.pokemonConfigs![0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}:option.2.boss_enraged`); queueEncounterMessage(pokemon.scene, `${namespace}:option.2.boss_enraged`);
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
@ -208,7 +208,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
return; return;
} else { } else {
// Gains 1 berry for every 10% faster the player's pokemon is than the enemy, up to a max of numBerries, minimum of 2 // Gains 1 berry for every 10% faster the player's pokemon is than the enemy, up to a max of numBerries, minimum of 2
const numBerriesGrabbed = Math.max(Math.min(Math.round((speedDiff - 1)/0.08), numBerries), 2); const numBerriesGrabbed = Math.max(Math.min(Math.round((speedDiff - 1) / 0.08), numBerries), 2);
encounter.setDialogueToken("numBerries", String(numBerriesGrabbed)); encounter.setDialogueToken("numBerries", String(numBerriesGrabbed));
const doFasterBerryRewards = () => { const doFasterBerryRewards = () => {
const berryText = i18next.t(`${namespace}:berries`); const berryText = i18next.t(`${namespace}:berries`);
@ -250,7 +250,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
function tryGiveBerry(scene: BattleScene, prioritizedPokemon?: PlayerPokemon) { function tryGiveBerry(scene: BattleScene, prioritizedPokemon?: PlayerPokemon) {
const berryType = randSeedInt(Object.keys(BerryType).filter(s => !isNaN(Number(s))).length) as BerryType; const berryType = randSeedInt(Object.keys(BerryType).filter(s => !isNaN(Number(s))).length) as BerryType;
const berry = generateModifierType(scene, modifierTypes.BERRY, [berryType]) as BerryModifierType; const berry = generateModifierType(scene, modifierTypes.BERRY, [ berryType ]) as BerryModifierType;
const party = scene.getParty(); const party = scene.getParty();

View File

@ -181,7 +181,7 @@ const MISC_TUTOR_MOVES = [
/** /**
* Wave breakpoints that determine how strong to make the Bug-Type Superfan's team * Wave breakpoints that determine how strong to make the Bug-Type Superfan's team
*/ */
const WAVE_LEVEL_BREAKPOINTS = [30, 50, 70, 100, 120, 140, 160]; const WAVE_LEVEL_BREAKPOINTS = [ 30, 50, 70, 100, 120, 140, 160 ];
/** /**
* Bug Type Superfan encounter. * Bug Type Superfan encounter.
@ -193,7 +193,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
.withEncounterTier(MysteryEncounterTier.GREAT) .withEncounterTier(MysteryEncounterTier.GREAT)
.withPrimaryPokemonRequirement(new CombinationPokemonRequirement( .withPrimaryPokemonRequirement(new CombinationPokemonRequirement(
// Must have at least 1 Bug type on team, OR have a bug item somewhere on the team // Must have at least 1 Bug type on team, OR have a bug item somewhere on the team
new HeldItemRequirement(["BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier"], 1), new HeldItemRequirement([ "BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier" ], 1),
new AttackTypeBoosterHeldItemTypeRequirement(Type.BUG, 1), new AttackTypeBoosterHeldItemTypeRequirement(Type.BUG, 1),
new TypeRequirement(Type.BUG, false, 1) new TypeRequirement(Type.BUG, false, 1)
)) ))
@ -268,7 +268,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
const requiredItems = [ const requiredItems = [
generateModifierType(scene, modifierTypes.QUICK_CLAW), generateModifierType(scene, modifierTypes.QUICK_CLAW),
generateModifierType(scene, modifierTypes.GRIP_CLAW), generateModifierType(scene, modifierTypes.GRIP_CLAW),
generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.BUG]), generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.BUG ]),
]; ];
const requiredItemString = requiredItems.map(m => m?.name ?? "unknown").join("/"); const requiredItemString = requiredItems.map(m => m?.name ?? "unknown").join("/");
@ -331,7 +331,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
encounter.setDialogueToken("numBugTypes", numBugTypesText); encounter.setDialogueToken("numBugTypes", numBugTypesText);
if (numBugTypes < 2) { if (numBugTypes < 2) {
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.SUPER_LURE, modifierTypes.GREAT_BALL], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.SUPER_LURE, modifierTypes.GREAT_BALL ], fillRemaining: false });
encounter.selectedOption!.dialogue!.selected = [ encounter.selectedOption!.dialogue!.selected = [
{ {
speaker: `${namespace}:speaker`, speaker: `${namespace}:speaker`,
@ -339,7 +339,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
}, },
]; ];
} else if (numBugTypes < 4) { } else if (numBugTypes < 4) {
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.QUICK_CLAW, modifierTypes.MAX_LURE, modifierTypes.ULTRA_BALL], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.QUICK_CLAW, modifierTypes.MAX_LURE, modifierTypes.ULTRA_BALL ], fillRemaining: false });
encounter.selectedOption!.dialogue!.selected = [ encounter.selectedOption!.dialogue!.selected = [
{ {
speaker: `${namespace}:speaker`, speaker: `${namespace}:speaker`,
@ -347,7 +347,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
}, },
]; ];
} else if (numBugTypes < 6) { } else if (numBugTypes < 6) {
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.GRIP_CLAW, modifierTypes.MAX_LURE, modifierTypes.ROGUE_BALL], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.GRIP_CLAW, modifierTypes.MAX_LURE, modifierTypes.ROGUE_BALL ], fillRemaining: false });
encounter.selectedOption!.dialogue!.selected = [ encounter.selectedOption!.dialogue!.selected = [
{ {
speaker: `${namespace}:speaker`, speaker: `${namespace}:speaker`,
@ -356,7 +356,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
]; ];
} else { } else {
// If player has any evolution/form change items that are valid for their party, will spawn one of those items in addition to a Master Ball // If player has any evolution/form change items that are valid for their party, will spawn one of those items in addition to a Master Ball
const modifierOptions: ModifierTypeOption[] = [generateModifierTypeOption(scene, modifierTypes.MASTER_BALL)!, generateModifierTypeOption(scene, modifierTypes.MAX_LURE)!]; const modifierOptions: ModifierTypeOption[] = [ generateModifierTypeOption(scene, modifierTypes.MASTER_BALL)!, generateModifierTypeOption(scene, modifierTypes.MAX_LURE)! ];
const specialOptions: ModifierTypeOption[] = []; const specialOptions: ModifierTypeOption[] = [];
const nonRareEvolutionModifier = generateModifierTypeOption(scene, modifierTypes.EVOLUTION_ITEM); const nonRareEvolutionModifier = generateModifierTypeOption(scene, modifierTypes.EVOLUTION_ITEM);
@ -397,7 +397,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT) .newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
.withPrimaryPokemonRequirement(new CombinationPokemonRequirement( .withPrimaryPokemonRequirement(new CombinationPokemonRequirement(
// Meets one or both of the below reqs // Meets one or both of the below reqs
new HeldItemRequirement(["BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier"], 1), new HeldItemRequirement([ "BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier" ], 1),
new AttackTypeBoosterHeldItemTypeRequirement(Type.BUG, 1) new AttackTypeBoosterHeldItemTypeRequirement(Type.BUG, 1)
)) ))
.withDialogue({ .withDialogue({
@ -474,7 +474,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
const bugNet = generateModifierTypeOption(scene, modifierTypes.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!; const bugNet = generateModifierTypeOption(scene, modifierTypes.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!;
bugNet.type.tier = ModifierTier.ROGUE; bugNet.type.tier = ModifierTier.ROGUE;
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [bugNet], guaranteedModifierTypeFuncs: [modifierTypes.REVIVER_SEED], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ bugNet ], guaranteedModifierTypeFuncs: [ modifierTypes.REVIVER_SEED ], fillRemaining: false });
leaveEncounterWithoutBattle(scene, true); leaveEncounterWithoutBattle(scene, true);
}) })
.build()) .build())
@ -535,7 +535,7 @@ function getTrainerConfigForWave(waveIndex: number) {
})) }))
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(3, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true)) .setPartyMemberFunc(3, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => { .setPartyMemberFunc(4, getRandomPartyMemberFunc([ pool3Mon.species ], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon.formIndex)) { if (!isNullOrUndefined(pool3Mon.formIndex)) {
p.formIndex = pool3Mon.formIndex; p.formIndex = pool3Mon.formIndex;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
@ -558,14 +558,14 @@ function getTrainerConfigForWave(waveIndex: number) {
p.generateName(); p.generateName();
})) }))
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => { .setPartyMemberFunc(3, getRandomPartyMemberFunc([ pool3Mon.species ], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon.formIndex)) { if (!isNullOrUndefined(pool3Mon.formIndex)) {
p.formIndex = pool3Mon.formIndex; p.formIndex = pool3Mon.formIndex;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.generateName(); p.generateName();
} }
})) }))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([pool3Mon2.species], TrainerSlot.TRAINER, true, p => { .setPartyMemberFunc(4, getRandomPartyMemberFunc([ pool3Mon2.species ], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon2.formIndex)) { if (!isNullOrUndefined(pool3Mon2.formIndex)) {
p.formIndex = pool3Mon2.formIndex; p.formIndex = pool3Mon2.formIndex;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
@ -586,7 +586,7 @@ function getTrainerConfigForWave(waveIndex: number) {
p.generateName(); p.generateName();
})) }))
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => { .setPartyMemberFunc(3, getRandomPartyMemberFunc([ pool3Mon.species ], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon.formIndex)) { if (!isNullOrUndefined(pool3Mon.formIndex)) {
p.formIndex = pool3Mon.formIndex; p.formIndex = pool3Mon.formIndex;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
@ -611,14 +611,14 @@ function getTrainerConfigForWave(waveIndex: number) {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.generateName(); p.generateName();
})) }))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => { .setPartyMemberFunc(2, getRandomPartyMemberFunc([ pool3Mon.species ], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon.formIndex)) { if (!isNullOrUndefined(pool3Mon.formIndex)) {
p.formIndex = pool3Mon.formIndex; p.formIndex = pool3Mon.formIndex;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.generateName(); p.generateName();
} }
})) }))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([pool3Mon2.species], TrainerSlot.TRAINER, true, p => { .setPartyMemberFunc(3, getRandomPartyMemberFunc([ pool3Mon2.species ], TrainerSlot.TRAINER, true, p => {
if (!isNullOrUndefined(pool3Mon2.formIndex)) { if (!isNullOrUndefined(pool3Mon2.formIndex)) {
p.formIndex = pool3Mon2.formIndex; p.formIndex = pool3Mon2.formIndex;
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();

View File

@ -129,20 +129,20 @@ export const ClowningAroundEncounter: MysteryEncounter =
{ {
species: getPokemonSpecies(Species.MR_MIME), species: getPokemonSpecies(Species.MR_MIME),
isBoss: true, isBoss: true,
moveSet: [Moves.TEETER_DANCE, Moves.ALLY_SWITCH, Moves.DAZZLING_GLEAM, Moves.PSYCHIC] moveSet: [ Moves.TEETER_DANCE, Moves.ALLY_SWITCH, Moves.DAZZLING_GLEAM, Moves.PSYCHIC ]
}, },
{ // Blacephalon has the random ability from pool, and 2 entirely random types to fit with the theme of the encounter { // Blacephalon has the random ability from pool, and 2 entirely random types to fit with the theme of the encounter
species: getPokemonSpecies(Species.BLACEPHALON), species: getPokemonSpecies(Species.BLACEPHALON),
mysteryEncounterPokemonData: new MysteryEncounterPokemonData({ ability: ability, types: [randSeedInt(18), randSeedInt(18)] }), mysteryEncounterPokemonData: new MysteryEncounterPokemonData({ ability: ability, types: [ randSeedInt(18), randSeedInt(18) ]}),
isBoss: true, isBoss: true,
moveSet: [Moves.TRICK, Moves.HYPNOSIS, Moves.SHADOW_BALL, Moves.MIND_BLOWN] moveSet: [ Moves.TRICK, Moves.HYPNOSIS, Moves.SHADOW_BALL, Moves.MIND_BLOWN ]
}, },
], ],
doubleBattle: true doubleBattle: true
}); });
// Load animations/sfx for start of fight moves // Load animations/sfx for start of fight moves
loadCustomMovesForEncounter(scene, [Moves.ROLE_PLAY, Moves.TAUNT]); loadCustomMovesForEncounter(scene, [ Moves.ROLE_PLAY, Moves.TAUNT ]);
encounter.setDialogueToken("blacephalonName", getPokemonSpecies(Species.BLACEPHALON).getName()); encounter.setDialogueToken("blacephalonName", getPokemonSpecies(Species.BLACEPHALON).getName());
@ -175,19 +175,19 @@ export const ClowningAroundEncounter: MysteryEncounter =
encounter.startOfBattleEffects.push( encounter.startOfBattleEffects.push(
{ // Mr. Mime copies the Blacephalon's random ability { // Mr. Mime copies the Blacephalon's random ability
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.ENEMY_2], targets: [ BattlerIndex.ENEMY_2 ],
move: new PokemonMove(Moves.ROLE_PLAY), move: new PokemonMove(Moves.ROLE_PLAY),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY_2, sourceBattlerIndex: BattlerIndex.ENEMY_2,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.TAUNT), move: new PokemonMove(Moves.TAUNT),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY_2, sourceBattlerIndex: BattlerIndex.ENEMY_2,
targets: [BattlerIndex.PLAYER_2], targets: [ BattlerIndex.PLAYER_2 ],
move: new PokemonMove(Moves.TAUNT), move: new PokemonMove(Moves.TAUNT),
ignorePp: true ignorePp: true
}); });
@ -336,11 +336,11 @@ export const ClowningAroundEncounter: MysteryEncounter =
.filter(move => move && !originalTypes.includes(move.getMove().type) && move.getMove().category !== MoveCategory.STATUS) .filter(move => move && !originalTypes.includes(move.getMove().type) && move.getMove().category !== MoveCategory.STATUS)
.map(move => move!.getMove().type); .map(move => move!.getMove().type);
if (priorityTypes?.length > 0) { if (priorityTypes?.length > 0) {
priorityTypes = [...new Set(priorityTypes)].sort(); priorityTypes = [ ...new Set(priorityTypes) ].sort();
priorityTypes = randSeedShuffle(priorityTypes); priorityTypes = randSeedShuffle(priorityTypes);
} }
const newTypes = [originalTypes[0]]; const newTypes = [ originalTypes[0] ];
let secondType: Type | null = null; let secondType: Type | null = null;
while (secondType === null || secondType === newTypes[0] || originalTypes.includes(secondType)) { while (secondType === null || secondType === newTypes[0] || originalTypes.includes(secondType)) {
if (priorityTypes.length > 0) { if (priorityTypes.length > 0) {
@ -453,37 +453,37 @@ function generateItemsOfTier(scene: BattleScene, pokemon: PlayerPokemon, numItem
// Pools have instances of the modifier type equal to the max stacks that modifier can be applied to any one pokemon // Pools have instances of the modifier type equal to the max stacks that modifier can be applied to any one pokemon
// This is to prevent "over-generating" a random item of a certain type during item swaps // This is to prevent "over-generating" a random item of a certain type during item swaps
const ultraPool = [ const ultraPool = [
[modifierTypes.REVIVER_SEED, 1], [ modifierTypes.REVIVER_SEED, 1 ],
[modifierTypes.GOLDEN_PUNCH, 5], [ modifierTypes.GOLDEN_PUNCH, 5 ],
[modifierTypes.ATTACK_TYPE_BOOSTER, 99], [ modifierTypes.ATTACK_TYPE_BOOSTER, 99 ],
[modifierTypes.QUICK_CLAW, 3], [ modifierTypes.QUICK_CLAW, 3 ],
[modifierTypes.WIDE_LENS, 3] [ modifierTypes.WIDE_LENS, 3 ]
]; ];
const roguePool = [ const roguePool = [
[modifierTypes.LEFTOVERS, 4], [ modifierTypes.LEFTOVERS, 4 ],
[modifierTypes.SHELL_BELL, 4], [ modifierTypes.SHELL_BELL, 4 ],
[modifierTypes.SOUL_DEW, 10], [ modifierTypes.SOUL_DEW, 10 ],
[modifierTypes.SOOTHE_BELL, 3], [ modifierTypes.SOOTHE_BELL, 3 ],
[modifierTypes.SCOPE_LENS, 1], [ modifierTypes.SCOPE_LENS, 1 ],
[modifierTypes.BATON, 1], [ modifierTypes.BATON, 1 ],
[modifierTypes.FOCUS_BAND, 5], [ modifierTypes.FOCUS_BAND, 5 ],
[modifierTypes.KINGS_ROCK, 3], [ modifierTypes.KINGS_ROCK, 3 ],
[modifierTypes.GRIP_CLAW, 5] [ modifierTypes.GRIP_CLAW, 5 ]
]; ];
const berryPool = [ const berryPool = [
[BerryType.APICOT, 3], [ BerryType.APICOT, 3 ],
[BerryType.ENIGMA, 2], [ BerryType.ENIGMA, 2 ],
[BerryType.GANLON, 3], [ BerryType.GANLON, 3 ],
[BerryType.LANSAT, 3], [ BerryType.LANSAT, 3 ],
[BerryType.LEPPA, 2], [ BerryType.LEPPA, 2 ],
[BerryType.LIECHI, 3], [ BerryType.LIECHI, 3 ],
[BerryType.LUM, 2], [ BerryType.LUM, 2 ],
[BerryType.PETAYA, 3], [ BerryType.PETAYA, 3 ],
[BerryType.SALAC, 2], [ BerryType.SALAC, 2 ],
[BerryType.SITRUS, 2], [ BerryType.SITRUS, 2 ],
[BerryType.STARF, 3] [ BerryType.STARF, 3 ]
]; ];
let pool: any[]; let pool: any[];
@ -502,7 +502,7 @@ function generateItemsOfTier(scene: BattleScene, pokemon: PlayerPokemon, numItem
const newItemType = pool[randIndex]; const newItemType = pool[randIndex];
let newMod: PokemonHeldItemModifierType; let newMod: PokemonHeldItemModifierType;
if (tier === "Berries") { if (tier === "Berries") {
newMod = generateModifierType(scene, modifierTypes.BERRY, [newItemType[0]]) as PokemonHeldItemModifierType; newMod = generateModifierType(scene, modifierTypes.BERRY, [ newItemType[0] ]) as PokemonHeldItemModifierType;
} else { } else {
newMod = generateModifierType(scene, newItemType[0]) as PokemonHeldItemModifierType; newMod = generateModifierType(scene, newItemType[0]) as PokemonHeldItemModifierType;
} }

View File

@ -141,7 +141,7 @@ export const DancingLessonsEncounter: MysteryEncounter =
scene.getEnemyParty().forEach(enemyPokemon => { scene.getEnemyParty().forEach(enemyPokemon => {
scene.field.remove(enemyPokemon, true); scene.field.remove(enemyPokemon, true);
}); });
scene.currentBattle.enemyParty = [oricorio]; scene.currentBattle.enemyParty = [ oricorio ];
scene.field.add(oricorio); scene.field.add(oricorio);
// Spawns on offscreen field // Spawns on offscreen field
oricorio.x -= 300; oricorio.x -= 300;
@ -153,14 +153,14 @@ export const DancingLessonsEncounter: MysteryEncounter =
dataSource: oricorioData, dataSource: oricorioData,
isBoss: true, isBoss: true,
// Gets +1 to all stats except SPD on battle start // Gets +1 to all stats except SPD on battle start
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}:option.1.boss_enraged`); queueEncounterMessage(pokemon.scene, `${namespace}:option.1.boss_enraged`);
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF], 1)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF ], 1));
} }
}], }],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
encounter.misc = { encounter.misc = {
oricorioData oricorioData
}; };
@ -187,13 +187,13 @@ export const DancingLessonsEncounter: MysteryEncounter =
encounter.startOfBattleEffects.push({ encounter.startOfBattleEffects.push({
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.REVELATION_DANCE), move: new PokemonMove(Moves.REVELATION_DANCE),
ignorePp: true ignorePp: true
}); });
await hideOricorioPokemon(scene); await hideOricorioPokemon(scene);
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.BATON], fillRemaining: true }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.BATON ], fillRemaining: true });
await initBattleWithEnemyConfig(scene, encounter.enemyPartyConfigs[0]); await initBattleWithEnemyConfig(scene, encounter.enemyPartyConfigs[0]);
}) })
.build() .build()

View File

@ -164,7 +164,7 @@ export const DarkDealEncounter: MysteryEncounter =
// Starter egg tier, 35/50/10/5 %odds for tiers 6/7/8/9+ // Starter egg tier, 35/50/10/5 %odds for tiers 6/7/8/9+
const roll = randSeedInt(100); const roll = randSeedInt(100);
const starterTier: number | [number, number] = const starterTier: number | [number, number] =
roll >= 65 ? 6 : roll >= 15 ? 7 : roll >= 5 ? 8 : [9, 10]; roll >= 65 ? 6 : roll >= 15 ? 7 : roll >= 5 ? 8 : [ 9, 10 ];
const bossSpecies = getPokemonSpecies(getRandomSpeciesByStarterTier(starterTier, excludedBosses, bossTypes)); const bossSpecies = getPokemonSpecies(getRandomSpeciesByStarterTier(starterTier, excludedBosses, bossTypes));
const pokemonConfig: EnemyPokemonConfig = { const pokemonConfig: EnemyPokemonConfig = {
species: bossSpecies, species: bossSpecies,
@ -179,7 +179,7 @@ export const DarkDealEncounter: MysteryEncounter =
pokemonConfig.formIndex = 0; pokemonConfig.formIndex = 0;
} }
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
pokemonConfigs: [pokemonConfig], pokemonConfigs: [ pokemonConfig ],
}; };
return initBattleWithEnemyConfig(scene, config); return initBattleWithEnemyConfig(scene, config);
}) })

View File

@ -22,7 +22,7 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
const namespace = "mysteryEncounters/delibirdy"; const namespace = "mysteryEncounters/delibirdy";
/** Berries only */ /** Berries only */
const OPTION_2_ALLOWED_MODIFIERS = ["BerryModifier", "PokemonInstantReviveModifier"]; const OPTION_2_ALLOWED_MODIFIERS = [ "BerryModifier", "PokemonInstantReviveModifier" ];
/** Disallowed items are berries, Reviver Seeds, and Vitamins (form change items and fusion items are not PokemonHeldItemModifiers) */ /** Disallowed items are berries, Reviver Seeds, and Vitamins (form change items and fusion items are not PokemonHeldItemModifiers) */
const OPTION_3_DISALLOWED_MODIFIERS = [ const OPTION_3_DISALLOWED_MODIFIERS = [

View File

@ -87,9 +87,9 @@ export const FieldTripEncounter: MysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
if (encounter.misc.correctMove) { if (encounter.misc.correctMove) {
const modifiers = [ const modifiers = [
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.ATK])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.ATK ])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.DEF])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.DEF ])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPD ])!,
generateModifierTypeOption(scene, modifierTypes.DIRE_HIT)!, generateModifierTypeOption(scene, modifierTypes.DIRE_HIT)!,
generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!, generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!,
]; ];
@ -133,9 +133,9 @@ export const FieldTripEncounter: MysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
if (encounter.misc.correctMove) { if (encounter.misc.correctMove) {
const modifiers = [ const modifiers = [
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPATK])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPATK ])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPDEF])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPDEF ])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPD ])!,
generateModifierTypeOption(scene, modifierTypes.DIRE_HIT)!, generateModifierTypeOption(scene, modifierTypes.DIRE_HIT)!,
generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!, generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!,
]; ];
@ -179,8 +179,8 @@ export const FieldTripEncounter: MysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
if (encounter.misc.correctMove) { if (encounter.misc.correctMove) {
const modifiers = [ const modifiers = [
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.ACC])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.ACC ])!,
generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_STAGE_BOOSTER, [ Stat.SPD ])!,
generateModifierTypeOption(scene, modifierTypes.GREAT_BALL)!, generateModifierTypeOption(scene, modifierTypes.GREAT_BALL)!,
generateModifierTypeOption(scene, modifierTypes.IV_SCANNER)!, generateModifierTypeOption(scene, modifierTypes.IV_SCANNER)!,
generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!, generateModifierTypeOption(scene, modifierTypes.RARER_CANDY)!,
@ -227,7 +227,7 @@ function pokemonAndMoveChosen(scene: BattleScene, pokemon: PlayerPokemon, move:
text: `${namespace}:correct_exp`, text: `${namespace}:correct_exp`,
}, },
]; ];
setEncounterExp(scene, [pokemon.id], 100); setEncounterExp(scene, [ pokemon.id ], 100);
} }
encounter.misc = { encounter.misc = {
correctMove: correctMove, correctMove: correctMove,

View File

@ -73,7 +73,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
doubleBattle: true, doubleBattle: true,
disableSwitch: true disableSwitch: true
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
// Load hidden Volcarona sprites // Load hidden Volcarona sprites
encounter.spriteConfigs = [ encounter.spriteConfigs = [
@ -99,7 +99,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
]; ];
// Load animations/sfx for Volcarona moves // Load animations/sfx for Volcarona moves
loadCustomMovesForEncounter(scene, [Moves.FIRE_SPIN, Moves.QUIVER_DANCE]); loadCustomMovesForEncounter(scene, [ Moves.FIRE_SPIN, Moves.QUIVER_DANCE ]);
scene.arena.trySetWeather(WeatherType.SUNNY, true); scene.arena.trySetWeather(WeatherType.SUNNY, true);
@ -143,25 +143,25 @@ export const FieryFalloutEncounter: MysteryEncounter =
encounter.startOfBattleEffects.push( encounter.startOfBattleEffects.push(
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.FIRE_SPIN), move: new PokemonMove(Moves.FIRE_SPIN),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY_2, sourceBattlerIndex: BattlerIndex.ENEMY_2,
targets: [BattlerIndex.PLAYER_2], targets: [ BattlerIndex.PLAYER_2 ],
move: new PokemonMove(Moves.FIRE_SPIN), move: new PokemonMove(Moves.FIRE_SPIN),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.ENEMY], targets: [ BattlerIndex.ENEMY ],
move: new PokemonMove(Moves.QUIVER_DANCE), move: new PokemonMove(Moves.QUIVER_DANCE),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY_2, sourceBattlerIndex: BattlerIndex.ENEMY_2,
targets: [BattlerIndex.ENEMY_2], targets: [ BattlerIndex.ENEMY_2 ],
move: new PokemonMove(Moves.QUIVER_DANCE), move: new PokemonMove(Moves.QUIVER_DANCE),
ignorePp: true ignorePp: true
}); });
@ -237,7 +237,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
const primary = encounter.options[2].primaryPokemon!; const primary = encounter.options[2].primaryPokemon!;
const secondary = encounter.options[2].secondaryPokemon![0]; const secondary = encounter.options[2].secondaryPokemon![0];
setEncounterExp(scene, [primary.id, secondary.id], getPokemonSpecies(Species.VOLCARONA).baseExp * 2); setEncounterExp(scene, [ primary.id, secondary.id ], getPokemonSpecies(Species.VOLCARONA).baseExp * 2);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
}) })
.build() .build()
@ -248,7 +248,7 @@ function giveLeadPokemonCharcoal(scene: BattleScene) {
// Give first party pokemon Charcoal for free at end of battle // Give first party pokemon Charcoal for free at end of battle
const leadPokemon = scene.getParty()?.[0]; const leadPokemon = scene.getParty()?.[0];
if (leadPokemon) { if (leadPokemon) {
const charcoal = generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.FIRE]) as AttackTypeBoosterModifierType; const charcoal = generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.FIRE ]) as AttackTypeBoosterModifierType;
applyModifierTypeToPlayerPokemon(scene, leadPokemon, charcoal); applyModifierTypeToPlayerPokemon(scene, leadPokemon, charcoal);
scene.currentBattle.mysteryEncounter!.setDialogueToken("leadPokemon", leadPokemon.getNameToRender()); scene.currentBattle.mysteryEncounter!.setDialogueToken("leadPokemon", leadPokemon.getNameToRender());
queueEncounterMessage(scene, `${namespace}:found_charcoal`); queueEncounterMessage(scene, `${namespace}:found_charcoal`);

View File

@ -65,16 +65,16 @@ export const FightOrFlightEncounter: MysteryEncounter =
species: bossSpecies, species: bossSpecies,
dataSource: new PokemonData(bossPokemon), dataSource: new PokemonData(bossPokemon),
isBoss: true, isBoss: true,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}:option.1.stat_boost`); queueEncounterMessage(pokemon.scene, `${namespace}:option.1.stat_boost`);
// Randomly boost 1 stat 2 stages // Randomly boost 1 stat 2 stages
// Cannot boost Spd, Acc, or Evasion // Cannot boost Spd, Acc, or Evasion
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [randSeedInt(4, 1)], 2)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ randSeedInt(4, 1) ], 2));
} }
}], }],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
// Calculate item // Calculate item
// Waves 10-40 GREAT, 60-120 ULTRA, 120-160 ROGUE, 160-180 MASTER // Waves 10-40 GREAT, 60-120 ULTRA, 120-160 ROGUE, 160-180 MASTER
@ -90,7 +90,7 @@ export const FightOrFlightEncounter: MysteryEncounter =
let item: ModifierTypeOption | null = null; let item: ModifierTypeOption | null = null;
// TMs and Candy Jar excluded from possible rewards as they're too swingy in value for a singular item reward // TMs and Candy Jar excluded from possible rewards as they're too swingy in value for a singular item reward
while (!item || item.type.id.includes("TM_") || item.type.id === "CANDY_JAR") { while (!item || item.type.id.includes("TM_") || item.type.id === "CANDY_JAR") {
item = getPlayerModifierTypeOptions(1, scene.getParty(), [], { guaranteedModifierTiers: [tier], allowLuckUpgrades: false })[0]; item = getPlayerModifierTypeOptions(1, scene.getParty(), [], { guaranteedModifierTiers: [ tier ], allowLuckUpgrades: false })[0];
} }
encounter.setDialogueToken("itemName", item.type.name); encounter.setDialogueToken("itemName", item.type.name);
encounter.misc = item; encounter.misc = item;
@ -137,7 +137,7 @@ export const FightOrFlightEncounter: MysteryEncounter =
// Pick battle // Pick battle
// Pokemon will randomly boost 1 stat by 2 stages // Pokemon will randomly boost 1 stat by 2 stages
const item = scene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption; const item = scene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption;
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ item ], fillRemaining: false });
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]); await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
} }
) )
@ -159,7 +159,7 @@ export const FightOrFlightEncounter: MysteryEncounter =
// Pick steal // Pick steal
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
const item = scene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption; const item = scene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption;
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ item ], fillRemaining: false });
// Use primaryPokemon to execute the thievery // Use primaryPokemon to execute the thievery
const primaryPokemon = encounter.options[1].primaryPokemon!; const primaryPokemon = encounter.options[1].primaryPokemon!;

View File

@ -197,7 +197,7 @@ async function summonPlayerPokemon(scene: BattleScene) {
const enemySpecies = getPokemonSpecies(Species.WOBBUFFET); const enemySpecies = getPokemonSpecies(Species.WOBBUFFET);
scene.currentBattle.enemyParty = []; scene.currentBattle.enemyParty = [];
const wobbuffet = scene.addEnemyPokemon(enemySpecies, encounter.misc.playerPokemon.level, TrainerSlot.NONE, false); const wobbuffet = scene.addEnemyPokemon(enemySpecies, encounter.misc.playerPokemon.level, TrainerSlot.NONE, false);
wobbuffet.ivs = [0, 0, 0, 0, 0, 0]; wobbuffet.ivs = [ 0, 0, 0, 0, 0, 0 ];
wobbuffet.setNature(Nature.MILD); wobbuffet.setNature(Nature.MILD);
wobbuffet.setAlpha(0); wobbuffet.setAlpha(0);
wobbuffet.setVisible(false); wobbuffet.setVisible(false);
@ -256,15 +256,15 @@ function handleNextTurn(scene: BattleScene) {
let isHealPhase = false; let isHealPhase = false;
if (healthRatio < 0.03) { if (healthRatio < 0.03) {
// Grand prize // Grand prize
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.MULTI_LENS], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.MULTI_LENS ], fillRemaining: false });
resultMessageKey = `${namespace}:best_result`; resultMessageKey = `${namespace}:best_result`;
} else if (healthRatio < 0.15) { } else if (healthRatio < 0.15) {
// 2nd prize // 2nd prize
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.SCOPE_LENS], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.SCOPE_LENS ], fillRemaining: false });
resultMessageKey = `${namespace}:great_result`; resultMessageKey = `${namespace}:great_result`;
} else if (healthRatio < 0.33) { } else if (healthRatio < 0.33) {
// 3rd prize // 3rd prize
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.WIDE_LENS], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.WIDE_LENS ], fillRemaining: false });
resultMessageKey = `${namespace}:good_result`; resultMessageKey = `${namespace}:good_result`;
} else { } else {
// No prize // No prize
@ -411,7 +411,7 @@ function hideShowmanIntroSprite(scene: BattleScene) {
// Slide the Wobbuffet and Game over slightly // Slide the Wobbuffet and Game over slightly
scene.tweens.add({ scene.tweens.add({
targets: [wobbuffet, carnivalGame], targets: [ wobbuffet, carnivalGame ],
x: "+=16", x: "+=16",
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
duration: 750 duration: 750

View File

@ -35,15 +35,15 @@ const WONDER_TRADE_SHINY_CHANCE = 512;
const MAX_WONDER_TRADE_SHINY_CHANCE = 4096; const MAX_WONDER_TRADE_SHINY_CHANCE = 4096;
const LEGENDARY_TRADE_POOLS = { const LEGENDARY_TRADE_POOLS = {
1: [Species.RATTATA, Species.PIDGEY, Species.WEEDLE], 1: [ Species.RATTATA, Species.PIDGEY, Species.WEEDLE ],
2: [Species.SENTRET, Species.HOOTHOOT, Species.LEDYBA], 2: [ Species.SENTRET, Species.HOOTHOOT, Species.LEDYBA ],
3: [Species.POOCHYENA, Species.ZIGZAGOON, Species.TAILLOW], 3: [ Species.POOCHYENA, Species.ZIGZAGOON, Species.TAILLOW ],
4: [Species.BIDOOF, Species.STARLY, Species.KRICKETOT], 4: [ Species.BIDOOF, Species.STARLY, Species.KRICKETOT ],
5: [Species.PATRAT, Species.PURRLOIN, Species.PIDOVE], 5: [ Species.PATRAT, Species.PURRLOIN, Species.PIDOVE ],
6: [Species.BUNNELBY, Species.LITLEO, Species.SCATTERBUG], 6: [ Species.BUNNELBY, Species.LITLEO, Species.SCATTERBUG ],
7: [Species.PIKIPEK, Species.YUNGOOS, Species.ROCKRUFF], 7: [ Species.PIKIPEK, Species.YUNGOOS, Species.ROCKRUFF ],
8: [Species.SKWOVET, Species.WOOLOO, Species.ROOKIDEE], 8: [ Species.SKWOVET, Species.WOOLOO, Species.ROOKIDEE ],
9: [Species.LECHONK, Species.FIDOUGH, Species.TAROUNTULA] 9: [ Species.LECHONK, Species.FIDOUGH, Species.TAROUNTULA ]
}; };
/** Exclude Paradox mons as they aren't considered legendary/mythical */ /** Exclude Paradox mons as they aren't considered legendary/mythical */
@ -387,11 +387,11 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
let item: ModifierTypeOption | null = null; let item: ModifierTypeOption | null = null;
// TMs excluded from possible rewards // TMs excluded from possible rewards
while (!item || item.type.id.includes("TM_")) { while (!item || item.type.id.includes("TM_")) {
item = getPlayerModifierTypeOptions(1, scene.getParty(), [], { guaranteedModifierTiers: [tier], allowLuckUpgrades: false })[0]; item = getPlayerModifierTypeOptions(1, scene.getParty(), [], { guaranteedModifierTiers: [ tier ], allowLuckUpgrades: false })[0];
} }
encounter.setDialogueToken("itemName", item.type.name); encounter.setDialogueToken("itemName", item.type.name);
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ item ], fillRemaining: false });
// Remove the chosen modifier if its stacks go to 0 // Remove the chosen modifier if its stacks go to 0
modifier.stackCount -= 1; modifier.stackCount -= 1;
@ -650,7 +650,7 @@ function doPokemonTradeSequence(scene: BattleScene, tradedPokemon: PlayerPokemon
// addPokeballOpenParticles(scene, tradedPokemon.x, tradedPokemon.y, tradedPokemon.pokeball); // addPokeballOpenParticles(scene, tradedPokemon.x, tradedPokemon.y, tradedPokemon.pokeball);
scene.tweens.add({ scene.tweens.add({
targets: [tradedPokemonTintSprite, tradedPokemonSprite], targets: [ tradedPokemonTintSprite, tradedPokemonSprite ],
duration: 500, duration: 500,
ease: "Sine.easeIn", ease: "Sine.easeIn",
scale: 0.25, scale: 0.25,
@ -726,7 +726,7 @@ function doPokemonTradeFlyBySequence(scene: BattleScene, tradedPokemonSprite: Ph
duration: FADE_DELAY, duration: FADE_DELAY,
onComplete: () => { onComplete: () => {
scene.tweens.add({ scene.tweens.add({
targets: [receivedPokemonSprite, tradedPokemonSprite], targets: [ receivedPokemonSprite, tradedPokemonSprite ],
y: tradeBaseBg.displayWidth / 2 - 100, y: tradeBaseBg.displayWidth / 2 - 100,
ease: "Cubic.easeInOut", ease: "Cubic.easeInOut",
duration: BASE_ANIM_DURATION * 3, duration: BASE_ANIM_DURATION * 3,

View File

@ -10,7 +10,7 @@ import { applyDamageToPokemon } from "#app/data/mystery-encounters/utils/encount
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
import {PokemonMove} from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon";
const OPTION_1_REQUIRED_MOVE = Moves.SURF; const OPTION_1_REQUIRED_MOVE = Moves.SURF;
const OPTION_2_REQUIRED_MOVE = Moves.FLY; const OPTION_2_REQUIRED_MOVE = Moves.FLY;

View File

@ -143,7 +143,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
// Spawn standard trainer battle with memory mushroom reward // Spawn standard trainer battle with memory mushroom reward
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0]; const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM], fillRemaining: true }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM ], fillRemaining: true });
// Seed offsets to remove possibility of different trainers having exact same teams // Seed offsets to remove possibility of different trainers having exact same teams
let ret; let ret;
@ -168,7 +168,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
// Spawn hard fight // Spawn hard fight
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1]; const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1];
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT], fillRemaining: true }); setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], fillRemaining: true });
// Seed offsets to remove possibility of different trainers having exact same teams // Seed offsets to remove possibility of different trainers having exact same teams
let ret; let ret;
@ -196,7 +196,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter =
// To avoid player level snowballing from picking this option // To avoid player level snowballing from picking this option
encounter.expMultiplier = 0.9; encounter.expMultiplier = 0.9;
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT], fillRemaining: true }); setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT ], fillRemaining: true });
// Seed offsets to remove possibility of different trainers having exact same teams // Seed offsets to remove possibility of different trainers having exact same teams
let ret; let ret;

View File

@ -76,12 +76,12 @@ export const MysteriousChestEncounter: MysteryEncounter =
species: getPokemonSpecies(Species.GIMMIGHOUL), species: getPokemonSpecies(Species.GIMMIGHOUL),
formIndex: 0, formIndex: 0,
isBoss: true, isBoss: true,
moveSet: [Moves.NASTY_PLOT, Moves.SHADOW_BALL, Moves.POWER_GEM, Moves.THIEF] moveSet: [ Moves.NASTY_PLOT, Moves.SHADOW_BALL, Moves.POWER_GEM, Moves.THIEF ]
} }
], ],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
encounter.setDialogueToken("gimmighoulName", getPokemonSpecies(Species.GIMMIGHOUL).getName()); encounter.setDialogueToken("gimmighoulName", getPokemonSpecies(Species.GIMMIGHOUL).getName());
encounter.setDialogueToken("trapPercent", TRAP_PERCENT.toString()); encounter.setDialogueToken("trapPercent", TRAP_PERCENT.toString());
@ -157,13 +157,13 @@ export const MysteriousChestEncounter: MysteryEncounter =
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT) { } else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT) {
// Choose between 2 ROGUE tier items (10%) // Choose between 2 ROGUE tier items (10%)
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE] }); setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE ]});
// Display result message then proceed to rewards // Display result message then proceed to rewards
queueEncounterMessage(scene, `${namespace}:option.1.great`); queueEncounterMessage(scene, `${namespace}:option.1.great`);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT - MASTER_REWARDS_PERCENT) { } else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT - MASTER_REWARDS_PERCENT) {
// Choose 1 MASTER tier item (5%) // Choose 1 MASTER tier item (5%)
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.MASTER] }); setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.MASTER ]});
// Display result message then proceed to rewards // Display result message then proceed to rewards
queueEncounterMessage(scene, `${namespace}:option.1.amazing`); queueEncounterMessage(scene, `${namespace}:option.1.amazing`);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);

View File

@ -94,7 +94,7 @@ export const PartTimerEncounter: MysteryEncounter =
// Calculation from Pokemon.calculateStats // Calculation from Pokemon.calculateStats
const baselineValue = Math.floor(((2 * 90 + 16) * pokemon.level) * 0.01) + 5; const baselineValue = Math.floor(((2 * 90 + 16) * pokemon.level) * 0.01) + 5;
const percentDiff = (pokemon.getStat(Stat.SPD) - baselineValue) / baselineValue; const percentDiff = (pokemon.getStat(Stat.SPD) - baselineValue) / baselineValue;
const moneyMultiplier = Math.min(Math.max(2.5 * (1+ percentDiff), 1), 4); const moneyMultiplier = Math.min(Math.max(2.5 * (1 + percentDiff), 1), 4);
encounter.misc = { encounter.misc = {
moneyMultiplier moneyMultiplier

View File

@ -23,7 +23,7 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/safariZone"; const namespace = "mysteryEncounters/safariZone";
const TRAINER_THROW_ANIMATION_TIMES = [512, 184, 768]; const TRAINER_THROW_ANIMATION_TIMES = [ 512, 184, 768 ];
const SAFARI_MONEY_MULTIPLIER = 2; const SAFARI_MONEY_MULTIPLIER = 2;
@ -260,7 +260,7 @@ async function summonSafariPokemon(scene: BattleScene) {
let enemySpecies; let enemySpecies;
let pokemon; let pokemon;
scene.executeWithSeedOffset(() => { scene.executeWithSeedOffset(() => {
enemySpecies = getPokemonSpecies(getRandomSpeciesByStarterTier([0, 5], undefined, undefined, false, false, false)); enemySpecies = getPokemonSpecies(getRandomSpeciesByStarterTier([ 0, 5 ], undefined, undefined, false, false, false));
const level = scene.currentBattle.getLevelForWave(); const level = scene.currentBattle.getLevelForWave();
enemySpecies = getPokemonSpecies(enemySpecies.getWildSpeciesForLevel(level, true, false, scene.gameMode)); enemySpecies = getPokemonSpecies(enemySpecies.getWildSpeciesForLevel(level, true, false, scene.gameMode));
pokemon = scene.addEnemyPokemon(enemySpecies, level, TrainerSlot.NONE, false); pokemon = scene.addEnemyPokemon(enemySpecies, level, TrainerSlot.NONE, false);

View File

@ -33,7 +33,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
.withEncounterTier(MysteryEncounterTier.COMMON) .withEncounterTier(MysteryEncounterTier.COMMON)
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
.withSceneRequirement(new MoneyRequirement(0, VITAMIN_DEALER_CHEAP_PRICE_MULTIPLIER)) // Must have the money for at least the cheap deal .withSceneRequirement(new MoneyRequirement(0, VITAMIN_DEALER_CHEAP_PRICE_MULTIPLIER)) // Must have the money for at least the cheap deal
.withPrimaryPokemonHealthRatioRequirement([0.51, 1]) // At least 1 Pokemon must have above half HP .withPrimaryPokemonHealthRatioRequirement([ 0.51, 1 ]) // At least 1 Pokemon must have above half HP
.withIntroSpriteConfigs([ .withIntroSpriteConfigs([
{ {
spriteKey: Species.KROOKODILE.toString(), spriteKey: Species.KROOKODILE.toString(),
@ -140,7 +140,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
chosenPokemon.nature = newNature; chosenPokemon.nature = newNature;
encounter.setDialogueToken("newNature", getNatureName(newNature)); encounter.setDialogueToken("newNature", getNatureName(newNature));
queueEncounterMessage(scene, `${namespace}:cheap_side_effects`); queueEncounterMessage(scene, `${namespace}:cheap_side_effects`);
setEncounterExp(scene, [chosenPokemon.id], 100); setEncounterExp(scene, [ chosenPokemon.id ], 100);
chosenPokemon.updateInfo(); chosenPokemon.updateInfo();
}) })
.build() .build()
@ -201,7 +201,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter =
const chosenPokemon = encounter.misc.chosenPokemon; const chosenPokemon = encounter.misc.chosenPokemon;
queueEncounterMessage(scene, `${namespace}:no_bad_effects`); queueEncounterMessage(scene, `${namespace}:no_bad_effects`);
setEncounterExp(scene, [chosenPokemon.id], 100); setEncounterExp(scene, [ chosenPokemon.id ], 100);
chosenPokemon.updateInfo(); chosenPokemon.updateInfo();
}) })

View File

@ -60,15 +60,15 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
const pokemonConfig: EnemyPokemonConfig = { const pokemonConfig: EnemyPokemonConfig = {
species: bossSpecies, species: bossSpecies,
isBoss: true, isBoss: true,
status: [StatusEffect.SLEEP, 5], // Extra turns on timer for Snorlax's start of fight moves status: [ StatusEffect.SLEEP, 5 ], // Extra turns on timer for Snorlax's start of fight moves
moveSet: [Moves.REST, Moves.SLEEP_TALK, Moves.CRUNCH, Moves.GIGA_IMPACT], moveSet: [ Moves.REST, Moves.SLEEP_TALK, Moves.CRUNCH, Moves.GIGA_IMPACT ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.SITRUS ]) as PokemonHeldItemModifierType,
stackCount: 2 stackCount: 2
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.ENIGMA ]) as PokemonHeldItemModifierType,
stackCount: 2 stackCount: 2
}, },
], ],
@ -77,12 +77,12 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
}; };
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
levelAdditiveModifier: 0.5, levelAdditiveModifier: 0.5,
pokemonConfigs: [pokemonConfig], pokemonConfigs: [ pokemonConfig ],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
// Load animations/sfx for Snorlax fight start moves // Load animations/sfx for Snorlax fight start moves
loadCustomMovesForEncounter(scene, [Moves.SNORE]); loadCustomMovesForEncounter(scene, [ Moves.SNORE ]);
encounter.setDialogueToken("snorlaxName", getPokemonSpecies(Species.SNORLAX).getName()); encounter.setDialogueToken("snorlaxName", getPokemonSpecies(Species.SNORLAX).getName());
@ -104,17 +104,17 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
async (scene: BattleScene) => { async (scene: BattleScene) => {
// Pick battle // Pick battle
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: true}); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.LEFTOVERS ], fillRemaining: true });
encounter.startOfBattleEffects.push( encounter.startOfBattleEffects.push(
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.SNORE), move: new PokemonMove(Moves.SNORE),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.SNORE), move: new PokemonMove(Moves.SNORE),
ignorePp: true ignorePp: true
}); });
@ -156,7 +156,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
.withOptionPhase(async (scene: BattleScene) => { .withOptionPhase(async (scene: BattleScene) => {
// Steal the Snorlax's Leftovers // Steal the Snorlax's Leftovers
const instance = scene.currentBattle.mysteryEncounter!; const instance = scene.currentBattle.mysteryEncounter!;
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.LEFTOVERS ], fillRemaining: false });
// Snorlax exp to Pokemon that did the stealing // Snorlax exp to Pokemon that did the stealing
setEncounterExp(scene, instance.primaryPokemon!.id, getPokemonSpecies(Species.SNORLAX).baseExp); setEncounterExp(scene, instance.primaryPokemon!.id, getPokemonSpecies(Species.SNORLAX).baseExp);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);

View File

@ -26,8 +26,8 @@ import { getEncounterPokemonLevelForWave, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIF
const namespace = "mysteryEncounters/teleportingHijinks"; const namespace = "mysteryEncounters/teleportingHijinks";
const MONEY_COST_MULTIPLIER = 1.75; const MONEY_COST_MULTIPLIER = 1.75;
const BIOME_CANDIDATES = [Biome.SPACE, Biome.FAIRY_CAVE, Biome.LABORATORY, Biome.ISLAND, Biome.WASTELAND, Biome.DOJO]; const BIOME_CANDIDATES = [ Biome.SPACE, Biome.FAIRY_CAVE, Biome.LABORATORY, Biome.ISLAND, Biome.WASTELAND, Biome.DOJO ];
const MACHINE_INTERFACING_TYPES = [Type.ELECTRIC, Type.STEEL]; const MACHINE_INTERFACING_TYPES = [ Type.ELECTRIC, Type.STEEL ];
/** /**
* Teleporting Hijinks encounter. * Teleporting Hijinks encounter.
@ -38,7 +38,7 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.TELEPORTING_HIJINKS) MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.TELEPORTING_HIJINKS)
.withEncounterTier(MysteryEncounterTier.COMMON) .withEncounterTier(MysteryEncounterTier.COMMON)
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
.withSceneRequirement(new WaveModulusRequirement([1, 2, 3], 10)) // Must be in first 3 waves after boss wave .withSceneRequirement(new WaveModulusRequirement([ 1, 2, 3 ], 10)) // Must be in first 3 waves after boss wave
.withSceneRequirement(new MoneyRequirement(0, MONEY_COST_MULTIPLIER)) // Must be able to pay teleport cost .withSceneRequirement(new MoneyRequirement(0, MONEY_COST_MULTIPLIER)) // Must be able to pay teleport cost
.withAutoHideIntroVisuals(false) .withAutoHideIntroVisuals(false)
.withCatchAllowed(true) .withCatchAllowed(true)
@ -145,9 +145,9 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
}], }],
}; };
const magnet = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.STEEL])!; const magnet = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.STEEL ])!;
const metalCoat = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.ELECTRIC])!; const metalCoat = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.ELECTRIC ])!;
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [magnet, metalCoat], fillRemaining: true }); setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ magnet, metalCoat ], fillRemaining: true });
transitionMysteryEncounterIntroVisuals(scene, true, true); transitionMysteryEncounterIntroVisuals(scene, true, true);
await initBattleWithEnemyConfig(scene, config); await initBattleWithEnemyConfig(scene, config);
} }
@ -163,7 +163,7 @@ async function doBiomeTransitionDialogueAndBattleInit(scene: BattleScene) {
// Show dialogue and transition biome // Show dialogue and transition biome
await showEncounterText(scene, `${namespace}:transport`); await showEncounterText(scene, `${namespace}:transport`);
await Promise.all([animateBiomeChange(scene, newBiome), transitionMysteryEncounterIntroVisuals(scene)]); await Promise.all([ animateBiomeChange(scene, newBiome), transitionMysteryEncounterIntroVisuals(scene) ]);
scene.playBgm(); scene.playBgm();
await showEncounterText(scene, `${namespace}:attacked`); await showEncounterText(scene, `${namespace}:attacked`);
@ -175,8 +175,8 @@ async function doBiomeTransitionDialogueAndBattleInit(scene: BattleScene) {
// Defense/Spd buffs below wave 50, +1 to all stats otherwise // Defense/Spd buffs below wave 50, +1 to all stats otherwise
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ? const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ?
[Stat.DEF, Stat.SPDEF, Stat.SPD] : [ Stat.DEF, Stat.SPDEF, Stat.SPD ] :
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]; [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ];
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
pokemonConfigs: [{ pokemonConfigs: [{
@ -184,7 +184,7 @@ async function doBiomeTransitionDialogueAndBattleInit(scene: BattleScene) {
species: bossSpecies, species: bossSpecies,
dataSource: new PokemonData(bossPokemon), dataSource: new PokemonData(bossPokemon),
isBoss: true, isBoss: true,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}:boss_enraged`); queueEncounterMessage(pokemon.scene, `${namespace}:boss_enraged`);
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
@ -198,7 +198,7 @@ async function doBiomeTransitionDialogueAndBattleInit(scene: BattleScene) {
async function animateBiomeChange(scene: BattleScene, nextBiome: Biome) { async function animateBiomeChange(scene: BattleScene, nextBiome: Biome) {
return new Promise<void>(resolve => { return new Promise<void>(resolve => {
scene.tweens.add({ scene.tweens.add({
targets: [scene.arenaEnemy, scene.lastEnemyTrainer], targets: [ scene.arenaEnemy, scene.lastEnemyTrainer ],
x: "+=300", x: "+=300",
duration: 2000, duration: 2000,
onComplete: () => { onComplete: () => {
@ -214,7 +214,7 @@ async function animateBiomeChange(scene: BattleScene, nextBiome: Biome) {
scene.arenaPlayerTransition.setVisible(true); scene.arenaPlayerTransition.setVisible(true);
scene.tweens.add({ scene.tweens.add({
targets: [scene.arenaPlayer, scene.arenaBgTransition, scene.arenaPlayerTransition], targets: [ scene.arenaPlayer, scene.arenaBgTransition, scene.arenaPlayerTransition ],
duration: 1000, duration: 1000,
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
alpha: (target: any) => target === scene.arenaPlayer ? 0 : 1, alpha: (target: any) => target === scene.arenaPlayer ? 0 : 1,

View File

@ -48,29 +48,29 @@ class BreederSpeciesEvolution {
} }
const POOL_1_POKEMON: (Species | BreederSpeciesEvolution)[][] = [ const POOL_1_POKEMON: (Species | BreederSpeciesEvolution)[][] = [
[Species.MUNCHLAX, new BreederSpeciesEvolution(Species.SNORLAX, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.MUNCHLAX, new BreederSpeciesEvolution(Species.SNORLAX, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.HAPPINY, new BreederSpeciesEvolution(Species.CHANSEY, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.BLISSEY, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.HAPPINY, new BreederSpeciesEvolution(Species.CHANSEY, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.BLISSEY, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.MAGBY, new BreederSpeciesEvolution(Species.MAGMAR, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.MAGMORTAR, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.MAGBY, new BreederSpeciesEvolution(Species.MAGMAR, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.MAGMORTAR, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.ELEKID, new BreederSpeciesEvolution(Species.ELECTABUZZ, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.ELECTIVIRE, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.ELEKID, new BreederSpeciesEvolution(Species.ELECTABUZZ, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.ELECTIVIRE, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.RIOLU, new BreederSpeciesEvolution(Species.LUCARIO, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.RIOLU, new BreederSpeciesEvolution(Species.LUCARIO, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.BUDEW, new BreederSpeciesEvolution(Species.ROSELIA, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.ROSERADE, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.BUDEW, new BreederSpeciesEvolution(Species.ROSELIA, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.ROSERADE, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.TOXEL, new BreederSpeciesEvolution(Species.TOXTRICITY, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.TOXEL, new BreederSpeciesEvolution(Species.TOXTRICITY, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.MIME_JR, new BreederSpeciesEvolution(Species.GALAR_MR_MIME, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.MR_RIME, FINAL_STAGE_EVOLUTION_WAVE)] [ Species.MIME_JR, new BreederSpeciesEvolution(Species.GALAR_MR_MIME, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.MR_RIME, FINAL_STAGE_EVOLUTION_WAVE) ]
]; ];
const POOL_2_POKEMON: (Species | BreederSpeciesEvolution)[][] = [ const POOL_2_POKEMON: (Species | BreederSpeciesEvolution)[][] = [
[Species.PICHU, new BreederSpeciesEvolution(Species.PIKACHU, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.RAICHU, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.PICHU, new BreederSpeciesEvolution(Species.PIKACHU, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.RAICHU, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.PICHU, new BreederSpeciesEvolution(Species.PIKACHU, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.ALOLA_RAICHU, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.PICHU, new BreederSpeciesEvolution(Species.PIKACHU, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.ALOLA_RAICHU, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.JYNX], [ Species.JYNX ],
[Species.TYROGUE, new BreederSpeciesEvolution(Species.HITMONLEE, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.TYROGUE, new BreederSpeciesEvolution(Species.HITMONLEE, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.TYROGUE, new BreederSpeciesEvolution(Species.HITMONCHAN, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.TYROGUE, new BreederSpeciesEvolution(Species.HITMONCHAN, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.TYROGUE, new BreederSpeciesEvolution(Species.HITMONTOP, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.TYROGUE, new BreederSpeciesEvolution(Species.HITMONTOP, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.IGGLYBUFF, new BreederSpeciesEvolution(Species.JIGGLYPUFF, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.WIGGLYTUFF, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.IGGLYBUFF, new BreederSpeciesEvolution(Species.JIGGLYPUFF, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.WIGGLYTUFF, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.AZURILL, new BreederSpeciesEvolution(Species.MARILL, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.AZUMARILL, FINAL_STAGE_EVOLUTION_WAVE)], [ Species.AZURILL, new BreederSpeciesEvolution(Species.MARILL, FIRST_STAGE_EVOLUTION_WAVE), new BreederSpeciesEvolution(Species.AZUMARILL, FINAL_STAGE_EVOLUTION_WAVE) ],
[Species.WYNAUT, new BreederSpeciesEvolution(Species.WOBBUFFET, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.WYNAUT, new BreederSpeciesEvolution(Species.WOBBUFFET, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.CHINGLING, new BreederSpeciesEvolution(Species.CHIMECHO, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.CHINGLING, new BreederSpeciesEvolution(Species.CHIMECHO, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.BONSLY, new BreederSpeciesEvolution(Species.SUDOWOODO, SECOND_STAGE_EVOLUTION_WAVE)], [ Species.BONSLY, new BreederSpeciesEvolution(Species.SUDOWOODO, SECOND_STAGE_EVOLUTION_WAVE) ],
[Species.MANTYKE, new BreederSpeciesEvolution(Species.MANTINE, SECOND_STAGE_EVOLUTION_WAVE)] [ Species.MANTYKE, new BreederSpeciesEvolution(Species.MANTINE, SECOND_STAGE_EVOLUTION_WAVE) ]
]; ];
/** /**
@ -138,7 +138,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter =
encounter.setDialogueToken("pokemon3Name", pokemon3.getNameToRender()); encounter.setDialogueToken("pokemon3Name", pokemon3.getNameToRender());
// Dialogue and egg calcs for Pokemon 1 // Dialogue and egg calcs for Pokemon 1
const [pokemon1CommonEggs, pokemon1RareEggs] = calculateEggRewardsForPokemon(pokemon1); const [ pokemon1CommonEggs, pokemon1RareEggs ] = calculateEggRewardsForPokemon(pokemon1);
let pokemon1Tooltip = getEncounterText(scene, `${namespace}:option.1.tooltip_base`)!; let pokemon1Tooltip = getEncounterText(scene, `${namespace}:option.1.tooltip_base`)!;
if (pokemon1RareEggs > 0) { if (pokemon1RareEggs > 0) {
const eggsText = i18next.t(`${namespace}:numEggs`, { count: pokemon1RareEggs, rarity: i18next.t("egg:greatTier") }); const eggsText = i18next.t(`${namespace}:numEggs`, { count: pokemon1RareEggs, rarity: i18next.t("egg:greatTier") });
@ -153,7 +153,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter =
encounter.options[0].dialogue!.buttonTooltip = pokemon1Tooltip; encounter.options[0].dialogue!.buttonTooltip = pokemon1Tooltip;
// Dialogue and egg calcs for Pokemon 2 // Dialogue and egg calcs for Pokemon 2
const [pokemon2CommonEggs, pokemon2RareEggs] = calculateEggRewardsForPokemon(pokemon2); const [ pokemon2CommonEggs, pokemon2RareEggs ] = calculateEggRewardsForPokemon(pokemon2);
let pokemon2Tooltip = getEncounterText(scene, `${namespace}:option.2.tooltip_base`)!; let pokemon2Tooltip = getEncounterText(scene, `${namespace}:option.2.tooltip_base`)!;
if (pokemon2RareEggs > 0) { if (pokemon2RareEggs > 0) {
const eggsText = i18next.t(`${namespace}:numEggs`, { count: pokemon2RareEggs, rarity: i18next.t("egg:greatTier") }); const eggsText = i18next.t(`${namespace}:numEggs`, { count: pokemon2RareEggs, rarity: i18next.t("egg:greatTier") });
@ -168,7 +168,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter =
encounter.options[1].dialogue!.buttonTooltip = pokemon2Tooltip; encounter.options[1].dialogue!.buttonTooltip = pokemon2Tooltip;
// Dialogue and egg calcs for Pokemon 3 // Dialogue and egg calcs for Pokemon 3
const [pokemon3CommonEggs, pokemon3RareEggs] = calculateEggRewardsForPokemon(pokemon3); const [ pokemon3CommonEggs, pokemon3RareEggs ] = calculateEggRewardsForPokemon(pokemon3);
let pokemon3Tooltip = getEncounterText(scene, `${namespace}:option.3.tooltip_base`)!; let pokemon3Tooltip = getEncounterText(scene, `${namespace}:option.3.tooltip_base`)!;
if (pokemon3RareEggs > 0) { if (pokemon3RareEggs > 0) {
const eggsText = i18next.t(`${namespace}:numEggs`, { count: pokemon3RareEggs, rarity: i18next.t("egg:greatTier") }); const eggsText = i18next.t(`${namespace}:numEggs`, { count: pokemon3RareEggs, rarity: i18next.t("egg:greatTier") });
@ -381,11 +381,11 @@ function getPartyConfig(scene: BattleScene): EnemyPartyConfig {
abilityIndex: 1, // Magic Guard abilityIndex: 1, // Magic Guard
shiny: false, shiny: false,
nature: Nature.ADAMANT, nature: Nature.ADAMANT,
moveSet: [Moves.METEOR_MASH, Moves.FIRE_PUNCH, Moves.ICE_PUNCH, Moves.THUNDER_PUNCH], moveSet: [ Moves.METEOR_MASH, Moves.FIRE_PUNCH, Moves.ICE_PUNCH, Moves.THUNDER_PUNCH ],
ivs: [31, 31, 31, 31, 31, 31], ivs: [ 31, 31, 31, 31, 31, 31 ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.TERA_SHARD, [Type.STEEL]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.TERA_SHARD, [ Type.STEEL ]) as PokemonHeldItemModifierType,
} }
] ]
} }
@ -402,8 +402,8 @@ function getPartyConfig(scene: BattleScene): EnemyPartyConfig {
shiny: true, shiny: true,
variant: 1, variant: 1,
nature: Nature.MODEST, nature: Nature.MODEST,
moveSet: [Moves.MOONBLAST, Moves.MYSTICAL_FIRE, Moves.ICE_BEAM, Moves.THUNDERBOLT], moveSet: [ Moves.MOONBLAST, Moves.MYSTICAL_FIRE, Moves.ICE_BEAM, Moves.THUNDERBOLT ],
ivs: [31, 31, 31, 31, 31, 31] ivs: [ 31, 31, 31, 31, 31, 31 ]
}, },
{ {
nickname: i18next.t(`${namespace}:cleffa_3_nickname`, { speciesName: getPokemonSpecies(cleffaSpecies).getName() }), nickname: i18next.t(`${namespace}:cleffa_3_nickname`, { speciesName: getPokemonSpecies(cleffaSpecies).getName() }),
@ -413,8 +413,8 @@ function getPartyConfig(scene: BattleScene): EnemyPartyConfig {
shiny: true, shiny: true,
variant: 2, variant: 2,
nature: Nature.BOLD, nature: Nature.BOLD,
moveSet: [Moves.TRI_ATTACK, Moves.STORED_POWER, Moves.TAKE_HEART, Moves.MOONLIGHT], moveSet: [ Moves.TRI_ATTACK, Moves.STORED_POWER, Moves.TAKE_HEART, Moves.MOONLIGHT ],
ivs: [31, 31, 31, 31, 31, 31] ivs: [ 31, 31, 31, 31, 31, 31 ]
}); });
} else { } else {
// Second member from pool 1 // Second member from pool 1
@ -425,12 +425,12 @@ function getPartyConfig(scene: BattleScene): EnemyPartyConfig {
baseConfig.pokemonConfigs!.push({ baseConfig.pokemonConfigs!.push({
species: getPokemonSpecies(pool1Species), species: getPokemonSpecies(pool1Species),
isBoss: false, isBoss: false,
ivs: [31, 31, 31, 31, 31, 31] ivs: [ 31, 31, 31, 31, 31, 31 ]
}, },
{ {
species: getPokemonSpecies(pool2Species), species: getPokemonSpecies(pool2Species),
isBoss: false, isBoss: false,
ivs: [31, 31, 31, 31, 31, 31] ivs: [ 31, 31, 31, 31, 31, 31 ]
}); });
} }
@ -468,7 +468,7 @@ function calculateEggRewardsForPokemon(pokemon: PlayerPokemon): [number, number]
// 1 Common egg for every point leftover // 1 Common egg for every point leftover
const numCommons = totalPoints % 6; const numCommons = totalPoints % 6;
return [numCommons, numRares]; return [ numCommons, numRares ];
} }
function getEggOptions(scene: BattleScene, commonEggs: number, rareEggs: number) { function getEggOptions(scene: BattleScene, commonEggs: number, rareEggs: number) {

View File

@ -59,12 +59,12 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter =
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
let species = getPokemonSpecies(getRandomSpeciesByStarterTier([0, 5], undefined, undefined, false, false, false)); let species = getPokemonSpecies(getRandomSpeciesByStarterTier([ 0, 5 ], undefined, undefined, false, false, false));
let tries = 0; let tries = 0;
// Reroll any species that don't have HAs // Reroll any species that don't have HAs
while ((isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE) && tries < 5) { while ((isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE) && tries < 5) {
species = getPokemonSpecies(getRandomSpeciesByStarterTier([0, 5], undefined, undefined, false, false, false)); species = getPokemonSpecies(getRandomSpeciesByStarterTier([ 0, 5 ], undefined, undefined, false, false, false));
tries++; tries++;
} }

View File

@ -81,37 +81,37 @@ export const TheStrongStuffEncounter: MysteryEncounter =
bossSegments: 5, bossSegments: 5,
mysteryEncounterPokemonData: new MysteryEncounterPokemonData({ spriteScale: 1.25 }), mysteryEncounterPokemonData: new MysteryEncounterPokemonData({ spriteScale: 1.25 }),
nature: Nature.BOLD, nature: Nature.BOLD,
moveSet: [Moves.INFESTATION, Moves.SALT_CURE, Moves.GASTRO_ACID, Moves.HEAL_ORDER], moveSet: [ Moves.INFESTATION, Moves.SALT_CURE, Moves.GASTRO_ACID, Moves.HEAL_ORDER ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.SITRUS ]) as PokemonHeldItemModifierType
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.ENIGMA ]) as PokemonHeldItemModifierType
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.APICOT]) as PokemonHeldItemModifierType modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.APICOT ]) as PokemonHeldItemModifierType
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.GANLON]) as PokemonHeldItemModifierType modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.GANLON ]) as PokemonHeldItemModifierType
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.LUM ]) as PokemonHeldItemModifierType,
stackCount: 2 stackCount: 2
} }
], ],
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}:option.2.stat_boost`); queueEncounterMessage(pokemon.scene, `${namespace}:option.2.stat_boost`);
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [Stat.DEF, Stat.SPDEF], 2)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.DEF, Stat.SPDEF ], 2));
} }
} }
], ],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
loadCustomMovesForEncounter(scene, [Moves.GASTRO_ACID, Moves.STEALTH_ROCK]); loadCustomMovesForEncounter(scene, [ Moves.GASTRO_ACID, Moves.STEALTH_ROCK ]);
encounter.setDialogueToken("shuckleName", getPokemonSpecies(Species.SHUCKLE).getName()); encounter.setDialogueToken("shuckleName", getPokemonSpecies(Species.SHUCKLE).getName());
@ -184,17 +184,17 @@ export const TheStrongStuffEncounter: MysteryEncounter =
async (scene: BattleScene) => { async (scene: BattleScene) => {
// Pick battle // Pick battle
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.SOUL_DEW], fillRemaining: true }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.SOUL_DEW ], fillRemaining: true });
encounter.startOfBattleEffects.push( encounter.startOfBattleEffects.push(
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.GASTRO_ACID), move: new PokemonMove(Moves.GASTRO_ACID),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.STEALTH_ROCK), move: new PokemonMove(Moves.STEALTH_ROCK),
ignorePp: true ignorePp: true
}); });

View File

@ -131,7 +131,7 @@ export const TheWinstrateChallengeEncounter: MysteryEncounter =
async (scene: BattleScene) => { async (scene: BattleScene) => {
// Refuse the challenge, they full heal the party and give the player a Rarer Candy // Refuse the challenge, they full heal the party and give the player a Rarer Candy
scene.unshiftPhase(new PartyHealPhase(scene, true)); scene.unshiftPhase(new PartyHealPhase(scene, true));
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.RARER_CANDY], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.RARER_CANDY ], fillRemaining: false });
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} }
) )
@ -154,7 +154,7 @@ async function spawnNextTrainerOrEndEncounter(scene: BattleScene) {
scene.ui.clearText(); // Clears "Winstrate" title from screen as rewards get animated in scene.ui.clearText(); // Clears "Winstrate" title from screen as rewards get animated in
const machoBrace = generateModifierTypeOption(scene, modifierTypes.MYSTERY_ENCOUNTER_MACHO_BRACE)!; const machoBrace = generateModifierTypeOption(scene, modifierTypes.MYSTERY_ENCOUNTER_MACHO_BRACE)!;
machoBrace.type.tier = ModifierTier.MASTER; machoBrace.type.tier = ModifierTier.MASTER;
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [machoBrace], fillRemaining: false }); setEncounterRewards(scene, { guaranteedModifierTypeOptions: [ machoBrace ], fillRemaining: false });
encounter.doContinueEncounter = undefined; encounter.doContinueEncounter = undefined;
leaveEncounterWithoutBattle(scene, false, MysteryEncounterMode.NO_BATTLE); leaveEncounterWithoutBattle(scene, false, MysteryEncounterMode.NO_BATTLE);
} else { } else {
@ -232,7 +232,7 @@ function getVictorTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 0, // Guts abilityIndex: 0, // Guts
nature: Nature.ADAMANT, nature: Nature.ADAMANT,
moveSet: [Moves.FACADE, Moves.BRAVE_BIRD, Moves.PROTECT, Moves.QUICK_ATTACK], moveSet: [ Moves.FACADE, Moves.BRAVE_BIRD, Moves.PROTECT, Moves.QUICK_ATTACK ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.FLAME_ORB) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.FLAME_ORB) as PokemonHeldItemModifierType,
@ -250,7 +250,7 @@ function getVictorTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 1, // Guts abilityIndex: 1, // Guts
nature: Nature.ADAMANT, nature: Nature.ADAMANT,
moveSet: [Moves.FACADE, Moves.OBSTRUCT, Moves.NIGHT_SLASH, Moves.FIRE_PUNCH], moveSet: [ Moves.FACADE, Moves.OBSTRUCT, Moves.NIGHT_SLASH, Moves.FIRE_PUNCH ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.FLAME_ORB) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.FLAME_ORB) as PokemonHeldItemModifierType,
@ -276,7 +276,7 @@ function getVictoriaTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 0, // Natural Cure abilityIndex: 0, // Natural Cure
nature: Nature.CALM, nature: Nature.CALM,
moveSet: [Moves.SYNTHESIS, Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.SLEEP_POWDER], moveSet: [ Moves.SYNTHESIS, Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.SLEEP_POWDER ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.SOUL_DEW) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.SOUL_DEW) as PokemonHeldItemModifierType,
@ -294,15 +294,15 @@ function getVictoriaTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
formIndex: 1, formIndex: 1,
nature: Nature.TIMID, nature: Nature.TIMID,
moveSet: [Moves.PSYSHOCK, Moves.MOONBLAST, Moves.SHADOW_BALL, Moves.WILL_O_WISP], moveSet: [ Moves.PSYSHOCK, Moves.MOONBLAST, Moves.SHADOW_BALL, Moves.WILL_O_WISP ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.PSYCHIC]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.PSYCHIC ]) as PokemonHeldItemModifierType,
stackCount: 1, stackCount: 1,
isTransferable: false isTransferable: false
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.FAIRY]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [ Type.FAIRY ]) as PokemonHeldItemModifierType,
stackCount: 1, stackCount: 1,
isTransferable: false isTransferable: false
} }
@ -321,15 +321,15 @@ function getViviTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 3, // Lightning Rod abilityIndex: 3, // Lightning Rod
nature: Nature.ADAMANT, nature: Nature.ADAMANT,
moveSet: [Moves.WATERFALL, Moves.MEGAHORN, Moves.KNOCK_OFF, Moves.REST], moveSet: [ Moves.WATERFALL, Moves.MEGAHORN, Moves.KNOCK_OFF, Moves.REST ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.LUM ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
isTransferable: false isTransferable: false
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [Stat.HP]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [ Stat.HP ]) as PokemonHeldItemModifierType,
stackCount: 4, stackCount: 4,
isTransferable: false isTransferable: false
} }
@ -340,10 +340,10 @@ function getViviTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 1, // Poison Heal abilityIndex: 1, // Poison Heal
nature: Nature.JOLLY, nature: Nature.JOLLY,
moveSet: [Moves.SPORE, Moves.SWORDS_DANCE, Moves.SEED_BOMB, Moves.DRAIN_PUNCH], moveSet: [ Moves.SPORE, Moves.SWORDS_DANCE, Moves.SEED_BOMB, Moves.DRAIN_PUNCH ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [Stat.HP]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [ Stat.HP ]) as PokemonHeldItemModifierType,
stackCount: 4, stackCount: 4,
isTransferable: false isTransferable: false
}, },
@ -358,7 +358,7 @@ function getViviTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
formIndex: 1, formIndex: 1,
nature: Nature.CALM, nature: Nature.CALM,
moveSet: [Moves.EARTH_POWER, Moves.FIRE_BLAST, Moves.YAWN, Moves.PROTECT], moveSet: [ Moves.EARTH_POWER, Moves.FIRE_BLAST, Moves.YAWN, Moves.PROTECT ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType,
@ -380,7 +380,7 @@ function getVickyTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
formIndex: 1, formIndex: 1,
nature: Nature.IMPISH, nature: Nature.IMPISH,
moveSet: [Moves.AXE_KICK, Moves.ICE_PUNCH, Moves.ZEN_HEADBUTT, Moves.BULLET_PUNCH], moveSet: [ Moves.AXE_KICK, Moves.ICE_PUNCH, Moves.ZEN_HEADBUTT, Moves.BULLET_PUNCH ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType,
@ -401,10 +401,10 @@ function getVitoTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 0, // Soundproof abilityIndex: 0, // Soundproof
nature: Nature.MODEST, nature: Nature.MODEST,
moveSet: [Moves.THUNDERBOLT, Moves.GIGA_DRAIN, Moves.FOUL_PLAY, Moves.THUNDER_WAVE], moveSet: [ Moves.THUNDERBOLT, Moves.GIGA_DRAIN, Moves.FOUL_PLAY, Moves.THUNDER_WAVE ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [Stat.SPD]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BASE_STAT_BOOSTER, [ Stat.SPD ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
isTransferable: false isTransferable: false
} }
@ -415,50 +415,50 @@ function getVitoTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 2, // Gluttony abilityIndex: 2, // Gluttony
nature: Nature.QUIET, nature: Nature.QUIET,
moveSet: [Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.ICE_BEAM, Moves.EARTHQUAKE], moveSet: [ Moves.SLUDGE_BOMB, Moves.GIGA_DRAIN, Moves.ICE_BEAM, Moves.EARTHQUAKE ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.SITRUS ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.APICOT]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.APICOT ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.GANLON]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.GANLON ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.STARF]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.STARF ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.SALAC]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.SALAC ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LUM]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.LUM ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LANSAT]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.LANSAT ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LIECHI]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.LIECHI ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.PETAYA]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.PETAYA ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.ENIGMA ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
}, },
{ {
modifier: generateModifierType(scene, modifierTypes.BERRY, [BerryType.LEPPA]) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.BERRY, [ BerryType.LEPPA ]) as PokemonHeldItemModifierType,
stackCount: 2, stackCount: 2,
} }
] ]
@ -468,7 +468,7 @@ function getVitoTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 2, // Tangled Feet abilityIndex: 2, // Tangled Feet
nature: Nature.JOLLY, nature: Nature.JOLLY,
moveSet: [Moves.DRILL_PECK, Moves.QUICK_ATTACK, Moves.THRASH, Moves.KNOCK_OFF], moveSet: [ Moves.DRILL_PECK, Moves.QUICK_ATTACK, Moves.THRASH, Moves.KNOCK_OFF ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.KINGS_ROCK) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.KINGS_ROCK) as PokemonHeldItemModifierType,
@ -482,7 +482,7 @@ function getVitoTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
formIndex: 1, formIndex: 1,
nature: Nature.BOLD, nature: Nature.BOLD,
moveSet: [Moves.PSYCHIC, Moves.SHADOW_BALL, Moves.FOCUS_BLAST, Moves.THUNDERBOLT], moveSet: [ Moves.PSYCHIC, Moves.SHADOW_BALL, Moves.FOCUS_BLAST, Moves.THUNDERBOLT ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.WIDE_LENS) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.WIDE_LENS) as PokemonHeldItemModifierType,
@ -496,7 +496,7 @@ function getVitoTrainerConfig(scene: BattleScene): EnemyPartyConfig {
isBoss: false, isBoss: false,
abilityIndex: 0, // Sheer Force abilityIndex: 0, // Sheer Force
nature: Nature.IMPISH, nature: Nature.IMPISH,
moveSet: [Moves.EARTHQUAKE, Moves.U_TURN, Moves.FLARE_BLITZ, Moves.ROCK_SLIDE], moveSet: [ Moves.EARTHQUAKE, Moves.U_TURN, Moves.FLARE_BLITZ, Moves.ROCK_SLIDE ],
modifierConfigs: [ modifierConfigs: [
{ {
modifier: generateModifierType(scene, modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType, modifier: generateModifierType(scene, modifierTypes.QUICK_CLAW) as PokemonHeldItemModifierType,

View File

@ -67,17 +67,17 @@ export const TrashToTreasureEncounter: MysteryEncounter =
isBoss: true, isBoss: true,
formIndex: 1, // Gmax formIndex: 1, // Gmax
bossSegmentModifier: 1, // +1 Segment from normal bossSegmentModifier: 1, // +1 Segment from normal
moveSet: [Moves.PAYBACK, Moves.GUNK_SHOT, Moves.STOMPING_TANTRUM, Moves.DRAIN_PUNCH] moveSet: [ Moves.PAYBACK, Moves.GUNK_SHOT, Moves.STOMPING_TANTRUM, Moves.DRAIN_PUNCH ]
}; };
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
levelAdditiveModifier: 1, levelAdditiveModifier: 1,
pokemonConfigs: [pokemonConfig], pokemonConfigs: [ pokemonConfig ],
disableSwitch: true disableSwitch: true
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
// Load animations/sfx for Garbodor fight start moves // Load animations/sfx for Garbodor fight start moves
loadCustomMovesForEncounter(scene, [Moves.TOXIC, Moves.AMNESIA]); loadCustomMovesForEncounter(scene, [ Moves.TOXIC, Moves.AMNESIA ]);
scene.loadSe("PRSFX- Dig2", "battle_anims", "PRSFX- Dig2.wav"); scene.loadSe("PRSFX- Dig2", "battle_anims", "PRSFX- Dig2.wav");
scene.loadSe("PRSFX- Venom Drench", "battle_anims", "PRSFX- Venom Drench.wav"); scene.loadSe("PRSFX- Venom Drench", "battle_anims", "PRSFX- Venom Drench.wav");
@ -107,7 +107,7 @@ export const TrashToTreasureEncounter: MysteryEncounter =
transitionMysteryEncounterIntroVisuals(scene); transitionMysteryEncounterIntroVisuals(scene);
await tryApplyDigRewardItems(scene); await tryApplyDigRewardItems(scene);
const blackSludge = generateModifierType(scene, modifierTypes.MYSTERY_ENCOUNTER_BLACK_SLUDGE, [SHOP_ITEM_COST_MULTIPLIER]); const blackSludge = generateModifierType(scene, modifierTypes.MYSTERY_ENCOUNTER_BLACK_SLUDGE, [ SHOP_ITEM_COST_MULTIPLIER ]);
const modifier = blackSludge?.newModifier(); const modifier = blackSludge?.newModifier();
if (modifier) { if (modifier) {
await scene.addModifier(modifier, false, false, false, true); await scene.addModifier(modifier, false, false, false, true);
@ -139,17 +139,17 @@ export const TrashToTreasureEncounter: MysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT], fillRemaining: true }); setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT ], fillRemaining: true });
encounter.startOfBattleEffects.push( encounter.startOfBattleEffects.push(
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [ BattlerIndex.PLAYER ],
move: new PokemonMove(Moves.TOXIC), move: new PokemonMove(Moves.TOXIC),
ignorePp: true ignorePp: true
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.ENEMY], targets: [ BattlerIndex.ENEMY ],
move: new PokemonMove(Moves.AMNESIA), move: new PokemonMove(Moves.AMNESIA),
ignorePp: true ignorePp: true
}); });

View File

@ -74,8 +74,8 @@ export const UncommonBreedEncounter: MysteryEncounter =
// Defense/Spd buffs below wave 50, +1 to all stats otherwise // Defense/Spd buffs below wave 50, +1 to all stats otherwise
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ? const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ?
[Stat.DEF, Stat.SPDEF, Stat.SPD] : [ Stat.DEF, Stat.SPDEF, Stat.SPD ] :
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]; [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ];
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
pokemonConfigs: [{ pokemonConfigs: [{
@ -83,14 +83,14 @@ export const UncommonBreedEncounter: MysteryEncounter =
species: species, species: species,
dataSource: new PokemonData(pokemon), dataSource: new PokemonData(pokemon),
isBoss: false, isBoss: false,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [ BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON ],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}:option.1.stat_boost`); queueEncounterMessage(pokemon.scene, `${namespace}:option.1.stat_boost`);
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
} }
}], }],
}; };
encounter.enemyPartyConfigs = [config]; encounter.enemyPartyConfigs = [ config ];
const { spriteKey, fileRoot } = getSpriteKeysFromPokemon(pokemon); const { spriteKey, fileRoot } = getSpriteKeysFromPokemon(pokemon);
encounter.spriteConfigs = [ encounter.spriteConfigs = [
@ -152,7 +152,7 @@ export const UncommonBreedEncounter: MysteryEncounter =
encounter.startOfBattleEffects.push( encounter.startOfBattleEffects.push(
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [target], targets: [ target ],
move: pokemonMove, move: pokemonMove,
ignorePp: true ignorePp: true
}); });
@ -181,7 +181,7 @@ export const UncommonBreedEncounter: MysteryEncounter =
// Remove 4 random berries from player's party // Remove 4 random berries from player's party
// Get all player berry items, remove from party, and store reference // Get all player berry items, remove from party, and store reference
const berryItems: BerryModifier[]= scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[]; const berryItems: BerryModifier[] = scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
for (let i = 0; i < 4; i++) { for (let i = 0; i < 4; i++) {
const index = randSeedInt(berryItems.length); const index = randSeedInt(berryItems.length);
const randBerry = berryItems[index]; const randBerry = berryItems[index];

View File

@ -89,12 +89,12 @@ const PERCENT_LEVEL_LOSS_ON_REFUSE = 12.5;
* Value ranges of the resulting species BST transformations after adding values to original species * Value ranges of the resulting species BST transformations after adding values to original species
* 2 Pokemon in the party use this range * 2 Pokemon in the party use this range
*/ */
const HIGH_BST_TRANSFORM_BASE_VALUES: [number, number] = [90, 110]; const HIGH_BST_TRANSFORM_BASE_VALUES: [number, number] = [ 90, 110 ];
/** /**
* Value ranges of the resulting species BST transformations after adding values to original species * Value ranges of the resulting species BST transformations after adding values to original species
* All remaining Pokemon in the party use this range * All remaining Pokemon in the party use this range
*/ */
const STANDARD_BST_TRANSFORM_BASE_VALUES: [number, number] = [40, 50]; const STANDARD_BST_TRANSFORM_BASE_VALUES: [number, number] = [ 40, 50 ];
/** /**
* Weird Dream encounter. * Weird Dream encounter.
@ -192,7 +192,7 @@ export const WeirdDreamEncounter: MysteryEncounter =
await showEncounterText(scene, `${namespace}:option.1.dream_complete`); await showEncounterText(scene, `${namespace}:option.1.dream_complete`);
await doNewTeamPostProcess(scene, transformations); await doNewTeamPostProcess(scene, transformations);
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.MEMORY_MUSHROOM, modifierTypes.ROGUE_BALL, modifierTypes.MINT, modifierTypes.MINT]}); setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.MEMORY_MUSHROOM, modifierTypes.ROGUE_BALL, modifierTypes.MINT, modifierTypes.MINT ]});
leaveEncounterWithoutBattle(scene, true); leaveEncounterWithoutBattle(scene, true);
}) })
.build() .build()
@ -372,7 +372,7 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon
// Randomize the second type of the pokemon // Randomize the second type of the pokemon
// If the pokemon does not normally have a second type, it will gain 1 // If the pokemon does not normally have a second type, it will gain 1
const newTypes = [newPokemon.getTypes()[0]]; const newTypes = [ newPokemon.getTypes()[0] ];
let newType = randSeedInt(18) as Type; let newType = randSeedInt(18) as Type;
while (newType === newTypes[0]) { while (newType === newTypes[0]) {
newType = randSeedInt(18) as Type; newType = randSeedInt(18) as Type;
@ -390,14 +390,14 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon
// Any pokemon that is at or below 450 BST gets +20 permanent BST to 3 stats: HP (halved, +10), lowest of Atk/SpAtk, and lowest of Def/SpDef // Any pokemon that is at or below 450 BST gets +20 permanent BST to 3 stats: HP (halved, +10), lowest of Atk/SpAtk, and lowest of Def/SpDef
if (newPokemon.getSpeciesForm().getBaseStatTotal() <= GAIN_OLD_GATEAU_ITEM_BST_THRESHOLD) { if (newPokemon.getSpeciesForm().getBaseStatTotal() <= GAIN_OLD_GATEAU_ITEM_BST_THRESHOLD) {
const stats: Stat[] = [Stat.HP]; const stats: Stat[] = [ Stat.HP ];
const baseStats = newPokemon.getSpeciesForm().baseStats.slice(0); const baseStats = newPokemon.getSpeciesForm().baseStats.slice(0);
// Attack or SpAtk // Attack or SpAtk
stats.push(baseStats[Stat.ATK] < baseStats[Stat.SPATK] ? Stat.ATK : Stat.SPATK); stats.push(baseStats[Stat.ATK] < baseStats[Stat.SPATK] ? Stat.ATK : Stat.SPATK);
// Def or SpDef // Def or SpDef
stats.push(baseStats[Stat.DEF] < baseStats[Stat.SPDEF] ? Stat.DEF : Stat.SPDEF); stats.push(baseStats[Stat.DEF] < baseStats[Stat.SPDEF] ? Stat.DEF : Stat.SPDEF);
const modType = modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU() const modType = modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU()
.generateType(scene.getParty(), [20, stats]) .generateType(scene.getParty(), [ 20, stats ])
?.withIdFromFunc(modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU); ?.withIdFromFunc(modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU);
const modifier = modType?.newModifier(newPokemon); const modifier = modType?.newModifier(newPokemon);
if (modifier) { if (modifier) {
@ -553,7 +553,7 @@ async function addEggMoveToNewPokemonMoveset(scene: BattleScene, newPokemon: Pla
let eggMoveIndex: null | number = null; let eggMoveIndex: null | number = null;
const eggMoves = newPokemon.getEggMoves()?.slice(0); const eggMoves = newPokemon.getEggMoves()?.slice(0);
if (eggMoves) { if (eggMoves) {
const eggMoveIndices = randSeedShuffle([0, 1, 2, 3]); const eggMoveIndices = randSeedShuffle([ 0, 1, 2, 3 ]);
let randomEggMoveIndex = eggMoveIndices.pop(); let randomEggMoveIndex = eggMoveIndices.pop();
let randomEggMove = !isNullOrUndefined(randomEggMoveIndex) ? eggMoves[randomEggMoveIndex] : null; let randomEggMove = !isNullOrUndefined(randomEggMoveIndex) ? eggMoves[randomEggMoveIndex] : null;
let retries = 0; let retries = 0;

View File

@ -147,7 +147,7 @@ export class PreviousEncounterRequirement extends EncounterSceneRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["previousEncounter", scene.mysteryEncounterSaveData.encounteredEvents.find(e => e.type === this.previousEncounterRequirement)?.[0].toString() ?? ""]; return [ "previousEncounter", scene.mysteryEncounterSaveData.encounteredEvents.find(e => e.type === this.previousEncounterRequirement)?.[0].toString() ?? "" ];
} }
} }
@ -175,7 +175,7 @@ export class WaveRangeRequirement extends EncounterSceneRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["waveIndex", scene.currentBattle.waveIndex.toString()]; return [ "waveIndex", scene.currentBattle.waveIndex.toString() ];
} }
} }
@ -204,7 +204,7 @@ export class WaveModulusRequirement extends EncounterSceneRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["waveIndex", scene.currentBattle.waveIndex.toString()]; return [ "waveIndex", scene.currentBattle.waveIndex.toString() ];
} }
} }
@ -213,7 +213,7 @@ export class TimeOfDayRequirement extends EncounterSceneRequirement {
constructor(timeOfDay: TimeOfDay | TimeOfDay[]) { constructor(timeOfDay: TimeOfDay | TimeOfDay[]) {
super(); super();
this.requiredTimeOfDay = Array.isArray(timeOfDay) ? timeOfDay : [timeOfDay]; this.requiredTimeOfDay = Array.isArray(timeOfDay) ? timeOfDay : [ timeOfDay ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -226,7 +226,7 @@ export class TimeOfDayRequirement extends EncounterSceneRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["timeOfDay", TimeOfDay[scene.arena.getTimeOfDay()].toLocaleLowerCase()]; return [ "timeOfDay", TimeOfDay[scene.arena.getTimeOfDay()].toLocaleLowerCase() ];
} }
} }
@ -235,7 +235,7 @@ export class WeatherRequirement extends EncounterSceneRequirement {
constructor(weather: WeatherType | WeatherType[]) { constructor(weather: WeatherType | WeatherType[]) {
super(); super();
this.requiredWeather = Array.isArray(weather) ? weather : [weather]; this.requiredWeather = Array.isArray(weather) ? weather : [ weather ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -253,7 +253,7 @@ export class WeatherRequirement extends EncounterSceneRequirement {
if (!isNullOrUndefined(currentWeather)) { if (!isNullOrUndefined(currentWeather)) {
token = WeatherType[currentWeather].replace("_", " ").toLocaleLowerCase(); token = WeatherType[currentWeather].replace("_", " ").toLocaleLowerCase();
} }
return ["weather", token]; return [ "weather", token ];
} }
} }
@ -285,7 +285,7 @@ export class PartySizeRequirement extends EncounterSceneRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["partySize", scene.getParty().length.toString()]; return [ "partySize", scene.getParty().length.toString() ];
} }
} }
@ -296,7 +296,7 @@ export class PersistentModifierRequirement extends EncounterSceneRequirement {
constructor(heldItem: string | string[], minNumberOfItems: number = 1) { constructor(heldItem: string | string[], minNumberOfItems: number = 1) {
super(); super();
this.minNumberOfItems = minNumberOfItems; this.minNumberOfItems = minNumberOfItems;
this.requiredHeldItemModifiers = Array.isArray(heldItem) ? heldItem : [heldItem]; this.requiredHeldItemModifiers = Array.isArray(heldItem) ? heldItem : [ heldItem ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -318,7 +318,7 @@ export class PersistentModifierRequirement extends EncounterSceneRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["requiredItem", this.requiredHeldItemModifiers[0]]; return [ "requiredItem", this.requiredHeldItemModifiers[0] ];
} }
} }
@ -346,7 +346,7 @@ export class MoneyRequirement extends EncounterSceneRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const value = this.scalingMultiplier > 0 ? scene.getWaveMoneyAmount(this.scalingMultiplier).toString() : this.requiredMoney.toString(); const value = this.scalingMultiplier > 0 ? scene.getWaveMoneyAmount(this.scalingMultiplier).toString() : this.requiredMoney.toString();
return ["money", value]; return [ "money", value ];
} }
} }
@ -359,7 +359,7 @@ export class SpeciesRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredSpecies = Array.isArray(species) ? species : [species]; this.requiredSpecies = Array.isArray(species) ? species : [ species ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -381,9 +381,9 @@ export class SpeciesRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
if (pokemon?.species.speciesId && this.requiredSpecies.includes(pokemon.species.speciesId)) { if (pokemon?.species.speciesId && this.requiredSpecies.includes(pokemon.species.speciesId)) {
return ["species", Species[pokemon.species.speciesId]]; return [ "species", Species[pokemon.species.speciesId] ];
} }
return ["species", ""]; return [ "species", "" ];
} }
} }
@ -397,7 +397,7 @@ export class NatureRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredNature = Array.isArray(nature) ? nature : [nature]; this.requiredNature = Array.isArray(nature) ? nature : [ nature ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -419,9 +419,9 @@ export class NatureRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
if (!isNullOrUndefined(pokemon?.nature) && this.requiredNature.includes(pokemon.nature)) { if (!isNullOrUndefined(pokemon?.nature) && this.requiredNature.includes(pokemon.nature)) {
return ["nature", Nature[pokemon.nature]]; return [ "nature", Nature[pokemon.nature] ];
} }
return ["nature", ""]; return [ "nature", "" ];
} }
} }
@ -436,7 +436,7 @@ export class TypeRequirement extends EncounterPokemonRequirement {
this.excludeFainted = excludeFainted; this.excludeFainted = excludeFainted;
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredType = Array.isArray(type) ? type : [type]; this.requiredType = Array.isArray(type) ? type : [ type ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -465,9 +465,9 @@ export class TypeRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const includedTypes = this.requiredType.filter((ty) => pokemon?.getTypes().includes(ty)); const includedTypes = this.requiredType.filter((ty) => pokemon?.getTypes().includes(ty));
if (includedTypes.length > 0) { if (includedTypes.length > 0) {
return ["type", Type[includedTypes[0]]]; return [ "type", Type[includedTypes[0]] ];
} }
return ["type", ""]; return [ "type", "" ];
} }
} }
@ -481,7 +481,7 @@ export class MoveRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredMoves = Array.isArray(moves) ? moves : [moves]; this.requiredMoves = Array.isArray(moves) ? moves : [ moves ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -504,9 +504,9 @@ export class MoveRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const includedMoves = pokemon?.moveset.filter((move) => move?.moveId && this.requiredMoves.includes(move.moveId)); const includedMoves = pokemon?.moveset.filter((move) => move?.moveId && this.requiredMoves.includes(move.moveId));
if (includedMoves && includedMoves.length > 0 && includedMoves[0]) { if (includedMoves && includedMoves.length > 0 && includedMoves[0]) {
return ["move", includedMoves[0].getName()]; return [ "move", includedMoves[0].getName() ];
} }
return ["move", ""]; return [ "move", "" ];
} }
} }
@ -525,7 +525,7 @@ export class CompatibleMoveRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredMoves = Array.isArray(learnableMove) ? learnableMove : [learnableMove]; this.requiredMoves = Array.isArray(learnableMove) ? learnableMove : [ learnableMove ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -548,9 +548,9 @@ export class CompatibleMoveRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const includedCompatMoves = this.requiredMoves.filter((reqMove) => pokemon?.compatibleTms.filter((tm) => !pokemon.moveset.find(m => m?.moveId === tm)).includes(reqMove)); const includedCompatMoves = this.requiredMoves.filter((reqMove) => pokemon?.compatibleTms.filter((tm) => !pokemon.moveset.find(m => m?.moveId === tm)).includes(reqMove));
if (includedCompatMoves.length > 0) { if (includedCompatMoves.length > 0) {
return ["compatibleMove", Moves[includedCompatMoves[0]]]; return [ "compatibleMove", Moves[includedCompatMoves[0]] ];
} }
return ["compatibleMove", ""]; return [ "compatibleMove", "" ];
} }
} }
@ -564,7 +564,7 @@ export class AbilityRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredAbilities = Array.isArray(abilities) ? abilities : [abilities]; this.requiredAbilities = Array.isArray(abilities) ? abilities : [ abilities ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -586,9 +586,9 @@ export class AbilityRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
if (pokemon?.getAbility().id && this.requiredAbilities.some(a => pokemon.getAbility().id === a)) { if (pokemon?.getAbility().id && this.requiredAbilities.some(a => pokemon.getAbility().id === a)) {
return ["ability", pokemon.getAbility().name]; return [ "ability", pokemon.getAbility().name ];
} }
return ["ability", ""]; return [ "ability", "" ];
} }
} }
@ -601,7 +601,7 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredStatusEffect = Array.isArray(statusEffect) ? statusEffect : [statusEffect]; this.requiredStatusEffect = Array.isArray(statusEffect) ? statusEffect : [ statusEffect ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -649,9 +649,9 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement {
return pokemon!.status?.effect === a; return pokemon!.status?.effect === a;
}); });
if (reqStatus.length > 0) { if (reqStatus.length > 0) {
return ["status", StatusEffect[reqStatus[0]]]; return [ "status", StatusEffect[reqStatus[0]] ];
} }
return ["status", ""]; return [ "status", "" ];
} }
} }
@ -670,7 +670,7 @@ export class CanFormChangeWithItemRequirement extends EncounterPokemonRequiremen
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredFormChangeItem = Array.isArray(formChangeItem) ? formChangeItem : [formChangeItem]; this.requiredFormChangeItem = Array.isArray(formChangeItem) ? formChangeItem : [ formChangeItem ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -706,9 +706,9 @@ export class CanFormChangeWithItemRequirement extends EncounterPokemonRequiremen
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const requiredItems = this.requiredFormChangeItem.filter((formChangeItem) => this.filterByForm(pokemon, formChangeItem)); const requiredItems = this.requiredFormChangeItem.filter((formChangeItem) => this.filterByForm(pokemon, formChangeItem));
if (requiredItems.length > 0) { if (requiredItems.length > 0) {
return ["formChangeItem", FormChangeItem[requiredItems[0]]]; return [ "formChangeItem", FormChangeItem[requiredItems[0]] ];
} }
return ["formChangeItem", ""]; return [ "formChangeItem", "" ];
} }
} }
@ -722,7 +722,7 @@ export class CanEvolveWithItemRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredEvolutionItem = Array.isArray(evolutionItems) ? evolutionItems : [evolutionItems]; this.requiredEvolutionItem = Array.isArray(evolutionItems) ? evolutionItems : [ evolutionItems ];
} }
override meetsRequirement(scene: BattleScene): boolean { override meetsRequirement(scene: BattleScene): boolean {
@ -756,9 +756,9 @@ export class CanEvolveWithItemRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const requiredItems = this.requiredEvolutionItem.filter((evoItem) => this.filterByEvo(pokemon, evoItem)); const requiredItems = this.requiredEvolutionItem.filter((evoItem) => this.filterByEvo(pokemon, evoItem));
if (requiredItems.length > 0) { if (requiredItems.length > 0) {
return ["evolutionItem", EvolutionItem[requiredItems[0]]]; return [ "evolutionItem", EvolutionItem[requiredItems[0]] ];
} }
return ["evolutionItem", ""]; return [ "evolutionItem", "" ];
} }
} }
@ -772,7 +772,7 @@ export class HeldItemRequirement extends EncounterPokemonRequirement {
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredHeldItemModifiers = Array.isArray(heldItem) ? heldItem : [heldItem]; this.requiredHeldItemModifiers = Array.isArray(heldItem) ? heldItem : [ heldItem ];
this.requireTransferable = requireTransferable; this.requireTransferable = requireTransferable;
} }
@ -807,9 +807,9 @@ export class HeldItemRequirement extends EncounterPokemonRequirement {
&& (!this.requireTransferable || it.isTransferable); && (!this.requireTransferable || it.isTransferable);
}); });
if (requiredItems && requiredItems.length > 0) { if (requiredItems && requiredItems.length > 0) {
return ["heldItem", requiredItems[0].type.name]; return [ "heldItem", requiredItems[0].type.name ];
} }
return ["heldItem", ""]; return [ "heldItem", "" ];
} }
} }
@ -823,7 +823,7 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredHeldItemTypes = Array.isArray(heldItemTypes) ? heldItemTypes : [heldItemTypes]; this.requiredHeldItemTypes = Array.isArray(heldItemTypes) ? heldItemTypes : [ heldItemTypes ];
this.requireTransferable = requireTransferable; this.requireTransferable = requireTransferable;
} }
@ -864,9 +864,9 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
&& (!this.requireTransferable || it.isTransferable); && (!this.requireTransferable || it.isTransferable);
}); });
if (requiredItems && requiredItems.length > 0) { if (requiredItems && requiredItems.length > 0) {
return ["heldItem", requiredItems[0].type.name]; return [ "heldItem", requiredItems[0].type.name ];
} }
return ["heldItem", ""]; return [ "heldItem", "" ];
} }
} }
@ -904,7 +904,7 @@ export class LevelRequirement extends EncounterPokemonRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["level", pokemon?.level.toString() ?? ""]; return [ "level", pokemon?.level.toString() ?? "" ];
} }
} }
@ -942,7 +942,7 @@ export class FriendshipRequirement extends EncounterPokemonRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["friendship", pokemon?.friendship.toString() ?? ""]; return [ "friendship", pokemon?.friendship.toString() ?? "" ];
} }
} }
@ -989,9 +989,9 @@ export class HealthRatioRequirement extends EncounterPokemonRequirement {
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
const hpRatio = pokemon?.getHpRatio(); const hpRatio = pokemon?.getHpRatio();
if (!isNullOrUndefined(hpRatio)) { if (!isNullOrUndefined(hpRatio)) {
return ["healthRatio", Math.floor(hpRatio * 100).toString() + "%"]; return [ "healthRatio", Math.floor(hpRatio * 100).toString() + "%" ];
} }
return ["healthRatio", ""]; return [ "healthRatio", "" ];
} }
} }
@ -1029,8 +1029,7 @@ export class WeightRequirement extends EncounterPokemonRequirement {
} }
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
return ["weight", pokemon?.getWeight().toString() ?? ""]; return [ "weight", pokemon?.getWeight().toString() ?? "" ];
} }
} }

View File

@ -265,7 +265,7 @@ export default class MysteryEncounter implements IMysteryEncounter {
} }
this.encounterTier = this.encounterTier ?? MysteryEncounterTier.COMMON; this.encounterTier = this.encounterTier ?? MysteryEncounterTier.COMMON;
this.dialogue = this.dialogue ?? {}; this.dialogue = this.dialogue ?? {};
this.spriteConfigs = this.spriteConfigs ? [...this.spriteConfigs] : []; this.spriteConfigs = this.spriteConfigs ? [ ...this.spriteConfigs ] : [];
// Default max is 1 for ROGUE encounters, 2 for others // Default max is 1 for ROGUE encounters, 2 for others
this.maxAllowedEncounters = this.maxAllowedEncounters ?? this.encounterTier === MysteryEncounterTier.ROGUE ? DEFAULT_MAX_ALLOWED_ROGUE_ENCOUNTERS : DEFAULT_MAX_ALLOWED_ENCOUNTERS; this.maxAllowedEncounters = this.maxAllowedEncounters ?? this.encounterTier === MysteryEncounterTier.ROGUE ? DEFAULT_MAX_ALLOWED_ROGUE_ENCOUNTERS : DEFAULT_MAX_ALLOWED_ENCOUNTERS;
this.encounterMode = MysteryEncounterMode.DEFAULT; this.encounterMode = MysteryEncounterMode.DEFAULT;
@ -573,7 +573,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
*/ */
withOption(option: MysteryEncounterOption): this & Pick<IMysteryEncounter, "options"> { withOption(option: MysteryEncounterOption): this & Pick<IMysteryEncounter, "options"> {
if (!this.options) { if (!this.options) {
const options = [option]; const options = [ option ];
return Object.assign(this, { options }); return Object.assign(this, { options });
} else { } else {
this.options.push(option); this.options.push(option);
@ -624,11 +624,11 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
} }
withIntroDialogue(dialogue: MysteryEncounterDialogue["intro"] = []): this { withIntroDialogue(dialogue: MysteryEncounterDialogue["intro"] = []): this {
this.dialogue = {...this.dialogue, intro: dialogue }; this.dialogue = { ...this.dialogue, intro: dialogue };
return this; return this;
} }
withIntro({spriteConfigs, dialogue} : {spriteConfigs: MysteryEncounterSpriteConfig[], dialogue?: MysteryEncounterDialogue["intro"]}) { withIntro({ spriteConfigs, dialogue } : {spriteConfigs: MysteryEncounterSpriteConfig[], dialogue?: MysteryEncounterDialogue["intro"]}) {
return this.withIntroSpriteConfigs(spriteConfigs).withIntroDialogue(dialogue); return this.withIntroSpriteConfigs(spriteConfigs).withIntroDialogue(dialogue);
} }
@ -660,7 +660,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
* @returns * @returns
*/ */
withAnimations(...encounterAnimations: EncounterAnim[]): this & Required<Pick<IMysteryEncounter, "encounterAnimations">> { withAnimations(...encounterAnimations: EncounterAnim[]): this & Required<Pick<IMysteryEncounter, "encounterAnimations">> {
const animations = Array.isArray(encounterAnimations) ? encounterAnimations : [encounterAnimations]; const animations = Array.isArray(encounterAnimations) ? encounterAnimations : [ encounterAnimations ];
return Object.assign(this, { encounterAnimations: animations }); return Object.assign(this, { encounterAnimations: animations });
} }
@ -670,7 +670,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
* @param disallowedGameModes * @param disallowedGameModes
*/ */
withDisallowedGameModes(...disallowedGameModes: GameModes[]): this & Required<Pick<IMysteryEncounter, "disallowedGameModes">> { withDisallowedGameModes(...disallowedGameModes: GameModes[]): this & Required<Pick<IMysteryEncounter, "disallowedGameModes">> {
const gameModes = Array.isArray(disallowedGameModes) ? disallowedGameModes : [disallowedGameModes]; const gameModes = Array.isArray(disallowedGameModes) ? disallowedGameModes : [ disallowedGameModes ];
return Object.assign(this, { disallowedGameModes: gameModes }); return Object.assign(this, { disallowedGameModes: gameModes });
} }
@ -680,7 +680,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
* @param disallowedChallenges * @param disallowedChallenges
*/ */
withDisallowedChallenges(...disallowedChallenges: Challenges[]): this & Required<Pick<IMysteryEncounter, "disallowedChallenges">> { withDisallowedChallenges(...disallowedChallenges: Challenges[]): this & Required<Pick<IMysteryEncounter, "disallowedChallenges">> {
const challenges = Array.isArray(disallowedChallenges) ? disallowedChallenges : [disallowedChallenges]; const challenges = Array.isArray(disallowedChallenges) ? disallowedChallenges : [ disallowedChallenges ];
return Object.assign(this, { disallowedChallenges: challenges }); return Object.assign(this, { disallowedChallenges: challenges });
} }
@ -755,7 +755,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
* @returns * @returns
*/ */
withSceneWaveRangeRequirement(min: number, max?: number): this & Required<Pick<IMysteryEncounter, "requirements">> { withSceneWaveRangeRequirement(min: number, max?: number): this & Required<Pick<IMysteryEncounter, "requirements">> {
return this.withSceneRequirement(new WaveRangeRequirement([min, max ?? min])); return this.withSceneRequirement(new WaveRangeRequirement([ min, max ?? min ]));
} }
/** /**
@ -767,7 +767,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
* @returns * @returns
*/ */
withScenePartySizeRequirement(min: number, max?: number, excludeDisallowedPokemon: boolean = false): this & Required<Pick<IMysteryEncounter, "requirements">> { withScenePartySizeRequirement(min: number, max?: number, excludeDisallowedPokemon: boolean = false): this & Required<Pick<IMysteryEncounter, "requirements">> {
return this.withSceneRequirement(new PartySizeRequirement([min, max ?? min], excludeDisallowedPokemon)); return this.withSceneRequirement(new PartySizeRequirement([ min, max ?? min ], excludeDisallowedPokemon));
} }
/** /**
@ -982,7 +982,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
* @returns * @returns
*/ */
withOutroDialogue(dialogue: MysteryEncounterDialogue["outro"] = []): this { withOutroDialogue(dialogue: MysteryEncounterDialogue["outro"] = []): this {
this.dialogue = {...this.dialogue, outro: dialogue }; this.dialogue = { ...this.dialogue, outro: dialogue };
return this; return this;
} }

View File

@ -224,72 +224,72 @@ const anyBiomeEncounters: MysteryEncounterType[] = [
* that biome groups do not cover * that biome groups do not cover
*/ */
export const mysteryEncountersByBiome = new Map<Biome, MysteryEncounterType[]>([ export const mysteryEncountersByBiome = new Map<Biome, MysteryEncounterType[]>([
[Biome.TOWN, []], [ Biome.TOWN, []],
[Biome.PLAINS, [ [ Biome.PLAINS, [
MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.SLUMBERING_SNORLAX,
MysteryEncounterType.ABSOLUTE_AVARICE MysteryEncounterType.ABSOLUTE_AVARICE
]], ]],
[Biome.GRASS, [ [ Biome.GRASS, [
MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.SLUMBERING_SNORLAX,
MysteryEncounterType.ABSOLUTE_AVARICE MysteryEncounterType.ABSOLUTE_AVARICE
]], ]],
[Biome.TALL_GRASS, [ [ Biome.TALL_GRASS, [
MysteryEncounterType.ABSOLUTE_AVARICE MysteryEncounterType.ABSOLUTE_AVARICE
]], ]],
[Biome.METROPOLIS, []], [ Biome.METROPOLIS, []],
[Biome.FOREST, [ [ Biome.FOREST, [
MysteryEncounterType.SAFARI_ZONE, MysteryEncounterType.SAFARI_ZONE,
MysteryEncounterType.ABSOLUTE_AVARICE MysteryEncounterType.ABSOLUTE_AVARICE
]], ]],
[Biome.SEA, [ [ Biome.SEA, [
MysteryEncounterType.LOST_AT_SEA MysteryEncounterType.LOST_AT_SEA
]], ]],
[Biome.SWAMP, [ [ Biome.SWAMP, [
MysteryEncounterType.SAFARI_ZONE MysteryEncounterType.SAFARI_ZONE
]], ]],
[Biome.BEACH, []], [ Biome.BEACH, []],
[Biome.LAKE, []], [ Biome.LAKE, []],
[Biome.SEABED, []], [ Biome.SEABED, []],
[Biome.MOUNTAIN, []], [ Biome.MOUNTAIN, []],
[Biome.BADLANDS, [ [ Biome.BADLANDS, [
MysteryEncounterType.DANCING_LESSONS MysteryEncounterType.DANCING_LESSONS
]], ]],
[Biome.CAVE, [ [ Biome.CAVE, [
MysteryEncounterType.THE_STRONG_STUFF MysteryEncounterType.THE_STRONG_STUFF
]], ]],
[Biome.DESERT, [ [ Biome.DESERT, [
MysteryEncounterType.DANCING_LESSONS MysteryEncounterType.DANCING_LESSONS
]], ]],
[Biome.ICE_CAVE, []], [ Biome.ICE_CAVE, []],
[Biome.MEADOW, []], [ Biome.MEADOW, []],
[Biome.POWER_PLANT, []], [ Biome.POWER_PLANT, []],
[Biome.VOLCANO, [ [ Biome.VOLCANO, [
MysteryEncounterType.FIERY_FALLOUT, MysteryEncounterType.FIERY_FALLOUT,
MysteryEncounterType.DANCING_LESSONS MysteryEncounterType.DANCING_LESSONS
]], ]],
[Biome.GRAVEYARD, []], [ Biome.GRAVEYARD, []],
[Biome.DOJO, []], [ Biome.DOJO, []],
[Biome.FACTORY, []], [ Biome.FACTORY, []],
[Biome.RUINS, []], [ Biome.RUINS, []],
[Biome.WASTELAND, [ [ Biome.WASTELAND, [
MysteryEncounterType.DANCING_LESSONS MysteryEncounterType.DANCING_LESSONS
]], ]],
[Biome.ABYSS, [ [ Biome.ABYSS, [
MysteryEncounterType.DANCING_LESSONS MysteryEncounterType.DANCING_LESSONS
]], ]],
[Biome.SPACE, [ [ Biome.SPACE, [
MysteryEncounterType.THE_EXPERT_POKEMON_BREEDER MysteryEncounterType.THE_EXPERT_POKEMON_BREEDER
]], ]],
[Biome.CONSTRUCTION_SITE, []], [ Biome.CONSTRUCTION_SITE, []],
[Biome.JUNGLE, [ [ Biome.JUNGLE, [
MysteryEncounterType.SAFARI_ZONE MysteryEncounterType.SAFARI_ZONE
]], ]],
[Biome.FAIRY_CAVE, []], [ Biome.FAIRY_CAVE, []],
[Biome.TEMPLE, []], [ Biome.TEMPLE, []],
[Biome.SLUM, []], [ Biome.SLUM, []],
[Biome.SNOWY_FOREST, []], [ Biome.SNOWY_FOREST, []],
[Biome.ISLAND, []], [ Biome.ISLAND, []],
[Biome.LABORATORY, []] [ Biome.LABORATORY, []]
]); ]);
export function initMysteryEncounters() { export function initMysteryEncounters() {

View File

@ -28,7 +28,7 @@ export class CanLearnMoveRequirement extends EncounterPokemonRequirement {
constructor(requiredMoves: Moves | Moves[], options: CanLearnMoveRequirementOptions = {}) { constructor(requiredMoves: Moves | Moves[], options: CanLearnMoveRequirementOptions = {}) {
super(); super();
this.requiredMoves = Array.isArray(requiredMoves) ? requiredMoves : [requiredMoves]; this.requiredMoves = Array.isArray(requiredMoves) ? requiredMoves : [ requiredMoves ];
this.excludeLevelMoves = options.excludeLevelMoves ?? false; this.excludeLevelMoves = options.excludeLevelMoves ?? false;
this.excludeTmMoves = options.excludeTmMoves ?? false; this.excludeTmMoves = options.excludeTmMoves ?? false;
@ -64,11 +64,11 @@ export class CanLearnMoveRequirement extends EncounterPokemonRequirement {
} }
override getDialogueToken(_scene: BattleScene, _pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(_scene: BattleScene, _pokemon?: PlayerPokemon): [string, string] {
return ["requiredMoves", this.requiredMoves.map(m => new PokemonMove(m).getName()).join(", ")]; return [ "requiredMoves", this.requiredMoves.map(m => new PokemonMove(m).getName()).join(", ") ];
} }
private getPokemonLevelMoves(pkm: PlayerPokemon): Moves[] { private getPokemonLevelMoves(pkm: PlayerPokemon): Moves[] {
return pkm.getLevelMoves().map(([_level, move]) => move); return pkm.getLevelMoves().map(([ _level, move ]) => move);
} }
private getAllPokemonMoves(pkm: PlayerPokemon): Moves[] { private getAllPokemonMoves(pkm: PlayerPokemon): Moves[] {

View File

@ -373,7 +373,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
* @param moves * @param moves
*/ */
export function loadCustomMovesForEncounter(scene: BattleScene, moves: Moves | Moves[]) { export function loadCustomMovesForEncounter(scene: BattleScene, moves: Moves | Moves[]) {
moves = Array.isArray(moves) ? moves : [moves]; moves = Array.isArray(moves) ? moves : [ moves ];
return Promise.all(moves.map(move => initMoveAnim(scene, move))) return Promise.all(moves.map(move => initMoveAnim(scene, move)))
.then(() => loadMoveAnimAssets(scene, moves)); .then(() => loadMoveAnimAssets(scene, moves));
} }
@ -663,7 +663,7 @@ export function setEncounterRewards(scene: BattleScene, customShopRewards?: Cust
* @param useWaveIndex - set to false when directly passing the the full exp value instead of baseExpValue * @param useWaveIndex - set to false when directly passing the the full exp value instead of baseExpValue
*/ */
export function setEncounterExp(scene: BattleScene, participantId: number | number[], baseExpValue: number, useWaveIndex: boolean = true) { export function setEncounterExp(scene: BattleScene, participantId: number | number[], baseExpValue: number, useWaveIndex: boolean = true) {
const participantIds = Array.isArray(participantId) ? participantId : [participantId]; const participantIds = Array.isArray(participantId) ? participantId : [ participantId ];
scene.currentBattle.mysteryEncounter!.doEncounterExp = (scene: BattleScene) => { scene.currentBattle.mysteryEncounter!.doEncounterExp = (scene: BattleScene) => {
scene.unshiftPhase(new PartyExpPhase(scene, baseExpValue, useWaveIndex, new Set(participantIds))); scene.unshiftPhase(new PartyExpPhase(scene, baseExpValue, useWaveIndex, new Set(participantIds)));
@ -800,8 +800,8 @@ export function transitionMysteryEncounterIntroVisuals(scene: BattleScene, hide:
// Transition // Transition
scene.tweens.add({ scene.tweens.add({
targets: [introVisuals, enemyPokemon], targets: [ introVisuals, enemyPokemon ],
x: `${hide? "+" : "-"}=16`, x: `${hide ? "+" : "-"}=16`,
y: `${hide ? "-" : "+"}=16`, y: `${hide ? "-" : "+"}=16`,
alpha: hide ? 0 : 1, alpha: hide ? 0 : 1,
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
@ -888,14 +888,14 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n
const numRuns = 1000; const numRuns = 1000;
let run = 0; let run = 0;
const biomes = Object.keys(Biome).filter(key => isNaN(Number(key))); const biomes = Object.keys(Biome).filter(key => isNaN(Number(key)));
const alwaysPickTheseBiomes = [Biome.ISLAND, Biome.ABYSS, Biome.WASTELAND, Biome.FAIRY_CAVE, Biome.TEMPLE, Biome.LABORATORY, Biome.SPACE, Biome.WASTELAND]; const alwaysPickTheseBiomes = [ Biome.ISLAND, Biome.ABYSS, Biome.WASTELAND, Biome.FAIRY_CAVE, Biome.TEMPLE, Biome.LABORATORY, Biome.SPACE, Biome.WASTELAND ];
const calculateNumEncounters = (): any[] => { const calculateNumEncounters = (): any[] => {
let encounterRate = baseSpawnWeight; // BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT let encounterRate = baseSpawnWeight; // BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT
const numEncounters = [0, 0, 0, 0]; const numEncounters = [ 0, 0, 0, 0 ];
let mostRecentEncounterWave = 0; let mostRecentEncounterWave = 0;
const encountersByBiome = new Map<string, number>(biomes.map(b => [b, 0])); const encountersByBiome = new Map<string, number>(biomes.map(b => [ b, 0 ]));
const validMEfloorsByBiome = new Map<string, number>(biomes.map(b => [b, 0])); const validMEfloorsByBiome = new Map<string, number>(biomes.map(b => [ b, 0 ]));
let currentBiome = Biome.TOWN; let currentBiome = Biome.TOWN;
let currentArena = scene.newArena(currentBiome); let currentArena = scene.newArena(currentBiome);
scene.setSeed(Utils.randomString(24)); scene.setSeed(Utils.randomString(24));
@ -968,7 +968,7 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n
// Calculate encounter rarity // Calculate encounter rarity
// Common / Uncommon / Rare / Super Rare (base is out of 128) // Common / Uncommon / Rare / Super Rare (base is out of 128)
const tierWeights = [66, 40, 19, 3]; const tierWeights = [ 66, 40, 19, 3 ];
// Adjust tier weights by currently encountered events (pity system that lowers odds of multiple Common/Great) // Adjust tier weights by currently encountered events (pity system that lowers odds of multiple Common/Great)
tierWeights[0] = tierWeights[0] - 6 * numEncounters[0]; tierWeights[0] = tierWeights[0] - 6 * numEncounters[0];
@ -987,7 +987,7 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n
} }
} }
return [numEncounters, encountersByBiome, validMEfloorsByBiome]; return [ numEncounters, encountersByBiome, validMEfloorsByBiome ];
}; };
const encounterRuns: number[][] = []; const encounterRuns: number[][] = [];
@ -995,7 +995,7 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n
const validFloorsByBiome: Map<string, number>[] = []; const validFloorsByBiome: Map<string, number>[] = [];
while (run < numRuns) { while (run < numRuns) {
scene.executeWithSeedOffset(() => { scene.executeWithSeedOffset(() => {
const [numEncounters, encountersByBiome, validMEfloorsByBiome] = calculateNumEncounters(); const [ numEncounters, encountersByBiome, validMEfloorsByBiome ] = calculateNumEncounters();
encounterRuns.push(numEncounters); encounterRuns.push(numEncounters);
encountersByBiomeRuns.push(encountersByBiome); encountersByBiomeRuns.push(encountersByBiome);
validFloorsByBiome.push(validMEfloorsByBiome); validFloorsByBiome.push(validMEfloorsByBiome);
@ -1036,7 +1036,7 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n
let stats = `Starting weight: ${baseSpawnWeight}\nAverage MEs per run: ${totalMean}\nStandard Deviation: ${totalStd}\nAvg Commons: ${commonMean}\nAvg Greats: ${uncommonMean}\nAvg Ultras: ${rareMean}\nAvg Rogues: ${superRareMean}\n`; let stats = `Starting weight: ${baseSpawnWeight}\nAverage MEs per run: ${totalMean}\nStandard Deviation: ${totalStd}\nAvg Commons: ${commonMean}\nAvg Greats: ${uncommonMean}\nAvg Ultras: ${rareMean}\nAvg Rogues: ${superRareMean}\n`;
const meanEncountersPerRunPerBiomeSorted = [...meanEncountersPerRunPerBiome.entries()].sort((e1, e2) => e2[1] - e1[1]); const meanEncountersPerRunPerBiomeSorted = [ ...meanEncountersPerRunPerBiome.entries() ].sort((e1, e2) => e2[1] - e1[1]);
meanEncountersPerRunPerBiomeSorted.forEach(value => stats = stats + `${value[0]}: avg valid floors ${meanMEFloorsPerRunPerBiome.get(value[0])}, avg MEs ${value[1]},\n`); meanEncountersPerRunPerBiomeSorted.forEach(value => stats = stats + `${value[0]}: avg valid floors ${meanMEFloorsPerRunPerBiome.get(value[0])}, avg MEs ${value[1]},\n`);
console.log(stats); console.log(stats);
@ -1054,7 +1054,7 @@ export function calculateRareSpawnAggregateStats(scene: BattleScene, luckValue:
let run = 0; let run = 0;
const calculateNumRareEncounters = (): any[] => { const calculateNumRareEncounters = (): any[] => {
const bossEncountersByRarity = [0, 0, 0, 0]; const bossEncountersByRarity = [ 0, 0, 0, 0 ];
scene.setSeed(Utils.randomString(24)); scene.setSeed(Utils.randomString(24));
scene.resetSeed(); scene.resetSeed();
// There are 12 wild boss floors // There are 12 wild boss floors

View File

@ -208,7 +208,7 @@ export function getRandomSpeciesByStarterTier(starterTiers: number | [number, nu
let max = Array.isArray(starterTiers) ? starterTiers[1] : starterTiers; let max = Array.isArray(starterTiers) ? starterTiers[1] : starterTiers;
let filteredSpecies: [PokemonSpecies, number][] = Object.keys(speciesStarterCosts) let filteredSpecies: [PokemonSpecies, number][] = Object.keys(speciesStarterCosts)
.map(s => [parseInt(s) as Species, speciesStarterCosts[s] as number]) .map(s => [ parseInt(s) as Species, speciesStarterCosts[s] as number ])
.filter(s => { .filter(s => {
const pokemonSpecies = getPokemonSpecies(s[0]); const pokemonSpecies = getPokemonSpecies(s[0]);
return pokemonSpecies && (!excludedSpecies || !excludedSpecies.includes(s[0])) return pokemonSpecies && (!excludedSpecies || !excludedSpecies.includes(s[0]))
@ -216,7 +216,7 @@ export function getRandomSpeciesByStarterTier(starterTiers: number | [number, nu
&& (allowLegendary || !pokemonSpecies.legendary) && (allowLegendary || !pokemonSpecies.legendary)
&& (allowMythical || !pokemonSpecies.mythical); && (allowMythical || !pokemonSpecies.mythical);
}) })
.map(s => [getPokemonSpecies(s[0]), s[1]]); .map(s => [ getPokemonSpecies(s[0]), s[1] ]);
if (types && types.length > 0) { if (types && types.length > 0) {
filteredSpecies = filteredSpecies.filter(s => types.includes(s[0].type1) || (!isNullOrUndefined(s[0].type2) && types.includes(s[0].type2))); filteredSpecies = filteredSpecies.filter(s => types.includes(s[0].type1) || (!isNullOrUndefined(s[0].type2) && types.includes(s[0].type2)));
@ -313,7 +313,7 @@ export function applyHealToPokemon(scene: BattleScene, pokemon: PlayerPokemon, h
*/ */
export async function modifyPlayerPokemonBST(pokemon: PlayerPokemon, value: number) { export async function modifyPlayerPokemonBST(pokemon: PlayerPokemon, value: number) {
const modType = modifierTypes.MYSTERY_ENCOUNTER_SHUCKLE_JUICE() const modType = modifierTypes.MYSTERY_ENCOUNTER_SHUCKLE_JUICE()
.generateType(pokemon.scene.getParty(), [value]) .generateType(pokemon.scene.getParty(), [ value ])
?.withIdFromFunc(modifierTypes.MYSTERY_ENCOUNTER_SHUCKLE_JUICE); ?.withIdFromFunc(modifierTypes.MYSTERY_ENCOUNTER_SHUCKLE_JUICE);
const modifier = modType?.newModifier(pokemon); const modifier = modType?.newModifier(pokemon);
if (modifier) { if (modifier) {
@ -602,7 +602,7 @@ export async function catchPokemon(scene: BattleScene, pokemon: EnemyPokemon, po
} }
}); });
}; };
Promise.all([pokemon.hideInfo(), scene.gameData.setPokemonCaught(pokemon)]).then(() => { Promise.all([ pokemon.hideInfo(), scene.gameData.setPokemonCaught(pokemon) ]).then(() => {
if (scene.getParty().length === 6) { if (scene.getParty().length === 6) {
const promptRelease = () => { const promptRelease = () => {
scene.ui.showText(i18next.t("battle:partyFull", { pokemonName: pokemon.getNameToRender() }), null, () => { scene.ui.showText(i18next.t("battle:partyFull", { pokemonName: pokemon.getNameToRender() }), null, () => {
@ -728,33 +728,33 @@ export function doPlayerFlee(scene: BattleScene, pokemon: EnemyPokemon): Promise
* Bug Species and their corresponding weights * Bug Species and their corresponding weights
*/ */
const GOLDEN_BUG_NET_SPECIES_POOL: [Species, number][] = [ const GOLDEN_BUG_NET_SPECIES_POOL: [Species, number][] = [
[Species.SCYTHER, 40], [ Species.SCYTHER, 40 ],
[Species.SCIZOR, 40], [ Species.SCIZOR, 40 ],
[Species.KLEAVOR, 40], [ Species.KLEAVOR, 40 ],
[Species.PINSIR, 40], [ Species.PINSIR, 40 ],
[Species.HERACROSS, 40], [ Species.HERACROSS, 40 ],
[Species.YANMA, 40], [ Species.YANMA, 40 ],
[Species.YANMEGA, 40], [ Species.YANMEGA, 40 ],
[Species.SHUCKLE, 40], [ Species.SHUCKLE, 40 ],
[Species.ANORITH, 40], [ Species.ANORITH, 40 ],
[Species.ARMALDO, 40], [ Species.ARMALDO, 40 ],
[Species.ESCAVALIER, 40], [ Species.ESCAVALIER, 40 ],
[Species.ACCELGOR, 40], [ Species.ACCELGOR, 40 ],
[Species.JOLTIK, 40], [ Species.JOLTIK, 40 ],
[Species.GALVANTULA, 40], [ Species.GALVANTULA, 40 ],
[Species.DURANT, 40], [ Species.DURANT, 40 ],
[Species.LARVESTA, 40], [ Species.LARVESTA, 40 ],
[Species.VOLCARONA, 40], [ Species.VOLCARONA, 40 ],
[Species.DEWPIDER, 40], [ Species.DEWPIDER, 40 ],
[Species.ARAQUANID, 40], [ Species.ARAQUANID, 40 ],
[Species.WIMPOD, 40], [ Species.WIMPOD, 40 ],
[Species.GOLISOPOD, 40], [ Species.GOLISOPOD, 40 ],
[Species.SIZZLIPEDE, 40], [ Species.SIZZLIPEDE, 40 ],
[Species.CENTISKORCH, 40], [ Species.CENTISKORCH, 40 ],
[Species.NYMBLE, 40], [ Species.NYMBLE, 40 ],
[Species.LOKIX, 40], [ Species.LOKIX, 40 ],
[Species.BUZZWOLE, 1], [ Species.BUZZWOLE, 1 ],
[Species.PHEROMOSA, 1], [ Species.PHEROMOSA, 1 ],
]; ];
/** /**

View File

@ -640,18 +640,18 @@ export const pokemonFormChanges: PokemonFormChanges = {
new SpeciesFormChange(Species.ALTARIA, "", SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.ALTARIANITE)) new SpeciesFormChange(Species.ALTARIA, "", SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.ALTARIANITE))
], ],
[Species.CASTFORM]: [ [Species.CASTFORM]: [
new SpeciesFormChange(Species.CASTFORM, "", "sunny", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.SUNNY, WeatherType.HARSH_SUN]), true), new SpeciesFormChange(Species.CASTFORM, "", "sunny", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.SUNNY, WeatherType.HARSH_SUN ]), true),
new SpeciesFormChange(Species.CASTFORM, "rainy", "sunny", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.SUNNY, WeatherType.HARSH_SUN]), true), new SpeciesFormChange(Species.CASTFORM, "rainy", "sunny", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.SUNNY, WeatherType.HARSH_SUN ]), true),
new SpeciesFormChange(Species.CASTFORM, "snowy", "sunny", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.SUNNY, WeatherType.HARSH_SUN]), true), new SpeciesFormChange(Species.CASTFORM, "snowy", "sunny", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.SUNNY, WeatherType.HARSH_SUN ]), true),
new SpeciesFormChange(Species.CASTFORM, "", "rainy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.RAIN, WeatherType.HEAVY_RAIN]), true), new SpeciesFormChange(Species.CASTFORM, "", "rainy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.RAIN, WeatherType.HEAVY_RAIN ]), true),
new SpeciesFormChange(Species.CASTFORM, "sunny", "rainy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.RAIN, WeatherType.HEAVY_RAIN]), true), new SpeciesFormChange(Species.CASTFORM, "sunny", "rainy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.RAIN, WeatherType.HEAVY_RAIN ]), true),
new SpeciesFormChange(Species.CASTFORM, "snowy", "rainy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.RAIN, WeatherType.HEAVY_RAIN]), true), new SpeciesFormChange(Species.CASTFORM, "snowy", "rainy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.RAIN, WeatherType.HEAVY_RAIN ]), true),
new SpeciesFormChange(Species.CASTFORM, "", "snowy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.HAIL, WeatherType.SNOW]), true), new SpeciesFormChange(Species.CASTFORM, "", "snowy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.HAIL, WeatherType.SNOW ]), true),
new SpeciesFormChange(Species.CASTFORM, "sunny", "snowy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.HAIL, WeatherType.SNOW]), true), new SpeciesFormChange(Species.CASTFORM, "sunny", "snowy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.HAIL, WeatherType.SNOW ]), true),
new SpeciesFormChange(Species.CASTFORM, "rainy", "snowy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [WeatherType.HAIL, WeatherType.SNOW]), true), new SpeciesFormChange(Species.CASTFORM, "rainy", "snowy", new SpeciesFormChangeWeatherTrigger(Abilities.FORECAST, [ WeatherType.HAIL, WeatherType.SNOW ]), true),
new SpeciesFormChange(Species.CASTFORM, "sunny", "", new SpeciesFormChangeRevertWeatherFormTrigger(Abilities.FORECAST, [WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG]), true), new SpeciesFormChange(Species.CASTFORM, "sunny", "", new SpeciesFormChangeRevertWeatherFormTrigger(Abilities.FORECAST, [ WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG ]), true),
new SpeciesFormChange(Species.CASTFORM, "rainy", "", new SpeciesFormChangeRevertWeatherFormTrigger(Abilities.FORECAST, [WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG]), true), new SpeciesFormChange(Species.CASTFORM, "rainy", "", new SpeciesFormChangeRevertWeatherFormTrigger(Abilities.FORECAST, [ WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG ]), true),
new SpeciesFormChange(Species.CASTFORM, "snowy", "", new SpeciesFormChangeRevertWeatherFormTrigger(Abilities.FORECAST, [WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG]), true), new SpeciesFormChange(Species.CASTFORM, "snowy", "", new SpeciesFormChangeRevertWeatherFormTrigger(Abilities.FORECAST, [ WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG ]), true),
new SpeciesFormChange(Species.CASTFORM, "sunny", "", new SpeciesFormChangeActiveTrigger(), true), new SpeciesFormChange(Species.CASTFORM, "sunny", "", new SpeciesFormChangeActiveTrigger(), true),
new SpeciesFormChange(Species.CASTFORM, "rainy", "", new SpeciesFormChangeActiveTrigger(), true), new SpeciesFormChange(Species.CASTFORM, "rainy", "", new SpeciesFormChangeActiveTrigger(), true),
new SpeciesFormChange(Species.CASTFORM, "snowy", "", new SpeciesFormChangeActiveTrigger(), true) new SpeciesFormChange(Species.CASTFORM, "snowy", "", new SpeciesFormChangeActiveTrigger(), true)

View File

@ -484,6 +484,8 @@ export abstract class PokemonSpeciesForm {
frameRate: 12, frameRate: 12,
repeat: -1 repeat: -1
}); });
} else {
scene.anims.get(spriteKey).frameRate = 12;
} }
let spritePath = this.getSpriteAtlasPath(female, formIndex, shiny, variant).replace("variant/", "").replace(/_[1-3]$/, ""); let spritePath = this.getSpriteAtlasPath(female, formIndex, shiny, variant).replace("variant/", "").replace(/_[1-3]$/, "");
const useExpSprite = scene.experimentalSprites && scene.hasExpSprite(spriteKey); const useExpSprite = scene.experimentalSprites && scene.hasExpSprite(spriteKey);
@ -649,7 +651,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
} }
if (key) { if (key) {
return i18next.t(`battlePokemonForm:${key}`, {pokemonName: this.name}); return i18next.t(`battlePokemonForm:${key}`, { pokemonName: this.name });
} }
} }
return this.name; return this.name;
@ -913,7 +915,7 @@ export class PokemonForm extends PokemonSpeciesForm {
public formSpriteKey: string | null; public formSpriteKey: string | null;
// This is a collection of form keys that have in-run form changes, but should still be separately selectable from the start screen // This is a collection of form keys that have in-run form changes, but should still be separately selectable from the start screen
private starterSelectableKeys: string[] = ["10", "50", "10-pc", "50-pc", "red", "orange", "yellow", "green", "blue", "indigo", "violet"]; private starterSelectableKeys: string[] = [ "10", "50", "10-pc", "50-pc", "red", "orange", "yellow", "green", "blue", "indigo", "violet" ];
constructor(formName: string, formKey: string, type1: Type, type2: Type | null, height: number, weight: number, ability1: Abilities, ability2: Abilities, abilityHidden: Abilities, constructor(formName: string, formKey: string, type1: Type, type2: Type | null, height: number, weight: number, ability1: Abilities, ability2: Abilities, abilityHidden: Abilities,
baseTotal: integer, baseHp: integer, baseAtk: integer, baseDef: integer, baseSpatk: integer, baseSpdef: integer, baseSpd: integer, baseTotal: integer, baseHp: integer, baseAtk: integer, baseDef: integer, baseSpatk: integer, baseSpdef: integer, baseSpd: integer,

View File

@ -185,26 +185,26 @@ const seasonalSplashMessages: Season[] = [
name: "Halloween", name: "Halloween",
start: "09-15", start: "09-15",
end: "10-31", end: "10-31",
messages: ["halloween.pumpkabooAbout", "halloween.mayContainSpiders", "halloween.spookyScarySkeledirge", "halloween.gourgeistUsedTrickOrTreat", "halloween.letsSnuggleForever"], messages: [ "halloween.pumpkabooAbout", "halloween.mayContainSpiders", "halloween.spookyScarySkeledirge", "halloween.gourgeistUsedTrickOrTreat", "halloween.letsSnuggleForever" ],
}, },
{ {
name: "XMAS", name: "XMAS",
start: "12-01", start: "12-01",
end: "12-26", end: "12-26",
messages: ["xmas.happyHolidays", "xmas.unaffilicatedWithDelibirdServices", "xmas.delibirdSeason", "xmas.diamondsFromTheSky", "xmas.holidayStylePikachuNotIncluded"], messages: [ "xmas.happyHolidays", "xmas.unaffilicatedWithDelibirdServices", "xmas.delibirdSeason", "xmas.diamondsFromTheSky", "xmas.holidayStylePikachuNotIncluded" ],
}, },
{ {
name: "New Year's", name: "New Year's",
start: "01-01", start: "01-01",
end: "01-31", end: "01-31",
messages: ["newYears.happyNewYear"], messages: [ "newYears.happyNewYear" ],
}, },
]; ];
//#endregion //#endregion
export function getSplashMessages(): string[] { export function getSplashMessages(): string[] {
const splashMessages: string[] = [...commonSplashMessages]; const splashMessages: string[] = [ ...commonSplashMessages ];
console.log("use seasonal splash messages", USE_SEASONAL_SPLASH_MESSAGES); console.log("use seasonal splash messages", USE_SEASONAL_SPLASH_MESSAGES);
if (USE_SEASONAL_SPLASH_MESSAGES) { if (USE_SEASONAL_SPLASH_MESSAGES) {
// add seasonal splash messages if the season is active // add seasonal splash messages if the season is active

File diff suppressed because it is too large Load Diff

View File

@ -75,56 +75,56 @@ const trainerNameConfigs: TrainerNameConfigs = {
}; };
export const trainerNamePools = { export const trainerNamePools = {
[TrainerType.ACE_TRAINER]: [["Aaron", "Allen", "Blake", "Brian", "Gaven", "Jake", "Kevin", "Mike", "Nick", "Paul", "Ryan", "Sean", "Darin", "Albert", "Berke", "Clyde", "Edgar", "George", "Leroy", "Owen", "Parker", "Randall", "Ruben", "Samuel", "Vincent", "Warren", "Wilton", "Zane", "Alfred", "Braxton", "Felix", "Gerald", "Jonathan", "Leonel", "Marcel", "Mitchell", "Quincy", "Roderick", "Colby", "Rolando", "Yuji", "Abel", "Anton", "Arthur", "Cesar", "Dalton", "Dennis", "Ernest", "Garrett", "Graham", "Henry", "Isaiah", "Jonah", "Jose", "Keenan", "Micah", "Omar", "Quinn", "Rodolfo", "Saul", "Sergio", "Skylar", "Stefan", "Zachery", "Alton", "Arabella", "Bonita", "Cal", "Cody", "French", "Kobe", "Paulo", "Shaye", "Austin", "Beckett", "Charlie", "Corky", "David", "Dwayne", "Elmer", "Jesse", "Jared", "Johan", "Jordan", "Kipp", "Lou", "Terry", "Tom", "Webster", "Billy", "Doyle", "Enzio", "Geoff", "Grant", "Kelsey", "Miguel", "Pierce", "Ray", "Santino", "Shel", "Adelbert", "Bence", "Emil", "Evan", "Mathis", "Maxim", "Neil", "Rico", "Robbie", "Theo", "Viktor", "Benedict", "Cornelius", "Hisato", "Leopold", "Neville", "Vito", "Chase", "Cole", "Hiroshi", "Jackson", "Jim", "Kekoa", "Makana", "Yuki", "Elwood", "Seth", "Alvin", "Arjun", "Arnold", "Cameron", "Carl", "Carlton", "Christopher", "Dave", "Dax", "Dominic", "Edmund", "Finn", "Fred", "Garret", "Grayson", "Jace", "Jaxson", "Jay", "Jirard", "Johnson", "Kayden", "Kite", "Louis", "Mac", "Marty", "Percy", "Raymond", "Ronnie", "Satch", "Tim", "Zach", "Conner", "Vince", "Bedro", "Boda", "Botan", "Daras", "Dury", "Herton", "Rewn", "Stum", "Tock", "Trilo", "Berki", "Cruik", "Dazon", "Desid", "Dillot", "Farfin", "Forgon", "Hebel", "Morfon", "Moril", "Shadd", "Vanhub", "Bardo", "Carben", "Degin", "Gorps", "Klept", "Lask", "Malex", "Mopar", "Niled", "Noxon", "Teslor", "Tetil"], ["Beth", "Carol", "Cybil", "Emma", "Fran", "Gwen", "Irene", "Jenn", "Joyce", "Kate", "Kelly", "Lois", "Lola", "Megan", "Quinn", "Reena", "Cara", "Alexa", "Brooke", "Caroline", "Elaine", "Hope", "Jennifer", "Jody", "Julie", "Lori", "Mary", "Michelle", "Shannon", "Wendy", "Alexia", "Alicia", "Athena", "Carolina", "Cristin", "Darcy", "Dianne", "Halle", "Jazmyn", "Katelynn", "Keira", "Marley", "Allyson", "Kathleen", "Naomi", "Alyssa", "Ariana", "Brandi", "Breanna", "Brenda", "Brenna", "Catherine", "Clarice", "Dana", "Deanna", "Destiny", "Jamie", "Jasmin", "Kassandra", "Laura", "Maria", "Mariah", "Maya", "Meagan", "Mikayla", "Monique", "Natasha", "Olivia", "Sandra", "Savannah", "Sydney", "Moira", "Piper", "Salma", "Allison", "Beverly", "Cathy", "Cheyenne", "Clara", "Dara", "Eileen", "Glinda", "Junko", "Lena", "Lucille", "Mariana", "Olwen", "Shanta", "Stella", "Angi", "Belle", "Chandra", "Cora", "Eve", "Jacqueline", "Jeanne", "Juliet", "Kathrine", "Layla", "Lucca", "Melina", "Miki", "Nina", "Sable", "Shelly", "Summer", "Trish", "Vicki", "Alanza", "Cordelia", "Hilde", "Imelda", "Michele", "Mireille", "Claudia", "Constance", "Harriet", "Honor", "Melba", "Portia", "Alexis", "Angela", "Karla", "Lindsey", "Tori", "Sheri", "Jada", "Kailee", "Amanda", "Annie", "Kindra", "Kyla", "Sofia", "Yvette", "Becky", "Flora", "Gloria", "Buna", "Ferda", "Lehan", "Liqui", "Lomen", "Neira", "Atilo", "Detta", "Gilly", "Gosney", "Levens", "Moden", "Rask", "Rateis", "Rosno", "Tynan", "Veron", "Zoel", "Cida", "Dibsin", "Dodin", "Ebson", "Equin", "Flostin", "Gabsen", "Halsion", "Hileon", "Quelor", "Rapeel", "Roze", "Tensin"]], [TrainerType.ACE_TRAINER]: [[ "Aaron", "Allen", "Blake", "Brian", "Gaven", "Jake", "Kevin", "Mike", "Nick", "Paul", "Ryan", "Sean", "Darin", "Albert", "Berke", "Clyde", "Edgar", "George", "Leroy", "Owen", "Parker", "Randall", "Ruben", "Samuel", "Vincent", "Warren", "Wilton", "Zane", "Alfred", "Braxton", "Felix", "Gerald", "Jonathan", "Leonel", "Marcel", "Mitchell", "Quincy", "Roderick", "Colby", "Rolando", "Yuji", "Abel", "Anton", "Arthur", "Cesar", "Dalton", "Dennis", "Ernest", "Garrett", "Graham", "Henry", "Isaiah", "Jonah", "Jose", "Keenan", "Micah", "Omar", "Quinn", "Rodolfo", "Saul", "Sergio", "Skylar", "Stefan", "Zachery", "Alton", "Arabella", "Bonita", "Cal", "Cody", "French", "Kobe", "Paulo", "Shaye", "Austin", "Beckett", "Charlie", "Corky", "David", "Dwayne", "Elmer", "Jesse", "Jared", "Johan", "Jordan", "Kipp", "Lou", "Terry", "Tom", "Webster", "Billy", "Doyle", "Enzio", "Geoff", "Grant", "Kelsey", "Miguel", "Pierce", "Ray", "Santino", "Shel", "Adelbert", "Bence", "Emil", "Evan", "Mathis", "Maxim", "Neil", "Rico", "Robbie", "Theo", "Viktor", "Benedict", "Cornelius", "Hisato", "Leopold", "Neville", "Vito", "Chase", "Cole", "Hiroshi", "Jackson", "Jim", "Kekoa", "Makana", "Yuki", "Elwood", "Seth", "Alvin", "Arjun", "Arnold", "Cameron", "Carl", "Carlton", "Christopher", "Dave", "Dax", "Dominic", "Edmund", "Finn", "Fred", "Garret", "Grayson", "Jace", "Jaxson", "Jay", "Jirard", "Johnson", "Kayden", "Kite", "Louis", "Mac", "Marty", "Percy", "Raymond", "Ronnie", "Satch", "Tim", "Zach", "Conner", "Vince", "Bedro", "Boda", "Botan", "Daras", "Dury", "Herton", "Rewn", "Stum", "Tock", "Trilo", "Berki", "Cruik", "Dazon", "Desid", "Dillot", "Farfin", "Forgon", "Hebel", "Morfon", "Moril", "Shadd", "Vanhub", "Bardo", "Carben", "Degin", "Gorps", "Klept", "Lask", "Malex", "Mopar", "Niled", "Noxon", "Teslor", "Tetil" ], [ "Beth", "Carol", "Cybil", "Emma", "Fran", "Gwen", "Irene", "Jenn", "Joyce", "Kate", "Kelly", "Lois", "Lola", "Megan", "Quinn", "Reena", "Cara", "Alexa", "Brooke", "Caroline", "Elaine", "Hope", "Jennifer", "Jody", "Julie", "Lori", "Mary", "Michelle", "Shannon", "Wendy", "Alexia", "Alicia", "Athena", "Carolina", "Cristin", "Darcy", "Dianne", "Halle", "Jazmyn", "Katelynn", "Keira", "Marley", "Allyson", "Kathleen", "Naomi", "Alyssa", "Ariana", "Brandi", "Breanna", "Brenda", "Brenna", "Catherine", "Clarice", "Dana", "Deanna", "Destiny", "Jamie", "Jasmin", "Kassandra", "Laura", "Maria", "Mariah", "Maya", "Meagan", "Mikayla", "Monique", "Natasha", "Olivia", "Sandra", "Savannah", "Sydney", "Moira", "Piper", "Salma", "Allison", "Beverly", "Cathy", "Cheyenne", "Clara", "Dara", "Eileen", "Glinda", "Junko", "Lena", "Lucille", "Mariana", "Olwen", "Shanta", "Stella", "Angi", "Belle", "Chandra", "Cora", "Eve", "Jacqueline", "Jeanne", "Juliet", "Kathrine", "Layla", "Lucca", "Melina", "Miki", "Nina", "Sable", "Shelly", "Summer", "Trish", "Vicki", "Alanza", "Cordelia", "Hilde", "Imelda", "Michele", "Mireille", "Claudia", "Constance", "Harriet", "Honor", "Melba", "Portia", "Alexis", "Angela", "Karla", "Lindsey", "Tori", "Sheri", "Jada", "Kailee", "Amanda", "Annie", "Kindra", "Kyla", "Sofia", "Yvette", "Becky", "Flora", "Gloria", "Buna", "Ferda", "Lehan", "Liqui", "Lomen", "Neira", "Atilo", "Detta", "Gilly", "Gosney", "Levens", "Moden", "Rask", "Rateis", "Rosno", "Tynan", "Veron", "Zoel", "Cida", "Dibsin", "Dodin", "Ebson", "Equin", "Flostin", "Gabsen", "Halsion", "Hileon", "Quelor", "Rapeel", "Roze", "Tensin" ]],
[TrainerType.ARTIST]: [["Ismael", "William", "Horton", "Pierre", "Zach", "Gough", "Salvador", "Vincent", "Duncan"], ["Georgia"]], [TrainerType.ARTIST]: [[ "Ismael", "William", "Horton", "Pierre", "Zach", "Gough", "Salvador", "Vincent", "Duncan" ], [ "Georgia" ]],
[TrainerType.BACKERS]: [["Alf & Fred", "Hawk & Dar", "Joe & Ross", "Les & Web", "Masa & Yas", "Stu & Art"], ["Ai & Ciel", "Ami & Eira", "Cam & Abby", "Fey & Sue", "Kat & Phae", "Kay & Ali", "Ava & Aya", "Cleo & Rio", "May & Mal"]], [TrainerType.BACKERS]: [[ "Alf & Fred", "Hawk & Dar", "Joe & Ross", "Les & Web", "Masa & Yas", "Stu & Art" ], [ "Ai & Ciel", "Ami & Eira", "Cam & Abby", "Fey & Sue", "Kat & Phae", "Kay & Ali", "Ava & Aya", "Cleo & Rio", "May & Mal" ]],
[TrainerType.BACKPACKER]: [["Alexander", "Carlos", "Herman", "Jerome", "Keane", "Kelsey", "Kiyo", "Michael", "Nate", "Peter", "Sam", "Stephen", "Talon", "Terrance", "Toru", "Waylon", "Boone", "Clifford", "Ivan", "Kendall", "Lowell", "Randall", "Reece", "Roland", "Shane", "Walt", "Farid", "Heike", "Joren", "Lane", "Roderick", "Darnell", "Deon", "Emory", "Graeme", "Grayson", "Aitor", "Alex", "Arturo", "Asier", "Jaime", "Jonathan", "Julio", "Kevin", "Kosuke", "Lander", "Markel", "Mateo", "Nil", "Pau", "Samuel"], ["Anna", "Corin", "Elaine", "Emi", "Jill", "Kumiko", "Liz", "Lois", "Lora", "Molly", "Patty", "Ruth", "Vicki", "Annie", "Blossom", "Clara", "Eileen", "Mae", "Myra", "Rachel", "Tami", "Ashley", "Mikiko", "Kiana", "Perdy", "Maria", "Yuho", "Peren", "Barbara", "Diane"]], [TrainerType.BACKPACKER]: [[ "Alexander", "Carlos", "Herman", "Jerome", "Keane", "Kelsey", "Kiyo", "Michael", "Nate", "Peter", "Sam", "Stephen", "Talon", "Terrance", "Toru", "Waylon", "Boone", "Clifford", "Ivan", "Kendall", "Lowell", "Randall", "Reece", "Roland", "Shane", "Walt", "Farid", "Heike", "Joren", "Lane", "Roderick", "Darnell", "Deon", "Emory", "Graeme", "Grayson", "Aitor", "Alex", "Arturo", "Asier", "Jaime", "Jonathan", "Julio", "Kevin", "Kosuke", "Lander", "Markel", "Mateo", "Nil", "Pau", "Samuel" ], [ "Anna", "Corin", "Elaine", "Emi", "Jill", "Kumiko", "Liz", "Lois", "Lora", "Molly", "Patty", "Ruth", "Vicki", "Annie", "Blossom", "Clara", "Eileen", "Mae", "Myra", "Rachel", "Tami", "Ashley", "Mikiko", "Kiana", "Perdy", "Maria", "Yuho", "Peren", "Barbara", "Diane" ]],
[TrainerType.BAKER]: ["Chris", "Jenn", "Lilly"], [TrainerType.BAKER]: [ "Chris", "Jenn", "Lilly" ],
[TrainerType.BEAUTY]: ["Cassie", "Julia", "Olivia", "Samantha", "Valerie", "Victoria", "Bridget", "Connie", "Jessica", "Johanna", "Melissa", "Sheila", "Shirley", "Tiffany", "Namiko", "Thalia", "Grace", "Lola", "Lori", "Maura", "Tamia", "Cyndy", "Devon", "Gabriella", "Harley", "Lindsay", "Nicola", "Callie", "Charlotte", "Kassandra", "December", "Fleming", "Nikola", "Aimee", "Anais", "Brigitte", "Cassandra", "Andrea", "Brittney", "Carolyn", "Krystal", "Alexis", "Alice", "Aina", "Anya", "Arianna", "Aubrey", "Beverly", "Camille", "Beauty", "Evette", "Hansol", "Haruka", "Jill", "Jo", "Lana", "Lois", "Lucy", "Mai", "Nickie", "Nicole", "Prita", "Rose", "Shelly", "Suzy", "Tessa", "Anita", "Alissa", "Rita", "Cudsy", "Eloff", "Miru", "Minot", "Nevah", "Niven", "Ogoin"], [TrainerType.BEAUTY]: [ "Cassie", "Julia", "Olivia", "Samantha", "Valerie", "Victoria", "Bridget", "Connie", "Jessica", "Johanna", "Melissa", "Sheila", "Shirley", "Tiffany", "Namiko", "Thalia", "Grace", "Lola", "Lori", "Maura", "Tamia", "Cyndy", "Devon", "Gabriella", "Harley", "Lindsay", "Nicola", "Callie", "Charlotte", "Kassandra", "December", "Fleming", "Nikola", "Aimee", "Anais", "Brigitte", "Cassandra", "Andrea", "Brittney", "Carolyn", "Krystal", "Alexis", "Alice", "Aina", "Anya", "Arianna", "Aubrey", "Beverly", "Camille", "Beauty", "Evette", "Hansol", "Haruka", "Jill", "Jo", "Lana", "Lois", "Lucy", "Mai", "Nickie", "Nicole", "Prita", "Rose", "Shelly", "Suzy", "Tessa", "Anita", "Alissa", "Rita", "Cudsy", "Eloff", "Miru", "Minot", "Nevah", "Niven", "Ogoin" ],
[TrainerType.BIKER]: ["Charles", "Dwayne", "Glenn", "Harris", "Joel", "Riley", "Zeke", "Alex", "Billy", "Ernest", "Gerald", "Hideo", "Isaac", "Jared", "Jaren", "Jaxon", "Jordy", "Lao", "Lukas", "Malik", "Nikolas", "Ricardo", "Ruben", "Virgil", "William", "Aiden", "Dale", "Dan", "Jacob", "Markey", "Reese", "Teddy", "Theron", "Jeremy", "Morgann", "Phillip", "Philip", "Stanley", "Dillon"], [TrainerType.BIKER]: [ "Charles", "Dwayne", "Glenn", "Harris", "Joel", "Riley", "Zeke", "Alex", "Billy", "Ernest", "Gerald", "Hideo", "Isaac", "Jared", "Jaren", "Jaxon", "Jordy", "Lao", "Lukas", "Malik", "Nikolas", "Ricardo", "Ruben", "Virgil", "William", "Aiden", "Dale", "Dan", "Jacob", "Markey", "Reese", "Teddy", "Theron", "Jeremy", "Morgann", "Phillip", "Philip", "Stanley", "Dillon" ],
[TrainerType.BLACK_BELT]: [["Kenji", "Lao", "Lung", "Nob", "Wai", "Yoshi", "Atsushi", "Daisuke", "Hideki", "Hitoshi", "Kiyo", "Koichi", "Koji", "Yuji", "Cristian", "Rhett", "Takao", "Theodore", "Zander", "Aaron", "Hugh", "Mike", "Nicolas", "Shea", "Takashi", "Adam", "Carl", "Colby", "Darren", "David", "Davon", "Derek", "Eddie", "Gregory", "Griffin", "Jarrett", "Jeffery", "Kendal", "Kyle", "Luke", "Miles", "Nathaniel", "Philip", "Rafael", "Ray", "Ricky", "Sean", "Willie", "Ander", "Manford", "Benjamin", "Corey", "Edward", "Grant", "Jay", "Kendrew", "Kentaro", "Ryder", "Teppei", "Thomas", "Tyrone", "Andrey", "Donny", "Drago", "Gordon", "Grigor", "Jeriel", "Kenneth", "Martell", "Mathis", "Rich", "Rocky", "Rodrigo", "Wesley", "Zachery", "Alonzo", "Cadoc", "Gunnar", "Igor", "Killian", "Markus", "Ricardo", "Yanis", "Banting", "Clayton", "Duane", "Earl", "Greg", "Roy", "Terry", "Tracy", "Walter", "Alvaro", "Curtis", "Francis", "Ross", "Brice", "Cheng", "Dudley", "Eric", "Kano", "Masahiro", "Randy", "Ryuji", "Steve", "Tadashi", "Wong", "Yuen", "Brian", "Carter", "Reece", "Nick", "Yang"], ["Cora", "Cyndy", "Jill", "Laura", "Sadie", "Tessa", "Vivian", "Aisha", "Callie", "Danielle", "Helene", "Jocelyn", "Lilith", "Paula", "Reyna", "Helen", "Kelsey", "Tyler", "Amy", "Chandra", "Hillary", "Janie", "Lee", "Maggie", "Mikiko", "Miriam", "Sharon", "Susie", "Xiao", "Alize", "Azra", "Brenda", "Chalina", "Chan", "Glinda", "Maki", "Tia", "Tiffany", "Wendy", "Andrea", "Gabrielle", "Gerardine", "Hailey", "Hedvig", "Justine", "Kinsey", "Sigrid", "Veronique", "Tess"]], [TrainerType.BLACK_BELT]: [[ "Kenji", "Lao", "Lung", "Nob", "Wai", "Yoshi", "Atsushi", "Daisuke", "Hideki", "Hitoshi", "Kiyo", "Koichi", "Koji", "Yuji", "Cristian", "Rhett", "Takao", "Theodore", "Zander", "Aaron", "Hugh", "Mike", "Nicolas", "Shea", "Takashi", "Adam", "Carl", "Colby", "Darren", "David", "Davon", "Derek", "Eddie", "Gregory", "Griffin", "Jarrett", "Jeffery", "Kendal", "Kyle", "Luke", "Miles", "Nathaniel", "Philip", "Rafael", "Ray", "Ricky", "Sean", "Willie", "Ander", "Manford", "Benjamin", "Corey", "Edward", "Grant", "Jay", "Kendrew", "Kentaro", "Ryder", "Teppei", "Thomas", "Tyrone", "Andrey", "Donny", "Drago", "Gordon", "Grigor", "Jeriel", "Kenneth", "Martell", "Mathis", "Rich", "Rocky", "Rodrigo", "Wesley", "Zachery", "Alonzo", "Cadoc", "Gunnar", "Igor", "Killian", "Markus", "Ricardo", "Yanis", "Banting", "Clayton", "Duane", "Earl", "Greg", "Roy", "Terry", "Tracy", "Walter", "Alvaro", "Curtis", "Francis", "Ross", "Brice", "Cheng", "Dudley", "Eric", "Kano", "Masahiro", "Randy", "Ryuji", "Steve", "Tadashi", "Wong", "Yuen", "Brian", "Carter", "Reece", "Nick", "Yang" ], [ "Cora", "Cyndy", "Jill", "Laura", "Sadie", "Tessa", "Vivian", "Aisha", "Callie", "Danielle", "Helene", "Jocelyn", "Lilith", "Paula", "Reyna", "Helen", "Kelsey", "Tyler", "Amy", "Chandra", "Hillary", "Janie", "Lee", "Maggie", "Mikiko", "Miriam", "Sharon", "Susie", "Xiao", "Alize", "Azra", "Brenda", "Chalina", "Chan", "Glinda", "Maki", "Tia", "Tiffany", "Wendy", "Andrea", "Gabrielle", "Gerardine", "Hailey", "Hedvig", "Justine", "Kinsey", "Sigrid", "Veronique", "Tess" ]],
[TrainerType.BREEDER]: [["Isaac", "Myles", "Salvadore", "Albert", "Kahlil", "Eustace", "Galen", "Owen", "Addison", "Marcus", "Foster", "Cory", "Glenn", "Jay", "Wesley", "William", "Adrian", "Bradley", "Jaime"], ["Allison", "Alize", "Bethany", "Lily", "Lydia", "Gabrielle", "Jayden", "Pat", "Veronica", "Amber", "Jennifer", "Kaylee", "Adelaide", "Brooke", "Ethel", "April", "Irene", "Magnolia", "Amala", "Mercy", "Amanda", "Ikue", "Savannah", "Yuka", "Chloe", "Debra", "Denise", "Elena"]], [TrainerType.BREEDER]: [[ "Isaac", "Myles", "Salvadore", "Albert", "Kahlil", "Eustace", "Galen", "Owen", "Addison", "Marcus", "Foster", "Cory", "Glenn", "Jay", "Wesley", "William", "Adrian", "Bradley", "Jaime" ], [ "Allison", "Alize", "Bethany", "Lily", "Lydia", "Gabrielle", "Jayden", "Pat", "Veronica", "Amber", "Jennifer", "Kaylee", "Adelaide", "Brooke", "Ethel", "April", "Irene", "Magnolia", "Amala", "Mercy", "Amanda", "Ikue", "Savannah", "Yuka", "Chloe", "Debra", "Denise", "Elena" ]],
[TrainerType.CLERK]: [["Chaz", "Clemens", "Doug", "Fredric", "Ivan", "Isaac", "Nelson", "Wade", "Warren", "Augustin", "Gilligan", "Cody", "Jeremy", "Shane", "Dugal", "Royce", "Ronald"], ["Alberta", "Ingrid", "Katie", "Piper", "Trisha", "Wren", "Britney", "Lana", "Jessica", "Kristen", "Michelle", "Gabrielle"]], [TrainerType.CLERK]: [[ "Chaz", "Clemens", "Doug", "Fredric", "Ivan", "Isaac", "Nelson", "Wade", "Warren", "Augustin", "Gilligan", "Cody", "Jeremy", "Shane", "Dugal", "Royce", "Ronald" ], [ "Alberta", "Ingrid", "Katie", "Piper", "Trisha", "Wren", "Britney", "Lana", "Jessica", "Kristen", "Michelle", "Gabrielle" ]],
[TrainerType.CYCLIST]: [["Axel", "James", "John", "Ryan", "Hector", "Jeremiah"], ["Kayla", "Megan", "Nicole", "Rachel", "Krissa", "Adelaide"]], [TrainerType.CYCLIST]: [[ "Axel", "James", "John", "Ryan", "Hector", "Jeremiah" ], [ "Kayla", "Megan", "Nicole", "Rachel", "Krissa", "Adelaide" ]],
[TrainerType.DANCER]: ["Brian", "Davey", "Dirk", "Edmond", "Mickey", "Raymond", "Cara", "Julia", "Maika", "Mireille", "Ronda", "Zoe"], [TrainerType.DANCER]: [ "Brian", "Davey", "Dirk", "Edmond", "Mickey", "Raymond", "Cara", "Julia", "Maika", "Mireille", "Ronda", "Zoe" ],
[TrainerType.DEPOT_AGENT]: ["Josh", "Hank", "Vincent"], [TrainerType.DEPOT_AGENT]: [ "Josh", "Hank", "Vincent" ],
[TrainerType.DOCTOR]: [["Hank", "Jerry", "Jules", "Logan", "Wayne", "Braid", "Derek", "Heath", "Julius", "Kit", "Graham"], ["Kirsten", "Sachiko", "Shery", "Carol", "Dixie", "Mariah"]], [TrainerType.DOCTOR]: [[ "Hank", "Jerry", "Jules", "Logan", "Wayne", "Braid", "Derek", "Heath", "Julius", "Kit", "Graham" ], [ "Kirsten", "Sachiko", "Shery", "Carol", "Dixie", "Mariah" ]],
[TrainerType.FIREBREATHER]: ["Bill", "Burt", "Cliff", "Dick", "Lyle", "Ned", "Otis", "Ray", "Richard", "Walt"], [TrainerType.FIREBREATHER]: [ "Bill", "Burt", "Cliff", "Dick", "Lyle", "Ned", "Otis", "Ray", "Richard", "Walt" ],
[TrainerType.FISHERMAN]: ["Andre", "Arnold", "Barney", "Chris", "Edgar", "Henry", "Jonah", "Justin", "Kyle", "Martin", "Marvin", "Ralph", "Raymond", "Scott", "Stephen", "Wilton", "Tully", "Andrew", "Barny", "Carter", "Claude", "Dale", "Elliot", "Eugene", "Ivan", "Ned", "Nolan", "Roger", "Ronald", "Wade", "Wayne", "Darian", "Kai", "Chip", "Hank", "Kaden", "Tommy", "Tylor", "Alec", "Brett", "Cameron", "Cody", "Cole", "Cory", "Erick", "George", "Joseph", "Juan", "Kenneth", "Luc", "Miguel", "Travis", "Walter", "Zachary", "Josh", "Gideon", "Kyler", "Liam", "Murphy", "Bruce", "Damon", "Devon", "Hubert", "Jones", "Lydon", "Mick", "Pete", "Sean", "Sid", "Vince", "Bucky", "Dean", "Eustace", "Kenzo", "Leroy", "Mack", "Ryder", "Ewan", "Finn", "Murray", "Seward", "Shad", "Wharton", "Finley", "Fisher", "Fisk", "River", "Sheaffer", "Timin", "Carl", "Ernest", "Hal", "Herbert", "Hisato", "Mike", "Vernon", "Harriet", "Marina", "Chase"], [TrainerType.FISHERMAN]: [ "Andre", "Arnold", "Barney", "Chris", "Edgar", "Henry", "Jonah", "Justin", "Kyle", "Martin", "Marvin", "Ralph", "Raymond", "Scott", "Stephen", "Wilton", "Tully", "Andrew", "Barny", "Carter", "Claude", "Dale", "Elliot", "Eugene", "Ivan", "Ned", "Nolan", "Roger", "Ronald", "Wade", "Wayne", "Darian", "Kai", "Chip", "Hank", "Kaden", "Tommy", "Tylor", "Alec", "Brett", "Cameron", "Cody", "Cole", "Cory", "Erick", "George", "Joseph", "Juan", "Kenneth", "Luc", "Miguel", "Travis", "Walter", "Zachary", "Josh", "Gideon", "Kyler", "Liam", "Murphy", "Bruce", "Damon", "Devon", "Hubert", "Jones", "Lydon", "Mick", "Pete", "Sean", "Sid", "Vince", "Bucky", "Dean", "Eustace", "Kenzo", "Leroy", "Mack", "Ryder", "Ewan", "Finn", "Murray", "Seward", "Shad", "Wharton", "Finley", "Fisher", "Fisk", "River", "Sheaffer", "Timin", "Carl", "Ernest", "Hal", "Herbert", "Hisato", "Mike", "Vernon", "Harriet", "Marina", "Chase" ],
[TrainerType.GUITARIST]: ["Anna", "Beverly", "January", "Tina", "Alicia", "Claudia", "Julia", "Lidia", "Mireia", "Noelia", "Sara", "Sheila", "Tatiana"], [TrainerType.GUITARIST]: [ "Anna", "Beverly", "January", "Tina", "Alicia", "Claudia", "Julia", "Lidia", "Mireia", "Noelia", "Sara", "Sheila", "Tatiana" ],
[TrainerType.HARLEQUIN]: ["Charley", "Ian", "Jack", "Kerry", "Louis", "Pat", "Paul", "Rick", "Anders", "Clarence", "Gary"], [TrainerType.HARLEQUIN]: [ "Charley", "Ian", "Jack", "Kerry", "Louis", "Pat", "Paul", "Rick", "Anders", "Clarence", "Gary" ],
[TrainerType.HIKER]: ["Anthony", "Bailey", "Benjamin", "Daniel", "Erik", "Jim", "Kenny", "Leonard", "Michael", "Parry", "Phillip", "Russell", "Sidney", "Tim", "Timothy", "Alan", "Brice", "Clark", "Eric", "Lenny", "Lucas", "Mike", "Trent", "Devan", "Eli", "Marc", "Sawyer", "Allen", "Daryl", "Dudley", "Earl", "Franklin", "Jeremy", "Marcos", "Nob", "Oliver", "Wayne", "Alexander", "Damon", "Jonathan", "Justin", "Kevin", "Lorenzo", "Louis", "Maurice", "Nicholas", "Reginald", "Robert", "Theodore", "Bruce", "Clarke", "Devin", "Dwight", "Edwin", "Eoin", "Noland", "Russel", "Andy", "Bret", "Darrell", "Gene", "Hardy", "Hugh", "Jebediah", "Jeremiah", "Kit", "Neil", "Terrell", "Don", "Doug", "Hunter", "Jared", "Jerome", "Keith", "Manuel", "Markus", "Otto", "Shelby", "Stephen", "Teppei", "Tobias", "Wade", "Zaiem", "Aaron", "Alain", "Bergin", "Bernard", "Brent", "Corwin", "Craig", "Delmon", "Dunstan", "Orestes", "Ross", "Davian", "Calhoun", "David", "Gabriel", "Ryan", "Thomas", "Travis", "Zachary", "Anuhea", "Barnaby", "Claus", "Collin", "Colson", "Dexter", "Dillan", "Eugine", "Farkas", "Hisato", "Julius", "Kenji", "Irwin", "Lionel", "Paul", "Richter", "Valentino", "Donald", "Douglas", "Kevyn", "Chester"], //["Angela","Carla","Celia","Daniela","Estela","Fatima","Helena","Leire","Lucia","Luna","Manuela","Mar","Marina","Miyu","Nancy","Nerea","Paula","Rocio","Yanira"] [TrainerType.HIKER]: [ "Anthony", "Bailey", "Benjamin", "Daniel", "Erik", "Jim", "Kenny", "Leonard", "Michael", "Parry", "Phillip", "Russell", "Sidney", "Tim", "Timothy", "Alan", "Brice", "Clark", "Eric", "Lenny", "Lucas", "Mike", "Trent", "Devan", "Eli", "Marc", "Sawyer", "Allen", "Daryl", "Dudley", "Earl", "Franklin", "Jeremy", "Marcos", "Nob", "Oliver", "Wayne", "Alexander", "Damon", "Jonathan", "Justin", "Kevin", "Lorenzo", "Louis", "Maurice", "Nicholas", "Reginald", "Robert", "Theodore", "Bruce", "Clarke", "Devin", "Dwight", "Edwin", "Eoin", "Noland", "Russel", "Andy", "Bret", "Darrell", "Gene", "Hardy", "Hugh", "Jebediah", "Jeremiah", "Kit", "Neil", "Terrell", "Don", "Doug", "Hunter", "Jared", "Jerome", "Keith", "Manuel", "Markus", "Otto", "Shelby", "Stephen", "Teppei", "Tobias", "Wade", "Zaiem", "Aaron", "Alain", "Bergin", "Bernard", "Brent", "Corwin", "Craig", "Delmon", "Dunstan", "Orestes", "Ross", "Davian", "Calhoun", "David", "Gabriel", "Ryan", "Thomas", "Travis", "Zachary", "Anuhea", "Barnaby", "Claus", "Collin", "Colson", "Dexter", "Dillan", "Eugine", "Farkas", "Hisato", "Julius", "Kenji", "Irwin", "Lionel", "Paul", "Richter", "Valentino", "Donald", "Douglas", "Kevyn", "Chester" ], //["Angela","Carla","Celia","Daniela","Estela","Fatima","Helena","Leire","Lucia","Luna","Manuela","Mar","Marina","Miyu","Nancy","Nerea","Paula","Rocio","Yanira"]
[TrainerType.HOOLIGANS]: ["Jim & Cas", "Rob & Sal"], [TrainerType.HOOLIGANS]: [ "Jim & Cas", "Rob & Sal" ],
[TrainerType.HOOPSTER]: ["Bobby", "John", "Lamarcus", "Derrick", "Nicolas"], [TrainerType.HOOPSTER]: [ "Bobby", "John", "Lamarcus", "Derrick", "Nicolas" ],
[TrainerType.INFIELDER]: ["Alex", "Connor", "Todd"], [TrainerType.INFIELDER]: [ "Alex", "Connor", "Todd" ],
[TrainerType.JANITOR]: ["Caleb", "Geoff", "Brady", "Felix", "Orville", "Melvin", "Shawn"], [TrainerType.JANITOR]: [ "Caleb", "Geoff", "Brady", "Felix", "Orville", "Melvin", "Shawn" ],
[TrainerType.LINEBACKER]: ["Bob", "Dan", "Jonah"], [TrainerType.LINEBACKER]: [ "Bob", "Dan", "Jonah" ],
[TrainerType.MAID]: ["Belinda", "Sophie", "Emily", "Elena", "Clare", "Alica", "Tanya", "Tammy"], [TrainerType.MAID]: [ "Belinda", "Sophie", "Emily", "Elena", "Clare", "Alica", "Tanya", "Tammy" ],
[TrainerType.MUSICIAN]: ["Boris", "Preston", "Charles", "Clyde", "Vincent", "Dalton", "Kirk", "Shawn", "Fabian", "Fernando", "Joseph", "Marcos", "Arturo", "Jerry", "Lonnie", "Tony"], [TrainerType.MUSICIAN]: [ "Boris", "Preston", "Charles", "Clyde", "Vincent", "Dalton", "Kirk", "Shawn", "Fabian", "Fernando", "Joseph", "Marcos", "Arturo", "Jerry", "Lonnie", "Tony" ],
[TrainerType.NURSERY_AIDE]: ["Autumn", "Briana", "Leah", "Miho", "Ethel", "Hollie", "Ilse", "June", "Kimya", "Rosalyn"], [TrainerType.NURSERY_AIDE]: [ "Autumn", "Briana", "Leah", "Miho", "Ethel", "Hollie", "Ilse", "June", "Kimya", "Rosalyn" ],
[TrainerType.OFFICER]: ["Dirk", "Keith", "Alex", "Bobby", "Caleb", "Danny", "Dylan", "Thomas", "Daniel", "Jeff", "Braven", "Dell", "Neagle", "Haruki", "Mitchell", "Raymond"], [TrainerType.OFFICER]: [ "Dirk", "Keith", "Alex", "Bobby", "Caleb", "Danny", "Dylan", "Thomas", "Daniel", "Jeff", "Braven", "Dell", "Neagle", "Haruki", "Mitchell", "Raymond" ],
[TrainerType.PARASOL_LADY]: ["Angelica", "Clarissa", "Madeline", "Akari", "Annabell", "Kayley", "Rachel", "Alexa", "Sabrina", "April", "Gwyneth", "Laura", "Lumi", "Mariah", "Melita", "Nicole", "Tihana", "Ingrid", "Tyra"], [TrainerType.PARASOL_LADY]: [ "Angelica", "Clarissa", "Madeline", "Akari", "Annabell", "Kayley", "Rachel", "Alexa", "Sabrina", "April", "Gwyneth", "Laura", "Lumi", "Mariah", "Melita", "Nicole", "Tihana", "Ingrid", "Tyra" ],
[TrainerType.PILOT]: ["Chase", "Leonard", "Ted", "Elron", "Ewing", "Flynn", "Winslow"], [TrainerType.PILOT]: [ "Chase", "Leonard", "Ted", "Elron", "Ewing", "Flynn", "Winslow" ],
[TrainerType.POKEFAN]: [["Alex", "Allan", "Brandon", "Carter", "Colin", "Derek", "Jeremy", "Joshua", "Rex", "Robert", "Trevor", "William", "Colton", "Miguel", "Francisco", "Kaleb", "Leonard", "Boone", "Elliot", "Jude", "Norbert", "Corey", "Gabe", "Baxter"], ["Beverly", "Georgia", "Jaime", "Ruth", "Isabel", "Marissa", "Vanessa", "Annika", "Bethany", "Kimberly", "Meredith", "Rebekah", "Eleanor", "Darcy", "Lydia", "Sachiko", "Abigail", "Agnes", "Lydie", "Roisin", "Tara", "Carmen", "Janet"]], [TrainerType.POKEFAN]: [[ "Alex", "Allan", "Brandon", "Carter", "Colin", "Derek", "Jeremy", "Joshua", "Rex", "Robert", "Trevor", "William", "Colton", "Miguel", "Francisco", "Kaleb", "Leonard", "Boone", "Elliot", "Jude", "Norbert", "Corey", "Gabe", "Baxter" ], [ "Beverly", "Georgia", "Jaime", "Ruth", "Isabel", "Marissa", "Vanessa", "Annika", "Bethany", "Kimberly", "Meredith", "Rebekah", "Eleanor", "Darcy", "Lydia", "Sachiko", "Abigail", "Agnes", "Lydie", "Roisin", "Tara", "Carmen", "Janet" ]],
[TrainerType.PRESCHOOLER]: [["Billy", "Doyle", "Evan", "Homer", "Tully", "Albert", "Buster", "Greg", "Ike", "Jojo", "Tyrone", "Adrian", "Oliver", "Hayden", "Hunter", "Kaleb", "Liam", "Dylan"], ["Juliet", "Mia", "Sarah", "Wendy", "Winter", "Chrissy", "Eva", "Lin", "Samantha", "Ella", "Lily", "Natalie", "Ailey", "Hannah", "Malia", "Kindra", "Nancy"]], [TrainerType.PRESCHOOLER]: [[ "Billy", "Doyle", "Evan", "Homer", "Tully", "Albert", "Buster", "Greg", "Ike", "Jojo", "Tyrone", "Adrian", "Oliver", "Hayden", "Hunter", "Kaleb", "Liam", "Dylan" ], [ "Juliet", "Mia", "Sarah", "Wendy", "Winter", "Chrissy", "Eva", "Lin", "Samantha", "Ella", "Lily", "Natalie", "Ailey", "Hannah", "Malia", "Kindra", "Nancy" ]],
[TrainerType.PSYCHIC]: [["Fidel", "Franklin", "Gilbert", "Greg", "Herman", "Jared", "Mark", "Nathan", "Norman", "Phil", "Richard", "Rodney", "Cameron", "Edward", "Fritz", "Joshua", "Preston", "Virgil", "William", "Alvaro", "Blake", "Cedric", "Keenan", "Nicholas", "Dario", "Johan", "Lorenzo", "Tyron", "Bryce", "Corbin", "Deandre", "Elijah", "Kody", "Landon", "Maxwell", "Mitchell", "Sterling", "Eli", "Nelson", "Vernon", "Gaven", "Gerard", "Low", "Micki", "Perry", "Rudolf", "Tommy", "Al", "Nandor", "Tully", "Arthur", "Emanuel", "Franz", "Harry", "Paschal", "Robert", "Sayid", "Angelo", "Anton", "Arin", "Avery", "Danny", "Frasier", "Harrison", "Jaime", "Ross", "Rui", "Vlad", "Mason"], ["Alexis", "Hannah", "Jacki", "Jaclyn", "Kayla", "Maura", "Samantha", "Alix", "Brandi", "Edie", "Macey", "Mariella", "Marlene", "Laura", "Rodette", "Abigail", "Brittney", "Chelsey", "Daisy", "Desiree", "Kendra", "Lindsey", "Rachael", "Valencia", "Belle", "Cybil", "Doreen", "Dua", "Future", "Lin", "Madhu", "Alia", "Ena", "Joyce", "Lynette", "Olesia", "Sarah"]], [TrainerType.PSYCHIC]: [[ "Fidel", "Franklin", "Gilbert", "Greg", "Herman", "Jared", "Mark", "Nathan", "Norman", "Phil", "Richard", "Rodney", "Cameron", "Edward", "Fritz", "Joshua", "Preston", "Virgil", "William", "Alvaro", "Blake", "Cedric", "Keenan", "Nicholas", "Dario", "Johan", "Lorenzo", "Tyron", "Bryce", "Corbin", "Deandre", "Elijah", "Kody", "Landon", "Maxwell", "Mitchell", "Sterling", "Eli", "Nelson", "Vernon", "Gaven", "Gerard", "Low", "Micki", "Perry", "Rudolf", "Tommy", "Al", "Nandor", "Tully", "Arthur", "Emanuel", "Franz", "Harry", "Paschal", "Robert", "Sayid", "Angelo", "Anton", "Arin", "Avery", "Danny", "Frasier", "Harrison", "Jaime", "Ross", "Rui", "Vlad", "Mason" ], [ "Alexis", "Hannah", "Jacki", "Jaclyn", "Kayla", "Maura", "Samantha", "Alix", "Brandi", "Edie", "Macey", "Mariella", "Marlene", "Laura", "Rodette", "Abigail", "Brittney", "Chelsey", "Daisy", "Desiree", "Kendra", "Lindsey", "Rachael", "Valencia", "Belle", "Cybil", "Doreen", "Dua", "Future", "Lin", "Madhu", "Alia", "Ena", "Joyce", "Lynette", "Olesia", "Sarah" ]],
[TrainerType.RANGER]: [["Carlos", "Jackson", "Sebastian", "Gav", "Lorenzo", "Logan", "Nicolas", "Trenton", "Deshawn", "Dwayne", "Jeffery", "Kyler", "Taylor", "Alain", "Claude", "Crofton", "Forrest", "Harry", "Jaden", "Keith", "Lewis", "Miguel", "Pedro", "Ralph", "Richard", "Bret", "Daryl", "Eddie", "Johan", "Leaf", "Louis", "Maxwell", "Parker", "Rick", "Steve", "Bjorn", "Chaise", "Dean", "Lee", "Maurice", "Nash", "Ralf", "Reed", "Shinobu", "Silas"], ["Catherine", "Jenna", "Sophia", "Merdith", "Nora", "Beth", "Chelsea", "Katelyn", "Madeline", "Allison", "Ashlee", "Felicia", "Krista", "Annie", "Audra", "Brenda", "Chloris", "Eliza", "Heidi", "Irene", "Mary", "Mylene", "Shanti", "Shelly", "Thalia", "Anja", "Briana", "Dianna", "Elaine", "Elle", "Hillary", "Katie", "Lena", "Lois", "Malory", "Melita", "Mikiko", "Naoko", "Serenity", "Ambre", "Brooke", "Clementine", "Melina", "Petra", "Twiggy"]], [TrainerType.RANGER]: [[ "Carlos", "Jackson", "Sebastian", "Gav", "Lorenzo", "Logan", "Nicolas", "Trenton", "Deshawn", "Dwayne", "Jeffery", "Kyler", "Taylor", "Alain", "Claude", "Crofton", "Forrest", "Harry", "Jaden", "Keith", "Lewis", "Miguel", "Pedro", "Ralph", "Richard", "Bret", "Daryl", "Eddie", "Johan", "Leaf", "Louis", "Maxwell", "Parker", "Rick", "Steve", "Bjorn", "Chaise", "Dean", "Lee", "Maurice", "Nash", "Ralf", "Reed", "Shinobu", "Silas" ], [ "Catherine", "Jenna", "Sophia", "Merdith", "Nora", "Beth", "Chelsea", "Katelyn", "Madeline", "Allison", "Ashlee", "Felicia", "Krista", "Annie", "Audra", "Brenda", "Chloris", "Eliza", "Heidi", "Irene", "Mary", "Mylene", "Shanti", "Shelly", "Thalia", "Anja", "Briana", "Dianna", "Elaine", "Elle", "Hillary", "Katie", "Lena", "Lois", "Malory", "Melita", "Mikiko", "Naoko", "Serenity", "Ambre", "Brooke", "Clementine", "Melina", "Petra", "Twiggy" ]],
[TrainerType.RICH]: [["Alfred", "Edward", "Gregory", "Preston", "Thomas", "Tucker", "Walter", "Clifford", "Everett", "Micah", "Nate", "Pierre", "Terrance", "Arthur", "Brooks", "Emanuel", "Lamar", "Jeremy", "Leonardo", "Milton", "Frederic", "Renaud", "Robert", "Yan", "Daniel", "Sheldon", "Stonewall", "Gerald", "Ronald", "Smith", "Stanley", "Reginald", "Orson", "Wilco", "Caden", "Glenn"], ["Rebecca", "Reina", "Cassandra", "Emilia", "Grace", "Marian", "Elizabeth", "Kathleen", "Sayuri", "Caroline", "Judy"]], [TrainerType.RICH]: [[ "Alfred", "Edward", "Gregory", "Preston", "Thomas", "Tucker", "Walter", "Clifford", "Everett", "Micah", "Nate", "Pierre", "Terrance", "Arthur", "Brooks", "Emanuel", "Lamar", "Jeremy", "Leonardo", "Milton", "Frederic", "Renaud", "Robert", "Yan", "Daniel", "Sheldon", "Stonewall", "Gerald", "Ronald", "Smith", "Stanley", "Reginald", "Orson", "Wilco", "Caden", "Glenn" ], [ "Rebecca", "Reina", "Cassandra", "Emilia", "Grace", "Marian", "Elizabeth", "Kathleen", "Sayuri", "Caroline", "Judy" ]],
[TrainerType.RICH_KID]: [["Garret", "Winston", "Dawson", "Enrique", "Jason", "Roman", "Trey", "Liam", "Anthony", "Brad", "Cody", "Manuel", "Martin", "Pierce", "Rolan", "Keenan", "Filbert", "Antoin", "Cyus", "Diek", "Dugo", "Flitz", "Jurek", "Lond", "Perd", "Quint", "Basto", "Benit", "Brot", "Denc", "Guyit", "Marcon", "Perc", "Puros", "Roex", "Sainz", "Symin", "Tark", "Venak"], ["Anette", "Brianna", "Cindy", "Colleen", "Daphne", "Elizabeth", "Naomi", "Sarah", "Charlotte", "Gillian", "Jacki", "Lady", "Melissa", "Celeste", "Colette", "Elizandra", "Isabel", "Lynette", "Magnolia", "Sophie", "Lina", "Dulcie", "Auro", "Brin", "Caril", "Eloos", "Gwin", "Illa", "Kowly", "Rima", "Ristin", "Vesey", "Brena", "Deasy", "Denslon", "Kylet", "Nemi", "Rene", "Sanol", "Stouner", "Sturk", "Talmen", "Zoila"]], [TrainerType.RICH_KID]: [[ "Garret", "Winston", "Dawson", "Enrique", "Jason", "Roman", "Trey", "Liam", "Anthony", "Brad", "Cody", "Manuel", "Martin", "Pierce", "Rolan", "Keenan", "Filbert", "Antoin", "Cyus", "Diek", "Dugo", "Flitz", "Jurek", "Lond", "Perd", "Quint", "Basto", "Benit", "Brot", "Denc", "Guyit", "Marcon", "Perc", "Puros", "Roex", "Sainz", "Symin", "Tark", "Venak" ], [ "Anette", "Brianna", "Cindy", "Colleen", "Daphne", "Elizabeth", "Naomi", "Sarah", "Charlotte", "Gillian", "Jacki", "Lady", "Melissa", "Celeste", "Colette", "Elizandra", "Isabel", "Lynette", "Magnolia", "Sophie", "Lina", "Dulcie", "Auro", "Brin", "Caril", "Eloos", "Gwin", "Illa", "Kowly", "Rima", "Ristin", "Vesey", "Brena", "Deasy", "Denslon", "Kylet", "Nemi", "Rene", "Sanol", "Stouner", "Sturk", "Talmen", "Zoila" ]],
[TrainerType.ROUGHNECK]: ["Camron", "Corey", "Gabriel", "Isaiah", "Jamal", "Koji", "Luke", "Paxton", "Raul", "Zeek", "Kirby", "Chance", "Dave", "Fletcher", "Johnny", "Reese", "Joey", "Ricky", "Silvester", "Martin"], [TrainerType.ROUGHNECK]: [ "Camron", "Corey", "Gabriel", "Isaiah", "Jamal", "Koji", "Luke", "Paxton", "Raul", "Zeek", "Kirby", "Chance", "Dave", "Fletcher", "Johnny", "Reese", "Joey", "Ricky", "Silvester", "Martin" ],
[TrainerType.SAILOR]: ["Alberto", "Bost", "Brennan", "Brenden", "Claude", "Cory", "Damian", "Dirk", "Duncan", "Dwayne", "Dylan", "Eddie", "Edmond", "Elijah", "Ernest", "Eugene", "Garrett", "Golos", "Gratin", "Grestly", "Harry", "Hols", "Hudson", "Huey", "Jebol", "Jeff", "Leonald", "Luther", "Kelvin", "Kenneth", "Kent", "Knook", "Marc", "Mifis", "Monar", "Morkor", "Ordes", "Oxlin", "Parker", "Paul", "Philip", "Roberto", "Samson", "Skyler", "Stanly", "Tebu", "Terrell", "Trevor", "Yasu", "Zachariah"], [TrainerType.SAILOR]: [ "Alberto", "Bost", "Brennan", "Brenden", "Claude", "Cory", "Damian", "Dirk", "Duncan", "Dwayne", "Dylan", "Eddie", "Edmond", "Elijah", "Ernest", "Eugene", "Garrett", "Golos", "Gratin", "Grestly", "Harry", "Hols", "Hudson", "Huey", "Jebol", "Jeff", "Leonald", "Luther", "Kelvin", "Kenneth", "Kent", "Knook", "Marc", "Mifis", "Monar", "Morkor", "Ordes", "Oxlin", "Parker", "Paul", "Philip", "Roberto", "Samson", "Skyler", "Stanly", "Tebu", "Terrell", "Trevor", "Yasu", "Zachariah" ],
[TrainerType.SCIENTIST]: [["Jed", "Marc", "Mitch", "Rich", "Ross", "Beau", "Braydon", "Connor", "Ed", "Ivan", "Jerry", "Jose", "Joshua", "Parker", "Rodney", "Taylor", "Ted", "Travis", "Zackery", "Darrius", "Emilio", "Fredrick", "Shaun", "Stefano", "Travon", "Daniel", "Garett", "Gregg", "Linden", "Lowell", "Trenton", "Dudley", "Luke", "Markus", "Nathan", "Orville", "Randall", "Ron", "Ronald", "Simon", "Steve", "William", "Franklin", "Clarke", "Jacques", "Terrance", "Ernst", "Justus", "Ikaika", "Jayson", "Kyle", "Reid", "Tyrone", "Adam", "Albert", "Alphonse", "Cory", "Donnie", "Elton", "Francis", "Gordon", "Herbert", "Humphrey", "Jordan", "Julian", "Keaton", "Levi", "Melvin", "Murray", "West", "Craig", "Coren", "Dubik", "Kotan", "Lethco", "Mante", "Mort", "Myron", "Odlow", "Ribek", "Roeck", "Vogi", "Vonder", "Zogo", "Doimo", "Doton", "Durel", "Hildon", "Kukla", "Messa", "Nanot", "Platen", "Raburn", "Reman", "Acrod", "Coffy", "Elrok", "Foss", "Hardig", "Hombol", "Hospel", "Kaller", "Klots", "Krilok", "Limar", "Loket", "Mesak", "Morbit", "Newin", "Orill", "Tabor", "Tekot"], ["Blythe", "Chan", "Kathrine", "Marie", "Maria", "Naoko", "Samantha", "Satomi", "Shannon", "Athena", "Caroline", "Lumi", "Lumina", "Marissa", "Sonia"]], [TrainerType.SCIENTIST]: [[ "Jed", "Marc", "Mitch", "Rich", "Ross", "Beau", "Braydon", "Connor", "Ed", "Ivan", "Jerry", "Jose", "Joshua", "Parker", "Rodney", "Taylor", "Ted", "Travis", "Zackery", "Darrius", "Emilio", "Fredrick", "Shaun", "Stefano", "Travon", "Daniel", "Garett", "Gregg", "Linden", "Lowell", "Trenton", "Dudley", "Luke", "Markus", "Nathan", "Orville", "Randall", "Ron", "Ronald", "Simon", "Steve", "William", "Franklin", "Clarke", "Jacques", "Terrance", "Ernst", "Justus", "Ikaika", "Jayson", "Kyle", "Reid", "Tyrone", "Adam", "Albert", "Alphonse", "Cory", "Donnie", "Elton", "Francis", "Gordon", "Herbert", "Humphrey", "Jordan", "Julian", "Keaton", "Levi", "Melvin", "Murray", "West", "Craig", "Coren", "Dubik", "Kotan", "Lethco", "Mante", "Mort", "Myron", "Odlow", "Ribek", "Roeck", "Vogi", "Vonder", "Zogo", "Doimo", "Doton", "Durel", "Hildon", "Kukla", "Messa", "Nanot", "Platen", "Raburn", "Reman", "Acrod", "Coffy", "Elrok", "Foss", "Hardig", "Hombol", "Hospel", "Kaller", "Klots", "Krilok", "Limar", "Loket", "Mesak", "Morbit", "Newin", "Orill", "Tabor", "Tekot" ], [ "Blythe", "Chan", "Kathrine", "Marie", "Maria", "Naoko", "Samantha", "Satomi", "Shannon", "Athena", "Caroline", "Lumi", "Lumina", "Marissa", "Sonia" ]],
[TrainerType.SMASHER]: ["Aspen", "Elena", "Mari", "Amy", "Lizzy"], [TrainerType.SMASHER]: [ "Aspen", "Elena", "Mari", "Amy", "Lizzy" ],
[TrainerType.SNOW_WORKER]: [["Braden", "Brendon", "Colin", "Conrad", "Dillan", "Gary", "Gerardo", "Holden", "Jackson", "Mason", "Quentin", "Willy", "Noel", "Arnold", "Brady", "Brand", "Cairn", "Cliff", "Don", "Eddie", "Felix", "Filipe", "Glenn", "Gus", "Heath", "Matthew", "Patton", "Rich", "Rob", "Ryan", "Scott", "Shelby", "Sterling", "Tyler", "Victor", "Zack", "Friedrich", "Herman", "Isaac", "Leo", "Maynard", "Mitchell", "Morgann", "Nathan", "Niel", "Pasqual", "Paul", "Tavarius", "Tibor", "Dimitri", "Narek", "Yusif", "Frank", "Jeff", "Vaclav", "Ovid", "Francis", "Keith", "Russel", "Sangon", "Toway", "Bomber", "Chean", "Demit", "Hubor", "Kebile", "Laber", "Ordo", "Retay", "Ronix", "Wagel", "Dobit", "Kaster", "Lobel", "Releo", "Saken", "Rustix"], ["Georgia", "Sandra", "Yvonne"]], [TrainerType.SNOW_WORKER]: [[ "Braden", "Brendon", "Colin", "Conrad", "Dillan", "Gary", "Gerardo", "Holden", "Jackson", "Mason", "Quentin", "Willy", "Noel", "Arnold", "Brady", "Brand", "Cairn", "Cliff", "Don", "Eddie", "Felix", "Filipe", "Glenn", "Gus", "Heath", "Matthew", "Patton", "Rich", "Rob", "Ryan", "Scott", "Shelby", "Sterling", "Tyler", "Victor", "Zack", "Friedrich", "Herman", "Isaac", "Leo", "Maynard", "Mitchell", "Morgann", "Nathan", "Niel", "Pasqual", "Paul", "Tavarius", "Tibor", "Dimitri", "Narek", "Yusif", "Frank", "Jeff", "Vaclav", "Ovid", "Francis", "Keith", "Russel", "Sangon", "Toway", "Bomber", "Chean", "Demit", "Hubor", "Kebile", "Laber", "Ordo", "Retay", "Ronix", "Wagel", "Dobit", "Kaster", "Lobel", "Releo", "Saken", "Rustix" ], [ "Georgia", "Sandra", "Yvonne" ]],
[TrainerType.STRIKER]: ["Marco", "Roberto", "Tony"], [TrainerType.STRIKER]: [ "Marco", "Roberto", "Tony" ],
[TrainerType.SCHOOL_KID]: [["Alan", "Billy", "Chad", "Danny", "Dudley", "Jack", "Joe", "Johnny", "Kipp", "Nate", "Ricky", "Tommy", "Jerry", "Paul", "Ted", "Chance", "Esteban", "Forrest", "Harrison", "Connor", "Sherman", "Torin", "Travis", "Al", "Carter", "Edgar", "Jem", "Sammy", "Shane", "Shayne", "Alvin", "Keston", "Neil", "Seymour", "William", "Carson", "Clark", "Nolan"], ["Georgia", "Karen", "Meiko", "Christine", "Mackenzie", "Tiera", "Ann", "Gina", "Lydia", "Marsha", "Millie", "Sally", "Serena", "Silvia", "Alberta", "Cassie", "Mara", "Rita", "Georgie", "Meena", "Nitzel"]], [TrainerType.SCHOOL_KID]: [[ "Alan", "Billy", "Chad", "Danny", "Dudley", "Jack", "Joe", "Johnny", "Kipp", "Nate", "Ricky", "Tommy", "Jerry", "Paul", "Ted", "Chance", "Esteban", "Forrest", "Harrison", "Connor", "Sherman", "Torin", "Travis", "Al", "Carter", "Edgar", "Jem", "Sammy", "Shane", "Shayne", "Alvin", "Keston", "Neil", "Seymour", "William", "Carson", "Clark", "Nolan" ], [ "Georgia", "Karen", "Meiko", "Christine", "Mackenzie", "Tiera", "Ann", "Gina", "Lydia", "Marsha", "Millie", "Sally", "Serena", "Silvia", "Alberta", "Cassie", "Mara", "Rita", "Georgie", "Meena", "Nitzel" ]],
[TrainerType.SWIMMER]: [["Berke", "Cameron", "Charlie", "George", "Harold", "Jerome", "Kirk", "Mathew", "Parker", "Randall", "Seth", "Simon", "Tucker", "Austin", "Barry", "Chad", "Cody", "Darrin", "David", "Dean", "Douglas", "Franklin", "Gilbert", "Herman", "Jack", "Luis", "Matthew", "Reed", "Richard", "Rodney", "Roland", "Spencer", "Stan", "Tony", "Clarence", "Declan", "Dominik", "Harrison", "Kevin", "Leonardo", "Nolen", "Pete", "Santiago", "Axle", "Braden", "Finn", "Garrett", "Mymo", "Reece", "Samir", "Toby", "Adrian", "Colton", "Dillon", "Erik", "Evan", "Francisco", "Glenn", "Kurt", "Oscar", "Ricardo", "Sam", "Sheltin", "Troy", "Vincent", "Wade", "Wesley", "Duane", "Elmo", "Esteban", "Frankie", "Ronald", "Tyson", "Bart", "Matt", "Tim", "Wright", "Jeffery", "Kyle", "Alessandro", "Estaban", "Kieran", "Ramses", "Casey", "Dakota", "Jared", "Kalani", "Keoni", "Lawrence", "Logan", "Robert", "Roddy", "Yasu", "Derek", "Jacob", "Bruce", "Clayton"], ["Briana", "Dawn", "Denise", "Diana", "Elaine", "Kara", "Kaylee", "Lori", "Nicole", "Nikki", "Paula", "Susie", "Wendy", "Alice", "Beth", "Beverly", "Brenda", "Dana", "Debra", "Grace", "Jenny", "Katie", "Laurel", "Linda", "Missy", "Sharon", "Tanya", "Tara", "Tisha", "Carlee", "Imani", "Isabelle", "Kyla", "Sienna", "Abigail", "Amara", "Anya", "Connie", "Maria", "Melissa", "Nora", "Shirley", "Shania", "Tiffany", "Aubree", "Cassandra", "Claire", "Crystal", "Erica", "Gabrielle", "Haley", "Jessica", "Joanna", "Lydia", "Mallory", "Mary", "Miranda", "Paige", "Sophia", "Vanessa", "Chelan", "Debbie", "Joy", "Kendra", "Leona", "Mina", "Caroline", "Joyce", "Larissa", "Rebecca", "Tyra", "Dara", "Desiree", "Kaoru", "Ruth", "Coral", "Genevieve", "Isla", "Marissa", "Romy", "Sheryl", "Alexandria", "Alicia", "Chelsea", "Jade", "Kelsie", "Laura", "Portia", "Shelby", "Sara", "Tiare", "Kyra", "Natasha", "Layla", "Scarlett", "Cora"]], [TrainerType.SWIMMER]: [[ "Berke", "Cameron", "Charlie", "George", "Harold", "Jerome", "Kirk", "Mathew", "Parker", "Randall", "Seth", "Simon", "Tucker", "Austin", "Barry", "Chad", "Cody", "Darrin", "David", "Dean", "Douglas", "Franklin", "Gilbert", "Herman", "Jack", "Luis", "Matthew", "Reed", "Richard", "Rodney", "Roland", "Spencer", "Stan", "Tony", "Clarence", "Declan", "Dominik", "Harrison", "Kevin", "Leonardo", "Nolen", "Pete", "Santiago", "Axle", "Braden", "Finn", "Garrett", "Mymo", "Reece", "Samir", "Toby", "Adrian", "Colton", "Dillon", "Erik", "Evan", "Francisco", "Glenn", "Kurt", "Oscar", "Ricardo", "Sam", "Sheltin", "Troy", "Vincent", "Wade", "Wesley", "Duane", "Elmo", "Esteban", "Frankie", "Ronald", "Tyson", "Bart", "Matt", "Tim", "Wright", "Jeffery", "Kyle", "Alessandro", "Estaban", "Kieran", "Ramses", "Casey", "Dakota", "Jared", "Kalani", "Keoni", "Lawrence", "Logan", "Robert", "Roddy", "Yasu", "Derek", "Jacob", "Bruce", "Clayton" ], [ "Briana", "Dawn", "Denise", "Diana", "Elaine", "Kara", "Kaylee", "Lori", "Nicole", "Nikki", "Paula", "Susie", "Wendy", "Alice", "Beth", "Beverly", "Brenda", "Dana", "Debra", "Grace", "Jenny", "Katie", "Laurel", "Linda", "Missy", "Sharon", "Tanya", "Tara", "Tisha", "Carlee", "Imani", "Isabelle", "Kyla", "Sienna", "Abigail", "Amara", "Anya", "Connie", "Maria", "Melissa", "Nora", "Shirley", "Shania", "Tiffany", "Aubree", "Cassandra", "Claire", "Crystal", "Erica", "Gabrielle", "Haley", "Jessica", "Joanna", "Lydia", "Mallory", "Mary", "Miranda", "Paige", "Sophia", "Vanessa", "Chelan", "Debbie", "Joy", "Kendra", "Leona", "Mina", "Caroline", "Joyce", "Larissa", "Rebecca", "Tyra", "Dara", "Desiree", "Kaoru", "Ruth", "Coral", "Genevieve", "Isla", "Marissa", "Romy", "Sheryl", "Alexandria", "Alicia", "Chelsea", "Jade", "Kelsie", "Laura", "Portia", "Shelby", "Sara", "Tiare", "Kyra", "Natasha", "Layla", "Scarlett", "Cora" ]],
[TrainerType.TWINS]: ["Amy & May", "Jo & Zoe", "Meg & Peg", "Ann & Anne", "Lea & Pia", "Amy & Liv", "Gina & Mia", "Miu & Yuki", "Tori & Tia", "Eli & Anne", "Jen & Kira", "Joy & Meg", "Kiri & Jan", "Miu & Mia", "Emma & Lil", "Liv & Liz", "Teri & Tia", "Amy & Mimi", "Clea & Gil", "Day & Dani", "Kay & Tia", "Tori & Til", "Saya & Aya", "Emy & Lin", "Kumi & Amy", "Mayo & May", "Ally & Amy", "Lia & Lily", "Rae & Ula", "Sola & Ana", "Tara & Val", "Faith & Joy", "Nana & Nina"], [TrainerType.TWINS]: [ "Amy & May", "Jo & Zoe", "Meg & Peg", "Ann & Anne", "Lea & Pia", "Amy & Liv", "Gina & Mia", "Miu & Yuki", "Tori & Tia", "Eli & Anne", "Jen & Kira", "Joy & Meg", "Kiri & Jan", "Miu & Mia", "Emma & Lil", "Liv & Liz", "Teri & Tia", "Amy & Mimi", "Clea & Gil", "Day & Dani", "Kay & Tia", "Tori & Til", "Saya & Aya", "Emy & Lin", "Kumi & Amy", "Mayo & May", "Ally & Amy", "Lia & Lily", "Rae & Ula", "Sola & Ana", "Tara & Val", "Faith & Joy", "Nana & Nina" ],
[TrainerType.VETERAN]: [["Armando", "Brenden", "Brian", "Clayton", "Edgar", "Emanuel", "Grant", "Harlan", "Terrell", "Arlen", "Chester", "Hugo", "Martell", "Ray", "Shaun", "Abraham", "Carter", "Claude", "Jerry", "Lucius", "Murphy", "Rayne", "Ron", "Sinan", "Sterling", "Vincent", "Zach", "Gerard", "Gilles", "Louis", "Timeo", "Akira", "Don", "Eric", "Harry", "Leon", "Roger", "Angus", "Aristo", "Brone", "Johnny"], ["Julia", "Karla", "Kim", "Sayuri", "Tiffany", "Cathy", "Cecile", "Chloris", "Denae", "Gina", "Maya", "Oriana", "Portia", "Rhona", "Rosaline", "Catrina", "Inga", "Trisha", "Heather", "Lynn", "Sheri", "Alonsa", "Ella", "Leticia", "Kiara"]], [TrainerType.VETERAN]: [[ "Armando", "Brenden", "Brian", "Clayton", "Edgar", "Emanuel", "Grant", "Harlan", "Terrell", "Arlen", "Chester", "Hugo", "Martell", "Ray", "Shaun", "Abraham", "Carter", "Claude", "Jerry", "Lucius", "Murphy", "Rayne", "Ron", "Sinan", "Sterling", "Vincent", "Zach", "Gerard", "Gilles", "Louis", "Timeo", "Akira", "Don", "Eric", "Harry", "Leon", "Roger", "Angus", "Aristo", "Brone", "Johnny" ], [ "Julia", "Karla", "Kim", "Sayuri", "Tiffany", "Cathy", "Cecile", "Chloris", "Denae", "Gina", "Maya", "Oriana", "Portia", "Rhona", "Rosaline", "Catrina", "Inga", "Trisha", "Heather", "Lynn", "Sheri", "Alonsa", "Ella", "Leticia", "Kiara" ]],
[TrainerType.WAITER]: [["Bert", "Clint", "Maxwell", "Lou"], ["Kati", "Aurora", "Bonita", "Flo", "Tia", "Jan", "Olwen", "Paget", "Paula", "Talia"]], [TrainerType.WAITER]: [[ "Bert", "Clint", "Maxwell", "Lou" ], [ "Kati", "Aurora", "Bonita", "Flo", "Tia", "Jan", "Olwen", "Paget", "Paula", "Talia" ]],
[TrainerType.WORKER]: [["Braden", "Brendon", "Colin", "Conrad", "Dillan", "Gary", "Gerardo", "Holden", "Jackson", "Mason", "Quentin", "Willy", "Noel", "Arnold", "Brady", "Brand", "Cairn", "Cliff", "Don", "Eddie", "Felix", "Filipe", "Glenn", "Gus", "Heath", "Matthew", "Patton", "Rich", "Rob", "Ryan", "Scott", "Shelby", "Sterling", "Tyler", "Victor", "Zack", "Friedrich", "Herman", "Isaac", "Leo", "Maynard", "Mitchell", "Morgann", "Nathan", "Niel", "Pasqual", "Paul", "Tavarius", "Tibor", "Dimitri", "Narek", "Yusif", "Frank", "Jeff", "Vaclav", "Ovid", "Francis", "Keith", "Russel", "Sangon", "Toway", "Bomber", "Chean", "Demit", "Hubor", "Kebile", "Laber", "Ordo", "Retay", "Ronix", "Wagel", "Dobit", "Kaster", "Lobel", "Releo", "Saken", "Rustix"], ["Georgia", "Sandra", "Yvonne"]], [TrainerType.WORKER]: [[ "Braden", "Brendon", "Colin", "Conrad", "Dillan", "Gary", "Gerardo", "Holden", "Jackson", "Mason", "Quentin", "Willy", "Noel", "Arnold", "Brady", "Brand", "Cairn", "Cliff", "Don", "Eddie", "Felix", "Filipe", "Glenn", "Gus", "Heath", "Matthew", "Patton", "Rich", "Rob", "Ryan", "Scott", "Shelby", "Sterling", "Tyler", "Victor", "Zack", "Friedrich", "Herman", "Isaac", "Leo", "Maynard", "Mitchell", "Morgann", "Nathan", "Niel", "Pasqual", "Paul", "Tavarius", "Tibor", "Dimitri", "Narek", "Yusif", "Frank", "Jeff", "Vaclav", "Ovid", "Francis", "Keith", "Russel", "Sangon", "Toway", "Bomber", "Chean", "Demit", "Hubor", "Kebile", "Laber", "Ordo", "Retay", "Ronix", "Wagel", "Dobit", "Kaster", "Lobel", "Releo", "Saken", "Rustix" ], [ "Georgia", "Sandra", "Yvonne" ]],
[TrainerType.YOUNGSTER]: [["Albert", "Gordon", "Ian", "Jason", "Jimmy", "Mikey", "Owen", "Samuel", "Warren", "Allen", "Ben", "Billy", "Calvin", "Dillion", "Eddie", "Joey", "Josh", "Neal", "Timmy", "Tommy", "Breyden", "Deandre", "Demetrius", "Dillon", "Jaylen", "Johnson", "Shigenobu", "Chad", "Cole", "Cordell", "Dan", "Dave", "Destin", "Nash", "Tyler", "Yasu", "Austin", "Dallas", "Darius", "Donny", "Jonathon", "Logan", "Michael", "Oliver", "Sebastian", "Tristan", "Wayne", "Norman", "Roland", "Regis", "Abe", "Astor", "Keita", "Kenneth", "Kevin", "Kyle", "Lester", "Masao", "Nicholas", "Parker", "Wes", "Zachary", "Cody", "Henley", "Jaye", "Karl", "Kenny", "Masahiro", "Pedro", "Petey", "Sinclair", "Terrell", "Waylon", "Aidan", "Anthony", "David", "Jacob", "Jayden", "Cutler", "Ham", "Caleb", "Kai", "Honus", "Kenway", "Bret", "Chris", "Cid", "Dennis", "Easton", "Ken", "Robby", "Ronny", "Shawn", "Benjamin", "Jake", "Travis", "Adan", "Aday", "Beltran", "Elian", "Hernan", "Julen", "Luka", "Roi", "Bernie", "Dustin", "Jonathan", "Wyatt"], ["Alice", "Bridget", "Carrie", "Connie", "Dana", "Ellen", "Krise", "Laura", "Linda", "Michelle", "Shannon", "Andrea", "Crissy", "Janice", "Robin", "Sally", "Tiana", "Haley", "Ali", "Ann", "Dalia", "Dawn", "Iris", "Joana", "Julia", "Kay", "Lisa", "Megan", "Mikaela", "Miriam", "Paige", "Reli", "Blythe", "Briana", "Caroline", "Cassidy", "Kaitlin", "Madeline", "Molly", "Natalie", "Samantha", "Sarah", "Cathy", "Dye", "Eri", "Eva", "Fey", "Kara", "Lurleen", "Maki", "Mali", "Maya", "Miki", "Sibyl", "Daya", "Diana", "Flo", "Helia", "Henrietta", "Isabel", "Mai", "Persephone", "Serena", "Anna", "Charlotte", "Elin", "Elsa", "Lise", "Sara", "Suzette", "Audrey", "Emmy", "Isabella", "Madison", "Rika", "Rylee", "Salla", "Ellie", "Alexandra", "Amy", "Lass", "Brittany", "Chel", "Cindy", "Dianne", "Emily", "Emma", "Evelyn", "Hana", "Harleen", "Hazel", "Jocelyn", "Katrina", "Kimberly", "Lina", "Marge", "Mila", "Mizuki", "Rena", "Sal", "Satoko", "Summer", "Tomoe", "Vicky", "Yue", "Yumi", "Lauren", "Rei", "Riley", "Lois", "Nancy", "Tammy", "Terry"]], [TrainerType.YOUNGSTER]: [[ "Albert", "Gordon", "Ian", "Jason", "Jimmy", "Mikey", "Owen", "Samuel", "Warren", "Allen", "Ben", "Billy", "Calvin", "Dillion", "Eddie", "Joey", "Josh", "Neal", "Timmy", "Tommy", "Breyden", "Deandre", "Demetrius", "Dillon", "Jaylen", "Johnson", "Shigenobu", "Chad", "Cole", "Cordell", "Dan", "Dave", "Destin", "Nash", "Tyler", "Yasu", "Austin", "Dallas", "Darius", "Donny", "Jonathon", "Logan", "Michael", "Oliver", "Sebastian", "Tristan", "Wayne", "Norman", "Roland", "Regis", "Abe", "Astor", "Keita", "Kenneth", "Kevin", "Kyle", "Lester", "Masao", "Nicholas", "Parker", "Wes", "Zachary", "Cody", "Henley", "Jaye", "Karl", "Kenny", "Masahiro", "Pedro", "Petey", "Sinclair", "Terrell", "Waylon", "Aidan", "Anthony", "David", "Jacob", "Jayden", "Cutler", "Ham", "Caleb", "Kai", "Honus", "Kenway", "Bret", "Chris", "Cid", "Dennis", "Easton", "Ken", "Robby", "Ronny", "Shawn", "Benjamin", "Jake", "Travis", "Adan", "Aday", "Beltran", "Elian", "Hernan", "Julen", "Luka", "Roi", "Bernie", "Dustin", "Jonathan", "Wyatt" ], [ "Alice", "Bridget", "Carrie", "Connie", "Dana", "Ellen", "Krise", "Laura", "Linda", "Michelle", "Shannon", "Andrea", "Crissy", "Janice", "Robin", "Sally", "Tiana", "Haley", "Ali", "Ann", "Dalia", "Dawn", "Iris", "Joana", "Julia", "Kay", "Lisa", "Megan", "Mikaela", "Miriam", "Paige", "Reli", "Blythe", "Briana", "Caroline", "Cassidy", "Kaitlin", "Madeline", "Molly", "Natalie", "Samantha", "Sarah", "Cathy", "Dye", "Eri", "Eva", "Fey", "Kara", "Lurleen", "Maki", "Mali", "Maya", "Miki", "Sibyl", "Daya", "Diana", "Flo", "Helia", "Henrietta", "Isabel", "Mai", "Persephone", "Serena", "Anna", "Charlotte", "Elin", "Elsa", "Lise", "Sara", "Suzette", "Audrey", "Emmy", "Isabella", "Madison", "Rika", "Rylee", "Salla", "Ellie", "Alexandra", "Amy", "Lass", "Brittany", "Chel", "Cindy", "Dianne", "Emily", "Emma", "Evelyn", "Hana", "Harleen", "Hazel", "Jocelyn", "Katrina", "Kimberly", "Lina", "Marge", "Mila", "Mizuki", "Rena", "Sal", "Satoko", "Summer", "Tomoe", "Vicky", "Yue", "Yumi", "Lauren", "Rei", "Riley", "Lois", "Nancy", "Tammy", "Terry" ]],
[TrainerType.HEX_MANIAC]: ["Kindra", "Patricia", "Tammy", "Tasha", "Valerie", "Alaina", "Kathleen", "Leah", "Makie", "Sylvia", "Anina", "Arachna", "Carrie", "Desdemona", "Josette", "Luna", "Melanie", "Osanna", "Raziah"], [TrainerType.HEX_MANIAC]: [ "Kindra", "Patricia", "Tammy", "Tasha", "Valerie", "Alaina", "Kathleen", "Leah", "Makie", "Sylvia", "Anina", "Arachna", "Carrie", "Desdemona", "Josette", "Luna", "Melanie", "Osanna", "Raziah" ],
}; };
// function used in a commented code // function used in a commented code
@ -140,7 +140,7 @@ function fetchAndPopulateTrainerNames(url: string, parser: DOMParser, trainerNam
if (!trainerListHeader) { if (!trainerListHeader) {
return []; return [];
} }
const elements = [...(trainerListHeader?.parentElement?.childNodes ?? [])]; const elements = [ ...(trainerListHeader?.parentElement?.childNodes ?? []) ];
const startChildIndex = elements.indexOf(trainerListHeader); const startChildIndex = elements.indexOf(trainerListHeader);
const endChildIndex = elements.findIndex(h => h.nodeName === "H2" && elements.indexOf(h) > startChildIndex); const endChildIndex = elements.findIndex(h => h.nodeName === "H2" && elements.indexOf(h) > startChildIndex);
const tables = elements.filter(t => { const tables = elements.filter(t => {
@ -152,7 +152,7 @@ function fetchAndPopulateTrainerNames(url: string, parser: DOMParser, trainerNam
}).map(t => t as Element); }).map(t => t as Element);
console.log(url, tables); console.log(url, tables);
for (const table of tables) { for (const table of tables) {
const trainerRows = [...table.querySelectorAll("tr:not(:first-child)")].filter(r => r.children.length === 9); const trainerRows = [ ...table.querySelectorAll("tr:not(:first-child)") ].filter(r => r.children.length === 9);
for (const row of trainerRows) { for (const row of trainerRows) {
const nameCell = row.firstElementChild; const nameCell = row.firstElementChild;
if (!nameCell) { if (!nameCell) {

View File

@ -171,9 +171,9 @@ export function getWeatherLapseMessage(weatherType: WeatherType): string | null
export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokemon): string | null { export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokemon): string | null {
switch (weatherType) { switch (weatherType) {
case WeatherType.SANDSTORM: case WeatherType.SANDSTORM:
return i18next.t("weather:sandstormDamageMessage", {pokemonNameWithAffix: getPokemonNameWithAffix(pokemon)}); return i18next.t("weather:sandstormDamageMessage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
case WeatherType.HAIL: case WeatherType.HAIL:
return i18next.t("weather:hailDamageMessage", {pokemonNameWithAffix: getPokemonNameWithAffix(pokemon)}); return i18next.t("weather:hailDamageMessage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
} }
return null; return null;
@ -238,9 +238,9 @@ export function getTerrainClearMessage(terrainType: TerrainType): string | null
export function getTerrainBlockMessage(pokemon: Pokemon, terrainType: TerrainType): string { export function getTerrainBlockMessage(pokemon: Pokemon, terrainType: TerrainType): string {
if (terrainType === TerrainType.MISTY) { if (terrainType === TerrainType.MISTY) {
return i18next.t("terrain:mistyBlockMessage", {pokemonNameWithAffix: getPokemonNameWithAffix(pokemon)}); return i18next.t("terrain:mistyBlockMessage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
} }
return i18next.t("terrain:defaultBlockMessage", {pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), terrainName: getTerrainName(terrainType)}); return i18next.t("terrain:defaultBlockMessage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), terrainName: getTerrainName(terrainType) });
} }
interface WeatherPoolEntry { interface WeatherPoolEntry {

View File

@ -1,4 +1,3 @@
export enum ArenaTagType { export enum ArenaTagType {
NONE = "NONE", NONE = "NONE",
MUD_SPORT = "MUD_SPORT", MUD_SPORT = "MUD_SPORT",
@ -25,5 +24,8 @@ export enum ArenaTagType {
SAFEGUARD = "SAFEGUARD", SAFEGUARD = "SAFEGUARD",
NO_CRIT = "NO_CRIT", NO_CRIT = "NO_CRIT",
IMPRISON = "IMPRISON", IMPRISON = "IMPRISON",
PLASMA_FISTS = "PLASMA_FISTS", ION_DELUGE = "ION_DELUGE",
FIRE_GRASS_PLEDGE = "FIRE_GRASS_PLEDGE",
WATER_FIRE_PLEDGE = "WATER_FIRE_PLEDGE",
GRASS_WATER_PLEDGE = "GRASS_WATER_PLEDGE",
} }

View File

@ -1,4 +1,3 @@
export enum BattlerTagType { export enum BattlerTagType {
NONE = "NONE", NONE = "NONE",
RECHARGING = "RECHARGING", RECHARGING = "RECHARGING",
@ -86,4 +85,5 @@ export enum BattlerTagType {
TAUNT = "TAUNT", TAUNT = "TAUNT",
IMPRISON = "IMPRISON", IMPRISON = "IMPRISON",
SYRUP_BOMB = "SYRUP_BOMB", SYRUP_BOMB = "SYRUP_BOMB",
ELECTRIFIED = "ELECTRIFIED",
} }

View File

@ -1,4 +1,3 @@
export enum BerryType { export enum BerryType {
SITRUS, SITRUS,
LUM, LUM,

View File

@ -1,4 +1,3 @@
export enum Biome { export enum Biome {
TOWN, TOWN,
PLAINS, PLAINS,

View File

@ -1,4 +1,3 @@
export enum TimeOfDay { export enum TimeOfDay {
ALL = -1, ALL = -1,
DAWN, DAWN,

View File

@ -392,16 +392,16 @@ export class Arena {
return true; return true;
} }
isMoveWeatherCancelled(user: Pokemon, move: Move) { public isMoveWeatherCancelled(user: Pokemon, move: Move): boolean {
return this.weather && !this.weather.isEffectSuppressed(this.scene) && this.weather.isMoveWeatherCancelled(user, move); return !!this.weather && !this.weather.isEffectSuppressed(this.scene) && this.weather.isMoveWeatherCancelled(user, move);
} }
isMoveTerrainCancelled(user: Pokemon, targets: BattlerIndex[], move: Move) { public isMoveTerrainCancelled(user: Pokemon, targets: BattlerIndex[], move: Move): boolean {
return this.terrain && this.terrain.isMoveTerrainCancelled(user, targets, move); return !!this.terrain && this.terrain.isMoveTerrainCancelled(user, targets, move);
} }
getTerrainType() : TerrainType { public getTerrainType(): TerrainType {
return this.terrain?.terrainType || TerrainType.NONE; return this.terrain?.terrainType ?? TerrainType.NONE;
} }
getAttackTypeMultiplier(attackType: Type, grounded: boolean): number { getAttackTypeMultiplier(attackType: Type, grounded: boolean): number {

View File

@ -101,14 +101,14 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
const getSprite = (spriteKey: string, hasShadow?: boolean, yShadow?: number) => { const getSprite = (spriteKey: string, hasShadow?: boolean, yShadow?: number) => {
const ret = this.scene.addFieldSprite(0, 0, spriteKey); const ret = this.scene.addFieldSprite(0, 0, spriteKey);
ret.setOrigin(0.5, 1); ret.setOrigin(0.5, 1);
ret.setPipeline(this.scene.spritePipeline, { tone: [0.0, 0.0, 0.0, 0.0], hasShadow: !!hasShadow, yShadowOffset: yShadow ?? 0 }); ret.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: !!hasShadow, yShadowOffset: yShadow ?? 0 });
return ret; return ret;
}; };
const getItemSprite = (spriteKey: string, hasShadow?: boolean, yShadow?: number) => { const getItemSprite = (spriteKey: string, hasShadow?: boolean, yShadow?: number) => {
const icon = this.scene.add.sprite(-19, 2, "items", spriteKey); const icon = this.scene.add.sprite(-19, 2, "items", spriteKey);
icon.setOrigin(0.5, 1); icon.setOrigin(0.5, 1);
icon.setPipeline(this.scene.spritePipeline, { tone: [0.0, 0.0, 0.0, 0.0], hasShadow: !!hasShadow, yShadowOffset: yShadow ?? 0 }); icon.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: !!hasShadow, yShadowOffset: yShadow ?? 0 });
return icon; return icon;
}; };

View File

@ -36,7 +36,7 @@ export default class PokemonSpriteSparkleHandler {
const ratioY = s.height / height; const ratioY = s.height / height;
const pixel = texture.manager.getPixel(pixelX, pixelY, texture.key, "__BASE"); const pixel = texture.manager.getPixel(pixelX, pixelY, texture.key, "__BASE");
if (pixel?.alpha) { if (pixel?.alpha) {
const [ xOffset, yOffset ] = [ -s.originX * s.width, -s.originY * s.height]; const [ xOffset, yOffset ] = [ -s.originX * s.width, -s.originY * s.height ];
const sparkle = (s.scene as BattleScene).addFieldSprite(((pokemon?.x || 0) + s.x + pixelX * ratioX + xOffset), ((pokemon?.y || 0) + s.y + pixelY * ratioY + yOffset), "tera_sparkle"); const sparkle = (s.scene as BattleScene).addFieldSprite(((pokemon?.x || 0) + s.x + pixelX * ratioX + xOffset), ((pokemon?.y || 0) + s.y + pixelY * ratioY + yOffset), "tera_sparkle");
sparkle.pipelineData["ignoreTimeTint"] = s.pipelineData["ignoreTimeTint"]; sparkle.pipelineData["ignoreTimeTint"] = s.pipelineData["ignoreTimeTint"];
sparkle.setName("sprite-tera-sparkle"); sparkle.setName("sprite-tera-sparkle");

View File

@ -3,7 +3,7 @@ import BattleScene, { AnySound } from "#app/battle-scene";
import { Variant, VariantSet, variantColorCache } from "#app/data/variant"; import { Variant, VariantSet, variantColorCache } from "#app/data/variant";
import { variantData } from "#app/data/variant"; import { variantData } from "#app/data/variant";
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "#app/ui/battle-info"; import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "#app/ui/battle-info";
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, VariableMoveTypeAttr, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatStagesAttr, SacrificialAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatStageChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, OneHitKOAccuracyAttr, RespectAttackTypeImmunityAttr, MoveTarget } from "#app/data/move"; import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, VariableMoveTypeAttr, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatStagesAttr, SacrificialAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatStageChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, OneHitKOAccuracyAttr, RespectAttackTypeImmunityAttr, MoveTarget, CombinedPledgeStabBoostAttr } from "#app/data/move";
import { default as PokemonSpecies, PokemonSpeciesForm, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species"; import { default as PokemonSpecies, PokemonSpeciesForm, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters"; import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters";
import { starterPassiveAbilities } from "#app/data/balance/passives"; import { starterPassiveAbilities } from "#app/data/balance/passives";
@ -696,7 +696,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* @see {@linkcode getFieldPositionOffset} * @see {@linkcode getFieldPositionOffset}
*/ */
getSubstituteOffset(): [ number, number ] { getSubstituteOffset(): [ number, number ] {
return this.isPlayer() ? [-30, 10] : [30, -10]; return this.isPlayer() ? [ -30, 10 ] : [ 30, -10 ];
} }
/** /**
@ -924,11 +924,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
break; break;
case Stat.SPD: case Stat.SPD:
// Check both the player and enemy to see if Tailwind should be multiplying the speed of the Pokemon const side = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
if ((this.isPlayer() && this.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.PLAYER)) if (this.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, side)) {
|| (!this.isPlayer() && this.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.ENEMY))) {
ret *= 2; ret *= 2;
} }
if (this.scene.arena.getTagOnSide(ArenaTagType.GRASS_WATER_PLEDGE, side)) {
ret >>= 2;
}
if (this.getTag(BattlerTagType.SLOW_START)) { if (this.getTag(BattlerTagType.SLOW_START)) {
ret >>= 1; ret >>= 1;
@ -1087,6 +1089,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return !!this.fusionSpecies; return !!this.fusionSpecies;
} }
/**
* Checks if the {@linkcode Pokemon} has a fusion with the specified {@linkcode Species}.
* @param species the pokemon {@linkcode Species} to check
* @returns `true` if the {@linkcode Pokemon} has a fusion with the specified {@linkcode Species}, `false` otherwise
*/
hasFusionSpecies(species: Species): boolean {
return this.fusionSpecies?.speciesId === species;
}
abstract isBoss(): boolean; abstract isBoss(): boolean;
getMoveset(ignoreOverride?: boolean): (PokemonMove | null)[] { getMoveset(ignoreOverride?: boolean): (PokemonMove | null)[] {
@ -1097,7 +1108,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
// Overrides moveset based on arrays specified in overrides.ts // Overrides moveset based on arrays specified in overrides.ts
let overrideArray: Moves | Array<Moves> = this.isPlayer() ? Overrides.MOVESET_OVERRIDE : Overrides.OPP_MOVESET_OVERRIDE; let overrideArray: Moves | Array<Moves> = this.isPlayer() ? Overrides.MOVESET_OVERRIDE : Overrides.OPP_MOVESET_OVERRIDE;
if (!Array.isArray(overrideArray)) { if (!Array.isArray(overrideArray)) {
overrideArray = [overrideArray]; overrideArray = [ overrideArray ];
} }
if (overrideArray.length > 0) { if (overrideArray.length > 0) {
if (!this.isPlayer()) { if (!this.isPlayer()) {
@ -1383,10 +1394,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const suppressed = new Utils.BooleanHolder(false); const suppressed = new Utils.BooleanHolder(false);
this.scene.getField(true).filter(p => p !== this).map(p => { this.scene.getField(true).filter(p => p !== this).map(p => {
if (p.getAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility()) { if (p.getAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility()) {
p.getAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, false, false, suppressed, [ability])); p.getAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, false, false, suppressed, [ ability ]));
} }
if (p.getPassiveAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility(true)) { if (p.getPassiveAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility(true)) {
p.getPassiveAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, true, false, suppressed, [ability])); p.getPassiveAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, true, false, suppressed, [ ability ]));
} }
}); });
if (suppressed.value) { if (suppressed.value) {
@ -1516,13 +1527,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
applyMoveAttrs(VariableMoveTypeAttr, this, null, move, moveTypeHolder); applyMoveAttrs(VariableMoveTypeAttr, this, null, move, moveTypeHolder);
applyPreAttackAbAttrs(MoveTypeChangeAbAttr, this, null, move, simulated, moveTypeHolder); applyPreAttackAbAttrs(MoveTypeChangeAbAttr, this, null, move, simulated, moveTypeHolder);
this.scene.arena.applyTags(ArenaTagType.PLASMA_FISTS, moveTypeHolder); this.scene.arena.applyTags(ArenaTagType.ION_DELUGE, moveTypeHolder);
if (this.getTag(BattlerTagType.ELECTRIFIED)) {
moveTypeHolder.value = Type.ELECTRIC;
}
return moveTypeHolder.value as Type; return moveTypeHolder.value as Type;
} }
/** /**
* Calculates the effectiveness of a move against the Pokémon. * Calculates the effectiveness of a move against the Pokémon.
* This includes modifiers from move and ability attributes. * This includes modifiers from move and ability attributes.
@ -1956,7 +1969,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
&& species.speciesId !== this.species.speciesId; && species.speciesId !== this.species.speciesId;
}; };
this.fusionSpecies = this.scene.randomSpecies(this.scene.currentBattle?.waveIndex || 0, this.level, false, filter, true); let fusionOverride: PokemonSpecies | undefined = undefined;
if (forStarter && this instanceof PlayerPokemon && Overrides.STARTER_FUSION_SPECIES_OVERRIDE) {
fusionOverride = getPokemonSpecies(Overrides.STARTER_FUSION_SPECIES_OVERRIDE);
} else if (this instanceof EnemyPokemon && Overrides.OPP_FUSION_SPECIES_OVERRIDE) {
fusionOverride = getPokemonSpecies(Overrides.OPP_FUSION_SPECIES_OVERRIDE);
}
this.fusionSpecies = fusionOverride ?? this.scene.randomSpecies(this.scene.currentBattle?.waveIndex || 0, this.level, false, filter, true);
this.fusionAbilityIndex = (this.fusionSpecies.abilityHidden && hasHiddenAbility ? 2 : this.fusionSpecies.ability2 !== this.fusionSpecies.ability1 ? randAbilityIndex : 0); this.fusionAbilityIndex = (this.fusionSpecies.abilityHidden && hasHiddenAbility ? 2 : this.fusionSpecies.ability2 !== this.fusionSpecies.ability1 ? randAbilityIndex : 0);
this.fusionShiny = this.shiny; this.fusionShiny = this.shiny;
this.fusionVariant = this.variant; this.fusionVariant = this.variant;
@ -2017,7 +2038,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
weight /= 100; weight /= 100;
} // Unimplemented level up moves are possible to generate, but 1% of their normal chance. } // Unimplemented level up moves are possible to generate, but 1% of their normal chance.
if (!movePool.some(m => m[0] === levelMove[1])) { if (!movePool.some(m => m[0] === levelMove[1])) {
movePool.push([levelMove[1], weight]); movePool.push([ levelMove[1], weight ]);
} }
} }
@ -2039,11 +2060,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
if (compatible && !movePool.some(m => m[0] === moveId) && !allMoves[moveId].name.endsWith(" (N)")) { if (compatible && !movePool.some(m => m[0] === moveId) && !allMoves[moveId].name.endsWith(" (N)")) {
if (tmPoolTiers[moveId] === ModifierTier.COMMON && this.level >= 15) { if (tmPoolTiers[moveId] === ModifierTier.COMMON && this.level >= 15) {
movePool.push([moveId, 4]); movePool.push([ moveId, 4 ]);
} else if (tmPoolTiers[moveId] === ModifierTier.GREAT && this.level >= 30) { } else if (tmPoolTiers[moveId] === ModifierTier.GREAT && this.level >= 30) {
movePool.push([moveId, 8]); movePool.push([ moveId, 8 ]);
} else if (tmPoolTiers[moveId] === ModifierTier.ULTRA && this.level >= 50) { } else if (tmPoolTiers[moveId] === ModifierTier.ULTRA && this.level >= 50) {
movePool.push([moveId, 14]); movePool.push([ moveId, 14 ]);
} }
} }
} }
@ -2052,23 +2073,23 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
for (let i = 0; i < 3; i++) { for (let i = 0; i < 3; i++) {
const moveId = speciesEggMoves[this.species.getRootSpeciesId()][i]; const moveId = speciesEggMoves[this.species.getRootSpeciesId()][i];
if (!movePool.some(m => m[0] === moveId) && !allMoves[moveId].name.endsWith(" (N)")) { if (!movePool.some(m => m[0] === moveId) && !allMoves[moveId].name.endsWith(" (N)")) {
movePool.push([moveId, 40]); movePool.push([ moveId, 40 ]);
} }
} }
const moveId = speciesEggMoves[this.species.getRootSpeciesId()][3]; const moveId = speciesEggMoves[this.species.getRootSpeciesId()][3];
if (this.level >= 170 && !movePool.some(m => m[0] === moveId) && !allMoves[moveId].name.endsWith(" (N)") && !this.isBoss()) { // No rare egg moves before e4 if (this.level >= 170 && !movePool.some(m => m[0] === moveId) && !allMoves[moveId].name.endsWith(" (N)") && !this.isBoss()) { // No rare egg moves before e4
movePool.push([moveId, 30]); movePool.push([ moveId, 30 ]);
} }
if (this.fusionSpecies) { if (this.fusionSpecies) {
for (let i = 0; i < 3; i++) { for (let i = 0; i < 3; i++) {
const moveId = speciesEggMoves[this.fusionSpecies.getRootSpeciesId()][i]; const moveId = speciesEggMoves[this.fusionSpecies.getRootSpeciesId()][i];
if (!movePool.some(m => m[0] === moveId) && !allMoves[moveId].name.endsWith(" (N)")) { if (!movePool.some(m => m[0] === moveId) && !allMoves[moveId].name.endsWith(" (N)")) {
movePool.push([moveId, 40]); movePool.push([ moveId, 40 ]);
} }
} }
const moveId = speciesEggMoves[this.fusionSpecies.getRootSpeciesId()][3]; const moveId = speciesEggMoves[this.fusionSpecies.getRootSpeciesId()][3];
if (this.level >= 170 && !movePool.some(m => m[0] === moveId) && !allMoves[moveId].name.endsWith(" (N)") && !this.isBoss()) {// No rare egg moves before e4 if (this.level >= 170 && !movePool.some(m => m[0] === moveId) && !allMoves[moveId].name.endsWith(" (N)") && !this.isBoss()) {// No rare egg moves before e4
movePool.push([moveId, 30]); movePool.push([ moveId, 30 ]);
} }
} }
} }
@ -2082,26 +2103,26 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
// Trainers never get OHKO moves // Trainers never get OHKO moves
movePool = movePool.filter(m => !allMoves[m[0]].hasAttr(OneHitKOAttr)); movePool = movePool.filter(m => !allMoves[m[0]].hasAttr(OneHitKOAttr));
// Half the weight of self KO moves // Half the weight of self KO moves
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].hasAttr(SacrificialAttr) ? 0.5 : 1)]); movePool = movePool.map(m => [ m[0], m[1] * (!!allMoves[m[0]].hasAttr(SacrificialAttr) ? 0.5 : 1) ]);
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].hasAttr(SacrificialAttrOnHit) ? 0.5 : 1)]); movePool = movePool.map(m => [ m[0], m[1] * (!!allMoves[m[0]].hasAttr(SacrificialAttrOnHit) ? 0.5 : 1) ]);
// Trainers get a weight bump to stat buffing moves // Trainers get a weight bump to stat buffing moves
movePool = movePool.map(m => [m[0], m[1] * (allMoves[m[0]].getAttrs(StatStageChangeAttr).some(a => a.stages > 1 && a.selfTarget) ? 1.25 : 1)]); movePool = movePool.map(m => [ m[0], m[1] * (allMoves[m[0]].getAttrs(StatStageChangeAttr).some(a => a.stages > 1 && a.selfTarget) ? 1.25 : 1) ]);
// Trainers get a weight decrease to multiturn moves // Trainers get a weight decrease to multiturn moves
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].hasAttr(ChargeAttr) || !!allMoves[m[0]].hasAttr(RechargeAttr) ? 0.7 : 1)]); movePool = movePool.map(m => [ m[0], m[1] * (!!allMoves[m[0]].hasAttr(ChargeAttr) || !!allMoves[m[0]].hasAttr(RechargeAttr) ? 0.7 : 1) ]);
} }
// Weight towards higher power moves, by reducing the power of moves below the highest power. // Weight towards higher power moves, by reducing the power of moves below the highest power.
// Caps max power at 90 to avoid something like hyper beam ruining the stats. // Caps max power at 90 to avoid something like hyper beam ruining the stats.
// This is a pretty soft weighting factor, although it is scaled with the weight multiplier. // This is a pretty soft weighting factor, although it is scaled with the weight multiplier.
const maxPower = Math.min(movePool.reduce((v, m) => Math.max(allMoves[m[0]].power, v), 40), 90); const maxPower = Math.min(movePool.reduce((v, m) => Math.max(allMoves[m[0]].power, v), 40), 90);
movePool = movePool.map(m => [m[0], m[1] * (allMoves[m[0]].category === MoveCategory.STATUS ? 1 : Math.max(Math.min(allMoves[m[0]].power/maxPower, 1), 0.5))]); movePool = movePool.map(m => [ m[0], m[1] * (allMoves[m[0]].category === MoveCategory.STATUS ? 1 : Math.max(Math.min(allMoves[m[0]].power / maxPower, 1), 0.5)) ]);
// Weight damaging moves against the lower stat // Weight damaging moves against the lower stat
const atk = this.getStat(Stat.ATK); const atk = this.getStat(Stat.ATK);
const spAtk = this.getStat(Stat.SPATK); const spAtk = this.getStat(Stat.SPATK);
const worseCategory: MoveCategory = atk > spAtk ? MoveCategory.SPECIAL : MoveCategory.PHYSICAL; const worseCategory: MoveCategory = atk > spAtk ? MoveCategory.SPECIAL : MoveCategory.PHYSICAL;
const statRatio = worseCategory === MoveCategory.PHYSICAL ? atk / spAtk : spAtk / atk; const statRatio = worseCategory === MoveCategory.PHYSICAL ? atk / spAtk : spAtk / atk;
movePool = movePool.map(m => [m[0], m[1] * (allMoves[m[0]].category === worseCategory ? statRatio : 1)]); movePool = movePool.map(m => [ m[0], m[1] * (allMoves[m[0]].category === worseCategory ? statRatio : 1) ]);
let weightMultiplier = 0.9; // The higher this is the more the game weights towards higher level moves. At 0 all moves are equal weight. let weightMultiplier = 0.9; // The higher this is the more the game weights towards higher level moves. At 0 all moves are equal weight.
if (this.hasTrainer()) { if (this.hasTrainer()) {
@ -2110,7 +2131,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (this.isBoss()) { if (this.isBoss()) {
weightMultiplier += 0.4; weightMultiplier += 0.4;
} }
const baseWeights: [Moves, number][] = movePool.map(m => [m[0], Math.ceil(Math.pow(m[1], weightMultiplier)*100)]); const baseWeights: [Moves, number][] = movePool.map(m => [ m[0], Math.ceil(Math.pow(m[1], weightMultiplier) * 100) ]);
if (this.hasTrainer() || this.isBoss()) { // Trainers and bosses always force a stab move if (this.hasTrainer() || this.isBoss()) { // Trainers and bosses always force a stab move
const stabMovePool = baseWeights.filter(m => allMoves[m[0]].category !== MoveCategory.STATUS && this.isOfType(allMoves[m[0]].type)); const stabMovePool = baseWeights.filter(m => allMoves[m[0]].category !== MoveCategory.STATUS && this.isOfType(allMoves[m[0]].type));
@ -2142,7 +2163,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
// Sqrt the weight of any damaging moves with overlapping types. This is about a 0.05 - 0.1 multiplier. // Sqrt the weight of any damaging moves with overlapping types. This is about a 0.05 - 0.1 multiplier.
// Other damaging moves 2x weight if 0-1 damaging moves, 0.5x if 2, 0.125x if 3. These weights double if STAB. // Other damaging moves 2x weight if 0-1 damaging moves, 0.5x if 2, 0.125x if 3. These weights double if STAB.
// Status moves remain unchanged on weight, this encourages 1-2 // Status moves remain unchanged on weight, this encourages 1-2
movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo?.moveId)).map(m => [m[0], this.moveset.some(mo => mo?.getMove().category !== MoveCategory.STATUS && mo?.getMove().type === allMoves[m[0]].type) ? Math.ceil(Math.sqrt(m[1])) : allMoves[m[0]].category !== MoveCategory.STATUS ? Math.ceil(m[1]/Math.max(Math.pow(4, this.moveset.filter(mo => (mo?.getMove().power!) > 1).length)/8, 0.5) * (this.isOfType(allMoves[m[0]].type) ? 2 : 1)) : m[1]]); // TODO: is this bang correct? movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo?.moveId)).map(m => [ m[0], this.moveset.some(mo => mo?.getMove().category !== MoveCategory.STATUS && mo?.getMove().type === allMoves[m[0]].type) ? Math.ceil(Math.sqrt(m[1])) : allMoves[m[0]].category !== MoveCategory.STATUS ? Math.ceil(m[1] / Math.max(Math.pow(4, this.moveset.filter(mo => (mo?.getMove().power!) > 1).length) / 8, 0.5) * (this.isOfType(allMoves[m[0]].type) ? 2 : 1)) : m[1] ]); // TODO: is this bang correct?
} else { // Non-trainer pokemon just use normal weights } else { // Non-trainer pokemon just use normal weights
movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo?.moveId)); movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo?.moveId));
} }
@ -2546,6 +2567,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (matchesSourceType) { if (matchesSourceType) {
stabMultiplier.value += 0.5; stabMultiplier.value += 0.5;
} }
applyMoveAttrs(CombinedPledgeStabBoostAttr, source, this, move, stabMultiplier);
if (sourceTeraType !== Type.UNKNOWN && sourceTeraType === moveType) { if (sourceTeraType !== Type.UNKNOWN && sourceTeraType === moveType) {
stabMultiplier.value += 0.5; stabMultiplier.value += 0.5;
} }
@ -2680,7 +2702,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (critOnly.value || critAlways) { if (critOnly.value || critAlways) {
isCritical = true; isCritical = true;
} else { } else {
const critChance = [24, 8, 2, 1][Math.max(0, Math.min(this.getCritStage(source, move), 3))]; const critChance = [ 24, 8, 2, 1 ][Math.max(0, Math.min(this.getCritStage(source, move), 3))];
isCritical = critChance === 1 || !this.scene.randBattleSeedInt(critChance); isCritical = critChance === 1 || !this.scene.randBattleSeedInt(critChance);
} }
@ -2865,7 +2887,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
isMax(): boolean { isMax(): boolean {
const maxForms = [SpeciesFormKey.GIGANTAMAX, SpeciesFormKey.GIGANTAMAX_RAPID, SpeciesFormKey.GIGANTAMAX_SINGLE, SpeciesFormKey.ETERNAMAX] as string[]; const maxForms = [ SpeciesFormKey.GIGANTAMAX, SpeciesFormKey.GIGANTAMAX_RAPID, SpeciesFormKey.GIGANTAMAX_SINGLE, SpeciesFormKey.ETERNAMAX ] as string[];
return maxForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && maxForms.includes(this.getFusionFormKey()!)); return maxForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && maxForms.includes(this.getFusionFormKey()!));
} }
@ -3353,7 +3375,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
break; break;
case StatusEffect.FREEZE: case StatusEffect.FREEZE:
if (this.isOfType(Type.ICE) || (this.scene?.arena?.weather?.weatherType &&[WeatherType.SUNNY, WeatherType.HARSH_SUN].includes(this.scene.arena.weather.weatherType))) { if (this.isOfType(Type.ICE) || (this.scene?.arena?.weather?.weatherType && [ WeatherType.SUNNY, WeatherType.HARSH_SUN ].includes(this.scene.arena.weather.weatherType))) {
return false; return false;
} }
break; break;
@ -3646,7 +3668,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const pixel = pixelData[f].slice(i, i + 4); const pixel = pixelData[f].slice(i, i + 4);
let [ r, g, b, a ] = pixel; let [ r, g, b, a ] = pixel;
if (variantColors) { if (variantColors) {
const color = Utils.rgbaToInt([r, g, b, a]); const color = Utils.rgbaToInt([ r, g, b, a ]);
if (variantColorSet.has(color)) { if (variantColorSet.has(color)) {
const mappedPixel = variantColorSet.get(color); const mappedPixel = variantColorSet.get(color);
if (mappedPixel) { if (mappedPixel) {
@ -3690,7 +3712,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
let [ r, g, b, a ] = [ pixelData[2 + f][i], pixelData[2 + f][i + 1], pixelData[2 + f][i + 2], pixelData[2 + f][i + 3] ]; let [ r, g, b, a ] = [ pixelData[2 + f][i], pixelData[2 + f][i + 1], pixelData[2 + f][i + 2], pixelData[2 + f][i + 3] ];
if (variantColors) { if (variantColors) {
const color = Utils.rgbaToInt([r, g, b, a]); const color = Utils.rgbaToInt([ r, g, b, a ]);
if (variantColorSet.has(color)) { if (variantColorSet.has(color)) {
const mappedPixel = variantColorSet.get(color); const mappedPixel = variantColorSet.get(color);
if (mappedPixel) { if (mappedPixel) {
@ -3985,7 +4007,7 @@ export class PlayerPokemon extends Pokemon {
let compatible = false; let compatible = false;
for (const p of tmSpecies[tm]) { for (const p of tmSpecies[tm]) {
if (Array.isArray(p)) { if (Array.isArray(p)) {
const [pkm, form] = p; const [ pkm, form ] = p;
if ((pkm === this.species.speciesId || this.fusionSpecies && pkm === this.fusionSpecies.speciesId) && form === this.getFormKey()) { if ((pkm === this.species.speciesId || this.fusionSpecies && pkm === this.fusionSpecies.speciesId) && form === this.getFormKey()) {
compatible = true; compatible = true;
break; break;
@ -4074,7 +4096,7 @@ export class PlayerPokemon extends Pokemon {
revivalBlessing(): Promise<void> { revivalBlessing(): Promise<void> {
return new Promise(resolve => { return new Promise(resolve => {
this.scene.ui.setMode(Mode.PARTY, PartyUiMode.REVIVAL_BLESSING, this.getFieldIndex(), (slotIndex:integer, option: PartyOption) => { this.scene.ui.setMode(Mode.PARTY, PartyUiMode.REVIVAL_BLESSING, this.getFieldIndex(), (slotIndex:integer, option: PartyOption) => {
if (slotIndex >= 0 && slotIndex<6) { if (slotIndex >= 0 && slotIndex < 6) {
const pokemon = this.scene.getParty()[slotIndex]; const pokemon = this.scene.getParty()[slotIndex];
if (!pokemon || !pokemon.isFainted()) { if (!pokemon || !pokemon.isFainted()) {
resolve(); resolve();
@ -4083,11 +4105,11 @@ export class PlayerPokemon extends Pokemon {
pokemon.resetTurnData(); pokemon.resetTurnData();
pokemon.resetStatus(); pokemon.resetStatus();
pokemon.heal(Math.min(Utils.toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp())); pokemon.heal(Math.min(Utils.toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp()));
this.scene.queueMessage(i18next.t("moveTriggers:revivalBlessing", {pokemonName: pokemon.name}), 0, true); this.scene.queueMessage(i18next.t("moveTriggers:revivalBlessing", { pokemonName: pokemon.name }), 0, true);
if (this.scene.currentBattle.double && this.scene.getParty().length > 1) { if (this.scene.currentBattle.double && this.scene.getParty().length > 1) {
const allyPokemon = this.getAlly(); const allyPokemon = this.getAlly();
if (slotIndex<=1) { if (slotIndex <= 1) {
// Revived ally pokemon // Revived ally pokemon
this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, SwitchType.SWITCH, pokemon.getFieldIndex(), slotIndex, false, true)); this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, SwitchType.SWITCH, pokemon.getFieldIndex(), slotIndex, false, true));
this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true)); this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true));
@ -4154,7 +4176,7 @@ export class PlayerPokemon extends Pokemon {
if (!isFusion) { if (!isFusion) {
const abilityCount = this.getSpeciesForm().getAbilityCount(); const abilityCount = this.getSpeciesForm().getAbilityCount();
const preEvoAbilityCount = preEvolution.getAbilityCount(); const preEvoAbilityCount = preEvolution.getAbilityCount();
if ([0, 1, 2].includes(this.abilityIndex)) { if ([ 0, 1, 2 ].includes(this.abilityIndex)) {
// Handles cases where a Pokemon with 3 abilities evolves into a Pokemon with 2 abilities (ie: Eevee -> any Eeveelution) // Handles cases where a Pokemon with 3 abilities evolves into a Pokemon with 2 abilities (ie: Eevee -> any Eeveelution)
if (this.abilityIndex === 2 && preEvoAbilityCount === 3 && abilityCount === 2) { if (this.abilityIndex === 2 && preEvoAbilityCount === 3 && abilityCount === 2) {
this.abilityIndex = 1; this.abilityIndex = 1;
@ -4167,7 +4189,7 @@ export class PlayerPokemon extends Pokemon {
} else { // Do the same as above, but for fusions } else { // Do the same as above, but for fusions
const abilityCount = this.getFusionSpeciesForm().getAbilityCount(); const abilityCount = this.getFusionSpeciesForm().getAbilityCount();
const preEvoAbilityCount = preEvolution.getAbilityCount(); const preEvoAbilityCount = preEvolution.getAbilityCount();
if ([0, 1, 2].includes(this.fusionAbilityIndex)) { if ([ 0, 1, 2 ].includes(this.fusionAbilityIndex)) {
if (this.fusionAbilityIndex === 2 && preEvoAbilityCount === 3 && abilityCount === 2) { if (this.fusionAbilityIndex === 2 && preEvoAbilityCount === 3 && abilityCount === 2) {
this.fusionAbilityIndex = 1; this.fusionAbilityIndex = 1;
} }
@ -4558,7 +4580,7 @@ export class EnemyPokemon extends Pokemon {
return move.category !== MoveCategory.STATUS return move.category !== MoveCategory.STATUS
&& moveTargets.some(p => { && moveTargets.some(p => {
const doesNotFail = move.applyConditions(this, p, move) || [Moves.SUCKER_PUNCH, Moves.UPPER_HAND, Moves.THUNDERCLAP].includes(move.id); const doesNotFail = move.applyConditions(this, p, move) || [ Moves.SUCKER_PUNCH, Moves.UPPER_HAND, Moves.THUNDERCLAP ].includes(move.id);
return doesNotFail && p.getAttackDamage(this, move, !p.battleData.abilityRevealed, false, isCritical).damage >= p.hp; return doesNotFail && p.getAttackDamage(this, move, !p.battleData.abilityRevealed, false, isCritical).damage >= p.hp;
}); });
}, this); }, this);
@ -4601,7 +4623,7 @@ export class EnemyPokemon extends Pokemon {
* If this move is unimplemented, or the move is known to fail when used, set its * If this move is unimplemented, or the move is known to fail when used, set its
* target score to -20 * target score to -20
*/ */
if ((move.name.endsWith(" (N)") || !move.applyConditions(this, target, move)) && ![Moves.SUCKER_PUNCH, Moves.UPPER_HAND, Moves.THUNDERCLAP].includes(move.id)) { if ((move.name.endsWith(" (N)") || !move.applyConditions(this, target, move)) && ![ Moves.SUCKER_PUNCH, Moves.UPPER_HAND, Moves.THUNDERCLAP ].includes(move.id)) {
targetScore = -20; targetScore = -20;
} else if (move instanceof AttackMove) { } else if (move instanceof AttackMove) {
/** /**
@ -4697,7 +4719,7 @@ export class EnemyPokemon extends Pokemon {
// Set target to BattlerIndex.ATTACKER when using a counter move // Set target to BattlerIndex.ATTACKER when using a counter move
// This is the same as when the player does so // This is the same as when the player does so
if (move.hasAttr(CounterDamageAttr)) { if (move.hasAttr(CounterDamageAttr)) {
return [BattlerIndex.ATTACKER]; return [ BattlerIndex.ATTACKER ];
} }
return []; return [];
@ -5011,8 +5033,12 @@ export class PokemonBattleSummonData {
export class PokemonTurnData { export class PokemonTurnData {
public flinched: boolean = false; public flinched: boolean = false;
public acted: boolean = false; public acted: boolean = false;
public hitCount: number; public hitCount: number = 0;
public hitsLeft: number; /**
* - `-1` = Calculate how many hits are left
* - `0` = Move is finished
*/
public hitsLeft: number = -1;
public damageDealt: number = 0; public damageDealt: number = 0;
public currDamageDealt: number = 0; public currDamageDealt: number = 0;
public damageTaken: number = 0; public damageTaken: number = 0;
@ -5021,6 +5047,7 @@ export class PokemonTurnData {
public statStagesIncreased: boolean = false; public statStagesIncreased: boolean = false;
public statStagesDecreased: boolean = false; public statStagesDecreased: boolean = false;
public moveEffectiveness: TypeDamageMultiplier | null = null; public moveEffectiveness: TypeDamageMultiplier | null = null;
public combiningPledge?: Moves;
} }
export enum AiType { export enum AiType {
@ -5098,7 +5125,7 @@ export class PokemonMove {
* @param {boolean} ignoreRestrictionTags If `true`, skips the check for move restriction tags (see {@link MoveRestrictionBattlerTag}) * @param {boolean} ignoreRestrictionTags If `true`, skips the check for move restriction tags (see {@link MoveRestrictionBattlerTag})
* @returns `true` if the move can be selected and used by the Pokemon, otherwise `false`. * @returns `true` if the move can be selected and used by the Pokemon, otherwise `false`.
*/ */
isUsable(pokemon: Pokemon, ignorePp?: boolean, ignoreRestrictionTags?: boolean): boolean { isUsable(pokemon: Pokemon, ignorePp: boolean = false, ignoreRestrictionTags: boolean = false): boolean {
if (this.moveId && !ignoreRestrictionTags && pokemon.isMoveRestricted(this.moveId)) { if (this.moveId && !ignoreRestrictionTags && pokemon.isMoveRestricted(this.moveId)) {
return false; return false;
} }

View File

@ -1,6 +1,6 @@
import BattleScene from "#app/battle-scene"; import BattleScene from "#app/battle-scene";
import {pokemonPrevolutions} from "#app/data/balance/pokemon-evolutions"; import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
import PokemonSpecies, {getPokemonSpecies} from "#app/data/pokemon-species"; import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species";
import { import {
TrainerConfig, TrainerConfig,
TrainerPartyCompoundTemplate, TrainerPartyCompoundTemplate,
@ -11,7 +11,7 @@ import {
trainerPartyTemplates, trainerPartyTemplates,
signatureSpecies signatureSpecies
} from "#app/data/trainer-config"; } from "#app/data/trainer-config";
import {EnemyPokemon} from "#app/field/pokemon"; import { EnemyPokemon } from "#app/field/pokemon";
import * as Utils from "#app/utils"; import * as Utils from "#app/utils";
import { PersistentModifier } from "#app/modifier/modifier"; import { PersistentModifier } from "#app/modifier/modifier";
import { trainerNamePools } from "#app/data/trainer-names"; import { trainerNamePools } from "#app/data/trainer-names";
@ -56,7 +56,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
if (partnerName) { if (partnerName) {
this.partnerName = partnerName; this.partnerName = partnerName;
} else { } else {
[this.name, this.partnerName] = this.name.split(" & "); [ this.name, this.partnerName ] = this.name.split(" & ");
} }
} else { } else {
this.partnerName = partnerName || Utils.randSeedItem(Array.isArray(namePool[0]) ? namePool[1] : namePool); this.partnerName = partnerName || Utils.randSeedItem(Array.isArray(namePool[0]) ? namePool[1] : namePool);
@ -82,7 +82,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
const getSprite = (hasShadow?: boolean, forceFemale?: boolean) => { const getSprite = (hasShadow?: boolean, forceFemale?: boolean) => {
const ret = this.scene.addFieldSprite(0, 0, this.config.getSpriteKey(variant === TrainerVariant.FEMALE || forceFemale, this.isDouble())); const ret = this.scene.addFieldSprite(0, 0, this.config.getSpriteKey(variant === TrainerVariant.FEMALE || forceFemale, this.isDouble()));
ret.setOrigin(0.5, 1); ret.setOrigin(0.5, 1);
ret.setPipeline(this.scene.spritePipeline, {tone: [0.0, 0.0, 0.0, 0.0], hasShadow: !!hasShadow}); ret.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: !!hasShadow });
return ret; return ret;
}; };
@ -126,7 +126,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
// Determine the title to include based on the configuration and includeTitle flag. // Determine the title to include based on the configuration and includeTitle flag.
let title = includeTitle && this.config.title ? this.config.title : null; let title = includeTitle && this.config.title ? this.config.title : null;
const evilTeamTitles = ["grunt"]; const evilTeamTitles = [ "grunt" ];
if (this.name === "" && evilTeamTitles.some(t => name.toLocaleLowerCase().includes(t))) { if (this.name === "" && evilTeamTitles.some(t => name.toLocaleLowerCase().includes(t))) {
// This is a evil team grunt so we localize it by only using the "name" as the title // This is a evil team grunt so we localize it by only using the "name" as the title
title = i18next.t(`trainerClasses:${name.toLowerCase().replace(/\s/g, "_")}`); title = i18next.t(`trainerClasses:${name.toLowerCase().replace(/\s/g, "_")}`);
@ -336,9 +336,9 @@ export default class Trainer extends Phaser.GameObjects.Container {
if (!(index % 2)) { if (!(index % 2)) {
// Since the only currently allowed double battle with named trainers is Tate & Liza, we need to make sure that Solrock is the first pokemon in the party for Tate and Lunatone for Liza // Since the only currently allowed double battle with named trainers is Tate & Liza, we need to make sure that Solrock is the first pokemon in the party for Tate and Lunatone for Liza
if (index === 0 && (TrainerType[this.config.trainerType] === TrainerType[TrainerType.TATE])) { if (index === 0 && (TrainerType[this.config.trainerType] === TrainerType[TrainerType.TATE])) {
newSpeciesPool = [Species.SOLROCK]; newSpeciesPool = [ Species.SOLROCK ];
} else if (index === 0 && (TrainerType[this.config.trainerType] === TrainerType[TrainerType.LIZA])) { } else if (index === 0 && (TrainerType[this.config.trainerType] === TrainerType[TrainerType.LIZA])) {
newSpeciesPool = [Species.LUNATONE]; newSpeciesPool = [ Species.LUNATONE ];
} else { } else {
newSpeciesPool = speciesPoolFiltered; newSpeciesPool = speciesPoolFiltered;
} }
@ -346,9 +346,9 @@ export default class Trainer extends Phaser.GameObjects.Container {
// If the index is odd, use the species pool for the partner trainer (that way he only uses his own pokemon in battle) // If the index is odd, use the species pool for the partner trainer (that way he only uses his own pokemon in battle)
// Since the only currently allowed double battle with named trainers is Tate & Liza, we need to make sure that Solrock is the first pokemon in the party for Tate and Lunatone for Liza // Since the only currently allowed double battle with named trainers is Tate & Liza, we need to make sure that Solrock is the first pokemon in the party for Tate and Lunatone for Liza
if (index === 1 && (TrainerType[this.config.trainerTypeDouble] === TrainerType[TrainerType.TATE])) { if (index === 1 && (TrainerType[this.config.trainerTypeDouble] === TrainerType[TrainerType.TATE])) {
newSpeciesPool = [Species.SOLROCK]; newSpeciesPool = [ Species.SOLROCK ];
} else if (index === 1 && (TrainerType[this.config.trainerTypeDouble] === TrainerType[TrainerType.LIZA])) { } else if (index === 1 && (TrainerType[this.config.trainerTypeDouble] === TrainerType[TrainerType.LIZA])) {
newSpeciesPool = [Species.LUNATONE]; newSpeciesPool = [ Species.LUNATONE ];
} else { } else {
newSpeciesPool = speciesPoolPartnerFiltered; newSpeciesPool = speciesPoolPartnerFiltered;
} }
@ -475,7 +475,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
} }
} }
return [party.indexOf(p), score]; return [ party.indexOf(p), score ];
}) as [integer, integer][]; }) as [integer, integer][];
return partyMemberScores; return partyMemberScores;

View File

@ -33,8 +33,8 @@ interface GameModeConfig {
} }
// Describes min and max waves for MEs in specific game modes // Describes min and max waves for MEs in specific game modes
export const CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [10, 180]; export const CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [ 10, 180 ];
export const CHALLENGE_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [10, 180]; export const CHALLENGE_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [ 10, 180 ];
export class GameMode implements GameModeConfig { export class GameMode implements GameModeConfig {
public modeId: GameModes; public modeId: GameModes;
@ -330,7 +330,7 @@ export class GameMode implements GameModeConfig {
getMysteryEncounterLegalWaves(): [number, number] { getMysteryEncounterLegalWaves(): [number, number] {
switch (this.modeId) { switch (this.modeId) {
default: default:
return [0, 0]; return [ 0, 0 ];
case GameModes.CLASSIC: case GameModes.CLASSIC:
return CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES; return CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES;
case GameModes.CHALLENGE: case GameModes.CHALLENGE:

View File

@ -1,12 +1,12 @@
import Phaser from "phaser"; import Phaser from "phaser";
import * as Utils from "./utils"; import * as Utils from "./utils";
import {deepCopy} from "./utils"; import { deepCopy } from "./utils";
import pad_generic from "./configs/inputs/pad_generic"; import pad_generic from "./configs/inputs/pad_generic";
import pad_unlicensedSNES from "./configs/inputs/pad_unlicensedSNES"; import pad_unlicensedSNES from "./configs/inputs/pad_unlicensedSNES";
import pad_xbox360 from "./configs/inputs/pad_xbox360"; import pad_xbox360 from "./configs/inputs/pad_xbox360";
import pad_dualshock from "./configs/inputs/pad_dualshock"; import pad_dualshock from "./configs/inputs/pad_dualshock";
import pad_procon from "./configs/inputs/pad_procon"; import pad_procon from "./configs/inputs/pad_procon";
import {Mode} from "./ui/ui"; import { Mode } from "./ui/ui";
import SettingsGamepadUiHandler from "./ui/settings/settings-gamepad-ui-handler"; import SettingsGamepadUiHandler from "./ui/settings/settings-gamepad-ui-handler";
import SettingsKeyboardUiHandler from "./ui/settings/settings-keyboard-ui-handler"; import SettingsKeyboardUiHandler from "./ui/settings/settings-keyboard-ui-handler";
import cfg_keyboard_qwerty from "./configs/inputs/cfg_keyboard_qwerty"; import cfg_keyboard_qwerty from "./configs/inputs/cfg_keyboard_qwerty";
@ -16,8 +16,8 @@ import {
getIconForLatestInput, swap, getIconForLatestInput, swap,
} from "#app/configs/inputs/configHandler"; } from "#app/configs/inputs/configHandler";
import BattleScene from "./battle-scene"; import BattleScene from "./battle-scene";
import {SettingGamepad} from "#app/system/settings/settings-gamepad"; import { SettingGamepad } from "#app/system/settings/settings-gamepad";
import {SettingKeyboard} from "#app/system/settings/settings-keyboard"; import { SettingKeyboard } from "#app/system/settings/settings-keyboard";
import TouchControl from "#app/touch-controls"; import TouchControl from "#app/touch-controls";
import { Button } from "#enums/buttons"; import { Button } from "#enums/buttons";
import { Device } from "#enums/devices"; import { Device } from "#enums/devices";
@ -294,7 +294,7 @@ export class InputsController {
this.setChosenGamepad(gamepadID); this.setChosenGamepad(gamepadID);
} }
const config = deepCopy(this.getConfig(gamepadID)) as InterfaceConfig; const config = deepCopy(this.getConfig(gamepadID)) as InterfaceConfig;
config.custom = this.configs[gamepadID]?.custom || {...config.default}; config.custom = this.configs[gamepadID]?.custom || { ...config.default };
this.configs[gamepadID] = config; this.configs[gamepadID] = config;
this.scene.gameData?.saveMappingConfigs(gamepadID, this.configs[gamepadID]); this.scene.gameData?.saveMappingConfigs(gamepadID, this.configs[gamepadID]);
} }
@ -307,9 +307,9 @@ export class InputsController {
* Initializes or updates configurations for connected keyboards. * Initializes or updates configurations for connected keyboards.
*/ */
setupKeyboard(): void { setupKeyboard(): void {
for (const layout of ["default"]) { for (const layout of [ "default" ]) {
const config = deepCopy(this.getConfigKeyboard(layout)) as InterfaceConfig; const config = deepCopy(this.getConfigKeyboard(layout)) as InterfaceConfig;
config.custom = this.configs[layout]?.custom || {...config.default}; config.custom = this.configs[layout]?.custom || { ...config.default };
this.configs[layout] = config; this.configs[layout] = config;
this.scene.gameData?.saveMappingConfigs(this.selectedDevice[Device.KEYBOARD], this.configs[layout]); this.scene.gameData?.saveMappingConfigs(this.selectedDevice[Device.KEYBOARD], this.configs[layout]);
} }
@ -330,7 +330,7 @@ export class InputsController {
return el !== null; return el !== null;
}) ?? []; }) ?? [];
for (const [index, thisGamepad] of this.gamepads.entries()) { for (const [ index, thisGamepad ] of this.gamepads.entries()) {
thisGamepad.index = index; // Overwrite the gamepad index, in case we had undefined gamepads earlier thisGamepad.index = index; // Overwrite the gamepad index, in case we had undefined gamepads earlier
} }
} }

View File

@ -19,7 +19,7 @@ import i18next from "i18next";
import { initStatsKeys } from "#app/ui/game-stats-ui-handler"; import { initStatsKeys } from "#app/ui/game-stats-ui-handler";
import { initVouchers } from "#app/system/voucher"; import { initVouchers } from "#app/system/voucher";
import { Biome } from "#enums/biome"; import { Biome } from "#enums/biome";
import {initMysteryEncounters} from "#app/data/mystery-encounters/mystery-encounters"; import { initMysteryEncounters } from "#app/data/mystery-encounters/mystery-encounters";
export class LoadingScene extends SceneBase { export class LoadingScene extends SceneBase {
public static readonly KEY = "loading"; public static readonly KEY = "loading";
@ -242,9 +242,9 @@ export class LoadingScene extends SceneBase {
this.loadAtlas("statuses", ""); this.loadAtlas("statuses", "");
this.loadAtlas("types", ""); this.loadAtlas("types", "");
} }
const availableLangs = ["en", "de", "it", "fr", "ja", "ko", "es", "pt-BR", "zh-CN"]; const availableLangs = [ "en", "de", "it", "fr", "ja", "ko", "es", "pt-BR", "zh-CN" ];
if (lang && availableLangs.includes(lang)) { if (lang && availableLangs.includes(lang)) {
this.loadImage("egg-update_"+lang, "events"); this.loadImage("egg-update_" + lang, "events");
} else { } else {
this.loadImage("egg-update_en", "events"); this.loadImage("egg-update_en", "events");
} }

View File

@ -1014,10 +1014,10 @@ class TempStatStageBoosterModifierTypeGenerator extends ModifierTypeGenerator {
class SpeciesStatBoosterModifierTypeGenerator extends ModifierTypeGenerator { class SpeciesStatBoosterModifierTypeGenerator extends ModifierTypeGenerator {
/** Object comprised of the currently available species-based stat boosting held items */ /** Object comprised of the currently available species-based stat boosting held items */
public static readonly items = { public static readonly items = {
LIGHT_BALL: { stats: [Stat.ATK, Stat.SPATK], multiplier: 2, species: [Species.PIKACHU] }, LIGHT_BALL: { stats: [ Stat.ATK, Stat.SPATK ], multiplier: 2, species: [ Species.PIKACHU ]},
THICK_CLUB: { stats: [Stat.ATK], multiplier: 2, species: [Species.CUBONE, Species.MAROWAK, Species.ALOLA_MAROWAK] }, THICK_CLUB: { stats: [ Stat.ATK ], multiplier: 2, species: [ Species.CUBONE, Species.MAROWAK, Species.ALOLA_MAROWAK ]},
METAL_POWDER: { stats: [Stat.DEF], multiplier: 2, species: [Species.DITTO] }, METAL_POWDER: { stats: [ Stat.DEF ], multiplier: 2, species: [ Species.DITTO ]},
QUICK_POWDER: { stats: [Stat.SPD], multiplier: 2, species: [Species.DITTO] }, QUICK_POWDER: { stats: [ Stat.SPD ], multiplier: 2, species: [ Species.DITTO ]},
}; };
constructor() { constructor() {
@ -1132,7 +1132,7 @@ class FormChangeItemModifierTypeGenerator extends ModifierTypeGenerator {
return new FormChangeItemModifierType(pregenArgs[0] as FormChangeItem); return new FormChangeItemModifierType(pregenArgs[0] as FormChangeItem);
} }
const formChangeItemPool = [...new Set(party.filter(p => pokemonFormChanges.hasOwnProperty(p.species.speciesId)).map(p => { const formChangeItemPool = [ ...new Set(party.filter(p => pokemonFormChanges.hasOwnProperty(p.species.speciesId)).map(p => {
const formChanges = pokemonFormChanges[p.species.speciesId]; const formChanges = pokemonFormChanges[p.species.speciesId];
let formChangeItemTriggers = formChanges.filter(fc => ((fc.formKey.indexOf(SpeciesFormKey.MEGA) === -1 && fc.formKey.indexOf(SpeciesFormKey.PRIMAL) === -1) || party[0].scene.getModifiers(MegaEvolutionAccessModifier).length) let formChangeItemTriggers = formChanges.filter(fc => ((fc.formKey.indexOf(SpeciesFormKey.MEGA) === -1 && fc.formKey.indexOf(SpeciesFormKey.PRIMAL) === -1) || party[0].scene.getModifiers(MegaEvolutionAccessModifier).length)
&& ((fc.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) === -1 && fc.formKey.indexOf(SpeciesFormKey.ETERNAMAX) === -1) || party[0].scene.getModifiers(GigantamaxAccessModifier).length) && ((fc.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) === -1 && fc.formKey.indexOf(SpeciesFormKey.ETERNAMAX) === -1) || party[0].scene.getModifiers(GigantamaxAccessModifier).length)
@ -1507,9 +1507,9 @@ export const modifierTypes = {
SOOTHE_BELL: () => new PokemonFriendshipBoosterModifierType("modifierType:ModifierType.SOOTHE_BELL", "soothe_bell"), SOOTHE_BELL: () => new PokemonFriendshipBoosterModifierType("modifierType:ModifierType.SOOTHE_BELL", "soothe_bell"),
SCOPE_LENS: () => new PokemonHeldItemModifierType("modifierType:ModifierType.SCOPE_LENS", "scope_lens", (type, args) => new CritBoosterModifier(type, (args[0] as Pokemon).id, 1)), SCOPE_LENS: () => new PokemonHeldItemModifierType("modifierType:ModifierType.SCOPE_LENS", "scope_lens", (type, args) => new CritBoosterModifier(type, (args[0] as Pokemon).id, 1)),
LEEK: () => new PokemonHeldItemModifierType("modifierType:ModifierType.LEEK", "leek", (type, args) => new SpeciesCritBoosterModifier(type, (args[0] as Pokemon).id, 2, [Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD])), LEEK: () => new PokemonHeldItemModifierType("modifierType:ModifierType.LEEK", "leek", (type, args) => new SpeciesCritBoosterModifier(type, (args[0] as Pokemon).id, 2, [ Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD ])),
EVIOLITE: () => new PokemonHeldItemModifierType("modifierType:ModifierType.EVIOLITE", "eviolite", (type, args) => new EvolutionStatBoosterModifier(type, (args[0] as Pokemon).id, [Stat.DEF, Stat.SPDEF], 1.5)), EVIOLITE: () => new PokemonHeldItemModifierType("modifierType:ModifierType.EVIOLITE", "eviolite", (type, args) => new EvolutionStatBoosterModifier(type, (args[0] as Pokemon).id, [ Stat.DEF, Stat.SPDEF ], 1.5)),
SOUL_DEW: () => new PokemonHeldItemModifierType("modifierType:ModifierType.SOUL_DEW", "soul_dew", (type, args) => new PokemonNatureWeightModifier(type, (args[0] as Pokemon).id)), SOUL_DEW: () => new PokemonHeldItemModifierType("modifierType:ModifierType.SOUL_DEW", "soul_dew", (type, args) => new PokemonNatureWeightModifier(type, (args[0] as Pokemon).id)),
@ -1583,7 +1583,7 @@ export const modifierTypes = {
if (pregenArgs) { if (pregenArgs) {
return new PokemonBaseStatFlatModifierType(pregenArgs[0] as number, pregenArgs[1] as Stat[]); return new PokemonBaseStatFlatModifierType(pregenArgs[0] as number, pregenArgs[1] as Stat[]);
} }
return new PokemonBaseStatFlatModifierType(randSeedInt(20), [Stat.HP, Stat.ATK, Stat.DEF]); return new PokemonBaseStatFlatModifierType(randSeedInt(20), [ Stat.HP, Stat.ATK, Stat.DEF ]);
}), }),
MYSTERY_ENCOUNTER_BLACK_SLUDGE: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => { MYSTERY_ENCOUNTER_BLACK_SLUDGE: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => {
if (pregenArgs) { if (pregenArgs) {
@ -1733,22 +1733,22 @@ const modifierPool: ModifierPool = {
|| (p.isFusion() && checkedSpecies.includes(p.getFusionSpeciesForm(true).speciesId)))) ? 12 : 0; || (p.isFusion() && checkedSpecies.includes(p.getFusionSpeciesForm(true).speciesId)))) ? 12 : 0;
}, 12), }, 12),
new WeightedModifierType(modifierTypes.TOXIC_ORB, (party: Pokemon[]) => { new WeightedModifierType(modifierTypes.TOXIC_ORB, (party: Pokemon[]) => {
const checkedAbilities = [Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.TOXIC_BOOST, Abilities.POISON_HEAL, Abilities.MAGIC_GUARD]; const checkedAbilities = [ Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.TOXIC_BOOST, Abilities.POISON_HEAL, Abilities.MAGIC_GUARD ];
const checkedMoves = [Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT]; const checkedMoves = [ Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT ];
// If a party member doesn't already have one of these two orbs and has one of the above moves or abilities, the orb can appear // If a party member doesn't already have one of these two orbs and has one of the above moves or abilities, the orb can appear
return party.some(p => !p.getHeldItems().some(i => i instanceof TurnStatusEffectModifier) return party.some(p => !p.getHeldItems().some(i => i instanceof TurnStatusEffectModifier)
&& (checkedAbilities.some(a => p.hasAbility(a, false, true)) && (checkedAbilities.some(a => p.hasAbility(a, false, true))
|| p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0; || p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0;
}, 10), }, 10),
new WeightedModifierType(modifierTypes.FLAME_ORB, (party: Pokemon[]) => { new WeightedModifierType(modifierTypes.FLAME_ORB, (party: Pokemon[]) => {
const checkedAbilities = [Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.FLARE_BOOST, Abilities.MAGIC_GUARD]; const checkedAbilities = [ Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.FLARE_BOOST, Abilities.MAGIC_GUARD ];
const checkedMoves = [Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT]; const checkedMoves = [ Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT ];
// If a party member doesn't already have one of these two orbs and has one of the above moves or abilities, the orb can appear // If a party member doesn't already have one of these two orbs and has one of the above moves or abilities, the orb can appear
return party.some(p => !p.getHeldItems().some(i => i instanceof TurnStatusEffectModifier) return party.some(p => !p.getHeldItems().some(i => i instanceof TurnStatusEffectModifier)
&& (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0; && (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0;
}, 10), }, 10),
new WeightedModifierType(modifierTypes.WHITE_HERB, (party: Pokemon[]) => { new WeightedModifierType(modifierTypes.WHITE_HERB, (party: Pokemon[]) => {
const checkedAbilities = [Abilities.WEAK_ARMOR, Abilities.CONTRARY, Abilities.MOODY, Abilities.ANGER_SHELL, Abilities.COMPETITIVE, Abilities.DEFIANT]; const checkedAbilities = [ Abilities.WEAK_ARMOR, Abilities.CONTRARY, Abilities.MOODY, Abilities.ANGER_SHELL, Abilities.COMPETITIVE, Abilities.DEFIANT ];
const weightMultiplier = party.filter( const weightMultiplier = party.filter(
p => !p.getHeldItems().some(i => i instanceof ResetNegativeStatStageModifier && i.stackCount >= i.getMaxHeldItemCount(p)) && p => !p.getHeldItems().some(i => i instanceof ResetNegativeStatStageModifier && i.stackCount >= i.getMaxHeldItemCount(p)) &&
(checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && selfStatLowerMoves.includes(m.moveId)))).length; (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && selfStatLowerMoves.includes(m.moveId)))).length;
@ -2196,7 +2196,7 @@ export function overridePlayerModifierTypeOptions(options: ModifierTypeOption[],
let modifierType: ModifierType | null = modifierFunc(); let modifierType: ModifierType | null = modifierFunc();
if (modifierType instanceof ModifierTypeGenerator) { if (modifierType instanceof ModifierTypeGenerator) {
const pregenArgs = ("type" in override) && (override.type !== null) ? [override.type] : undefined; const pregenArgs = ("type" in override) && (override.type !== null) ? [ override.type ] : undefined;
modifierType = modifierType.generateType(party, pregenArgs); modifierType = modifierType.generateType(party, pregenArgs);
} }

View File

@ -408,7 +408,7 @@ export abstract class LapsingPersistentModifier extends PersistentModifier {
} }
getArgs(): any[] { getArgs(): any[] {
return [this.maxBattles, this.battleCount]; return [ this.maxBattles, this.battleCount ];
} }
getMaxStackCount(_scene: BattleScene, _forThreshold?: boolean): number { getMaxStackCount(_scene: BattleScene, _forThreshold?: boolean): number {
@ -939,7 +939,7 @@ export class EvoTrackerModifier extends PokemonHeldItemModifier {
} }
getArgs(): any[] { getArgs(): any[] {
return super.getArgs().concat([this.species, this.required]); return super.getArgs().concat([ this.species, this.required ]);
} }
/** /**
@ -1860,7 +1860,7 @@ export class BerryModifier extends PokemonHeldItemModifier {
} }
getMaxHeldItemCount(pokemon: Pokemon): number { getMaxHeldItemCount(pokemon: Pokemon): number {
if ([BerryType.LUM, BerryType.LEPPA, BerryType.SITRUS, BerryType.ENIGMA].includes(this.berryType)) { if ([ BerryType.LUM, BerryType.LEPPA, BerryType.SITRUS, BerryType.ENIGMA ].includes(this.berryType)) {
return 2; return 2;
} }
return 3; return 3;
@ -2204,7 +2204,7 @@ export class PokemonLevelIncrementModifier extends ConsumablePokemonModifier {
* @param levelCount The amount of levels to increment * @param levelCount The amount of levels to increment
* @returns always `true` * @returns always `true`
*/ */
override apply(playerPokemon: PlayerPokemon, levelCount: NumberHolder): boolean { override apply(playerPokemon: PlayerPokemon, levelCount: NumberHolder = new NumberHolder(1)): boolean {
playerPokemon.scene.applyModifiers(LevelIncrementBoosterModifier, true, levelCount); playerPokemon.scene.applyModifiers(LevelIncrementBoosterModifier, true, levelCount);
playerPokemon.level += levelCount.value; playerPokemon.level += levelCount.value;
@ -3602,7 +3602,7 @@ export function overrideModifiers(scene: BattleScene, isPlayer: boolean = true):
let modifierType: ModifierType | null = modifierFunc(); let modifierType: ModifierType | null = modifierFunc();
if (modifierType instanceof ModifierTypeGenerator) { if (modifierType instanceof ModifierTypeGenerator) {
const pregenArgs = ("type" in item) && (item.type !== null) ? [item.type] : undefined; const pregenArgs = ("type" in item) && (item.type !== null) ? [ item.type ] : undefined;
modifierType = modifierType.generateType([], pregenArgs); modifierType = modifierType.generateType([], pregenArgs);
} }
@ -3643,7 +3643,7 @@ export function overrideHeldItems(scene: BattleScene, pokemon: Pokemon, isPlayer
const qty = item.count || 1; const qty = item.count || 1;
if (modifierType instanceof ModifierTypeGenerator) { if (modifierType instanceof ModifierTypeGenerator) {
const pregenArgs = ("type" in item) && (item.type !== null) ? [item.type] : undefined; const pregenArgs = ("type" in item) && (item.type !== null) ? [ item.type ] : undefined;
modifierType = modifierType.generateType([], pregenArgs); modifierType = modifierType.generateType([], pregenArgs);
} }

View File

@ -100,6 +100,14 @@ class DefaultOverrides {
* @example SPECIES_OVERRIDE = Species.Bulbasaur; * @example SPECIES_OVERRIDE = Species.Bulbasaur;
*/ */
readonly STARTER_SPECIES_OVERRIDE: Species | number = 0; readonly STARTER_SPECIES_OVERRIDE: Species | number = 0;
/**
* This will force your starter to be a random fusion
*/
readonly STARTER_FUSION_OVERRIDE: boolean = false;
/**
* This will override the species of the fusion
*/
readonly STARTER_FUSION_SPECIES_OVERRIDE: Species | integer = 0;
readonly ABILITY_OVERRIDE: Abilities = Abilities.NONE; readonly ABILITY_OVERRIDE: Abilities = Abilities.NONE;
readonly PASSIVE_ABILITY_OVERRIDE: Abilities = Abilities.NONE; readonly PASSIVE_ABILITY_OVERRIDE: Abilities = Abilities.NONE;
readonly STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE; readonly STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE;
@ -112,6 +120,14 @@ class DefaultOverrides {
// OPPONENT / ENEMY OVERRIDES // OPPONENT / ENEMY OVERRIDES
// -------------------------- // --------------------------
readonly OPP_SPECIES_OVERRIDE: Species | number = 0; readonly OPP_SPECIES_OVERRIDE: Species | number = 0;
/**
* This will make all opponents fused Pokemon
*/
readonly OPP_FUSION_OVERRIDE: boolean = false;
/**
* This will override the species of the fusion only when the opponent is already a fusion
*/
readonly OPP_FUSION_SPECIES_OVERRIDE: Species | integer = 0;
readonly OPP_LEVEL_OVERRIDE: number = 0; readonly OPP_LEVEL_OVERRIDE: number = 0;
readonly OPP_ABILITY_OVERRIDE: Abilities = Abilities.NONE; readonly OPP_ABILITY_OVERRIDE: Abilities = Abilities.NONE;
readonly OPP_PASSIVE_ABILITY_OVERRIDE: Abilities = Abilities.NONE; readonly OPP_PASSIVE_ABILITY_OVERRIDE: Abilities = Abilities.NONE;

View File

@ -248,7 +248,7 @@ export class AttemptCapturePhase extends PokemonPhase {
} }
}); });
}; };
Promise.all([pokemon.hideInfo(), this.scene.gameData.setPokemonCaught(pokemon)]).then(() => { Promise.all([ pokemon.hideInfo(), this.scene.gameData.setPokemonCaught(pokemon) ]).then(() => {
if (this.scene.getParty().length === 6) { if (this.scene.getParty().length === 6) {
const promptRelease = () => { const promptRelease = () => {
this.scene.ui.showText(i18next.t("battle:partyFull", { pokemonName: pokemon.getNameToRender() }), null, () => { this.scene.ui.showText(i18next.t("battle:partyFull", { pokemonName: pokemon.getNameToRender() }), null, () => {

View File

@ -33,7 +33,7 @@ export class AttemptRunPhase extends PokemonPhase {
this.scene.queueMessage(i18next.t("battle:runAwaySuccess"), null, true, 500); this.scene.queueMessage(i18next.t("battle:runAwaySuccess"), null, true, 500);
this.scene.tweens.add({ this.scene.tweens.add({
targets: [this.scene.arenaEnemy, enemyField].flat(), targets: [ this.scene.arenaEnemy, enemyField ].flat(),
alpha: 0, alpha: 0,
duration: 250, duration: 250,
ease: "Sine.easeIn", ease: "Sine.easeIn",

View File

@ -12,7 +12,7 @@ export class BattlePhase extends Phase {
const tintSprites = this.scene.currentBattle.trainer?.getTintSprites()!; // TODO: is this bang correct? const tintSprites = this.scene.currentBattle.trainer?.getTintSprites()!; // TODO: is this bang correct?
for (let i = 0; i < sprites.length; i++) { for (let i = 0; i < sprites.length; i++) {
const visible = !trainerSlot || !i === (trainerSlot === TrainerSlot.TRAINER) || sprites.length < 2; const visible = !trainerSlot || !i === (trainerSlot === TrainerSlot.TRAINER) || sprites.length < 2;
[sprites[i], tintSprites[i]].map(sprite => { [ sprites[i], tintSprites[i] ].map(sprite => {
if (visible) { if (visible) {
sprite.x = trainerSlot || sprites.length < 2 ? 0 : i ? 16 : -16; sprite.x = trainerSlot || sprites.length < 2 ? 0 : i ? 16 : -16;
} }

View File

@ -93,7 +93,7 @@ export class CommandPhase extends FieldPhase {
const turnCommand: TurnCommand = { command: Command.FIGHT, cursor: cursor, move: { move: moveId, targets: [], ignorePP: args[0] }, args: args }; const turnCommand: TurnCommand = { command: Command.FIGHT, cursor: cursor, move: { move: moveId, targets: [], ignorePP: args[0] }, args: args };
const moveTargets: MoveTargetSet = args.length < 3 ? getMoveTargets(playerPokemon, moveId) : args[2]; const moveTargets: MoveTargetSet = args.length < 3 ? getMoveTargets(playerPokemon, moveId) : args[2];
if (!moveId) { if (!moveId) {
turnCommand.targets = [this.fieldIndex]; turnCommand.targets = [ this.fieldIndex ];
} }
console.log(moveTargets, getPokemonNameWithAffix(playerPokemon)); console.log(moveTargets, getPokemonNameWithAffix(playerPokemon));
if (moveTargets.targets.length > 1 && moveTargets.multiple) { if (moveTargets.targets.length > 1 && moveTargets.multiple) {

View File

@ -28,7 +28,7 @@ export class EggLapsePhase extends Phase {
return Overrides.EGG_IMMEDIATE_HATCH_OVERRIDE ? true : --egg.hatchWaves < 1; return Overrides.EGG_IMMEDIATE_HATCH_OVERRIDE ? true : --egg.hatchWaves < 1;
}); });
const eggsToHatchCount: number = eggsToHatch.length; const eggsToHatchCount: number = eggsToHatch.length;
this.eggHatchData= []; this.eggHatchData = [];
if (eggsToHatchCount > 0) { if (eggsToHatchCount > 0) {
if (eggsToHatchCount >= this.minEggsToSkip && this.scene.eggSkipPreference === 1) { if (eggsToHatchCount >= this.minEggsToSkip && this.scene.eggSkipPreference === 1) {

View File

@ -259,7 +259,7 @@ export class EncounterPhase extends BattlePhase {
const enemyField = this.scene.getEnemyField(); const enemyField = this.scene.getEnemyField();
this.scene.tweens.add({ this.scene.tweens.add({
targets: [this.scene.arenaEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.arenaPlayer, this.scene.trainer].flat(), targets: [ this.scene.arenaEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.arenaPlayer, this.scene.trainer ].flat(),
x: (_target, _key, value, fieldIndex: integer) => fieldIndex < 2 + (enemyField.length) ? value + 300 : value - 300, x: (_target, _key, value, fieldIndex: integer) => fieldIndex < 2 + (enemyField.length) ? value + 300 : value - 300,
duration: 2000, duration: 2000,
onComplete: () => { onComplete: () => {
@ -287,7 +287,7 @@ export class EncounterPhase extends BattlePhase {
const enemyField = this.scene.getEnemyField(); const enemyField = this.scene.getEnemyField();
if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) { if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
return i18next.t("battle:bossAppeared", { bossName: getPokemonNameWithAffix(enemyField[0])}); return i18next.t("battle:bossAppeared", { bossName: getPokemonNameWithAffix(enemyField[0]) });
} }
if (this.scene.currentBattle.battleType === BattleType.TRAINER) { if (this.scene.currentBattle.battleType === BattleType.TRAINER) {
@ -436,7 +436,7 @@ export class EncounterPhase extends BattlePhase {
} }
}); });
if (![BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.scene.currentBattle.battleType)) { if (![ BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER ].includes(this.scene.currentBattle.battleType)) {
enemyField.map(p => this.scene.pushConditionalPhase(new PostSummonPhase(this.scene, p.getBattlerIndex()), () => { enemyField.map(p => this.scene.pushConditionalPhase(new PostSummonPhase(this.scene, p.getBattlerIndex()), () => {
// if there is not a player party, we can't continue // if there is not a player party, we can't continue
if (!this.scene.getParty()?.length) { if (!this.scene.getParty()?.length) {
@ -505,7 +505,7 @@ export class EncounterPhase extends BattlePhase {
} else { } else {
const count = 5643853 + this.scene.gameData.gameStats.classicSessionsPlayed; const count = 5643853 + this.scene.gameData.gameStats.classicSessionsPlayed;
// The line below checks if an English ordinal is necessary or not based on whether an entry for encounterLocalizationKey exists in the language or not. // The line below checks if an English ordinal is necessary or not based on whether an entry for encounterLocalizationKey exists in the language or not.
const ordinalUsed = !i18next.exists(localizationKey, {fallbackLng: []}) || i18next.resolvedLanguage === "en" ? i18next.t("battleSpecDialogue:key", { count: count, ordinal: true }) : ""; const ordinalUsed = !i18next.exists(localizationKey, { fallbackLng: []}) || i18next.resolvedLanguage === "en" ? i18next.t("battleSpecDialogue:key", { count: count, ordinal: true }) : "";
const cycleCount = count.toLocaleString() + ordinalUsed; const cycleCount = count.toLocaleString() + ordinalUsed;
const genderIndex = this.scene.gameData.gender ?? PlayerGender.UNSET; const genderIndex = this.scene.gameData.gender ?? PlayerGender.UNSET;
const genderStr = PlayerGender[genderIndex].toLowerCase(); const genderStr = PlayerGender[genderIndex].toLowerCase();

View File

@ -61,7 +61,7 @@ export class EnemyCommandPhase extends FieldPhase {
const index = trainer.getNextSummonIndex(enemyPokemon.trainerSlot, partyMemberScores); const index = trainer.getNextSummonIndex(enemyPokemon.trainerSlot, partyMemberScores);
battle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] = battle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] =
{ command: Command.POKEMON, cursor: index, args: [false], skip: this.skipTurn }; { command: Command.POKEMON, cursor: index, args: [ false ], skip: this.skipTurn };
battle.enemySwitchCounter++; battle.enemySwitchCounter++;

View File

@ -111,7 +111,7 @@ export class FaintPhase extends PokemonPhase {
} }
} else { } else {
this.scene.unshiftPhase(new VictoryPhase(this.scene, this.battlerIndex)); this.scene.unshiftPhase(new VictoryPhase(this.scene, this.battlerIndex));
if ([BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.scene.currentBattle.battleType)) { if ([ BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER ].includes(this.scene.currentBattle.battleType)) {
const hasReservePartyMember = !!this.scene.getEnemyParty().filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot).length; const hasReservePartyMember = !!this.scene.getEnemyParty().filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot).length;
if (hasReservePartyMember) { if (hasReservePartyMember) {
this.scene.pushPhase(new SwitchSummonPhase(this.scene, SwitchType.SWITCH, this.fieldIndex, -1, false, false)); this.scene.pushPhase(new SwitchSummonPhase(this.scene, SwitchType.SWITCH, this.fieldIndex, -1, false, false));

View File

@ -59,7 +59,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
const learnMovePrompt = i18next.t("battle:learnMovePrompt", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }); const learnMovePrompt = i18next.t("battle:learnMovePrompt", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name });
const moveLimitReached = i18next.t("battle:learnMoveLimitReached", { pokemonName: getPokemonNameWithAffix(pokemon) }); const moveLimitReached = i18next.t("battle:learnMoveLimitReached", { pokemonName: getPokemonNameWithAffix(pokemon) });
const shouldReplaceQ = i18next.t("battle:learnMoveReplaceQuestion", { moveName: move.name }); const shouldReplaceQ = i18next.t("battle:learnMoveReplaceQuestion", { moveName: move.name });
const preQText = [learnMovePrompt, moveLimitReached].join("$"); const preQText = [ learnMovePrompt, moveLimitReached ].join("$");
await this.scene.ui.showTextPromise(preQText); await this.scene.ui.showTextPromise(preQText);
await this.scene.ui.showTextPromise(shouldReplaceQ, undefined, false); await this.scene.ui.showTextPromise(shouldReplaceQ, undefined, false);
await this.scene.ui.setModeWithoutClear(Mode.CONFIRM, await this.scene.ui.setModeWithoutClear(Mode.CONFIRM,
@ -91,7 +91,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
return; return;
} }
const forgetSuccessText = i18next.t("battle:learnMoveForgetSuccess", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: pokemon.moveset[moveIndex]!.getName() }); const forgetSuccessText = i18next.t("battle:learnMoveForgetSuccess", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: pokemon.moveset[moveIndex]!.getName() });
const fullText = [i18next.t("battle:countdownPoof"), forgetSuccessText, i18next.t("battle:learnMoveAnd")].join("$"); const fullText = [ i18next.t("battle:countdownPoof"), forgetSuccessText, i18next.t("battle:learnMoveAnd") ].join("$");
this.scene.ui.setMode(this.messageMode).then(() => this.learnMove(moveIndex, move, pokemon, fullText)); this.scene.ui.setMode(this.messageMode).then(() => this.learnMove(moveIndex, move, pokemon, fullText));
}); });
} }
@ -144,12 +144,12 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
} }
pokemon.setMove(index, this.moveId); pokemon.setMove(index, this.moveId);
initMoveAnim(this.scene, this.moveId).then(() => { initMoveAnim(this.scene, this.moveId).then(() => {
loadMoveAnimAssets(this.scene, [this.moveId], true); loadMoveAnimAssets(this.scene, [ this.moveId ], true);
this.scene.playSound("level_up_fanfare"); // Sound loaded into game as is this.scene.playSound("level_up_fanfare"); // Sound loaded into game as is
}); });
this.scene.ui.setMode(this.messageMode); this.scene.ui.setMode(this.messageMode);
const learnMoveText = i18next.t("battle:learnMove", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }); const learnMoveText = i18next.t("battle:learnMove", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name });
textMessage = textMessage ? textMessage+"$"+learnMoveText : learnMoveText; textMessage = textMessage ? textMessage + "$" + learnMoveText : learnMoveText;
await this.scene.ui.showTextPromise(textMessage, this.messageMode === Mode.EVOLUTION_SCENE ? 1000 : undefined, true); await this.scene.ui.showTextPromise(textMessage, this.messageMode === Mode.EVOLUTION_SCENE ? 1000 : undefined, true);
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeMoveLearnedTrigger, true); this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeMoveLearnedTrigger, true);
this.end(); this.end();

View File

@ -22,7 +22,7 @@ export class LoginPhase extends Phase {
const hasSession = !!Utils.getCookie(Utils.sessionIdKey); const hasSession = !!Utils.getCookie(Utils.sessionIdKey);
this.scene.ui.setMode(Mode.LOADING, { buttonActions: [] }); this.scene.ui.setMode(Mode.LOADING, { buttonActions: []});
Utils.executeIf(bypassLogin || hasSession, updateUserInfo).then(response => { Utils.executeIf(bypassLogin || hasSession, updateUserInfo).then(response => {
const success = response ? response[0] : false; const success = response ? response[0] : false;
const statusCode = response ? response[1] : null; const statusCode = response ? response[1] : null;

View File

@ -29,7 +29,7 @@ export class MoveAnimTestPhase extends BattlePhase {
} }
initMoveAnim(this.scene, moveId).then(() => { initMoveAnim(this.scene, moveId).then(() => {
loadMoveAnimAssets(this.scene, [moveId], true) loadMoveAnimAssets(this.scene, [ moveId ], true)
.then(() => { .then(() => {
const user = player ? this.scene.getPlayerPokemon()! : this.scene.getEnemyPokemon()!; const user = player ? this.scene.getPlayerPokemon()! : this.scene.getEnemyPokemon()!;
const target = (player !== (allMoves[moveId] instanceof SelfStatusMove)) ? this.scene.getEnemyPokemon()! : this.scene.getPlayerPokemon()!; const target = (player !== (allMoves[moveId] instanceof SelfStatusMove)) ? this.scene.getEnemyPokemon()! : this.scene.getPlayerPokemon()!;

View File

@ -70,7 +70,7 @@ export class MoveEffectPhase extends PokemonPhase {
* resolve the move's total hit count. This block combines the * resolve the move's total hit count. This block combines the
* effects of the move itself, Parental Bond, and Multi-Lens to do so. * effects of the move itself, Parental Bond, and Multi-Lens to do so.
*/ */
if (user.turnData.hitsLeft === undefined) { if (user.turnData.hitsLeft === -1) {
const hitCount = new Utils.IntegerHolder(1); const hitCount = new Utils.IntegerHolder(1);
// Assume single target for multi hit // Assume single target for multi hit
applyMoveAttrs(MultiHitAttr, user, this.getTarget() ?? null, move, hitCount); applyMoveAttrs(MultiHitAttr, user, this.getTarget() ?? null, move, hitCount);
@ -96,7 +96,7 @@ export class MoveEffectPhase extends PokemonPhase {
* Stores results of hit checks of the invoked move against all targets, organized by battler index. * Stores results of hit checks of the invoked move against all targets, organized by battler index.
* @see {@linkcode hitCheck} * @see {@linkcode hitCheck}
*/ */
const targetHitChecks = Object.fromEntries(targets.map(p => [p.getBattlerIndex(), this.hitCheck(p)])); const targetHitChecks = Object.fromEntries(targets.map(p => [ p.getBattlerIndex(), this.hitCheck(p) ]));
const hasActiveTargets = targets.some(t => t.isActive(true)); const hasActiveTargets = targets.some(t => t.isActive(true));
/** Check if the target is immune via ability to the attacking move */ /** Check if the target is immune via ability to the attacking move */
@ -111,7 +111,7 @@ export class MoveEffectPhase extends PokemonPhase {
if (!hasActiveTargets || (!move.hasAttr(VariableTargetAttr) && !move.isMultiTarget() && !targetHitChecks[this.targets[0]] && !targets[0].getTag(ProtectedTag) && !isImmune)) { if (!hasActiveTargets || (!move.hasAttr(VariableTargetAttr) && !move.isMultiTarget() && !targetHitChecks[this.targets[0]] && !targets[0].getTag(ProtectedTag) && !isImmune)) {
this.stopMultiHit(); this.stopMultiHit();
if (hasActiveTargets) { if (hasActiveTargets) {
this.scene.queueMessage(i18next.t("battle:attackMissed", { pokemonNameWithAffix: this.getTarget()? getPokemonNameWithAffix(this.getTarget()!) : "" })); this.scene.queueMessage(i18next.t("battle:attackMissed", { pokemonNameWithAffix: this.getTarget() ? getPokemonNameWithAffix(this.getTarget()!) : "" }));
moveHistoryEntry.result = MoveResult.MISS; moveHistoryEntry.result = MoveResult.MISS;
applyMoveAttrs(MissEffectAttr, user, null, move); applyMoveAttrs(MissEffectAttr, user, null, move);
} else { } else {
@ -376,7 +376,7 @@ export class MoveEffectPhase extends PokemonPhase {
*/ */
hitCheck(target: Pokemon): boolean { hitCheck(target: Pokemon): boolean {
// Moves targeting the user and entry hazards can't miss // Moves targeting the user and entry hazards can't miss
if ([MoveTarget.USER, MoveTarget.ENEMY_SIDE].includes(this.move.getMove().moveTarget)) { if ([ MoveTarget.USER, MoveTarget.ENEMY_SIDE ].includes(this.move.getMove().moveTarget)) {
return true; return true;
} }
@ -407,7 +407,7 @@ export class MoveEffectPhase extends PokemonPhase {
const semiInvulnerableTag = target.getTag(SemiInvulnerableTag); const semiInvulnerableTag = target.getTag(SemiInvulnerableTag);
if (semiInvulnerableTag if (semiInvulnerableTag
&& !this.move.getMove().getAttrs(HitsTagAttr).some(hta => hta.tagType === semiInvulnerableTag.tagType) && !this.move.getMove().getAttrs(HitsTagAttr).some(hta => hta.tagType === semiInvulnerableTag.tagType)
&& !(this.move.getMove().getAttrs(ToxicAccuracyAttr) && user.isOfType(Type.POISON)) && !(this.move.getMove().hasAttr(ToxicAccuracyAttr) && user.isOfType(Type.POISON))
) { ) {
return false; return false;
} }

View File

@ -1,5 +1,5 @@
import BattleScene from "#app/battle-scene";
import { BattlerIndex } from "#app/battle"; import { BattlerIndex } from "#app/battle";
import BattleScene from "#app/battle-scene";
import { applyAbAttrs, applyPostMoveUsedAbAttrs, applyPreAttackAbAttrs, BlockRedirectAbAttr, IncreasePpAbAttr, PokemonTypeChangeAbAttr, PostMoveUsedAbAttr, RedirectMoveAbAttr } from "#app/data/ability"; import { applyAbAttrs, applyPostMoveUsedAbAttrs, applyPreAttackAbAttrs, BlockRedirectAbAttr, IncreasePpAbAttr, PokemonTypeChangeAbAttr, PostMoveUsedAbAttr, RedirectMoveAbAttr } from "#app/data/ability";
import { CommonAnim } from "#app/data/battle-anims"; import { CommonAnim } from "#app/data/battle-anims";
import { BattlerTagLapseType, CenterOfAttentionTag } from "#app/data/battler-tags"; import { BattlerTagLapseType, CenterOfAttentionTag } from "#app/data/battler-tags";
@ -15,236 +15,149 @@ import { StatusEffect } from "#app/enums/status-effect";
import { MoveUsedEvent } from "#app/events/battle-scene"; import { MoveUsedEvent } from "#app/events/battle-scene";
import Pokemon, { MoveResult, PokemonMove, TurnMove } from "#app/field/pokemon"; import Pokemon, { MoveResult, PokemonMove, TurnMove } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { BattlePhase } from "#app/phases/battle-phase";
import { CommonAnimPhase } from "#app/phases/common-anim-phase";
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { MoveEndPhase } from "#app/phases/move-end-phase";
import { ShowAbilityPhase } from "#app/phases/show-ability-phase";
import * as Utils from "#app/utils"; import * as Utils from "#app/utils";
import i18next from "i18next"; import i18next from "i18next";
import { BattlePhase } from "./battle-phase";
import { CommonAnimPhase } from "./common-anim-phase";
import { MoveEffectPhase } from "./move-effect-phase";
import { MoveEndPhase } from "./move-end-phase";
import { ShowAbilityPhase } from "./show-ability-phase";
export class MovePhase extends BattlePhase { export class MovePhase extends BattlePhase {
public pokemon: Pokemon; protected _pokemon: Pokemon;
public move: PokemonMove; protected _move: PokemonMove;
public targets: BattlerIndex[]; protected _targets: BattlerIndex[];
protected followUp: boolean; protected followUp: boolean;
protected ignorePp: boolean; protected ignorePp: boolean;
protected failed: boolean; protected failed: boolean = false;
protected cancelled: boolean; protected cancelled: boolean = false;
constructor(scene: BattleScene, pokemon: Pokemon, targets: BattlerIndex[], move: PokemonMove, followUp?: boolean, ignorePp?: boolean) { public get pokemon(): Pokemon {
return this._pokemon;
}
protected set pokemon(pokemon: Pokemon) {
this._pokemon = pokemon;
}
public get move(): PokemonMove {
return this._move;
}
protected set move(move: PokemonMove) {
this._move = move;
}
public get targets(): BattlerIndex[] {
return this._targets;
}
protected set targets(targets: BattlerIndex[]) {
this._targets = targets;
}
/**
* @param followUp Indicates that the move being uses is a "follow-up" - for example, a move being used by Metronome or Dancer.
* Follow-ups bypass a few failure conditions, including flinches, sleep/paralysis/freeze and volatile status checks, etc.
*/
constructor(scene: BattleScene, pokemon: Pokemon, targets: BattlerIndex[], move: PokemonMove, followUp: boolean = false, ignorePp: boolean = false) {
super(scene); super(scene);
this.pokemon = pokemon; this.pokemon = pokemon;
this.targets = targets; this.targets = targets;
this.move = move; this.move = move;
this.followUp = followUp ?? false; this.followUp = followUp;
this.ignorePp = ignorePp ?? false; this.ignorePp = ignorePp;
this.failed = false;
this.cancelled = false;
} }
canMove(ignoreDisableTags?: boolean): boolean { /**
* Checks if the pokemon is active, if the move is usable, and that the move is targetting something.
* @param ignoreDisableTags `true` to not check if the move is disabled
* @returns `true` if all the checks pass
*/
public canMove(ignoreDisableTags: boolean = false): boolean {
return this.pokemon.isActive(true) && this.move.isUsable(this.pokemon, this.ignorePp, ignoreDisableTags) && !!this.targets.length; return this.pokemon.isActive(true) && this.move.isUsable(this.pokemon, this.ignorePp, ignoreDisableTags) && !!this.targets.length;
} }
/**Signifies the current move should fail but still use PP */ /**Signifies the current move should fail but still use PP */
fail(): void { public fail(): void {
this.failed = true; this.failed = true;
} }
/**Signifies the current move should cancel and retain PP */ /**Signifies the current move should cancel and retain PP */
cancel(): void { public cancel(): void {
this.cancelled = true; this.cancelled = true;
} }
start() { public start() {
super.start(); super.start();
console.log(Moves[this.move.moveId]); console.log(Moves[this.move.moveId]);
// Check if move is unusable (e.g. because it's out of PP due to a mid-turn Spite).
if (!this.canMove(true)) { if (!this.canMove(true)) {
if (this.pokemon.isActive(true) && this.move.ppUsed >= this.move.getMovePp()) { // if the move PP was reduced from Spite or otherwise, the move fails if (this.pokemon.isActive(true) && this.move.ppUsed >= this.move.getMovePp()) {
this.fail(); this.fail();
this.showMoveText(); this.showMoveText();
this.showFailedText(); this.showFailedText();
} }
return this.end(); return this.end();
} }
this.pokemon.turnData.acted = true;
// Reset hit-related turn data when starting follow-up moves (e.g. Metronomed moves, Dancer repeats)
if (this.followUp) {
this.pokemon.turnData.hitsLeft = -1;
this.pokemon.turnData.hitCount = 0;
}
// Check move to see if arena.ignoreAbilities should be true.
if (!this.followUp) { if (!this.followUp) {
if (this.move.getMove().checkFlag(MoveFlags.IGNORE_ABILITIES, this.pokemon, null)) { if (this.move.getMove().checkFlag(MoveFlags.IGNORE_ABILITIES, this.pokemon, null)) {
this.scene.arena.setIgnoreAbilities(true, this.pokemon.getBattlerIndex()); this.scene.arena.setIgnoreAbilities(true, this.pokemon.getBattlerIndex());
} }
}
this.resolveRedirectTarget();
this.resolveCounterAttackTarget();
this.resolvePreMoveStatusEffects();
this.lapsePreMoveAndMoveTags();
this.resolveFinalPreMoveCancellationChecks();
if (this.cancelled || this.failed) {
this.handlePreMoveFailures();
} else { } else {
this.pokemon.turnData.hitsLeft = 0; // TODO: is `0` correct? this.useMove();
this.pokemon.turnData.hitCount = 0; // TODO: is `0` correct?
} }
// Move redirection abilities (ie. Storm Drain) only support single target moves this.end();
const moveTarget = this.targets.length === 1 }
? new Utils.IntegerHolder(this.targets[0])
: null; /** Check for cancellation edge cases - no targets remaining, or {@linkcode Moves.NONE} is in the queue */
if (moveTarget) { protected resolveFinalPreMoveCancellationChecks() {
const oldTarget = moveTarget.value; const targets = this.getActiveTargetPokemon();
this.scene.getField(true).filter(p => p !== this.pokemon).forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, false, this.move.moveId, moveTarget)); const moveQueue = this.pokemon.getMoveQueue();
this.pokemon.getOpponents().forEach(p => {
const redirectTag = p.getTag(CenterOfAttentionTag) as CenterOfAttentionTag; if (targets.length === 0 || (moveQueue.length && moveQueue[0].move === Moves.NONE)) {
if (redirectTag && (!redirectTag.powder || (!this.pokemon.isOfType(Type.GRASS) && !this.pokemon.hasAbility(Abilities.OVERCOAT)))) { this.showFailedText();
moveTarget.value = p.getBattlerIndex(); this.cancelled = true;
}
});
//Check if this move is immune to being redirected, and restore its target to the intended target if it is.
if ((this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr) || this.move.getMove().hasAttr(BypassRedirectAttr))) {
//If an ability prevented this move from being redirected, display its ability pop up.
if ((this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr) && !this.move.getMove().hasAttr(BypassRedirectAttr)) && oldTarget !== moveTarget.value) {
this.scene.unshiftPhase(new ShowAbilityPhase(this.scene, this.pokemon.getBattlerIndex(), this.pokemon.getPassiveAbility().hasAttr(BlockRedirectAbAttr)));
}
moveTarget.value = oldTarget;
}
this.targets[0] = moveTarget.value;
} }
}
// Check for counterattack moves to switch target public getActiveTargetPokemon() {
if (this.targets.length === 1 && this.targets[0] === BattlerIndex.ATTACKER) { return this.scene.getField(true).filter(p => this.targets.includes(p.getBattlerIndex()));
if (this.pokemon.turnData.attacksReceived.length) { }
const attack = this.pokemon.turnData.attacksReceived[0];
this.targets[0] = attack.sourceBattlerIndex;
// account for metal burst and comeuppance hitting remaining targets in double battles
// counterattack will redirect to remaining ally if original attacker faints
if (this.scene.currentBattle.double && this.move.getMove().hasFlag(MoveFlags.REDIRECT_COUNTER)) {
if (this.scene.getField()[this.targets[0]].hp === 0) {
const opposingField = this.pokemon.isPlayer() ? this.scene.getEnemyField() : this.scene.getPlayerField();
//@ts-ignore
this.targets[0] = opposingField.find(p => p.hp > 0)?.getBattlerIndex(); //TODO: fix ts-ignore
}
}
}
if (this.targets[0] === BattlerIndex.ATTACKER) {
this.fail(); // Marks the move as failed for later in doMove
this.showMoveText();
this.showFailedText();
}
}
const targets = this.scene.getField(true).filter(p => {
if (this.targets.indexOf(p.getBattlerIndex()) > -1) {
return true;
}
return false;
});
const doMove = () => {
this.pokemon.turnData.acted = true; // Record that the move was attempted, even if it fails
this.pokemon.lapseTags(BattlerTagLapseType.PRE_MOVE);
let ppUsed = 1;
// Filter all opponents to include only those this move is targeting
const targetedOpponents = this.pokemon.getOpponents().filter(o => this.targets.includes(o.getBattlerIndex()));
for (const opponent of targetedOpponents) {
if (this.move.ppUsed + ppUsed >= this.move.getMovePp()) { // If we're already at max PP usage, stop checking
break;
}
if (opponent.hasAbilityWithAttr(IncreasePpAbAttr)) { // Accounting for abilities like Pressure
ppUsed++;
}
}
if (!this.followUp && this.canMove() && !this.cancelled) {
this.pokemon.lapseTags(BattlerTagLapseType.MOVE);
}
const moveQueue = this.pokemon.getMoveQueue();
if (this.cancelled || this.failed) {
if (this.failed) {
this.move.usePp(ppUsed); // Only use PP if the move failed
this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), this.move.ppUsed));
}
// Record a failed move so Abilities like Truant don't trigger next turn and soft-lock
this.pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.FAIL });
this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT); // Remove any tags from moves like Fly/Dive/etc.
this.pokemon.lapseTags(BattlerTagLapseType.AFTER_MOVE);
moveQueue.shift(); // Remove the second turn of charge moves
return this.end();
}
this.scene.triggerPokemonFormChange(this.pokemon, SpeciesFormChangePreMoveTrigger);
if (this.move.moveId) {
this.showMoveText();
}
// This should only happen when there are no valid targets left on the field
if ((moveQueue.length && moveQueue[0].move === Moves.NONE) || !targets.length) {
this.showFailedText();
this.cancel();
// Record a failed move so Abilities like Truant don't trigger next turn and soft-lock
this.pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.FAIL });
this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT); // Remove any tags from moves like Fly/Dive/etc.
this.pokemon.lapseTags(BattlerTagLapseType.AFTER_MOVE);
moveQueue.shift();
return this.end();
}
if ((!moveQueue.length || !moveQueue.shift()?.ignorePP) && !this.ignorePp) { // using .shift here clears out two turn moves once they've been used
this.move.usePp(ppUsed);
this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), this.move.ppUsed));
}
if (!allMoves[this.move.moveId].hasAttr(CopyMoveAttr)) {
this.scene.currentBattle.lastMove = this.move.moveId;
}
// Assume conditions affecting targets only apply to moves with a single target
let success = this.move.getMove().applyConditions(this.pokemon, targets[0], this.move.getMove());
const cancelled = new Utils.BooleanHolder(false);
let failedText = this.move.getMove().getFailedText(this.pokemon, targets[0], this.move.getMove(), cancelled);
if (success && this.scene.arena.isMoveWeatherCancelled(this.pokemon, this.move.getMove())) {
success = false;
} else if (success && this.scene.arena.isMoveTerrainCancelled(this.pokemon, this.targets, this.move.getMove())) {
success = false;
if (failedText === null) {
failedText = getTerrainBlockMessage(targets[0], this.scene.arena.terrain?.terrainType!); // TODO: is this bang correct?
}
}
/**
* Trigger pokemon type change before playing the move animation
* Will still change the user's type when using Roar, Whirlwind, Trick-or-Treat, and Forest's Curse,
* regardless of whether the move successfully executes or not.
*/
if (success || [Moves.ROAR, Moves.WHIRLWIND, Moves.TRICK_OR_TREAT, Moves.FORESTS_CURSE].includes(this.move.moveId)) {
applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove());
}
if (success) {
this.scene.unshiftPhase(this.getEffectPhase());
} else {
this.pokemon.pushMoveHistory({ move: this.move.moveId, targets: this.targets, result: MoveResult.FAIL, virtual: this.move.virtual });
if (!cancelled.value) {
this.showFailedText(failedText);
}
}
// Checks if Dancer ability is triggered
if (this.move.getMove().hasFlag(MoveFlags.DANCE_MOVE) && !this.followUp) {
// Pokemon with Dancer can be on either side of the battle so we check in both cases
this.scene.getPlayerField().forEach(pokemon => {
applyPostMoveUsedAbAttrs(PostMoveUsedAbAttr, pokemon, this.move, this.pokemon, this.targets);
});
this.scene.getEnemyField().forEach(pokemon => {
applyPostMoveUsedAbAttrs(PostMoveUsedAbAttr, pokemon, this.move, this.pokemon, this.targets);
});
}
this.end();
};
/**
* Handles {@link StatusEffect.SLEEP Sleep}/{@link StatusEffect.PARALYSIS Paralysis}/{@link StatusEffect.FREEZE Freeze} rolls and side effects.
*/
protected resolvePreMoveStatusEffects() {
if (!this.followUp && this.pokemon.status && !this.pokemon.status.isPostTurn()) { if (!this.followUp && this.pokemon.status && !this.pokemon.status.isPostTurn()) {
this.pokemon.status.incrementTurn(); this.pokemon.status.incrementTurn();
let activated = false; let activated = false;
@ -273,25 +186,265 @@ export class MovePhase extends BattlePhase {
if (activated) { if (activated) {
this.scene.queueMessage(getStatusEffectActivationText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon))); this.scene.queueMessage(getStatusEffectActivationText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)));
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, this.pokemon.getBattlerIndex(), undefined, CommonAnim.POISON + (this.pokemon.status.effect - 1))); this.scene.unshiftPhase(new CommonAnimPhase(this.scene, this.pokemon.getBattlerIndex(), undefined, CommonAnim.POISON + (this.pokemon.status.effect - 1)));
doMove(); } else if (healed) {
} else { this.scene.queueMessage(getStatusEffectHealText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)));
if (healed) { this.pokemon.resetStatus();
this.scene.queueMessage(getStatusEffectHealText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon))); this.pokemon.updateInfo();
this.pokemon.resetStatus();
this.pokemon.updateInfo();
}
doMove();
} }
} else {
doMove();
} }
} }
getEffectPhase(): MoveEffectPhase { /**
return new MoveEffectPhase(this.scene, this.pokemon.getBattlerIndex(), this.targets, this.move); * Lapse {@linkcode BattlerTagLapseType.PRE_MOVE PRE_MOVE} tags that trigger before a move is used, regardless of whether or not it failed.
* Also lapse {@linkcode BattlerTagLapseType.MOVE MOVE} tags if the move should be successful.
*/
protected lapsePreMoveAndMoveTags() {
this.pokemon.lapseTags(BattlerTagLapseType.PRE_MOVE);
// TODO: does this intentionally happen before the no targets/Moves.NONE on queue cancellation case is checked?
if (!this.followUp && this.canMove() && !this.cancelled) {
this.pokemon.lapseTags(BattlerTagLapseType.MOVE);
}
} }
showMoveText(): void { protected useMove() {
const targets = this.getActiveTargetPokemon();
const moveQueue = this.pokemon.getMoveQueue();
// form changes happen even before we know that the move wll execute.
this.scene.triggerPokemonFormChange(this.pokemon, SpeciesFormChangePreMoveTrigger);
this.showMoveText();
// TODO: Clean up implementation of two-turn moves.
if (moveQueue.length > 0) { // Using .shift here clears out two turn moves once they've been used
this.ignorePp = moveQueue.shift()?.ignorePP ?? false;
}
// "commit" to using the move, deducting PP.
if (!this.ignorePp) {
const ppUsed = 1 + this.getPpIncreaseFromPressure(targets);
this.move.usePp(ppUsed);
this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), ppUsed));
}
// Update the battle's "last move" pointer, unless we're currently mimicking a move.
if (!allMoves[this.move.moveId].hasAttr(CopyMoveAttr)) {
this.scene.currentBattle.lastMove = this.move.moveId;
}
/**
* Determine if the move is successful (meaning that its damage/effects can be attempted)
* by checking that all of the following are true:
* - Conditional attributes of the move are all met
* - The target's `ForceSwitchOutImmunityAbAttr` is not triggered (see {@linkcode Move.prototype.applyConditions})
* - Weather does not block the move
* - Terrain does not block the move
*
* TODO: These steps are straightforward, but the implementation below is extremely convoluted.
*/
const move = this.move.getMove();
/**
* Move conditions assume the move has a single target
* TODO: is this sustainable?
*/
const passesConditions = move.applyConditions(this.pokemon, targets[0], move);
const failedDueToWeather: boolean = this.scene.arena.isMoveWeatherCancelled(this.pokemon, move);
const failedDueToTerrain: boolean = this.scene.arena.isMoveTerrainCancelled(this.pokemon, this.targets, move);
const success = passesConditions && !failedDueToWeather && !failedDueToTerrain;
/**
* If the move has not failed, trigger ability-based user type changes and then execute it.
*
* Notably, Roar, Whirlwind, Trick-or-Treat, and Forest's Curse will trigger these type changes even
* if the move fails.
*/
if (success) {
applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove());
this.scene.unshiftPhase(new MoveEffectPhase(this.scene, this.pokemon.getBattlerIndex(), this.targets, this.move));
} else {
if ([ Moves.ROAR, Moves.WHIRLWIND, Moves.TRICK_OR_TREAT, Moves.FORESTS_CURSE ].includes(this.move.moveId)) {
applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove());
}
this.pokemon.pushMoveHistory({ move: this.move.moveId, targets: this.targets, result: MoveResult.FAIL, virtual: this.move.virtual });
let failedText: string | undefined;
const failureMessage = move.getFailedText(this.pokemon, targets[0], move, new Utils.BooleanHolder(false));
if (failureMessage) {
failedText = failureMessage;
} else if (failedDueToTerrain) {
failedText = getTerrainBlockMessage(this.pokemon, this.scene.arena.getTerrainType());
}
this.showFailedText(failedText);
}
// Handle Dancer, which triggers immediately after a move is used (rather than waiting on `this.end()`).
// Note that the `!this.followUp` check here prevents an infinite Dancer loop.
if (this.move.getMove().hasFlag(MoveFlags.DANCE_MOVE) && !this.followUp) {
this.scene.getField(true).forEach(pokemon => {
applyPostMoveUsedAbAttrs(PostMoveUsedAbAttr, pokemon, this.move, this.pokemon, this.targets);
});
}
}
/**
* Queues a {@linkcode MoveEndPhase} if the move wasn't a {@linkcode followUp} and {@linkcode canMove()} returns `true`,
* then ends the phase.
*/
public end() {
if (!this.followUp && this.canMove()) {
this.scene.unshiftPhase(new MoveEndPhase(this.scene, this.pokemon.getBattlerIndex()));
}
super.end();
}
/**
* Applies PP increasing abilities (currently only {@link Abilities.PRESSURE Pressure}) if they exist on the target pokemon.
* Note that targets must include only active pokemon.
*
* TODO: This hardcodes the PP increase at 1 per opponent, rather than deferring to the ability.
*/
public getPpIncreaseFromPressure(targets: Pokemon[]) {
const foesWithPressure = this.pokemon.getOpponents().filter(o => targets.includes(o) && o.isActive(true) && o.hasAbilityWithAttr(IncreasePpAbAttr));
return foesWithPressure.length;
}
/**
* Modifies `this.targets` in place, based upon:
* - Move redirection abilities, effects, etc.
* - Counterattacks, which pass a special value into the `targets` constructor param (`[`{@linkcode BattlerIndex.ATTACKER}`]`).
*/
protected resolveRedirectTarget() {
if (this.targets.length === 1) {
const currentTarget = this.targets[0];
const redirectTarget = new Utils.NumberHolder(currentTarget);
// check move redirection abilities of every pokemon *except* the user.
this.scene.getField(true).filter(p => p !== this.pokemon).forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, false, this.move.moveId, redirectTarget));
/** `true` if an Ability is responsible for redirecting the move to another target; `false` otherwise */
let redirectedByAbility = (currentTarget !== redirectTarget.value);
// check for center-of-attention tags (note that this will override redirect abilities)
this.pokemon.getOpponents().forEach(p => {
const redirectTag = p.getTag(CenterOfAttentionTag);
// TODO: don't hardcode this interaction.
// Handle interaction between the rage powder center-of-attention tag and moves used by grass types/overcoat-havers (which are immune to RP's redirect)
if (redirectTag && (!redirectTag.powder || (!this.pokemon.isOfType(Type.GRASS) && !this.pokemon.hasAbility(Abilities.OVERCOAT)))) {
redirectTarget.value = p.getBattlerIndex();
redirectedByAbility = false;
}
});
if (currentTarget !== redirectTarget.value) {
const bypassRedirectAttrs = this.move.getMove().getAttrs(BypassRedirectAttr);
bypassRedirectAttrs.forEach((attr) => {
if (!attr.abilitiesOnly || redirectedByAbility) {
redirectTarget.value = currentTarget;
}
});
if (this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr)) {
redirectTarget.value = currentTarget;
this.scene.unshiftPhase(new ShowAbilityPhase(this.scene, this.pokemon.getBattlerIndex(), this.pokemon.getPassiveAbility().hasAttr(BlockRedirectAbAttr)));
}
this.targets[0] = redirectTarget.value;
}
}
}
/**
* Counter-attacking moves pass in `[`{@linkcode BattlerIndex.ATTACKER}`]` into the constructor's `targets` param.
* This function modifies `this.targets` to reflect the actual battler index of the user's last
* attacker.
*
* If there is no last attacker, or they are no longer on the field, a message is displayed and the
* move is marked for failure.
*/
protected resolveCounterAttackTarget() {
if (this.targets.length === 1 && this.targets[0] === BattlerIndex.ATTACKER) {
if (this.pokemon.turnData.attacksReceived.length) {
const attacker = this.pokemon.scene.getPokemonById(this.pokemon.turnData.attacksReceived[0].sourceId);
if (attacker?.isActive(true)) {
this.targets[0] = attacker.getBattlerIndex();
}
// account for metal burst and comeuppance hitting remaining targets in double battles
// counterattack will redirect to remaining ally if original attacker faints
if (this.scene.currentBattle.double && this.move.getMove().hasFlag(MoveFlags.REDIRECT_COUNTER)) {
if (this.scene.getField()[this.targets[0]].hp === 0) {
const opposingField = this.pokemon.isPlayer() ? this.scene.getEnemyField() : this.scene.getPlayerField();
this.targets[0] = opposingField.find(p => p.hp > 0)?.getBattlerIndex() ?? BattlerIndex.ATTACKER;
}
}
}
if (this.targets[0] === BattlerIndex.ATTACKER) {
this.fail();
this.showMoveText();
this.showFailedText();
}
}
}
/**
* Handles the case where the move was cancelled or failed:
* - Uses PP if the move failed (not cancelled) and should use PP (failed moves are not affected by {@link Abilities.PRESSURE Pressure})
* - Records a cancelled OR failed move in move history, so abilities like {@link Abilities.TRUANT Truant} don't trigger on the
* next turn and soft-lock.
* - Lapses `MOVE_EFFECT` tags:
* - Semi-invulnerable battler tags (Fly/Dive/etc.) are intended to lapse on move effects, but also need
* to lapse on move failure/cancellation.
*
* TODO: ...this seems weird.
* - Lapses `AFTER_MOVE` tags:
* - This handles the effects of {@link Moves.SUBSTITUTE Substitute}
* - Removes the second turn of charge moves
*
* TODO: handle charge moves more gracefully
*/
protected handlePreMoveFailures() {
if (this.cancelled || this.failed) {
if (this.failed) {
const ppUsed = this.ignorePp ? 0 : 1;
if (ppUsed) {
this.move.usePp();
}
this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), ppUsed));
}
this.pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.FAIL });
this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT);
this.pokemon.lapseTags(BattlerTagLapseType.AFTER_MOVE);
this.pokemon.getMoveQueue().shift();
}
}
/**
* Displays the move's usage text to the player, unless it's a charge turn (ie: {@link Moves.SOLAR_BEAM Solar Beam}),
* the pokemon is on a recharge turn (ie: {@link Moves.HYPER_BEAM Hyper Beam}), or a 2-turn move was interrupted (ie: {@link Moves.FLY Fly}).
*/
protected showMoveText(): void {
if (this.move.moveId === Moves.NONE) {
return;
}
if (this.move.getMove().hasAttr(ChargeAttr)) { if (this.move.getMove().hasAttr(ChargeAttr)) {
const lastMove = this.pokemon.getLastXMoves() as TurnMove[]; const lastMove = this.pokemon.getLastXMoves() as TurnMove[];
if (!lastMove.length || lastMove[0].move !== this.move.getMove().id || lastMove[0].result !== MoveResult.OTHER) { if (!lastMove.length || lastMove[0].move !== this.move.getMove().id || lastMove[0].result !== MoveResult.OTHER) {
@ -311,18 +464,10 @@ export class MovePhase extends BattlePhase {
pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon),
moveName: this.move.getName() moveName: this.move.getName()
}), 500); }), 500);
applyMoveAttrs(PreMoveMessageAttr, this.pokemon, this.pokemon.getOpponents().find(() => true)!, this.move.getMove()); //TODO: is the bang correct here? applyMoveAttrs(PreMoveMessageAttr, this.pokemon, this.pokemon.getOpponents()[0], this.move.getMove());
} }
showFailedText(failedText: string | null = null): void { protected showFailedText(failedText?: string): void {
this.scene.queueMessage(failedText || i18next.t("battle:attackFailed")); this.scene.queueMessage(failedText ?? i18next.t("battle:attackFailed"));
}
end() {
if (!this.followUp && this.canMove()) {
this.scene.unshiftPhase(new MoveEndPhase(this.scene, this.pokemon.getBattlerIndex()));
}
super.end();
} }
} }

View File

@ -220,7 +220,7 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
super.start(); super.start();
// Lapse any residual flinches/endures but ignore all other turn-end battle tags // Lapse any residual flinches/endures but ignore all other turn-end battle tags
const includedLapseTags = [BattlerTagType.FLINCHED, BattlerTagType.ENDURING]; const includedLapseTags = [ BattlerTagType.FLINCHED, BattlerTagType.ENDURING ];
const field = this.scene.getField(true).filter(p => p.summonData); const field = this.scene.getField(true).filter(p => p.summonData);
field.forEach(pokemon => { field.forEach(pokemon => {
const tags = pokemon.summonData.tags; const tags = pokemon.summonData.tags;

View File

@ -22,7 +22,7 @@ export class NewBiomeEncounterPhase extends NextEncounterPhase {
} }
const enemyField = this.scene.getEnemyField(); const enemyField = this.scene.getEnemyField();
const moveTargets: any[] = [this.scene.arenaEnemy, enemyField]; const moveTargets: any[] = [ this.scene.arenaEnemy, enemyField ];
const mysteryEncounter = this.scene.currentBattle?.mysteryEncounter?.introVisuals; const mysteryEncounter = this.scene.currentBattle?.mysteryEncounter?.introVisuals;
if (mysteryEncounter) { if (mysteryEncounter) {
moveTargets.push(mysteryEncounter); moveTargets.push(mysteryEncounter);

View File

@ -23,7 +23,7 @@ export class NextEncounterPhase extends EncounterPhase {
this.scene.arenaNextEnemy.setVisible(true); this.scene.arenaNextEnemy.setVisible(true);
const enemyField = this.scene.getEnemyField(); const enemyField = this.scene.getEnemyField();
const moveTargets: any[] = [this.scene.arenaEnemy, this.scene.arenaNextEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.lastEnemyTrainer]; const moveTargets: any[] = [ this.scene.arenaEnemy, this.scene.arenaNextEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.lastEnemyTrainer ];
const lastEncounterVisuals = this.scene.lastMysteryEncounter?.introVisuals; const lastEncounterVisuals = this.scene.lastMysteryEncounter?.introVisuals;
if (lastEncounterVisuals) { if (lastEncounterVisuals) {
moveTargets.push(lastEncounterVisuals); moveTargets.push(lastEncounterVisuals);

View File

@ -5,7 +5,6 @@ import Pokemon from "#app/field/pokemon";
import { BattlePhase } from "#app/phases/battle-phase"; import { BattlePhase } from "#app/phases/battle-phase";
export class PokemonAnimPhase extends BattlePhase { export class PokemonAnimPhase extends BattlePhase {
/** The type of animation to play in this phase */ /** The type of animation to play in this phase */
private key: PokemonAnimType; private key: PokemonAnimType;
@ -53,7 +52,7 @@ export class PokemonAnimPhase extends BattlePhase {
const sprite = this.scene.addFieldSprite( const sprite = this.scene.addFieldSprite(
this.pokemon.x + this.pokemon.getSprite().x, this.pokemon.x + this.pokemon.getSprite().x,
this.pokemon.y + this.pokemon.getSprite().y, this.pokemon.y + this.pokemon.getSprite().y,
`pkmn${this.pokemon.isPlayer() ? "__back": ""}__sub` `pkmn${this.pokemon.isPlayer() ? "__back" : ""}__sub`
); );
sprite.setOrigin(0.5, 1); sprite.setOrigin(0.5, 1);
this.scene.field.add(sprite); this.scene.field.add(sprite);
@ -179,7 +178,7 @@ export class PokemonAnimPhase extends BattlePhase {
const sprite = this.scene.addFieldSprite( const sprite = this.scene.addFieldSprite(
subSprite.x, subSprite.x,
subSprite.y, subSprite.y,
`pkmn${this.pokemon.isPlayer() ? "__back": ""}__sub` `pkmn${this.pokemon.isPlayer() ? "__back" : ""}__sub`
); );
sprite.setOrigin(0.5, 1); sprite.setOrigin(0.5, 1);
this.scene.field.add(sprite); this.scene.field.add(sprite);

View File

@ -45,7 +45,7 @@ export class SelectBiomePhase extends BattlePhase {
let biomeChoices: Biome[] = []; let biomeChoices: Biome[] = [];
this.scene.executeWithSeedOffset(() => { this.scene.executeWithSeedOffset(() => {
biomeChoices = (!Array.isArray(biomeLinks[currentBiome]) biomeChoices = (!Array.isArray(biomeLinks[currentBiome])
? [biomeLinks[currentBiome] as Biome] ? [ biomeLinks[currentBiome] as Biome ]
: biomeLinks[currentBiome] as (Biome | [Biome, integer])[]) : biomeLinks[currentBiome] as (Biome | [Biome, integer])[])
.filter((b, i) => !Array.isArray(b) || !Utils.randSeedInt(b[1])) .filter((b, i) => !Array.isArray(b) || !Utils.randSeedInt(b[1]))
.map(b => Array.isArray(b) ? b[0] : b); .map(b => Array.isArray(b) ? b[0] : b);

Some files were not shown because too many files have changed in this diff Show More