Merge remote-tracking branch 'upstream/main' into fix/damp

This commit is contained in:
zacharied 2024-06-18 16:47:24 -04:00
commit 033a79805c
379 changed files with 4223 additions and 1109 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

54
src/@types/i18next.d.ts vendored Normal file
View File

@ -0,0 +1,54 @@
import { AbilityTranslationEntries, SimpleTranslationEntries, AchievementTranslationEntries, BerryTranslationEntries, DialogueTranslationEntries, ModifierTypeTranslationEntries, MoveTranslationEntries, PokemonInfoTranslationEntries } from "#app/interfaces/locales";
// Module declared to make referencing keys in the localization files type-safe.
declare module "i18next" {
interface CustomTypeOptions {
defaultNS: "menu", // needed here as well for typedoc
resources: {
ability: AbilityTranslationEntries;
abilityTriggers: SimpleTranslationEntries;
achv: AchievementTranslationEntries;
battle: SimpleTranslationEntries;
battleMessageUiHandler: SimpleTranslationEntries;
berry: BerryTranslationEntries;
biome: SimpleTranslationEntries;
challenges: SimpleTranslationEntries;
commandUiHandler: SimpleTranslationEntries;
PGMachv: AchievementTranslationEntries;
PGFachv: AchievementTranslationEntries;
PGMdialogue: DialogueTranslationEntries;
PGFdialogue: DialogueTranslationEntries;
PGMbattleSpecDialogue: SimpleTranslationEntries;
PGFbattleSpecDialogue: SimpleTranslationEntries;
PGMmiscDialogue: SimpleTranslationEntries;
PGFmiscDialogue: SimpleTranslationEntries;
PGMdoubleBattleDialogue: DialogueTranslationEntries;
PGFdoubleBattleDialogue: DialogueTranslationEntries;
egg: SimpleTranslationEntries;
fightUiHandler: SimpleTranslationEntries;
gameMode: SimpleTranslationEntries;
gameStatsUiHandler: SimpleTranslationEntries;
growth: SimpleTranslationEntries;
menu: SimpleTranslationEntries;
menuUiHandler: SimpleTranslationEntries;
modifierType: ModifierTypeTranslationEntries;
move: MoveTranslationEntries;
nature: SimpleTranslationEntries;
partyUiHandler: SimpleTranslationEntries;
pokeball: SimpleTranslationEntries;
pokemon: SimpleTranslationEntries;
pokemonInfo: PokemonInfoTranslationEntries;
pokemonInfoContainer: SimpleTranslationEntries;
saveSlotSelectUiHandler: SimpleTranslationEntries;
settings: SimpleTranslationEntries;
splashMessages: SimpleTranslationEntries;
starterSelectUiHandler: SimpleTranslationEntries;
titles: SimpleTranslationEntries;
trainerClasses: SimpleTranslationEntries;
trainerNames: SimpleTranslationEntries;
tutorial: SimpleTranslationEntries;
voucher: SimpleTranslationEntries;
weather: SimpleTranslationEntries;
};
}
}

View File

@ -7,6 +7,7 @@ export interface UserInfo {
} }
export let loggedInUser: UserInfo = null; export let loggedInUser: UserInfo = null;
// This is a random string that is used to identify the client session - unique per session (tab or window) so that the game will only save on the one that the server is expecting
export const clientSessionId = Utils.randomString(32); export const clientSessionId = Utils.randomString(32);
export function initLoggedInUser(): void { export function initLoggedInUser(): void {

View File

@ -47,7 +47,7 @@ import { biomeDepths, getBiomeName } from "./data/biomes";
import { SceneBase } from "./scene-base"; import { SceneBase } from "./scene-base";
import CandyBar from "./ui/candy-bar"; import CandyBar from "./ui/candy-bar";
import { Variant, variantData } from "./data/variant"; import { Variant, variantData } from "./data/variant";
import { Localizable } from "./plugins/i18n"; import { Localizable } from "#app/interfaces/locales";
import * as Overrides from "./overrides"; import * as Overrides from "./overrides";
import {InputsController} from "./inputs-controller"; import {InputsController} from "./inputs-controller";
import {UiInputs} from "./ui-inputs"; import {UiInputs} from "./ui-inputs";

182
src/data/ability.ts Executable file → Normal file
View File

@ -14,7 +14,8 @@ import { Stat, getStatName } from "./pokemon-stat";
import { BerryModifier, PokemonHeldItemModifier } from "../modifier/modifier"; import { BerryModifier, PokemonHeldItemModifier } from "../modifier/modifier";
import { TerrainType } from "./terrain"; import { TerrainType } from "./terrain";
import { SpeciesFormChangeManualTrigger } from "./pokemon-forms"; import { SpeciesFormChangeManualTrigger } from "./pokemon-forms";
import i18next, { Localizable } from "#app/plugins/i18n.js"; import i18next from "i18next";
import { Localizable } from "#app/interfaces/locales.js";
import { Command } from "../ui/command-ui-handler"; import { Command } from "../ui/command-ui-handler";
import { BerryModifierType } from "#app/modifier/modifier-type"; import { BerryModifierType } from "#app/modifier/modifier-type";
import { getPokeballName } from "./pokeball"; import { getPokeballName } from "./pokeball";
@ -1044,6 +1045,56 @@ export class PreAttackAbAttr extends AbAttr {
} }
} }
/**
* Modifies moves additional effects with multipliers, ie. Sheer Force, Serene Grace.
* @extends AbAttr
* @see {@linkcode apply}
*/
export class MoveEffectChanceMultiplierAbAttr extends AbAttr {
private chanceMultiplier: number;
constructor(chanceMultiplier?: number) {
super(true);
this.chanceMultiplier = chanceMultiplier;
}
/**
* @param args [0]: {@linkcode Utils.NumberHolder} Move additional effect chance. Has to be higher than or equal to 0.
* [1]: {@linkcode Moves } Move used by the ability user.
*/
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if ((args[0] as Utils.NumberHolder).value <= 0 || (args[1] as Move).id === Moves.ORDER_UP) {
return false;
}
(args[0] as Utils.NumberHolder).value *= this.chanceMultiplier;
(args[0] as Utils.NumberHolder).value = Math.min((args[0] as Utils.NumberHolder).value, 100);
return true;
}
}
/**
* Sets incoming moves additional effect chance to zero, ignoring all effects from moves. ie. Shield Dust.
* @extends PreDefendAbAttr
* @see {@linkcode applyPreDefend}
*/
export class IgnoreMoveEffectsAbAttr extends PreDefendAbAttr {
/**
* @param args [0]: {@linkcode Utils.NumberHolder} Move additional effect chance.
*/
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if ((args[0] as Utils.NumberHolder).value <= 0) {
return false;
}
(args[0] as Utils.NumberHolder).value = 0;
return true;
}
}
export class VariableMovePowerAbAttr extends PreAttackAbAttr { export class VariableMovePowerAbAttr extends PreAttackAbAttr {
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean { applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean {
//const power = args[0] as Utils.NumberHolder; //const power = args[0] as Utils.NumberHolder;
@ -1275,17 +1326,18 @@ export class VariableMovePowerBoostAbAttr extends VariableMovePowerAbAttr {
} }
} }
export class FieldVariableMovePowerAbAttr extends AbAttr { /**
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean { * Boosts the power of a Pokémon's move under certain conditions.
//const power = args[0] as Utils.NumberHolder; * @extends AbAttr
return false; */
} export class FieldMovePowerBoostAbAttr extends AbAttr {
}
export class FieldMovePowerBoostAbAttr extends FieldVariableMovePowerAbAttr {
private condition: PokemonAttackCondition; private condition: PokemonAttackCondition;
private powerMultiplier: number; private powerMultiplier: number;
/**
* @param condition - A function that determines whether the power boost condition is met.
* @param powerMultiplier - The multiplier to apply to the move's power when the condition is met.
*/
constructor(condition: PokemonAttackCondition, powerMultiplier: number) { constructor(condition: PokemonAttackCondition, powerMultiplier: number) {
super(false); super(false);
this.condition = condition; this.condition = condition;
@ -1303,12 +1355,34 @@ export class FieldMovePowerBoostAbAttr extends FieldVariableMovePowerAbAttr {
} }
} }
/**
* Boosts the power of a specific type of move.
* @extends FieldMovePowerBoostAbAttr
*/
export class FieldMoveTypePowerBoostAbAttr extends FieldMovePowerBoostAbAttr { export class FieldMoveTypePowerBoostAbAttr extends FieldMovePowerBoostAbAttr {
/**
* @param boostedType - The type of move that will receive the power boost.
* @param powerMultiplier - The multiplier to apply to the move's power, defaults to 1.5 if not provided.
*/
constructor(boostedType: Type, powerMultiplier?: number) { constructor(boostedType: Type, powerMultiplier?: number) {
super((pokemon, defender, move) => move.type === boostedType, powerMultiplier || 1.5); super((pokemon, defender, move) => move.type === boostedType, powerMultiplier || 1.5);
} }
} }
/**
* Boosts the power of moves in specified categories.
* @extends FieldMovePowerBoostAbAttr
*/
export class AllyMoveCategoryPowerBoostAbAttr extends FieldMovePowerBoostAbAttr {
/**
* @param boostedCategories - The categories of moves that will receive the power boost.
* @param powerMultiplier - The multiplier to apply to the move's power.
*/
constructor(boostedCategories: MoveCategory[], powerMultiplier: number) {
super((pokemon, defender, move) => boostedCategories.includes(move.category), powerMultiplier);
}
}
export class BattleStatMultiplierAbAttr extends AbAttr { export class BattleStatMultiplierAbAttr extends AbAttr {
private battleStat: BattleStat; private battleStat: BattleStat;
private multiplier: number; private multiplier: number;
@ -1387,7 +1461,8 @@ export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr {
} }
applyPostAttack(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { applyPostAttack(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
if (pokemon !== attacker && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) { /**Status inflicted by abilities post attacking are also considered additional effects.*/
if (!attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) {
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)]; const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
return attacker.trySetStatus(effect, true, pokemon); return attacker.trySetStatus(effect, true, pokemon);
} }
@ -1417,10 +1492,9 @@ export class PostAttackApplyBattlerTagAbAttr extends PostAttackAbAttr {
} }
applyPostAttack(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { applyPostAttack(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
if (pokemon !== attacker && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance(attacker, pokemon, move) && !pokemon.status) { /**Battler tags inflicted by abilities post attacking are also considered additional effects.*/
if (!attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance(attacker, pokemon, move) && !pokemon.status) {
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)]; const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
return attacker.addTag(effect); return attacker.addTag(effect);
} }
@ -1625,6 +1699,28 @@ export class PostSummonAbAttr extends AbAttr {
return false; return false;
} }
} }
/**
* Removes specified arena tags when a Pokemon is summoned.
*/
export class PostSummonRemoveArenaTagAbAttr extends PostSummonAbAttr {
private arenaTags: ArenaTagType[];
/**
* @param arenaTags {@linkcode ArenaTagType[]} - the arena tags to be removed
*/
constructor(arenaTags: ArenaTagType[]) {
super(true);
this.arenaTags = arenaTags;
}
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise<boolean> {
for (const arenaTag of this.arenaTags) {
pokemon.scene.arena.removeTag(arenaTag);
}
return true;
}
}
export class PostSummonMessageAbAttr extends PostSummonAbAttr { export class PostSummonMessageAbAttr extends PostSummonAbAttr {
private messageFunc: (pokemon: Pokemon) => string; private messageFunc: (pokemon: Pokemon) => string;
@ -2349,6 +2445,35 @@ export class SuppressWeatherEffectAbAttr extends PreWeatherEffectAbAttr {
} }
} }
/**
* Condition function to applied to abilities related to Sheer Force.
* Checks if last move used against target was affected by a Sheer Force user and:
* Disables: Color Change, Pickpocket, Wimp Out, Emergency Exit, Berserk, Anger Shell
* @returns {AbAttrCondition} If false disables the ability which the condition is applied to.
*/
function getSheerForceHitDisableAbCondition(): AbAttrCondition {
return (pokemon: Pokemon) => {
if (!pokemon.turnData) {
return true;
}
const lastReceivedAttack = pokemon.turnData.attacksReceived[0];
if (!lastReceivedAttack) {
return true;
}
const lastAttacker = pokemon.getOpponents().find(p => p.id === lastReceivedAttack.sourceId);
if (!lastAttacker) {
return true;
}
/**if the last move chance is greater than or equal to cero, and the last attacker's ability is sheer force*/
const SheerForceAffected = allMoves[lastReceivedAttack.move].chance >= 0 && lastAttacker.hasAbility(Abilities.SHEER_FORCE);
return !SheerForceAffected;
};
}
function getWeatherCondition(...weatherTypes: WeatherType[]): AbAttrCondition { function getWeatherCondition(...weatherTypes: WeatherType[]): AbAttrCondition {
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
if (pokemon.scene.arena.weather?.isEffectSuppressed(pokemon.scene)) { if (pokemon.scene.arena.weather?.isEffectSuppressed(pokemon.scene)) {
@ -3925,7 +4050,8 @@ export function initAbilities() {
.attr(BattlerTagImmunityAbAttr, BattlerTagType.DROWSY) .attr(BattlerTagImmunityAbAttr, BattlerTagType.DROWSY)
.ignorable(), .ignorable(),
new Ability(Abilities.COLOR_CHANGE, 3) new Ability(Abilities.COLOR_CHANGE, 3)
.attr(PostDefendTypeChangeAbAttr), .attr(PostDefendTypeChangeAbAttr)
.condition(getSheerForceHitDisableAbCondition()),
new Ability(Abilities.IMMUNITY, 3) new Ability(Abilities.IMMUNITY, 3)
.attr(StatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC) .attr(StatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
.ignorable(), .ignorable(),
@ -3933,8 +4059,8 @@ export function initAbilities() {
.attr(TypeImmunityAddBattlerTagAbAttr, Type.FIRE, BattlerTagType.FIRE_BOOST, 1, (pokemon: Pokemon) => !pokemon.status || pokemon.status.effect !== StatusEffect.FREEZE) .attr(TypeImmunityAddBattlerTagAbAttr, Type.FIRE, BattlerTagType.FIRE_BOOST, 1, (pokemon: Pokemon) => !pokemon.status || pokemon.status.effect !== StatusEffect.FREEZE)
.ignorable(), .ignorable(),
new Ability(Abilities.SHIELD_DUST, 3) new Ability(Abilities.SHIELD_DUST, 3)
.ignorable() .attr(IgnoreMoveEffectsAbAttr)
.unimplemented(), .partial(),
new Ability(Abilities.OWN_TEMPO, 3) new Ability(Abilities.OWN_TEMPO, 3)
.attr(BattlerTagImmunityAbAttr, BattlerTagType.CONFUSED) .attr(BattlerTagImmunityAbAttr, BattlerTagType.CONFUSED)
.attr(IntimidateImmunityAbAttr) .attr(IntimidateImmunityAbAttr)
@ -3977,7 +4103,8 @@ export function initAbilities() {
.attr(TypeImmunityStatChangeAbAttr, Type.ELECTRIC, BattleStat.SPATK, 1) .attr(TypeImmunityStatChangeAbAttr, Type.ELECTRIC, BattleStat.SPATK, 1)
.ignorable(), .ignorable(),
new Ability(Abilities.SERENE_GRACE, 3) new Ability(Abilities.SERENE_GRACE, 3)
.unimplemented(), .attr(MoveEffectChanceMultiplierAbAttr, 2)
.partial(),
new Ability(Abilities.SWIFT_SWIM, 3) new Ability(Abilities.SWIFT_SWIM, 3)
.attr(BattleStatMultiplierAbAttr, BattleStat.SPD, 2) .attr(BattleStatMultiplierAbAttr, BattleStat.SPD, 2)
.condition(getWeatherCondition(WeatherType.RAIN, WeatherType.HEAVY_RAIN)), .condition(getWeatherCondition(WeatherType.RAIN, WeatherType.HEAVY_RAIN)),
@ -4253,9 +4380,12 @@ export function initAbilities() {
new Ability(Abilities.BAD_DREAMS, 4) new Ability(Abilities.BAD_DREAMS, 4)
.attr(PostTurnHurtIfSleepingAbAttr), .attr(PostTurnHurtIfSleepingAbAttr),
new Ability(Abilities.PICKPOCKET, 5) new Ability(Abilities.PICKPOCKET, 5)
.attr(PostDefendStealHeldItemAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT)), .attr(PostDefendStealHeldItemAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT))
.condition(getSheerForceHitDisableAbCondition()),
new Ability(Abilities.SHEER_FORCE, 5) new Ability(Abilities.SHEER_FORCE, 5)
.unimplemented(), .attr(MovePowerBoostAbAttr, (user, target, move) => move.chance >= 1, 5461/4096)
.attr(MoveEffectChanceMultiplierAbAttr, 0)
.partial(),
new Ability(Abilities.CONTRARY, 5) new Ability(Abilities.CONTRARY, 5)
.attr(StatChangeMultiplierAbAttr, -1) .attr(StatChangeMultiplierAbAttr, -1)
.ignorable(), .ignorable(),
@ -4464,8 +4594,10 @@ export function initAbilities() {
new Ability(Abilities.STAMINA, 7) new Ability(Abilities.STAMINA, 7)
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, BattleStat.DEF, 1), .attr(PostDefendStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, BattleStat.DEF, 1),
new Ability(Abilities.WIMP_OUT, 7) new Ability(Abilities.WIMP_OUT, 7)
.condition(getSheerForceHitDisableAbCondition())
.unimplemented(), .unimplemented(),
new Ability(Abilities.EMERGENCY_EXIT, 7) new Ability(Abilities.EMERGENCY_EXIT, 7)
.condition(getSheerForceHitDisableAbCondition())
.unimplemented(), .unimplemented(),
new Ability(Abilities.WATER_COMPACTION, 7) new Ability(Abilities.WATER_COMPACTION, 7)
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.type === Type.WATER && move.category !== MoveCategory.STATUS, BattleStat.DEF, 2), .attr(PostDefendStatChangeAbAttr, (target, user, move) => move.type === Type.WATER && move.category !== MoveCategory.STATUS, BattleStat.DEF, 2),
@ -4491,7 +4623,8 @@ export function initAbilities() {
new Ability(Abilities.STEELWORKER, 7) new Ability(Abilities.STEELWORKER, 7)
.attr(MoveTypePowerBoostAbAttr, Type.STEEL), .attr(MoveTypePowerBoostAbAttr, Type.STEEL),
new Ability(Abilities.BERSERK, 7) new Ability(Abilities.BERSERK, 7)
.attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [BattleStat.SPATK], 1), .attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [BattleStat.SPATK], 1)
.condition(getSheerForceHitDisableAbCondition()),
new Ability(Abilities.SLUSH_RUSH, 7) new Ability(Abilities.SLUSH_RUSH, 7)
.attr(BattleStatMultiplierAbAttr, BattleStat.SPD, 2) .attr(BattleStatMultiplierAbAttr, BattleStat.SPD, 2)
.condition(getWeatherCondition(WeatherType.HAIL, WeatherType.SNOW)), .condition(getWeatherCondition(WeatherType.HAIL, WeatherType.SNOW)),
@ -4565,7 +4698,7 @@ export function initAbilities() {
new Ability(Abilities.DANCER, 7) new Ability(Abilities.DANCER, 7)
.attr(PostDancingMoveAbAttr), .attr(PostDancingMoveAbAttr),
new Ability(Abilities.BATTERY, 7) new Ability(Abilities.BATTERY, 7)
.unimplemented(), .attr(AllyMoveCategoryPowerBoostAbAttr, [MoveCategory.SPECIAL], 1.3),
new Ability(Abilities.FLUFFY, 7) new Ability(Abilities.FLUFFY, 7)
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), 0.5) .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), 0.5)
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.type === Type.FIRE, 2) .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.type === Type.FIRE, 2)
@ -4677,11 +4810,11 @@ export function initAbilities() {
.attr(IceFaceMoveImmunityAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL && !!target.getTag(BattlerTagType.ICE_FACE)) .attr(IceFaceMoveImmunityAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL && !!target.getTag(BattlerTagType.ICE_FACE))
.ignorable(), .ignorable(),
new Ability(Abilities.POWER_SPOT, 8) new Ability(Abilities.POWER_SPOT, 8)
.unimplemented(), .attr(AllyMoveCategoryPowerBoostAbAttr, [MoveCategory.SPECIAL, MoveCategory.PHYSICAL], 1.3),
new Ability(Abilities.MIMICRY, 8) new Ability(Abilities.MIMICRY, 8)
.unimplemented(), .unimplemented(),
new Ability(Abilities.SCREEN_CLEANER, 8) new Ability(Abilities.SCREEN_CLEANER, 8)
.unimplemented(), .attr(PostSummonRemoveArenaTagAbAttr, [ArenaTagType.AURORA_VEIL, ArenaTagType.LIGHT_SCREEN, ArenaTagType.REFLECT]),
new Ability(Abilities.STEELY_SPIRIT, 8) new Ability(Abilities.STEELY_SPIRIT, 8)
.attr(MoveTypePowerBoostAbAttr, Type.STEEL) .attr(MoveTypePowerBoostAbAttr, Type.STEEL)
.partial(), .partial(),
@ -4750,7 +4883,8 @@ export function initAbilities() {
.ignorable(), .ignorable(),
new Ability(Abilities.ANGER_SHELL, 9) new Ability(Abilities.ANGER_SHELL, 9)
.attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [ BattleStat.ATK, BattleStat.SPATK, BattleStat.SPD ], 1) .attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [ BattleStat.ATK, BattleStat.SPATK, BattleStat.SPD ], 1)
.attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [ BattleStat.DEF, BattleStat.SPDEF ], -1), .attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [ BattleStat.DEF, BattleStat.SPDEF ], -1)
.condition(getSheerForceHitDisableAbCondition()),
new Ability(Abilities.PURIFYING_SALT, 9) new Ability(Abilities.PURIFYING_SALT, 9)
.attr(StatusEffectImmunityAbAttr) .attr(StatusEffectImmunityAbAttr)
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.GHOST, 0.5) .attr(ReceivedTypeDamageMultiplierAbAttr, Type.GHOST, 0.5)

View File

@ -633,6 +633,11 @@ export class GravityTag extends ArenaTag {
onAdd(arena: Arena): void { onAdd(arena: Arena): void {
arena.scene.queueMessage("Gravity intensified!"); arena.scene.queueMessage("Gravity intensified!");
arena.scene.getField(true).forEach((pokemon) => {
if (pokemon !== null) {
pokemon.removeTag(BattlerTagType.MAGNET_RISEN);
}
});
} }
onRemove(arena: Arena): void { onRemove(arena: Arena): void {

View File

@ -1009,6 +1009,33 @@ export class PerishSongTag extends BattlerTag {
} }
} }
/**
* Applies the "Center of Attention" volatile status effect, the effect applied by Follow Me, Rage Powder, and Spotlight.
* @see {@link https://bulbapedia.bulbagarden.net/wiki/Center_of_attention | Center of Attention}
*/
export class CenterOfAttentionTag extends BattlerTag {
public powder: boolean;
constructor(sourceMove: Moves) {
super(BattlerTagType.CENTER_OF_ATTENTION, BattlerTagLapseType.TURN_END, 1, sourceMove);
this.powder = (this.sourceMove === Moves.RAGE_POWDER);
}
/** "Center of Attention" can't be added if an ally is already the Center of Attention. */
canAdd(pokemon: Pokemon): boolean {
const activeTeam = pokemon.isPlayer() ? pokemon.scene.getPlayerField() : pokemon.scene.getEnemyField();
return !activeTeam.find(p => p.getTag(BattlerTagType.CENTER_OF_ATTENTION));
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " became the center\nof attention!"));
}
}
export class AbilityBattlerTag extends BattlerTag { export class AbilityBattlerTag extends BattlerTag {
public ability: Abilities; public ability: Abilities;
@ -1187,8 +1214,11 @@ export class HideSpriteTag extends BattlerTag {
export class TypeImmuneTag extends BattlerTag { export class TypeImmuneTag extends BattlerTag {
public immuneType: Type; public immuneType: Type;
constructor(tagType: BattlerTagType, sourceMove: Moves, immuneType: Type, length: number) {
super(tagType, BattlerTagLapseType.TURN_END, 1, sourceMove); constructor(tagType: BattlerTagType, sourceMove: Moves, immuneType: Type, length: number = 1) {
super(tagType, BattlerTagLapseType.TURN_END, length, sourceMove);
this.immuneType = immuneType;
} }
/** /**
@ -1205,6 +1235,18 @@ export class MagnetRisenTag extends TypeImmuneTag {
constructor(tagType: BattlerTagType, sourceMove: Moves) { constructor(tagType: BattlerTagType, sourceMove: Moves) {
super(tagType, sourceMove, Type.GROUND, 5); super(tagType, sourceMove, Type.GROUND, 5);
} }
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " levitated with electromagnetism!"));
}
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " stopped levitating!"));
}
} }
export class TypeBoostTag extends BattlerTag { export class TypeBoostTag extends BattlerTag {
@ -1479,6 +1521,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
return new SturdyTag(sourceMove); return new SturdyTag(sourceMove);
case BattlerTagType.PERISH_SONG: case BattlerTagType.PERISH_SONG:
return new PerishSongTag(turnCount); return new PerishSongTag(turnCount);
case BattlerTagType.CENTER_OF_ATTENTION:
return new CenterOfAttentionTag(sourceMove);
case BattlerTagType.TRUANT: case BattlerTagType.TRUANT:
return new TruantTag(); return new TruantTag();
case BattlerTagType.SLOW_START: case BattlerTagType.SLOW_START:

View File

@ -5,7 +5,7 @@ import { BattleStat } from "./battle-stat";
import { getStatusEffectHealText } from "./status-effect"; import { getStatusEffectHealText } from "./status-effect";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { DoubleBerryEffectAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs } from "./ability"; import { DoubleBerryEffectAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs } from "./ability";
import i18next from "../plugins/i18n"; import i18next from "i18next";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { BerryType } from "#enums/berry-type"; import { BerryType } from "#enums/berry-type";

View File

@ -1,12 +1,14 @@
import * as Utils from "../utils"; import * as Utils from "../utils";
import i18next from "#app/plugins/i18n.js"; import i18next from "i18next";
import { GameData } from "#app/system/game-data.js"; import { DexAttrProps, GameData } from "#app/system/game-data.js";
import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./pokemon-species"; import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm, speciesStarters } from "./pokemon-species";
import Pokemon from "#app/field/pokemon.js"; import Pokemon from "#app/field/pokemon.js";
import { BattleType, FixedBattleConfig } from "#app/battle.js"; import { BattleType, FixedBattleConfig } from "#app/battle.js";
import Trainer, { TrainerVariant } from "#app/field/trainer.js"; import Trainer, { TrainerVariant } from "#app/field/trainer.js";
import { GameMode } from "#app/game-mode.js"; import { GameMode } from "#app/game-mode.js";
import { Type } from "./type"; import { Type } from "./type";
import { pokemonEvolutions } from "./pokemon-evolutions";
import { pokemonFormChanges } from "./pokemon-forms";
import { Challenges } from "#enums/challenges"; import { Challenges } from "#enums/challenges";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
@ -277,8 +279,22 @@ export class SingleGenerationChallenge extends Challenge {
case ChallengeType.STARTER_CHOICE: case ChallengeType.STARTER_CHOICE:
const species = args[0] as PokemonSpecies; const species = args[0] as PokemonSpecies;
const isValidStarter = args[1] as Utils.BooleanHolder; const isValidStarter = args[1] as Utils.BooleanHolder;
const amountOfPokemon = args[3] as number;
const starterGeneration = species.speciesId === Species.VICTINI ? 5 : species.generation; const starterGeneration = species.speciesId === Species.VICTINI ? 5 : species.generation;
if (starterGeneration !== this.value) { const generations = [starterGeneration];
if (amountOfPokemon > 0) {
const speciesToCheck = [species.speciesId];
while (speciesToCheck.length) {
const checking = speciesToCheck.pop();
if (pokemonEvolutions.hasOwnProperty(checking)) {
pokemonEvolutions[checking].forEach(e => {
speciesToCheck.push(e.speciesId);
generations.push(getPokemonSpecies(e.speciesId).generation);
});
}
}
}
if (!generations.includes(this.value)) {
isValidStarter.value = false; isValidStarter.value = false;
return true; return true;
} }
@ -372,7 +388,32 @@ export class SingleTypeChallenge extends Challenge {
case ChallengeType.STARTER_CHOICE: case ChallengeType.STARTER_CHOICE:
const species = args[0] as PokemonSpecies; const species = args[0] as PokemonSpecies;
const isValidStarter = args[1] as Utils.BooleanHolder; const isValidStarter = args[1] as Utils.BooleanHolder;
if (!species.isOfType(this.value - 1)) { const dexAttr = args[2] as DexAttrProps;
const amountOfPokemon = args[3] as number;
const speciesForm = getPokemonSpeciesForm(species.speciesId, dexAttr.formIndex);
const types = [speciesForm.type1, speciesForm.type2];
if (amountOfPokemon > 0) {
const speciesToCheck = [species.speciesId];
while (speciesToCheck.length) {
const checking = speciesToCheck.pop();
if (pokemonEvolutions.hasOwnProperty(checking)) {
pokemonEvolutions[checking].forEach(e => {
speciesToCheck.push(e.speciesId);
types.push(getPokemonSpecies(e.speciesId).type1, getPokemonSpecies(e.speciesId).type2);
});
}
if (pokemonFormChanges.hasOwnProperty(checking)) {
pokemonFormChanges[checking].forEach(f1 => {
getPokemonSpecies(checking).forms.forEach(f2 => {
if (f1.formKey === f2.formKey) {
types.push(f2.type1, f2.type2);
}
});
});
}
}
}
if (!types.includes(this.value - 1)) {
isValidStarter.value = false; isValidStarter.value = false;
return true; return true;
} }
@ -535,7 +576,7 @@ export class LowerStarterPointsChallenge extends Challenge {
/** /**
* Apply all challenges of a given challenge type. * Apply all challenges of a given challenge type.
* @param {BattleScene} scene The current scene * @param {GameMode} gameMode The current game mode
* @param {ChallengeType} challengeType What challenge type to apply * @param {ChallengeType} challengeType What challenge type to apply
* @param {any[]} args Any args for that challenge type * @param {any[]} args Any args for that challenge type
* @returns {boolean} True if any challenge was successfully applied. * @returns {boolean} True if any challenge was successfully applied.

View File

@ -1,6 +1,6 @@
import BattleScene from "../battle-scene"; import BattleScene from "../battle-scene";
import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./pokemon-species"; import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./pokemon-species";
import i18next from "../plugins/i18n"; import i18next from "i18next";
import { EggTier } from "#enums/egg-type"; import { EggTier } from "#enums/egg-type";
import { Species } from "#enums/species"; import { Species } from "#enums/species";

View File

@ -9,7 +9,7 @@ import { Type } from "./type";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { WeatherType } from "./weather"; import { WeatherType } from "./weather";
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag"; import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, BlockItemTheftAbAttr, applyPostAttackAbAttrs, ConfusionOnStatusEffectAbAttr, HealFromBerryUseAbAttr, IgnoreProtectOnContactAbAttr, ForceSwitchOutImmunityAbAttr } from "./ability"; import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, BlockItemTheftAbAttr, applyPostAttackAbAttrs, ConfusionOnStatusEffectAbAttr, HealFromBerryUseAbAttr, IgnoreProtectOnContactAbAttr, ForceSwitchOutImmunityAbAttr, IgnoreMoveEffectsAbAttr, applyPreDefendAbAttrs, MoveEffectChanceMultiplierAbAttr } from "./ability";
import { allAbilities } from "./ability"; import { allAbilities } from "./ability";
import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier } from "../modifier/modifier"; import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier } from "../modifier/modifier";
import { BattlerIndex } from "../battle"; import { BattlerIndex } from "../battle";
@ -18,7 +18,8 @@ import { TerrainType } from "./terrain";
import { SpeciesFormChangeActiveTrigger } from "./pokemon-forms"; import { SpeciesFormChangeActiveTrigger } from "./pokemon-forms";
import { ModifierPoolType } from "#app/modifier/modifier-type"; import { ModifierPoolType } from "#app/modifier/modifier-type";
import { Command } from "../ui/command-ui-handler"; import { Command } from "../ui/command-ui-handler";
import i18next, { Localizable } from "../plugins/i18n"; import i18next from "i18next";
import { Localizable } from "#app/interfaces/locales";
import { getBerryEffectFunc } from "./berry"; import { getBerryEffectFunc } from "./berry";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { ArenaTagType } from "#enums/arena-tag-type"; import { ArenaTagType } from "#enums/arena-tag-type";
@ -277,18 +278,29 @@ export default class Move implements Localizable {
} }
/** /**
* Checks if the move is immune to certain types * Checks if the move is immune to certain types.
* currently only look at case of Grass types and powder moves * Currently looks at cases of Grass types with powder moves and Dark types with moves affected by Prankster.
* @param type {@linkcode Type} enum * @param {Pokemon} user the source of this move
* @param {Pokemon} target the target of this move
* @param {Type} type the type of the move's target
* @returns boolean * @returns boolean
*/ */
isTypeImmune(type: Type): boolean { isTypeImmune(user: Pokemon, target: Pokemon, type: Type): boolean {
if (this.moveTarget === MoveTarget.USER) {
return false;
}
switch (type) { switch (type) {
case Type.GRASS: case Type.GRASS:
if (this.hasFlag(MoveFlags.POWDER_MOVE)) { if (this.hasFlag(MoveFlags.POWDER_MOVE)) {
return true; return true;
} }
break; break;
case Type.DARK:
if (user.hasAbility(Abilities.PRANKSTER) && this.category === MoveCategory.STATUS && (user.isPlayer() !== target.isPlayer())) {
return true;
}
break;
} }
return false; return false;
} }
@ -793,7 +805,7 @@ export enum MoveEffectTrigger {
*/ */
export class MoveEffectAttr extends MoveAttr { export class MoveEffectAttr extends MoveAttr {
/** Defines when this effect should trigger in the move's effect order /** Defines when this effect should trigger in the move's effect order
* @see {@linkcode MoveEffectPhase.start} * @see {@linkcode phases.MoveEffectPhase.start}
*/ */
public trigger: MoveEffectTrigger; public trigger: MoveEffectTrigger;
/** Should this effect only apply on the first hit? */ /** Should this effect only apply on the first hit? */
@ -824,6 +836,22 @@ export class MoveEffectAttr extends MoveAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise<boolean> { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise<boolean> {
return this.canApply(user, target, move, args); return this.canApply(user, target, move, args);
} }
/**
* Gets the used move's additional effect chance.
* If user's ability has MoveEffectChanceMultiplierAbAttr or IgnoreMoveEffectsAbAttr modifies the base chance.
* @param user {@linkcode Pokemon} using this move
* @param target {@linkcode Pokemon} target of this move
* @param move {@linkcode Move} being used
* @param selfEffect {@linkcode Boolean} if move targets user.
* @returns Move chance value.
*/
getMoveChance(user: Pokemon, target: Pokemon, move: Move, selfEffect?: Boolean): integer {
const moveChance = new Utils.NumberHolder(move.chance);
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, moveChance, move, target, selfEffect);
applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr,target,user,null,null, moveChance);
return moveChance.value;
}
} }
export class PreMoveMessageAttr extends MoveAttr { export class PreMoveMessageAttr extends MoveAttr {
@ -1668,7 +1696,8 @@ export class StatusEffectAttr extends MoveEffectAttr {
} }
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const statusCheck = move.chance < 0 || move.chance === 100 || user.randSeedInt(100) < move.chance; const moveChance = this.getMoveChance(user,target,move,this.selfTarget);
const statusCheck = moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance;
if (statusCheck) { if (statusCheck) {
const pokemon = this.selfTarget ? user : target; const pokemon = this.selfTarget ? user : target;
if (pokemon.status) { if (pokemon.status) {
@ -1678,7 +1707,7 @@ export class StatusEffectAttr extends MoveEffectAttr {
return false; return false;
} }
} }
if ((!pokemon.status || (pokemon.status.effect === this.effect && move.chance < 0)) if ((!pokemon.status || (pokemon.status.effect === this.effect && moveChance < 0))
&& pokemon.trySetStatus(this.effect, true, user, this.cureTurn)) { && pokemon.trySetStatus(this.effect, true, user, this.cureTurn)) {
applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null,this.effect); applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null,this.effect);
return true; return true;
@ -1688,7 +1717,8 @@ export class StatusEffectAttr extends MoveEffectAttr {
} }
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(this.effect, true, false, user) ? Math.floor(move.chance * -0.1) : 0; const moveChance = this.getMoveChance(user,target,move,this.selfTarget);
return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(this.effect, true, false, user) ? Math.floor(moveChance * -0.1) : 0;
} }
} }
@ -1707,7 +1737,8 @@ export class MultiStatusEffectAttr extends StatusEffectAttr {
} }
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(this.effect, true, false, user) ? Math.floor(move.chance * -0.1) : 0; const moveChance = this.getMoveChance(user,target,move,this.selfTarget);
return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(this.effect, true, false, user) ? Math.floor(moveChance * -0.1) : 0;
} }
} }
@ -2310,7 +2341,8 @@ export class StatChangeAttr extends MoveEffectAttr {
return false; return false;
} }
if (move.chance < 0 || move.chance === 100 || user.randSeedInt(100) < move.chance) { const moveChance = this.getMoveChance(user,target,move,this.selfTarget);
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) {
const levels = this.getLevels(user); const levels = this.getLevels(user);
user.scene.unshiftPhase(new StatChangePhase(user.scene, (this.selfTarget ? user : target).getBattlerIndex(), this.selfTarget, this.stats, levels, this.showMessage)); user.scene.unshiftPhase(new StatChangePhase(user.scene, (this.selfTarget ? user : target).getBattlerIndex(), this.selfTarget, this.stats, levels, this.showMessage));
return true; return true;
@ -3034,10 +3066,8 @@ export class FriendshipPowerAttr extends VariablePowerAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const power = args[0] as Utils.NumberHolder; const power = args[0] as Utils.NumberHolder;
if (user instanceof PlayerPokemon) { const friendshipPower = Math.floor(Math.min(user instanceof PlayerPokemon ? user.friendship : user.species.baseFriendship, 255) / 2.5);
const friendshipPower = Math.floor(Math.min(user.friendship, 255) / 2.5); power.value = Math.max(!this.invert ? friendshipPower : 102 - friendshipPower, 1);
power.value = Math.max(!this.invert ? friendshipPower : 102 - friendshipPower, 1);
}
return true; return true;
} }
@ -3889,18 +3919,14 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
return false; return false;
} }
const chance = this.getTagChance(user, target, move); const moveChance = this.getMoveChance(user,target,move,this.selfTarget);
if (chance < 0 || chance === 100 || user.randSeedInt(100) < chance) { if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) {
return (this.selfTarget ? user : target).addTag(this.tagType, user.randSeedInt(this.turnCountMax - this.turnCountMin, this.turnCountMin), move.id, user.id); return (this.selfTarget ? user : target).addTag(this.tagType, user.randSeedInt(this.turnCountMax - this.turnCountMin, this.turnCountMin), move.id, user.id);
} }
return false; return false;
} }
getTagChance(user: Pokemon, target: Pokemon, move: Move): integer {
return move.chance;
}
getCondition(): MoveConditionFunc { getCondition(): MoveConditionFunc {
return this.failOnOverlap return this.failOnOverlap
? (user, target, move) => !(this.selfTarget ? user : target).getTag(this.tagType) ? (user, target, move) => !(this.selfTarget ? user : target).getTag(this.tagType)
@ -3950,11 +3976,11 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
} }
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer { getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
let chance = this.getTagChance(user, target, move); let moveChance = this.getMoveChance(user,target,move,this.selfTarget);
if (chance < 0) { if (moveChance < 0) {
chance = 100; moveChance = 100;
} }
return Math.floor(this.getTagTargetBenefitScore(user, target, move) * (chance / 100)); return Math.floor(this.getTagTargetBenefitScore(user, target, move) * (moveChance / 100));
} }
} }
@ -4219,15 +4245,42 @@ export class AddArenaTrapTagAttr extends AddArenaTagAttr {
getCondition(): MoveConditionFunc { getCondition(): MoveConditionFunc {
return (user, target, move) => { return (user, target, move) => {
const side = (this.selfSideTarget ? user : target).isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; const side = (this.selfSideTarget ? user : target).isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
if (move.category !== MoveCategory.STATUS || !user.scene.arena.getTagOnSide(this.tagType, side)) { const tag = user.scene.arena.getTagOnSide(this.tagType, side) as ArenaTrapTag;
if (!tag) {
return true; return true;
} }
const tag = user.scene.arena.getTagOnSide(this.tagType, side) as ArenaTrapTag;
return tag.layers < tag.maxLayers; return tag.layers < tag.maxLayers;
}; };
} }
} }
/**
* Attribute used for Stone Axe and Ceaseless Edge.
* Applies the given ArenaTrapTag when move is used.
* @extends AddArenaTagAttr
* @see {@linkcode apply}
*/
export class AddArenaTrapTagHitAttr extends AddArenaTagAttr {
/**
* @param user {@linkcode Pokemon} using this move
* @param target {@linkcode Pokemon} target of this move
* @param move {@linkcode Move} being used
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const moveChance = this.getMoveChance(user,target,move,this.selfTarget);
const side = (this.selfSideTarget ? user : target).isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
const tag = user.scene.arena.getTagOnSide(this.tagType, side) as ArenaTrapTag;
if ((moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance)) {
user.scene.arena.addTag(this.tagType, 0, move.id, user.id, side);
if (!tag) {
return true;
}
return tag.layers < tag.maxLayers;
}
return false;
}
}
export class RemoveArenaTrapAttr extends MoveEffectAttr { export class RemoveArenaTrapAttr extends MoveEffectAttr {
private targetBothSides: boolean; private targetBothSides: boolean;
@ -4553,7 +4606,7 @@ export class RemoveTypeAttr extends MoveEffectAttr {
export class CopyTypeAttr extends MoveEffectAttr { export class CopyTypeAttr extends MoveEffectAttr {
constructor() { constructor() {
super(true); super(false);
} }
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
@ -4919,14 +4972,36 @@ export class CopyMoveAttr extends OverrideMoveEffectAttr {
} }
} }
/**
* Attribute used for moves that reduce PP of the target's last used move.
* Used for Spite.
*/
export class ReducePpMoveAttr extends MoveEffectAttr { export class ReducePpMoveAttr extends MoveEffectAttr {
protected reduction: number;
constructor(reduction: number) {
super();
this.reduction = reduction;
}
/**
* Reduces the PP of the target's last-used move by an amount based on this attribute instance's {@linkcode reduction}.
*
* @param user {@linkcode Pokemon} that used the attack
* @param target {@linkcode Pokemon} targeted by the attack
* @param move {@linkcode Move} being used
* @param args N/A
* @returns {boolean} true
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
// Null checks can be skipped due to condition function // Null checks can be skipped due to condition function
const lastMove = target.getLastXMoves().find(() => true); const lastMove = target.getLastXMoves().find(() => true);
const movesetMove = target.getMoveset().find(m => m.moveId === lastMove.move); const movesetMove = target.getMoveset().find(m => m.moveId === lastMove.move);
const lastPpUsed = movesetMove.ppUsed; const lastPpUsed = movesetMove.ppUsed;
movesetMove.ppUsed = Math.min(movesetMove.ppUsed + 4, movesetMove.getMovePp()); movesetMove.ppUsed = Math.min(movesetMove.ppUsed + this.reduction, movesetMove.getMovePp());
user.scene.queueMessage(`It reduced the PP of ${getPokemonMessage(target, `'s\n${movesetMove.getName()} by ${movesetMove.ppUsed - lastPpUsed}!`)}`);
const message = i18next.t("battle:ppReduced", {targetName: target.name, moveName: movesetMove.getName(), reduction: movesetMove.ppUsed - lastPpUsed});
user.scene.queueMessage(message);
return true; return true;
} }
@ -4961,6 +5036,42 @@ export class ReducePpMoveAttr extends MoveEffectAttr {
} }
} }
/**
* Attribute used for moves that damage target, and then reduce PP of the target's last used move.
* Used for Eerie Spell.
*/
export class AttackReducePpMoveAttr extends ReducePpMoveAttr {
constructor(reduction: number) {
super(reduction);
}
/**
* Checks if the target has used a move prior to the attack. PP-reduction is applied through the super class if so.
*
* @param user {@linkcode Pokemon} that used the attack
* @param target {@linkcode Pokemon} targeted by the attack
* @param move {@linkcode Move} being used
* @param args N/A
* @returns {boolean} true
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const lastMove = target.getLastXMoves().find(() => true);
if (lastMove) {
const movesetMove = target.getMoveset().find(m => m.moveId === lastMove.move);
if (Boolean(movesetMove?.getPpRatio())) {
super.apply(user, target, move, args);
}
}
return true;
}
// Override condition function to always perform damage. Instead, perform pp-reduction condition check in apply function above
getCondition(): MoveConditionFunc {
return (user, target, move) => true;
}
}
// TODO: Review this // TODO: Review this
const targetMoveCopiableCondition: MoveConditionFunc = (user, target, move) => { const targetMoveCopiableCondition: MoveConditionFunc = (user, target, move) => {
const targetMoves = target.getMoveHistory().filter(m => !m.virtual); const targetMoves = target.getMoveHistory().filter(m => !m.virtual);
@ -5546,7 +5657,7 @@ export function initMoves() {
.attr(ChargeAttr, ChargeAnim.FLY_CHARGING, "flew\nup high!", BattlerTagType.FLYING) .attr(ChargeAttr, ChargeAnim.FLY_CHARGING, "flew\nup high!", BattlerTagType.FLYING)
.condition(failOnGravityCondition) .condition(failOnGravityCondition)
.ignoresVirtual(), .ignoresVirtual(),
new AttackMove(Moves.BIND, Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 20, 100, 0, 1) new AttackMove(Moves.BIND, Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 20, -1, 0, 1)
.attr(TrapAttr, BattlerTagType.BIND), .attr(TrapAttr, BattlerTagType.BIND),
new AttackMove(Moves.SLAM, Type.NORMAL, MoveCategory.PHYSICAL, 80, 75, 20, -1, 0, 1), new AttackMove(Moves.SLAM, Type.NORMAL, MoveCategory.PHYSICAL, 80, 75, 20, -1, 0, 1),
new AttackMove(Moves.VINE_WHIP, Type.GRASS, MoveCategory.PHYSICAL, 45, 100, 25, -1, 0, 1), new AttackMove(Moves.VINE_WHIP, Type.GRASS, MoveCategory.PHYSICAL, 45, 100, 25, -1, 0, 1),
@ -5579,7 +5690,7 @@ export function initMoves() {
.attr(MinimizeAccuracyAttr) .attr(MinimizeAccuracyAttr)
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true) .attr(HitsTagAttr, BattlerTagType.MINIMIZED, true)
.attr(StatusEffectAttr, StatusEffect.PARALYSIS), .attr(StatusEffectAttr, StatusEffect.PARALYSIS),
new AttackMove(Moves.WRAP, Type.NORMAL, MoveCategory.PHYSICAL, 15, 90, 20, 100, 0, 1) new AttackMove(Moves.WRAP, Type.NORMAL, MoveCategory.PHYSICAL, 15, 90, 20, -1, 0, 1)
.attr(TrapAttr, BattlerTagType.WRAP), .attr(TrapAttr, BattlerTagType.WRAP),
new AttackMove(Moves.TAKE_DOWN, Type.NORMAL, MoveCategory.PHYSICAL, 90, 85, 20, -1, 0, 1) new AttackMove(Moves.TAKE_DOWN, Type.NORMAL, MoveCategory.PHYSICAL, 90, 85, 20, -1, 0, 1)
.attr(RecoilAttr) .attr(RecoilAttr)
@ -5604,7 +5715,7 @@ export function initMoves() {
new AttackMove(Moves.PIN_MISSILE, Type.BUG, MoveCategory.PHYSICAL, 25, 95, 20, -1, 0, 1) new AttackMove(Moves.PIN_MISSILE, Type.BUG, MoveCategory.PHYSICAL, 25, 95, 20, -1, 0, 1)
.attr(MultiHitAttr) .attr(MultiHitAttr)
.makesContact(false), .makesContact(false),
new StatusMove(Moves.LEER, Type.NORMAL, 100, 30, 100, 0, 1) new StatusMove(Moves.LEER, Type.NORMAL, 100, 30, -1, 0, 1)
.attr(StatChangeAttr, BattleStat.DEF, -1) .attr(StatChangeAttr, BattleStat.DEF, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.BITE, Type.DARK, MoveCategory.PHYSICAL, 60, 100, 25, 30, 0, 1) new AttackMove(Moves.BITE, Type.DARK, MoveCategory.PHYSICAL, 60, 100, 25, 30, 0, 1)
@ -5713,7 +5824,7 @@ export function initMoves() {
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.DRAGON_RAGE, Type.DRAGON, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 1) new AttackMove(Moves.DRAGON_RAGE, Type.DRAGON, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 1)
.attr(FixedDamageAttr, 40), .attr(FixedDamageAttr, 40),
new AttackMove(Moves.FIRE_SPIN, Type.FIRE, MoveCategory.SPECIAL, 35, 85, 15, 100, 0, 1) new AttackMove(Moves.FIRE_SPIN, Type.FIRE, MoveCategory.SPECIAL, 35, 85, 15, -1, 0, 1)
.attr(TrapAttr, BattlerTagType.FIRE_SPIN), .attr(TrapAttr, BattlerTagType.FIRE_SPIN),
new AttackMove(Moves.THUNDER_SHOCK, Type.ELECTRIC, MoveCategory.SPECIAL, 40, 100, 30, 10, 0, 1) new AttackMove(Moves.THUNDER_SHOCK, Type.ELECTRIC, MoveCategory.SPECIAL, 40, 100, 30, 10, 0, 1)
.attr(StatusEffectAttr, StatusEffect.PARALYSIS), .attr(StatusEffectAttr, StatusEffect.PARALYSIS),
@ -5828,11 +5939,11 @@ export function initMoves() {
.attr(StatusEffectAttr, StatusEffect.BURN), .attr(StatusEffectAttr, StatusEffect.BURN),
new AttackMove(Moves.WATERFALL, Type.WATER, MoveCategory.PHYSICAL, 80, 100, 15, 20, 0, 1) new AttackMove(Moves.WATERFALL, Type.WATER, MoveCategory.PHYSICAL, 80, 100, 15, 20, 0, 1)
.attr(FlinchAttr), .attr(FlinchAttr),
new AttackMove(Moves.CLAMP, Type.WATER, MoveCategory.PHYSICAL, 35, 85, 15, 100, 0, 1) new AttackMove(Moves.CLAMP, Type.WATER, MoveCategory.PHYSICAL, 35, 85, 15, -1, 0, 1)
.attr(TrapAttr, BattlerTagType.CLAMP), .attr(TrapAttr, BattlerTagType.CLAMP),
new AttackMove(Moves.SWIFT, Type.NORMAL, MoveCategory.SPECIAL, 60, -1, 20, -1, 0, 1) new AttackMove(Moves.SWIFT, Type.NORMAL, MoveCategory.SPECIAL, 60, -1, 20, -1, 0, 1)
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.SKULL_BASH, Type.NORMAL, MoveCategory.PHYSICAL, 130, 100, 10, 100, 0, 1) new AttackMove(Moves.SKULL_BASH, Type.NORMAL, MoveCategory.PHYSICAL, 130, 100, 10, -1, 0, 1)
.attr(ChargeAttr, ChargeAnim.SKULL_BASH_CHARGING, "lowered\nits head!", null, true) .attr(ChargeAttr, ChargeAnim.SKULL_BASH_CHARGING, "lowered\nits head!", null, true)
.attr(StatChangeAttr, BattleStat.DEF, 1, true) .attr(StatChangeAttr, BattleStat.DEF, 1, true)
.ignoresVirtual(), .ignoresVirtual(),
@ -5980,7 +6091,7 @@ export function initMoves() {
new AttackMove(Moves.REVERSAL, Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 15, -1, 0, 2) new AttackMove(Moves.REVERSAL, Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 15, -1, 0, 2)
.attr(LowHpPowerAttr), .attr(LowHpPowerAttr),
new StatusMove(Moves.SPITE, Type.GHOST, 100, 10, -1, 0, 2) new StatusMove(Moves.SPITE, Type.GHOST, 100, 10, -1, 0, 2)
.attr(ReducePpMoveAttr), .attr(ReducePpMoveAttr, 4),
new AttackMove(Moves.POWDER_SNOW, Type.ICE, MoveCategory.SPECIAL, 40, 100, 25, 10, 0, 2) new AttackMove(Moves.POWDER_SNOW, Type.ICE, MoveCategory.SPECIAL, 40, 100, 25, 10, 0, 2)
.attr(StatusEffectAttr, StatusEffect.FREEZE) .attr(StatusEffectAttr, StatusEffect.FREEZE)
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
@ -6180,7 +6291,7 @@ export function initMoves() {
.attr(DelayedAttackAttr, ArenaTagType.FUTURE_SIGHT, ChargeAnim.FUTURE_SIGHT_CHARGING, "foresaw\nan attack!"), .attr(DelayedAttackAttr, ArenaTagType.FUTURE_SIGHT, ChargeAnim.FUTURE_SIGHT_CHARGING, "foresaw\nan attack!"),
new AttackMove(Moves.ROCK_SMASH, Type.FIGHTING, MoveCategory.PHYSICAL, 40, 100, 15, 50, 0, 2) new AttackMove(Moves.ROCK_SMASH, Type.FIGHTING, MoveCategory.PHYSICAL, 40, 100, 15, 50, 0, 2)
.attr(StatChangeAttr, BattleStat.DEF, -1), .attr(StatChangeAttr, BattleStat.DEF, -1),
new AttackMove(Moves.WHIRLPOOL, Type.WATER, MoveCategory.SPECIAL, 35, 85, 15, 100, 0, 2) new AttackMove(Moves.WHIRLPOOL, Type.WATER, MoveCategory.SPECIAL, 35, 85, 15, -1, 0, 2)
.attr(TrapAttr, BattlerTagType.WHIRLPOOL) .attr(TrapAttr, BattlerTagType.WHIRLPOOL)
.attr(HitsTagAttr, BattlerTagType.UNDERWATER, true), .attr(HitsTagAttr, BattlerTagType.UNDERWATER, true),
new AttackMove(Moves.BEAT_UP, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 2) new AttackMove(Moves.BEAT_UP, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 2)
@ -6232,7 +6343,7 @@ export function initMoves() {
.attr(MovePowerMultiplierAttr, (user, target, move) => target.status?.effect === StatusEffect.PARALYSIS ? 2 : 1) .attr(MovePowerMultiplierAttr, (user, target, move) => target.status?.effect === StatusEffect.PARALYSIS ? 2 : 1)
.attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS), .attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS),
new SelfStatusMove(Moves.FOLLOW_ME, Type.NORMAL, -1, 20, -1, 2, 3) new SelfStatusMove(Moves.FOLLOW_ME, Type.NORMAL, -1, 20, -1, 2, 3)
.unimplemented(), .attr(AddBattlerTagAttr, BattlerTagType.CENTER_OF_ATTENTION, true),
new StatusMove(Moves.NATURE_POWER, Type.NORMAL, -1, 20, -1, 0, 3) new StatusMove(Moves.NATURE_POWER, Type.NORMAL, -1, 20, -1, 0, 3)
.attr(NaturePowerAttr) .attr(NaturePowerAttr)
.ignoresVirtual(), .ignoresVirtual(),
@ -6256,7 +6367,7 @@ export function initMoves() {
.ignoresVirtual(), .ignoresVirtual(),
new SelfStatusMove(Moves.INGRAIN, Type.GRASS, -1, 20, -1, 0, 3) new SelfStatusMove(Moves.INGRAIN, Type.GRASS, -1, 20, -1, 0, 3)
.attr(AddBattlerTagAttr, BattlerTagType.INGRAIN, true, true), .attr(AddBattlerTagAttr, BattlerTagType.INGRAIN, true, true),
new AttackMove(Moves.SUPERPOWER, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, 100, 0, 3) new AttackMove(Moves.SUPERPOWER, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 3)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1, true), .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1, true),
new SelfStatusMove(Moves.MAGIC_COAT, Type.PSYCHIC, -1, 15, -1, 4, 3) new SelfStatusMove(Moves.MAGIC_COAT, Type.PSYCHIC, -1, 15, -1, 4, 3)
.unimplemented(), .unimplemented(),
@ -6358,7 +6469,7 @@ export function initMoves() {
.slicingMove() .slicingMove()
.windMove() .windMove()
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.OVERHEAT, Type.FIRE, MoveCategory.SPECIAL, 130, 90, 5, 100, 0, 3) new AttackMove(Moves.OVERHEAT, Type.FIRE, MoveCategory.SPECIAL, 130, 90, 5, -1, 0, 3)
.attr(StatChangeAttr, BattleStat.SPATK, -2, true) .attr(StatChangeAttr, BattleStat.SPATK, -2, true)
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE), .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE),
new StatusMove(Moves.ODOR_SLEUTH, Type.NORMAL, -1, 40, -1, 0, 3) new StatusMove(Moves.ODOR_SLEUTH, Type.NORMAL, -1, 40, -1, 0, 3)
@ -6391,7 +6502,7 @@ export function initMoves() {
new AttackMove(Moves.SKY_UPPERCUT, Type.FIGHTING, MoveCategory.PHYSICAL, 85, 90, 15, -1, 0, 3) new AttackMove(Moves.SKY_UPPERCUT, Type.FIGHTING, MoveCategory.PHYSICAL, 85, 90, 15, -1, 0, 3)
.attr(HitsTagAttr, BattlerTagType.FLYING) .attr(HitsTagAttr, BattlerTagType.FLYING)
.punchingMove(), .punchingMove(),
new AttackMove(Moves.SAND_TOMB, Type.GROUND, MoveCategory.PHYSICAL, 35, 85, 15, 100, 0, 3) new AttackMove(Moves.SAND_TOMB, Type.GROUND, MoveCategory.PHYSICAL, 35, 85, 15, -1, 0, 3)
.attr(TrapAttr, BattlerTagType.SAND_TOMB) .attr(TrapAttr, BattlerTagType.SAND_TOMB)
.makesContact(false), .makesContact(false),
new AttackMove(Moves.SHEER_COLD, Type.ICE, MoveCategory.SPECIAL, 200, 20, 5, -1, 0, 3) new AttackMove(Moves.SHEER_COLD, Type.ICE, MoveCategory.SPECIAL, 200, 20, 5, -1, 0, 3)
@ -6461,7 +6572,7 @@ export function initMoves() {
.pulseMove(), .pulseMove(),
new AttackMove(Moves.DOOM_DESIRE, Type.STEEL, MoveCategory.SPECIAL, 140, 100, 5, -1, 0, 3) new AttackMove(Moves.DOOM_DESIRE, Type.STEEL, MoveCategory.SPECIAL, 140, 100, 5, -1, 0, 3)
.attr(DelayedAttackAttr, ArenaTagType.DOOM_DESIRE, ChargeAnim.DOOM_DESIRE_CHARGING, "chose\nDoom Desire as its destiny!"), .attr(DelayedAttackAttr, ArenaTagType.DOOM_DESIRE, ChargeAnim.DOOM_DESIRE_CHARGING, "chose\nDoom Desire as its destiny!"),
new AttackMove(Moves.PSYCHO_BOOST, Type.PSYCHIC, MoveCategory.SPECIAL, 140, 90, 5, 100, 0, 3) new AttackMove(Moves.PSYCHO_BOOST, Type.PSYCHIC, MoveCategory.SPECIAL, 140, 90, 5, -1, 0, 3)
.attr(StatChangeAttr, BattleStat.SPATK, -2, true), .attr(StatChangeAttr, BattleStat.SPATK, -2, true),
new SelfStatusMove(Moves.ROOST, Type.FLYING, -1, 5, -1, 0, 4) new SelfStatusMove(Moves.ROOST, Type.FLYING, -1, 5, -1, 0, 4)
.attr(HealAttr, 0.5) .attr(HealAttr, 0.5)
@ -6475,7 +6586,7 @@ export function initMoves() {
new AttackMove(Moves.WAKE_UP_SLAP, Type.FIGHTING, MoveCategory.PHYSICAL, 70, 100, 10, -1, 0, 4) new AttackMove(Moves.WAKE_UP_SLAP, Type.FIGHTING, MoveCategory.PHYSICAL, 70, 100, 10, -1, 0, 4)
.attr(MovePowerMultiplierAttr, (user, target, move) => targetSleptOrComatoseCondition(user, target, move) ? 2 : 1) .attr(MovePowerMultiplierAttr, (user, target, move) => targetSleptOrComatoseCondition(user, target, move) ? 2 : 1)
.attr(HealStatusEffectAttr, false, StatusEffect.SLEEP), .attr(HealStatusEffectAttr, false, StatusEffect.SLEEP),
new AttackMove(Moves.HAMMER_ARM, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 90, 10, 100, 0, 4) new AttackMove(Moves.HAMMER_ARM, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 90, 10, -1, 0, 4)
.attr(StatChangeAttr, BattleStat.SPD, -1, true) .attr(StatChangeAttr, BattleStat.SPD, -1, true)
.punchingMove(), .punchingMove(),
new AttackMove(Moves.GYRO_BALL, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4) new AttackMove(Moves.GYRO_BALL, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4)
@ -6509,7 +6620,7 @@ export function initMoves() {
.target(MoveTarget.ATTACKER), .target(MoveTarget.ATTACKER),
new AttackMove(Moves.U_TURN, Type.BUG, MoveCategory.PHYSICAL, 70, 100, 20, -1, 0, 4) new AttackMove(Moves.U_TURN, Type.BUG, MoveCategory.PHYSICAL, 70, 100, 20, -1, 0, 4)
.attr(ForceSwitchOutAttr, true, false), .attr(ForceSwitchOutAttr, true, false),
new AttackMove(Moves.CLOSE_COMBAT, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, 100, 0, 4) new AttackMove(Moves.CLOSE_COMBAT, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 4)
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true), .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true),
new AttackMove(Moves.PAYBACK, Type.DARK, MoveCategory.PHYSICAL, 50, 100, 10, -1, 0, 4) new AttackMove(Moves.PAYBACK, Type.DARK, MoveCategory.PHYSICAL, 50, 100, 10, -1, 0, 4)
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getLastXMoves(1).find(m => m.turn === target.scene.currentBattle.turn) || user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.BALL ? 2 : 1), .attr(MovePowerMultiplierAttr, (user, target, move) => target.getLastXMoves(1).find(m => m.turn === target.scene.currentBattle.turn) || user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.BALL ? 2 : 1),
@ -6553,9 +6664,9 @@ export function initMoves() {
new SelfStatusMove(Moves.COPYCAT, Type.NORMAL, -1, 20, -1, 0, 4) new SelfStatusMove(Moves.COPYCAT, Type.NORMAL, -1, 20, -1, 0, 4)
.attr(CopyMoveAttr) .attr(CopyMoveAttr)
.ignoresVirtual(), .ignoresVirtual(),
new StatusMove(Moves.POWER_SWAP, Type.PSYCHIC, -1, 10, -1, 0, 4) new StatusMove(Moves.POWER_SWAP, Type.PSYCHIC, -1, 10, 100, 0, 4)
.unimplemented(), .unimplemented(),
new StatusMove(Moves.GUARD_SWAP, Type.PSYCHIC, -1, 10, -1, 0, 4) new StatusMove(Moves.GUARD_SWAP, Type.PSYCHIC, -1, 10, 100, 0, 4)
.unimplemented(), .unimplemented(),
new AttackMove(Moves.PUNISHMENT, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4) new AttackMove(Moves.PUNISHMENT, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4)
.makesContact(true) .makesContact(true)
@ -6575,10 +6686,7 @@ export function initMoves() {
.attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, true), .attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, true),
new SelfStatusMove(Moves.MAGNET_RISE, Type.ELECTRIC, -1, 10, -1, 0, 4) new SelfStatusMove(Moves.MAGNET_RISE, Type.ELECTRIC, -1, 10, -1, 0, 4)
.attr(AddBattlerTagAttr, BattlerTagType.MAGNET_RISEN, true, true) .attr(AddBattlerTagAttr, BattlerTagType.MAGNET_RISEN, true, true)
.condition((user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY) && .condition((user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY) && [BattlerTagType.MAGNET_RISEN, BattlerTagType.IGNORE_FLYING, BattlerTagType.INGRAIN].every((tag) => !user.getTag(tag))),
!user.getTag(BattlerTagType.IGNORE_FLYING) && !user.getTag(BattlerTagType.INGRAIN) &&
!user.getTag(BattlerTagType.MAGNET_RISEN))
.unimplemented(),
new AttackMove(Moves.FLARE_BLITZ, Type.FIRE, MoveCategory.PHYSICAL, 120, 100, 15, 10, 0, 4) new AttackMove(Moves.FLARE_BLITZ, Type.FIRE, MoveCategory.PHYSICAL, 120, 100, 15, 10, 0, 4)
.attr(RecoilAttr, false, 0.33) .attr(RecoilAttr, false, 0.33)
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE) .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
@ -6686,7 +6794,7 @@ export function initMoves() {
.attr(AddArenaTagAttr, ArenaTagType.TRICK_ROOM, 5) .attr(AddArenaTagAttr, ArenaTagType.TRICK_ROOM, 5)
.ignoresProtect() .ignoresProtect()
.target(MoveTarget.BOTH_SIDES), .target(MoveTarget.BOTH_SIDES),
new AttackMove(Moves.DRACO_METEOR, Type.DRAGON, MoveCategory.SPECIAL, 130, 90, 5, 100, 0, 4) new AttackMove(Moves.DRACO_METEOR, Type.DRAGON, MoveCategory.SPECIAL, 130, 90, 5, -1, 0, 4)
.attr(StatChangeAttr, BattleStat.SPATK, -2, true), .attr(StatChangeAttr, BattleStat.SPATK, -2, true),
new AttackMove(Moves.DISCHARGE, Type.ELECTRIC, MoveCategory.SPECIAL, 80, 100, 15, 30, 0, 4) new AttackMove(Moves.DISCHARGE, Type.ELECTRIC, MoveCategory.SPECIAL, 80, 100, 15, 30, 0, 4)
.attr(StatusEffectAttr, StatusEffect.PARALYSIS) .attr(StatusEffectAttr, StatusEffect.PARALYSIS)
@ -6694,7 +6802,7 @@ export function initMoves() {
new AttackMove(Moves.LAVA_PLUME, Type.FIRE, MoveCategory.SPECIAL, 80, 100, 15, 30, 0, 4) new AttackMove(Moves.LAVA_PLUME, Type.FIRE, MoveCategory.SPECIAL, 80, 100, 15, 30, 0, 4)
.attr(StatusEffectAttr, StatusEffect.BURN) .attr(StatusEffectAttr, StatusEffect.BURN)
.target(MoveTarget.ALL_NEAR_OTHERS), .target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.LEAF_STORM, Type.GRASS, MoveCategory.SPECIAL, 130, 90, 5, 100, 0, 4) new AttackMove(Moves.LEAF_STORM, Type.GRASS, MoveCategory.SPECIAL, 130, 90, 5, -1, 0, 4)
.attr(StatChangeAttr, BattleStat.SPATK, -2, true), .attr(StatChangeAttr, BattleStat.SPATK, -2, true),
new AttackMove(Moves.POWER_WHIP, Type.GRASS, MoveCategory.PHYSICAL, 120, 85, 10, -1, 0, 4), new AttackMove(Moves.POWER_WHIP, Type.GRASS, MoveCategory.PHYSICAL, 120, 85, 10, -1, 0, 4),
new AttackMove(Moves.ROCK_WRECKER, Type.ROCK, MoveCategory.PHYSICAL, 150, 90, 5, -1, 0, 4) new AttackMove(Moves.ROCK_WRECKER, Type.ROCK, MoveCategory.PHYSICAL, 150, 90, 5, -1, 0, 4)
@ -6764,7 +6872,7 @@ export function initMoves() {
.unimplemented(), .unimplemented(),
new AttackMove(Moves.CRUSH_GRIP, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4) new AttackMove(Moves.CRUSH_GRIP, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4)
.attr(OpponentHighHpPowerAttr), .attr(OpponentHighHpPowerAttr),
new AttackMove(Moves.MAGMA_STORM, Type.FIRE, MoveCategory.SPECIAL, 100, 75, 5, 100, 0, 4) new AttackMove(Moves.MAGMA_STORM, Type.FIRE, MoveCategory.SPECIAL, 100, 75, 5, -1, 0, 4)
.attr(TrapAttr, BattlerTagType.MAGMA_STORM), .attr(TrapAttr, BattlerTagType.MAGMA_STORM),
new StatusMove(Moves.DARK_VOID, Type.DARK, 50, 10, -1, 0, 4) new StatusMove(Moves.DARK_VOID, Type.DARK, 50, 10, -1, 0, 4)
.attr(StatusEffectAttr, StatusEffect.SLEEP) .attr(StatusEffectAttr, StatusEffect.SLEEP)
@ -6800,7 +6908,7 @@ export function initMoves() {
.partial(), .partial(),
new SelfStatusMove(Moves.RAGE_POWDER, Type.BUG, -1, 20, -1, 2, 5) new SelfStatusMove(Moves.RAGE_POWDER, Type.BUG, -1, 20, -1, 2, 5)
.powderMove() .powderMove()
.unimplemented(), .attr(AddBattlerTagAttr, BattlerTagType.CENTER_OF_ATTENTION, true),
new StatusMove(Moves.TELEKINESIS, Type.PSYCHIC, -1, 15, -1, 0, 5) new StatusMove(Moves.TELEKINESIS, Type.PSYCHIC, -1, 15, -1, 0, 5)
.condition(failOnGravityCondition) .condition(failOnGravityCondition)
.unimplemented(), .unimplemented(),
@ -6811,7 +6919,7 @@ export function initMoves() {
new AttackMove(Moves.SMACK_DOWN, Type.ROCK, MoveCategory.PHYSICAL, 50, 100, 15, 100, 0, 5) new AttackMove(Moves.SMACK_DOWN, Type.ROCK, MoveCategory.PHYSICAL, 50, 100, 15, 100, 0, 5)
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 5) .attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 5)
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED) .attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING]) .attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN])
.attr(HitsTagAttr, BattlerTagType.FLYING, false) .attr(HitsTagAttr, BattlerTagType.FLYING, false)
.makesContact(false), .makesContact(false),
new AttackMove(Moves.STORM_THROW, Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, 0, 5) new AttackMove(Moves.STORM_THROW, Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, 0, 5)
@ -7024,7 +7132,7 @@ export function initMoves() {
new AttackMove(Moves.ICICLE_CRASH, Type.ICE, MoveCategory.PHYSICAL, 85, 90, 10, 30, 0, 5) new AttackMove(Moves.ICICLE_CRASH, Type.ICE, MoveCategory.PHYSICAL, 85, 90, 10, 30, 0, 5)
.attr(FlinchAttr) .attr(FlinchAttr)
.makesContact(false), .makesContact(false),
new AttackMove(Moves.V_CREATE, Type.FIRE, MoveCategory.PHYSICAL, 180, 95, 5, 100, 0, 5) new AttackMove(Moves.V_CREATE, Type.FIRE, MoveCategory.PHYSICAL, 180, 95, 5, -1, 0, 5)
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF, BattleStat.SPD ], -1, true), .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF, BattleStat.SPD ], -1, true),
new AttackMove(Moves.FUSION_FLARE, Type.FIRE, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 5) new AttackMove(Moves.FUSION_FLARE, Type.FIRE, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 5)
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE) .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
@ -7043,7 +7151,7 @@ export function initMoves() {
.condition(new FirstMoveCondition()), .condition(new FirstMoveCondition()),
new AttackMove(Moves.BELCH, Type.POISON, MoveCategory.SPECIAL, 120, 90, 10, -1, 0, 6) new AttackMove(Moves.BELCH, Type.POISON, MoveCategory.SPECIAL, 120, 90, 10, -1, 0, 6)
.condition((user, target, move) => user.battleData.berriesEaten.length > 0), .condition((user, target, move) => user.battleData.berriesEaten.length > 0),
new StatusMove(Moves.ROTOTILLER, Type.GROUND, -1, 10, 100, 0, 6) new StatusMove(Moves.ROTOTILLER, Type.GROUND, -1, 10, -1, 0, 6)
.target(MoveTarget.ALL) .target(MoveTarget.ALL)
.condition((user,target,move) => { .condition((user,target,move) => {
// If any fielded pokémon is grass-type and grounded. // If any fielded pokémon is grass-type and grounded.
@ -7062,7 +7170,7 @@ export function initMoves() {
new StatusMove(Moves.TRICK_OR_TREAT, Type.GHOST, 100, 20, -1, 0, 6) new StatusMove(Moves.TRICK_OR_TREAT, Type.GHOST, 100, 20, -1, 0, 6)
.attr(AddTypeAttr, Type.GHOST) .attr(AddTypeAttr, Type.GHOST)
.partial(), .partial(),
new StatusMove(Moves.NOBLE_ROAR, Type.NORMAL, 100, 30, 100, 0, 6) new StatusMove(Moves.NOBLE_ROAR, Type.NORMAL, 100, 30, -1, 0, 6)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1)
.soundBased(), .soundBased(),
new StatusMove(Moves.ION_DELUGE, Type.ELECTRIC, -1, 25, -1, 1, 6) new StatusMove(Moves.ION_DELUGE, Type.ELECTRIC, -1, 25, -1, 1, 6)
@ -7085,7 +7193,7 @@ export function initMoves() {
new AttackMove(Moves.DISARMING_VOICE, Type.FAIRY, MoveCategory.SPECIAL, 40, -1, 15, -1, 0, 6) new AttackMove(Moves.DISARMING_VOICE, Type.FAIRY, MoveCategory.SPECIAL, 40, -1, 15, -1, 0, 6)
.soundBased() .soundBased()
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
new StatusMove(Moves.PARTING_SHOT, Type.DARK, 100, 20, 100, 0, 6) new StatusMove(Moves.PARTING_SHOT, Type.DARK, 100, 20, -1, 0, 6)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1, false, null, true, true, MoveEffectTrigger.PRE_APPLY) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1, false, null, true, true, MoveEffectTrigger.PRE_APPLY)
.attr(ForceSwitchOutAttr, true, false) .attr(ForceSwitchOutAttr, true, false)
.soundBased(), .soundBased(),
@ -7098,7 +7206,7 @@ export function initMoves() {
new StatusMove(Moves.CRAFTY_SHIELD, Type.FAIRY, -1, 10, -1, 3, 6) new StatusMove(Moves.CRAFTY_SHIELD, Type.FAIRY, -1, 10, -1, 3, 6)
.target(MoveTarget.USER_SIDE) .target(MoveTarget.USER_SIDE)
.attr(AddArenaTagAttr, ArenaTagType.CRAFTY_SHIELD, 1, true, true), .attr(AddArenaTagAttr, ArenaTagType.CRAFTY_SHIELD, 1, true, true),
new StatusMove(Moves.FLOWER_SHIELD, Type.FAIRY, -1, 10, 100, 0, 6) new StatusMove(Moves.FLOWER_SHIELD, Type.FAIRY, -1, 10, -1, 0, 6)
.target(MoveTarget.ALL) .target(MoveTarget.ALL)
.unimplemented(), .unimplemented(),
new StatusMove(Moves.GRASSY_TERRAIN, Type.GRASS, -1, 10, -1, 0, 6) new StatusMove(Moves.GRASSY_TERRAIN, Type.GRASS, -1, 10, -1, 0, 6)
@ -7123,9 +7231,9 @@ export function initMoves() {
.unimplemented(), .unimplemented(),
new SelfStatusMove(Moves.KINGS_SHIELD, Type.STEEL, -1, 10, -1, 4, 6) new SelfStatusMove(Moves.KINGS_SHIELD, Type.STEEL, -1, 10, -1, 4, 6)
.attr(ProtectAttr, BattlerTagType.KINGS_SHIELD), .attr(ProtectAttr, BattlerTagType.KINGS_SHIELD),
new StatusMove(Moves.PLAY_NICE, Type.NORMAL, -1, 20, 100, 0, 6) new StatusMove(Moves.PLAY_NICE, Type.NORMAL, -1, 20, -1, 0, 6)
.attr(StatChangeAttr, BattleStat.ATK, -1), .attr(StatChangeAttr, BattleStat.ATK, -1),
new StatusMove(Moves.CONFIDE, Type.NORMAL, -1, 20, 100, 0, 6) new StatusMove(Moves.CONFIDE, Type.NORMAL, -1, 20, -1, 0, 6)
.attr(StatChangeAttr, BattleStat.SPATK, -1) .attr(StatChangeAttr, BattleStat.SPATK, -1)
.soundBased(), .soundBased(),
new AttackMove(Moves.DIAMOND_STORM, Type.ROCK, MoveCategory.PHYSICAL, 100, 95, 5, 50, 0, 6) new AttackMove(Moves.DIAMOND_STORM, Type.ROCK, MoveCategory.PHYSICAL, 100, 95, 5, 50, 0, 6)
@ -7151,7 +7259,7 @@ export function initMoves() {
.target(MoveTarget.NEAR_ALLY), .target(MoveTarget.NEAR_ALLY),
new StatusMove(Moves.EERIE_IMPULSE, Type.ELECTRIC, 100, 15, -1, 0, 6) new StatusMove(Moves.EERIE_IMPULSE, Type.ELECTRIC, 100, 15, -1, 0, 6)
.attr(StatChangeAttr, BattleStat.SPATK, -2), .attr(StatChangeAttr, BattleStat.SPATK, -2),
new StatusMove(Moves.VENOM_DRENCH, Type.POISON, 100, 20, 100, 0, 6) new StatusMove(Moves.VENOM_DRENCH, Type.POISON, 100, 20, -1, 0, 6)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK, BattleStat.SPD ], -1, false, (user, target, move) => target.status?.effect === StatusEffect.POISON || target.status?.effect === StatusEffect.TOXIC) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK, BattleStat.SPD ], -1, false, (user, target, move) => target.status?.effect === StatusEffect.POISON || target.status?.effect === StatusEffect.TOXIC)
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
new StatusMove(Moves.POWDER, Type.BUG, 100, 20, -1, 1, 6) new StatusMove(Moves.POWDER, Type.BUG, 100, 20, -1, 1, 6)
@ -7182,7 +7290,7 @@ export function initMoves() {
.attr(StatusEffectAttr, StatusEffect.PARALYSIS), .attr(StatusEffectAttr, StatusEffect.PARALYSIS),
new AttackMove(Moves.HOLD_BACK, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 40, -1, 0, 6) new AttackMove(Moves.HOLD_BACK, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 40, -1, 0, 6)
.attr(SurviveDamageAttr), .attr(SurviveDamageAttr),
new AttackMove(Moves.INFESTATION, Type.BUG, MoveCategory.SPECIAL, 20, 100, 20, 100, 0, 6) new AttackMove(Moves.INFESTATION, Type.BUG, MoveCategory.SPECIAL, 20, 100, 20, -1, 0, 6)
.makesContact() .makesContact()
.attr(TrapAttr, BattlerTagType.INFESTATION), .attr(TrapAttr, BattlerTagType.INFESTATION),
new AttackMove(Moves.POWER_UP_PUNCH, Type.FIGHTING, MoveCategory.PHYSICAL, 40, 100, 20, 100, 0, 6) new AttackMove(Moves.POWER_UP_PUNCH, Type.FIGHTING, MoveCategory.PHYSICAL, 40, 100, 20, 100, 0, 6)
@ -7191,11 +7299,11 @@ export function initMoves() {
new AttackMove(Moves.OBLIVION_WING, Type.FLYING, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 6) new AttackMove(Moves.OBLIVION_WING, Type.FLYING, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 6)
.attr(HitHealAttr, 0.75) .attr(HitHealAttr, 0.75)
.triageMove(), .triageMove(),
new AttackMove(Moves.THOUSAND_ARROWS, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, 100, 0, 6) new AttackMove(Moves.THOUSAND_ARROWS, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6)
.attr(NeutralDamageAgainstFlyingTypeMultiplierAttr) .attr(NeutralDamageAgainstFlyingTypeMultiplierAttr)
.attr(HitsTagAttr, BattlerTagType.FLYING, false) .attr(HitsTagAttr, BattlerTagType.FLYING, false)
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED) .attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING]) .attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN])
.makesContact(false) .makesContact(false)
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.THOUSAND_WAVES, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6) new AttackMove(Moves.THOUSAND_WAVES, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6)
@ -7214,9 +7322,9 @@ export function initMoves() {
new AttackMove(Moves.PRECIPICE_BLADES, Type.GROUND, MoveCategory.PHYSICAL, 120, 85, 10, -1, 0, 6) new AttackMove(Moves.PRECIPICE_BLADES, Type.GROUND, MoveCategory.PHYSICAL, 120, 85, 10, -1, 0, 6)
.makesContact(false) .makesContact(false)
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.DRAGON_ASCENT, Type.FLYING, MoveCategory.PHYSICAL, 120, 100, 5, 100, 0, 6) new AttackMove(Moves.DRAGON_ASCENT, Type.FLYING, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 6)
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true), .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true),
new AttackMove(Moves.HYPERSPACE_FURY, Type.DARK, MoveCategory.PHYSICAL, 100, -1, 5, 100, 0, 6) new AttackMove(Moves.HYPERSPACE_FURY, Type.DARK, MoveCategory.PHYSICAL, 100, -1, 5, -1, 0, 6)
.attr(StatChangeAttr, BattleStat.DEF, -1, true) .attr(StatChangeAttr, BattleStat.DEF, -1, true)
.makesContact(false) .makesContact(false)
.ignoresProtect(), .ignoresProtect(),
@ -7340,23 +7448,23 @@ export function initMoves() {
.condition(new FirstMoveCondition()), .condition(new FirstMoveCondition()),
new SelfStatusMove(Moves.BANEFUL_BUNKER, Type.POISON, -1, 10, -1, 4, 7) new SelfStatusMove(Moves.BANEFUL_BUNKER, Type.POISON, -1, 10, -1, 4, 7)
.attr(ProtectAttr, BattlerTagType.BANEFUL_BUNKER), .attr(ProtectAttr, BattlerTagType.BANEFUL_BUNKER),
new AttackMove(Moves.SPIRIT_SHACKLE, Type.GHOST, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 7) new AttackMove(Moves.SPIRIT_SHACKLE, Type.GHOST, MoveCategory.PHYSICAL, 80, 100, 10, 100, 0, 7)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1) .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1)
.makesContact(false), .makesContact(false),
new AttackMove(Moves.DARKEST_LARIAT, Type.DARK, MoveCategory.PHYSICAL, 85, 100, 10, -1, 0, 7) new AttackMove(Moves.DARKEST_LARIAT, Type.DARK, MoveCategory.PHYSICAL, 85, 100, 10, -1, 0, 7)
.attr(IgnoreOpponentStatChangesAttr), .attr(IgnoreOpponentStatChangesAttr),
new AttackMove(Moves.SPARKLING_ARIA, Type.WATER, MoveCategory.SPECIAL, 90, 100, 10, -1, 0, 7) new AttackMove(Moves.SPARKLING_ARIA, Type.WATER, MoveCategory.SPECIAL, 90, 100, 10, 100, 0, 7)
.attr(HealStatusEffectAttr, false, StatusEffect.BURN) .attr(HealStatusEffectAttr, false, StatusEffect.BURN)
.soundBased() .soundBased()
.target(MoveTarget.ALL_NEAR_OTHERS), .target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.ICE_HAMMER, Type.ICE, MoveCategory.PHYSICAL, 100, 90, 10, 100, 0, 7) new AttackMove(Moves.ICE_HAMMER, Type.ICE, MoveCategory.PHYSICAL, 100, 90, 10, -1, 0, 7)
.attr(StatChangeAttr, BattleStat.SPD, -1, true) .attr(StatChangeAttr, BattleStat.SPD, -1, true)
.punchingMove(), .punchingMove(),
new StatusMove(Moves.FLORAL_HEALING, Type.FAIRY, -1, 10, -1, 0, 7) new StatusMove(Moves.FLORAL_HEALING, Type.FAIRY, -1, 10, -1, 0, 7)
.attr(BoostHealAttr, 0.5, 2/3, true, false, (user, target, move) => user.scene.arena.terrain?.terrainType === TerrainType.GRASSY) .attr(BoostHealAttr, 0.5, 2/3, true, false, (user, target, move) => user.scene.arena.terrain?.terrainType === TerrainType.GRASSY)
.triageMove(), .triageMove(),
new AttackMove(Moves.HIGH_HORSEPOWER, Type.GROUND, MoveCategory.PHYSICAL, 95, 95, 10, -1, 0, 7), new AttackMove(Moves.HIGH_HORSEPOWER, Type.GROUND, MoveCategory.PHYSICAL, 95, 95, 10, -1, 0, 7),
new StatusMove(Moves.STRENGTH_SAP, Type.GRASS, 100, 10, 100, 0, 7) new StatusMove(Moves.STRENGTH_SAP, Type.GRASS, 100, 10, -1, 0, 7)
.attr(HitHealAttr, null, Stat.ATK) .attr(HitHealAttr, null, Stat.ATK)
.attr(StatChangeAttr, BattleStat.ATK, -1) .attr(StatChangeAttr, BattleStat.ATK, -1)
.condition((user, target, move) => target.summonData.battleStats[BattleStat.ATK] > -6) .condition((user, target, move) => target.summonData.battleStats[BattleStat.ATK] > -6)
@ -7368,8 +7476,8 @@ export function initMoves() {
new AttackMove(Moves.LEAFAGE, Type.GRASS, MoveCategory.PHYSICAL, 40, 100, 40, -1, 0, 7) new AttackMove(Moves.LEAFAGE, Type.GRASS, MoveCategory.PHYSICAL, 40, 100, 40, -1, 0, 7)
.makesContact(false), .makesContact(false),
new StatusMove(Moves.SPOTLIGHT, Type.NORMAL, -1, 15, -1, 3, 7) new StatusMove(Moves.SPOTLIGHT, Type.NORMAL, -1, 15, -1, 3, 7)
.unimplemented(), .attr(AddBattlerTagAttr, BattlerTagType.CENTER_OF_ATTENTION, false),
new StatusMove(Moves.TOXIC_THREAD, Type.POISON, 100, 20, 100, 0, 7) new StatusMove(Moves.TOXIC_THREAD, Type.POISON, 100, 20, -1, 0, 7)
.attr(StatusEffectAttr, StatusEffect.POISON) .attr(StatusEffectAttr, StatusEffect.POISON)
.attr(StatChangeAttr, BattleStat.SPD, -1), .attr(StatChangeAttr, BattleStat.SPD, -1),
new SelfStatusMove(Moves.LASER_FOCUS, Type.NORMAL, -1, 30, -1, 0, 7) new SelfStatusMove(Moves.LASER_FOCUS, Type.NORMAL, -1, 30, -1, 0, 7)
@ -7384,7 +7492,7 @@ export function initMoves() {
.attr(StatusCategoryOnAllyAttr) .attr(StatusCategoryOnAllyAttr)
.attr(HealOnAllyAttr, 0.5, true, false) .attr(HealOnAllyAttr, 0.5, true, false)
.ballBombMove(), .ballBombMove(),
new AttackMove(Moves.ANCHOR_SHOT, Type.STEEL, MoveCategory.PHYSICAL, 80, 100, 20, -1, 0, 7) new AttackMove(Moves.ANCHOR_SHOT, Type.STEEL, MoveCategory.PHYSICAL, 80, 100, 20, 100, 0, 7)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1), .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1),
new StatusMove(Moves.PSYCHIC_TERRAIN, Type.PSYCHIC, -1, 10, -1, 0, 7) new StatusMove(Moves.PSYCHIC_TERRAIN, Type.PSYCHIC, -1, 10, -1, 0, 7)
.attr(TerrainChangeAttr, TerrainType.PSYCHIC) .attr(TerrainChangeAttr, TerrainType.PSYCHIC)
@ -7428,7 +7536,7 @@ export function initMoves() {
.ballBombMove() .ballBombMove()
.makesContact(false) .makesContact(false)
.partial(), .partial(),
new AttackMove(Moves.CLANGING_SCALES, Type.DRAGON, MoveCategory.SPECIAL, 110, 100, 5, 100, 0, 7) new AttackMove(Moves.CLANGING_SCALES, Type.DRAGON, MoveCategory.SPECIAL, 110, 100, 5, -1, 0, 7)
.attr(StatChangeAttr, BattleStat.DEF, -1, true) .attr(StatChangeAttr, BattleStat.DEF, -1, true)
.soundBased() .soundBased()
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
@ -7462,17 +7570,17 @@ export function initMoves() {
new AttackMove(Moves.PULVERIZING_PANCAKE, Type.NORMAL, MoveCategory.PHYSICAL, 210, -1, 1, -1, 0, 7) new AttackMove(Moves.PULVERIZING_PANCAKE, Type.NORMAL, MoveCategory.PHYSICAL, 210, -1, 1, -1, 0, 7)
.partial() .partial()
.ignoresVirtual(), .ignoresVirtual(),
new SelfStatusMove(Moves.EXTREME_EVOBOOST, Type.NORMAL, -1, 1, 100, 0, 7) new SelfStatusMove(Moves.EXTREME_EVOBOOST, Type.NORMAL, -1, 1, -1, 0, 7)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 2, true) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 2, true)
.ignoresVirtual(), .ignoresVirtual(),
new AttackMove(Moves.GENESIS_SUPERNOVA, Type.PSYCHIC, MoveCategory.SPECIAL, 185, -1, 1, -1, 0, 7) new AttackMove(Moves.GENESIS_SUPERNOVA, Type.PSYCHIC, MoveCategory.SPECIAL, 185, -1, 1, 100, 0, 7)
.attr(TerrainChangeAttr, TerrainType.PSYCHIC) .attr(TerrainChangeAttr, TerrainType.PSYCHIC)
.ignoresVirtual(), .ignoresVirtual(),
/* End Unused */ /* End Unused */
new AttackMove(Moves.SHELL_TRAP, Type.FIRE, MoveCategory.SPECIAL, 150, 100, 5, -1, -3, 7) new AttackMove(Moves.SHELL_TRAP, Type.FIRE, MoveCategory.SPECIAL, 150, 100, 5, -1, -3, 7)
.target(MoveTarget.ALL_NEAR_ENEMIES) .target(MoveTarget.ALL_NEAR_ENEMIES)
.partial(), .partial(),
new AttackMove(Moves.FLEUR_CANNON, Type.FAIRY, MoveCategory.SPECIAL, 130, 90, 5, 100, 0, 7) new AttackMove(Moves.FLEUR_CANNON, Type.FAIRY, MoveCategory.SPECIAL, 130, 90, 5, -1, 0, 7)
.attr(StatChangeAttr, BattleStat.SPATK, -2, true), .attr(StatChangeAttr, BattleStat.SPATK, -2, true),
new AttackMove(Moves.PSYCHIC_FANGS, Type.PSYCHIC, MoveCategory.PHYSICAL, 85, 100, 10, -1, 0, 7) new AttackMove(Moves.PSYCHIC_FANGS, Type.PSYCHIC, MoveCategory.PHYSICAL, 85, 100, 10, -1, 0, 7)
.bitingMove() .bitingMove()
@ -7495,7 +7603,7 @@ export function initMoves() {
new AttackMove(Moves.MOONGEIST_BEAM, Type.GHOST, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 7) new AttackMove(Moves.MOONGEIST_BEAM, Type.GHOST, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 7)
.ignoresAbilities() .ignoresAbilities()
.partial(), .partial(),
new StatusMove(Moves.TEARFUL_LOOK, Type.NORMAL, -1, 20, 100, 0, 7) new StatusMove(Moves.TEARFUL_LOOK, Type.NORMAL, -1, 20, -1, 0, 7)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1), .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1),
new AttackMove(Moves.ZING_ZAP, Type.ELECTRIC, MoveCategory.PHYSICAL, 80, 100, 10, 30, 0, 7) new AttackMove(Moves.ZING_ZAP, Type.ELECTRIC, MoveCategory.PHYSICAL, 80, 100, 10, 30, 0, 7)
.attr(FlinchAttr), .attr(FlinchAttr),
@ -7565,6 +7673,7 @@ export function initMoves() {
new AttackMove(Moves.BADDY_BAD, Type.DARK, MoveCategory.SPECIAL, 80, 95, 15, -1, 0, 7) new AttackMove(Moves.BADDY_BAD, Type.DARK, MoveCategory.SPECIAL, 80, 95, 15, -1, 0, 7)
.attr(AddArenaTagAttr, ArenaTagType.REFLECT, 5, false, true), .attr(AddArenaTagAttr, ArenaTagType.REFLECT, 5, false, true),
new AttackMove(Moves.SAPPY_SEED, Type.GRASS, MoveCategory.PHYSICAL, 100, 90, 10, 100, 0, 7) new AttackMove(Moves.SAPPY_SEED, Type.GRASS, MoveCategory.PHYSICAL, 100, 90, 10, 100, 0, 7)
.makesContact(false)
.attr(AddBattlerTagAttr, BattlerTagType.SEEDED), .attr(AddBattlerTagAttr, BattlerTagType.SEEDED),
new AttackMove(Moves.FREEZY_FROST, Type.ICE, MoveCategory.SPECIAL, 100, 90, 10, -1, 0, 7) new AttackMove(Moves.FREEZY_FROST, Type.ICE, MoveCategory.SPECIAL, 100, 90, 10, -1, 0, 7)
.attr(ResetStatsAttr), .attr(ResetStatsAttr),
@ -7592,7 +7701,7 @@ export function initMoves() {
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1) .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, false, 1) .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, false, 1)
.bitingMove(), .bitingMove(),
new SelfStatusMove(Moves.STUFF_CHEEKS, Type.NORMAL, -1, 10, 100, 0, 8) // TODO: Stuff Cheeks should not be selectable when the user does not have a berry, see wiki new SelfStatusMove(Moves.STUFF_CHEEKS, Type.NORMAL, -1, 10, -1, 0, 8) // TODO: Stuff Cheeks should not be selectable when the user does not have a berry, see wiki
.attr(EatBerryAttr) .attr(EatBerryAttr)
.attr(StatChangeAttr, BattleStat.DEF, 2, true) .attr(StatChangeAttr, BattleStat.DEF, 2, true)
.condition((user) => { .condition((user) => {
@ -7600,10 +7709,10 @@ export function initMoves() {
return userBerries.length > 0; return userBerries.length > 0;
}) })
.partial(), .partial(),
new SelfStatusMove(Moves.NO_RETREAT, Type.FIGHTING, -1, 5, 100, 0, 8) new SelfStatusMove(Moves.NO_RETREAT, Type.FIGHTING, -1, 5, -1, 0, 8)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, true) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, true)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, true, 1), .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, true, 1),
new StatusMove(Moves.TAR_SHOT, Type.ROCK, 100, 15, 100, 0, 8) new StatusMove(Moves.TAR_SHOT, Type.ROCK, 100, 15, -1, 0, 8)
.attr(StatChangeAttr, BattleStat.SPD, -1) .attr(StatChangeAttr, BattleStat.SPD, -1)
.partial(), .partial(),
new StatusMove(Moves.MAGIC_POWDER, Type.PSYCHIC, 100, 20, -1, 0, 8) new StatusMove(Moves.MAGIC_POWDER, Type.PSYCHIC, 100, 20, -1, 0, 8)
@ -7699,18 +7808,18 @@ export function initMoves() {
.unimplemented() .unimplemented()
.ignoresVirtual(), .ignoresVirtual(),
/* End Unused */ /* End Unused */
new SelfStatusMove(Moves.CLANGOROUS_SOUL, Type.DRAGON, 100, 5, 100, 0, 8) new SelfStatusMove(Moves.CLANGOROUS_SOUL, Type.DRAGON, 100, 5, -1, 0, 8)
.attr(CutHpStatBoostAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, 3) .attr(CutHpStatBoostAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, 3)
.soundBased() .soundBased()
.danceMove(), .danceMove(),
new AttackMove(Moves.BODY_PRESS, Type.FIGHTING, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 8) new AttackMove(Moves.BODY_PRESS, Type.FIGHTING, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 8)
.attr(DefAtkAttr), .attr(DefAtkAttr),
new StatusMove(Moves.DECORATE, Type.FAIRY, -1, 15, 100, 0, 8) new StatusMove(Moves.DECORATE, Type.FAIRY, -1, 15, -1, 0, 8)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 2), .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 2),
new AttackMove(Moves.DRUM_BEATING, Type.GRASS, MoveCategory.PHYSICAL, 80, 100, 10, 100, 0, 8) new AttackMove(Moves.DRUM_BEATING, Type.GRASS, MoveCategory.PHYSICAL, 80, 100, 10, 100, 0, 8)
.attr(StatChangeAttr, BattleStat.SPD, -1) .attr(StatChangeAttr, BattleStat.SPD, -1)
.makesContact(false), .makesContact(false),
new AttackMove(Moves.SNAP_TRAP, Type.GRASS, MoveCategory.PHYSICAL, 35, 100, 15, 100, 0, 8) new AttackMove(Moves.SNAP_TRAP, Type.GRASS, MoveCategory.PHYSICAL, 35, 100, 15, -1, 0, 8)
.attr(TrapAttr, BattlerTagType.SNAP_TRAP), .attr(TrapAttr, BattlerTagType.SNAP_TRAP),
new AttackMove(Moves.PYRO_BALL, Type.FIRE, MoveCategory.PHYSICAL, 120, 90, 5, 10, 0, 8) new AttackMove(Moves.PYRO_BALL, Type.FIRE, MoveCategory.PHYSICAL, 120, 90, 5, 10, 0, 8)
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE) .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
@ -7762,7 +7871,7 @@ export function initMoves() {
new AttackMove(Moves.STEEL_ROLLER, Type.STEEL, MoveCategory.PHYSICAL, 130, 100, 5, -1, 0, 8) new AttackMove(Moves.STEEL_ROLLER, Type.STEEL, MoveCategory.PHYSICAL, 130, 100, 5, -1, 0, 8)
.attr(ClearTerrainAttr) .attr(ClearTerrainAttr)
.condition((user, target, move) => !!user.scene.arena.terrain), .condition((user, target, move) => !!user.scene.arena.terrain),
new AttackMove(Moves.SCALE_SHOT, Type.DRAGON, MoveCategory.PHYSICAL, 25, 90, 20, 100, 0, 8) new AttackMove(Moves.SCALE_SHOT, Type.DRAGON, MoveCategory.PHYSICAL, 25, 90, 20, -1, 0, 8)
//.attr(StatChangeAttr, BattleStat.SPD, 1, true) // TODO: Have boosts only apply at end of move, not after every hit //.attr(StatChangeAttr, BattleStat.SPD, 1, true) // TODO: Have boosts only apply at end of move, not after every hit
//.attr(StatChangeAttr, BattleStat.DEF, -1, true) //.attr(StatChangeAttr, BattleStat.DEF, -1, true)
.attr(MultiHitAttr) .attr(MultiHitAttr)
@ -7802,7 +7911,7 @@ export function initMoves() {
new StatusMove(Moves.CORROSIVE_GAS, Type.POISON, 100, 40, -1, 0, 8) new StatusMove(Moves.CORROSIVE_GAS, Type.POISON, 100, 40, -1, 0, 8)
.target(MoveTarget.ALL_NEAR_OTHERS) .target(MoveTarget.ALL_NEAR_OTHERS)
.unimplemented(), .unimplemented(),
new StatusMove(Moves.COACHING, Type.FIGHTING, -1, 10, 100, 0, 8) new StatusMove(Moves.COACHING, Type.FIGHTING, -1, 10, -1, 0, 8)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], 1) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], 1)
.target(MoveTarget.NEAR_ALLY), .target(MoveTarget.NEAR_ALLY),
new AttackMove(Moves.FLIP_TURN, Type.WATER, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 8) new AttackMove(Moves.FLIP_TURN, Type.WATER, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 8)
@ -7828,7 +7937,7 @@ export function initMoves() {
.attr(MultiHitAttr, MultiHitType._3) .attr(MultiHitAttr, MultiHitType._3)
.attr(CritOnlyAttr) .attr(CritOnlyAttr)
.punchingMove(), .punchingMove(),
new AttackMove(Moves.THUNDER_CAGE, Type.ELECTRIC, MoveCategory.SPECIAL, 80, 90, 15, 100, 0, 8) new AttackMove(Moves.THUNDER_CAGE, Type.ELECTRIC, MoveCategory.SPECIAL, 80, 90, 15, -1, 0, 8)
.attr(TrapAttr, BattlerTagType.THUNDER_CAGE), .attr(TrapAttr, BattlerTagType.THUNDER_CAGE),
new AttackMove(Moves.DRAGON_ENERGY, Type.DRAGON, MoveCategory.SPECIAL, 150, 100, 5, -1, 0, 8) new AttackMove(Moves.DRAGON_ENERGY, Type.DRAGON, MoveCategory.SPECIAL, 150, 100, 5, -1, 0, 8)
.attr(HpPowerAttr) .attr(HpPowerAttr)
@ -7846,16 +7955,16 @@ export function initMoves() {
new AttackMove(Moves.ASTRAL_BARRAGE, Type.GHOST, MoveCategory.SPECIAL, 120, 100, 5, -1, 0, 8) new AttackMove(Moves.ASTRAL_BARRAGE, Type.GHOST, MoveCategory.SPECIAL, 120, 100, 5, -1, 0, 8)
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.EERIE_SPELL, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 5, 100, 0, 8) new AttackMove(Moves.EERIE_SPELL, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 5, 100, 0, 8)
.soundBased() .attr(AttackReducePpMoveAttr, 3)
.partial(), .soundBased(),
new AttackMove(Moves.DIRE_CLAW, Type.POISON, MoveCategory.PHYSICAL, 80, 100, 15, 50, 0, 8) new AttackMove(Moves.DIRE_CLAW, Type.POISON, MoveCategory.PHYSICAL, 80, 100, 15, 50, 0, 8)
.attr(MultiStatusEffectAttr, [StatusEffect.POISON, StatusEffect.PARALYSIS, StatusEffect.SLEEP]), .attr(MultiStatusEffectAttr, [StatusEffect.POISON, StatusEffect.PARALYSIS, StatusEffect.SLEEP]),
new AttackMove(Moves.PSYSHIELD_BASH, Type.PSYCHIC, MoveCategory.PHYSICAL, 70, 90, 10, 100, 0, 8) new AttackMove(Moves.PSYSHIELD_BASH, Type.PSYCHIC, MoveCategory.PHYSICAL, 70, 90, 10, 100, 0, 8)
.attr(StatChangeAttr, BattleStat.DEF, 1, true), .attr(StatChangeAttr, BattleStat.DEF, 1, true),
new SelfStatusMove(Moves.POWER_SHIFT, Type.NORMAL, -1, 10, 100, 0, 8) new SelfStatusMove(Moves.POWER_SHIFT, Type.NORMAL, -1, 10, -1, 0, 8)
.unimplemented(), .unimplemented(),
new AttackMove(Moves.STONE_AXE, Type.ROCK, MoveCategory.PHYSICAL, 65, 90, 15, 100, 0, 8) new AttackMove(Moves.STONE_AXE, Type.ROCK, MoveCategory.PHYSICAL, 65, 90, 15, 100, 0, 8)
.attr(AddArenaTrapTagAttr, ArenaTagType.STEALTH_ROCK) .attr(AddArenaTrapTagHitAttr, ArenaTagType.STEALTH_ROCK)
.slicingMove(), .slicingMove(),
new AttackMove(Moves.SPRINGTIDE_STORM, Type.FAIRY, MoveCategory.SPECIAL, 100, 80, 5, 30, 0, 8) new AttackMove(Moves.SPRINGTIDE_STORM, Type.FAIRY, MoveCategory.SPECIAL, 100, 80, 5, 30, 0, 8)
.attr(StatChangeAttr, BattleStat.ATK, -1) .attr(StatChangeAttr, BattleStat.ATK, -1)
@ -7874,10 +7983,10 @@ export function initMoves() {
.attr(RecoilAttr, true, 0.5), .attr(RecoilAttr, true, 0.5),
new AttackMove(Moves.MOUNTAIN_GALE, Type.ICE, MoveCategory.PHYSICAL, 100, 85, 10, 30, 0, 8) new AttackMove(Moves.MOUNTAIN_GALE, Type.ICE, MoveCategory.PHYSICAL, 100, 85, 10, 30, 0, 8)
.attr(FlinchAttr), .attr(FlinchAttr),
new SelfStatusMove(Moves.VICTORY_DANCE, Type.FIGHTING, -1, 10, 100, 0, 8) new SelfStatusMove(Moves.VICTORY_DANCE, Type.FIGHTING, -1, 10, -1, 0, 8)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPD ], 1, true) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPD ], 1, true)
.danceMove(), .danceMove(),
new AttackMove(Moves.HEADLONG_RUSH, Type.GROUND, MoveCategory.PHYSICAL, 120, 100, 5, 100, 0, 8) new AttackMove(Moves.HEADLONG_RUSH, Type.GROUND, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 8)
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true) .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true)
.punchingMove(), .punchingMove(),
new AttackMove(Moves.BARB_BARRAGE, Type.POISON, MoveCategory.PHYSICAL, 60, 100, 10, 50, 0, 8) new AttackMove(Moves.BARB_BARRAGE, Type.POISON, MoveCategory.PHYSICAL, 60, 100, 10, 50, 0, 8)
@ -7899,7 +8008,7 @@ export function initMoves() {
.attr(StatusEffectAttr, StatusEffect.BURN) .attr(StatusEffectAttr, StatusEffect.BURN)
.attr(MovePowerMultiplierAttr, (user, target, move) => target.status ? 2 : 1), .attr(MovePowerMultiplierAttr, (user, target, move) => target.status ? 2 : 1),
new AttackMove(Moves.CEASELESS_EDGE, Type.DARK, MoveCategory.PHYSICAL, 65, 90, 15, 100, 0, 8) new AttackMove(Moves.CEASELESS_EDGE, Type.DARK, MoveCategory.PHYSICAL, 65, 90, 15, 100, 0, 8)
.attr(AddArenaTrapTagAttr, ArenaTagType.SPIKES) .attr(AddArenaTrapTagHitAttr, ArenaTagType.SPIKES)
.slicingMove(), .slicingMove(),
new AttackMove(Moves.BLEAKWIND_STORM, Type.FLYING, MoveCategory.SPECIAL, 100, 80, 10, 30, 0, 8) new AttackMove(Moves.BLEAKWIND_STORM, Type.FLYING, MoveCategory.SPECIAL, 100, 80, 10, 30, 0, 8)
.attr(ThunderAccuracyAttr) .attr(ThunderAccuracyAttr)
@ -8040,15 +8149,15 @@ export function initMoves() {
.makesContact(false), .makesContact(false),
new AttackMove(Moves.LUMINA_CRASH, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, 100, 0, 9) new AttackMove(Moves.LUMINA_CRASH, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, 100, 0, 9)
.attr(StatChangeAttr, BattleStat.SPDEF, -2), .attr(StatChangeAttr, BattleStat.SPDEF, -2),
new AttackMove(Moves.ORDER_UP, Type.DRAGON, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 9) new AttackMove(Moves.ORDER_UP, Type.DRAGON, MoveCategory.PHYSICAL, 80, 100, 10, 100, 0, 9)
.makesContact(false) .makesContact(false)
.partial(), .partial(),
new AttackMove(Moves.JET_PUNCH, Type.WATER, MoveCategory.PHYSICAL, 60, 100, 15, -1, 1, 9) new AttackMove(Moves.JET_PUNCH, Type.WATER, MoveCategory.PHYSICAL, 60, 100, 15, -1, 1, 9)
.punchingMove(), .punchingMove(),
new StatusMove(Moves.SPICY_EXTRACT, Type.GRASS, -1, 15, 100, 0, 9) new StatusMove(Moves.SPICY_EXTRACT, Type.GRASS, -1, 15, -1, 0, 9)
.attr(StatChangeAttr, BattleStat.ATK, 2) .attr(StatChangeAttr, BattleStat.ATK, 2)
.attr(StatChangeAttr, BattleStat.DEF, -2), .attr(StatChangeAttr, BattleStat.DEF, -2),
new AttackMove(Moves.SPIN_OUT, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, 100, 0, 9) new AttackMove(Moves.SPIN_OUT, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9)
.attr(StatChangeAttr, BattleStat.SPD, -2, true), .attr(StatChangeAttr, BattleStat.SPD, -2, true),
new AttackMove(Moves.POPULATION_BOMB, Type.NORMAL, MoveCategory.PHYSICAL, 20, 90, 10, -1, 0, 9) new AttackMove(Moves.POPULATION_BOMB, Type.NORMAL, MoveCategory.PHYSICAL, 20, 90, 10, -1, 0, 9)
.attr(MultiHitAttr, MultiHitType._10) .attr(MultiHitAttr, MultiHitType._10)
@ -8062,7 +8171,7 @@ export function initMoves() {
.triageMove() .triageMove()
.attr(RevivalBlessingAttr) .attr(RevivalBlessingAttr)
.target(MoveTarget.USER), .target(MoveTarget.USER),
new AttackMove(Moves.SALT_CURE, Type.ROCK, MoveCategory.PHYSICAL, 40, 100, 15, -1, 0, 9) new AttackMove(Moves.SALT_CURE, Type.ROCK, MoveCategory.PHYSICAL, 40, 100, 15, 100, 0, 9)
.attr(AddBattlerTagAttr, BattlerTagType.SALT_CURED) .attr(AddBattlerTagAttr, BattlerTagType.SALT_CURED)
.makesContact(false), .makesContact(false),
new AttackMove(Moves.TRIPLE_DIVE, Type.WATER, MoveCategory.PHYSICAL, 30, 95, 10, -1, 0, 9) new AttackMove(Moves.TRIPLE_DIVE, Type.WATER, MoveCategory.PHYSICAL, 30, 95, 10, -1, 0, 9)
@ -8125,7 +8234,7 @@ export function initMoves() {
.attr(WeatherChangeAttr, WeatherType.SNOW) .attr(WeatherChangeAttr, WeatherType.SNOW)
.attr(ForceSwitchOutAttr, true, false) .attr(ForceSwitchOutAttr, true, false)
.target(MoveTarget.BOTH_SIDES), .target(MoveTarget.BOTH_SIDES),
new SelfStatusMove(Moves.TIDY_UP, Type.NORMAL, -1, 10, 100, 0, 9) new SelfStatusMove(Moves.TIDY_UP, Type.NORMAL, -1, 10, -1, 0, 9)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPD ], 1, true, null, true, true) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPD ], 1, true, null, true, true)
.attr(RemoveArenaTrapAttr) .attr(RemoveArenaTrapAttr)
.target(MoveTarget.BOTH_SIDES), .target(MoveTarget.BOTH_SIDES),
@ -8136,7 +8245,7 @@ export function initMoves() {
.attr(StatChangeAttr, BattleStat.SPD, -1), .attr(StatChangeAttr, BattleStat.SPD, -1),
new AttackMove(Moves.TRAILBLAZE, Type.GRASS, MoveCategory.PHYSICAL, 50, 100, 20, 100, 0, 9) new AttackMove(Moves.TRAILBLAZE, Type.GRASS, MoveCategory.PHYSICAL, 50, 100, 20, 100, 0, 9)
.attr(StatChangeAttr, BattleStat.SPD, 1, true), .attr(StatChangeAttr, BattleStat.SPD, 1, true),
new AttackMove(Moves.CHILLING_WATER, Type.WATER, MoveCategory.SPECIAL, 50, 100, 20, -1, 0, 9) new AttackMove(Moves.CHILLING_WATER, Type.WATER, MoveCategory.SPECIAL, 50, 100, 20, 100, 0, 9)
.attr(StatChangeAttr, BattleStat.ATK, -1), .attr(StatChangeAttr, BattleStat.ATK, -1),
new AttackMove(Moves.HYPER_DRILL, Type.NORMAL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9) new AttackMove(Moves.HYPER_DRILL, Type.NORMAL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9)
.ignoresProtect(), .ignoresProtect(),
@ -8198,8 +8307,7 @@ export function initMoves() {
.attr(HealStatusEffectAttr, false, StatusEffect.FREEZE) .attr(HealStatusEffectAttr, false, StatusEffect.FREEZE)
.attr(StatusEffectAttr, StatusEffect.BURN) .attr(StatusEffectAttr, StatusEffect.BURN)
.target(MoveTarget.ALL_NEAR_ENEMIES) .target(MoveTarget.ALL_NEAR_ENEMIES)
.triageMove() .triageMove(),
.partial(),
new AttackMove(Moves.SYRUP_BOMB, Type.GRASS, MoveCategory.SPECIAL, 60, 85, 10, -1, 0, 9) new AttackMove(Moves.SYRUP_BOMB, Type.GRASS, MoveCategory.SPECIAL, 60, 85, 10, -1, 0, 9)
.attr(StatChangeAttr, BattleStat.SPD, -1) //Temporary .attr(StatChangeAttr, BattleStat.SPD, -1) //Temporary
.ballBombMove() .ballBombMove()
@ -8217,7 +8325,7 @@ export function initMoves() {
new AttackMove(Moves.FICKLE_BEAM, Type.DRAGON, MoveCategory.SPECIAL, 80, 100, 5, 30, 0, 9) new AttackMove(Moves.FICKLE_BEAM, Type.DRAGON, MoveCategory.SPECIAL, 80, 100, 5, 30, 0, 9)
.attr(PreMoveMessageAttr, doublePowerChanceMessageFunc) .attr(PreMoveMessageAttr, doublePowerChanceMessageFunc)
.attr(DoublePowerChanceAttr), .attr(DoublePowerChanceAttr),
new SelfStatusMove(Moves.BURNING_BULWARK, Type.FIRE, -1, 10, 100, 4, 9) new SelfStatusMove(Moves.BURNING_BULWARK, Type.FIRE, -1, 10, -1, 4, 9)
.attr(ProtectAttr, BattlerTagType.BURNING_BULWARK), .attr(ProtectAttr, BattlerTagType.BURNING_BULWARK),
new AttackMove(Moves.THUNDERCLAP, Type.ELECTRIC, MoveCategory.SPECIAL, 70, 100, 5, -1, 1, 9) new AttackMove(Moves.THUNDERCLAP, Type.ELECTRIC, MoveCategory.SPECIAL, 70, 100, 5, -1, 1, 9)
.condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].category !== MoveCategory.STATUS), .condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].category !== MoveCategory.STATUS),
@ -8229,7 +8337,7 @@ export function initMoves() {
.slicingMove(), .slicingMove(),
new AttackMove(Moves.HARD_PRESS, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9) new AttackMove(Moves.HARD_PRESS, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9)
.attr(OpponentHighHpPowerAttr), .attr(OpponentHighHpPowerAttr),
new StatusMove(Moves.DRAGON_CHEER, Type.DRAGON, -1, 15, 100, 0, 9) new StatusMove(Moves.DRAGON_CHEER, Type.DRAGON, -1, 15, -1, 0, 9)
.attr(AddBattlerTagAttr, BattlerTagType.CRIT_BOOST, false, true) .attr(AddBattlerTagAttr, BattlerTagType.CRIT_BOOST, false, true)
.target(MoveTarget.NEAR_ALLY) .target(MoveTarget.NEAR_ALLY)
.partial(), .partial(),

View File

@ -1,5 +1,5 @@
import BattleScene from "../battle-scene"; import BattleScene from "../battle-scene";
import i18next from "../plugins/i18n"; import i18next from "i18next";
export enum PokeballType { export enum PokeballType {
POKEBALL, POKEBALL,

View File

@ -13,7 +13,8 @@ import { speciesEggMoves } from "./egg-moves";
import { GameMode } from "../game-mode"; import { GameMode } from "../game-mode";
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities"; import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities";
import { VariantSet } from "./variant"; import { VariantSet } from "./variant";
import i18next, { Localizable } from "../plugins/i18n"; import i18next from "i18next";
import { Localizable } from "#app/interfaces/locales";
import { Stat } from "./pokemon-stat"; import { Stat } from "./pokemon-stat";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { PartyMemberStrength } from "#enums/party-member-strength"; import { PartyMemberStrength } from "#enums/party-member-strength";
@ -3795,7 +3796,7 @@ export const starterPassiveAbilities = {
[Species.IRON_TREADS]: Abilities.STEELY_SPIRIT, [Species.IRON_TREADS]: Abilities.STEELY_SPIRIT,
[Species.IRON_BUNDLE]: Abilities.SNOW_WARNING, [Species.IRON_BUNDLE]: Abilities.SNOW_WARNING,
[Species.IRON_HANDS]: Abilities.IRON_FIST, [Species.IRON_HANDS]: Abilities.IRON_FIST,
[Species.IRON_JUGULIS]: Abilities.AERILATE, [Species.IRON_JUGULIS]: Abilities.LIGHTNING_ROD,
[Species.IRON_MOTH]: Abilities.LEVITATE, [Species.IRON_MOTH]: Abilities.LEVITATE,
[Species.IRON_THORNS]: Abilities.SAND_STREAM, [Species.IRON_THORNS]: Abilities.SAND_STREAM,
[Species.FRIGIBAX]: Abilities.SNOW_WARNING, [Species.FRIGIBAX]: Abilities.SNOW_WARNING,

View File

@ -1,4 +1,4 @@
import i18next from "../plugins/i18n"; import i18next from "i18next";
export enum Stat { export enum Stat {
HP = 0, HP = 0,

View File

@ -1,4 +1,4 @@
import i18next from "../plugins/i18n"; import i18next from "i18next";
export function getBattleCountSplashMessage(): string { export function getBattleCountSplashMessage(): string {
return `{COUNT} ${i18next.t("splashMessages:battlesWon")}`; return `{COUNT} ${i18next.t("splashMessages:battlesWon")}`;

View File

@ -262,6 +262,9 @@ export class EggHatchPhase extends Phase {
if (!this.canSkip || this.skipped) { if (!this.canSkip || this.skipped) {
return false; return false;
} }
if (this.eggCounterContainer.eggCountText?.data === undefined) {
return false;
}
this.skipped = true; this.skipped = true;
if (!this.hatched) { if (!this.hatched) {
this.doHatch(); this.doHatch();

View File

@ -58,5 +58,6 @@ export enum BattlerTagType {
MAGNET_RISEN = "MAGNET_RISEN", MAGNET_RISEN = "MAGNET_RISEN",
MINIMIZED = "MINIMIZED", MINIMIZED = "MINIMIZED",
DESTINY_BOND = "DESTINY_BOND", DESTINY_BOND = "DESTINY_BOND",
CENTER_OF_ATTENTION = "CENTER_OF_ATTENTION",
ICE_FACE = "ICE_FACE" ICE_FACE = "ICE_FACE"
} }

View File

@ -18,11 +18,11 @@ import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEv
import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "../data/tms"; import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "../data/tms";
import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase, ToggleDoublePositionPhase } from "../phases"; import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase, ToggleDoublePositionPhase } from "../phases";
import { BattleStat } from "../data/battle-stat"; import { BattleStat } from "../data/battle-stat";
import { BattlerTag, BattlerTagLapseType, EncoreTag, HelpingHandTag, HighestStatBoostTag, TypeBoostTag, getBattlerTag } from "../data/battler-tags"; import { BattlerTag, BattlerTagLapseType, EncoreTag, HelpingHandTag, HighestStatBoostTag, TypeBoostTag, TypeImmuneTag, getBattlerTag } from "../data/battler-tags";
import { WeatherType } from "../data/weather"; import { WeatherType } from "../data/weather";
import { TempBattleStat } from "../data/temp-battle-stat"; import { TempBattleStat } from "../data/temp-battle-stat";
import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from "../data/arena-tag"; import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from "../data/arena-tag";
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 { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, 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, AllyMoveCategoryPowerBoostAbAttr, FieldMoveTypePowerBoostAbAttr } from "../data/ability";
import PokemonData from "../system/pokemon-data"; import PokemonData from "../system/pokemon-data";
import { BattlerIndex } from "../battle"; import { BattlerIndex } from "../battle";
import { Mode } from "../ui/ui"; import { Mode } from "../ui/ui";
@ -37,7 +37,7 @@ import { SpeciesFormChange, SpeciesFormChangeActiveTrigger, SpeciesFormChangeMov
import { TerrainType } from "../data/terrain"; import { TerrainType } from "../data/terrain";
import { TrainerSlot } from "../data/trainer-config"; import { TrainerSlot } from "../data/trainer-config";
import * as Overrides from "../overrides"; import * as Overrides from "../overrides";
import i18next from "../plugins/i18n"; import i18next from "i18next";
import { speciesEggMoves } from "../data/egg-moves"; import { speciesEggMoves } from "../data/egg-moves";
import { ModifierTier } from "../modifier/modifier-tier"; import { ModifierTier } from "../modifier/modifier-tier";
import { applyChallenges, ChallengeType } from "#app/data/challenge.js"; import { applyChallenges, ChallengeType } from "#app/data/challenge.js";
@ -1096,7 +1096,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
isGrounded(): boolean { isGrounded(): boolean {
return !this.isOfType(Type.FLYING, true, true) && !this.hasAbility(Abilities.LEVITATE); return !this.isOfType(Type.FLYING, true, true) && !this.hasAbility(Abilities.LEVITATE) && !this.getTag(BattlerTagType.MAGNET_RISEN);
} }
/** /**
@ -1134,6 +1134,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (!cancelled.value && !ignoreAbility) { if (!cancelled.value && !ignoreAbility) {
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true); applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true);
} }
return (!cancelled.value ? typeMultiplier.value : 0) as TypeDamageMultiplier; return (!cancelled.value ? typeMultiplier.value : 0) as TypeDamageMultiplier;
} }
@ -1161,6 +1162,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (!ignoreStrongWinds && this.scene.arena.weather?.weatherType === WeatherType.STRONG_WINDS && !this.scene.arena.weather.isEffectSuppressed(this.scene) && multiplier >= 2 && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) { if (!ignoreStrongWinds && this.scene.arena.weather?.weatherType === WeatherType.STRONG_WINDS && !this.scene.arena.weather.isEffectSuppressed(this.scene) && multiplier >= 2 && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) {
multiplier /= 2; multiplier /= 2;
} }
if (!!this.summonData?.tags.find((tag) => tag instanceof TypeImmuneTag && tag.immuneType === moveType)) {
multiplier = 0;
}
return multiplier; return multiplier;
} }
@ -1724,7 +1730,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (typeless) { if (typeless) {
typeMultiplier.value = 1; typeMultiplier.value = 1;
} }
if (types.find(t => move.isTypeImmune(t))) { if (types.find(t => move.isTypeImmune(source, this, t))) {
typeMultiplier.value = 0; typeMultiplier.value = 0;
} }
@ -1747,7 +1753,20 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
power.value = 60; power.value = 60;
} }
applyPreAttackAbAttrs(VariableMovePowerAbAttr, source, this, move, power); applyPreAttackAbAttrs(VariableMovePowerAbAttr, source, this, move, power);
this.scene.getField(true).map(p => applyPreAttackAbAttrs(FieldVariableMovePowerAbAttr, this, source, move, power));
if (source.getAlly()?.hasAbilityWithAttr(AllyMoveCategoryPowerBoostAbAttr)) {
applyPreAttackAbAttrs(AllyMoveCategoryPowerBoostAbAttr, source, this, move, power);
}
const fieldAuras = new Set(
this.scene.getField(true)
.map((p) => p.getAbilityAttrs(FieldMoveTypePowerBoostAbAttr) as FieldMoveTypePowerBoostAbAttr[])
.flat(),
);
for (const aura of fieldAuras) {
// The only relevant values are `move` and the `power` holder
aura.applyPreAttack(null, null, null, move, [power]);
}
applyPreDefendAbAttrs(ReceivedMoveDamageMultiplierAbAttr, this, source, move, cancelled, power); applyPreDefendAbAttrs(ReceivedMoveDamageMultiplierAbAttr, this, source, move, cancelled, power);

76
src/interfaces/locales.ts Normal file
View File

@ -0,0 +1,76 @@
export interface Localizable {
localize(): void;
}
export interface SimpleTranslationEntries {
[key: string]: string
}
export interface MoveTranslationEntry {
name: string,
effect: string
}
export interface MoveTranslationEntries {
[key: string]: MoveTranslationEntry
}
export interface AbilityTranslationEntry {
name: string,
description: string
}
export interface AbilityTranslationEntries {
[key: string]: AbilityTranslationEntry
}
export interface ModifierTypeTranslationEntry {
name?: string,
description?: string,
extra?: SimpleTranslationEntries
}
export interface ModifierTypeTranslationEntries {
ModifierType: { [key: string]: ModifierTypeTranslationEntry },
AttackTypeBoosterItem: SimpleTranslationEntries,
TempBattleStatBoosterItem: SimpleTranslationEntries,
TempBattleStatBoosterStatName: SimpleTranslationEntries,
BaseStatBoosterItem: SimpleTranslationEntries,
EvolutionItem: SimpleTranslationEntries,
FormChangeItem: SimpleTranslationEntries,
}
export interface PokemonInfoTranslationEntries {
Stat: SimpleTranslationEntries,
Type: SimpleTranslationEntries,
}
export interface BerryTranslationEntry {
name: string,
effect: string,
}
export interface BerryTranslationEntries {
[key: string]: BerryTranslationEntry
}
export interface AchievementTranslationEntry {
name?: string,
description?: string,
}
export interface AchievementTranslationEntries {
[key: string]: AchievementTranslationEntry;
}
export interface DialogueTranslationEntry {
[key: number]: string;
}
export interface DialogueTranslationCategory {
[category: string]: DialogueTranslationEntry;
}
export interface DialogueTranslationEntries {
[trainertype: string]: DialogueTranslationCategory;
}

View File

@ -24,6 +24,8 @@ import { Biome } from "#enums/biome";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
export class LoadingScene extends SceneBase { export class LoadingScene extends SceneBase {
readonly LOAD_EVENTS = Phaser.Loader.Events;
constructor() { constructor() {
super("loading"); super("loading");
@ -35,10 +37,6 @@ export class LoadingScene extends SceneBase {
Utils.localPing(); Utils.localPing();
this.load["manifest"] = this.game["manifest"]; this.load["manifest"] = this.game["manifest"];
if (!isMobile()) {
this.load.video("intro_dark", "images/intro_dark.mp4", true);
}
this.loadImage("loading_bg", "arenas"); this.loadImage("loading_bg", "arenas");
this.loadImage("logo", ""); this.loadImage("logo", "");
this.loadImage("pride-update", "events"); this.loadImage("pride-update", "events");
@ -421,58 +419,46 @@ export class LoadingScene extends SceneBase {
}); });
disclaimerDescriptionText.setOrigin(0.5, 0.5); disclaimerDescriptionText.setOrigin(0.5, 0.5);
disclaimerText.setVisible(false); loadingGraphics.push(bg, graphics, progressBar, progressBox, logo, percentText, assetText, disclaimerText, disclaimerDescriptionText);
disclaimerDescriptionText.setVisible(false);
const intro = this.add.video(0, 0);
intro.setOrigin(0, 0);
intro.setScale(3);
this.load.on("progress", (value: string) => {
const parsedValue = parseFloat(value);
percentText.setText(`${Math.floor(parsedValue * 100)}%`);
progressBar.clear();
progressBar.fillStyle(0xffffff, 0.8);
progressBar.fillRect(midWidth - 320, 360, 640 * parsedValue, 64);
});
this.load.on("fileprogress", file => {
assetText.setText(i18next.t("menu:loadingAsset", { assetName: file.key }));
});
loadingGraphics.push(bg, graphics, progressBar, progressBox, logo, percentText, assetText);
if (!mobile) { if (!mobile) {
loadingGraphics.map(g => g.setVisible(false)); loadingGraphics.map(g => g.setVisible(false));
} }
const destroyLoadingAssets = () => { const intro = this.add.video(0, 0);
intro.destroy(); intro.on(Phaser.GameObjects.Events.VIDEO_COMPLETE, (video: Phaser.GameObjects.Video) => {
bg.destroy(); this.tweens.add({
logo.destroy(); targets: intro,
progressBar.destroy(); duration: 500,
progressBox.destroy(); alpha: 0,
percentText.destroy(); ease: "Sine.easeIn",
assetText.destroy(); onComplete: () => video.destroy(),
}; });
loadingGraphics.forEach(g => g.setVisible(true));
});
intro.setOrigin(0, 0);
intro.setScale(3);
this.load.on("filecomplete", key => { this.load.once(this.LOAD_EVENTS.START, () => {
// videos do not need to be preloaded
intro.loadURL("images/intro_dark.mp4", true);
if (mobile) {
intro.video.setAttribute("webkit-playsinline", "webkit-playsinline");
intro.video.setAttribute("playsinline", "playsinline");
}
intro.play();
});
this.load.on(this.LOAD_EVENTS.PROGRESS , (progress: number) => {
percentText.setText(`${Math.floor(progress * 100)}%`);
progressBar.clear();
progressBar.fillStyle(0xffffff, 0.8);
progressBar.fillRect(midWidth - 320, 360, 640 * progress, 64);
});
this.load.on(this.LOAD_EVENTS.FILE_COMPLETE, (key: string) => {
assetText.setText(i18next.t("menu:loadingAsset", { assetName: key }));
switch (key) { switch (key) {
case "intro_dark":
intro.load("intro_dark");
intro.on("complete", () => {
this.tweens.add({
targets: intro,
duration: 500,
alpha: 0,
ease: "Sine.easeIn"
});
loadingGraphics.map(g => g.setVisible(true));
disclaimerText.setVisible(true);
disclaimerDescriptionText.setVisible(true);
});
intro.play();
break;
case "loading_bg": case "loading_bg":
bg.setTexture("loading_bg"); bg.setTexture("loading_bg");
if (mobile) { if (mobile) {
@ -488,7 +474,7 @@ export class LoadingScene extends SceneBase {
} }
}); });
this.load.on("complete", () => destroyLoadingAssets()); this.load.on(this.LOAD_EVENTS.COMPLETE, () => loadingGraphics.forEach(go => go.destroy()));
} }
get gameHeight() { get gameHeight() {

View File

@ -1,8 +1,8 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
"blockRecoilDamage" : "{{pokemonName}} wurde durch {{abilityName}}\nvor Rückstoß geschützt!", "blockRecoilDamage" : "{{pokemonName}} wurde durch {{abilityName}}\nvor Rückstoß geschützt!",
"badDreams": "{{pokemonName}} ist in einem Alptraum gefangen!", "badDreams": "{{pokemonName}} ist in einem Alptraum gefangen!",
"windPowerCharged": "Der Treffer durch {{moveName}} läd die Stärke von {{pokemonName}} auf!", "windPowerCharged": "Der Treffer durch {{moveName}} läd die Stärke von {{pokemonName}} auf!",
"iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!", "iceFaceAvoidedDamage": "{{pokemonName}} wehrt Schaden\nmit {{abilityName}} ab!",
} as const; } as const;

View File

@ -1,4 +1,4 @@
import { AbilityTranslationEntries } from "#app/plugins/i18n.js"; import { AbilityTranslationEntries } from "#app/interfaces/locales.js";
export const ability: AbilityTranslationEntries = { export const ability: AbilityTranslationEntries = {
stench: { stench: {

View File

@ -1,4 +1,4 @@
import {AchievementTranslationEntries} from "#app/plugins/i18n.js"; import {AchievementTranslationEntries} from "#app/interfaces/locales.js";
// Achievement translations for the when the player character is male // Achievement translations for the when the player character is male
export const PGMachv: AchievementTranslationEntries = { export const PGMachv: AchievementTranslationEntries = {

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const battleMessageUiHandler: SimpleTranslationEntries = { export const battleMessageUiHandler: SimpleTranslationEntries = {
"ivBest": "Sensationell", "ivBest": "Sensationell",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const battle: SimpleTranslationEntries = { export const battle: SimpleTranslationEntries = {
"bossAppeared": "{{bossName}} erscheint.", "bossAppeared": "{{bossName}} erscheint.",
@ -62,12 +62,13 @@ export const battle: SimpleTranslationEntries = {
"drainMessage": "{{pokemonName}} wurde Energie abgesaugt", "drainMessage": "{{pokemonName}} wurde Energie abgesaugt",
"regainHealth": "KP von {{pokemonName}} wurden wieder aufgefrischt!", "regainHealth": "KP von {{pokemonName}} wurden wieder aufgefrischt!",
"fainted": "{{pokemonNameWithAffix}} wurde besiegt!", "fainted": "{{pokemonNameWithAffix}} wurde besiegt!",
"statRose": "rose", "statRose": "steigt",
"statSharplyRose": "sharply rose", "statSharplyRose": "steigt stark",
"statRoseDrastically": "rose drastically", "statRoseDrastically": "steigt drastisch",
"statWontGoAnyHigher": "won't go any higher", "statWontGoAnyHigher": "kann nicht weiter erhöht werden",
"statFell": "fell", "statFell": "sinkt",
"statHarshlyFell": "harshly fell", "statHarshlyFell": "sinkt stark",
"statSeverelyFell": "severely fell", "statSeverelyFell": "sinkt drastisch",
"statWontGoAnyLower": "won't go any lower", "statWontGoAnyLower": "kann nicht weiter sinken",
"ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!",
} as const; } as const;

View File

@ -1,4 +1,4 @@
import { BerryTranslationEntries } from "#app/plugins/i18n"; import { BerryTranslationEntries } from "#app/interfaces/locales";
export const berry: BerryTranslationEntries = { export const berry: BerryTranslationEntries = {
"SITRUS": { "SITRUS": {

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const biome: SimpleTranslationEntries = { export const biome: SimpleTranslationEntries = {
"unknownLocation": "An einem unbekannten Ort", "unknownLocation": "An einem unbekannten Ort",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const challenges: SimpleTranslationEntries = { export const challenges: SimpleTranslationEntries = {
"title": "Herausforderungsmodifikatoren", "title": "Herausforderungsmodifikatoren",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const commandUiHandler: SimpleTranslationEntries = { export const commandUiHandler: SimpleTranslationEntries = {
"fight": "Kampf", "fight": "Kampf",

View File

@ -39,6 +39,7 @@ import { tutorial } from "./tutorial";
import { voucher } from "./voucher"; import { voucher } from "./voucher";
import { weather } from "./weather"; import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler"; import { partyUiHandler } from "./party-ui-handler";
import { settings } from "#app/locales/de/settings.js";
export const deConfig = { export const deConfig = {
ability: ability, ability: ability,
@ -74,6 +75,7 @@ export const deConfig = {
pokemonInfo: pokemonInfo, pokemonInfo: pokemonInfo,
pokemonInfoContainer: pokemonInfoContainer, pokemonInfoContainer: pokemonInfoContainer,
saveSlotSelectUiHandler: saveSlotSelectUiHandler, saveSlotSelectUiHandler: saveSlotSelectUiHandler,
settings: settings,
splashMessages: splashMessages, splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler, starterSelectUiHandler: starterSelectUiHandler,
titles: titles, titles: titles,

View File

@ -1,4 +1,4 @@
import {DialogueTranslationEntries, SimpleTranslationEntries} from "#app/plugins/i18n"; import {DialogueTranslationEntries, SimpleTranslationEntries} from "#app/interfaces/locales";
// Dialogue of the NPCs in the game when the player character is male (or unset) // Dialogue of the NPCs in the game when the player character is male (or unset)
@ -2351,31 +2351,30 @@ export const PGMdialogue: DialogueTranslationEntries = {
}, },
"alder": { "alder": {
"encounter": { "encounter": {
1: "Prepare yourself for a match against the strongest Trainer in Unova!" 1: "Mach dich bereit für einen Kampf gegen den stärksten Trainer in Einall! Mich - Lauro!"
}, },
"victory": { "victory": {
1: "Well done! You certainly are an unmatched talent." 1: "Gut gemacht! Du hast wirklich ein unvergleichliches Talent."
}, },
"defeat": { "defeat": {
1: `A fresh wind blows through my heart... 1: `Ein frischer Wind weht durch mein Herz...
$What an extraordinary effort!` $Was für ein außergewöhnliches Gefühl!`
} }
}, },
"kieran": { "kieran": {
"encounter": { "encounter": {
1: `Through hard work, I become stronger and stronger! 1: `Durch harte Arbeit werde ich immer stärker und stärker!
$I don't lose.` $Ich verliere nicht.`
}, },
"victory": { "victory": {
1: `I don't believe it... 1: `Ich kann es nicht glauben...
$What a fun and heart-pounding battle!` $Was für ein lustiger und herzzerreißender Kampf!`
}, },
"defeat": { "defeat": {
1: `Wowzers, what a battle! 1: `Wow, was für ein Kampf!
$Time for you to train even harder.` $Es ist Zeit für dich, noch härter zu trainieren.`
} }
}, },
"rival": { "rival": {
"encounter": { "encounter": {
1: `@c{smile}Hey, ich habe dich gesucht! Ich weiß, dass du es nicht erwarten konntest loszugehen, 1: `@c{smile}Hey, ich habe dich gesucht! Ich weiß, dass du es nicht erwarten konntest loszugehen,

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const egg: SimpleTranslationEntries = { export const egg: SimpleTranslationEntries = {
"egg": "Ei", "egg": "Ei",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const fightUiHandler: SimpleTranslationEntries = { export const fightUiHandler: SimpleTranslationEntries = {
"pp": "AP", "pp": "AP",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const gameMode: SimpleTranslationEntries = { export const gameMode: SimpleTranslationEntries = {
"classic": "Klassik", "classic": "Klassik",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const gameStatsUiHandler: SimpleTranslationEntries = { export const gameStatsUiHandler: SimpleTranslationEntries = {
"stats": "Statistiken", "stats": "Statistiken",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const growth: SimpleTranslationEntries = { export const growth: SimpleTranslationEntries = {
"Erratic": "Unregelmäßig", "Erratic": "Unregelmäßig",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const menuUiHandler: SimpleTranslationEntries = { export const menuUiHandler: SimpleTranslationEntries = {
"GAME_SETTINGS": "Spieleinstellungen", "GAME_SETTINGS": "Spieleinstellungen",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
/** /**
* The menu namespace holds most miscellaneous text that isn't directly part of the game's * The menu namespace holds most miscellaneous text that isn't directly part of the game's
@ -34,8 +34,6 @@ export const menu: SimpleTranslationEntries = {
"sessionSuccess": "Sitzung erfolgreich geladen.", "sessionSuccess": "Sitzung erfolgreich geladen.",
"failedToLoadSession": "Ihre Sitzungsdaten konnten nicht geladen werden.\nSie könnten beschädigt sein.", "failedToLoadSession": "Ihre Sitzungsdaten konnten nicht geladen werden.\nSie könnten beschädigt sein.",
"boyOrGirl": "Bist du ein Junge oder ein Mädchen?", "boyOrGirl": "Bist du ein Junge oder ein Mädchen?",
"boy": "Junge",
"girl": "Mädchen",
"evolving": "Nanu?\n{{pokemonName}} entwickelt sich!", "evolving": "Nanu?\n{{pokemonName}} entwickelt sich!",
"stoppedEvolving": "Hm? {{pokemonName}} hat die Entwicklung \nabgebrochen.", // "Hm? Entwicklung wurde abgebrochen!" without naming the pokemon seems to be the original. "stoppedEvolving": "Hm? {{pokemonName}} hat die Entwicklung \nabgebrochen.", // "Hm? Entwicklung wurde abgebrochen!" without naming the pokemon seems to be the original.
"pauseEvolutionsQuestion": "Die Entwicklung von {{pokemonName}} vorübergehend pausieren?\nEntwicklungen können im Gruppenmenü wieder aktiviert werden.", "pauseEvolutionsQuestion": "Die Entwicklung von {{pokemonName}} vorübergehend pausieren?\nEntwicklungen können im Gruppenmenü wieder aktiviert werden.",
@ -44,11 +42,15 @@ export const menu: SimpleTranslationEntries = {
"dailyRankings": "Tägliche Rangliste", "dailyRankings": "Tägliche Rangliste",
"weeklyRankings": "Wöchentliche Rangliste", "weeklyRankings": "Wöchentliche Rangliste",
"noRankings": "Keine Rangliste", "noRankings": "Keine Rangliste",
"positionIcon": "#",
"usernameScoreboard": "Benutzername",
"score": "Punkte",
"wave": "Welle",
"loading": "Lade…", "loading": "Lade…",
"loadingAsset": "Loading asset: {{assetName}}", "loadingAsset": "Loading asset: {{assetName}}",
"playersOnline": "Spieler Online", "playersOnline": "Spieler Online",
"yes":"Ja", "yes":"Ja",
"no":"Nein", "no":"Nein",
"disclaimer": "DISCLAIMER", "disclaimer": "DISCLAIMER",
"disclaimerDescription": "This game is an unfinished product; it might have playability issues (including the potential loss of save data),\n change without notice, and may or may not be updated further or completed." "disclaimerDescription": "Dieses Spiel ist ein unfertiges Produkt. Es kann spielbeinträchtigende Fehler (bis hin zum Verlust des Speicherstandes)\n aufweisen, sich ohne Vorankündigung ändern und es gibt keine Garantie dass es weiterentwickelt oder fertiggestellt wird.",
} as const; } as const;

View File

@ -1,4 +1,4 @@
import { ModifierTypeTranslationEntries } from "#app/plugins/i18n"; import { ModifierTypeTranslationEntries } from "#app/interfaces/locales";
export const modifierType: ModifierTypeTranslationEntries = { export const modifierType: ModifierTypeTranslationEntries = {
ModifierType: { ModifierType: {

View File

@ -1,4 +1,4 @@
import { MoveTranslationEntries } from "#app/plugins/i18n"; import { MoveTranslationEntries } from "#app/interfaces/locales";
export const move: MoveTranslationEntries = { export const move: MoveTranslationEntries = {
"pound": { "pound": {

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const nature: SimpleTranslationEntries = { export const nature: SimpleTranslationEntries = {
"Hardy": "Robust", "Hardy": "Robust",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const partyUiHandler: SimpleTranslationEntries = { export const partyUiHandler: SimpleTranslationEntries = {
"SEND_OUT": "Einwechseln", "SEND_OUT": "Einwechseln",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const pokeball: SimpleTranslationEntries = { export const pokeball: SimpleTranslationEntries = {
"pokeBall": "Pokéball", "pokeBall": "Pokéball",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const pokemonInfoContainer: SimpleTranslationEntries = { export const pokemonInfoContainer: SimpleTranslationEntries = {
"moveset": "Attacken", "moveset": "Attacken",

View File

@ -1,4 +1,4 @@
import { PokemonInfoTranslationEntries } from "#app/plugins/i18n"; import { PokemonInfoTranslationEntries } from "#app/interfaces/locales";
export const pokemonInfo: PokemonInfoTranslationEntries = { export const pokemonInfo: PokemonInfoTranslationEntries = {
Stat: { Stat: {
@ -14,8 +14,8 @@ export const pokemonInfo: PokemonInfoTranslationEntries = {
"SPDEFshortened": "SpVert", "SPDEFshortened": "SpVert",
"SPD": "Initiative", "SPD": "Initiative",
"SPDshortened": "Init", "SPDshortened": "Init",
"ACC": "Accuracy", "ACC": "Genauigkeit",
"EVA": "Evasiveness" "EVA": "Fluchtwert",
}, },
Type: { Type: {

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const pokemon: SimpleTranslationEntries = { export const pokemon: SimpleTranslationEntries = {
"bulbasaur": "Bisasam", "bulbasaur": "Bisasam",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const saveSlotSelectUiHandler: SimpleTranslationEntries = { export const saveSlotSelectUiHandler: SimpleTranslationEntries = {
"overwriteData": "Den ausgewählten Speicherstand überschreiben?", "overwriteData": "Den ausgewählten Speicherstand überschreiben?",

View File

@ -0,0 +1,98 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales.js";
export const settings: SimpleTranslationEntries = {
"boy": "Junge",
"girl": "Mädchen",
"general": "Allgemein",
"display": "Anzeige",
"audio": "Audio",
"gamepad": "Controller",
"keyboard": "Tastatur",
"gameSpeed": "Spielgeschwindigkeit",
"hpBarSpeed": "KP-Balken Geschwindigkeit",
"expGainsSpeed": "EXP-Balken Geschwindigkeit",
"expPartyDisplay": "Team-EXP anzeigen",
"skipSeenDialogues": "Gesehenen Dialog überspringen",
"battleStyle": "Kampfstil",
"enableRetries": "Erneut versuchen aktivieren",
"tutorials": "Tutorials",
"touchControls": "Touch Steuerung",
"vibrations": "Vibration",
"normal": "Normal",
"fast": "Schnell",
"faster": "Schneller",
"skip": "Überspringen",
"levelUpNotifications": "Auflevelbenachrichtigung",
"on": "An",
"off": "Aus",
"switch": "Wechsel",
"set": "Folge",
"auto": "Auto",
"disabled": "Deaktiviert",
"language": "Sprache",
"change": "Ändern",
"uiTheme": "UI Thema",
"default": "Standard",
"legacy": "Legacy",
"windowType": "Fenster Typ",
"moneyFormat": "Währungsformat",
"damageNumbers": "Schadensnummern",
"simple": "Simpel",
"fancy": "Schön",
"abbreviated": "Abgekürzt",
"moveAnimations": "Attacken Animationen",
"showStatsOnLevelUp": "Werte beim Aufleveln anzeigen",
"candyUpgradeNotification": "Bonbon Upgrade Benachrichtigung",
"passivesOnly": "Nur Passive",
"candyUpgradeDisplay": "Bonbon Upgrade Anzeige",
"icon": "Icon",
"animation": "Animation",
"moveInfo": "Attacken-Info",
"showMovesetFlyout": "Zeige Attacken Flyout",
"showArenaFlyout": "Zeige Arena Flyout",
"showTimeOfDayWidget": "Zeige Tageszeit Widget",
"timeOfDayAnimation": "Tageszeit Animation",
"bounce": "Springen",
"timeOfDay_back": "Zurück",
"spriteSet": "Sprite Satz",
"consistent": "Konistent",
"mixedAnimated": "Gemischt animiert",
"fusionPaletteSwaps": "Fusion-Farbpalettenwechsel",
"playerGender": "Spieler Geschlecht",
"typeHints": "Typhinweise",
"masterVolume": "Gesamtlautstärke",
"bgmVolume": "Hintergrundmusik",
"seVolume": "Spezialeffekte",
"musicPreference": "Musik Präferenz",
"mixed": "Gemisch",
"gamepadPleasePlug": "Bitte einen Controller anschließen oder eine Taste drücken",
"delete": "Löschen",
"keyboardPleasePress": "Bitte eine Taste auf der Tastatur drücken",
"reset": "Zurücksetzen",
"requireReload": "Neuladen benötigt",
"action": "Aktion",
"back": "Zurück",
"pressToBind": "Zum Zuweisen drücken",
"pressButton": "Eine Taste drücken...",
"buttonUp": "Hoch",
"buttonDown": "Runter",
"buttonLeft": "Links",
"buttonRight": "Rechts",
"buttonAction": "Aktion",
"buttonMenu": "Menü",
"buttonSubmit": "Bestätigen",
"buttonCancel": "Abbrechen",
"buttonStats": "Statistiken",
"buttonCycleForm": "Form wechseln",
"buttonCycleShiny": "Schillernd wechseln",
"buttonCycleGender": "Geschlecht wechseln",
"buttonCycleAbility": "Fähigkeit wechseln",
"buttonCycleNature": "Wesen wechseln",
"buttonCycleVariant": "Variante wechseln",
"buttonSpeedUp": "Beschleunigen",
"buttonSlowDown": "Verlangsamen",
"alt": " (Alt)",
"mute": "Mute",
"controller": "Controller",
"gamepadSupport": "Gamepad Support"
} as const;

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const splashMessages: SimpleTranslationEntries = { export const splashMessages: SimpleTranslationEntries = {
"battlesWon": "Kämpfe gewonnen!", "battlesWon": "Kämpfe gewonnen!",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
/** /**
* The menu namespace holds most miscellaneous text that isn't directly part of the game's * The menu namespace holds most miscellaneous text that isn't directly part of the game's
@ -25,7 +25,9 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"addToParty": "Zum Team hinzufügen", "addToParty": "Zum Team hinzufügen",
"toggleIVs": "DVs anzeigen/verbergen", "toggleIVs": "DVs anzeigen/verbergen",
"manageMoves": "Attacken ändern", "manageMoves": "Attacken ändern",
"manageNature": "Wesen ändern",
"useCandies": "Bonbons verwenden", "useCandies": "Bonbons verwenden",
"selectNature": "Wähle das neue Wesen.",
"selectMoveSwapOut": "Wähle die zu ersetzende Attacke.", "selectMoveSwapOut": "Wähle die zu ersetzende Attacke.",
"selectMoveSwapWith": "Wähle die gewünschte Attacke.", "selectMoveSwapWith": "Wähle die gewünschte Attacke.",
"unlockPassive": "Passiv-Skill freischalten", "unlockPassive": "Passiv-Skill freischalten",

View File

@ -1,4 +1,4 @@
import {SimpleTranslationEntries} from "#app/plugins/i18n"; import {SimpleTranslationEntries} from "#app/interfaces/locales";
// Titles of special trainers like gym leaders, elite four, and the champion // Titles of special trainers like gym leaders, elite four, and the champion
export const titles: SimpleTranslationEntries = { export const titles: SimpleTranslationEntries = {

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const tutorial: SimpleTranslationEntries = { export const tutorial: SimpleTranslationEntries = {
"intro": `Willkommen bei PokéRogue! Dies ist ein kampforientiertes Pokémon-Fangame mit Roguelite-Elementen. "intro": `Willkommen bei PokéRogue! Dies ist ein kampforientiertes Pokémon-Fangame mit Roguelite-Elementen.

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const voucher: SimpleTranslationEntries = { export const voucher: SimpleTranslationEntries = {
"vouchers": "Gutscheine", "vouchers": "Gutscheine",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
/** /**
* The weather namespace holds text displayed when weather is active during a battle * The weather namespace holds text displayed when weather is active during a battle

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
"blockRecoilDamage" : "{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!", "blockRecoilDamage" : "{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!",

View File

@ -1,4 +1,4 @@
import { AbilityTranslationEntries } from "#app/plugins/i18n.js"; import { AbilityTranslationEntries } from "#app/interfaces/locales.js";
export const ability: AbilityTranslationEntries = { export const ability: AbilityTranslationEntries = {
stench: { stench: {

View File

@ -1,4 +1,4 @@
import { AchievementTranslationEntries } from "#app/plugins/i18n.js"; import { AchievementTranslationEntries } from "#app/interfaces/locales.js";
// Achievement translations for the when the player character is male // Achievement translations for the when the player character is male
export const PGMachv: AchievementTranslationEntries = { export const PGMachv: AchievementTranslationEntries = {

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const battleMessageUiHandler: SimpleTranslationEntries = { export const battleMessageUiHandler: SimpleTranslationEntries = {
"ivBest": "Best", "ivBest": "Best",
@ -7,4 +7,4 @@ export const battleMessageUiHandler: SimpleTranslationEntries = {
"ivPrettyGood": "Pretty Good", "ivPrettyGood": "Pretty Good",
"ivDecent": "Decent", "ivDecent": "Decent",
"ivNoGood": "No Good", "ivNoGood": "No Good",
} as const; } as const;

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const battle: SimpleTranslationEntries = { export const battle: SimpleTranslationEntries = {
"bossAppeared": "{{bossName}} appeared.", "bossAppeared": "{{bossName}} appeared.",
@ -70,4 +70,5 @@ export const battle: SimpleTranslationEntries = {
"statHarshlyFell": "harshly fell", "statHarshlyFell": "harshly fell",
"statSeverelyFell": "severely fell", "statSeverelyFell": "severely fell",
"statWontGoAnyLower": "won't go any lower", "statWontGoAnyLower": "won't go any lower",
"ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!",
} as const; } as const;

View File

@ -1,4 +1,4 @@
import { BerryTranslationEntries } from "#app/plugins/i18n"; import { BerryTranslationEntries } from "#app/interfaces/locales";
export const berry: BerryTranslationEntries = { export const berry: BerryTranslationEntries = {
"SITRUS": { "SITRUS": {

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const biome: SimpleTranslationEntries = { export const biome: SimpleTranslationEntries = {
"unknownLocation": "Somewhere you can\'t remember", "unknownLocation": "Somewhere you can\'t remember",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const challenges: SimpleTranslationEntries = { export const challenges: SimpleTranslationEntries = {
"title": "Challenge Modifiers", "title": "Challenge Modifiers",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const commandUiHandler: SimpleTranslationEntries = { export const commandUiHandler: SimpleTranslationEntries = {
"fight": "Fight", "fight": "Fight",

View File

@ -1,3 +1,4 @@
import { settings } from "#app/locales/en/settings.js";
import { ability } from "./ability"; import { ability } from "./ability";
import { abilityTriggers } from "./ability-trigger"; import { abilityTriggers } from "./ability-trigger";
import { PGFachv, PGMachv } from "./achv"; import { PGFachv, PGMachv } from "./achv";
@ -75,6 +76,7 @@ export const enConfig = {
pokemonInfo: pokemonInfo, pokemonInfo: pokemonInfo,
pokemonInfoContainer: pokemonInfoContainer, pokemonInfoContainer: pokemonInfoContainer,
saveSlotSelectUiHandler: saveSlotSelectUiHandler, saveSlotSelectUiHandler: saveSlotSelectUiHandler,
settings: settings,
splashMessages: splashMessages, splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler, starterSelectUiHandler: starterSelectUiHandler,
titles: titles, titles: titles,

View File

@ -1,4 +1,4 @@
import { DialogueTranslationEntries, SimpleTranslationEntries } from "#app/plugins/i18n"; import { DialogueTranslationEntries, SimpleTranslationEntries } from "#app/interfaces/locales";
// Dialogue of the NPCs in the game when the player character is male (or unset) // Dialogue of the NPCs in the game when the player character is male (or unset)
export const PGMdialogue: DialogueTranslationEntries = { export const PGMdialogue: DialogueTranslationEntries = {

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const egg: SimpleTranslationEntries = { export const egg: SimpleTranslationEntries = {
"egg": "Egg", "egg": "Egg",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const fightUiHandler: SimpleTranslationEntries = { export const fightUiHandler: SimpleTranslationEntries = {
"pp": "PP", "pp": "PP",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const gameMode: SimpleTranslationEntries = { export const gameMode: SimpleTranslationEntries = {
"classic": "Classic", "classic": "Classic",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const gameStatsUiHandler: SimpleTranslationEntries = { export const gameStatsUiHandler: SimpleTranslationEntries = {
"stats": "Stats", "stats": "Stats",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const growth: SimpleTranslationEntries = { export const growth: SimpleTranslationEntries = {
"Erratic": "Erratic", "Erratic": "Erratic",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const menuUiHandler: SimpleTranslationEntries = { export const menuUiHandler: SimpleTranslationEntries = {
"GAME_SETTINGS": "Game Settings", "GAME_SETTINGS": "Game Settings",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
/** /**
* The menu namespace holds most miscellaneous text that isn't directly part of the game's * The menu namespace holds most miscellaneous text that isn't directly part of the game's
@ -34,8 +34,6 @@ export const menu: SimpleTranslationEntries = {
"sessionSuccess": "Session loaded successfully.", "sessionSuccess": "Session loaded successfully.",
"failedToLoadSession": "Your session data could not be loaded.\nIt may be corrupted.", "failedToLoadSession": "Your session data could not be loaded.\nIt may be corrupted.",
"boyOrGirl": "Are you a boy or a girl?", "boyOrGirl": "Are you a boy or a girl?",
"boy": "Boy",
"girl": "Girl",
"evolving": "What?\n{{pokemonName}} is evolving!", "evolving": "What?\n{{pokemonName}} is evolving!",
"stoppedEvolving": "{{pokemonName}} stopped evolving.", "stoppedEvolving": "{{pokemonName}} stopped evolving.",
"pauseEvolutionsQuestion": "Would you like to pause evolutions for {{pokemonName}}?\nEvolutions can be re-enabled from the party screen.", "pauseEvolutionsQuestion": "Would you like to pause evolutions for {{pokemonName}}?\nEvolutions can be re-enabled from the party screen.",
@ -44,11 +42,15 @@ export const menu: SimpleTranslationEntries = {
"dailyRankings": "Daily Rankings", "dailyRankings": "Daily Rankings",
"weeklyRankings": "Weekly Rankings", "weeklyRankings": "Weekly Rankings",
"noRankings": "No Rankings", "noRankings": "No Rankings",
"positionIcon": "#",
"usernameScoreboard": "Username",
"score": "Score",
"wave": "Wave",
"loading": "Loading…", "loading": "Loading…",
"loadingAsset": "Loading asset: {{assetName}}", "loadingAsset": "Loading asset: {{assetName}}",
"playersOnline": "Players Online", "playersOnline": "Players Online",
"yes":"Yes", "yes":"Yes",
"no":"No", "no":"No",
"disclaimer": "DISCLAIMER", "disclaimer": "DISCLAIMER",
"disclaimerDescription": "This game is an unfinished product; it might have playability issues (including the potential loss of save data),\n change without notice, and may or may not be updated further or completed." "disclaimerDescription": "This game is an unfinished product; it might have playability issues (including the potential loss of save data),\n change without notice, and may or may not be updated further or completed.",
} as const; } as const;

View File

@ -1,4 +1,4 @@
import { ModifierTypeTranslationEntries } from "#app/plugins/i18n"; import { ModifierTypeTranslationEntries } from "#app/interfaces/locales";
export const modifierType: ModifierTypeTranslationEntries = { export const modifierType: ModifierTypeTranslationEntries = {
ModifierType: { ModifierType: {

View File

@ -1,4 +1,4 @@
import { MoveTranslationEntries } from "#app/plugins/i18n"; import { MoveTranslationEntries } from "#app/interfaces/locales";
export const move: MoveTranslationEntries = { export const move: MoveTranslationEntries = {
"pound": { "pound": {

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const nature: SimpleTranslationEntries = { export const nature: SimpleTranslationEntries = {
"Hardy": "Hardy", "Hardy": "Hardy",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const partyUiHandler: SimpleTranslationEntries = { export const partyUiHandler: SimpleTranslationEntries = {
"ALL": "All", "ALL": "All",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const pokeball: SimpleTranslationEntries = { export const pokeball: SimpleTranslationEntries = {
"pokeBall": "Poké Ball", "pokeBall": "Poké Ball",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const pokemonInfoContainer: SimpleTranslationEntries = { export const pokemonInfoContainer: SimpleTranslationEntries = {
"moveset": "Moveset", "moveset": "Moveset",

View File

@ -1,4 +1,4 @@
import { PokemonInfoTranslationEntries } from "#app/plugins/i18n"; import { PokemonInfoTranslationEntries } from "#app/interfaces/locales";
export const pokemonInfo: PokemonInfoTranslationEntries = { export const pokemonInfo: PokemonInfoTranslationEntries = {
Stat: { Stat: {

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const pokemon: SimpleTranslationEntries = { export const pokemon: SimpleTranslationEntries = {
"bulbasaur": "Bulbasaur", "bulbasaur": "Bulbasaur",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const saveSlotSelectUiHandler: SimpleTranslationEntries = { export const saveSlotSelectUiHandler: SimpleTranslationEntries = {
"overwriteData": "Overwrite the data in the selected slot?", "overwriteData": "Overwrite the data in the selected slot?",

View File

@ -0,0 +1,98 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales.js";
export const settings: SimpleTranslationEntries = {
"boy": "Boy",
"girl": "Girl",
"general": "General",
"display": "Display",
"audio": "Audio",
"gamepad": "Gamepad",
"keyboard": "Keyboard",
"gameSpeed": "Game Speed",
"hpBarSpeed": "HP Bar Speed",
"expGainsSpeed": "EXP Gains Speed",
"expPartyDisplay": "Show EXP Party",
"skipSeenDialogues": "Skip Seen Dialogues",
"battleStyle": "Battle Style",
"enableRetries": "Enable Retries",
"tutorials": "Tutorials",
"touchControls": "Touch Controls",
"vibrations": "Vibrations",
"normal": "Normal",
"fast": "Fast",
"faster": "Faster",
"skip": "Skip",
"levelUpNotifications": "Level Up Notifications",
"on": "On",
"off": "Off",
"switch": "Switch",
"set": "Set",
"auto": "Auto",
"disabled": "Disabled",
"language": "Language",
"change": "Change",
"uiTheme": "UI Theme",
"default": "Default",
"legacy": "Legacy",
"windowType": "Window Type",
"moneyFormat": "Money Format",
"damageNumbers": "Damage Numbers",
"simple": "Simple",
"fancy": "Fancy",
"abbreviated": "Abbreviated",
"moveAnimations": "Move Animations",
"showStatsOnLevelUp": "Show Stats on Level Up",
"candyUpgradeNotification": "Candy Upgrade Notification",
"passivesOnly": "Passives Only",
"candyUpgradeDisplay": "Candy Upgrade Display",
"icon": "Icon",
"animation": "Animation",
"moveInfo": "Move Info",
"showMovesetFlyout": "Show Moveset Flyout",
"showArenaFlyout": "Show Arena Flyout",
"showTimeOfDayWidget": "Show Time of Day Widget",
"timeOfDayAnimation": "Time of Day Animation",
"bounce": "Bounce",
"timeOfDay_back": "Back",
"spriteSet": "Sprite Set",
"consistent": "Consistent",
"mixedAnimated": "Mixed Animated",
"fusionPaletteSwaps": "Fusion Palette Swaps",
"playerGender": "Player Gender",
"typeHints": "Type Hints",
"masterVolume": "Master Volume",
"bgmVolume": "BGM Volume",
"seVolume": "SE Volume",
"musicPreference": "Music Preference",
"mixed": "Mixed",
"gamepadPleasePlug": "Please Plug in a Gamepad or Press a Button",
"delete": "Delete",
"keyboardPleasePress": "Please Press a Key on Your Keyboard",
"reset": "Reset",
"requireReload": "Reload Required",
"action": "Action",
"back": "Back",
"pressToBind": "Press to Bind",
"pressButton": "Press a Button...",
"buttonUp": "Up",
"buttonDown": "Down",
"buttonLeft": "Left",
"buttonRight": "Right",
"buttonAction": "Action",
"buttonMenu": "Menu",
"buttonSubmit": "Submit",
"buttonCancel": "Cancel",
"buttonStats": "Stats",
"buttonCycleForm": "Cycle Form",
"buttonCycleShiny": "Cycle Shiny",
"buttonCycleGender": "Cycle Gender",
"buttonCycleAbility": "Cycle Ability",
"buttonCycleNature": "Cycle Nature",
"buttonCycleVariant": "Cycle Variant",
"buttonSpeedUp": "Speed Up",
"buttonSlowDown": "Slow Down",
"alt": " (Alt)",
"mute": "Mute",
"controller": "Controller",
"gamepadSupport": "Gamepad Support"
} as const;

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const splashMessages: SimpleTranslationEntries = { export const splashMessages: SimpleTranslationEntries = {
"battlesWon": "Battles Won!", "battlesWon": "Battles Won!",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
/** /**
* The menu namespace holds most miscellaneous text that isn't directly part of the game's * The menu namespace holds most miscellaneous text that isn't directly part of the game's
@ -25,7 +25,9 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"addToParty": "Add to Party", "addToParty": "Add to Party",
"toggleIVs": "Toggle IVs", "toggleIVs": "Toggle IVs",
"manageMoves": "Manage Moves", "manageMoves": "Manage Moves",
"manageNature": "Manage Nature",
"useCandies": "Use Candies", "useCandies": "Use Candies",
"selectNature": "Select nature.",
"selectMoveSwapOut": "Select a move to swap out.", "selectMoveSwapOut": "Select a move to swap out.",
"selectMoveSwapWith": "Select a move to swap with", "selectMoveSwapWith": "Select a move to swap with",
"unlockPassive": "Unlock Passive", "unlockPassive": "Unlock Passive",

View File

@ -1,4 +1,4 @@
import {SimpleTranslationEntries} from "#app/plugins/i18n"; import {SimpleTranslationEntries} from "#app/interfaces/locales";
// Titles of special trainers like gym leaders, elite four, and the champion // Titles of special trainers like gym leaders, elite four, and the champion
export const titles: SimpleTranslationEntries = { export const titles: SimpleTranslationEntries = {

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const tutorial: SimpleTranslationEntries = { export const tutorial: SimpleTranslationEntries = {
"intro": `Welcome to PokéRogue! This is a battle-focused Pokémon fangame with roguelite elements. "intro": `Welcome to PokéRogue! This is a battle-focused Pokémon fangame with roguelite elements.

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const voucher: SimpleTranslationEntries = { export const voucher: SimpleTranslationEntries = {
"vouchers": "Vouchers", "vouchers": "Vouchers",
@ -8,4 +8,4 @@ export const voucher: SimpleTranslationEntries = {
"eggVoucherGold": "Egg Voucher Gold", "eggVoucherGold": "Egg Voucher Gold",
"locked": "Locked", "locked": "Locked",
"defeatTrainer": "Defeat {{trainerName}}" "defeatTrainer": "Defeat {{trainerName}}"
} as const; } as const;

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
/** /**
* The weather namespace holds text displayed when weather is active during a battle * The weather namespace holds text displayed when weather is active during a battle

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
"blockRecoilDamage" : "¡{{abilityName}} de {{pokemonName}}\nlo protegió del daño de retroceso!", "blockRecoilDamage" : "¡{{abilityName}} de {{pokemonName}}\nlo protegió del daño de retroceso!",

View File

@ -1,4 +1,4 @@
import { AbilityTranslationEntries } from "#app/plugins/i18n.js"; import { AbilityTranslationEntries } from "#app/interfaces/locales.js";
export const ability: AbilityTranslationEntries = { export const ability: AbilityTranslationEntries = {
"stench": { "stench": {

View File

@ -1,4 +1,4 @@
import { AchievementTranslationEntries } from "#app/plugins/i18n.js"; import { AchievementTranslationEntries } from "#app/interfaces/locales.js";
// Achievement translations for the when the player character is male // Achievement translations for the when the player character is male
export const PGMachv: AchievementTranslationEntries = { export const PGMachv: AchievementTranslationEntries = {

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const battleMessageUiHandler: SimpleTranslationEntries = { export const battleMessageUiHandler: SimpleTranslationEntries = {
"ivBest": "Inmejorable", "ivBest": "Inmejorable",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const battle: SimpleTranslationEntries = { export const battle: SimpleTranslationEntries = {
"bossAppeared": "¡{{bossName}} te corta el paso!", "bossAppeared": "¡{{bossName}} te corta el paso!",
@ -70,4 +70,5 @@ export const battle: SimpleTranslationEntries = {
"statHarshlyFell": "harshly fell", "statHarshlyFell": "harshly fell",
"statSeverelyFell": "severely fell", "statSeverelyFell": "severely fell",
"statWontGoAnyLower": "won't go any lower", "statWontGoAnyLower": "won't go any lower",
"ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!",
} as const; } as const;

View File

@ -1,4 +1,4 @@
import { BerryTranslationEntries } from "#app/plugins/i18n"; import { BerryTranslationEntries } from "#app/interfaces/locales";
export const berry: BerryTranslationEntries = { export const berry: BerryTranslationEntries = {
"SITRUS": { "SITRUS": {

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const biome: SimpleTranslationEntries = { export const biome: SimpleTranslationEntries = {
"unknownLocation": "En algún lugar que no puedes recordar", "unknownLocation": "En algún lugar que no puedes recordar",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const challenges: SimpleTranslationEntries = { export const challenges: SimpleTranslationEntries = {
"title": "Parámetros de Desafíos", "title": "Parámetros de Desafíos",

View File

@ -1,4 +1,4 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const commandUiHandler: SimpleTranslationEntries = { export const commandUiHandler: SimpleTranslationEntries = {
"fight": "Luchar", "fight": "Luchar",

View File

@ -39,6 +39,7 @@ import { tutorial } from "./tutorial";
import { voucher } from "./voucher"; import { voucher } from "./voucher";
import { weather } from "./weather"; import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler"; import { partyUiHandler } from "./party-ui-handler";
import { settings } from "#app/locales/es/settings.js";
export const esConfig = { export const esConfig = {
ability: ability, ability: ability,
@ -74,6 +75,7 @@ export const esConfig = {
pokemonInfo: pokemonInfo, pokemonInfo: pokemonInfo,
pokemonInfoContainer: pokemonInfoContainer, pokemonInfoContainer: pokemonInfoContainer,
saveSlotSelectUiHandler: saveSlotSelectUiHandler, saveSlotSelectUiHandler: saveSlotSelectUiHandler,
settings: settings,
splashMessages: splashMessages, splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler, starterSelectUiHandler: starterSelectUiHandler,
titles: titles, titles: titles,

View File

@ -1,4 +1,4 @@
import {DialogueTranslationEntries, SimpleTranslationEntries} from "#app/plugins/i18n"; import {DialogueTranslationEntries, SimpleTranslationEntries} from "#app/interfaces/locales";
// Dialogue of the NPCs in the game when the player character is male (or unset) // Dialogue of the NPCs in the game when the player character is male (or unset)
export const PGMdialogue: DialogueTranslationEntries = { export const PGMdialogue: DialogueTranslationEntries = {
@ -2109,28 +2109,28 @@ export const PGMdialogue: DialogueTranslationEntries = {
}, },
"alder": { "alder": {
"encounter": { "encounter": {
1: "Prepare yourself for a match against the strongest Trainer in Unova!" 1: "Prepárate para una batalla contra el entrenador más fuerte en Unova!"
}, },
"victory": { "victory": {
1: "Well done! You certainly are an unmatched talent." 1: "Bien hecho! Tienes ciertamente un talento inigualable"
}, },
"defeat": { "defeat": {
1: `A fresh wind blows through my heart... 1: `Un viento fresco sopla a través en mi corazón
$What an extraordinary effort!` $Qué esfuerzo extraordinario!`
} }
}, },
"kieran": { "kieran": {
"encounter": { "encounter": {
1: `Through hard work, I become stronger and stronger! 1: `A través del trabajo duro, me he vuelto más y más fuerte!
$I don't lose.` $No pierdo.`
}, },
"victory": { "victory": {
1: `I don't believe it... 1: `No puedo creerlo...
$What a fun and heart-pounding battle!` $¡Qué batalla tan divertida y trepidante!`
}, },
"defeat": { "defeat": {
1: `Wowzers, what a battle! 1: `Asombroso, que batalla!
$Time for you to train even harder.` $Es hora de que entrenes aún más duro.`
} }
}, },
"rival": { "rival": {

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