mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-02 13:42:19 +02:00
Compare commits
10 Commits
78ce5e77d9
...
cf06ff3b8d
Author | SHA1 | Date | |
---|---|---|---|
|
cf06ff3b8d | ||
|
819fe9b4a1 | ||
|
048993b2c2 | ||
|
c929bbd23a | ||
|
a85a2a9b8b | ||
|
e0d3279a0b | ||
|
c908153761 | ||
|
0970c2cd4e | ||
|
16e14376c6 | ||
|
6be46ec0de |
@ -53,7 +53,10 @@
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"imports": {
|
||||
"#enums": "./enums",
|
||||
"#enums/*": "./enums/*",
|
||||
"#app": "./src/main.js",
|
||||
"#app/*": "./src/*"
|
||||
"#app/*": "./src/*",
|
||||
"#test/*": "./src/test/*"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import re
|
||||
|
||||
filenames = [['src/data/enums/moves.ts', 'move'], ['src/data/enums/abilities.ts', 'ability'], ['src/data/enums/species.ts', 'Pokémon']]
|
||||
filenames = [['src/enums/moves.ts', 'move'], ['src/enums/abilities.ts', 'ability'], ['src/enums/species.ts', 'Pokémon']]
|
||||
|
||||
commentBlockStart = re.compile('\/\*[^\*].*') # Regex for the start of a comment block
|
||||
commentBlockEnd = re.compile('.*,\*\/') # Regex for the end of a comment block
|
||||
|
@ -9,6 +9,10 @@ export interface UserInfo {
|
||||
export let loggedInUser: UserInfo = null;
|
||||
export const clientSessionId = Utils.randomString(32);
|
||||
|
||||
export function initLoggedInUser(): void {
|
||||
loggedInUser = { username: "Guest", lastSessionSlot: -1 };
|
||||
}
|
||||
|
||||
export function updateUserInfo(): Promise<[boolean, integer]> {
|
||||
return new Promise<[boolean, integer]>(resolve => {
|
||||
if (bypassLogin) {
|
||||
|
@ -9,12 +9,9 @@ import { PokeballType } from "./data/pokeball";
|
||||
import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets, populateAnims } from "./data/battle-anims";
|
||||
import { Phase } from "./phase";
|
||||
import { initGameSpeed } from "./system/game-speed";
|
||||
import { Biome } from "./data/enums/biome";
|
||||
import { Arena, ArenaBase } from "./field/arena";
|
||||
import { GameData } from "./system/game-data";
|
||||
import { PlayerGender } from "./data/enums/player-gender";
|
||||
import { TextStyle, addTextObject, getTextColor } from "./ui/text";
|
||||
import { Moves } from "./data/enums/moves";
|
||||
import { allMoves } from "./data/move";
|
||||
import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getLuckString, getLuckTextTint, getModifierPoolForType, getPartyLuckValue } from "./modifier/modifier-type";
|
||||
import AbilityBar from "./ui/ability-bar";
|
||||
@ -31,7 +28,6 @@ import TrainerData from "./system/trainer-data";
|
||||
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
|
||||
import { pokemonPrevolutions } from "./data/pokemon-evolutions";
|
||||
import PokeballTray from "./ui/pokeball-tray";
|
||||
import { Species } from "./data/enums/species";
|
||||
import InvertPostFX from "./pipelines/invert";
|
||||
import { Achv, ModifierAchv, MoneyAchv, achvs } from "./system/achv";
|
||||
import { Voucher, vouchers } from "./system/voucher";
|
||||
@ -42,14 +38,12 @@ import PokemonData from "./system/pokemon-data";
|
||||
import { Nature } from "./data/nature";
|
||||
import { SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger, pokemonFormChanges } from "./data/pokemon-forms";
|
||||
import { FormChangePhase, QuietFormChangePhase } from "./form-change-phase";
|
||||
import { BattleSpec } from "./enums/battle-spec";
|
||||
import { getTypeRgb } from "./data/type";
|
||||
import PokemonSpriteSparkleHandler from "./field/pokemon-sprite-sparkle-handler";
|
||||
import CharSprite from "./ui/char-sprite";
|
||||
import DamageNumberHandler from "./field/damage-number-handler";
|
||||
import PokemonInfoContainer from "./ui/pokemon-info-container";
|
||||
import { biomeDepths, getBiomeName } from "./data/biomes";
|
||||
import { UiTheme } from "./enums/ui-theme";
|
||||
import { SceneBase } from "./scene-base";
|
||||
import CandyBar from "./ui/candy-bar";
|
||||
import { Variant, variantData } from "./data/variant";
|
||||
@ -57,12 +51,9 @@ import { Localizable } from "./plugins/i18n";
|
||||
import * as Overrides from "./overrides";
|
||||
import {InputsController} from "./inputs-controller";
|
||||
import {UiInputs} from "./ui-inputs";
|
||||
import { MoneyFormat } from "./enums/money-format";
|
||||
import { NewArenaEvent } from "./events/battle-scene";
|
||||
import { Abilities } from "./data/enums/abilities";
|
||||
import { Abilities, BattleSpec, BattleStyle, Biome, EaseType, ExpNotification, MoneyFormat, Moves, PlayerGender, UiTheme, Species} from "#enums";
|
||||
import ArenaFlyout from "./ui/arena-flyout";
|
||||
import { EaseType } from "./ui/enums/ease-type";
|
||||
import { ExpNotification } from "./enums/exp-notification";
|
||||
|
||||
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
|
||||
|
||||
@ -156,10 +147,10 @@ export default class BattleScene extends SceneBase {
|
||||
public enableVibration: boolean = false;
|
||||
/**
|
||||
* Determines the selected battle style.
|
||||
* - 0 = 'Shift'
|
||||
* - 0 = 'Switch'
|
||||
* - 1 = 'Set' - The option to switch the active pokemon at the start of a battle will not display.
|
||||
*/
|
||||
public battleStyle: integer = 0;
|
||||
public battleStyle: integer = BattleStyle.SWITCH;
|
||||
|
||||
/**
|
||||
* Defines whether or not to show type effectiveness hints
|
||||
@ -1098,18 +1089,18 @@ export default class BattleScene extends SceneBase {
|
||||
if (pokemon.hasAbility(Abilities.ICE_FACE)) {
|
||||
pokemon.formIndex = 0;
|
||||
}
|
||||
|
||||
pokemon.resetBattleData();
|
||||
applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon);
|
||||
}
|
||||
|
||||
this.unshiftPhase(new ShowTrainerPhase(this));
|
||||
}
|
||||
|
||||
for (const pokemon of this.getParty()) {
|
||||
if (pokemon) {
|
||||
if (resetArenaState) {
|
||||
pokemon.resetBattleData();
|
||||
applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon, true);
|
||||
}
|
||||
this.triggerPokemonFormChange(pokemon, SpeciesFormChangeTimeOfDayTrigger);
|
||||
}
|
||||
this.triggerPokemonFormChange(pokemon, SpeciesFormChangeTimeOfDayTrigger);
|
||||
}
|
||||
|
||||
if (!this.gameMode.hasRandomBiomes && !isNewBiome) {
|
||||
this.pushPhase(new NextEncounterPhase(this));
|
||||
} else {
|
||||
@ -1922,6 +1913,8 @@ export default class BattleScene extends SceneBase {
|
||||
}
|
||||
if (!this.phaseQueue.length) {
|
||||
this.populatePhaseQueue();
|
||||
// clear the conditionalQueue if there are no phases left in the phaseQueue
|
||||
this.conditionalQueue = [];
|
||||
}
|
||||
this.currentPhase = this.phaseQueue.shift();
|
||||
|
||||
|
@ -3,12 +3,8 @@ import { EnemyPokemon, PlayerPokemon, QueuedMove } from "./field/pokemon";
|
||||
import { Command } from "./ui/command-ui-handler";
|
||||
import * as Utils from "./utils";
|
||||
import Trainer, { TrainerVariant } from "./field/trainer";
|
||||
import { Species } from "./data/enums/species";
|
||||
import { Moves } from "./data/enums/moves";
|
||||
import { TrainerType } from "./data/enums/trainer-type";
|
||||
import { GameMode } from "./game-mode";
|
||||
import { BattleSpec } from "./enums/battle-spec";
|
||||
import { PlayerGender } from "./data/enums/player-gender";
|
||||
import { BattleSpec, Moves, PlayerGender, Species, TrainerType } from "#enums";
|
||||
import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier";
|
||||
import { PokeballType } from "./data/pokeball";
|
||||
import {trainerConfigs} from "#app/data/trainer-config";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {Button} from "#app/enums/buttons";
|
||||
import {Button} from "#enums";
|
||||
import {SettingKeyboard} from "#app/system/settings/settings-keyboard";
|
||||
|
||||
const cfg_keyboard_qwerty = {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {Device} from "#app/enums/devices";
|
||||
import {Device} from "#enums";
|
||||
|
||||
/**
|
||||
* Retrieves the key associated with the specified keycode from the mapping.
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {SettingGamepad} from "../../system/settings/settings-gamepad";
|
||||
import {Button} from "../../enums/buttons";
|
||||
import {Button} from "#enums";
|
||||
|
||||
/**
|
||||
* Dualshock mapping
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {SettingGamepad} from "../../system/settings/settings-gamepad";
|
||||
import {Button} from "../../enums/buttons";
|
||||
import {Button} from "#enums";
|
||||
|
||||
/**
|
||||
* Generic pad mapping
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {SettingGamepad} from "#app/system/settings/settings-gamepad.js";
|
||||
import {Button} from "#app/enums/buttons";
|
||||
import {Button} from "#enums";
|
||||
|
||||
/**
|
||||
* Nintendo Pro Controller mapping
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {SettingGamepad} from "../../system/settings/settings-gamepad";
|
||||
import {Button} from "../../enums/buttons";
|
||||
import {Button} from "#enums";
|
||||
|
||||
/**
|
||||
* 081f-e401 - UnlicensedSNES
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {SettingGamepad} from "../../system/settings/settings-gamepad";
|
||||
import {Button} from "#app/enums/buttons";
|
||||
import {Button} from "#enums";
|
||||
|
||||
/**
|
||||
* Generic pad mapping
|
||||
|
@ -6,23 +6,19 @@ import { MovePhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "
|
||||
import { getPokemonMessage, getPokemonNameWithAffix } from "../messages";
|
||||
import { Weather, WeatherType } from "./weather";
|
||||
import { BattlerTag } from "./battler-tags";
|
||||
import { BattlerTagType } from "./enums/battler-tag-type";
|
||||
import { ArenaTagType, Abilities, BattlerTagType, Moves, Species } from "#enums";
|
||||
import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
||||
import { Gender } from "./gender";
|
||||
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr } from "./move";
|
||||
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr } from "./move";
|
||||
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
|
||||
import { ArenaTagType } from "./enums/arena-tag-type";
|
||||
import { Stat, getStatName } from "./pokemon-stat";
|
||||
import { BerryModifier, PokemonHeldItemModifier } from "../modifier/modifier";
|
||||
import { Moves } from "./enums/moves";
|
||||
import { TerrainType } from "./terrain";
|
||||
import { SpeciesFormChangeManualTrigger } from "./pokemon-forms";
|
||||
import { Abilities } from "./enums/abilities";
|
||||
import i18next, { Localizable } from "#app/plugins/i18n.js";
|
||||
import { Command } from "../ui/command-ui-handler";
|
||||
import { BerryModifierType } from "#app/modifier/modifier-type";
|
||||
import { getPokeballName } from "./pokeball";
|
||||
import { Species } from "./enums/species";
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
|
||||
export class Ability implements Localizable {
|
||||
@ -372,7 +368,7 @@ export class TypeImmunityAbAttr extends PreDefendAbAttr {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (move.type === this.immuneType) {
|
||||
if (attacker !== pokemon && move.type === this.immuneType) {
|
||||
(args[0] as Utils.NumberHolder).value = 0;
|
||||
return true;
|
||||
}
|
||||
@ -1085,21 +1081,20 @@ export class FieldMultiplyBattleStatAbAttr extends AbAttr {
|
||||
}
|
||||
|
||||
export class MoveTypeChangeAttr extends PreAttackAbAttr {
|
||||
private newType: Type;
|
||||
private powerMultiplier: number;
|
||||
private condition: PokemonAttackCondition;
|
||||
|
||||
constructor(newType: Type, powerMultiplier: number, condition: PokemonAttackCondition) {
|
||||
constructor(
|
||||
private newType: Type,
|
||||
private powerMultiplier: number,
|
||||
private condition?: PokemonAttackCondition
|
||||
) {
|
||||
super(true);
|
||||
this.newType = newType;
|
||||
this.powerMultiplier = powerMultiplier;
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean {
|
||||
if (this.condition(pokemon, defender, move)) {
|
||||
if (this.condition && this.condition(pokemon, defender, move)) {
|
||||
move.type = this.newType;
|
||||
(args[0] as Utils.NumberHolder).value *= this.powerMultiplier;
|
||||
if (args[0] && args[0] instanceof Utils.NumberHolder) {
|
||||
args[0].value *= this.powerMultiplier;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1107,6 +1102,58 @@ export class MoveTypeChangeAttr extends PreAttackAbAttr {
|
||||
}
|
||||
}
|
||||
|
||||
/** Ability attribute for changing a pokemon's type before using a move */
|
||||
export class PokemonTypeChangeAbAttr extends PreAttackAbAttr {
|
||||
private moveType: Type;
|
||||
|
||||
constructor() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean {
|
||||
if (
|
||||
!pokemon.isTerastallized() &&
|
||||
move.id !== Moves.STRUGGLE &&
|
||||
/**
|
||||
* Skip moves that call other moves because these moves generate a following move that will trigger this ability attribute
|
||||
* @see {@link https://bulbapedia.bulbagarden.net/wiki/Category:Moves_that_call_other_moves}
|
||||
*/
|
||||
!move.findAttr((attr) =>
|
||||
attr instanceof RandomMovesetMoveAttr ||
|
||||
attr instanceof RandomMoveAttr ||
|
||||
attr instanceof NaturePowerAttr ||
|
||||
attr instanceof CopyMoveAttr
|
||||
)
|
||||
) {
|
||||
// TODO remove this copy when phase order is changed so that damage, type, category, etc.
|
||||
// TODO are all calculated prior to playing the move animation.
|
||||
const moveCopy = new Move(move.id, move.type, move.category, move.moveTarget, move.power, move.accuracy, move.pp, move.chance, move.priority, move.generation);
|
||||
moveCopy.attrs = move.attrs;
|
||||
|
||||
// Moves like Weather Ball ignore effects of abilities like Normalize and Refrigerate
|
||||
if (move.findAttr(attr => attr instanceof VariableMoveTypeAttr)) {
|
||||
applyMoveAttrs(VariableMoveTypeAttr, pokemon, null, moveCopy);
|
||||
} else {
|
||||
applyPreAttackAbAttrs(MoveTypeChangeAttr, pokemon, null, moveCopy);
|
||||
}
|
||||
|
||||
if (pokemon.getTypes().some((t) => t !== moveCopy.type)) {
|
||||
this.moveType = moveCopy.type;
|
||||
pokemon.summonData.types = [moveCopy.type];
|
||||
pokemon.updateInfo();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
|
||||
return getPokemonMessage(pokemon, ` transformed into the ${Type[this.moveType]} type!`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for abilities that boost the damage of moves
|
||||
* For abilities that boost the base power of moves, see VariableMovePowerAbAttr
|
||||
@ -3525,7 +3572,7 @@ export class IceFaceMoveImmunityAbAttr extends MoveImmunityAbAttr {
|
||||
function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any[]): TAttr },
|
||||
pokemon: Pokemon, applyFunc: AbAttrApplyFunc<TAttr>, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
if (!pokemon.canApplyAbility(passive, args[0])) {
|
||||
if (!pokemon.canApplyAbility(passive)) {
|
||||
if (!passive) {
|
||||
return applyAbAttrsInternal(attrType, pokemon, applyFunc, args, isAsync, showAbilityInstant, quiet, true).then(() => resolve());
|
||||
} else {
|
||||
@ -3557,6 +3604,9 @@ function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any
|
||||
}
|
||||
pokemon.scene.setPhaseQueueSplice();
|
||||
const onApplySuccess = () => {
|
||||
if (pokemon.summonData && !pokemon.summonData.abilitiesApplied.includes(ability.id)) {
|
||||
pokemon.summonData.abilitiesApplied.push(ability.id);
|
||||
}
|
||||
if (pokemon.battleData && !pokemon.battleData.abilitiesApplied.includes(ability.id)) {
|
||||
pokemon.battleData.abilitiesApplied.push(ability.id);
|
||||
}
|
||||
@ -4039,8 +4089,9 @@ export function initAbilities() {
|
||||
.conditionalAttr(pokemon => pokemon.status ? pokemon.status.effect === StatusEffect.PARALYSIS : false, BattleStatMultiplierAbAttr, BattleStat.SPD, 2)
|
||||
.conditionalAttr(pokemon => !!pokemon.status || pokemon.hasAbility(Abilities.COMATOSE), BattleStatMultiplierAbAttr, BattleStat.SPD, 1.5),
|
||||
new Ability(Abilities.NORMALIZE, 4)
|
||||
.attr(MoveTypeChangeAttr, Type.NORMAL, 1.2, (user, target, move) => move.id !== Moves.HIDDEN_POWER && move.id !== Moves.WEATHER_BALL &&
|
||||
move.id !== Moves.NATURAL_GIFT && move.id !== Moves.JUDGMENT && move.id !== Moves.TECHNO_BLAST),
|
||||
.attr(MoveTypeChangeAttr, Type.NORMAL, 1.2, (user, target, move) => {
|
||||
return ![Moves.HIDDEN_POWER, Moves.WEATHER_BALL, Moves.NATURAL_GIFT, Moves.JUDGMENT, Moves.TECHNO_BLAST].includes(move.id);
|
||||
}),
|
||||
new Ability(Abilities.SNIPER, 4)
|
||||
.attr(MultCritAbAttr, 1.5),
|
||||
new Ability(Abilities.MAGIC_GUARD, 4)
|
||||
@ -4238,7 +4289,8 @@ export function initAbilities() {
|
||||
.attr(UncopiableAbilityAbAttr)
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
.attr(UnsuppressableAbilityAbAttr)
|
||||
.attr(NoFusionAbilityAbAttr),
|
||||
.attr(NoFusionAbilityAbAttr)
|
||||
.bypassFaint(),
|
||||
new Ability(Abilities.VICTORY_STAR, 5)
|
||||
.attr(BattleStatMultiplierAbAttr, BattleStat.ACC, 1.1)
|
||||
.partial(),
|
||||
@ -4258,7 +4310,8 @@ export function initAbilities() {
|
||||
.attr(HealFromBerryUseAbAttr, 1/3)
|
||||
.partial(), // Healing not blocked by Heal Block
|
||||
new Ability(Abilities.PROTEAN, 6)
|
||||
.unimplemented(),
|
||||
.attr(PokemonTypeChangeAbAttr)
|
||||
.condition((p) => !p.summonData?.abilitiesApplied.includes(Abilities.PROTEAN)),
|
||||
new Ability(Abilities.FUR_COAT, 6)
|
||||
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL, 0.5)
|
||||
.ignorable(),
|
||||
@ -4347,6 +4400,7 @@ export function initAbilities() {
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
.attr(UnsuppressableAbilityAbAttr)
|
||||
.attr(NoFusionAbilityAbAttr)
|
||||
.bypassFaint()
|
||||
.partial(),
|
||||
new Ability(Abilities.STAKEOUT, 7)
|
||||
.attr(MovePowerBoostAbAttr, (user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.POKEMON, 2),
|
||||
@ -4379,7 +4433,8 @@ export function initAbilities() {
|
||||
.attr(UncopiableAbilityAbAttr)
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
.attr(UnsuppressableAbilityAbAttr)
|
||||
.attr(NoFusionAbilityAbAttr),
|
||||
.attr(NoFusionAbilityAbAttr)
|
||||
.bypassFaint(),
|
||||
new Ability(Abilities.DISGUISE, 7)
|
||||
.attr(PreDefendMovePowerToOneAbAttr, (target, user, move) => target.formIndex === 0 && target.getAttackTypeEffectiveness(move.type, user) > 0)
|
||||
.attr(PostSummonFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1)
|
||||
@ -4392,6 +4447,7 @@ export function initAbilities() {
|
||||
.attr(UnsuppressableAbilityAbAttr)
|
||||
.attr(NoTransformAbilityAbAttr)
|
||||
.attr(NoFusionAbilityAbAttr)
|
||||
.bypassFaint()
|
||||
.ignorable()
|
||||
.partial(),
|
||||
new Ability(Abilities.BATTLE_BOND, 7)
|
||||
@ -4400,7 +4456,8 @@ export function initAbilities() {
|
||||
.attr(UncopiableAbilityAbAttr)
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
.attr(UnsuppressableAbilityAbAttr)
|
||||
.attr(NoFusionAbilityAbAttr),
|
||||
.attr(NoFusionAbilityAbAttr)
|
||||
.bypassFaint(),
|
||||
new Ability(Abilities.POWER_CONSTRUCT, 7) // TODO: 10% Power Construct Zygarde isn't accounted for yet. If changed, update Zygarde's getSpeciesFormIndex entry accordingly
|
||||
.attr(PostBattleInitFormChangeAbAttr, () => 2)
|
||||
.attr(PostSummonFormChangeAbAttr, p => p.getHpRatio() <= 0.5 || p.getFormKey() === "complete" ? 4 : 2)
|
||||
@ -4409,6 +4466,7 @@ export function initAbilities() {
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
.attr(UnsuppressableAbilityAbAttr)
|
||||
.attr(NoFusionAbilityAbAttr)
|
||||
.bypassFaint()
|
||||
.partial(),
|
||||
new Ability(Abilities.CORROSION, 7) // TODO: Test Corrosion against Magic Bounce once it is implemented
|
||||
.attr(IgnoreTypeStatusEffectImmunityAbAttr, [StatusEffect.POISON, StatusEffect.TOXIC], [Type.STEEL, Type.POISON])
|
||||
@ -4492,7 +4550,8 @@ export function initAbilities() {
|
||||
.attr(PostSummonStatChangeAbAttr, BattleStat.DEF, 1, true)
|
||||
.condition(getOncePerBattleCondition(Abilities.DAUNTLESS_SHIELD)),
|
||||
new Ability(Abilities.LIBERO, 8)
|
||||
.unimplemented(),
|
||||
.attr(PokemonTypeChangeAbAttr)
|
||||
.condition((p) => !p.summonData?.abilitiesApplied.includes(Abilities.LIBERO)),
|
||||
new Ability(Abilities.BALL_FETCH, 8)
|
||||
.attr(FetchBallAbAttr)
|
||||
.condition(getOncePerBattleCondition(Abilities.BALL_FETCH)),
|
||||
@ -4639,7 +4698,8 @@ export function initAbilities() {
|
||||
.attr(NoTransformAbilityAbAttr)
|
||||
.attr(NoFusionAbilityAbAttr)
|
||||
.attr(PostBattleInitFormChangeAbAttr, () => 0)
|
||||
.attr(PreSwitchOutFormChangeAbAttr, () => 1),
|
||||
.attr(PreSwitchOutFormChangeAbAttr, () => 1)
|
||||
.bypassFaint(),
|
||||
new Ability(Abilities.COMMANDER, 9)
|
||||
.attr(UncopiableAbilityAbAttr)
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
|
@ -6,11 +6,9 @@ import PokemonSpecies, { PokemonForm, SpeciesFormKey, allSpecies } from "./pokem
|
||||
import { GrowthRate } from "./exp";
|
||||
import { Type } from "./type";
|
||||
import { allAbilities } from "./ability";
|
||||
import { Abilities } from "./enums/abilities";
|
||||
import { Species } from "./enums/species";
|
||||
import { Abilities, Moves, Species } from "#enums";
|
||||
import { pokemonFormLevelMoves } from "./pokemon-level-moves";
|
||||
import { tmSpecies } from "./tms";
|
||||
import { Moves } from "./enums/moves";
|
||||
|
||||
const targetMap = {
|
||||
"specific-move": MoveTarget.ATTACKER,
|
||||
|
@ -7,13 +7,10 @@ import Pokemon, { HitResult, PokemonMove } from "../field/pokemon";
|
||||
import { MoveEffectPhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase} from "../phases";
|
||||
import { StatusEffect } from "./status-effect";
|
||||
import { BattlerIndex } from "../battle";
|
||||
import { Moves } from "./enums/moves";
|
||||
import { ArenaTagType } from "./enums/arena-tag-type";
|
||||
import { Abilities, ArenaTagType, BattlerTagType, Moves } from "#enums";
|
||||
import { BlockNonDirectDamageAbAttr, ProtectStatAbAttr, applyAbAttrs } from "./ability";
|
||||
import { BattleStat } from "./battle-stat";
|
||||
import { CommonAnim, CommonBattleAnim } from "./battle-anims";
|
||||
import { Abilities } from "./enums/abilities";
|
||||
import { BattlerTagType } from "./enums/battler-tag-type";
|
||||
import i18next from "i18next";
|
||||
|
||||
export enum ArenaTagSide {
|
||||
|
@ -5,7 +5,7 @@ import Pokemon from "../field/pokemon";
|
||||
import * as Utils from "../utils";
|
||||
import { BattlerIndex } from "../battle";
|
||||
import { Element } from "json-stable-stringify";
|
||||
import { Moves } from "./enums/moves";
|
||||
import { Moves } from "#enums";
|
||||
//import fs from 'vite-plugin-fs/browser';
|
||||
|
||||
export enum AnimFrameTarget {
|
||||
|
@ -5,18 +5,15 @@ import Pokemon, { MoveResult, HitResult } from "../field/pokemon";
|
||||
import { Stat, getStatName } from "./pokemon-stat";
|
||||
import { StatusEffect } from "./status-effect";
|
||||
import * as Utils from "../utils";
|
||||
import { Moves } from "./enums/moves";
|
||||
import { ChargeAttr, MoveFlags, allMoves } from "./move";
|
||||
import { Type } from "./type";
|
||||
import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs } from "./ability";
|
||||
import { Abilities } from "./enums/abilities";
|
||||
import { BattlerTagType } from "./enums/battler-tag-type";
|
||||
import { Abilities, BattlerTagType, Moves, Species } from "#enums";
|
||||
import { TerrainType } from "./terrain";
|
||||
import { WeatherType } from "./weather";
|
||||
import { BattleStat } from "./battle-stat";
|
||||
import { allAbilities } from "./ability";
|
||||
import { SpeciesFormChangeManualTrigger } from "./pokemon-forms";
|
||||
import { Species } from "./enums/species";
|
||||
|
||||
export enum BattlerTagLapseType {
|
||||
FAINT,
|
||||
|
@ -2,12 +2,11 @@ import { PokemonHealPhase, StatChangePhase } from "../phases";
|
||||
import { getPokemonMessage } from "../messages";
|
||||
import Pokemon, { HitResult } from "../field/pokemon";
|
||||
import { BattleStat } from "./battle-stat";
|
||||
import { BattlerTagType } from "./enums/battler-tag-type";
|
||||
import { BattlerTagType, BerryType } from "#enums";
|
||||
import { getStatusEffectHealText } from "./status-effect";
|
||||
import * as Utils from "../utils";
|
||||
import { DoubleBerryEffectAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs } from "./ability";
|
||||
import i18next from "../plugins/i18n";
|
||||
import { BerryType } from "./enums/berry-type";
|
||||
|
||||
export function getBerryName(berryType: BerryType): string {
|
||||
return i18next.t(`berry:${BerryType[berryType]}.name`);
|
||||
|
@ -1,10 +1,7 @@
|
||||
import { Species } from "./enums/species";
|
||||
import { Type } from "./type";
|
||||
import * as Utils from "../utils";
|
||||
import beautify from "json-beautify";
|
||||
import { TrainerType } from "./enums/trainer-type";
|
||||
import { TimeOfDay } from "./enums/time-of-day";
|
||||
import { Biome } from "./enums/biome";
|
||||
import { Biome, Species, TimeOfDay, TrainerType } from "#enums";
|
||||
import {pokemonEvolutions, SpeciesFormEvolution} from "./pokemon-evolutions";
|
||||
import i18next from "i18next";
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
import * as Utils from "../utils";
|
||||
import { Challenges } from "./enums/challenges";
|
||||
import { Challenges, TrainerType, Species } from "#enums";
|
||||
import i18next from "#app/plugins/i18n.js";
|
||||
import { GameData } from "#app/system/game-data.js";
|
||||
import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./pokemon-species";
|
||||
import Pokemon from "#app/field/pokemon.js";
|
||||
import { BattleType, FixedBattleConfig } from "#app/battle.js";
|
||||
import { TrainerType } from "./enums/trainer-type";
|
||||
import Trainer, { TrainerVariant } from "#app/field/trainer.js";
|
||||
import { GameMode } from "#app/game-mode.js";
|
||||
import { Species } from "./enums/species";
|
||||
import { Type } from "./type";
|
||||
|
||||
/**
|
||||
|
@ -2,9 +2,8 @@ import BattleScene from "../battle-scene";
|
||||
import { PlayerPokemon } from "../field/pokemon";
|
||||
import { Starter } from "../ui/starter-select-ui-handler";
|
||||
import * as Utils from "../utils";
|
||||
import { Species } from "./enums/species";
|
||||
import PokemonSpecies, { PokemonSpeciesForm, getPokemonSpecies, getPokemonSpeciesForm, speciesStarters } from "./pokemon-species";
|
||||
import { PartyMemberStrength } from "./enums/party-member-strength";
|
||||
import { PartyMemberStrength, Species } from "#enums";
|
||||
|
||||
export interface DailyRunConfig {
|
||||
seed: integer;
|
||||
|
@ -1,6 +1,5 @@
|
||||
import {trainerConfigs} from "./trainer-config";
|
||||
import {TrainerType} from "./enums/trainer-type";
|
||||
import {BattleSpec} from "../enums/battle-spec";
|
||||
import {BattleSpec, TrainerType} from "#enums";
|
||||
|
||||
export interface TrainerTypeMessages {
|
||||
encounter?: string | string[],
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Moves } from "./enums/moves";
|
||||
import { Species } from "./enums/species";
|
||||
import { Moves, Species } from "#enums";
|
||||
import { allMoves } from "./move";
|
||||
import * as Utils from "../utils";
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import BattleScene from "../battle-scene";
|
||||
import { Species } from "./enums/species";
|
||||
import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./pokemon-species";
|
||||
import { EggTier } from "./enums/egg-type";
|
||||
import { EggTier, Species } from "#enums";
|
||||
import i18next from "../plugins/i18n";
|
||||
|
||||
export const EGG_SEED = 1073741824;
|
||||
|
@ -1,9 +1,7 @@
|
||||
import { Moves } from "./enums/moves";
|
||||
import { ChargeAnim, MoveChargeAnim, initMoveAnim, loadMoveAnimAssets } from "./battle-anims";
|
||||
import { BattleEndPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, PokemonHealPhase, StatChangePhase, SwitchSummonPhase } from "../phases";
|
||||
import { BattleStat, getBattleStatName } from "./battle-stat";
|
||||
import { EncoreTag } from "./battler-tags";
|
||||
import { BattlerTagType } from "./enums/battler-tag-type";
|
||||
import { getPokemonMessage } from "../messages";
|
||||
import Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon";
|
||||
import { StatusEffect, getStatusEffectHealText, isNonVolatileStatusEffect, getNonVolatileStatusEffects} from "./status-effect";
|
||||
@ -11,19 +9,16 @@ import { Type } from "./type";
|
||||
import * as Utils from "../utils";
|
||||
import { WeatherType } from "./weather";
|
||||
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
|
||||
import { ArenaTagType } from "./enums/arena-tag-type";
|
||||
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, BlockItemTheftAbAttr, applyPostAttackAbAttrs, ConfusionOnStatusEffectAbAttr, HealFromBerryUseAbAttr } from "./ability";
|
||||
import { Abilities } from "./enums/abilities";
|
||||
import { Abilities, ArenaTagType, BattlerTagType, Biome, Moves, Species } from "#enums";
|
||||
import { allAbilities } from "./ability";
|
||||
import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier } from "../modifier/modifier";
|
||||
import { BattlerIndex } from "../battle";
|
||||
import { Stat } from "./pokemon-stat";
|
||||
import { TerrainType } from "./terrain";
|
||||
import { SpeciesFormChangeActiveTrigger } from "./pokemon-forms";
|
||||
import { Species } from "./enums/species";
|
||||
import { ModifierPoolType } from "#app/modifier/modifier-type";
|
||||
import { Command } from "../ui/command-ui-handler";
|
||||
import { Biome } from "./enums/biome";
|
||||
import i18next, { Localizable } from "../plugins/i18n";
|
||||
import { getBerryEffectFunc } from "./berry";
|
||||
|
||||
@ -1797,7 +1792,7 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute that causes targets of the move to eat a berry. If chosenBerry is not overriden, a random berry will be picked from the target's inventory.
|
||||
* Attribute that causes targets of the move to eat a berry. If chosenBerry is not overridden, a random berry will be picked from the target's inventory.
|
||||
*/
|
||||
export class EatBerryAttr extends MoveEffectAttr {
|
||||
protected chosenBerry: BerryModifier;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Stat, getStatName } from "./pokemon-stat";
|
||||
import * as Utils from "../utils";
|
||||
import { TextStyle, getBBCodeFrag } from "../ui/text";
|
||||
import { UiTheme } from "#app/enums/ui-theme";
|
||||
import { UiTheme } from "#enums";
|
||||
import i18next from "i18next";
|
||||
|
||||
export enum Nature {
|
||||
|
@ -1,15 +1,12 @@
|
||||
import { Gender } from "./gender";
|
||||
import { Moves } from "./enums/moves";
|
||||
import { PokeballType } from "./pokeball";
|
||||
import Pokemon from "../field/pokemon";
|
||||
import { Stat } from "./pokemon-stat";
|
||||
import { Species } from "./enums/species";
|
||||
import { Type } from "./type";
|
||||
import * as Utils from "../utils";
|
||||
import { SpeciesFormKey } from "./pokemon-species";
|
||||
import { WeatherType } from "./weather";
|
||||
import { Biome } from "./enums/biome";
|
||||
import { TimeOfDay } from "./enums/time-of-day";
|
||||
import { Biome, Moves, Species, TimeOfDay } from "#enums";
|
||||
import { Nature } from "./nature";
|
||||
|
||||
export enum SpeciesWildEvolutionDelay {
|
||||
|
@ -1,12 +1,9 @@
|
||||
import { TimeOfDay } from "./enums/time-of-day";
|
||||
import { PokemonFormChangeItemModifier } from "../modifier/modifier";
|
||||
import Pokemon from "../field/pokemon";
|
||||
import { Moves } from "./enums/moves";
|
||||
import { SpeciesFormKey } from "./pokemon-species";
|
||||
import { Species } from "./enums/species";
|
||||
import { StatusEffect } from "./status-effect";
|
||||
import { MoveCategory, allMoves } from "./move";
|
||||
import { Abilities } from "./enums/abilities";
|
||||
import { Abilities, Moves, Species, TimeOfDay } from "#enums";
|
||||
|
||||
export enum FormChangeItem {
|
||||
NONE,
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Moves } from "./enums/moves";
|
||||
import { Species } from "./enums/species";
|
||||
import { Moves, Species } from "#enums";
|
||||
|
||||
export type LevelMoves = ([integer, Moves])[];
|
||||
|
||||
|
@ -1,17 +1,15 @@
|
||||
import { Abilities } from "./enums/abilities";
|
||||
import { Abilities, PartyMemberStrength, Species } from "#enums";
|
||||
import BattleScene, { AnySound } from "../battle-scene";
|
||||
import { Variant, variantColorCache } from "./variant";
|
||||
import { variantData } from "./variant";
|
||||
import { GrowthRate } from "./exp";
|
||||
import { SpeciesWildEvolutionDelay, pokemonEvolutions, pokemonPrevolutions } from "./pokemon-evolutions";
|
||||
import { Species } from "./enums/species";
|
||||
import { Type } from "./type";
|
||||
import { LevelMoves, pokemonFormLevelMoves, pokemonFormLevelMoves as pokemonSpeciesFormLevelMoves, pokemonSpeciesLevelMoves } from "./pokemon-level-moves";
|
||||
import { uncatchableSpecies } from "./biomes";
|
||||
import * as Utils from "../utils";
|
||||
import { StarterMoveset } from "../system/game-data";
|
||||
import { speciesEggMoves } from "./egg-moves";
|
||||
import { PartyMemberStrength } from "./enums/party-member-strength";
|
||||
import { GameMode } from "../game-mode";
|
||||
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities";
|
||||
import { VariantSet } from "./variant";
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { ModifierTier } from "../modifier/modifier-tier";
|
||||
import { Moves } from "./enums/moves";
|
||||
import { Species } from "./enums/species";
|
||||
import { Moves, Species } from "#enums";
|
||||
|
||||
interface TmSpecies {
|
||||
[key: integer]: Array<Species | Array<Species | string>>
|
||||
|
@ -2,18 +2,15 @@ import BattleScene, {startingWave} from "../battle-scene";
|
||||
import {ModifierTypeFunc, modifierTypes} from "../modifier/modifier-type";
|
||||
import {EnemyPokemon} from "../field/pokemon";
|
||||
import * as Utils from "../utils";
|
||||
import {TrainerType} from "./enums/trainer-type";
|
||||
import {Moves} from "./enums/moves";
|
||||
import {PokeballType} from "./pokeball";
|
||||
import {pokemonEvolutions, pokemonPrevolutions} from "./pokemon-evolutions";
|
||||
import PokemonSpecies, {getPokemonSpecies, PokemonSpeciesFilter} from "./pokemon-species";
|
||||
import {Species} from "./enums/species";
|
||||
import {tmSpecies} from "./tms";
|
||||
import {Type} from "./type";
|
||||
import {doubleBattleDialogue} from "./dialogue";
|
||||
import {PersistentModifier} from "../modifier/modifier";
|
||||
import {TrainerVariant} from "../field/trainer";
|
||||
import {PartyMemberStrength} from "./enums/party-member-strength";
|
||||
import {Moves, PartyMemberStrength, Species, TrainerType} from "#enums";
|
||||
import {getIsInitialized, initI18n} from "#app/plugins/i18n";
|
||||
import i18next from "i18next";
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { TrainerType } from "./enums/trainer-type";
|
||||
import { TrainerType } from "#enums";
|
||||
import * as Utils from "../utils";
|
||||
|
||||
class TrainerNameConfig {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Biome } from "./enums/biome";
|
||||
import { Biome } from "#enums";
|
||||
import { getPokemonMessage, getPokemonNameWithAffix } from "../messages";
|
||||
import Pokemon from "../field/pokemon";
|
||||
import { Type } from "./type";
|
||||
|
@ -5,12 +5,11 @@ import * as Utils from "./utils";
|
||||
import { Mode } from "./ui/ui";
|
||||
import { EGG_SEED, Egg, GachaType, getLegendaryGachaSpeciesForTimestamp } from "./data/egg";
|
||||
import EggHatchSceneHandler from "./ui/egg-hatch-scene-handler";
|
||||
import { Species } from "./data/enums/species";
|
||||
import { PlayerPokemon } from "./field/pokemon";
|
||||
import { getPokemonSpecies, speciesStarters } from "./data/pokemon-species";
|
||||
import { achvs } from "./system/achv";
|
||||
import { pokemonPrevolutions } from "./data/pokemon-evolutions";
|
||||
import { EggTier } from "./data/enums/egg-type";
|
||||
import { EggTier, Species } from "#enums";
|
||||
import PokemonInfoContainer from "./ui/pokemon-info-container";
|
||||
import EggCounterContainer from "./ui/egg-counter-container";
|
||||
import { EggCountChangedEvent } from "./events/egg";
|
||||
|
9
src/enums/battle-style.ts
Normal file
9
src/enums/battle-style.ts
Normal file
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Determines the selected battle style.
|
||||
* - 'Switch' - The option to switch the active pokemon at the start of a battle will be displayed.
|
||||
* - 'Set' - The option to switch the active pokemon at the start of a battle will not display.
|
||||
*/
|
||||
export enum BattleStyle {
|
||||
SWITCH,
|
||||
SET
|
||||
}
|
25
src/enums/index.ts
Normal file
25
src/enums/index.ts
Normal file
@ -0,0 +1,25 @@
|
||||
export * from "./abilities";
|
||||
export * from "./arena-tag-type";
|
||||
export * from "./battle-spec";
|
||||
export * from "./battle-style";
|
||||
export * from "./battler-tag-type";
|
||||
export * from "./berry-type";
|
||||
export * from "./biome";
|
||||
export * from "./buttons";
|
||||
export * from "./challenges";
|
||||
export * from "./devices";
|
||||
export * from "./ease-type";
|
||||
export * from "./egg-type";
|
||||
export * from "./exp-notification";
|
||||
export * from "./game-data-type";
|
||||
export * from "./money-format";
|
||||
export * from "./moves";
|
||||
export * from "./money-format";
|
||||
export * from "./party-member-strength";
|
||||
export * from "./passive";
|
||||
export * from "./player-gender";
|
||||
export * from "./species";
|
||||
export * from "./time-of-day";
|
||||
export * from "./trainer-type";
|
||||
export * from "./ui-theme";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ArenaTagSide } from "#app/data/arena-tag.js";
|
||||
import { ArenaTagType } from "#app/data/enums/arena-tag-type.js";
|
||||
import { ArenaTagType } from "#enums";
|
||||
import { TerrainType } from "#app/data/terrain.js";
|
||||
import { WeatherType } from "#app/data/weather.js";
|
||||
|
@ -1,25 +1,20 @@
|
||||
import BattleScene from "../battle-scene";
|
||||
import { BiomePoolTier, PokemonPools, BiomeTierTrainerPools, biomePokemonPools, biomeTrainerPools } from "../data/biomes";
|
||||
import { Biome } from "../data/enums/biome";
|
||||
import { ArenaTagType, Biome, Moves, Species, TimeOfDay, TrainerType } from "#enums";
|
||||
import * as Utils from "../utils";
|
||||
import PokemonSpecies, { getPokemonSpecies } from "../data/pokemon-species";
|
||||
import { Species } from "../data/enums/species";
|
||||
import { Weather, WeatherType, getTerrainClearMessage, getTerrainStartMessage, getWeatherClearMessage, getWeatherStartMessage } from "../data/weather";
|
||||
import { CommonAnimPhase } from "../phases";
|
||||
import { CommonAnim } from "../data/battle-anims";
|
||||
import { Type } from "../data/type";
|
||||
import Move from "../data/move";
|
||||
import { ArenaTag, ArenaTagSide, getArenaTag } from "../data/arena-tag";
|
||||
import { ArenaTagType } from "../data/enums/arena-tag-type";
|
||||
import { TrainerType } from "../data/enums/trainer-type";
|
||||
import { BattlerIndex } from "../battle";
|
||||
import { Moves } from "../data/enums/moves";
|
||||
import { TimeOfDay } from "../data/enums/time-of-day";
|
||||
import { Terrain, TerrainType } from "../data/terrain";
|
||||
import { PostTerrainChangeAbAttr, PostWeatherChangeAbAttr, applyPostTerrainChangeAbAttrs, applyPostWeatherChangeAbAttrs } from "../data/ability";
|
||||
import Pokemon from "./pokemon";
|
||||
import * as Overrides from "../overrides";
|
||||
import { WeatherChangedEvent, TerrainChangedEvent, TagAddedEvent, TagRemovedEvent } from "./events/arena";
|
||||
import { WeatherChangedEvent, TerrainChangedEvent, TagAddedEvent, TagRemovedEvent } from "../events/arena";
|
||||
|
||||
export class Arena {
|
||||
public scene: BattleScene;
|
||||
|
@ -3,7 +3,6 @@ import BattleScene, { AnySound } from "../battle-scene";
|
||||
import { Variant, VariantSet, variantColorCache } from "#app/data/variant";
|
||||
import { variantData } from "#app/data/variant";
|
||||
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "../ui/battle-info";
|
||||
import { Moves } from "../data/enums/moves";
|
||||
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, VariableMoveTypeAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, MoveFlags } from "../data/move";
|
||||
import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species";
|
||||
import * as Utils from "../utils";
|
||||
@ -20,18 +19,13 @@ import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "../data/tms";
|
||||
import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase, ToggleDoublePositionPhase } from "../phases";
|
||||
import { BattleStat } from "../data/battle-stat";
|
||||
import { BattlerTag, BattlerTagLapseType, EncoreTag, HelpingHandTag, HighestStatBoostTag, TypeBoostTag, getBattlerTag } from "../data/battler-tags";
|
||||
import { BattlerTagType } from "../data/enums/battler-tag-type";
|
||||
import { Species } from "../data/enums/species";
|
||||
import { WeatherType } from "../data/weather";
|
||||
import { TempBattleStat } from "../data/temp-battle-stat";
|
||||
import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from "../data/arena-tag";
|
||||
import { ArenaTagType } from "../data/enums/arena-tag-type";
|
||||
import { Biome } from "../data/enums/biome";
|
||||
import { Abilities, ArenaTagType, Moves, BattlerTagType, Species, Biome, BattleSpec, BerryType } from "#enums";
|
||||
import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldBattleStatMultiplierAbAttrs, FieldMultiplyBattleStatAbAttr } from "../data/ability";
|
||||
import { Abilities } from "#app/data/enums/abilities";
|
||||
import PokemonData from "../system/pokemon-data";
|
||||
import { BattlerIndex } from "../battle";
|
||||
import { BattleSpec } from "../enums/battle-spec";
|
||||
import { Mode } from "../ui/ui";
|
||||
import PartyUiHandler, { PartyOption, PartyUiMode } from "../ui/party-ui-handler";
|
||||
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
|
||||
@ -44,7 +38,6 @@ import { SpeciesFormChange, SpeciesFormChangeActiveTrigger, SpeciesFormChangeMov
|
||||
import { TerrainType } from "../data/terrain";
|
||||
import { TrainerSlot } from "../data/trainer-config";
|
||||
import * as Overrides from "../overrides";
|
||||
import { BerryType } from "../data/enums/berry-type";
|
||||
import i18next from "../plugins/i18n";
|
||||
import { speciesEggMoves } from "../data/egg-moves";
|
||||
import { ModifierTier } from "../modifier/modifier-tier";
|
||||
@ -1004,7 +997,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
* @param {boolean} passive If true, check if passive can be applied instead of non-passive
|
||||
* @returns {Ability} The passive ability of the pokemon
|
||||
*/
|
||||
canApplyAbility(passive: boolean = false, forceBypass: boolean = false): boolean {
|
||||
canApplyAbility(passive: boolean = false): boolean {
|
||||
if (passive && !this.hasPassive()) {
|
||||
return false;
|
||||
}
|
||||
@ -1032,7 +1025,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (this.hp || ability.isBypassFaint || forceBypass) && !ability.conditions.find(condition => !condition(this));
|
||||
return (this.hp || ability.isBypassFaint) && !ability.conditions.find(condition => !condition(this));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3811,6 +3804,7 @@ export class PokemonSummonData {
|
||||
public disabledTurns: integer = 0;
|
||||
public tags: BattlerTag[] = [];
|
||||
public abilitySuppressed: boolean = false;
|
||||
public abilitiesApplied: Abilities[] = [];
|
||||
|
||||
public speciesForm: PokemonSpeciesForm;
|
||||
public fusionSpeciesForm: PokemonSpeciesForm;
|
||||
@ -3819,7 +3813,8 @@ export class PokemonSummonData {
|
||||
public fusionGender: Gender;
|
||||
public stats: integer[];
|
||||
public moveset: PokemonMove[];
|
||||
public types: Type[];
|
||||
// If not initialized this value will not be populated from save data.
|
||||
public types: Type[] = null;
|
||||
}
|
||||
|
||||
export class PokemonBattleData {
|
||||
@ -3831,7 +3826,9 @@ export class PokemonBattleData {
|
||||
}
|
||||
|
||||
export class PokemonBattleSummonData {
|
||||
/** The number of turns the pokemon has passed since entering the battle */
|
||||
public turnCount: integer = 1;
|
||||
/** The list of moves the pokemon has used since entering the battle */
|
||||
public moveHistory: TurnMove[] = [];
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,7 @@ import {
|
||||
trainerPartyTemplates,
|
||||
signatureSpecies
|
||||
} from "../data/trainer-config";
|
||||
import {PartyMemberStrength} from "../data/enums/party-member-strength";
|
||||
import {TrainerType} from "../data/enums/trainer-type";
|
||||
import {PartyMemberStrength, Species, TrainerType} from "#enums";
|
||||
import {EnemyPokemon} from "./pokemon";
|
||||
import * as Utils from "../utils";
|
||||
import {PersistentModifier} from "../modifier/modifier";
|
||||
@ -20,7 +19,6 @@ import {trainerNamePools} from "../data/trainer-names";
|
||||
import {ArenaTagSide, ArenaTrapTag} from "#app/data/arena-tag";
|
||||
import {getIsInitialized, initI18n} from "#app/plugins/i18n";
|
||||
import i18next from "i18next";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
|
||||
export enum TrainerVariant {
|
||||
DEFAULT,
|
||||
|
@ -7,7 +7,7 @@ import { EndEvolutionPhase, EvolutionPhase } from "./evolution-phase";
|
||||
import Pokemon, { EnemyPokemon, PlayerPokemon } from "./field/pokemon";
|
||||
import { Mode } from "./ui/ui";
|
||||
import PartyUiHandler from "./ui/party-ui-handler";
|
||||
import { BattleSpec } from "./enums/battle-spec";
|
||||
import { BattleSpec } from "#enums";
|
||||
import { BattlePhase, MovePhase, PokemonHealPhase } from "./phases";
|
||||
import { getTypeRgb } from "./data/type";
|
||||
|
||||
|
@ -2,8 +2,7 @@ import i18next from "i18next";
|
||||
import { classicFixedBattles, FixedBattleConfig, FixedBattleConfigs } from "./battle";
|
||||
import BattleScene from "./battle-scene";
|
||||
import { allChallenges, applyChallenges, Challenge, ChallengeType, copyChallenge } from "./data/challenge";
|
||||
import { Biome } from "./data/enums/biome";
|
||||
import { Species } from "./data/enums/species";
|
||||
import { Biome, Species } from "#enums";
|
||||
import PokemonSpecies, { allSpecies } from "./data/pokemon-species";
|
||||
import { Arena } from "./field/arena";
|
||||
import * as Overrides from "./overrides";
|
||||
|
@ -6,12 +6,11 @@ import pad_unlicensedSNES from "./configs/inputs/pad_unlicensedSNES";
|
||||
import pad_xbox360 from "./configs/inputs/pad_xbox360";
|
||||
import pad_dualshock from "./configs/inputs/pad_dualshock";
|
||||
import pad_procon from "./configs/inputs/pad_procon";
|
||||
import {Button} from "./enums/buttons";
|
||||
import {Mode} from "./ui/ui";
|
||||
import SettingsGamepadUiHandler from "./ui/settings/settings-gamepad-ui-handler";
|
||||
import SettingsKeyboardUiHandler from "./ui/settings/settings-keyboard-ui-handler";
|
||||
import cfg_keyboard_qwerty from "./configs/inputs/cfg_keyboard_qwerty";
|
||||
import {Device} from "#app/enums/devices";
|
||||
import {Button, Device} from "#enums";
|
||||
import {
|
||||
assign,
|
||||
getButtonWithKeycode,
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { GachaType } from "./data/egg";
|
||||
import { Biome } from "./data/enums/biome";
|
||||
import { TrainerType } from "./data/enums/trainer-type";
|
||||
import { Biome, TrainerType } from "#enums";
|
||||
import { trainerConfigs } from "./data/trainer-config";
|
||||
import { getBiomeHasProps } from "./field/arena";
|
||||
import CacheBustedLoaderPlugin from "./plugins/cache-busted-loader-plugin";
|
||||
|
@ -2931,7 +2931,7 @@ export const move: MoveTranslationEntries = {
|
||||
},
|
||||
"bouncyBubble": {
|
||||
name: "Blubbsauger",
|
||||
effect: "Evoli greift mit Wasserblasen an. Evolis KP werden um die Hälfte des vom Wasser angerichteten Schadens geheilt."
|
||||
effect: "Der Anwender greift mit Wasserblasen an. Seine KP werden in Höhe des vom Wasser angerichteten Schadens geheilt."
|
||||
},
|
||||
"buzzyBuzz": {
|
||||
name: "Knisterladung",
|
||||
|
@ -2931,7 +2931,7 @@ export const move: MoveTranslationEntries = {
|
||||
},
|
||||
"bouncyBubble": {
|
||||
name: "Bouncy Bubble",
|
||||
effect: "The user attacks by shooting water bubbles at the target. It then absorbs water and restores its HP by half the damage taken by the target."
|
||||
effect: "The user attacks by shooting water bubbles at the target. It then absorbs water and restores its HP by the damage taken by the target."
|
||||
},
|
||||
"buzzyBuzz": {
|
||||
name: "Buzzy Buzz",
|
||||
|
@ -2931,7 +2931,7 @@ export const move: MoveTranslationEntries = {
|
||||
},
|
||||
bouncyBubble: {
|
||||
name: "Bouncy Bubble",
|
||||
effect: "O usuário ataca atirando bolhas de água no alvo. Em seguida, absorve água e restaura seu HP pela metade do dano causado ao alvo."
|
||||
effect: "O usuário ataca atirando bolhas de água no alvo. Em seguida, absorve água e restaura seu HP pelo mesmo valor de dano causado ao alvo."
|
||||
},
|
||||
buzzyBuzz: {
|
||||
name: "Buzzy Buzz",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { BattleSpec } from "./enums/battle-spec";
|
||||
import { BattleSpec } from "#enums";
|
||||
import Pokemon from "./field/pokemon";
|
||||
import i18next from "./plugins/i18n";
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import * as Modifiers from "./modifier";
|
||||
import { AttackMove, allMoves } from "../data/move";
|
||||
import { Moves } from "../data/enums/moves";
|
||||
import { Abilities } from "../data/enums/abilities";
|
||||
import { Abilities, BattlerTagType, BerryType, Moves } from "#enums";
|
||||
import { PokeballType, getPokeballCatchMultiplier, getPokeballName } from "../data/pokeball";
|
||||
import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "../field/pokemon";
|
||||
import { EvolutionItem, pokemonEvolutions } from "../data/pokemon-evolutions";
|
||||
@ -12,7 +11,6 @@ import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from "..
|
||||
import * as Utils from "../utils";
|
||||
import { TempBattleStat, getTempBattleStatBoosterItemName, getTempBattleStatName } from "../data/temp-battle-stat";
|
||||
import { getBerryEffectDescription, getBerryName } from "../data/berry";
|
||||
import { BerryType } from "../data/enums/berry-type";
|
||||
import { Unlockables } from "../system/unlockables";
|
||||
import { StatusEffect, getStatusEffectDescriptor } from "../data/status-effect";
|
||||
import { SpeciesFormKey } from "../data/pokemon-species";
|
||||
@ -23,7 +21,6 @@ import { ModifierTier } from "./modifier-tier";
|
||||
import { Nature, getNatureName, getNatureStatMultiplier } from "#app/data/nature";
|
||||
import i18next from "#app/plugins/i18n";
|
||||
import { getModifierTierTextTint } from "#app/ui/text";
|
||||
import { BattlerTagType } from "#app/data/enums/battler-tag-type.js";
|
||||
import * as Overrides from "../overrides";
|
||||
import { MoneyMultiplierModifier } from "./modifier";
|
||||
|
||||
@ -1343,13 +1340,13 @@ const modifierPool: ModifierPool = {
|
||||
new WeightedModifierType(modifierTypes.RARE_EVOLUTION_ITEM, (party: Pokemon[]) => Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 15) * 4, 32), 32),
|
||||
new WeightedModifierType(modifierTypes.AMULET_COIN, 3),
|
||||
new WeightedModifierType(modifierTypes.TOXIC_ORB, (party: Pokemon[]) => {
|
||||
const checkedAbilities = [Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.TOXIC_BOOST, Abilities.POISON_HEAL];
|
||||
const checkedAbilities = [Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.TOXIC_BOOST, Abilities.POISON_HEAL, Abilities.MAGIC_GUARD];
|
||||
const checkedMoves = [Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT];
|
||||
// If a party member doesn't already have one of these two orbs and has one of the above moves or abilities, the orb can appear
|
||||
return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier) && (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => checkedMoves.includes(m.moveId)))) ? 10 : 0;
|
||||
}, 10),
|
||||
new WeightedModifierType(modifierTypes.FLAME_ORB, (party: Pokemon[]) => {
|
||||
const checkedAbilities = [Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.FLARE_BOOST];
|
||||
const checkedAbilities = [Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.FLARE_BOOST, Abilities.MAGIC_GUARD];
|
||||
const checkedMoves = [Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT];
|
||||
// If a party member doesn't already have one of these two orbs and has one of the above moves or abilities, the orb can appear
|
||||
return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier) && (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => checkedMoves.includes(m.moveId)))) ? 10 : 0;
|
||||
|
@ -13,13 +13,12 @@ import { getPokemonMessage } from "../messages";
|
||||
import * as Utils from "../utils";
|
||||
import { TempBattleStat } from "../data/temp-battle-stat";
|
||||
import { getBerryEffectFunc, getBerryPredicate } from "../data/berry";
|
||||
import { BerryType } from "../data/enums/berry-type";
|
||||
import { BattlerTagType, BerryType } from "#enums";
|
||||
import { StatusEffect, getStatusEffectHealText } from "../data/status-effect";
|
||||
import { achvs } from "../system/achv";
|
||||
import { VoucherType } from "../system/voucher";
|
||||
import { FormChangeItem, SpeciesFormChangeItemTrigger } from "../data/pokemon-forms";
|
||||
import { Nature } from "#app/data/nature";
|
||||
import { BattlerTagType } from "#app/data/enums/battler-tag-type";
|
||||
import * as Overrides from "../overrides";
|
||||
import { ModifierType, modifierTypes } from "./modifier-type";
|
||||
import { Command } from "#app/ui/command-ui-handler.js";
|
||||
|
@ -1,20 +1,16 @@
|
||||
import { Species } from "./data/enums/species";
|
||||
import { Abilities } from "./data/enums/abilities";
|
||||
import { Biome } from "./data/enums/biome";
|
||||
import { Moves } from "./data/enums/moves";
|
||||
import { Species, Abilities, Biome, Moves, BerryType, TimeOfDay } from "#enums";
|
||||
import { WeatherType } from "./data/weather";
|
||||
import { Variant } from "./data/variant";
|
||||
import { BerryType } from "./data/enums/berry-type";
|
||||
import { TempBattleStat } from "./data/temp-battle-stat";
|
||||
import { Nature } from "./data/nature";
|
||||
import { Type } from "./data/type";
|
||||
import { Stat } from "./data/pokemon-stat";
|
||||
import { PokeballCounts } from "./battle-scene";
|
||||
import { PokeballType } from "./data/pokeball";
|
||||
import {TimeOfDay} from "#app/data/enums/time-of-day";
|
||||
import { Gender } from "./data/gender";
|
||||
import { StatusEffect } from "./data/status-effect";
|
||||
import { modifierTypes } from "./modifier/modifier-type";
|
||||
import { allSpecies } from "./data/pokemon-species"; // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
|
||||
/**
|
||||
* Overrides for testing different in game situations
|
||||
@ -53,8 +49,18 @@ export const POKEBALL_OVERRIDE: { active: boolean, pokeballs: PokeballCounts } =
|
||||
* PLAYER OVERRIDES
|
||||
*/
|
||||
|
||||
// forms can be found in pokemon-species.ts
|
||||
export const STARTER_FORM_OVERRIDE: integer = 0;
|
||||
/**
|
||||
* Set the form index of any starter in the party whose `speciesId` is inside this override
|
||||
* @see {@link allSpecies} in `src/data/pokemon-species.ts` for form indexes
|
||||
* @example
|
||||
* ```
|
||||
* const STARTER_FORM_OVERRIDES = {
|
||||
* [Species.DARMANITAN]: 1
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export const STARTER_FORM_OVERRIDES: Partial<Record<Species, number>> = {};
|
||||
|
||||
// default 5 or 20 for Daily
|
||||
export const STARTING_LEVEL_OVERRIDE: integer = 0;
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
import BattleScene, { bypassLogin } from "./battle-scene";
|
||||
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult, TurnMove } from "./field/pokemon";
|
||||
import * as Utils from "./utils";
|
||||
import { Moves } from "./data/enums/moves";
|
||||
import { Abilities, ArenaTagType, BattleSpec, BattleStyle, BattlerTagType, Biome, ExpNotification, Moves, PlayerGender, Species, TrainerType } from "#enums";
|
||||
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr, BypassRedirectAttr, FixedDamageAttr, PostVictoryStatChangeAttr, OneHitKOAccuracyAttr, ForceSwitchOutAttr, VariableTargetAttr, IncrementMovePriorityAttr } from "./data/move";
|
||||
import { Mode } from "./ui/ui";
|
||||
import { Command } from "./ui/command-ui-handler";
|
||||
@ -17,34 +17,27 @@ import { EvolutionPhase } from "./evolution-phase";
|
||||
import { Phase } from "./phase";
|
||||
import { BattleStat, getBattleStatLevelChangeDescription, getBattleStatName } from "./data/battle-stat";
|
||||
import { biomeLinks, getBiomeName } from "./data/biomes";
|
||||
import { Biome } from "./data/enums/biome";
|
||||
import { ModifierTier } from "./modifier/modifier-tier";
|
||||
import { FusePokemonModifierType, ModifierPoolType, ModifierType, ModifierTypeFunc, ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, PokemonPpRestoreModifierType, PokemonPpUpModifierType, RememberMoveModifierType, TmModifierType, getDailyRunStarterModifiers, getEnemyBuffModifierForWave, getModifierType, getPlayerModifierTypeOptions, getPlayerShopModifierTypeOptionsForWave, modifierTypes, regenerateModifierPoolThresholds } from "./modifier/modifier-type";
|
||||
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
|
||||
import { BattlerTagLapseType, EncoreTag, HideSpriteTag as HiddenTag, ProtectedTag, TrappedTag } from "./data/battler-tags";
|
||||
import { BattlerTagType } from "./data/enums/battler-tag-type";
|
||||
import { getPokemonMessage, getPokemonNameWithAffix } from "./messages";
|
||||
import { Starter } from "./ui/starter-select-ui-handler";
|
||||
import { Gender } from "./data/gender";
|
||||
import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, getWeatherDamageMessage, getWeatherLapseMessage } from "./data/weather";
|
||||
import { TempBattleStat } from "./data/temp-battle-stat";
|
||||
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
|
||||
import { ArenaTagType } from "./data/enums/arena-tag-type";
|
||||
import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, IgnoreOpponentEvasionAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, BlockRedirectAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr, applyPostMoveUsedAbAttrs, PostMoveUsedAbAttr, MaxMultiHitAbAttr, HealFromBerryUseAbAttr } from "./data/ability";
|
||||
import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, IgnoreOpponentEvasionAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, BlockRedirectAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr, PokemonTypeChangeAbAttr, applyPreAttackAbAttrs, applyPostMoveUsedAbAttrs, PostMoveUsedAbAttr, MaxMultiHitAbAttr, HealFromBerryUseAbAttr } from "./data/ability";
|
||||
import { Unlockables, getUnlockableName } from "./system/unlockables";
|
||||
import { getBiomeKey } from "./field/arena";
|
||||
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
|
||||
import { BattleSpec } from "./enums/battle-spec";
|
||||
import { Species } from "./data/enums/species";
|
||||
import { ChallengeAchv, HealAchv, LevelAchv, achvs } from "./system/achv";
|
||||
import { TrainerSlot, trainerConfigs } from "./data/trainer-config";
|
||||
import { TrainerType } from "./data/enums/trainer-type";
|
||||
import { EggHatchPhase } from "./egg-hatch-phase";
|
||||
import { Egg } from "./data/egg";
|
||||
import { vouchers } from "./system/voucher";
|
||||
import { loggedInUser, updateUserInfo } from "./account";
|
||||
import { SessionSaveData } from "./system/game-data";
|
||||
import { PlayerGender } from "./data/enums/player-gender";
|
||||
import { addPokeballCaptureStars, addPokeballOpenParticles } from "./field/anims";
|
||||
import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger } from "./data/pokemon-forms";
|
||||
import { battleSpecDialogue, getCharVariantFromDialogue, miscDialogue } from "./data/dialogue";
|
||||
@ -58,12 +51,10 @@ import { fetchDailyRunSeed, getDailyRunStarters } from "./data/daily-run";
|
||||
import { GameMode, GameModes, getGameMode } from "./game-mode";
|
||||
import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./data/pokemon-species";
|
||||
import i18next from "./plugins/i18n";
|
||||
import { Abilities } from "./data/enums/abilities";
|
||||
import * as Overrides from "./overrides";
|
||||
import { TextStyle, addTextObject } from "./ui/text";
|
||||
import { Type } from "./data/type";
|
||||
import { BerryUsedEvent, EncounterPhaseEvent, MoveUsedEvent, TurnEndEvent, TurnInitEvent } from "./events/battle-scene";
|
||||
import { ExpNotification } from "./enums/exp-notification";
|
||||
|
||||
|
||||
export class LoginPhase extends Phase {
|
||||
@ -555,6 +546,10 @@ export class SelectStarterPhase extends Phase {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize starters before starting the first battle
|
||||
* @param starters {@linkcode Pokemon} with which to start the first battle
|
||||
*/
|
||||
initBattle(starters: Starter[]) {
|
||||
const party = this.scene.getParty();
|
||||
const loadPokemonAssets: Promise<void>[] = [];
|
||||
@ -564,9 +559,13 @@ export class SelectStarterPhase extends Phase {
|
||||
}
|
||||
const starterProps = this.scene.gameData.getSpeciesDexAttrProps(starter.species, starter.dexAttr);
|
||||
let starterFormIndex = Math.min(starterProps.formIndex, Math.max(starter.species.forms.length - 1, 0));
|
||||
if (!i && Overrides.STARTER_SPECIES_OVERRIDE) {
|
||||
starterFormIndex = Overrides.STARTER_FORM_OVERRIDE;
|
||||
if (
|
||||
starter.species.speciesId in Overrides.STARTER_FORM_OVERRIDES &&
|
||||
starter.species.forms[Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]]
|
||||
) {
|
||||
starterFormIndex = Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId];
|
||||
}
|
||||
|
||||
let starterGender = starter.species.malePercent !== null
|
||||
? !starterProps.female ? Gender.MALE : Gender.FEMALE
|
||||
: Gender.GENDERLESS;
|
||||
@ -1025,13 +1024,19 @@ export class EncounterPhase extends BattlePhase {
|
||||
|
||||
if (this.scene.currentBattle.battleType !== BattleType.TRAINER) {
|
||||
enemyField.map(p => this.scene.pushConditionalPhase(new PostSummonPhase(this.scene, p.getBattlerIndex()), () => {
|
||||
// is the player party initialized ?
|
||||
const a = !!this.scene.getParty()?.length;
|
||||
// if there is not a player party, we can't continue
|
||||
if (!this.scene.getParty()?.length) {
|
||||
return false;
|
||||
}
|
||||
// how many player pokemon are on the field ?
|
||||
const amountOnTheField = this.scene.getParty().filter(p => p.isOnField()).length;
|
||||
const pokemonsOnFieldCount = this.scene.getParty().filter(p => p.isOnField()).length;
|
||||
// if it's a 2vs1, there will never be a 2nd pokemon on our field even
|
||||
const requiredPokemonsOnField = Math.min(this.scene.getParty().filter((p) => !p.isFainted()).length, 2);
|
||||
// if it's a double, there should be 2, otherwise 1
|
||||
const b = this.scene.currentBattle.double ? amountOnTheField === 2 : amountOnTheField === 1;
|
||||
return a && b;
|
||||
if (this.scene.currentBattle.double) {
|
||||
return pokemonsOnFieldCount === requiredPokemonsOnField;
|
||||
}
|
||||
return pokemonsOnFieldCount === 1;
|
||||
}));
|
||||
const ivScannerModifier = this.scene.findModifier(m => m instanceof IvScannerModifier);
|
||||
if (ivScannerModifier) {
|
||||
@ -1733,7 +1738,7 @@ export class CheckSwitchPhase extends BattlePhase {
|
||||
|
||||
const pokemon = this.scene.getPlayerField()[this.fieldIndex];
|
||||
|
||||
if (this.scene.battleStyle === 1) {
|
||||
if (this.scene.battleStyle === BattleStyle.SET) {
|
||||
super.end();
|
||||
return;
|
||||
}
|
||||
@ -2677,6 +2682,16 @@ export class MovePhase extends BattlePhase {
|
||||
failedText = getTerrainBlockMessage(targets[0], this.scene.arena.terrain.terrainType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger pokemon type change before playing the move animation
|
||||
* Will still change the user's type when using Roar, Whirlwind, Trick-or-Treat, and Forest's Curse,
|
||||
* regardless of whether the move successfully executes or not.
|
||||
*/
|
||||
if (success || [Moves.ROAR, Moves.WHIRLWIND, Moves.TRICK_OR_TREAT, Moves.FORESTS_CURSE].includes(this.move.moveId)) {
|
||||
applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove());
|
||||
}
|
||||
|
||||
if (success) {
|
||||
this.scene.unshiftPhase(this.getEffectPhase());
|
||||
} else {
|
||||
|
@ -3,7 +3,7 @@ import BattleScene from "../battle-scene";
|
||||
import { TurnHeldItemTransferModifier } from "../modifier/modifier";
|
||||
import i18next from "../plugins/i18n";
|
||||
import * as Utils from "../utils";
|
||||
import { PlayerGender } from "#app/data/enums/player-gender";
|
||||
import { PlayerGender } from "#enums";
|
||||
import { ParseKeys } from "i18next";
|
||||
import { Challenge, SingleGenerationChallenge, SingleTypeChallenge } from "#app/data/challenge.js";
|
||||
|
||||
|
@ -1,17 +1,20 @@
|
||||
import { Arena } from "../field/arena";
|
||||
import { ArenaTag } from "../data/arena-tag";
|
||||
import { Biome } from "../data/enums/biome";
|
||||
import { Biome } from "#enums";
|
||||
import { Weather } from "../data/weather";
|
||||
import { Terrain } from "#app/data/terrain.js";
|
||||
|
||||
export default class ArenaData {
|
||||
public biome: Biome;
|
||||
public weather: Weather;
|
||||
public terrain: Terrain;
|
||||
public tags: ArenaTag[];
|
||||
|
||||
constructor(source: Arena | any) {
|
||||
const sourceArena = source instanceof Arena ? source as Arena : null;
|
||||
this.biome = sourceArena ? sourceArena.biomeType : source.biome;
|
||||
this.weather = sourceArena ? sourceArena.weather : source.weather ? new Weather(source.weather.weatherType, source.weather.turnsLeft) : undefined;
|
||||
this.terrain = sourceArena ? sourceArena.terrain : source.terrain ? new Terrain(source.terrain.terrainType, source.terrain.turnsLeft) : undefined;
|
||||
this.tags = sourceArena ? sourceArena.tags : [];
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import BattleScene, { PokeballCounts, bypassLogin } from "../battle-scene";
|
||||
import Pokemon, { EnemyPokemon, PlayerPokemon } from "../field/pokemon";
|
||||
import { pokemonEvolutions, pokemonPrevolutions } from "../data/pokemon-evolutions";
|
||||
import PokemonSpecies, { allSpecies, getPokemonSpecies, noStarterFormKeys, speciesStarters } from "../data/pokemon-species";
|
||||
import { Species, defaultStarterSpecies } from "../data/enums/species";
|
||||
import { Species, defaultStarterSpecies, Moves, Device, PlayerGender, GameDataType } from "#enums";
|
||||
import * as Utils from "../utils";
|
||||
import * as Overrides from "../overrides";
|
||||
import PokemonData from "./pokemon-data";
|
||||
@ -24,7 +24,6 @@ import { clientSessionId, loggedInUser, updateUserInfo } from "../account";
|
||||
import { Nature } from "../data/nature";
|
||||
import { GameStats } from "./game-stats";
|
||||
import { Tutorial } from "../tutorial";
|
||||
import { Moves } from "../data/enums/moves";
|
||||
import { speciesEggMoves } from "../data/egg-moves";
|
||||
import { allMoves } from "../data/move";
|
||||
import { TrainerVariant } from "../field/trainer";
|
||||
@ -32,12 +31,9 @@ import { OutdatedPhase, ReloadSessionPhase } from "#app/phases";
|
||||
import { Variant, variantData } from "#app/data/variant";
|
||||
import {setSettingGamepad, SettingGamepad, settingGamepadDefaults} from "./settings/settings-gamepad";
|
||||
import {setSettingKeyboard, SettingKeyboard} from "#app/system/settings/settings-keyboard";
|
||||
import { TerrainChangedEvent, WeatherChangedEvent } from "#app/field/events/arena";
|
||||
import { Device } from "#app/enums/devices.js";
|
||||
import { TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena.js";
|
||||
import { EnemyAttackStatusEffectChanceModifier } from "../modifier/modifier";
|
||||
import { StatusEffect } from "#app/data/status-effect.js";
|
||||
import { PlayerGender } from "#app/data/enums/player-gender";
|
||||
import { GameDataType } from "#app/data/enums/game-data-type";
|
||||
import ChallengeData from "./challenge-data";
|
||||
|
||||
const saveKey = "x0i2O7WRiANTqPmZ"; // Temporary; secure encryption is not yet necessary
|
||||
@ -829,7 +825,7 @@ export class GameData {
|
||||
loadSession(scene: BattleScene, slotId: integer, sessionData?: SessionSaveData): Promise<boolean> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const initSessionFromData = async sessionData => {
|
||||
const initSessionFromData = async (sessionData: SessionSaveData) => {
|
||||
console.debug(sessionData);
|
||||
|
||||
scene.gameMode = getGameMode(sessionData.gameMode || GameModes.CLASSIC);
|
||||
@ -1213,9 +1209,11 @@ export class GameData {
|
||||
|
||||
reader.onload = (_ => {
|
||||
return e => {
|
||||
let dataName: string;
|
||||
let dataStr = AES.decrypt(e.target.result.toString(), saveKey).toString(enc.Utf8);
|
||||
let valid = false;
|
||||
try {
|
||||
dataName = GameDataType[dataType].toLowerCase();
|
||||
switch (dataType) {
|
||||
case GameDataType.SYSTEM:
|
||||
dataStr = this.convertSystemDataStr(dataStr);
|
||||
@ -1235,28 +1233,12 @@ export class GameData {
|
||||
console.error(ex);
|
||||
}
|
||||
|
||||
let dataName: string;
|
||||
switch (dataType) {
|
||||
case GameDataType.SYSTEM:
|
||||
dataName = "save";
|
||||
break;
|
||||
case GameDataType.SESSION:
|
||||
dataName = "session";
|
||||
break;
|
||||
case GameDataType.SETTINGS:
|
||||
dataName = "settings";
|
||||
break;
|
||||
case GameDataType.TUTORIALS:
|
||||
dataName = "tutorials";
|
||||
break;
|
||||
}
|
||||
|
||||
const displayError = (error: string) => this.scene.ui.showText(error, null, () => this.scene.ui.showText(null, 0), Utils.fixedInt(1500));
|
||||
|
||||
if (!valid) {
|
||||
return this.scene.ui.showText(`Your ${dataName} data could not be loaded. It may be corrupted.`, null, () => this.scene.ui.showText(null, 0), Utils.fixedInt(1500));
|
||||
}
|
||||
this.scene.ui.revertMode();
|
||||
|
||||
this.scene.ui.showText(`Your ${dataName} data will be overridden and the page will reload. Proceed?`, null, () => {
|
||||
this.scene.ui.setOverlayMode(Mode.CONFIRM, () => {
|
||||
localStorage.setItem(dataKey, encrypt(dataStr, bypassLogin));
|
||||
|
@ -1,15 +1,13 @@
|
||||
import { BattleType } from "../battle";
|
||||
import BattleScene from "../battle-scene";
|
||||
import { Biome } from "../data/enums/biome";
|
||||
import { Biome, Species, Moves } from "#enums";
|
||||
import { Gender } from "../data/gender";
|
||||
import { Nature } from "../data/nature";
|
||||
import { PokeballType } from "../data/pokeball";
|
||||
import { getPokemonSpecies } from "../data/pokemon-species";
|
||||
import { Species } from "../data/enums/species";
|
||||
import { Status } from "../data/status-effect";
|
||||
import Pokemon, { EnemyPokemon, PokemonMove, PokemonSummonData } from "../field/pokemon";
|
||||
import { TrainerSlot } from "../data/trainer-config";
|
||||
import { Moves } from "../data/enums/moves";
|
||||
import { Variant } from "#app/data/variant";
|
||||
import { loadBattlerTag } from "../data/battler-tags";
|
||||
|
||||
@ -54,7 +52,7 @@ export default class PokemonData {
|
||||
public summonData: PokemonSummonData;
|
||||
|
||||
constructor(source: Pokemon | any, forHistory: boolean = false) {
|
||||
const sourcePokemon = source instanceof Pokemon ? source as Pokemon : null;
|
||||
const sourcePokemon = source instanceof Pokemon ? source : null;
|
||||
this.id = source.id;
|
||||
this.player = sourcePokemon ? sourcePokemon.isPlayer() : source.player;
|
||||
this.species = sourcePokemon ? sourcePokemon.species.speciesId : source.species;
|
||||
@ -121,6 +119,7 @@ export default class PokemonData {
|
||||
this.summonData.disabledMove = source.summonData.disabledMove;
|
||||
this.summonData.disabledTurns = source.summonData.disabledTurns;
|
||||
this.summonData.abilitySuppressed = source.summonData.abilitySuppressed;
|
||||
this.summonData.abilitiesApplied = source.summonData.abilitiesApplied;
|
||||
|
||||
this.summonData.ability = source.summonData.ability;
|
||||
this.summonData.moveset = source.summonData.moveset?.map(m => PokemonMove.loadMove(m));
|
||||
|
@ -2,7 +2,7 @@ import BattleScene from "../../battle-scene";
|
||||
import SettingsGamepadUiHandler from "../../ui/settings/settings-gamepad-ui-handler";
|
||||
import {Mode} from "../../ui/ui";
|
||||
import {truncateString} from "../../utils";
|
||||
import {Button} from "../../enums/buttons";
|
||||
import {Button} from "#enums";
|
||||
import {SettingKeyboard} from "#app/system/settings/settings-keyboard";
|
||||
|
||||
export enum SettingGamepad {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {Button} from "#app/enums/buttons";
|
||||
import {Button} from "#enums";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
import SettingsKeyboardUiHandler from "#app/ui/settings/settings-keyboard-ui-handler";
|
||||
|
@ -3,11 +3,9 @@ import i18next from "i18next";
|
||||
import BattleScene from "../../battle-scene";
|
||||
import { hasTouchscreen } from "../../touch-controls";
|
||||
import { updateWindowType } from "../../ui/ui-theme";
|
||||
import { PlayerGender } from "#app/data/enums/player-gender";
|
||||
import { PlayerGender, MoneyFormat, EaseType } from "#enums";
|
||||
import { CandyUpgradeNotificationChangedEvent } from "../../events/battle-scene";
|
||||
import { MoneyFormat } from "../../enums/money-format";
|
||||
import SettingsUiHandler from "#app/ui/settings/settings-ui-handler";
|
||||
import { EaseType } from "#app/ui/enums/ease-type.js";
|
||||
|
||||
const MUTE = "Mute";
|
||||
const VOLUME_OPTIONS = new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : MUTE);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import BattleScene from "../battle-scene";
|
||||
import { TrainerType } from "../data/enums/trainer-type";
|
||||
import { TrainerType } from "#enums";
|
||||
import Trainer, { TrainerVariant } from "../field/trainer";
|
||||
|
||||
export default class TrainerData {
|
||||
|
@ -1,8 +1,7 @@
|
||||
import BattleScene from "../battle-scene";
|
||||
import { TrainerType } from "../data/enums/trainer-type";
|
||||
import i18next from "../plugins/i18n";
|
||||
import { Achv, AchvTier, achvs, getAchievementDescription } from "./achv";
|
||||
import { PlayerGender } from "#app/data/enums/player-gender";
|
||||
import { PlayerGender, TrainerType } from "#enums";
|
||||
|
||||
export enum VoucherType {
|
||||
REGULAR,
|
||||
|
67
src/test/abilities/battle_bond.test.ts
Normal file
67
src/test/abilities/battle_bond.test.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import { getMovePosition } from "#test/utils/gameManagerUtils";
|
||||
import * as Overrides from "#app/overrides";
|
||||
import { Moves } from "#enums";
|
||||
import { Abilities } from "#enums";
|
||||
import { Species } from "#enums";
|
||||
import { Status, StatusEffect } from "#app/data/status-effect.js";
|
||||
import { TurnEndPhase } from "#app/phases.js";
|
||||
import { QuietFormChangePhase } from "#app/form-change-phase.js";
|
||||
|
||||
const TIMEOUT = 20 * 1000;
|
||||
|
||||
describe("Abilities - BATTLE BOND", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
const moveToUse = Moves.SPLASH;
|
||||
vi.spyOn(Overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(Overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.BATTLE_BOND);
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
|
||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||
});
|
||||
|
||||
test(
|
||||
"check if fainted pokemon switches to base form on arena reset",
|
||||
async () => {
|
||||
const baseForm = 1,
|
||||
ashForm = 2;
|
||||
vi.spyOn(Overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(4);
|
||||
vi.spyOn(Overrides, "STARTER_FORM_OVERRIDES", "get").mockReturnValue({
|
||||
[Species.GRENINJA]: ashForm,
|
||||
});
|
||||
|
||||
await game.startBattle([Species.MAGIKARP, Species.GRENINJA]);
|
||||
|
||||
const greninja = game.scene.getParty().find((p) => p.species.speciesId === Species.GRENINJA);
|
||||
expect(greninja).not.toBe(undefined);
|
||||
expect(greninja.formIndex).toBe(ashForm);
|
||||
|
||||
greninja.hp = 0;
|
||||
greninja.status = new Status(StatusEffect.FAINT);
|
||||
expect(greninja.isFainted()).toBe(true);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.doKillOpponents();
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
game.doSelectModifier();
|
||||
await game.phaseInterceptor.to(QuietFormChangePhase);
|
||||
|
||||
expect(greninja.formIndex).toBe(baseForm);
|
||||
},
|
||||
TIMEOUT
|
||||
);
|
||||
});
|
67
src/test/abilities/disguise.test.ts
Normal file
67
src/test/abilities/disguise.test.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import { getMovePosition } from "#test/utils/gameManagerUtils";
|
||||
import * as Overrides from "#app/overrides";
|
||||
import { Moves } from "#enums";
|
||||
import { Abilities } from "#enums";
|
||||
import { Species } from "#enums";
|
||||
import { Status, StatusEffect } from "#app/data/status-effect.js";
|
||||
import { TurnEndPhase } from "#app/phases.js";
|
||||
import { QuietFormChangePhase } from "#app/form-change-phase.js";
|
||||
|
||||
const TIMEOUT = 20 * 1000;
|
||||
|
||||
describe("Abilities - DISGUISE", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
const moveToUse = Moves.SPLASH;
|
||||
vi.spyOn(Overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(Overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.DISGUISE);
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
|
||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||
});
|
||||
|
||||
test(
|
||||
"check if fainted pokemon switched to base form on arena reset",
|
||||
async () => {
|
||||
const baseForm = 0,
|
||||
bustedForm = 1;
|
||||
vi.spyOn(Overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(4);
|
||||
vi.spyOn(Overrides, "STARTER_FORM_OVERRIDES", "get").mockReturnValue({
|
||||
[Species.MIMIKYU]: bustedForm,
|
||||
});
|
||||
|
||||
await game.startBattle([Species.MAGIKARP, Species.MIMIKYU]);
|
||||
|
||||
const mimikyu = game.scene.getParty().find((p) => p.species.speciesId === Species.MIMIKYU);
|
||||
expect(mimikyu).not.toBe(undefined);
|
||||
expect(mimikyu.formIndex).toBe(bustedForm);
|
||||
|
||||
mimikyu.hp = 0;
|
||||
mimikyu.status = new Status(StatusEffect.FAINT);
|
||||
expect(mimikyu.isFainted()).toBe(true);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.doKillOpponents();
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
game.doSelectModifier();
|
||||
await game.phaseInterceptor.to(QuietFormChangePhase);
|
||||
|
||||
expect(mimikyu.formIndex).toBe(baseForm);
|
||||
},
|
||||
TIMEOUT
|
||||
);
|
||||
});
|
@ -2,18 +2,18 @@ import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest
|
||||
import Phaser from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import {Abilities} from "#app/data/enums/abilities";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import {Abilities, Species, Moves} from "#enums";
|
||||
import {
|
||||
CommandPhase, DamagePhase,
|
||||
EnemyCommandPhase,
|
||||
CommandPhase, DamagePhase, EncounterPhase,
|
||||
EnemyCommandPhase, SelectStarterPhase,
|
||||
TurnInitPhase,
|
||||
} from "#app/phases";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
import {BattleStat} from "#app/data/battle-stat";
|
||||
import {Moves} from "#app/data/enums/moves";
|
||||
import {getMovePosition} from "#app/test/utils/gameManagerUtils";
|
||||
import {generateStarter, getMovePosition} from "#app/test/utils/gameManagerUtils";
|
||||
import {Command} from "#app/ui/command-ui-handler";
|
||||
import {Status, StatusEffect} from "#app/data/status-effect";
|
||||
import {GameModes, getGameMode} from "#app/game-mode";
|
||||
|
||||
|
||||
describe("Abilities - Intimidate", () => {
|
||||
@ -337,5 +337,53 @@ describe("Abilities - Intimidate", () => {
|
||||
expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1);
|
||||
battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;
|
||||
expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1);
|
||||
}, 200000);
|
||||
}, 20000);
|
||||
|
||||
it("double - wild vs only 1 on player side", async() => {
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(false);
|
||||
vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3);
|
||||
await game.runToSummon([
|
||||
Species.MIGHTYENA,
|
||||
]);
|
||||
await game.phaseInterceptor.to(CommandPhase, false);
|
||||
const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;
|
||||
expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1);
|
||||
const battleStatsOpponent2 = game.scene.currentBattle.enemyParty[1].summonData.battleStats;
|
||||
expect(battleStatsOpponent2[BattleStat.ATK]).toBe(-1);
|
||||
|
||||
const battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
|
||||
expect(battleStatsPokemon[BattleStat.ATK]).toBe(-2);
|
||||
}, 20000);
|
||||
|
||||
it("double - wild vs only 1 alive on player side", async() => {
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(false);
|
||||
vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3);
|
||||
await game.runToTitle();
|
||||
|
||||
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
|
||||
game.scene.gameMode = getGameMode(GameModes.CLASSIC);
|
||||
const starters = generateStarter(game.scene, [
|
||||
Species.MIGHTYENA,
|
||||
Species.POOCHYENA,
|
||||
]);
|
||||
const selectStarterPhase = new SelectStarterPhase(game.scene);
|
||||
game.scene.pushPhase(new EncounterPhase(game.scene, false));
|
||||
selectStarterPhase.initBattle(starters);
|
||||
game.scene.getParty()[1].hp = 0;
|
||||
game.scene.getParty()[1].status = new Status(StatusEffect.FAINT);
|
||||
});
|
||||
|
||||
await game.phaseInterceptor.run(EncounterPhase);
|
||||
|
||||
await game.phaseInterceptor.to(CommandPhase, false);
|
||||
const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;
|
||||
expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1);
|
||||
const battleStatsOpponent2 = game.scene.currentBattle.enemyParty[1].summonData.battleStats;
|
||||
expect(battleStatsOpponent2[BattleStat.ATK]).toBe(-1);
|
||||
|
||||
const battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
|
||||
expect(battleStatsPokemon[BattleStat.ATK]).toBe(-2);
|
||||
}, 20000);
|
||||
});
|
||||
|
@ -2,8 +2,7 @@ import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest
|
||||
import Phaser from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import {Abilities} from "#app/data/enums/abilities";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import {Abilities, Species} from "#enums";
|
||||
import {
|
||||
CommandPhase,
|
||||
} from "#app/phases";
|
||||
|
364
src/test/abilities/libero.test.ts
Normal file
364
src/test/abilities/libero.test.ts
Normal file
@ -0,0 +1,364 @@
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import GameManager from "../utils/gameManager";
|
||||
import * as Overrides from "#app/overrides";
|
||||
import { Species } from "#enums";
|
||||
import { Abilities } from "#enums";
|
||||
import { Moves } from "#enums";
|
||||
import { getMovePosition } from "../utils/gameManagerUtils";
|
||||
import { MoveEffectPhase, TurnEndPhase } from "#app/phases.js";
|
||||
import { allMoves } from "#app/data/move.js";
|
||||
import { BattlerTagType } from "#enums";
|
||||
import { Weather, WeatherType } from "#app/data/weather.js";
|
||||
import { Type } from "#app/data/type.js";
|
||||
import { Biome } from "#enums";
|
||||
import { PlayerPokemon } from "#app/field/pokemon.js";
|
||||
|
||||
const TIMEOUT = 20 * 1000;
|
||||
|
||||
describe("Abilities - Protean", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
vi.spyOn(Overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(Overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.LIBERO);
|
||||
vi.spyOn(Overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100);
|
||||
vi.spyOn(Overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
|
||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.ENDURE, Moves.ENDURE, Moves.ENDURE, Moves.ENDURE]);
|
||||
});
|
||||
|
||||
test(
|
||||
"ability applies and changes a pokemon's type",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies only once per switch in",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.AGILITY]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP, Species.BULBASAUR]);
|
||||
|
||||
let leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.AGILITY));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(leadPokemon.summonData.abilitiesApplied.filter((a) => a === Abilities.LIBERO)).toHaveLength(1);
|
||||
const leadPokemonType = Type[leadPokemon.getTypes()[0]];
|
||||
const moveType = Type[allMoves[Moves.AGILITY].defaultType];
|
||||
expect(leadPokemonType).not.toBe(moveType);
|
||||
|
||||
await game.toNextTurn();
|
||||
game.doSwitchPokemon(1);
|
||||
await game.toNextTurn();
|
||||
game.doSwitchPokemon(1);
|
||||
await game.toNextTurn();
|
||||
|
||||
leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the pokemon's move has a variable type",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.WEATHER_BALL]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.scene.arena.weather = new Weather(WeatherType.SUNNY);
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.WEATHER_BALL));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.LIBERO);
|
||||
expect(leadPokemon.getTypes()).toHaveLength(1);
|
||||
const leadPokemonType = Type[leadPokemon.getTypes()[0]],
|
||||
moveType = Type[Type.FIRE];
|
||||
expect(leadPokemonType).toBe(moveType);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the type has changed by another ability",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
|
||||
vi.spyOn(Overrides, "PASSIVE_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.REFRIGERATE);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.LIBERO);
|
||||
expect(leadPokemon.getTypes()).toHaveLength(1);
|
||||
const leadPokemonType = Type[leadPokemon.getTypes()[0]],
|
||||
moveType = Type[Type.ICE];
|
||||
expect(leadPokemonType).toBe(moveType);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the pokemon's move calls another move",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.NATURE_POWER]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.scene.arena.biomeType = Biome.MOUNTAIN;
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.NATURE_POWER));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.AIR_SLASH);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the pokemon's move is delayed / charging",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.DIG]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.DIG));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.DIG);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the pokemon's move misses",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
|
||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
|
||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(false);
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp());
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the pokemon's move is protected against",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
|
||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.PROTECT, Moves.PROTECT, Moves.PROTECT, Moves.PROTECT]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the pokemon's move fails because of type immunity",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
|
||||
vi.spyOn(Overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.GASTLY);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability is not applied if pokemon's type is the same as the move's type",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
leadPokemon.summonData.types = [allMoves[Moves.SPLASH].defaultType];
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability is not applied if pokemon is terastallized",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
vi.spyOn(leadPokemon, "isTerastallized").mockReturnValue(true);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability is not applied if pokemon uses struggle",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.STRUGGLE]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.STRUGGLE));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability is not applied if the pokemon's move fails",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.BURN_UP]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.BURN_UP));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the pokemon's Trick-or-Treat fails",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TRICK_OR_TREAT]);
|
||||
vi.spyOn(Overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.GASTLY);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.TRICK_OR_TREAT));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TRICK_OR_TREAT);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly and the pokemon curses itself",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.CURSE]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.CURSE));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.CURSE);
|
||||
expect(leadPokemon.getTag(BattlerTagType.CURSED)).not.toBe(undefined);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
});
|
||||
|
||||
function testPokemonTypeMatchesDefaultMoveType(pokemon: PlayerPokemon, move: Moves) {
|
||||
expect(pokemon.summonData.abilitiesApplied).toContain(Abilities.LIBERO);
|
||||
expect(pokemon.getTypes()).toHaveLength(1);
|
||||
const pokemonType = Type[pokemon.getTypes()[0]],
|
||||
moveType = Type[allMoves[move].defaultType];
|
||||
expect(pokemonType).toBe(moveType);
|
||||
}
|
@ -2,8 +2,7 @@ import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest
|
||||
import Phaser from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import {Abilities} from "#app/data/enums/abilities";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import {Abilities, Moves, Species} from "#enums";
|
||||
import {
|
||||
CommandPhase,
|
||||
EnemyCommandPhase,
|
||||
@ -11,7 +10,6 @@ import {
|
||||
} from "#app/phases";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
import {Stat} from "#app/data/pokemon-stat";
|
||||
import {Moves} from "#app/data/enums/moves";
|
||||
import {getMovePosition} from "#app/test/utils/gameManagerUtils";
|
||||
import {Command} from "#app/ui/command-ui-handler";
|
||||
import {BattleStat} from "#app/data/battle-stat";
|
||||
|
67
src/test/abilities/power_construct.test.ts
Normal file
67
src/test/abilities/power_construct.test.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import { getMovePosition } from "#test/utils/gameManagerUtils";
|
||||
import * as Overrides from "#app/overrides";
|
||||
import { Moves } from "#enums";
|
||||
import { Abilities } from "#enums";
|
||||
import { Species } from "#enums";
|
||||
import { Status, StatusEffect } from "#app/data/status-effect.js";
|
||||
import { TurnEndPhase } from "#app/phases.js";
|
||||
import { QuietFormChangePhase } from "#app/form-change-phase.js";
|
||||
|
||||
const TIMEOUT = 20 * 1000;
|
||||
|
||||
describe("Abilities - POWER CONSTRUCT", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
const moveToUse = Moves.SPLASH;
|
||||
vi.spyOn(Overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(Overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.POWER_CONSTRUCT);
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
|
||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||
});
|
||||
|
||||
test(
|
||||
"check if fainted pokemon switches to base form on arena reset",
|
||||
async () => {
|
||||
const baseForm = 2,
|
||||
completeForm = 4;
|
||||
vi.spyOn(Overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(4);
|
||||
vi.spyOn(Overrides, "STARTER_FORM_OVERRIDES", "get").mockReturnValue({
|
||||
[Species.ZYGARDE]: completeForm,
|
||||
});
|
||||
|
||||
await game.startBattle([Species.MAGIKARP, Species.ZYGARDE]);
|
||||
|
||||
const zygarde = game.scene.getParty().find((p) => p.species.speciesId === Species.ZYGARDE);
|
||||
expect(zygarde).not.toBe(undefined);
|
||||
expect(zygarde.formIndex).toBe(completeForm);
|
||||
|
||||
zygarde.hp = 0;
|
||||
zygarde.status = new Status(StatusEffect.FAINT);
|
||||
expect(zygarde.isFainted()).toBe(true);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.doKillOpponents();
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
game.doSelectModifier();
|
||||
await game.phaseInterceptor.to(QuietFormChangePhase);
|
||||
|
||||
expect(zygarde.formIndex).toBe(baseForm);
|
||||
},
|
||||
TIMEOUT
|
||||
);
|
||||
});
|
364
src/test/abilities/protean.test.ts
Normal file
364
src/test/abilities/protean.test.ts
Normal file
@ -0,0 +1,364 @@
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import GameManager from "../utils/gameManager";
|
||||
import * as Overrides from "#app/overrides";
|
||||
import { Species } from "#enums";
|
||||
import { Abilities } from "#enums";
|
||||
import { Moves } from "#enums";
|
||||
import { getMovePosition } from "../utils/gameManagerUtils";
|
||||
import { MoveEffectPhase, TurnEndPhase } from "#app/phases.js";
|
||||
import { allMoves } from "#app/data/move.js";
|
||||
import { BattlerTagType } from "#enums";
|
||||
import { Weather, WeatherType } from "#app/data/weather.js";
|
||||
import { Type } from "#app/data/type.js";
|
||||
import { Biome } from "#enums";
|
||||
import { PlayerPokemon } from "#app/field/pokemon.js";
|
||||
|
||||
const TIMEOUT = 20 * 1000;
|
||||
|
||||
describe("Abilities - Protean", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
vi.spyOn(Overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(Overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.PROTEAN);
|
||||
vi.spyOn(Overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100);
|
||||
vi.spyOn(Overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
|
||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.ENDURE, Moves.ENDURE, Moves.ENDURE, Moves.ENDURE]);
|
||||
});
|
||||
|
||||
test(
|
||||
"ability applies and changes a pokemon's type",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies only once per switch in",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.AGILITY]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP, Species.BULBASAUR]);
|
||||
|
||||
let leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.AGILITY));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(leadPokemon.summonData.abilitiesApplied.filter((a) => a === Abilities.PROTEAN)).toHaveLength(1);
|
||||
const leadPokemonType = Type[leadPokemon.getTypes()[0]];
|
||||
const moveType = Type[allMoves[Moves.AGILITY].defaultType];
|
||||
expect(leadPokemonType).not.toBe(moveType);
|
||||
|
||||
await game.toNextTurn();
|
||||
game.doSwitchPokemon(1);
|
||||
await game.toNextTurn();
|
||||
game.doSwitchPokemon(1);
|
||||
await game.toNextTurn();
|
||||
|
||||
leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the pokemon's move has a variable type",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.WEATHER_BALL]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.scene.arena.weather = new Weather(WeatherType.SUNNY);
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.WEATHER_BALL));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.PROTEAN);
|
||||
expect(leadPokemon.getTypes()).toHaveLength(1);
|
||||
const leadPokemonType = Type[leadPokemon.getTypes()[0]],
|
||||
moveType = Type[Type.FIRE];
|
||||
expect(leadPokemonType).toBe(moveType);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the type has changed by another ability",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
|
||||
vi.spyOn(Overrides, "PASSIVE_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.REFRIGERATE);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.PROTEAN);
|
||||
expect(leadPokemon.getTypes()).toHaveLength(1);
|
||||
const leadPokemonType = Type[leadPokemon.getTypes()[0]],
|
||||
moveType = Type[Type.ICE];
|
||||
expect(leadPokemonType).toBe(moveType);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the pokemon's move calls another move",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.NATURE_POWER]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.scene.arena.biomeType = Biome.MOUNTAIN;
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.NATURE_POWER));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.AIR_SLASH);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the pokemon's move is delayed / charging",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.DIG]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.DIG));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.DIG);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the pokemon's move misses",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
|
||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
|
||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(false);
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp());
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the pokemon's move is protected against",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
|
||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.PROTECT, Moves.PROTECT, Moves.PROTECT, Moves.PROTECT]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the pokemon's move fails because of type immunity",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
|
||||
vi.spyOn(Overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.GASTLY);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability is not applied if pokemon's type is the same as the move's type",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
leadPokemon.summonData.types = [allMoves[Moves.SPLASH].defaultType];
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability is not applied if pokemon is terastallized",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
vi.spyOn(leadPokemon, "isTerastallized").mockReturnValue(true);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability is not applied if pokemon uses struggle",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.STRUGGLE]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.STRUGGLE));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability is not applied if the pokemon's move fails",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.BURN_UP]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.BURN_UP));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly even if the pokemon's Trick-or-Treat fails",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TRICK_OR_TREAT]);
|
||||
vi.spyOn(Overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.GASTLY);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.TRICK_OR_TREAT));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TRICK_OR_TREAT);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
|
||||
test(
|
||||
"ability applies correctly and the pokemon curses itself",
|
||||
async () => {
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.CURSE]);
|
||||
|
||||
await game.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.CURSE));
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.CURSE);
|
||||
expect(leadPokemon.getTag(BattlerTagType.CURSED)).not.toBe(undefined);
|
||||
},
|
||||
TIMEOUT,
|
||||
);
|
||||
});
|
||||
|
||||
function testPokemonTypeMatchesDefaultMoveType(pokemon: PlayerPokemon, move: Moves) {
|
||||
expect(pokemon.summonData.abilitiesApplied).toContain(Abilities.PROTEAN);
|
||||
expect(pokemon.getTypes()).toHaveLength(1);
|
||||
const pokemonType = Type[pokemon.getTypes()[0]],
|
||||
moveType = Type[allMoves[move].defaultType];
|
||||
expect(pokemonType).toBe(moveType);
|
||||
}
|
@ -2,20 +2,18 @@ import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest
|
||||
import Phaser from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import {
|
||||
CommandPhase,
|
||||
EnemyCommandPhase, TurnEndPhase,
|
||||
EnemyCommandPhase, MoveEndPhase, TurnEndPhase,
|
||||
} from "#app/phases";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
import {Moves} from "#app/data/enums/moves";
|
||||
import {getMovePosition} from "#app/test/utils/gameManagerUtils";
|
||||
import {Command} from "#app/ui/command-ui-handler";
|
||||
import { Abilities } from "#app/data/enums/abilities.js";
|
||||
import { Abilities, BattlerTagType, Moves, Species } from "#enums";
|
||||
import { BattleStat } from "#app/data/battle-stat.js";
|
||||
import { TerrainType } from "#app/data/terrain.js";
|
||||
|
||||
// See also: ArenaTypeAbAttr
|
||||
// See also: TypeImmunityAbAttr
|
||||
describe("Abilities - Sap Sipper", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
@ -113,4 +111,28 @@ describe("Abilities - Sap Sipper", () => {
|
||||
expect(game.scene.arena.terrain.terrainType).toBe(TerrainType.GRASSY);
|
||||
expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(0);
|
||||
});
|
||||
|
||||
it("do not activate against status moves that target the user", async() => {
|
||||
const moveToUse = Moves.SPIKY_SHIELD;
|
||||
const ability = Abilities.SAP_SIPPER;
|
||||
|
||||
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
|
||||
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(ability);
|
||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.NONE, Moves.NONE, Moves.NONE]);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.NONE);
|
||||
|
||||
await game.startBattle();
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, moveToUse));
|
||||
|
||||
await game.phaseInterceptor.to(MoveEndPhase);
|
||||
|
||||
expect(game.scene.getParty()[0].getTag(BattlerTagType.SPIKY_SHIELD)).toBeDefined();
|
||||
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(game.scene.getParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(0);
|
||||
expect(game.phaseInterceptor.log).not.toContain("ShowAbilityPhase");
|
||||
});
|
||||
});
|
||||
|
67
src/test/abilities/schooling.test.ts
Normal file
67
src/test/abilities/schooling.test.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import { getMovePosition } from "#test/utils/gameManagerUtils";
|
||||
import * as Overrides from "#app/overrides";
|
||||
import { Moves } from "#enums";
|
||||
import { Abilities } from "#enums";
|
||||
import { Species } from "#enums";
|
||||
import { Status, StatusEffect } from "#app/data/status-effect.js";
|
||||
import { TurnEndPhase } from "#app/phases.js";
|
||||
import { QuietFormChangePhase } from "#app/form-change-phase.js";
|
||||
|
||||
const TIMEOUT = 20 * 1000;
|
||||
|
||||
describe("Abilities - SCHOOLING", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
const moveToUse = Moves.SPLASH;
|
||||
vi.spyOn(Overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(Overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.SCHOOLING);
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
|
||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||
});
|
||||
|
||||
test(
|
||||
"check if fainted pokemon switches to base form on arena reset",
|
||||
async () => {
|
||||
const soloForm = 0,
|
||||
schoolForm = 1;
|
||||
vi.spyOn(Overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(4);
|
||||
vi.spyOn(Overrides, "STARTER_FORM_OVERRIDES", "get").mockReturnValue({
|
||||
[Species.WISHIWASHI]: schoolForm,
|
||||
});
|
||||
|
||||
await game.startBattle([Species.MAGIKARP, Species.WISHIWASHI]);
|
||||
|
||||
const wishiwashi = game.scene.getParty().find((p) => p.species.speciesId === Species.WISHIWASHI);
|
||||
expect(wishiwashi).not.toBe(undefined);
|
||||
expect(wishiwashi.formIndex).toBe(schoolForm);
|
||||
|
||||
wishiwashi.hp = 0;
|
||||
wishiwashi.status = new Status(StatusEffect.FAINT);
|
||||
expect(wishiwashi.isFainted()).toBe(true);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.doKillOpponents();
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
game.doSelectModifier();
|
||||
await game.phaseInterceptor.to(QuietFormChangePhase);
|
||||
|
||||
expect(wishiwashi.formIndex).toBe(soloForm);
|
||||
},
|
||||
TIMEOUT
|
||||
);
|
||||
});
|
67
src/test/abilities/shields_down.test.ts
Normal file
67
src/test/abilities/shields_down.test.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import { getMovePosition } from "#test/utils/gameManagerUtils";
|
||||
import * as Overrides from "#app/overrides";
|
||||
import { Moves } from "#enums";
|
||||
import { Abilities } from "#enums";
|
||||
import { Species } from "#enums";
|
||||
import { Status, StatusEffect } from "#app/data/status-effect.js";
|
||||
import { TurnEndPhase } from "#app/phases.js";
|
||||
import { QuietFormChangePhase } from "#app/form-change-phase.js";
|
||||
|
||||
const TIMEOUT = 20 * 1000;
|
||||
|
||||
describe("Abilities - SHIELDS DOWN", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
const moveToUse = Moves.SPLASH;
|
||||
vi.spyOn(Overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(Overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.SHIELDS_DOWN);
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
|
||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||
});
|
||||
|
||||
test(
|
||||
"check if fainted pokemon switched to base form on arena reset",
|
||||
async () => {
|
||||
const meteorForm = 0,
|
||||
coreForm = 7;
|
||||
vi.spyOn(Overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(4);
|
||||
vi.spyOn(Overrides, "STARTER_FORM_OVERRIDES", "get").mockReturnValue({
|
||||
[Species.MINIOR]: coreForm,
|
||||
});
|
||||
|
||||
await game.startBattle([Species.MAGIKARP, Species.MINIOR]);
|
||||
|
||||
const minior = game.scene.getParty().find((p) => p.species.speciesId === Species.MINIOR);
|
||||
expect(minior).not.toBe(undefined);
|
||||
expect(minior.formIndex).toBe(coreForm);
|
||||
|
||||
minior.hp = 0;
|
||||
minior.status = new Status(StatusEffect.FAINT);
|
||||
expect(minior.isFainted()).toBe(true);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.doKillOpponents();
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
game.doSelectModifier();
|
||||
await game.phaseInterceptor.to(QuietFormChangePhase);
|
||||
|
||||
expect(minior.formIndex).toBe(meteorForm);
|
||||
},
|
||||
TIMEOUT
|
||||
);
|
||||
});
|
53
src/test/abilities/volt_absorb.test.ts
Normal file
53
src/test/abilities/volt_absorb.test.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
|
||||
import Phaser from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import {
|
||||
TurnEndPhase,
|
||||
} from "#app/phases";
|
||||
import {getMovePosition} from "#app/test/utils/gameManagerUtils";
|
||||
import { Abilities, BattlerTagType, Moves, Species } from "#enums";
|
||||
import { BattleStat } from "#app/data/battle-stat.js";
|
||||
|
||||
// See also: TypeImmunityAbAttr
|
||||
describe("Abilities - Volt Absorb", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "NEVER_CRIT_OVERRIDE", "get").mockReturnValue(true);
|
||||
});
|
||||
|
||||
it("does not activate when CHARGE is used", async () => {
|
||||
const moveToUse = Moves.CHARGE;
|
||||
const ability = Abilities.VOLT_ABSORB;
|
||||
|
||||
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
|
||||
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(ability);
|
||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.NONE, Moves.NONE, Moves.NONE]);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.DUSKULL);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.NONE);
|
||||
|
||||
await game.startBattle();
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, moveToUse));
|
||||
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(game.scene.getParty()[0].summonData.battleStats[BattleStat.SPDEF]).toBe(1);
|
||||
expect(game.scene.getParty()[0].getTag(BattlerTagType.CHARGED)).toBeDefined();
|
||||
expect(game.phaseInterceptor.log).not.toContain("ShowAbilityPhase");
|
||||
});
|
||||
});
|
@ -1,9 +1,7 @@
|
||||
import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import Phaser from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import {Abilities} from "#app/data/enums/abilities";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import * as Overrides from "#app/overrides";
|
||||
import {
|
||||
CommandPhase,
|
||||
DamagePhase,
|
||||
@ -12,18 +10,21 @@ import {
|
||||
PostSummonPhase,
|
||||
SwitchPhase,
|
||||
SwitchSummonPhase,
|
||||
TurnEndPhase, TurnInitPhase,
|
||||
TurnEndPhase,
|
||||
TurnInitPhase,
|
||||
TurnStartPhase,
|
||||
} from "#app/phases";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
import {Stat} from "#app/data/pokemon-stat";
|
||||
import {Moves} from "#app/data/enums/moves";
|
||||
import {getMovePosition} from "#app/test/utils/gameManagerUtils";
|
||||
import {Command} from "#app/ui/command-ui-handler";
|
||||
import {QuietFormChangePhase} from "#app/form-change-phase";
|
||||
import { Mode } from "#app/ui/ui";
|
||||
import { Stat } from "#app/data/pokemon-stat";
|
||||
import { Abilities, Moves, Species } from "#enums";
|
||||
import { getMovePosition } from "#app/test/utils/gameManagerUtils";
|
||||
import { Command } from "#app/ui/command-ui-handler";
|
||||
import { QuietFormChangePhase } from "#app/form-change-phase";
|
||||
import { Status, StatusEffect } from "#app/data/status-effect.js";
|
||||
|
||||
const TIMEOUT = 20 * 1000;
|
||||
|
||||
describe("Abilities - Zen mode", () => {
|
||||
describe("Abilities - ZEN MODE", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
@ -40,103 +41,139 @@ describe("Abilities - Zen mode", () => {
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
const moveToUse = Moves.SPLASH;
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.ZEN_MODE);
|
||||
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100);
|
||||
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
|
||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]);
|
||||
vi.spyOn(Overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(Overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
|
||||
vi.spyOn(Overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(Overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.ZEN_MODE);
|
||||
vi.spyOn(Overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100);
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
|
||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||
});
|
||||
|
||||
it("ZEN MODE - not enough damage to change form", async() => {
|
||||
const moveToUse = Moves.SPLASH;
|
||||
await game.startBattle([
|
||||
Species.DARMANITAN,
|
||||
]);
|
||||
game.scene.getParty()[0].stats[Stat.SPD] = 1;
|
||||
game.scene.getParty()[0].stats[Stat.HP] = 100;
|
||||
game.scene.getParty()[0].hp = 100;
|
||||
expect(game.scene.getParty()[0].formIndex).toBe(0);
|
||||
test(
|
||||
"not enough damage to change form",
|
||||
async () => {
|
||||
const moveToUse = Moves.SPLASH;
|
||||
await game.startBattle([Species.DARMANITAN]);
|
||||
game.scene.getParty()[0].stats[Stat.SPD] = 1;
|
||||
game.scene.getParty()[0].stats[Stat.HP] = 100;
|
||||
game.scene.getParty()[0].hp = 100;
|
||||
expect(game.scene.getParty()[0].formIndex).toBe(0);
|
||||
|
||||
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
|
||||
});
|
||||
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
|
||||
const movePosition = getMovePosition(game.scene, 0, moveToUse);
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
|
||||
});
|
||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(DamagePhase, false);
|
||||
// await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false);
|
||||
const damagePhase = game.scene.getCurrentPhase() as DamagePhase;
|
||||
damagePhase.updateAmount(40);
|
||||
await game.phaseInterceptor.runFrom(DamagePhase).to(TurnEndPhase, false);
|
||||
expect(game.scene.getParty()[0].hp).toBeLessThan(100);
|
||||
expect(game.scene.getParty()[0].formIndex).toBe(0);
|
||||
}, 20000);
|
||||
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
|
||||
});
|
||||
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
|
||||
const movePosition = getMovePosition(game.scene, 0, moveToUse);
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
|
||||
});
|
||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(DamagePhase, false);
|
||||
// await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false);
|
||||
const damagePhase = game.scene.getCurrentPhase() as DamagePhase;
|
||||
damagePhase.updateAmount(40);
|
||||
await game.phaseInterceptor.runFrom(DamagePhase).to(TurnEndPhase, false);
|
||||
expect(game.scene.getParty()[0].hp).toBeLessThan(100);
|
||||
expect(game.scene.getParty()[0].formIndex).toBe(0);
|
||||
},
|
||||
TIMEOUT
|
||||
);
|
||||
|
||||
it("ZEN MODE - enough damage to change form", async() => {
|
||||
const moveToUse = Moves.SPLASH;
|
||||
await game.startBattle([
|
||||
Species.DARMANITAN,
|
||||
]);
|
||||
game.scene.getParty()[0].stats[Stat.SPD] = 1;
|
||||
game.scene.getParty()[0].stats[Stat.HP] = 1000;
|
||||
game.scene.getParty()[0].hp = 100;
|
||||
expect(game.scene.getParty()[0].formIndex).toBe(0);
|
||||
test(
|
||||
"enough damage to change form",
|
||||
async () => {
|
||||
const moveToUse = Moves.SPLASH;
|
||||
await game.startBattle([Species.DARMANITAN]);
|
||||
game.scene.getParty()[0].stats[Stat.SPD] = 1;
|
||||
game.scene.getParty()[0].stats[Stat.HP] = 1000;
|
||||
game.scene.getParty()[0].hp = 100;
|
||||
expect(game.scene.getParty()[0].formIndex).toBe(0);
|
||||
|
||||
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
|
||||
});
|
||||
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
|
||||
const movePosition = getMovePosition(game.scene, 0, moveToUse);
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
|
||||
});
|
||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(QuietFormChangePhase);
|
||||
await game.phaseInterceptor.to(TurnInitPhase, false);
|
||||
expect(game.scene.getParty()[0].hp).not.toBe(100);
|
||||
expect(game.scene.getParty()[0].formIndex).not.toBe(0);
|
||||
}, 20000);
|
||||
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
|
||||
});
|
||||
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
|
||||
const movePosition = getMovePosition(game.scene, 0, moveToUse);
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
|
||||
});
|
||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(QuietFormChangePhase);
|
||||
await game.phaseInterceptor.to(TurnInitPhase, false);
|
||||
expect(game.scene.getParty()[0].hp).not.toBe(100);
|
||||
expect(game.scene.getParty()[0].formIndex).not.toBe(0);
|
||||
},
|
||||
TIMEOUT
|
||||
);
|
||||
|
||||
it("ZEN MODE - kill pokemon while on zen mode", async() => {
|
||||
const moveToUse = Moves.SPLASH;
|
||||
await game.startBattle([
|
||||
Species.DARMANITAN,
|
||||
Species.CHARIZARD,
|
||||
]);
|
||||
game.scene.getParty()[0].stats[Stat.SPD] = 1;
|
||||
game.scene.getParty()[0].stats[Stat.HP] = 1000;
|
||||
game.scene.getParty()[0].hp = 100;
|
||||
expect(game.scene.getParty()[0].formIndex).toBe(0);
|
||||
test(
|
||||
"kill pokemon while on zen mode",
|
||||
async () => {
|
||||
const moveToUse = Moves.SPLASH;
|
||||
await game.startBattle([Species.DARMANITAN, Species.CHARIZARD]);
|
||||
game.scene.getParty()[0].stats[Stat.SPD] = 1;
|
||||
game.scene.getParty()[0].stats[Stat.HP] = 1000;
|
||||
game.scene.getParty()[0].hp = 100;
|
||||
expect(game.scene.getParty()[0].formIndex).toBe(0);
|
||||
|
||||
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
|
||||
});
|
||||
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
|
||||
const movePosition = getMovePosition(game.scene, 0, moveToUse);
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
|
||||
});
|
||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(DamagePhase, false);
|
||||
// await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false);
|
||||
const damagePhase = game.scene.getCurrentPhase() as DamagePhase;
|
||||
damagePhase.updateAmount(80);
|
||||
await game.phaseInterceptor.runFrom(DamagePhase).to(QuietFormChangePhase);
|
||||
expect(game.scene.getParty()[0].hp).not.toBe(100);
|
||||
expect(game.scene.getParty()[0].formIndex).not.toBe(0);
|
||||
await game.killPokemon(game.scene.getParty()[0]);
|
||||
expect(game.scene.getParty()[0].isFainted()).toBe(true);
|
||||
await game.phaseInterceptor.run(MessagePhase);
|
||||
await game.phaseInterceptor.run(EnemyCommandPhase);
|
||||
await game.phaseInterceptor.run(TurnStartPhase);
|
||||
game.onNextPrompt("SwitchPhase", Mode.PARTY, () => {
|
||||
game.scene.unshiftPhase(new SwitchSummonPhase(game.scene, 0, 1, false, false));
|
||||
game.scene.ui.setMode(Mode.MESSAGE);
|
||||
});
|
||||
game.onNextPrompt("SwitchPhase", Mode.MESSAGE, () => {
|
||||
game.endPhase();
|
||||
});
|
||||
await game.phaseInterceptor.run(SwitchPhase);
|
||||
await game.phaseInterceptor.to(PostSummonPhase);
|
||||
expect(game.scene.getParty()[1].formIndex).toBe(1);
|
||||
}, 20000);
|
||||
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
|
||||
});
|
||||
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
|
||||
const movePosition = getMovePosition(game.scene, 0, moveToUse);
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
|
||||
});
|
||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(DamagePhase, false);
|
||||
// await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false);
|
||||
const damagePhase = game.scene.getCurrentPhase() as DamagePhase;
|
||||
damagePhase.updateAmount(80);
|
||||
await game.phaseInterceptor.runFrom(DamagePhase).to(QuietFormChangePhase);
|
||||
expect(game.scene.getParty()[0].hp).not.toBe(100);
|
||||
expect(game.scene.getParty()[0].formIndex).not.toBe(0);
|
||||
await game.killPokemon(game.scene.getParty()[0]);
|
||||
expect(game.scene.getParty()[0].isFainted()).toBe(true);
|
||||
await game.phaseInterceptor.run(MessagePhase);
|
||||
await game.phaseInterceptor.run(EnemyCommandPhase);
|
||||
await game.phaseInterceptor.run(TurnStartPhase);
|
||||
game.onNextPrompt("SwitchPhase", Mode.PARTY, () => {
|
||||
game.scene.unshiftPhase(new SwitchSummonPhase(game.scene, 0, 1, false, false));
|
||||
game.scene.ui.setMode(Mode.MESSAGE);
|
||||
});
|
||||
game.onNextPrompt("SwitchPhase", Mode.MESSAGE, () => {
|
||||
game.endPhase();
|
||||
});
|
||||
await game.phaseInterceptor.run(SwitchPhase);
|
||||
await game.phaseInterceptor.to(PostSummonPhase);
|
||||
expect(game.scene.getParty()[1].formIndex).toBe(1);
|
||||
},
|
||||
TIMEOUT
|
||||
);
|
||||
|
||||
test(
|
||||
"check if fainted pokemon switches to base form on arena reset",
|
||||
async () => {
|
||||
const baseForm = 0,
|
||||
zenForm = 1;
|
||||
vi.spyOn(Overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(4);
|
||||
vi.spyOn(Overrides, "STARTER_FORM_OVERRIDES", "get").mockReturnValue({
|
||||
[Species.DARMANITAN]: zenForm,
|
||||
});
|
||||
|
||||
await game.startBattle([Species.MAGIKARP, Species.DARMANITAN]);
|
||||
|
||||
const darmanitan = game.scene.getParty().find((p) => p.species.speciesId === Species.DARMANITAN);
|
||||
expect(darmanitan).not.toBe(undefined);
|
||||
expect(darmanitan.formIndex).toBe(zenForm);
|
||||
|
||||
darmanitan.hp = 0;
|
||||
darmanitan.status = new Status(StatusEffect.FAINT);
|
||||
expect(darmanitan.isFainted()).toBe(true);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.doKillOpponents();
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
game.doSelectModifier();
|
||||
await game.phaseInterceptor.to(QuietFormChangePhase);
|
||||
|
||||
expect(darmanitan.formIndex).toBe(baseForm);
|
||||
},
|
||||
TIMEOUT
|
||||
);
|
||||
});
|
||||
|
67
src/test/abilities/zero_to_hero.test.ts
Normal file
67
src/test/abilities/zero_to_hero.test.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import { getMovePosition } from "#test/utils/gameManagerUtils";
|
||||
import * as Overrides from "#app/overrides";
|
||||
import { Moves } from "#enums";
|
||||
import { Abilities } from "#enums";
|
||||
import { Species } from "#enums";
|
||||
import { Status, StatusEffect } from "#app/data/status-effect.js";
|
||||
import { TurnEndPhase } from "#app/phases.js";
|
||||
import { QuietFormChangePhase } from "#app/form-change-phase.js";
|
||||
|
||||
const TIMEOUT = 20 * 1000;
|
||||
|
||||
describe("Abilities - ZERO TO HERO", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
const moveToUse = Moves.SPLASH;
|
||||
vi.spyOn(Overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(Overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.ZERO_TO_HERO);
|
||||
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
|
||||
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||
});
|
||||
|
||||
test(
|
||||
"check if fainted pokemon switches to base form on arena reset",
|
||||
async () => {
|
||||
const baseForm = 0,
|
||||
heroForm = 1;
|
||||
vi.spyOn(Overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(4);
|
||||
vi.spyOn(Overrides, "STARTER_FORM_OVERRIDES", "get").mockReturnValue({
|
||||
[Species.PALAFIN]: heroForm,
|
||||
});
|
||||
|
||||
await game.startBattle([Species.MAGIKARP, Species.PALAFIN]);
|
||||
|
||||
const palafin = game.scene.getParty().find((p) => p.species.speciesId === Species.PALAFIN);
|
||||
expect(palafin).not.toBe(undefined);
|
||||
expect(palafin.formIndex).toBe(heroForm);
|
||||
|
||||
palafin.hp = 0;
|
||||
palafin.status = new Status(StatusEffect.FAINT);
|
||||
expect(palafin.isFainted()).toBe(true);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||
await game.doKillOpponents();
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
game.doSelectModifier();
|
||||
await game.phaseInterceptor.to(QuietFormChangePhase);
|
||||
|
||||
expect(palafin.formIndex).toBe(baseForm);
|
||||
},
|
||||
TIMEOUT
|
||||
);
|
||||
});
|
@ -2,19 +2,16 @@ import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest
|
||||
import Phaser from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import {Abilities} from "#app/data/enums/abilities";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import {Abilities, Species, Moves, Button} from "#enums";
|
||||
import {
|
||||
CommandPhase, EnemyCommandPhase, SelectTargetPhase,
|
||||
TurnStartPhase
|
||||
} from "#app/phases";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
import {getMovePosition} from "#app/test/utils/gameManagerUtils";
|
||||
import {Moves} from "#app/data/enums/moves";
|
||||
import {Command} from "#app/ui/command-ui-handler";
|
||||
import {Stat} from "#app/data/pokemon-stat";
|
||||
import TargetSelectUiHandler from "#app/ui/target-select-ui-handler";
|
||||
import {Button} from "#app/enums/buttons";
|
||||
|
||||
|
||||
describe("Battle order", () => {
|
||||
|
@ -2,7 +2,7 @@ import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest
|
||||
import {generateStarter, getMovePosition,} from "#app/test/utils/gameManagerUtils";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
import {GameModes} from "#app/game-mode";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import {Species, Moves, PlayerGender, Abilities} from "#enums";
|
||||
import * as overrides from "../../overrides";
|
||||
import {Command} from "#app/ui/command-ui-handler";
|
||||
import {
|
||||
@ -17,13 +17,10 @@ import {
|
||||
TitlePhase,
|
||||
TurnInitPhase, VictoryPhase,
|
||||
} from "#app/phases";
|
||||
import {Moves} from "#app/data/enums/moves";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import {allSpecies} from "#app/data/pokemon-species";
|
||||
import {PlayerGender} from "#app/data/enums/player-gender";
|
||||
import { getGameMode } from "#app/game-mode.js";
|
||||
import {Abilities} from "#app/data/enums/abilities";
|
||||
|
||||
describe("Test Battle Phase", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
|
@ -2,9 +2,7 @@ import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import * as overrides from "#app/overrides";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import {Moves} from "#app/data/enums/moves";
|
||||
import {Abilities} from "#app/data/enums/abilities";
|
||||
import {Species, Moves, Abilities} from "#enums";
|
||||
|
||||
describe("Test Battle Phase", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
|
@ -1,14 +1,12 @@
|
||||
import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import {Species, Moves, Abilities} from "#enums";
|
||||
import * as overrides from "../../overrides";
|
||||
import {
|
||||
CommandPhase,
|
||||
} from "#app/phases";
|
||||
import {Moves} from "#app/data/enums/moves";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import {Abilities} from "#app/data/enums/abilities";
|
||||
|
||||
describe("Test Battle Phase", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {beforeAll, describe, expect, it} from "vitest";
|
||||
import BattleScene from "../../battle-scene";
|
||||
import { getLegendaryGachaSpeciesForTimestamp } from "#app/data/egg.js";
|
||||
import { Species } from "#app/data/enums/species.js";
|
||||
import { Species } from "#enums";
|
||||
import Phaser from "phaser";
|
||||
|
||||
describe("getLegendaryGachaSpeciesForTimestamp", () => {
|
||||
|
@ -5,7 +5,7 @@ async function importModule() {
|
||||
try {
|
||||
initStatsKeys();
|
||||
const { PokemonMove } = await import("#app/field/pokemon");
|
||||
const { Species } = await import("#app/data/enums/species");
|
||||
const { Species } = await import("#enums");
|
||||
return {
|
||||
PokemonMove,
|
||||
Species,
|
||||
|
@ -2,8 +2,7 @@ import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest
|
||||
import Phaser from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import {Abilities} from "#app/data/enums/abilities";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import {Abilities, Moves, Species} from "#enums";
|
||||
import {
|
||||
CommandPhase,
|
||||
EnemyCommandPhase,
|
||||
@ -11,7 +10,6 @@ import {
|
||||
TurnEndPhase,
|
||||
} from "#app/phases";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
import {Moves} from "#app/data/enums/moves";
|
||||
import {getMovePosition} from "#app/test/utils/gameManagerUtils";
|
||||
import {Command} from "#app/ui/command-ui-handler";
|
||||
import {StatusEffect} from "#app/data/status-effect";
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {afterEach, beforeAll, describe, expect, it} from "vitest";
|
||||
import Phaser from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import {Species} from "#enums";
|
||||
import i18next from "i18next";
|
||||
import {initI18n} from "#app/plugins/i18n";
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user