mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-04-22 01:24:13 +01:00
Merge branch 'beta' into refactor/api-requests
This commit is contained in:
commit
e620c68b56
@ -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
|
||||||
|
|
||||||
|
@ -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
1
package-lock.json
generated
@ -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",
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
@ -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
|
||||||
|
@ -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,
|
||||||
@ -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"));
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -1107,12 +1107,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.QUILLADIN,
|
Species.QUILLADIN,
|
||||||
Species.CHESNAUGHT,
|
Species.CHESNAUGHT,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.BUNNELBY,
|
Species.BUNNELBY,
|
||||||
Species.DIGGERSBY,
|
Species.DIGGERSBY,
|
||||||
Species.FLETCHLING,
|
Species.FLETCHLING,
|
||||||
@ -2878,12 +2873,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.DELPHOX,
|
Species.DELPHOX,
|
||||||
Species.FROAKIE,
|
Species.FROAKIE,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.BUNNELBY,
|
Species.BUNNELBY,
|
||||||
Species.DIGGERSBY,
|
Species.DIGGERSBY,
|
||||||
Species.FLETCHLING,
|
Species.FLETCHLING,
|
||||||
@ -3910,7 +3900,6 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.YAMPER,
|
Species.YAMPER,
|
||||||
Species.BOLTUND,
|
Species.BOLTUND,
|
||||||
Species.ZAMAZENTA,
|
Species.ZAMAZENTA,
|
||||||
Species.URSHIFU,
|
|
||||||
Species.ZARUDE,
|
Species.ZARUDE,
|
||||||
Species.GLASTRIER,
|
Species.GLASTRIER,
|
||||||
Species.WYRDEER,
|
Species.WYRDEER,
|
||||||
@ -3940,6 +3929,10 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.ALOLA_NINETALES,
|
Species.ALOLA_NINETALES,
|
||||||
Species.ALOLA_PERSIAN,
|
Species.ALOLA_PERSIAN,
|
||||||
Species.ALOLA_GOLEM,
|
Species.ALOLA_GOLEM,
|
||||||
|
[
|
||||||
|
Species.URSHIFU,
|
||||||
|
"single-strike",
|
||||||
|
],
|
||||||
Species.HISUI_GROWLITHE,
|
Species.HISUI_GROWLITHE,
|
||||||
Species.HISUI_ARCANINE,
|
Species.HISUI_ARCANINE,
|
||||||
Species.HISUI_TYPHLOSION,
|
Species.HISUI_TYPHLOSION,
|
||||||
@ -6987,14 +6980,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -8301,7 +8287,6 @@ export const tmSpecies: TmSpecies = {
|
|||||||
[
|
[
|
||||||
Species.WORMADAM,
|
Species.WORMADAM,
|
||||||
"sandy",
|
"sandy",
|
||||||
"trash",
|
|
||||||
],
|
],
|
||||||
Species.ALOLA_SANDSHREW,
|
Species.ALOLA_SANDSHREW,
|
||||||
Species.ALOLA_SANDSLASH,
|
Species.ALOLA_SANDSLASH,
|
||||||
@ -8612,12 +8597,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.CHESNAUGHT,
|
Species.CHESNAUGHT,
|
||||||
Species.FROAKIE,
|
Species.FROAKIE,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.BUNNELBY,
|
Species.BUNNELBY,
|
||||||
Species.DIGGERSBY,
|
Species.DIGGERSBY,
|
||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
@ -9406,14 +9386,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -9766,14 +9739,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.DELPHOX,
|
Species.DELPHOX,
|
||||||
Species.VIVILLON,
|
Species.VIVILLON,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.ESPURR,
|
Species.ESPURR,
|
||||||
Species.MEOWSTIC,
|
Species.MEOWSTIC,
|
||||||
@ -11147,14 +11113,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -13657,12 +13616,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.DELPHOX,
|
Species.DELPHOX,
|
||||||
Species.FROAKIE,
|
Species.FROAKIE,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.FLETCHLING,
|
Species.FLETCHLING,
|
||||||
Species.FLETCHINDER,
|
Species.FLETCHINDER,
|
||||||
Species.TALONFLAME,
|
Species.TALONFLAME,
|
||||||
@ -15326,14 +15280,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -16934,14 +16881,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -18483,14 +18423,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -20250,14 +20183,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -21583,12 +21509,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.DELPHOX,
|
Species.DELPHOX,
|
||||||
Species.FROAKIE,
|
Species.FROAKIE,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.BUNNELBY,
|
Species.BUNNELBY,
|
||||||
Species.DIGGERSBY,
|
Species.DIGGERSBY,
|
||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
@ -22516,7 +22437,6 @@ export const tmSpecies: TmSpecies = {
|
|||||||
[
|
[
|
||||||
Species.WORMADAM,
|
Species.WORMADAM,
|
||||||
"sandy",
|
"sandy",
|
||||||
"trash",
|
|
||||||
],
|
],
|
||||||
Species.ALOLA_DIGLETT,
|
Species.ALOLA_DIGLETT,
|
||||||
Species.ALOLA_DUGTRIO,
|
Species.ALOLA_DUGTRIO,
|
||||||
@ -22691,14 +22611,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.CHESNAUGHT,
|
Species.CHESNAUGHT,
|
||||||
Species.VIVILLON,
|
Species.VIVILLON,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -23402,12 +23315,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.DELPHOX,
|
Species.DELPHOX,
|
||||||
Species.FROAKIE,
|
Species.FROAKIE,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.BUNNELBY,
|
Species.BUNNELBY,
|
||||||
Species.DIGGERSBY,
|
Species.DIGGERSBY,
|
||||||
Species.FLETCHLING,
|
Species.FLETCHLING,
|
||||||
@ -24134,12 +24042,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.KELDEO,
|
Species.KELDEO,
|
||||||
Species.FROAKIE,
|
Species.FROAKIE,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.PANCHAM,
|
Species.PANCHAM,
|
||||||
Species.PANGORO,
|
Species.PANGORO,
|
||||||
Species.HONEDGE,
|
Species.HONEDGE,
|
||||||
@ -24842,14 +24745,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -25712,14 +25608,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -26695,14 +26584,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -27845,14 +27727,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -28911,14 +28786,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -29514,14 +29382,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.DELPHOX,
|
Species.DELPHOX,
|
||||||
Species.VIVILLON,
|
Species.VIVILLON,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.ESPURR,
|
Species.ESPURR,
|
||||||
Species.MEOWSTIC,
|
Species.MEOWSTIC,
|
||||||
@ -31408,14 +31269,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -32327,14 +32181,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -33037,14 +32884,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -33471,7 +33311,6 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.ARCTOVISH,
|
Species.ARCTOVISH,
|
||||||
Species.ZACIAN,
|
Species.ZACIAN,
|
||||||
Species.ZAMAZENTA,
|
Species.ZAMAZENTA,
|
||||||
Species.URSHIFU,
|
|
||||||
Species.ZARUDE,
|
Species.ZARUDE,
|
||||||
Species.REGIDRAGO,
|
Species.REGIDRAGO,
|
||||||
Species.GLASTRIER,
|
Species.GLASTRIER,
|
||||||
@ -33522,6 +33361,10 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.ALOLA_MUK,
|
Species.ALOLA_MUK,
|
||||||
Species.GALAR_MEOWTH,
|
Species.GALAR_MEOWTH,
|
||||||
Species.GALAR_STUNFISK,
|
Species.GALAR_STUNFISK,
|
||||||
|
[
|
||||||
|
Species.URSHIFU,
|
||||||
|
"single-strike",
|
||||||
|
],
|
||||||
[
|
[
|
||||||
Species.CALYREX,
|
Species.CALYREX,
|
||||||
"ice",
|
"ice",
|
||||||
@ -36644,14 +36487,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -37389,14 +37225,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.BUNNELBY,
|
Species.BUNNELBY,
|
||||||
Species.DIGGERSBY,
|
Species.DIGGERSBY,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -38266,23 +38095,11 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.DELPHOX,
|
Species.DELPHOX,
|
||||||
Species.FROAKIE,
|
Species.FROAKIE,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -39323,12 +39140,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.CHESPIN,
|
Species.CHESPIN,
|
||||||
Species.QUILLADIN,
|
Species.QUILLADIN,
|
||||||
Species.CHESNAUGHT,
|
Species.CHESNAUGHT,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.BUNNELBY,
|
Species.BUNNELBY,
|
||||||
Species.DIGGERSBY,
|
Species.DIGGERSBY,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
@ -40356,7 +40168,10 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.FENNEKIN,
|
Species.FENNEKIN,
|
||||||
Species.BRAIXEN,
|
Species.BRAIXEN,
|
||||||
Species.DELPHOX,
|
Species.DELPHOX,
|
||||||
|
[
|
||||||
Species.MEOWSTIC,
|
Species.MEOWSTIC,
|
||||||
|
"male",
|
||||||
|
],
|
||||||
Species.KLEFKI,
|
Species.KLEFKI,
|
||||||
Species.PHANTUMP,
|
Species.PHANTUMP,
|
||||||
Species.TREVENANT,
|
Species.TREVENANT,
|
||||||
@ -41805,7 +41620,6 @@ export const tmSpecies: TmSpecies = {
|
|||||||
[
|
[
|
||||||
Species.WORMADAM,
|
Species.WORMADAM,
|
||||||
"sandy",
|
"sandy",
|
||||||
"trash",
|
|
||||||
],
|
],
|
||||||
Species.ALOLA_SANDSHREW,
|
Species.ALOLA_SANDSHREW,
|
||||||
Species.ALOLA_SANDSLASH,
|
Species.ALOLA_SANDSLASH,
|
||||||
@ -43701,12 +43515,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.DELPHOX,
|
Species.DELPHOX,
|
||||||
Species.FROAKIE,
|
Species.FROAKIE,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.BUNNELBY,
|
Species.BUNNELBY,
|
||||||
Species.DIGGERSBY,
|
Species.DIGGERSBY,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
@ -44160,14 +43969,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.QUILLADIN,
|
Species.QUILLADIN,
|
||||||
Species.CHESNAUGHT,
|
Species.CHESNAUGHT,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -44377,14 +44179,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.DELPHOX,
|
Species.DELPHOX,
|
||||||
Species.VIVILLON,
|
Species.VIVILLON,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.ESPURR,
|
Species.ESPURR,
|
||||||
Species.MEOWSTIC,
|
Species.MEOWSTIC,
|
||||||
@ -45256,6 +45051,10 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.IRON_CROWN,
|
Species.IRON_CROWN,
|
||||||
Species.TERAPAGOS,
|
Species.TERAPAGOS,
|
||||||
Species.ALOLA_EXEGGUTOR,
|
Species.ALOLA_EXEGGUTOR,
|
||||||
|
[
|
||||||
|
Species.INDEEDEE,
|
||||||
|
"male",
|
||||||
|
],
|
||||||
],
|
],
|
||||||
[Moves.GYRO_BALL]: [
|
[Moves.GYRO_BALL]: [
|
||||||
Species.SQUIRTLE,
|
Species.SQUIRTLE,
|
||||||
@ -47501,12 +47300,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.ACCELGOR,
|
Species.ACCELGOR,
|
||||||
Species.FROAKIE,
|
Species.FROAKIE,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.SKRELP,
|
Species.SKRELP,
|
||||||
Species.DRAGALGE,
|
Species.DRAGALGE,
|
||||||
Species.MAREANIE,
|
Species.MAREANIE,
|
||||||
@ -48143,7 +47937,6 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.RUNERIGUS,
|
Species.RUNERIGUS,
|
||||||
Species.MORPEKO,
|
Species.MORPEKO,
|
||||||
Species.DURALUDON,
|
Species.DURALUDON,
|
||||||
Species.URSHIFU,
|
|
||||||
Species.ZARUDE,
|
Species.ZARUDE,
|
||||||
Species.SPECTRIER,
|
Species.SPECTRIER,
|
||||||
Species.OVERQWIL,
|
Species.OVERQWIL,
|
||||||
@ -48179,6 +47972,10 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.GALAR_WEEZING,
|
Species.GALAR_WEEZING,
|
||||||
Species.GALAR_MOLTRES,
|
Species.GALAR_MOLTRES,
|
||||||
Species.GALAR_YAMASK,
|
Species.GALAR_YAMASK,
|
||||||
|
[
|
||||||
|
Species.URSHIFU,
|
||||||
|
"single-strike",
|
||||||
|
],
|
||||||
[
|
[
|
||||||
Species.CALYREX,
|
Species.CALYREX,
|
||||||
"shadow",
|
"shadow",
|
||||||
@ -48456,14 +48253,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.QUILLADIN,
|
Species.QUILLADIN,
|
||||||
Species.CHESNAUGHT,
|
Species.CHESNAUGHT,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -49622,7 +49412,10 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.TORTERRA,
|
Species.TORTERRA,
|
||||||
Species.BUDEW,
|
Species.BUDEW,
|
||||||
Species.ROSERADE,
|
Species.ROSERADE,
|
||||||
|
[
|
||||||
Species.WORMADAM,
|
Species.WORMADAM,
|
||||||
|
"plant",
|
||||||
|
],
|
||||||
Species.MOTHIM,
|
Species.MOTHIM,
|
||||||
Species.CHERUBI,
|
Species.CHERUBI,
|
||||||
Species.CHERRIM,
|
Species.CHERRIM,
|
||||||
@ -49698,14 +49491,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.CHESNAUGHT,
|
Species.CHESNAUGHT,
|
||||||
Species.VIVILLON,
|
Species.VIVILLON,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -52635,7 +52421,10 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.TORTERRA,
|
Species.TORTERRA,
|
||||||
Species.BUDEW,
|
Species.BUDEW,
|
||||||
Species.ROSERADE,
|
Species.ROSERADE,
|
||||||
|
[
|
||||||
Species.WORMADAM,
|
Species.WORMADAM,
|
||||||
|
"plant",
|
||||||
|
],
|
||||||
Species.SNOVER,
|
Species.SNOVER,
|
||||||
Species.ABOMASNOW,
|
Species.ABOMASNOW,
|
||||||
Species.TANGROWTH,
|
Species.TANGROWTH,
|
||||||
@ -53751,7 +53540,10 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.BIBAREL,
|
Species.BIBAREL,
|
||||||
Species.BUDEW,
|
Species.BUDEW,
|
||||||
Species.ROSERADE,
|
Species.ROSERADE,
|
||||||
|
[
|
||||||
Species.WORMADAM,
|
Species.WORMADAM,
|
||||||
|
"plant",
|
||||||
|
],
|
||||||
Species.PACHIRISU,
|
Species.PACHIRISU,
|
||||||
Species.CHERUBI,
|
Species.CHERUBI,
|
||||||
Species.CHERRIM,
|
Species.CHERRIM,
|
||||||
@ -53863,14 +53655,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.BUNNELBY,
|
Species.BUNNELBY,
|
||||||
Species.DIGGERSBY,
|
Species.DIGGERSBY,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -55590,12 +55375,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.CHESPIN,
|
Species.CHESPIN,
|
||||||
Species.QUILLADIN,
|
Species.QUILLADIN,
|
||||||
Species.CHESNAUGHT,
|
Species.CHESNAUGHT,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.PANCHAM,
|
Species.PANCHAM,
|
||||||
Species.PANGORO,
|
Species.PANGORO,
|
||||||
Species.HELIOPTILE,
|
Species.HELIOPTILE,
|
||||||
@ -55877,7 +55657,6 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.MR_RIME,
|
Species.MR_RIME,
|
||||||
Species.MORPEKO,
|
Species.MORPEKO,
|
||||||
Species.DURALUDON,
|
Species.DURALUDON,
|
||||||
Species.URSHIFU,
|
|
||||||
Species.SPECTRIER,
|
Species.SPECTRIER,
|
||||||
Species.MEOWSCARADA,
|
Species.MEOWSCARADA,
|
||||||
Species.SQUAWKABILLY,
|
Species.SQUAWKABILLY,
|
||||||
@ -55918,6 +55697,10 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.GALAR_MOLTRES,
|
Species.GALAR_MOLTRES,
|
||||||
Species.GALAR_SLOWKING,
|
Species.GALAR_SLOWKING,
|
||||||
Species.GALAR_STUNFISK,
|
Species.GALAR_STUNFISK,
|
||||||
|
[
|
||||||
|
Species.URSHIFU,
|
||||||
|
"single-strike",
|
||||||
|
],
|
||||||
[
|
[
|
||||||
Species.CALYREX,
|
Species.CALYREX,
|
||||||
"shadow",
|
"shadow",
|
||||||
@ -56577,14 +56360,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -57019,14 +56795,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.PANCHAM,
|
Species.PANCHAM,
|
||||||
Species.PANGORO,
|
Species.PANGORO,
|
||||||
@ -57354,14 +57123,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.BRAIXEN,
|
Species.BRAIXEN,
|
||||||
Species.DELPHOX,
|
Species.DELPHOX,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.ESPURR,
|
Species.ESPURR,
|
||||||
Species.MEOWSTIC,
|
Species.MEOWSTIC,
|
||||||
@ -58997,7 +58759,6 @@ export const tmSpecies: TmSpecies = {
|
|||||||
[
|
[
|
||||||
Species.WORMADAM,
|
Species.WORMADAM,
|
||||||
"sandy",
|
"sandy",
|
||||||
"trash",
|
|
||||||
],
|
],
|
||||||
Species.ALOLA_SANDSHREW,
|
Species.ALOLA_SANDSHREW,
|
||||||
Species.ALOLA_SANDSLASH,
|
Species.ALOLA_SANDSLASH,
|
||||||
@ -60070,7 +59831,6 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.DURALUDON,
|
Species.DURALUDON,
|
||||||
Species.ZACIAN,
|
Species.ZACIAN,
|
||||||
Species.ZAMAZENTA,
|
Species.ZAMAZENTA,
|
||||||
Species.URSHIFU,
|
|
||||||
Species.ZARUDE,
|
Species.ZARUDE,
|
||||||
Species.GLASTRIER,
|
Species.GLASTRIER,
|
||||||
Species.SPECTRIER,
|
Species.SPECTRIER,
|
||||||
@ -60116,6 +59876,10 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.HISUI_ZOROARK,
|
Species.HISUI_ZOROARK,
|
||||||
Species.HISUI_BRAVIARY,
|
Species.HISUI_BRAVIARY,
|
||||||
Species.BLOODMOON_URSALUNA,
|
Species.BLOODMOON_URSALUNA,
|
||||||
|
[
|
||||||
|
Species.URSHIFU,
|
||||||
|
"single-strike",
|
||||||
|
],
|
||||||
],
|
],
|
||||||
[Moves.PHANTOM_FORCE]: [
|
[Moves.PHANTOM_FORCE]: [
|
||||||
Species.HAUNTER,
|
Species.HAUNTER,
|
||||||
@ -60446,14 +60210,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.QUILLADIN,
|
Species.QUILLADIN,
|
||||||
Species.CHESNAUGHT,
|
Species.CHESNAUGHT,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -60529,16 +60286,12 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.WHIMSICOTT,
|
Species.WHIMSICOTT,
|
||||||
Species.ALOMOMOLA,
|
Species.ALOMOMOLA,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
|
[
|
||||||
Species.MEOWSTIC,
|
Species.MEOWSTIC,
|
||||||
|
"male",
|
||||||
|
],
|
||||||
Species.SPRITZEE,
|
Species.SPRITZEE,
|
||||||
Species.AROMATISSE,
|
Species.AROMATISSE,
|
||||||
Species.SYLVEON,
|
Species.SYLVEON,
|
||||||
@ -61402,14 +61155,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -61899,14 +61645,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.MELOETTA,
|
Species.MELOETTA,
|
||||||
Species.DELPHOX,
|
Species.DELPHOX,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SPRITZEE,
|
Species.SPRITZEE,
|
||||||
Species.AROMATISSE,
|
Species.AROMATISSE,
|
||||||
@ -62617,7 +62356,6 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.SIRFETCHD,
|
Species.SIRFETCHD,
|
||||||
Species.FALINKS,
|
Species.FALINKS,
|
||||||
Species.PINCURCHIN,
|
Species.PINCURCHIN,
|
||||||
Species.URSHIFU,
|
|
||||||
Species.ZARUDE,
|
Species.ZARUDE,
|
||||||
Species.GLASTRIER,
|
Species.GLASTRIER,
|
||||||
Species.TAROUNTULA,
|
Species.TAROUNTULA,
|
||||||
@ -62647,6 +62385,10 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.GALAR_ZAPDOS,
|
Species.GALAR_ZAPDOS,
|
||||||
Species.GALAR_CORSOLA,
|
Species.GALAR_CORSOLA,
|
||||||
Species.GALAR_LINOONE,
|
Species.GALAR_LINOONE,
|
||||||
|
[
|
||||||
|
Species.URSHIFU,
|
||||||
|
"single-strike",
|
||||||
|
],
|
||||||
[
|
[
|
||||||
Species.CALYREX,
|
Species.CALYREX,
|
||||||
"ice",
|
"ice",
|
||||||
@ -63541,12 +63283,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.KELDEO,
|
Species.KELDEO,
|
||||||
Species.FROAKIE,
|
Species.FROAKIE,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.INKAY,
|
Species.INKAY,
|
||||||
Species.MALAMAR,
|
Species.MALAMAR,
|
||||||
Species.BINACLE,
|
Species.BINACLE,
|
||||||
@ -64755,7 +64492,6 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.OBSTAGOON,
|
Species.OBSTAGOON,
|
||||||
Species.PERRSERKER,
|
Species.PERRSERKER,
|
||||||
Species.MORPEKO,
|
Species.MORPEKO,
|
||||||
Species.URSHIFU,
|
|
||||||
Species.ZARUDE,
|
Species.ZARUDE,
|
||||||
Species.GLASTRIER,
|
Species.GLASTRIER,
|
||||||
Species.SPECTRIER,
|
Species.SPECTRIER,
|
||||||
@ -64803,6 +64539,10 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.GALAR_LINOONE,
|
Species.GALAR_LINOONE,
|
||||||
Species.GALAR_DARMANITAN,
|
Species.GALAR_DARMANITAN,
|
||||||
Species.GALAR_STUNFISK,
|
Species.GALAR_STUNFISK,
|
||||||
|
[
|
||||||
|
Species.URSHIFU,
|
||||||
|
"single-strike",
|
||||||
|
],
|
||||||
[
|
[
|
||||||
Species.CALYREX,
|
Species.CALYREX,
|
||||||
"ice",
|
"ice",
|
||||||
@ -65933,12 +65673,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.DELPHOX,
|
Species.DELPHOX,
|
||||||
Species.FROAKIE,
|
Species.FROAKIE,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.BUNNELBY,
|
Species.BUNNELBY,
|
||||||
Species.DIGGERSBY,
|
Species.DIGGERSBY,
|
||||||
Species.FLETCHLING,
|
Species.FLETCHLING,
|
||||||
@ -65950,14 +65685,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
[
|
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
"red",
|
|
||||||
"yellow",
|
|
||||||
"orange",
|
|
||||||
"blue",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
Species.SKIDDO,
|
Species.SKIDDO,
|
||||||
Species.GOGOAT,
|
Species.GOGOAT,
|
||||||
@ -66291,6 +66019,13 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.MUNKIDORI,
|
Species.MUNKIDORI,
|
||||||
Species.FEZANDIPITI,
|
Species.FEZANDIPITI,
|
||||||
Species.OGERPON,
|
Species.OGERPON,
|
||||||
|
Species.ARCHALUDON,
|
||||||
|
Species.HYDRAPPLE,
|
||||||
|
Species.GOUGING_FIRE,
|
||||||
|
Species.RAGING_BOLT,
|
||||||
|
Species.IRON_BOULDER,
|
||||||
|
Species.IRON_CROWN,
|
||||||
|
Species.PECHARUNT,
|
||||||
Species.GALAR_MEOWTH,
|
Species.GALAR_MEOWTH,
|
||||||
Species.GALAR_SLOWPOKE,
|
Species.GALAR_SLOWPOKE,
|
||||||
Species.GALAR_SLOWBRO,
|
Species.GALAR_SLOWBRO,
|
||||||
@ -66429,16 +66164,8 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.PIPLUP,
|
Species.PIPLUP,
|
||||||
Species.PRINPLUP,
|
Species.PRINPLUP,
|
||||||
Species.EMPOLEON,
|
Species.EMPOLEON,
|
||||||
[
|
|
||||||
Species.SHELLOS,
|
Species.SHELLOS,
|
||||||
"east",
|
|
||||||
"west",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
Species.GASTRODON,
|
Species.GASTRODON,
|
||||||
"east",
|
|
||||||
"west",
|
|
||||||
],
|
|
||||||
Species.MISMAGIUS,
|
Species.MISMAGIUS,
|
||||||
Species.HAPPINY,
|
Species.HAPPINY,
|
||||||
Species.SNOVER,
|
Species.SNOVER,
|
||||||
@ -66456,25 +66183,11 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.CUBCHOO,
|
Species.CUBCHOO,
|
||||||
Species.BEARTIC,
|
Species.BEARTIC,
|
||||||
Species.CRYOGONAL,
|
Species.CRYOGONAL,
|
||||||
[
|
|
||||||
Species.TORNADUS,
|
Species.TORNADUS,
|
||||||
"incarnate",
|
|
||||||
"therian",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
Species.KYUREM,
|
Species.KYUREM,
|
||||||
"",
|
|
||||||
"black",
|
|
||||||
"white",
|
|
||||||
],
|
|
||||||
Species.FROAKIE,
|
Species.FROAKIE,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.SKRELP,
|
Species.SKRELP,
|
||||||
Species.DRAGALGE,
|
Species.DRAGALGE,
|
||||||
Species.BERGMITE,
|
Species.BERGMITE,
|
||||||
@ -66482,11 +66195,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.DIANCIE,
|
Species.DIANCIE,
|
||||||
Species.PRIMARINA,
|
Species.PRIMARINA,
|
||||||
Species.CRABOMINABLE,
|
Species.CRABOMINABLE,
|
||||||
[
|
|
||||||
Species.MAGEARNA,
|
Species.MAGEARNA,
|
||||||
"",
|
|
||||||
"original",
|
|
||||||
],
|
|
||||||
Species.INTELEON,
|
Species.INTELEON,
|
||||||
Species.FROSMOTH,
|
Species.FROSMOTH,
|
||||||
Species.EISCUE,
|
Species.EISCUE,
|
||||||
@ -66779,12 +66488,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.CHESNAUGHT,
|
Species.CHESNAUGHT,
|
||||||
Species.FROAKIE,
|
Species.FROAKIE,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.LITLEO,
|
Species.LITLEO,
|
||||||
Species.PYROAR,
|
Species.PYROAR,
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
@ -67007,23 +66711,14 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.WEAVILE,
|
Species.WEAVILE,
|
||||||
Species.GLACEON,
|
Species.GLACEON,
|
||||||
Species.FROSLASS,
|
Species.FROSLASS,
|
||||||
[
|
|
||||||
Species.PALKIA,
|
Species.PALKIA,
|
||||||
"",
|
|
||||||
"origin",
|
|
||||||
],
|
|
||||||
Species.PHIONE,
|
Species.PHIONE,
|
||||||
Species.MANAPHY,
|
Species.MANAPHY,
|
||||||
Species.ARCEUS,
|
Species.ARCEUS,
|
||||||
Species.OSHAWOTT,
|
Species.OSHAWOTT,
|
||||||
Species.DEWOTT,
|
Species.DEWOTT,
|
||||||
Species.SAMUROTT,
|
Species.SAMUROTT,
|
||||||
[
|
|
||||||
Species.BASCULIN,
|
Species.BASCULIN,
|
||||||
"red-striped",
|
|
||||||
"blue-striped",
|
|
||||||
"white-striped",
|
|
||||||
],
|
|
||||||
Species.MINCCINO,
|
Species.MINCCINO,
|
||||||
Species.CINCCINO,
|
Species.CINCCINO,
|
||||||
Species.DUCKLETT,
|
Species.DUCKLETT,
|
||||||
@ -67036,12 +66731,7 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.KELDEO,
|
Species.KELDEO,
|
||||||
Species.FROAKIE,
|
Species.FROAKIE,
|
||||||
Species.FROGADIER,
|
Species.FROGADIER,
|
||||||
[
|
|
||||||
Species.GRENINJA,
|
Species.GRENINJA,
|
||||||
"",
|
|
||||||
"battle-bond",
|
|
||||||
"ash",
|
|
||||||
],
|
|
||||||
Species.FLABEBE,
|
Species.FLABEBE,
|
||||||
Species.FLOETTE,
|
Species.FLOETTE,
|
||||||
Species.FLORGES,
|
Species.FLORGES,
|
||||||
@ -67304,6 +66994,10 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.FEZANDIPITI,
|
Species.FEZANDIPITI,
|
||||||
Species.ALOLA_RAICHU,
|
Species.ALOLA_RAICHU,
|
||||||
Species.ETERNAL_FLOETTE,
|
Species.ETERNAL_FLOETTE,
|
||||||
|
[
|
||||||
|
Species.INDEEDEE,
|
||||||
|
"female",
|
||||||
|
],
|
||||||
],
|
],
|
||||||
[Moves.TEMPER_FLARE]: [
|
[Moves.TEMPER_FLARE]: [
|
||||||
Species.CHARMANDER,
|
Species.CHARMANDER,
|
||||||
|
@ -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
|
||||||
@ -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) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2811,6 +2826,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
|
|||||||
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:
|
||||||
|
261
src/data/move.ts
261
src/data/move.ts
@ -1010,7 +1010,14 @@ export class MoveEffectAttr extends MoveAttr {
|
|||||||
*/
|
*/
|
||||||
getMoveChance(user: Pokemon, target: Pokemon, move: Move, selfEffect?: Boolean, showAbility?: Boolean): integer {
|
getMoveChance(user: Pokemon, target: Pokemon, move: Move, selfEffect?: Boolean, showAbility?: Boolean): integer {
|
||||||
const moveChance = new Utils.NumberHolder(move.chance);
|
const moveChance = new Utils.NumberHolder(move.chance);
|
||||||
|
|
||||||
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, false, moveChance, move, target, selfEffect, showAbility);
|
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, false, moveChance, move, target, selfEffect, showAbility);
|
||||||
|
|
||||||
|
if (!move.hasAttr(FlinchAttr) || moveChance.value <= move.chance) {
|
||||||
|
const userSide = user.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
|
||||||
|
user.scene.arena.applyTagsForSide(ArenaTagType.WATER_FIRE_PLEDGE, userSide, moveChance);
|
||||||
|
}
|
||||||
|
|
||||||
if (!selfEffect) {
|
if (!selfEffect) {
|
||||||
applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, target, user, null, null, false, moveChance);
|
applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, target, user, null, null, false, moveChance);
|
||||||
}
|
}
|
||||||
@ -2687,6 +2694,62 @@ export class DelayedAttackAttr extends OverrideMoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute that cancels the associated move's effects when set to be combined with the user's ally's
|
||||||
|
* subsequent move this turn. Used for Grass Pledge, Water Pledge, and Fire Pledge.
|
||||||
|
* @extends OverrideMoveEffectAttr
|
||||||
|
*/
|
||||||
|
export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr {
|
||||||
|
constructor() {
|
||||||
|
super(true);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* If the user's ally is set to use a different move with this attribute,
|
||||||
|
* defer this move's effects for a combined move on the ally's turn.
|
||||||
|
* @param user the {@linkcode Pokemon} using this move
|
||||||
|
* @param target n/a
|
||||||
|
* @param move the {@linkcode Move} being used
|
||||||
|
* @param args
|
||||||
|
* - [0] a {@linkcode Utils.BooleanHolder} indicating whether the move's base
|
||||||
|
* effects should be overridden this turn.
|
||||||
|
* @returns `true` if base move effects were overridden; `false` otherwise
|
||||||
|
*/
|
||||||
|
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
if (user.turnData.combiningPledge) {
|
||||||
|
// "The two moves have become one!\nIt's a combined move!"
|
||||||
|
user.scene.queueMessage(i18next.t("moveTriggers:combiningPledge"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const overridden = args[0] as Utils.BooleanHolder;
|
||||||
|
|
||||||
|
const allyMovePhase = user.scene.findPhase<MovePhase>((phase) => phase instanceof MovePhase && phase.pokemon.isPlayer() === user.isPlayer());
|
||||||
|
if (allyMovePhase) {
|
||||||
|
const allyMove = allyMovePhase.move.getMove();
|
||||||
|
if (allyMove !== move && allyMove.hasAttr(AwaitCombinedPledgeAttr)) {
|
||||||
|
[ user, allyMovePhase.pokemon ].forEach((p) => p.turnData.combiningPledge = move.id);
|
||||||
|
|
||||||
|
// "{userPokemonName} is waiting for {allyPokemonName}'s move..."
|
||||||
|
user.scene.queueMessage(i18next.t("moveTriggers:awaitingPledge", {
|
||||||
|
userPokemonName: getPokemonNameWithAffix(user),
|
||||||
|
allyPokemonName: getPokemonNameWithAffix(allyMovePhase.pokemon)
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Move the ally's MovePhase (if needed) so that the ally moves next
|
||||||
|
const allyMovePhaseIndex = user.scene.phaseQueue.indexOf(allyMovePhase);
|
||||||
|
const firstMovePhaseIndex = user.scene.phaseQueue.findIndex((phase) => phase instanceof MovePhase);
|
||||||
|
if (allyMovePhaseIndex !== firstMovePhaseIndex) {
|
||||||
|
user.scene.prependToPhase(user.scene.phaseQueue.splice(allyMovePhaseIndex, 1)[0], MovePhase);
|
||||||
|
}
|
||||||
|
|
||||||
|
overridden.value = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute used for moves that change stat stages
|
* Attribute used for moves that change stat stages
|
||||||
* @param stats {@linkcode BattleStat} array of stats to be changed
|
* @param stats {@linkcode BattleStat} array of stats to be changed
|
||||||
@ -3762,6 +3825,45 @@ export class LastMoveDoublePowerAttr extends VariablePowerAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes a Pledge move's power to 150 when combined with another unique Pledge
|
||||||
|
* move from an ally.
|
||||||
|
*/
|
||||||
|
export class CombinedPledgePowerAttr extends VariablePowerAttr {
|
||||||
|
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
const power = args[0];
|
||||||
|
if (!(power instanceof Utils.NumberHolder)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const combinedPledgeMove = user.turnData.combiningPledge;
|
||||||
|
|
||||||
|
if (combinedPledgeMove && combinedPledgeMove !== move.id) {
|
||||||
|
power.value *= 150 / 80;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies STAB to the given Pledge move if the move is part of a combined attack.
|
||||||
|
*/
|
||||||
|
export class CombinedPledgeStabBoostAttr extends MoveAttr {
|
||||||
|
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
const stabMultiplier = args[0];
|
||||||
|
if (!(stabMultiplier instanceof Utils.NumberHolder)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const combinedPledgeMove = user.turnData.combiningPledge;
|
||||||
|
|
||||||
|
if (combinedPledgeMove && combinedPledgeMove !== move.id) {
|
||||||
|
stabMultiplier.value = 1.5;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class VariableAtkAttr extends MoveAttr {
|
export class VariableAtkAttr extends MoveAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -3942,7 +4044,14 @@ export class PhotonGeyserCategoryAttr extends VariableMoveCategoryAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TeraBlastCategoryAttr extends VariableMoveCategoryAttr {
|
/**
|
||||||
|
* Attribute used for tera moves that change category based on the user's Atk and SpAtk stats
|
||||||
|
* Note: Currently, `getEffectiveStat` does not ignore all abilities that affect stats except those
|
||||||
|
* with the attribute of `StatMultiplierAbAttr`
|
||||||
|
* TODO: Remove the `.partial()` tag from Tera Blast and Tera Starstorm when the above issue is resolved
|
||||||
|
* @extends VariableMoveCategoryAttr
|
||||||
|
*/
|
||||||
|
export class TeraMoveCategoryAttr extends VariableMoveCategoryAttr {
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
const category = (args[0] as Utils.NumberHolder);
|
const category = (args[0] as Utils.NumberHolder);
|
||||||
|
|
||||||
@ -4031,6 +4140,30 @@ export class VariableMoveTypeAttr extends MoveAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute used for Tera Starstorm that changes the move type to Stellar
|
||||||
|
* @extends VariableMoveTypeAttr
|
||||||
|
*/
|
||||||
|
export class TeraStarstormTypeAttr extends VariableMoveTypeAttr {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param user the {@linkcode Pokemon} using the move
|
||||||
|
* @param target n/a
|
||||||
|
* @param move n/a
|
||||||
|
* @param args[0] {@linkcode Utils.NumberHolder} the move type
|
||||||
|
* @returns `true` if the move type is changed to {@linkcode Type.STELLAR}, `false` otherwise
|
||||||
|
*/
|
||||||
|
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
if (user.isTerastallized() && (user.hasFusionSpecies(Species.TERAPAGOS) || user.species.speciesId === Species.TERAPAGOS)) {
|
||||||
|
const moveType = args[0] as Utils.NumberHolder;
|
||||||
|
|
||||||
|
moveType.value = Type.STELLAR;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class FormChangeItemTypeAttr extends VariableMoveTypeAttr {
|
export class FormChangeItemTypeAttr extends VariableMoveTypeAttr {
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
const moveType = args[0];
|
const moveType = args[0];
|
||||||
@ -4327,6 +4460,47 @@ export class MatchUserTypeAttr extends VariableMoveTypeAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the type of a Pledge move based on the Pledge move combined with it.
|
||||||
|
* @extends VariableMoveTypeAttr
|
||||||
|
*/
|
||||||
|
export class CombinedPledgeTypeAttr extends VariableMoveTypeAttr {
|
||||||
|
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
const moveType = args[0];
|
||||||
|
if (!(moveType instanceof Utils.NumberHolder)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const combinedPledgeMove = user.turnData.combiningPledge;
|
||||||
|
if (!combinedPledgeMove) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (move.id) {
|
||||||
|
case Moves.FIRE_PLEDGE:
|
||||||
|
if (combinedPledgeMove === Moves.WATER_PLEDGE) {
|
||||||
|
moveType.value = Type.WATER;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case Moves.WATER_PLEDGE:
|
||||||
|
if (combinedPledgeMove === Moves.GRASS_PLEDGE) {
|
||||||
|
moveType.value = Type.GRASS;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case Moves.GRASS_PLEDGE:
|
||||||
|
if (combinedPledgeMove === Moves.FIRE_PLEDGE) {
|
||||||
|
moveType.value = Type.FIRE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class VariableMoveTypeMultiplierAttr extends MoveAttr {
|
export class VariableMoveTypeMultiplierAttr extends MoveAttr {
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -4474,7 +4648,15 @@ export class TypelessAttr extends MoveAttr { }
|
|||||||
* Attribute used for moves which ignore redirection effects, and always target their original target, i.e. Snipe Shot
|
* Attribute used for moves which ignore redirection effects, and always target their original target, i.e. Snipe Shot
|
||||||
* Bypasses Storm Drain, Follow Me, Ally Switch, and the like.
|
* Bypasses Storm Drain, Follow Me, Ally Switch, and the like.
|
||||||
*/
|
*/
|
||||||
export class BypassRedirectAttr extends MoveAttr { }
|
export class BypassRedirectAttr extends MoveAttr {
|
||||||
|
/** `true` if this move only bypasses redirection from Abilities */
|
||||||
|
public readonly abilitiesOnly: boolean;
|
||||||
|
|
||||||
|
constructor(abilitiesOnly: boolean = false) {
|
||||||
|
super();
|
||||||
|
this.abilitiesOnly = abilitiesOnly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class FrenzyAttr extends MoveEffectAttr {
|
export class FrenzyAttr extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -5165,6 +5347,32 @@ export class SwapArenaTagsAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute that adds a secondary effect to the field when two unique Pledge moves
|
||||||
|
* are combined. The effect added varies based on the two Pledge moves combined.
|
||||||
|
*/
|
||||||
|
export class AddPledgeEffectAttr extends AddArenaTagAttr {
|
||||||
|
private readonly requiredPledge: Moves;
|
||||||
|
|
||||||
|
constructor(tagType: ArenaTagType, requiredPledge: Moves, selfSideTarget: boolean = false) {
|
||||||
|
super(tagType, 4, false, selfSideTarget);
|
||||||
|
|
||||||
|
this.requiredPledge = requiredPledge;
|
||||||
|
}
|
||||||
|
|
||||||
|
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
// TODO: add support for `HIT` effect triggering in AddArenaTagAttr to remove the need for this check
|
||||||
|
if (user.getLastXMoves(1)[0].result !== MoveResult.SUCCESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.turnData.combiningPledge === this.requiredPledge) {
|
||||||
|
return super.apply(user, target, move, args);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute used for Revival Blessing.
|
* Attribute used for Revival Blessing.
|
||||||
* @extends MoveEffectAttr
|
* @extends MoveEffectAttr
|
||||||
@ -8310,11 +8518,29 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.INFERNO, Type.FIRE, MoveCategory.SPECIAL, 100, 50, 5, 100, 0, 5)
|
new AttackMove(Moves.INFERNO, Type.FIRE, MoveCategory.SPECIAL, 100, 50, 5, 100, 0, 5)
|
||||||
.attr(StatusEffectAttr, StatusEffect.BURN),
|
.attr(StatusEffectAttr, StatusEffect.BURN),
|
||||||
new AttackMove(Moves.WATER_PLEDGE, Type.WATER, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 5)
|
new AttackMove(Moves.WATER_PLEDGE, Type.WATER, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 5)
|
||||||
.partial(),
|
.attr(AwaitCombinedPledgeAttr)
|
||||||
|
.attr(CombinedPledgeTypeAttr)
|
||||||
|
.attr(CombinedPledgePowerAttr)
|
||||||
|
.attr(CombinedPledgeStabBoostAttr)
|
||||||
|
.attr(AddPledgeEffectAttr, ArenaTagType.WATER_FIRE_PLEDGE, Moves.FIRE_PLEDGE, true)
|
||||||
|
.attr(AddPledgeEffectAttr, ArenaTagType.GRASS_WATER_PLEDGE, Moves.GRASS_PLEDGE)
|
||||||
|
.attr(BypassRedirectAttr, true),
|
||||||
new AttackMove(Moves.FIRE_PLEDGE, Type.FIRE, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 5)
|
new AttackMove(Moves.FIRE_PLEDGE, Type.FIRE, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 5)
|
||||||
.partial(),
|
.attr(AwaitCombinedPledgeAttr)
|
||||||
|
.attr(CombinedPledgeTypeAttr)
|
||||||
|
.attr(CombinedPledgePowerAttr)
|
||||||
|
.attr(CombinedPledgeStabBoostAttr)
|
||||||
|
.attr(AddPledgeEffectAttr, ArenaTagType.FIRE_GRASS_PLEDGE, Moves.GRASS_PLEDGE)
|
||||||
|
.attr(AddPledgeEffectAttr, ArenaTagType.WATER_FIRE_PLEDGE, Moves.WATER_PLEDGE, true)
|
||||||
|
.attr(BypassRedirectAttr, true),
|
||||||
new AttackMove(Moves.GRASS_PLEDGE, Type.GRASS, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 5)
|
new AttackMove(Moves.GRASS_PLEDGE, Type.GRASS, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 5)
|
||||||
.partial(),
|
.attr(AwaitCombinedPledgeAttr)
|
||||||
|
.attr(CombinedPledgeTypeAttr)
|
||||||
|
.attr(CombinedPledgePowerAttr)
|
||||||
|
.attr(CombinedPledgeStabBoostAttr)
|
||||||
|
.attr(AddPledgeEffectAttr, ArenaTagType.GRASS_WATER_PLEDGE, Moves.WATER_PLEDGE)
|
||||||
|
.attr(AddPledgeEffectAttr, ArenaTagType.FIRE_GRASS_PLEDGE, Moves.FIRE_PLEDGE)
|
||||||
|
.attr(BypassRedirectAttr, true),
|
||||||
new AttackMove(Moves.VOLT_SWITCH, Type.ELECTRIC, MoveCategory.SPECIAL, 70, 100, 20, -1, 0, 5)
|
new AttackMove(Moves.VOLT_SWITCH, Type.ELECTRIC, MoveCategory.SPECIAL, 70, 100, 20, -1, 0, 5)
|
||||||
.attr(ForceSwitchOutAttr, true),
|
.attr(ForceSwitchOutAttr, true),
|
||||||
new AttackMove(Moves.STRUGGLE_BUG, Type.BUG, MoveCategory.SPECIAL, 50, 100, 20, 100, 0, 5)
|
new AttackMove(Moves.STRUGGLE_BUG, Type.BUG, MoveCategory.SPECIAL, 50, 100, 20, 100, 0, 5)
|
||||||
@ -8462,8 +8688,8 @@ export function initMoves() {
|
|||||||
.attr(StatStageChangeAttr, [ Stat.ATK, Stat.SPATK ], -1)
|
.attr(StatStageChangeAttr, [ Stat.ATK, Stat.SPATK ], -1)
|
||||||
.soundBased(),
|
.soundBased(),
|
||||||
new StatusMove(Moves.ION_DELUGE, Type.ELECTRIC, -1, 25, -1, 1, 6)
|
new StatusMove(Moves.ION_DELUGE, Type.ELECTRIC, -1, 25, -1, 1, 6)
|
||||||
.target(MoveTarget.BOTH_SIDES)
|
.attr(AddArenaTagAttr, ArenaTagType.ION_DELUGE)
|
||||||
.unimplemented(),
|
.target(MoveTarget.BOTH_SIDES),
|
||||||
new AttackMove(Moves.PARABOLIC_CHARGE, Type.ELECTRIC, MoveCategory.SPECIAL, 65, 100, 20, -1, 0, 6)
|
new AttackMove(Moves.PARABOLIC_CHARGE, Type.ELECTRIC, MoveCategory.SPECIAL, 65, 100, 20, -1, 0, 6)
|
||||||
.attr(HitHealAttr)
|
.attr(HitHealAttr)
|
||||||
.target(MoveTarget.ALL_NEAR_OTHERS)
|
.target(MoveTarget.ALL_NEAR_OTHERS)
|
||||||
@ -8506,7 +8732,7 @@ export function initMoves() {
|
|||||||
.attr(TerrainChangeAttr, TerrainType.MISTY)
|
.attr(TerrainChangeAttr, TerrainType.MISTY)
|
||||||
.target(MoveTarget.BOTH_SIDES),
|
.target(MoveTarget.BOTH_SIDES),
|
||||||
new StatusMove(Moves.ELECTRIFY, Type.ELECTRIC, -1, 20, -1, 0, 6)
|
new StatusMove(Moves.ELECTRIFY, Type.ELECTRIC, -1, 20, -1, 0, 6)
|
||||||
.unimplemented(),
|
.attr(AddBattlerTagAttr, BattlerTagType.ELECTRIFIED, false, true),
|
||||||
new AttackMove(Moves.PLAY_ROUGH, Type.FAIRY, MoveCategory.PHYSICAL, 90, 90, 10, 10, 0, 6)
|
new AttackMove(Moves.PLAY_ROUGH, Type.FAIRY, MoveCategory.PHYSICAL, 90, 90, 10, 10, 0, 6)
|
||||||
.attr(StatStageChangeAttr, [ Stat.ATK ], -1),
|
.attr(StatStageChangeAttr, [ Stat.ATK ], -1),
|
||||||
new AttackMove(Moves.FAIRY_WIND, Type.FAIRY, MoveCategory.SPECIAL, 40, 100, 30, -1, 0, 6)
|
new AttackMove(Moves.FAIRY_WIND, Type.FAIRY, MoveCategory.SPECIAL, 40, 100, 30, -1, 0, 6)
|
||||||
@ -8530,7 +8756,7 @@ export function initMoves() {
|
|||||||
.attr(StatStageChangeAttr, [ Stat.SPATK ], -1)
|
.attr(StatStageChangeAttr, [ Stat.SPATK ], -1)
|
||||||
.soundBased(),
|
.soundBased(),
|
||||||
new AttackMove(Moves.DIAMOND_STORM, Type.ROCK, MoveCategory.PHYSICAL, 100, 95, 5, 50, 0, 6)
|
new AttackMove(Moves.DIAMOND_STORM, Type.ROCK, MoveCategory.PHYSICAL, 100, 95, 5, 50, 0, 6)
|
||||||
.attr(StatStageChangeAttr, [ Stat.DEF ], 2, true)
|
.attr(StatStageChangeAttr, [ Stat.DEF ], 2, true, undefined, undefined, undefined, undefined, true)
|
||||||
.makesContact(false)
|
.makesContact(false)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new AttackMove(Moves.STEAM_ERUPTION, Type.WATER, MoveCategory.SPECIAL, 110, 95, 5, 30, 0, 6)
|
new AttackMove(Moves.STEAM_ERUPTION, Type.WATER, MoveCategory.SPECIAL, 110, 95, 5, 30, 0, 6)
|
||||||
@ -8932,7 +9158,7 @@ export function initMoves() {
|
|||||||
.attr(HalfSacrificialAttr)
|
.attr(HalfSacrificialAttr)
|
||||||
.target(MoveTarget.ALL_NEAR_OTHERS),
|
.target(MoveTarget.ALL_NEAR_OTHERS),
|
||||||
new AttackMove(Moves.PLASMA_FISTS, Type.ELECTRIC, MoveCategory.PHYSICAL, 100, 100, 15, -1, 0, 7)
|
new AttackMove(Moves.PLASMA_FISTS, Type.ELECTRIC, MoveCategory.PHYSICAL, 100, 100, 15, -1, 0, 7)
|
||||||
.attr(AddArenaTagAttr, ArenaTagType.PLASMA_FISTS, 1)
|
.attr(AddArenaTagAttr, ArenaTagType.ION_DELUGE, 1)
|
||||||
.punchingMove(),
|
.punchingMove(),
|
||||||
new AttackMove(Moves.PHOTON_GEYSER, Type.PSYCHIC, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 7)
|
new AttackMove(Moves.PHOTON_GEYSER, Type.PSYCHIC, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 7)
|
||||||
.attr(PhotonGeyserCategoryAttr)
|
.attr(PhotonGeyserCategoryAttr)
|
||||||
@ -8957,7 +9183,7 @@ export function initMoves() {
|
|||||||
.makesContact(false)
|
.makesContact(false)
|
||||||
.ignoresVirtual(),
|
.ignoresVirtual(),
|
||||||
new AttackMove(Moves.CLANGOROUS_SOULBLAZE, Type.DRAGON, MoveCategory.SPECIAL, 185, -1, 1, 100, 0, 7)
|
new AttackMove(Moves.CLANGOROUS_SOULBLAZE, Type.DRAGON, MoveCategory.SPECIAL, 185, -1, 1, 100, 0, 7)
|
||||||
.attr(StatStageChangeAttr, [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ], 1, true)
|
.attr(StatStageChangeAttr, [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ], 1, true, undefined, undefined, undefined, undefined, true)
|
||||||
.soundBased()
|
.soundBased()
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES)
|
.target(MoveTarget.ALL_NEAR_ENEMIES)
|
||||||
.partial()
|
.partial()
|
||||||
@ -9190,7 +9416,7 @@ export function initMoves() {
|
|||||||
.attr(HalfSacrificialAttr),
|
.attr(HalfSacrificialAttr),
|
||||||
new AttackMove(Moves.EXPANDING_FORCE, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 8)
|
new AttackMove(Moves.EXPANDING_FORCE, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 8)
|
||||||
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.PSYCHIC && user.isGrounded() ? 1.5 : 1)
|
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.PSYCHIC && user.isGrounded() ? 1.5 : 1)
|
||||||
.attr(VariableTargetAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.PSYCHIC && user.isGrounded() ? 6 : 3),
|
.attr(VariableTargetAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.PSYCHIC && user.isGrounded() ? MoveTarget.ALL_NEAR_ENEMIES : MoveTarget.NEAR_OTHER),
|
||||||
new AttackMove(Moves.STEEL_ROLLER, Type.STEEL, MoveCategory.PHYSICAL, 130, 100, 5, -1, 0, 8)
|
new AttackMove(Moves.STEEL_ROLLER, Type.STEEL, MoveCategory.PHYSICAL, 130, 100, 5, -1, 0, 8)
|
||||||
.attr(ClearTerrainAttr)
|
.attr(ClearTerrainAttr)
|
||||||
.condition((user, target, move) => !!user.scene.arena.terrain),
|
.condition((user, target, move) => !!user.scene.arena.terrain),
|
||||||
@ -9464,10 +9690,11 @@ export function initMoves() {
|
|||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
End Unused */
|
End Unused */
|
||||||
new AttackMove(Moves.TERA_BLAST, Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 9)
|
new AttackMove(Moves.TERA_BLAST, Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 9)
|
||||||
.attr(TeraBlastCategoryAttr)
|
.attr(TeraMoveCategoryAttr)
|
||||||
.attr(TeraBlastTypeAttr)
|
.attr(TeraBlastTypeAttr)
|
||||||
.attr(TeraBlastPowerAttr)
|
.attr(TeraBlastPowerAttr)
|
||||||
.attr(StatStageChangeAttr, [ Stat.ATK, Stat.SPATK ], -1, true, (user, target, move) => user.isTerastallized() && user.isOfType(Type.STELLAR)),
|
.attr(StatStageChangeAttr, [ Stat.ATK, Stat.SPATK ], -1, true, (user, target, move) => user.isTerastallized() && user.isOfType(Type.STELLAR))
|
||||||
|
.partial(), /** Does not ignore abilities that affect stats, relevant in determining the move's category {@see TeraMoveCategoryAttr} */
|
||||||
new SelfStatusMove(Moves.SILK_TRAP, Type.BUG, -1, 10, -1, 4, 9)
|
new SelfStatusMove(Moves.SILK_TRAP, Type.BUG, -1, 10, -1, 4, 9)
|
||||||
.attr(ProtectAttr, BattlerTagType.SILK_TRAP)
|
.attr(ProtectAttr, BattlerTagType.SILK_TRAP)
|
||||||
.condition(failIfLastCondition),
|
.condition(failIfLastCondition),
|
||||||
@ -9657,8 +9884,10 @@ export function initMoves() {
|
|||||||
.attr(ElectroShotChargeAttr)
|
.attr(ElectroShotChargeAttr)
|
||||||
.ignoresVirtual(),
|
.ignoresVirtual(),
|
||||||
new AttackMove(Moves.TERA_STARSTORM, Type.NORMAL, MoveCategory.SPECIAL, 120, 100, 5, -1, 0, 9)
|
new AttackMove(Moves.TERA_STARSTORM, Type.NORMAL, MoveCategory.SPECIAL, 120, 100, 5, -1, 0, 9)
|
||||||
.attr(TeraBlastCategoryAttr)
|
.attr(TeraMoveCategoryAttr)
|
||||||
.partial(),
|
.attr(TeraStarstormTypeAttr)
|
||||||
|
.attr(VariableTargetAttr, (user, target, move) => (user.hasFusionSpecies(Species.TERAPAGOS) || user.species.speciesId === Species.TERAPAGOS) && user.isTerastallized() ? MoveTarget.ALL_NEAR_ENEMIES : MoveTarget.NEAR_OTHER)
|
||||||
|
.partial(), /** Does not ignore abilities that affect stats, relevant in determining the move's category {@see TeraMoveCategoryAttr} */
|
||||||
new AttackMove(Moves.FICKLE_BEAM, Type.DRAGON, MoveCategory.SPECIAL, 80, 100, 5, 30, 0, 9)
|
new AttackMove(Moves.FICKLE_BEAM, Type.DRAGON, MoveCategory.SPECIAL, 80, 100, 5, 30, 0, 9)
|
||||||
.attr(PreMoveMessageAttr, doublePowerChanceMessageFunc)
|
.attr(PreMoveMessageAttr, doublePowerChanceMessageFunc)
|
||||||
.attr(DoublePowerChanceAttr),
|
.attr(DoublePowerChanceAttr),
|
||||||
|
@ -1033,4 +1033,3 @@ export class WeightRequirement extends EncounterPokemonRequirement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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",
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
export enum BerryType {
|
export enum BerryType {
|
||||||
SITRUS,
|
SITRUS,
|
||||||
LUM,
|
LUM,
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
export enum Biome {
|
export enum Biome {
|
||||||
TOWN,
|
TOWN,
|
||||||
PLAINS,
|
PLAINS,
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
export enum TimeOfDay {
|
export enum TimeOfDay {
|
||||||
ALL = -1,
|
ALL = -1,
|
||||||
DAWN,
|
DAWN,
|
||||||
|
@ -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 {
|
||||||
|
@ -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";
|
||||||
@ -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)[] {
|
||||||
@ -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;
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this.pokemon.turnData.hitsLeft = 0; // TODO: is `0` correct?
|
|
||||||
this.pokemon.turnData.hitCount = 0; // TODO: is `0` correct?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move redirection abilities (ie. Storm Drain) only support single target moves
|
this.resolveRedirectTarget();
|
||||||
const moveTarget = this.targets.length === 1
|
|
||||||
? new Utils.IntegerHolder(this.targets[0])
|
|
||||||
: null;
|
|
||||||
if (moveTarget) {
|
|
||||||
const oldTarget = moveTarget.value;
|
|
||||||
this.scene.getField(true).filter(p => p !== this.pokemon).forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, false, this.move.moveId, moveTarget));
|
|
||||||
this.pokemon.getOpponents().forEach(p => {
|
|
||||||
const redirectTag = p.getTag(CenterOfAttentionTag) as CenterOfAttentionTag;
|
|
||||||
if (redirectTag && (!redirectTag.powder || (!this.pokemon.isOfType(Type.GRASS) && !this.pokemon.hasAbility(Abilities.OVERCOAT)))) {
|
|
||||||
moveTarget.value = p.getBattlerIndex();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//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
|
this.resolveCounterAttackTarget();
|
||||||
if (this.targets.length === 1 && this.targets[0] === BattlerIndex.ATTACKER) {
|
|
||||||
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
|
this.resolvePreMoveStatusEffects();
|
||||||
// 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 => {
|
this.lapsePreMoveAndMoveTags();
|
||||||
if (this.targets.indexOf(p.getBattlerIndex()) > -1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
const doMove = () => {
|
this.resolveFinalPreMoveCancellationChecks();
|
||||||
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.cancelled || this.failed) {
|
||||||
if (this.failed) {
|
this.handlePreMoveFailures();
|
||||||
this.move.usePp(ppUsed); // Only use PP if the move failed
|
} else {
|
||||||
this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), this.move.ppUsed));
|
this.useMove();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record a failed move so Abilities like Truant don't trigger next turn and soft-lock
|
this.end();
|
||||||
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);
|
/** Check for cancellation edge cases - no targets remaining, or {@linkcode Moves.NONE} is in the queue */
|
||||||
|
protected resolveFinalPreMoveCancellationChecks() {
|
||||||
|
const targets = this.getActiveTargetPokemon();
|
||||||
|
const moveQueue = this.pokemon.getMoveQueue();
|
||||||
|
|
||||||
if (this.move.moveId) {
|
if (targets.length === 0 || (moveQueue.length && moveQueue[0].move === Moves.NONE)) {
|
||||||
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.showFailedText();
|
||||||
this.cancel();
|
this.cancelled = true;
|
||||||
|
}
|
||||||
// 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
|
public getActiveTargetPokemon() {
|
||||||
this.move.usePp(ppUsed);
|
return this.scene.getField(true).filter(p => this.targets.includes(p.getBattlerIndex()));
|
||||||
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
|
* Handles {@link StatusEffect.SLEEP Sleep}/{@link StatusEffect.PARALYSIS Paralysis}/{@link StatusEffect.FREEZE Freeze} rolls and side effects.
|
||||||
* 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)) {
|
protected resolvePreMoveStatusEffects() {
|
||||||
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();
|
|
||||||
};
|
|
||||||
|
|
||||||
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 {
|
|
||||||
if (healed) {
|
|
||||||
this.scene.queueMessage(getStatusEffectHealText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)));
|
this.scene.queueMessage(getStatusEffectHealText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)));
|
||||||
this.pokemon.resetStatus();
|
this.pokemon.resetStatus();
|
||||||
this.pokemon.updateInfo();
|
this.pokemon.updateInfo();
|
||||||
}
|
}
|
||||||
doMove();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
doMove();
|
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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getEffectPhase(): MoveEffectPhase {
|
/**
|
||||||
return new MoveEffectPhase(this.scene, this.pokemon.getBattlerIndex(), this.targets, this.move);
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
showMoveText(): void {
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -80,7 +80,7 @@ export class SelectStarterPhase extends Phase {
|
|||||||
starterPokemon.nickname = starter.nickname;
|
starterPokemon.nickname = starter.nickname;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.scene.gameMode.isSplicedOnly) {
|
if (this.scene.gameMode.isSplicedOnly || Overrides.STARTER_FUSION_OVERRIDE) {
|
||||||
starterPokemon.generateFusionSpecies(true);
|
starterPokemon.generateFusionSpecies(true);
|
||||||
}
|
}
|
||||||
starterPokemon.setVisible(false);
|
starterPokemon.setVisible(false);
|
||||||
|
@ -8,7 +8,6 @@ import GameManager from "#test/utils/gameManager";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - BATTLE BOND", () => {
|
describe("Abilities - BATTLE BOND", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -9,7 +9,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - COSTAR", () => {
|
describe("Abilities - COSTAR", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -8,7 +8,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - Dancer", () => {
|
describe("Abilities - Dancer", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -8,7 +8,6 @@ import GameManager from "#test/utils/gameManager";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - Disguise", () => {
|
describe("Abilities - Disguise", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -10,7 +10,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - Galvanize", () => {
|
describe("Abilities - Galvanize", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -13,7 +13,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - Libero", () => {
|
describe("Abilities - Libero", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -11,7 +11,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - Parental Bond", () => {
|
describe("Abilities - Parental Bond", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -8,7 +8,6 @@ import GameManager from "#test/utils/gameManager";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - POWER CONSTRUCT", () => {
|
describe("Abilities - POWER CONSTRUCT", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -13,7 +13,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - Protean", () => {
|
describe("Abilities - Protean", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -12,7 +12,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - Sand Veil", () => {
|
describe("Abilities - Sand Veil", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -8,7 +8,6 @@ import GameManager from "#test/utils/gameManager";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - SCHOOLING", () => {
|
describe("Abilities - SCHOOLING", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -8,7 +8,6 @@ import GameManager from "#test/utils/gameManager";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - SHIELDS DOWN", () => {
|
describe("Abilities - SHIELDS DOWN", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -9,7 +9,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - Sturdy", () => {
|
describe("Abilities - Sturdy", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -9,7 +9,6 @@ import { BattlerTagType } from "#app/enums/battler-tag-type";
|
|||||||
import { BerryPhase } from "#app/phases/berry-phase";
|
import { BerryPhase } from "#app/phases/berry-phase";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - Unseen Fist", () => {
|
describe("Abilities - Unseen Fist", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -21,7 +21,6 @@ import { Status, StatusEffect } from "#app/data/status-effect";
|
|||||||
import { SwitchType } from "#enums/switch-type";
|
import { SwitchType } from "#enums/switch-type";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - ZEN MODE", () => {
|
describe("Abilities - ZEN MODE", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -8,7 +8,6 @@ import GameManager from "#test/utils/gameManager";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Abilities - ZERO TO HERO", () => {
|
describe("Abilities - ZERO TO HERO", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -11,7 +11,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Inverse Battle", () => {
|
describe("Inverse Battle", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -3,9 +3,10 @@ import { Moves } from "#app/enums/moves";
|
|||||||
import { MapModifier } from "#app/modifier/modifier";
|
import { MapModifier } from "#app/modifier/modifier";
|
||||||
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
|
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
|
||||||
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
|
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
import { Mode } from "#app/ui/ui";
|
import { Mode } from "#app/ui/ui";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import GameManager from "./utils/gameManager";
|
import GameManager from "#app/test/utils/gameManager";
|
||||||
|
|
||||||
//const TIMEOUT = 20 * 1000;
|
//const TIMEOUT = 20 * 1000;
|
||||||
|
|
||||||
@ -55,12 +56,11 @@ describe("Shop modifications", async () => {
|
|||||||
|
|
||||||
game.override
|
game.override
|
||||||
.startingWave(9)
|
.startingWave(9)
|
||||||
.startingBiome(Biome.ICE_CAVE) // Will lead to Snowy Forest with randomly generated weather
|
.startingBiome(Biome.ICE_CAVE)
|
||||||
.battleType("single")
|
.battleType("single")
|
||||||
.startingLevel(100) // Avoid levelling up
|
.startingLevel(100) // Avoid levelling up
|
||||||
.enemyLevel(1000) // Avoid opponent dying before game.doKillOpponents()
|
|
||||||
.disableTrainerWaves()
|
.disableTrainerWaves()
|
||||||
.moveset([Moves.KOWTOW_CLEAVE])
|
.moveset([ Moves.SPLASH ])
|
||||||
.enemyMoveset(Moves.SPLASH);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
game.modifiers
|
game.modifiers
|
||||||
.addCheck("EVIOLITE")
|
.addCheck("EVIOLITE")
|
||||||
@ -74,9 +74,8 @@ describe("Shop modifications", async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should not have Eviolite and Mini Black Hole available in Classic if not unlocked", async () => {
|
it("should not have Eviolite and Mini Black Hole available in Classic if not unlocked", async () => {
|
||||||
await game.classicMode.startBattle();
|
await game.classicMode.startBattle([ Species.BULBASAUR ]);
|
||||||
game.move.select(Moves.KOWTOW_CLEAVE);
|
game.move.select(Moves.SPLASH);
|
||||||
await game.phaseInterceptor.to("DamagePhase");
|
|
||||||
await game.doKillOpponents();
|
await game.doKillOpponents();
|
||||||
await game.phaseInterceptor.to("BattleEndPhase");
|
await game.phaseInterceptor.to("BattleEndPhase");
|
||||||
game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => {
|
game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => {
|
||||||
@ -89,8 +88,7 @@ describe("Shop modifications", async () => {
|
|||||||
|
|
||||||
it("should have Eviolite and Mini Black Hole available in Daily", async () => {
|
it("should have Eviolite and Mini Black Hole available in Daily", async () => {
|
||||||
await game.dailyMode.startBattle();
|
await game.dailyMode.startBattle();
|
||||||
game.move.select(Moves.KOWTOW_CLEAVE);
|
game.move.select(Moves.SPLASH);
|
||||||
await game.phaseInterceptor.to("DamagePhase");
|
|
||||||
await game.doKillOpponents();
|
await game.doKillOpponents();
|
||||||
await game.phaseInterceptor.to("BattleEndPhase");
|
await game.phaseInterceptor.to("BattleEndPhase");
|
||||||
game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => {
|
game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => {
|
||||||
|
@ -9,7 +9,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - After You", () => {
|
describe("Moves - After You", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -9,7 +9,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Alluring Voice", () => {
|
describe("Moves - Alluring Voice", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -12,7 +12,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Astonish", () => {
|
describe("Moves - Astonish", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -8,7 +8,6 @@ import { BattlerIndex } from "#app/battle";
|
|||||||
import { StatusEffect } from "#app/enums/status-effect";
|
import { StatusEffect } from "#app/enums/status-effect";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Baneful Bunker", () => {
|
describe("Moves - Baneful Bunker", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -11,7 +11,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Beak Blast", () => {
|
describe("Moves - Beak Blast", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -9,7 +9,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Burning Jealousy", () => {
|
describe("Moves - Burning Jealousy", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -11,7 +11,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Ceaseless Edge", () => {
|
describe("Moves - Ceaseless Edge", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -10,7 +10,6 @@ import { BerryPhase } from "#app/phases/berry-phase";
|
|||||||
import { CommandPhase } from "#app/phases/command-phase";
|
import { CommandPhase } from "#app/phases/command-phase";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Crafty Shield", () => {
|
describe("Moves - Crafty Shield", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
46
src/test/moves/diamond_storm.test.ts
Normal file
46
src/test/moves/diamond_storm.test.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { allMoves } from "#app/data/move";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import { Stat } from "#enums/stat";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Diamond Storm", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.moveset([ Moves.DIAMOND_STORM ])
|
||||||
|
.battleType("single")
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should only increase defense once even if hitting 2 pokemon", async () => {
|
||||||
|
game.override.battleType("double");
|
||||||
|
const diamondStorm = allMoves[Moves.DIAMOND_STORM];
|
||||||
|
vi.spyOn(diamondStorm, "chance", "get").mockReturnValue(100);
|
||||||
|
vi.spyOn(diamondStorm, "accuracy", "get").mockReturnValue(100);
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.DIAMOND_STORM);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getPlayerPokemon()!.getStatStage(Stat.DEF)).toBe(2);
|
||||||
|
});
|
||||||
|
});
|
69
src/test/moves/electrify.test.ts
Normal file
69
src/test/moves/electrify.test.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { Type } from "#app/data/type";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, it, expect, vi } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Electrify", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.moveset(Moves.ELECTRIFY)
|
||||||
|
.battleType("single")
|
||||||
|
.startingLevel(100)
|
||||||
|
.enemySpecies(Species.SNORLAX)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.TACKLE)
|
||||||
|
.enemyLevel(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should convert attacks to Electric type", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.EXCADRILL ]);
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
vi.spyOn(enemyPokemon, "getMoveType");
|
||||||
|
|
||||||
|
game.move.select(Moves.ELECTRIFY);
|
||||||
|
|
||||||
|
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
expect(enemyPokemon.getMoveType).toHaveLastReturnedWith(Type.ELECTRIC);
|
||||||
|
expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should override type changes from abilities", async () => {
|
||||||
|
game.override.enemyAbility(Abilities.PIXILATE);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([ Species.EXCADRILL ]);
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
const enemyPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
vi.spyOn(enemyPokemon, "getMoveType");
|
||||||
|
|
||||||
|
game.move.select(Moves.ELECTRIFY);
|
||||||
|
|
||||||
|
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
expect(enemyPokemon.getMoveType).toHaveLastReturnedWith(Type.ELECTRIC);
|
||||||
|
expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp());
|
||||||
|
});
|
||||||
|
});
|
@ -11,7 +11,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Focus Punch", () => {
|
describe("Moves - Focus Punch", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -9,7 +9,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Follow Me", () => {
|
describe("Moves - Follow Me", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -7,7 +7,6 @@ import GameManager from "#test/utils/gameManager";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Gastro Acid", () => {
|
describe("Moves - Gastro Acid", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -7,7 +7,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Glaive Rush", () => {
|
describe("Moves - Glaive Rush", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -12,7 +12,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Jaw Lock", () => {
|
describe("Moves - Jaw Lock", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -8,7 +8,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Lash Out", () => {
|
describe("Moves - Lash Out", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -8,7 +8,6 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
|||||||
import GameManager from "../utils/gameManager";
|
import GameManager from "../utils/gameManager";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Lucky Chant", () => {
|
describe("Moves - Lucky Chant", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -9,7 +9,6 @@ import { MoveEndPhase } from "#app/phases/move-end-phase";
|
|||||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Make It Rain", () => {
|
describe("Moves - Make It Rain", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -10,7 +10,6 @@ import { CommandPhase } from "#app/phases/command-phase";
|
|||||||
import { TurnEndPhase } from "#app/phases/turn-end-phase";
|
import { TurnEndPhase } from "#app/phases/turn-end-phase";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Mat Block", () => {
|
describe("Moves - Mat Block", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -8,7 +8,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Multi-target damage reduction", () => {
|
describe("Multi-target damage reduction", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -11,7 +11,6 @@ import { MessagePhase } from "#app/phases/message-phase";
|
|||||||
import { TurnInitPhase } from "#app/phases/turn-init-phase";
|
import { TurnInitPhase } from "#app/phases/turn-init-phase";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Parting Shot", () => {
|
describe("Moves - Parting Shot", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
337
src/test/moves/pledge_moves.test.ts
Normal file
337
src/test/moves/pledge_moves.test.ts
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { allAbilities } from "#app/data/ability";
|
||||||
|
import { ArenaTagSide } from "#app/data/arena-tag";
|
||||||
|
import { allMoves, FlinchAttr } from "#app/data/move";
|
||||||
|
import { Type } from "#app/data/type";
|
||||||
|
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||||
|
import { Stat } from "#enums/stat";
|
||||||
|
import { toDmgValue } from "#app/utils";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, it, expect, vi } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Pledge Moves", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.battleType("double")
|
||||||
|
.startingLevel(100)
|
||||||
|
.moveset([ Moves.FIRE_PLEDGE, Moves.GRASS_PLEDGE, Moves.WATER_PLEDGE, Moves.SPLASH ])
|
||||||
|
.enemySpecies(Species.SNORLAX)
|
||||||
|
.enemyLevel(100)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(
|
||||||
|
"Fire Pledge - should be an 80-power Fire-type attack outside of combination",
|
||||||
|
async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.BLASTOISE, Species.CHARIZARD ]);
|
||||||
|
|
||||||
|
const firePledge = allMoves[Moves.FIRE_PLEDGE];
|
||||||
|
vi.spyOn(firePledge, "calculateBattlePower");
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerField();
|
||||||
|
vi.spyOn(playerPokemon[0], "getMoveType");
|
||||||
|
|
||||||
|
game.move.select(Moves.FIRE_PLEDGE, 0, BattlerIndex.ENEMY);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
|
||||||
|
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase", false);
|
||||||
|
|
||||||
|
expect(firePledge.calculateBattlePower).toHaveLastReturnedWith(80);
|
||||||
|
expect(playerPokemon[0].getMoveType).toHaveLastReturnedWith(Type.FIRE);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"Fire Pledge - should not combine with an ally using Fire Pledge",
|
||||||
|
async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.BLASTOISE, Species.CHARIZARD ]);
|
||||||
|
|
||||||
|
const firePledge = allMoves[Moves.FIRE_PLEDGE];
|
||||||
|
vi.spyOn(firePledge, "calculateBattlePower");
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerField();
|
||||||
|
playerPokemon.forEach(p => vi.spyOn(p, "getMoveType"));
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyField();
|
||||||
|
|
||||||
|
game.move.select(Moves.FIRE_PLEDGE, 0, BattlerIndex.ENEMY);
|
||||||
|
game.move.select(Moves.FIRE_PLEDGE, 0, BattlerIndex.ENEMY_2);
|
||||||
|
|
||||||
|
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
expect(firePledge.calculateBattlePower).toHaveLastReturnedWith(80);
|
||||||
|
expect(playerPokemon[0].getMoveType).toHaveLastReturnedWith(Type.FIRE);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
expect(firePledge.calculateBattlePower).toHaveLastReturnedWith(80);
|
||||||
|
expect(playerPokemon[1].getMoveType).toHaveLastReturnedWith(Type.FIRE);
|
||||||
|
|
||||||
|
enemyPokemon.forEach(p => expect(p.hp).toBeLessThan(p.getMaxHp()));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"Fire Pledge - should not combine with an enemy's Pledge move",
|
||||||
|
async () => {
|
||||||
|
game.override
|
||||||
|
.battleType("single")
|
||||||
|
.enemyMoveset(Moves.GRASS_PLEDGE);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([ Species.CHARIZARD ]);
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
game.move.select(Moves.FIRE_PLEDGE);
|
||||||
|
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
// Neither Pokemon should defer their move's effects as they would
|
||||||
|
// if they combined moves, so both should be damaged.
|
||||||
|
expect(playerPokemon.hp).toBeLessThan(playerPokemon.getMaxHp());
|
||||||
|
expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp());
|
||||||
|
expect(game.scene.arena.getTag(ArenaTagType.FIRE_GRASS_PLEDGE)).toBeUndefined();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"Grass Pledge - should combine with Fire Pledge to form a 150-power Fire-type attack that creates a 'sea of fire'",
|
||||||
|
async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.CHARIZARD, Species.BLASTOISE ]);
|
||||||
|
|
||||||
|
const grassPledge = allMoves[Moves.GRASS_PLEDGE];
|
||||||
|
vi.spyOn(grassPledge, "calculateBattlePower");
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerField();
|
||||||
|
const enemyPokemon = game.scene.getEnemyField();
|
||||||
|
|
||||||
|
vi.spyOn(playerPokemon[1], "getMoveType");
|
||||||
|
const baseDmgMock = vi.spyOn(enemyPokemon[0], "getBaseDamage");
|
||||||
|
|
||||||
|
game.move.select(Moves.FIRE_PLEDGE, 0, BattlerIndex.ENEMY_2);
|
||||||
|
game.move.select(Moves.GRASS_PLEDGE, 1, BattlerIndex.ENEMY);
|
||||||
|
|
||||||
|
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
|
||||||
|
// advance to the end of PLAYER_2's move this turn
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
}
|
||||||
|
expect(playerPokemon[1].getMoveType).toHaveLastReturnedWith(Type.FIRE);
|
||||||
|
expect(grassPledge.calculateBattlePower).toHaveLastReturnedWith(150);
|
||||||
|
|
||||||
|
const baseDmg = baseDmgMock.mock.results[baseDmgMock.mock.results.length - 1].value;
|
||||||
|
expect(enemyPokemon[0].getMaxHp() - enemyPokemon[0].hp).toBe(toDmgValue(baseDmg * 1.5));
|
||||||
|
expect(enemyPokemon[1].hp).toBe(enemyPokemon[1].getMaxHp()); // PLAYER should not have attacked
|
||||||
|
expect(game.scene.arena.getTagOnSide(ArenaTagType.FIRE_GRASS_PLEDGE, ArenaTagSide.ENEMY)).toBeDefined();
|
||||||
|
|
||||||
|
const enemyStartingHp = enemyPokemon.map(p => p.hp);
|
||||||
|
await game.toNextTurn();
|
||||||
|
enemyPokemon.forEach((p, i) => expect(enemyStartingHp[i] - p.hp).toBe(toDmgValue(p.getMaxHp() / 8)));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"Fire Pledge - should combine with Water Pledge to form a 150-power Water-type attack that creates a 'rainbow'",
|
||||||
|
async () => {
|
||||||
|
game.override.moveset([ Moves.FIRE_PLEDGE, Moves.WATER_PLEDGE, Moves.FIERY_DANCE, Moves.SPLASH ]);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([ Species.BLASTOISE, Species.VENUSAUR ]);
|
||||||
|
|
||||||
|
const firePledge = allMoves[Moves.FIRE_PLEDGE];
|
||||||
|
vi.spyOn(firePledge, "calculateBattlePower");
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerField();
|
||||||
|
const enemyPokemon = game.scene.getEnemyField();
|
||||||
|
|
||||||
|
vi.spyOn(playerPokemon[1], "getMoveType");
|
||||||
|
|
||||||
|
game.move.select(Moves.WATER_PLEDGE, 0, BattlerIndex.ENEMY_2);
|
||||||
|
game.move.select(Moves.FIRE_PLEDGE, 1, BattlerIndex.ENEMY);
|
||||||
|
|
||||||
|
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
|
||||||
|
// advance to the end of PLAYER_2's move this turn
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
}
|
||||||
|
expect(playerPokemon[1].getMoveType).toHaveLastReturnedWith(Type.WATER);
|
||||||
|
expect(firePledge.calculateBattlePower).toHaveLastReturnedWith(150);
|
||||||
|
expect(enemyPokemon[1].hp).toBe(enemyPokemon[1].getMaxHp()); // PLAYER should not have attacked
|
||||||
|
expect(game.scene.arena.getTagOnSide(ArenaTagType.WATER_FIRE_PLEDGE, ArenaTagSide.PLAYER)).toBeDefined();
|
||||||
|
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
game.move.select(Moves.FIERY_DANCE, 0, BattlerIndex.ENEMY_2);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
|
||||||
|
// Rainbow effect should increase Fiery Dance's chance of raising Sp. Atk to 100%
|
||||||
|
expect(playerPokemon[0].getStatStage(Stat.SPATK)).toBe(1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"Water Pledge - should combine with Grass Pledge to form a 150-power Grass-type attack that creates a 'swamp'",
|
||||||
|
async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.BLASTOISE, Species.CHARIZARD ]);
|
||||||
|
|
||||||
|
const waterPledge = allMoves[Moves.WATER_PLEDGE];
|
||||||
|
vi.spyOn(waterPledge, "calculateBattlePower");
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerField();
|
||||||
|
const enemyPokemon = game.scene.getEnemyField();
|
||||||
|
const enemyStartingSpd = enemyPokemon.map(p => p.getEffectiveStat(Stat.SPD));
|
||||||
|
|
||||||
|
vi.spyOn(playerPokemon[1], "getMoveType");
|
||||||
|
|
||||||
|
game.move.select(Moves.GRASS_PLEDGE, 0, BattlerIndex.ENEMY_2);
|
||||||
|
game.move.select(Moves.WATER_PLEDGE, 1, BattlerIndex.ENEMY);
|
||||||
|
|
||||||
|
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
|
||||||
|
// advance to the end of PLAYER_2's move this turn
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(playerPokemon[1].getMoveType).toHaveLastReturnedWith(Type.GRASS);
|
||||||
|
expect(waterPledge.calculateBattlePower).toHaveLastReturnedWith(150);
|
||||||
|
expect(enemyPokemon[1].hp).toBe(enemyPokemon[1].getMaxHp());
|
||||||
|
|
||||||
|
expect(game.scene.arena.getTagOnSide(ArenaTagType.GRASS_WATER_PLEDGE, ArenaTagSide.ENEMY)).toBeDefined();
|
||||||
|
enemyPokemon.forEach((p, i) => expect(p.getEffectiveStat(Stat.SPD)).toBe(Math.floor(enemyStartingSpd[i] / 4)));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"Pledge Moves - should alter turn order when used in combination",
|
||||||
|
async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.CHARIZARD, Species.BLASTOISE ]);
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyField();
|
||||||
|
|
||||||
|
game.move.select(Moves.WATER_PLEDGE, 0, BattlerIndex.ENEMY);
|
||||||
|
game.move.select(Moves.FIRE_PLEDGE, 1, BattlerIndex.ENEMY_2);
|
||||||
|
|
||||||
|
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2 ]);
|
||||||
|
// PLAYER_2 should act with a combined move immediately after PLAYER as the second move in the turn
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
}
|
||||||
|
expect(enemyPokemon[0].hp).toBe(enemyPokemon[0].getMaxHp());
|
||||||
|
expect(enemyPokemon[1].hp).toBeLessThan(enemyPokemon[1].getMaxHp());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"Pledge Moves - 'rainbow' effect should not stack with Serene Grace when applied to flinching moves",
|
||||||
|
async () => {
|
||||||
|
game.override
|
||||||
|
.ability(Abilities.SERENE_GRACE)
|
||||||
|
.moveset([ Moves.FIRE_PLEDGE, Moves.WATER_PLEDGE, Moves.IRON_HEAD, Moves.SPLASH ]);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([ Species.BLASTOISE, Species.CHARIZARD ]);
|
||||||
|
|
||||||
|
const ironHeadFlinchAttr = allMoves[Moves.IRON_HEAD].getAttrs(FlinchAttr)[0];
|
||||||
|
vi.spyOn(ironHeadFlinchAttr, "getMoveChance");
|
||||||
|
|
||||||
|
game.move.select(Moves.WATER_PLEDGE, 0, BattlerIndex.ENEMY);
|
||||||
|
game.move.select(Moves.FIRE_PLEDGE, 1, BattlerIndex.ENEMY_2);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(game.scene.arena.getTagOnSide(ArenaTagType.WATER_FIRE_PLEDGE, ArenaTagSide.PLAYER)).toBeDefined();
|
||||||
|
|
||||||
|
game.move.select(Moves.IRON_HEAD, 0, BattlerIndex.ENEMY);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
|
||||||
|
expect(ironHeadFlinchAttr.getMoveChance).toHaveLastReturnedWith(60);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"Pledge Moves - should have no effect when the second ally's move is cancelled",
|
||||||
|
async () => {
|
||||||
|
game.override
|
||||||
|
.enemyMoveset([ Moves.SPLASH, Moves.SPORE ]);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([ Species.BLASTOISE, Species.CHARIZARD ]);
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyField();
|
||||||
|
|
||||||
|
game.move.select(Moves.FIRE_PLEDGE, 0, BattlerIndex.ENEMY);
|
||||||
|
game.move.select(Moves.GRASS_PLEDGE, 1, BattlerIndex.ENEMY_2);
|
||||||
|
|
||||||
|
await game.forceEnemyMove(Moves.SPORE, BattlerIndex.PLAYER_2);
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
|
||||||
|
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2 ]);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
|
||||||
|
enemyPokemon.forEach((p) => expect(p.hp).toBe(p.getMaxHp()));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"Pledge Moves - should ignore redirection from another Pokemon's Storm Drain",
|
||||||
|
async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.BLASTOISE, Species.CHARIZARD ]);
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyField();
|
||||||
|
vi.spyOn(enemyPokemon[1], "getAbility").mockReturnValue(allAbilities[Abilities.STORM_DRAIN]);
|
||||||
|
|
||||||
|
game.move.select(Moves.WATER_PLEDGE, 0, BattlerIndex.ENEMY);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
|
||||||
|
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase", false);
|
||||||
|
|
||||||
|
expect(enemyPokemon[0].hp).toBeLessThan(enemyPokemon[0].getMaxHp());
|
||||||
|
expect(enemyPokemon[1].getStatStage(Stat.SPATK)).toBe(0);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"Pledge Moves - should not ignore redirection from another Pokemon's Follow Me",
|
||||||
|
async () => {
|
||||||
|
game.override.enemyMoveset([ Moves.FOLLOW_ME, Moves.SPLASH ]);
|
||||||
|
await game.classicMode.startBattle([ Species.BLASTOISE, Species.CHARIZARD ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.WATER_PLEDGE, 0, BattlerIndex.ENEMY);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
await game.forceEnemyMove(Moves.FOLLOW_ME);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyField();
|
||||||
|
expect(enemyPokemon[0].hp).toBe(enemyPokemon[0].getMaxHp());
|
||||||
|
expect(enemyPokemon[1].hp).toBeLessThan(enemyPokemon[1].getMaxHp());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
@ -11,7 +11,6 @@ import { BattlerIndex } from "#app/battle";
|
|||||||
import { MoveResult } from "#app/field/pokemon";
|
import { MoveResult } from "#app/field/pokemon";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Protect", () => {
|
describe("Moves - Protect", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -9,7 +9,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Purify", () => {
|
describe("Moves - Purify", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -9,7 +9,6 @@ import { BattlerIndex } from "#app/battle";
|
|||||||
import { MoveResult } from "#app/field/pokemon";
|
import { MoveResult } from "#app/field/pokemon";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Quick Guard", () => {
|
describe("Moves - Quick Guard", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -7,7 +7,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Rage Powder", () => {
|
describe("Moves - Rage Powder", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -10,7 +10,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Roost", () => {
|
describe("Moves - Roost", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -9,7 +9,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Safeguard", () => {
|
describe("Moves - Safeguard", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -11,7 +11,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Shell Trap", () => {
|
describe("Moves - Shell Trap", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -7,7 +7,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Spotlight", () => {
|
describe("Moves - Spotlight", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
98
src/test/moves/tera_starstorm.test.ts
Normal file
98
src/test/moves/tera_starstorm.test.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { Type } from "#app/data/type";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, it, expect, vi } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Tera Starstorm", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.moveset([ Moves.TERA_STARSTORM, Moves.SPLASH ])
|
||||||
|
.battleType("double")
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.SPLASH)
|
||||||
|
.enemyLevel(30)
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.startingHeldItems([{ name: "TERA_SHARD", type: Type.FIRE }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("changes type to Stellar when used by Terapagos in its Stellar Form", async () => {
|
||||||
|
game.override.battleType("single");
|
||||||
|
await game.classicMode.startBattle([ Species.TERAPAGOS ]);
|
||||||
|
|
||||||
|
const terapagos = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
|
vi.spyOn(terapagos, "getMoveType");
|
||||||
|
|
||||||
|
game.move.select(Moves.TERA_STARSTORM);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(terapagos.isTerastallized()).toBe(true);
|
||||||
|
expect(terapagos.getMoveType).toHaveReturnedWith(Type.STELLAR);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("targets both opponents in a double battle when used by Terapagos in its Stellar Form", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.MAGIKARP, Species.TERAPAGOS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.TERA_STARSTORM, 0, BattlerIndex.ENEMY);
|
||||||
|
game.move.select(Moves.TERA_STARSTORM, 1);
|
||||||
|
|
||||||
|
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]);
|
||||||
|
|
||||||
|
const enemyField = game.scene.getEnemyField();
|
||||||
|
|
||||||
|
// Pokemon other than Terapagos should not be affected - only hits one target
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
expect(enemyField.some(pokemon => pokemon.isFullHp())).toBe(true);
|
||||||
|
|
||||||
|
// Terapagos in Stellar Form should hit both targets
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
expect(enemyField.every(pokemon => pokemon.isFullHp())).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("applies the effects when Terapagos in Stellar Form is fused with another Pokemon", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.TERAPAGOS, Species.CHARMANDER, Species.MAGIKARP ]);
|
||||||
|
|
||||||
|
const fusionedMon = game.scene.getParty()[0];
|
||||||
|
const magikarp = game.scene.getParty()[2];
|
||||||
|
|
||||||
|
// Fuse party members (taken from PlayerPokemon.fuse(...) function)
|
||||||
|
fusionedMon.fusionSpecies = magikarp.species;
|
||||||
|
fusionedMon.fusionFormIndex = magikarp.formIndex;
|
||||||
|
fusionedMon.fusionAbilityIndex = magikarp.abilityIndex;
|
||||||
|
fusionedMon.fusionShiny = magikarp.shiny;
|
||||||
|
fusionedMon.fusionVariant = magikarp.variant;
|
||||||
|
fusionedMon.fusionGender = magikarp.gender;
|
||||||
|
fusionedMon.fusionLuck = magikarp.luck;
|
||||||
|
|
||||||
|
vi.spyOn(fusionedMon, "getMoveType");
|
||||||
|
|
||||||
|
game.move.select(Moves.TERA_STARSTORM, 0);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
// Fusion and terastallized
|
||||||
|
expect(fusionedMon.isFusion()).toBe(true);
|
||||||
|
expect(fusionedMon.isTerastallized()).toBe(true);
|
||||||
|
// Move effects should be applied
|
||||||
|
expect(fusionedMon.getMoveType).toHaveReturnedWith(Type.STELLAR);
|
||||||
|
expect(game.scene.getEnemyField().every(pokemon => pokemon.isFullHp())).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
@ -9,7 +9,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Thousand Arrows", () => {
|
describe("Moves - Thousand Arrows", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -8,7 +8,6 @@ import Phaser from "phaser";
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Thunder Wave", () => {
|
describe("Moves - Thunder Wave", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -73,4 +73,17 @@ describe("Moves - Toxic", () => {
|
|||||||
|
|
||||||
expect(game.scene.getEnemyPokemon()!.status).toBeUndefined();
|
expect(game.scene.getEnemyPokemon()!.status).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("moves other than Toxic should not hit semi-invulnerable targets even if user is Poison-type", async () => {
|
||||||
|
game.override.moveset(Moves.SWIFT);
|
||||||
|
game.override.enemyMoveset(Moves.FLY);
|
||||||
|
await game.classicMode.startBattle([ Species.TOXAPEX ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SWIFT);
|
||||||
|
await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import { BattlerIndex } from "#app/battle";
|
|
||||||
import { allMoves } from "#app/data/move";
|
|
||||||
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
||||||
|
import { MoveResult } from "#app/field/pokemon";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, it, expect, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
describe("Moves - Whirlwind", () => {
|
describe("Moves - Whirlwind", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
@ -40,14 +39,11 @@ describe("Moves - Whirlwind", () => {
|
|||||||
await game.classicMode.startBattle([ Species.STARAPTOR ]);
|
await game.classicMode.startBattle([ Species.STARAPTOR ]);
|
||||||
|
|
||||||
const staraptor = game.scene.getPlayerPokemon()!;
|
const staraptor = game.scene.getPlayerPokemon()!;
|
||||||
const whirlwind = allMoves[Moves.WHIRLWIND];
|
|
||||||
vi.spyOn(whirlwind, "getFailedText");
|
|
||||||
|
|
||||||
game.move.select(move);
|
game.move.select(move);
|
||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
|
||||||
await game.toNextTurn();
|
await game.toNextTurn();
|
||||||
|
|
||||||
expect(staraptor.findTag((t) => t.tagType === BattlerTagType.FLYING)).toBeDefined();
|
expect(staraptor.findTag((t) => t.tagType === BattlerTagType.FLYING)).toBeDefined();
|
||||||
expect(whirlwind.getFailedText).toHaveBeenCalledOnce();
|
expect(game.scene.getEnemyPokemon()!.getLastXMoves(1)[0].result).toBe(MoveResult.MISS);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,6 @@ import { BerryPhase } from "#app/phases/berry-phase";
|
|||||||
import { CommandPhase } from "#app/phases/command-phase";
|
import { CommandPhase } from "#app/phases/command-phase";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe("Moves - Wide Guard", () => {
|
describe("Moves - Wide Guard", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
@ -47,15 +47,13 @@ describe("Reload", () => {
|
|||||||
.startingWave(10)
|
.startingWave(10)
|
||||||
.battleType("single")
|
.battleType("single")
|
||||||
.startingLevel(100) // Avoid levelling up
|
.startingLevel(100) // Avoid levelling up
|
||||||
.enemyLevel(1000) // Avoid opponent dying before game.doKillOpponents()
|
|
||||||
.disableTrainerWaves()
|
.disableTrainerWaves()
|
||||||
.moveset([Moves.KOWTOW_CLEAVE])
|
.moveset([ Moves.SPLASH ])
|
||||||
.enemyMoveset(Moves.SPLASH);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
await game.dailyMode.startBattle();
|
await game.dailyMode.startBattle();
|
||||||
|
|
||||||
// Transition from Wave 10 to Wave 11 in order to trigger biome switch
|
// Transition from Wave 10 to Wave 11 in order to trigger biome switch
|
||||||
game.move.select(Moves.KOWTOW_CLEAVE);
|
game.move.select(Moves.SPLASH);
|
||||||
await game.phaseInterceptor.to("DamagePhase");
|
|
||||||
await game.doKillOpponents();
|
await game.doKillOpponents();
|
||||||
game.onNextPrompt("SelectBiomePhase", Mode.OPTION_SELECT, () => {
|
game.onNextPrompt("SelectBiomePhase", Mode.OPTION_SELECT, () => {
|
||||||
(game.scene.time as MockClock).overrideDelay = null;
|
(game.scene.time as MockClock).overrideDelay = null;
|
||||||
@ -82,15 +80,13 @@ describe("Reload", () => {
|
|||||||
.startingBiome(Biome.ICE_CAVE) // Will lead to Snowy Forest with randomly generated weather
|
.startingBiome(Biome.ICE_CAVE) // Will lead to Snowy Forest with randomly generated weather
|
||||||
.battleType("single")
|
.battleType("single")
|
||||||
.startingLevel(100) // Avoid levelling up
|
.startingLevel(100) // Avoid levelling up
|
||||||
.enemyLevel(1000) // Avoid opponent dying before game.doKillOpponents()
|
|
||||||
.disableTrainerWaves()
|
.disableTrainerWaves()
|
||||||
.moveset([Moves.KOWTOW_CLEAVE])
|
.moveset([ Moves.SPLASH ])
|
||||||
.enemyMoveset(Moves.SPLASH);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
await game.classicMode.startBattle(); // Apparently daily mode would override the biome
|
await game.classicMode.startBattle(); // Apparently daily mode would override the biome
|
||||||
|
|
||||||
// Transition from Wave 10 to Wave 11 in order to trigger biome switch
|
// Transition from Wave 10 to Wave 11 in order to trigger biome switch
|
||||||
game.move.select(Moves.KOWTOW_CLEAVE);
|
game.move.select(Moves.SPLASH);
|
||||||
await game.phaseInterceptor.to("DamagePhase");
|
|
||||||
await game.doKillOpponents();
|
await game.doKillOpponents();
|
||||||
await game.toNextWave();
|
await game.toNextWave();
|
||||||
expect(game.phaseInterceptor.log).toContain("NewBiomeEncounterPhase");
|
expect(game.phaseInterceptor.log).toContain("NewBiomeEncounterPhase");
|
||||||
|
@ -85,6 +85,27 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the player (pokemon) to be a random fusion
|
||||||
|
* @returns this
|
||||||
|
*/
|
||||||
|
enableStarterFusion(): this {
|
||||||
|
vi.spyOn(Overrides, "STARTER_FUSION_OVERRIDE", "get").mockReturnValue(true);
|
||||||
|
this.log("Player Pokemon is a random fusion!");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the player (pokemon) fusion species
|
||||||
|
* @param species the fusion species to set
|
||||||
|
* @returns this
|
||||||
|
*/
|
||||||
|
starterFusionSpecies(species: Species | number): this {
|
||||||
|
vi.spyOn(Overrides, "STARTER_FUSION_SPECIES_OVERRIDE", "get").mockReturnValue(species);
|
||||||
|
this.log(`Player Pokemon fusion species set to ${Species[species]} (=${species})!`);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override the player (pokemons) forms
|
* Override the player (pokemons) forms
|
||||||
* @param forms the (pokemon) forms to set
|
* @param forms the (pokemon) forms to set
|
||||||
@ -232,6 +253,27 @@ export class OverridesHelper extends GameManagerHelper {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the enemy (pokemon) to be a random fusion
|
||||||
|
* @returns this
|
||||||
|
*/
|
||||||
|
enableEnemyFusion(): this {
|
||||||
|
vi.spyOn(Overrides, "OPP_FUSION_OVERRIDE", "get").mockReturnValue(true);
|
||||||
|
this.log("Enemy Pokemon is a random fusion!");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the enemy (pokemon) fusion species
|
||||||
|
* @param species the fusion species to set
|
||||||
|
* @returns this
|
||||||
|
*/
|
||||||
|
enemyFusionSpecies(species: Species | number): this {
|
||||||
|
vi.spyOn(Overrides, "OPP_FUSION_SPECIES_OVERRIDE", "get").mockReturnValue(species);
|
||||||
|
this.log(`Enemy Pokemon fusion species set to ${Species[species]} (=${species})!`);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override the enemy (pokemon) {@linkcode Abilities | ability}
|
* Override the enemy (pokemon) {@linkcode Abilities | ability}
|
||||||
* @param ability the (pokemon) {@linkcode Abilities | ability} to set
|
* @param ability the (pokemon) {@linkcode Abilities | ability} to set
|
||||||
|
@ -212,5 +212,4 @@ export default class MockSprite implements MockGameObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,6 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Clears out the current string stored in all arena effect texts */
|
/** Clears out the current string stored in all arena effect texts */
|
||||||
private clearText() {
|
private clearText() {
|
||||||
this.flyoutTextPlayer.text = "";
|
this.flyoutTextPlayer.text = "";
|
||||||
|
@ -6,7 +6,6 @@ export const TOUCH_CONTROL_POSITIONS_LANDSCAPE = "touchControlPositionsLandscape
|
|||||||
export const TOUCH_CONTROL_POSITIONS_PORTRAIT = "touchControlPositionsPortrait";
|
export const TOUCH_CONTROL_POSITIONS_PORTRAIT = "touchControlPositionsPortrait";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
type ControlPosition = { id: string, x: number, y: number };
|
type ControlPosition = { id: string, x: number, y: number };
|
||||||
|
|
||||||
type ConfigurationEventListeners = {
|
type ConfigurationEventListeners = {
|
||||||
|
@ -77,7 +77,6 @@ export default class SettingsKeyboardUiHandler extends AbstractControlSettingsUi
|
|||||||
this.settingsContainer.add(deleteText);
|
this.settingsContainer.add(deleteText);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Map the 'noKeyboard' layout options for easy access.
|
// Map the 'noKeyboard' layout options for easy access.
|
||||||
this.layout["noKeyboard"].optionsContainer = optionsContainer;
|
this.layout["noKeyboard"].optionsContainer = optionsContainer;
|
||||||
this.layout["noKeyboard"].label = label;
|
this.layout["noKeyboard"].label = label;
|
||||||
|
@ -308,13 +308,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
private starterIconsCursorObj: Phaser.GameObjects.Image;
|
private starterIconsCursorObj: Phaser.GameObjects.Image;
|
||||||
private valueLimitLabel: Phaser.GameObjects.Text;
|
private valueLimitLabel: Phaser.GameObjects.Text;
|
||||||
private startCursorObj: Phaser.GameObjects.NineSlice;
|
private startCursorObj: Phaser.GameObjects.NineSlice;
|
||||||
// private starterValueLabels: Phaser.GameObjects.Text[];
|
|
||||||
// private shinyIcons: Phaser.GameObjects.Image[][];
|
|
||||||
// private hiddenAbilityIcons: Phaser.GameObjects.Image[];
|
|
||||||
// private classicWinIcons: Phaser.GameObjects.Image[];
|
|
||||||
// private candyUpgradeIcon: Phaser.GameObjects.Image[];
|
|
||||||
// private candyUpgradeOverlayIcon: Phaser.GameObjects.Image[];
|
|
||||||
//
|
|
||||||
private iconAnimHandler: PokemonIconAnimHandler;
|
private iconAnimHandler: PokemonIconAnimHandler;
|
||||||
|
|
||||||
//variables to keep track of the dynamically rendered list of instruction prompts for starter select
|
//variables to keep track of the dynamically rendered list of instruction prompts for starter select
|
||||||
@ -1316,12 +1310,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Button.UP:
|
case Button.UP:
|
||||||
|
// UP from start button: go to pokemon in team if any, otherwise filter
|
||||||
this.startCursorObj.setVisible(false);
|
this.startCursorObj.setVisible(false);
|
||||||
if (this.starterSpecies.length > 0) {
|
if (this.starterSpecies.length > 0) {
|
||||||
this.starterIconsCursorIndex = this.starterSpecies.length - 1;
|
this.starterIconsCursorIndex = this.starterSpecies.length - 1;
|
||||||
this.moveStarterIconsCursor(this.starterIconsCursorIndex);
|
this.moveStarterIconsCursor(this.starterIconsCursorIndex);
|
||||||
} else {
|
} else {
|
||||||
// up from start button with no Pokemon in the team > go to filter
|
|
||||||
this.startCursorObj.setVisible(false);
|
this.startCursorObj.setVisible(false);
|
||||||
this.filterBarCursor = Math.max(1, this.filterBar.numFilters - 1);
|
this.filterBarCursor = Math.max(1, this.filterBar.numFilters - 1);
|
||||||
this.setFilterMode(true);
|
this.setFilterMode(true);
|
||||||
@ -1329,29 +1323,27 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
case Button.DOWN:
|
case Button.DOWN:
|
||||||
this.startCursorObj.setVisible(false);
|
// DOWN from start button: Go to filters
|
||||||
if (this.starterSpecies.length > 0) {
|
|
||||||
this.starterIconsCursorIndex = 0;
|
|
||||||
this.moveStarterIconsCursor(this.starterIconsCursorIndex);
|
|
||||||
} else {
|
|
||||||
// down from start button with no Pokemon in the team > go to filter
|
|
||||||
this.startCursorObj.setVisible(false);
|
this.startCursorObj.setVisible(false);
|
||||||
this.filterBarCursor = Math.max(1, this.filterBar.numFilters - 1);
|
this.filterBarCursor = Math.max(1, this.filterBar.numFilters - 1);
|
||||||
this.setFilterMode(true);
|
this.setFilterMode(true);
|
||||||
}
|
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
case Button.LEFT:
|
case Button.LEFT:
|
||||||
|
if (numberOfStarters > 0) {
|
||||||
this.startCursorObj.setVisible(false);
|
this.startCursorObj.setVisible(false);
|
||||||
this.cursorObj.setVisible(true);
|
this.cursorObj.setVisible(true);
|
||||||
success = this.setCursor(onScreenFirstIndex + (onScreenNumberOfRows-1) * 9 + 8); // set last column
|
this.setCursor(onScreenFirstIndex + (onScreenNumberOfRows - 1) * 9 + 8); // set last column
|
||||||
success = true;
|
success = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Button.RIGHT:
|
case Button.RIGHT:
|
||||||
|
if (numberOfStarters > 0) {
|
||||||
this.startCursorObj.setVisible(false);
|
this.startCursorObj.setVisible(false);
|
||||||
this.cursorObj.setVisible(true);
|
this.cursorObj.setVisible(true);
|
||||||
success = this.setCursor(onScreenFirstIndex + (onScreenNumberOfRows-1) * 9); // set first column
|
this.setCursor(onScreenFirstIndex + (onScreenNumberOfRows - 1) * 9); // set first column
|
||||||
success = true;
|
success = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (this.filterMode) {
|
} else if (this.filterMode) {
|
||||||
@ -1373,7 +1365,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
case Button.UP:
|
case Button.UP:
|
||||||
if (this.filterBar.openDropDown) {
|
if (this.filterBar.openDropDown) {
|
||||||
success = this.filterBar.decDropDownCursor();
|
success = this.filterBar.decDropDownCursor();
|
||||||
// else if there is filtered starters
|
} else if (this.filterBarCursor === this.filterBar.numFilters - 1 && this.starterSpecies.length > 0) {
|
||||||
|
// UP from the last filter, move to start button
|
||||||
|
this.setFilterMode(false);
|
||||||
|
this.cursorObj.setVisible(false);
|
||||||
|
this.startCursorObj.setVisible(true);
|
||||||
|
success = true;
|
||||||
} else if (numberOfStarters > 0) {
|
} else if (numberOfStarters > 0) {
|
||||||
// UP from filter bar to bottom of Pokemon list
|
// UP from filter bar to bottom of Pokemon list
|
||||||
this.setFilterMode(false);
|
this.setFilterMode(false);
|
||||||
@ -1392,6 +1389,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
case Button.DOWN:
|
case Button.DOWN:
|
||||||
if (this.filterBar.openDropDown) {
|
if (this.filterBar.openDropDown) {
|
||||||
success = this.filterBar.incDropDownCursor();
|
success = this.filterBar.incDropDownCursor();
|
||||||
|
} else if (this.filterBarCursor === this.filterBar.numFilters - 1 && this.starterSpecies.length > 0) {
|
||||||
|
// DOWN from the last filter, move to Pokemon in party if any
|
||||||
|
this.setFilterMode(false);
|
||||||
|
this.cursorObj.setVisible(false);
|
||||||
|
this.starterIconsCursorIndex = 0;
|
||||||
|
this.moveStarterIconsCursor(this.starterIconsCursorIndex);
|
||||||
|
success = true;
|
||||||
} else if (numberOfStarters > 0) {
|
} else if (numberOfStarters > 0) {
|
||||||
// DOWN from filter bar to top of Pokemon list
|
// DOWN from filter bar to top of Pokemon list
|
||||||
this.setFilterMode(false);
|
this.setFilterMode(false);
|
||||||
@ -2656,9 +2660,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonShinyIcon.setTint(tint);
|
this.pokemonShinyIcon.setTint(tint);
|
||||||
this.setSpecies(species);
|
this.setSpecies(species);
|
||||||
this.updateInstructions();
|
this.updateInstructions();
|
||||||
} else {
|
|
||||||
console.warn("Species is undefined for cursor position", cursor);
|
|
||||||
this.setFilterMode(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2951,7 +2952,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setSpeciesDetails(species: PokemonSpecies, shiny?: boolean, formIndex?: integer, female?: boolean, variant?: Variant, abilityIndex?: integer, natureIndex?: integer, forSeen: boolean = false): void {
|
setSpeciesDetails(species: PokemonSpecies, shiny?: boolean, formIndex?: integer, female?: boolean, variant?: Variant, abilityIndex?: integer, natureIndex?: integer, forSeen: boolean = false): void {
|
||||||
const oldProps = species ? this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor) : null;
|
const oldProps = species ? this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor) : null;
|
||||||
const oldAbilityIndex = this.abilityCursor > -1 ? this.abilityCursor : this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
const oldAbilityIndex = this.abilityCursor > -1 ? this.abilityCursor : this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
||||||
@ -3327,6 +3327,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.moveStarterIconsCursor(this.starterIconsCursorIndex);
|
this.moveStarterIconsCursor(this.starterIconsCursorIndex);
|
||||||
|
} else if (this.startCursorObj.visible && this.starterSpecies.length === 0) {
|
||||||
|
// On the start button and no more Pokemon in party
|
||||||
|
this.startCursorObj.setVisible(false);
|
||||||
|
if (this.filteredStarterContainers.length > 0) {
|
||||||
|
// Back to the first Pokemon if there is one
|
||||||
|
this.cursorObj.setVisible(true);
|
||||||
|
this.setCursor(0 + this.scrollCursor * 9);
|
||||||
|
} else {
|
||||||
|
// Back to filters
|
||||||
|
this.filterBarCursor = Math.max(1, this.filterBar.numFilters - 1);
|
||||||
|
this.setFilterMode(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tryUpdateValue();
|
this.tryUpdateValue();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user