Merge branch 'beta' into trick

This commit is contained in:
Eucalyptus 2024-08-23 01:34:12 -04:00
commit a94b41e179
434 changed files with 43264 additions and 12729 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
github: patapancakes

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 KiB

After

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 800 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 743 B

After

Width:  |  Height:  |  Size: 793 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2513,7 +2513,6 @@
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:edb2df3a947401efb05329a2c96d5d73:f256d83ef4df17c17958acc6e0432ab0:bad05b37c157676604256a043511a6a2$"
"version": "3.0"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 976 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -3815,6 +3815,11 @@
1,
1
],
"178": [
0,
2,
2
],
"185": [
0,
1,
@ -7833,6 +7838,11 @@
1,
1
],
"178": [
0,
2,
2
],
"185": [
0,
1,

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -1,21 +1,5 @@
{
"1": {
"b0a080": "e552ec",
"f8f8e8": "ffe2ed",
"9b8259": "b021c5",
"e5e4c2": "ffb9f9",
"000000": "000000",
"bc9b4e": "900090",
"f8f8d0": "ff8ae9",
"e8e088": "ff49e7",
"d0b868": "d10cc7",
"7d673b": "510059",
"282828": "282828",
"f84040": "f84040",
"f88888": "1ae2e6",
"c81010": "00c2d2"
},
"2": {
"b0a080": "d96b23",
"f8f8e8": "ffe1b8",
"9b8259": "b43c06",
@ -30,5 +14,21 @@
"f84040": "f84040",
"f88888": "f88888",
"c81010": "c81010"
},
"2": {
"b0a080": "e552ec",
"f8f8e8": "ffe2ed",
"9b8259": "b021c5",
"e5e4c2": "ffb9f9",
"000000": "000000",
"bc9b4e": "900090",
"f8f8d0": "ff8ae9",
"e8e088": "ff49e7",
"d0b868": "d10cc7",
"7d673b": "510059",
"282828": "282828",
"f84040": "f84040",
"f88888": "1ae2e6",
"c81010": "00c2d2"
}
}

View File

@ -2,79 +2,35 @@
"1": {
"5a4d37": "1c1e76",
"766348": "323aa5",
"9d8361": "4059bd",
"c5b4aa": "d3e6e6",
"37332b": "104139",
"9e8360": "4059bd",
"f18725": "2e8c19",
"f18625": "2e8c19",
"bb6f2a": "2f7410",
"0f0f0f": "0f0f0f",
"575243": "18734a",
"b8702d": "2f7410",
"777462": "199e46",
"585243": "18734a",
"4f4531": "b29c3e",
"4d4530": "b29c3e",
"aea56b": "f9fba2",
"afa667": "f9fba2",
"a28e85": "c1d8db",
"a28c8c": "c1d8db",
"b64c95": "dedb64",
"afa668": "f9fba2",
"a28c88": "c1d8db",
"f2f2f2": "e8eab5",
"b05f8f": "dedb64",
"776348": "323aa5",
"b45492": "dedb64",
"f28625": "2e8c19",
"bc6e28": "2f7410",
"bb6e27": "2f7410",
"4d4430": "b29c3e",
"b0a766": "f9fba2",
"a18f8d": "c1d8db",
"a28f86": "c1d8db",
"b74a94": "dedb64",
"9e8461": "4059bd",
"777362": "199e46",
"ba6d27": "2f7410",
"afa567": "f9fba2",
"a18f85": "c1d8db"
"4e4530": "b29c3e",
"ba6e29": "2f7410"
},
"2": {
"5a4d37": "333e5f",
"766348": "8c9fbf",
"9d8361": "dbedec",
"c5b4aa": "39cfbc",
"37332b": "261031",
"9e8360": "dbedec",
"f18725": "4baecd",
"f18625": "4baecd",
"bb6f2a": "4792bd",
"0f0f0f": "0f0f0f",
"575243": "5e2d72",
"b8702d": "4792bd",
"777462": "8358a1",
"585243": "5e2d72",
"4f4531": "534b8c",
"4d4530": "534b8c",
"aea56b": "c9dbac",
"afa667": "c9dbac",
"a28e85": "52b0b0",
"a28c8c": "52b0b0",
"b64c95": "b56c3e",
"afa668": "c9dbac",
"a28e88": "52b0b0",
"f2f2f2": "d9c951",
"b05f8f": "b56c3e",
"776348": "8c9fbf",
"b45492": "b56c3e",
"f28625": "4baecd",
"bc6e28": "4792bd",
"bb6e27": "4792bd",
"4d4430": "534b8c",
"b0a766": "c9dbac",
"a18f8d": "52b0b0",
"a28f86": "52b0b0",
"b74a94": "b56c3e",
"9e8461": "dbedec",
"777362": "8358a1",
"ba6d27": "4792bd",
"afa567": "c9dbac",
"a18f85": "52b0b0"
"4e4530": "534b8c",
"ba6e29": "4792bd"
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -1,11 +1,10 @@
import Phaser from "phaser";
import UI from "./ui/ui";
import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase, SummonPhase, ToggleDoublePositionPhase } from "./phases";
import Pokemon, { PlayerPokemon, EnemyPokemon } from "./field/pokemon";
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies } from "./data/pokemon-species";
import { Constructor } from "#app/utils";
import * as Utils from "./utils";
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier, overrideModifiers, overrideHeldItems } from "./modifier/modifier";
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, TurnHeldItemTransferModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier, overrideModifiers, overrideHeldItems } from "./modifier/modifier";
import { PokeballType } from "./data/pokeball";
import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets, populateAnims } from "./data/battle-anims";
import { Phase } from "./phase";
@ -37,8 +36,8 @@ import UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin";
import { addUiThemeOverrides } from "./ui/ui-theme";
import PokemonData from "./system/pokemon-data";
import { Nature } from "./data/nature";
import { SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger, pokemonFormChanges, FormChangeItem } from "./data/pokemon-forms";
import { FormChangePhase, QuietFormChangePhase } from "./form-change-phase";
import { SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger, pokemonFormChanges, FormChangeItem, SpeciesFormChange } from "./data/pokemon-forms";
import { FormChangePhase } from "./phases/form-change-phase";
import { getTypeRgb } from "./data/type";
import PokemonSpriteSparkleHandler from "./field/pokemon-sprite-sparkle-handler";
import CharSprite from "./ui/char-sprite";
@ -69,6 +68,22 @@ import i18next from "i18next";
import {TrainerType} from "#enums/trainer-type";
import { battleSpecDialogue } from "./data/dialogue";
import { LoadingScene } from "./loading-scene";
import { LevelCapPhase } from "./phases/level-cap-phase";
import { LoginPhase } from "./phases/login-phase";
import { MessagePhase } from "./phases/message-phase";
import { MovePhase } from "./phases/move-phase";
import { NewBiomeEncounterPhase } from "./phases/new-biome-encounter-phase";
import { NextEncounterPhase } from "./phases/next-encounter-phase";
import { QuietFormChangePhase } from "./phases/quiet-form-change-phase";
import { ReturnPhase } from "./phases/return-phase";
import { SelectBiomePhase } from "./phases/select-biome-phase";
import { ShowTrainerPhase } from "./phases/show-trainer-phase";
import { SummonPhase } from "./phases/summon-phase";
import { SwitchPhase } from "./phases/switch-phase";
import { TitlePhase } from "./phases/title-phase";
import { ToggleDoublePositionPhase } from "./phases/toggle-double-position-phase";
import { TurnInitPhase } from "./phases/turn-init-phase";
import { ShopCursorTarget } from "./enums/shop-cursor-target";
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
@ -113,6 +128,7 @@ export default class BattleScene extends SceneBase {
public gameSpeed: integer = 1;
public damageNumbersMode: integer = 0;
public reroll: boolean = false;
public shopCursorTarget: number = ShopCursorTarget.CHECK_TEAM;
public showMovesetFlyout: boolean = true;
public showArenaFlyout: boolean = true;
public showTimeOfDayWidget: boolean = true;
@ -1086,7 +1102,7 @@ export default class BattleScene extends SceneBase {
} else if (trainerConfigs[trainerType].hasDouble) {
const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8);
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance));
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance));
doubleTrainer = !Utils.randSeedInt(doubleChance.value);
// Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance
if (trainerConfigs[trainerType].trainerTypeDouble && ![ TrainerType.TATE, TrainerType.LIZA ].includes(trainerType)) {
@ -1102,7 +1118,7 @@ export default class BattleScene extends SceneBase {
if (newBattleType === BattleType.WILD && !this.gameMode.isWaveFinal(newWaveIndex)) {
const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8);
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance));
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance));
newDouble = !Utils.randSeedInt(doubleChance.value);
} else if (newBattleType === BattleType.TRAINER) {
newDouble = newTrainer?.variant === TrainerVariant.DOUBLE;
@ -1504,7 +1520,7 @@ export default class BattleScene extends SceneBase {
return;
}
const formattedMoney = Utils.formatMoney(this.moneyFormat, this.money);
this.moneyText.setText(`${formattedMoney}`);
this.moneyText.setText(i18next.t("battleScene:moneyOwned", { formattedMoney }));
this.fieldUI.moveAbove(this.moneyText, this.luckText);
if (forceVisible) {
this.moneyText.setVisible(true);
@ -2122,7 +2138,7 @@ export default class BattleScene extends SceneBase {
pushMovePhase(movePhase: MovePhase, priorityOverride?: integer): void {
const movePriority = new Utils.IntegerHolder(priorityOverride !== undefined ? priorityOverride : movePhase.move.getMove().priority);
applyAbAttrs(ChangeMovePriorityAbAttr, movePhase.pokemon, null, movePhase.move.getMove(), movePriority);
applyAbAttrs(ChangeMovePriorityAbAttr, movePhase.pokemon, null, false, movePhase.move.getMove(), movePriority);
const lowerPriorityPhase = this.phaseQueue.find(p => p instanceof MovePhase && p.move.getMove().priority < movePriority.value);
if (lowerPriorityPhase) {
this.phaseQueue.splice(this.phaseQueue.indexOf(lowerPriorityPhase), 0, movePhase);
@ -2421,7 +2437,6 @@ export default class BattleScene extends SceneBase {
getEnemyModifierTypesForWave(difficultyWaveIndex, count, [ enemyPokemon ], this.currentBattle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD, upgradeChance)
.map(mt => mt.newModifier(enemyPokemon).add(this.enemyModifiers, false, this));
});
this.updateModifiers(false).then(() => resolve());
});
}
@ -2579,7 +2594,7 @@ export default class BattleScene extends SceneBase {
// in case this is NECROZMA, determine which forms this
const matchingFormChangeOpts = pokemonFormChanges[pokemon.species.speciesId].filter(fc => fc.findTrigger(formChangeTriggerType) && fc.canChange(pokemon));
let matchingFormChange;
let matchingFormChange: SpeciesFormChange | null;
if (pokemon.species.speciesId === Species.NECROZMA && matchingFormChangeOpts.length > 1) {
// Ultra Necrozma is changing its form back, so we need to figure out into which form it devolves.
const formChangeItemModifiers = (this.findModifiers(m => m instanceof PokemonFormChangeItemModifier && m.pokemonId === pokemon.id) as PokemonFormChangeItemModifier[]).filter(m => m.active).map(m => m.formChangeItem);
@ -2666,7 +2681,9 @@ export default class BattleScene extends SceneBase {
if (pokemon instanceof EnemyPokemon && pokemon.isBoss() && !pokemon.formIndex && pokemon.bossSegmentIndex < 1) {
this.fadeOutBgm(Utils.fixedInt(2000), false);
this.ui.showDialogue(battleSpecDialogue[BattleSpec.FINAL_BOSS].firstStageWin, pokemon.species.name, undefined, () => {
this.addEnemyModifier(getModifierType(modifierTypes.MINI_BLACK_HOLE).newModifier(pokemon) as PersistentModifier, false, true);
const finalBossMBH = getModifierType(modifierTypes.MINI_BLACK_HOLE).newModifier(pokemon) as TurnHeldItemTransferModifier;
finalBossMBH.setTransferrableFalse();
this.addEnemyModifier(finalBossMBH, false, true);
pokemon.generateAndPopulateMoveset(1);
this.setFieldScale(0.75);
this.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,6 @@ import * as Utils from "../utils";
import { MoveCategory, allMoves, MoveTarget, IncrementMovePriorityAttr, applyMoveAttrs } from "./move";
import { getPokemonNameWithAffix } from "../messages";
import Pokemon, { HitResult, PokemonMove } from "../field/pokemon";
import { MoveEffectPhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases";
import { StatusEffect } from "./status-effect";
import { BattlerIndex } from "../battle";
import { BlockNonDirectDamageAbAttr, ChangeMovePriorityAbAttr, ProtectStatAbAttr, applyAbAttrs } from "./ability";
@ -15,6 +14,10 @@ import { Abilities } from "#enums/abilities";
import { ArenaTagType } from "#enums/arena-tag-type";
import { BattlerTagType } from "#enums/battler-tag-type";
import { Moves } from "#enums/moves";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js";
import { ShowAbilityPhase } from "#app/phases/show-ability-phase.js";
import { StatChangePhase } from "#app/phases/stat-change-phase.js";
export enum ArenaTagSide {
BOTH,
@ -266,7 +269,7 @@ const QuickGuardConditionFunc: ProtectConditionFunc = (arena, moveId) => {
if (effectPhase instanceof MoveEffectPhase) {
const attacker = effectPhase.getUserPokemon()!;
applyMoveAttrs(IncrementMovePriorityAttr, attacker, null, move, priority);
applyAbAttrs(ChangeMovePriorityAbAttr, attacker, null, move, priority);
applyAbAttrs(ChangeMovePriorityAbAttr, attacker, null, false, move, priority);
}
return priority.value > 0;
};
@ -424,7 +427,7 @@ class WishTag extends ArenaTag {
if (user) {
this.battlerIndex = user.getBattlerIndex();
this.triggerMessage = i18next.t("arenaTag:wishTagOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(user) });
this.healHp = Math.max(Math.floor(user.getMaxHp() / 2), 1);
this.healHp = Utils.toDmgValue(user.getMaxHp() / 2);
} else {
console.warn("Failed to get source for WishTag onAdd");
}
@ -582,7 +585,7 @@ class SpikesTag extends ArenaTrapTag {
if (!cancelled.value) {
const damageHpRatio = 1 / (10 - 2 * this.layers);
const damage = Math.ceil(pokemon.getMaxHp() * damageHpRatio);
const damage = Utils.toDmgValue(pokemon.getMaxHp() * damageHpRatio);
pokemon.scene.queueMessage(i18next.t("arenaTag:spikesActivateTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
pokemon.damageAndUpdate(damage, HitResult.OTHER);
@ -742,7 +745,7 @@ class StealthRockTag extends ArenaTrapTag {
const damageHpRatio = this.getDamageHpRatio(pokemon);
if (damageHpRatio) {
const damage = Math.ceil(pokemon.getMaxHp() * damageHpRatio);
const damage = Utils.toDmgValue(pokemon.getMaxHp() * damageHpRatio);
pokemon.scene.queueMessage(i18next.t("arenaTag:stealthRockActivateTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
pokemon.damageAndUpdate(damage, HitResult.OTHER);
if (pokemon.turnData) {

View File

@ -1,5 +1,4 @@
import { ChargeAnim, CommonAnim, CommonBattleAnim, MoveChargeAnim } from "./battle-anims";
import { CommonAnimPhase, MoveEffectPhase, MovePhase, PokemonHealPhase, ShowAbilityPhase, StatChangeCallback, StatChangePhase } from "../phases";
import { getPokemonNameWithAffix } from "../messages";
import Pokemon, { MoveResult, HitResult } from "../field/pokemon";
import { Stat, getStatName } from "./pokemon-stat";
@ -18,6 +17,12 @@ import { BattlerTagType } from "#enums/battler-tag-type";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import i18next from "#app/plugins/i18n.js";
import { CommonAnimPhase } from "#app/phases/common-anim-phase.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
import { MovePhase } from "#app/phases/move-phase.js";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js";
import { ShowAbilityPhase } from "#app/phases/show-ability-phase.js";
import { StatChangePhase, StatChangeCallback } from "#app/phases/stat-change-phase.js";
export enum BattlerTagLapseType {
FAINT,
@ -342,7 +347,7 @@ export class ConfusedTag extends BattlerTag {
if (pokemon.randSeedInt(3) === 0) {
const atk = pokemon.getBattleStat(Stat.ATK);
const def = pokemon.getBattleStat(Stat.DEF);
const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100));
const damage = Utils.toDmgValue(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100));
pokemon.scene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself"));
pokemon.damageAndUpdate(damage);
pokemon.battleData.hitCount++;
@ -519,7 +524,7 @@ export class SeedTag extends BattlerTag {
if (!cancelled.value) {
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED));
const damage = pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 8), 1));
const damage = pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / 8));
const reverseDrain = pokemon.hasAbilityWithAttr(ReverseDrainAbAttr, false);
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, source.getBattlerIndex(),
!reverseDrain ? damage : damage * -1,
@ -565,7 +570,7 @@ export class NightmareTag extends BattlerTag {
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
if (!cancelled.value) {
pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / 4));
pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / 4));
}
}
@ -709,7 +714,7 @@ export class IngrainTag extends TrappedTag {
new PokemonHealPhase(
pokemon.scene,
pokemon.getBattlerIndex(),
Math.floor(pokemon.getMaxHp() / 16),
Utils.toDmgValue(pokemon.getMaxHp() / 16),
i18next.t("battlerTags:ingrainLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }),
true
)
@ -772,7 +777,7 @@ export class AquaRingTag extends BattlerTag {
new PokemonHealPhase(
pokemon.scene,
pokemon.getBattlerIndex(),
Math.floor(pokemon.getMaxHp() / 16),
Utils.toDmgValue(pokemon.getMaxHp() / 16),
i18next.t("battlerTags:aquaRingLapse", {
moveName: this.getMoveName(),
pokemonName: getPokemonNameWithAffix(pokemon)
@ -878,7 +883,7 @@ export abstract class DamagingTrapTag extends TrappedTag {
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
if (!cancelled.value) {
pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / 8));
pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / 8));
}
}
@ -1062,7 +1067,7 @@ export class ContactDamageProtectedTag extends ProtectedTag {
if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) {
const attacker = effectPhase.getPokemon();
if (!attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) {
attacker.damageAndUpdate(Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER);
attacker.damageAndUpdate(Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER);
}
}
}
@ -1536,7 +1541,7 @@ export class SaltCuredTag extends BattlerTag {
if (!cancelled.value) {
const pokemonSteelOrWater = pokemon.isOfType(Type.STEEL) || pokemon.isOfType(Type.WATER);
pokemon.damageAndUpdate(Math.max(Math.floor(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8), 1));
pokemon.damageAndUpdate(Utils.toDmgValue(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8));
pokemon.scene.queueMessage(
i18next.t("battlerTags:saltCuredLapse", {
@ -1582,7 +1587,7 @@ export class CursedTag extends BattlerTag {
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
if (!cancelled.value) {
pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 4), 1));
pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / 4));
pokemon.scene.queueMessage(i18next.t("battlerTags:cursedLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
}

View File

@ -1,4 +1,3 @@
import { PokemonHealPhase, StatChangePhase } from "../phases";
import { getPokemonNameWithAffix } from "../messages";
import Pokemon, { HitResult } from "../field/pokemon";
import { BattleStat } from "./battle-stat";
@ -8,6 +7,8 @@ import { DoubleBerryEffectAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs }
import i18next from "i18next";
import { BattlerTagType } from "#enums/battler-tag-type";
import { BerryType } from "#enums/berry-type";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js";
import { StatChangePhase } from "#app/phases/stat-change-phase.js";
export function getBerryName(berryType: BerryType): string {
return i18next.t(`berry:${BerryType[berryType]}.name`);
@ -35,25 +36,25 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate {
return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25);
const battleStat = (berryType - BerryType.LIECHI) as BattleStat;
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
return pokemon.getHpRatio() < threshold.value && pokemon.summonData.battleStats[battleStat] < 6;
};
case BerryType.LANSAT:
return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
return pokemon.getHpRatio() < 0.25 && !pokemon.getTag(BattlerTagType.CRIT_BOOST);
};
case BerryType.STARF:
return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
return pokemon.getHpRatio() < 0.25;
};
case BerryType.LEPPA:
return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
return !!pokemon.getMoveset().find(m => !m?.getPpRatio());
};
}
@ -69,8 +70,8 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
if (pokemon.battleData) {
pokemon.battleData.berriesEaten.push(berryType);
}
const hpHealed = new Utils.NumberHolder(Math.floor(pokemon.getMaxHp() / 4));
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, hpHealed);
const hpHealed = new Utils.NumberHolder(Utils.toDmgValue(pokemon.getMaxHp() / 4));
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, hpHealed);
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(),
hpHealed.value, i18next.t("battle:hpHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), berryName: getBerryName(berryType) }), true));
};
@ -96,7 +97,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
}
const battleStat = (berryType - BerryType.LIECHI) as BattleStat;
const statLevels = new Utils.NumberHolder(1);
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, statLevels);
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statLevels);
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ battleStat ], statLevels.value));
};
case BerryType.LANSAT:
@ -112,7 +113,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
pokemon.battleData.berriesEaten.push(berryType);
}
const statLevels = new Utils.NumberHolder(2);
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, statLevels);
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statLevels);
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ BattleStat.RAND ], statLevels.value));
};
case BerryType.LEPPA:

View File

@ -37,7 +37,7 @@ export const speciesEggMoves = {
[Species.SLOWPOKE]: [ Moves.BOUNCY_BUBBLE, Moves.FLAMETHROWER, Moves.MYSTICAL_POWER, Moves.SHED_TAIL ],
[Species.MAGNEMITE]: [ Moves.PARABOLIC_CHARGE, Moves.BODY_PRESS, Moves.ICE_BEAM, Moves.THUNDERCLAP ],
[Species.FARFETCHD]: [ Moves.IVY_CUDGEL, Moves.TRIPLE_ARROWS, Moves.ROOST, Moves.VICTORY_DANCE ],
[Species.DODUO]: [ Moves.ICE_SPINNER, Moves.MULTI_ATTACK, Moves.FLOATY_FALL, Moves.TRIPLE_ARROWS ],
[Species.DODUO]: [ Moves.TRIPLE_AXEL, Moves.MULTI_ATTACK, Moves.FLOATY_FALL, Moves.TRIPLE_ARROWS ],
[Species.SEEL]: [ Moves.FREEZE_DRY, Moves.BOUNCY_BUBBLE, Moves.SLACK_OFF, Moves.STEAM_ERUPTION ],
[Species.GRIMER]: [ Moves.SUCKER_PUNCH, Moves.CURSE, Moves.STRENGTH_SAP, Moves.NOXIOUS_TORQUE ],
[Species.SHELLDER]: [ Moves.ROCK_BLAST, Moves.WATER_SHURIKEN, Moves.BANEFUL_BUNKER, Moves.BONE_RUSH ],
@ -198,7 +198,7 @@ export const speciesEggMoves = {
[Species.KYOGRE]: [ Moves.BOUNCY_BUBBLE, Moves.HURRICANE, Moves.FREEZE_DRY, Moves.ELECTRO_SHOT ],
[Species.GROUDON]: [ Moves.STONE_AXE, Moves.SOLAR_BLADE, Moves.MORNING_SUN, Moves.SACRED_FIRE ],
[Species.RAYQUAZA]: [ Moves.V_CREATE, Moves.DRAGON_DARTS, Moves.CORE_ENFORCER, Moves.OBLIVION_WING ],
[Species.JIRACHI]: [ Moves.TACHYON_CUTTER, Moves.FLOATY_FALL, Moves.TRIPLE_ARROWS, Moves.SHELL_SMASH ],
[Species.JIRACHI]: [ Moves.TACHYON_CUTTER, Moves.TRIPLE_ARROWS, Moves.ROCK_SLIDE, Moves.SHELL_SMASH ],
[Species.DEOXYS]: [ Moves.COLLISION_COURSE, Moves.EARTH_POWER, Moves.PARTING_SHOT, Moves.LUMINA_CRASH ],
[Species.TURTWIG]: [ Moves.SHELL_SMASH, Moves.MIGHTY_CLEAVE, Moves.ICE_SPINNER, Moves.SAPPY_SEED ],
[Species.CHIMCHAR]: [ Moves.FIERY_DANCE, Moves.SECRET_SWORD, Moves.TRIPLE_AXEL, Moves.SACRED_FIRE ],
@ -418,7 +418,7 @@ export const speciesEggMoves = {
[Species.CELESTEELA]: [ Moves.RECOVER, Moves.BUZZY_BUZZ, Moves.SANDSEAR_STORM, Moves.OBLIVION_WING ],
[Species.KARTANA]: [ Moves.MIGHTY_CLEAVE, Moves.PSYBLADE, Moves.BITTER_BLADE, Moves.BEHEMOTH_BLADE ],
[Species.GUZZLORD]: [ Moves.SUCKER_PUNCH, Moves.COMEUPPANCE, Moves.SLACK_OFF, Moves.SHED_TAIL ],
[Species.NECROZMA]: [ Moves.CLANGOROUS_SOUL, Moves.SACRED_FIRE, Moves.ASTRAL_BARRAGE, Moves.CLANGOROUS_SOUL ],
[Species.NECROZMA]: [ Moves.CLANGOROUS_SOUL, Moves.SACRED_FIRE, Moves.ASTRAL_BARRAGE, Moves.DYNAMAX_CANNON ],
[Species.MAGEARNA]: [ Moves.STRENGTH_SAP, Moves.EARTH_POWER, Moves.MOONBLAST, Moves.MAKE_IT_RAIN ],
[Species.MARSHADOW]: [ Moves.POWER_UP_PUNCH, Moves.TRIPLE_AXEL, Moves.METEOR_MASH, Moves.STORM_THROW ],
[Species.POIPOLE]: [ Moves.CORE_ENFORCER, Moves.ICE_BEAM, Moves.SEARING_SHOT, Moves.MALIGNANT_CHAIN ],
@ -458,7 +458,7 @@ export const speciesEggMoves = {
[Species.MORPEKO]: [ Moves.TRIPLE_AXEL, Moves.OBSTRUCT, Moves.SWORDS_DANCE, Moves.COLLISION_COURSE ],
[Species.CUFANT]: [ Moves.LIQUIDATION, Moves.CURSE, Moves.COMBAT_TORQUE, Moves.GIGATON_HAMMER ],
[Species.DRACOZOLT]: [ Moves.TRIPLE_AXEL, Moves.DRAGON_HAMMER, Moves.FIRE_LASH, Moves.DRAGON_DANCE ],
[Species.ARCTOZOLT]: [ Moves.TRIPLE_AXEL, Moves.AQUA_STEP, Moves.HIGH_HORSEPOWER, Moves.SHIFT_GEAR ],
[Species.ARCTOZOLT]: [ Moves.MOUNTAIN_GALE, Moves.AQUA_STEP, Moves.HIGH_HORSEPOWER, Moves.SHIFT_GEAR ],
[Species.DRACOVISH]: [ Moves.TRIPLE_AXEL, Moves.DRAGON_HAMMER, Moves.THUNDER_FANG, Moves.DRAGON_DANCE ],
[Species.ARCTOVISH]: [ Moves.ICE_FANG, Moves.THUNDER_FANG, Moves.HIGH_HORSEPOWER, Moves.SHIFT_GEAR ],
[Species.DURALUDON]: [ Moves.CORE_ENFORCER, Moves.BODY_PRESS, Moves.RECOVER, Moves.TACHYON_CUTTER ],

View File

@ -1,5 +1,4 @@
import { ChargeAnim, MoveChargeAnim, initMoveAnim, loadMoveAnimAssets } from "./battle-anims";
import { BattleEndPhase, MoveEndPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, PokemonHealPhase, StatChangePhase, SwitchPhase, SwitchSummonPhase } from "../phases";
import { BattleStat, getBattleStatName } from "./battle-stat";
import { EncoreTag, GulpMissileTag, HelpingHandTag, SemiInvulnerableTag, ShellTrapTag, StockpilingTag, TrappedTag, TypeBoostTag } from "./battler-tags";
import { getPokemonNameWithAffix } from "../messages";
@ -29,6 +28,15 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import { MoveUsedEvent } from "#app/events/battle-scene.js";
import { ModifierTier } from "#app/modifier/modifier-tier.js";
import { PartyStatusCurePhase } from "#app/phases/party-status-cure-phase.js";
import { BattleEndPhase } from "#app/phases/battle-end-phase.js";
import { MoveEndPhase } from "#app/phases/move-end-phase.js";
import { MovePhase } from "#app/phases/move-phase.js";
import { NewBattlePhase } from "#app/phases/new-battle-phase.js";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js";
import { StatChangePhase } from "#app/phases/stat-change-phase.js";
import { SwitchPhase } from "#app/phases/switch-phase.js";
import { SwitchSummonPhase } from "#app/phases/switch-summon-phase.js";
export enum MoveCategory {
PHYSICAL,
@ -583,7 +591,7 @@ export default class Move implements Localizable {
case MoveFlags.IGNORE_ABILITIES:
if (user.hasAbilityWithAttr(MoveAbilityBypassAbAttr)) {
const abilityEffectsIgnored = new Utils.BooleanHolder(false);
applyAbAttrs(MoveAbilityBypassAbAttr, user, abilityEffectsIgnored, this);
applyAbAttrs(MoveAbilityBypassAbAttr, user, abilityEffectsIgnored, false, this);
if (abilityEffectsIgnored.value) {
return true;
}
@ -679,11 +687,11 @@ export default class Move implements Localizable {
* @param target {@linkcode Pokemon} The Pokémon being targeted by the move.
* @returns The calculated accuracy of the move.
*/
calculateBattleAccuracy(user: Pokemon, target: Pokemon) {
calculateBattleAccuracy(user: Pokemon, target: Pokemon, simulated: boolean = false) {
const moveAccuracy = new Utils.NumberHolder(this.accuracy);
applyMoveAttrs(VariableAccuracyAttr, user, target, this, moveAccuracy);
applyPreDefendAbAttrs(WonderSkinAbAttr, target, user, this, { value: false }, moveAccuracy);
applyPreDefendAbAttrs(WonderSkinAbAttr, target, user, this, { value: false }, simulated, moveAccuracy);
if (moveAccuracy.value === -1) {
return moveAccuracy.value;
@ -717,7 +725,7 @@ export default class Move implements Localizable {
* @param target {@linkcode Pokemon} The Pokémon being targeted by the move.
* @returns The calculated power of the move.
*/
calculateBattlePower(source: Pokemon, target: Pokemon): number {
calculateBattlePower(source: Pokemon, target: Pokemon, simulated: boolean = false): number {
if (this.category === MoveCategory.STATUS) {
return -1;
}
@ -725,17 +733,17 @@ export default class Move implements Localizable {
const power = new Utils.NumberHolder(this.power);
const typeChangeMovePowerMultiplier = new Utils.NumberHolder(1);
applyPreAttackAbAttrs(MoveTypeChangeAttr, source, target, this, typeChangeMovePowerMultiplier);
applyPreAttackAbAttrs(MoveTypeChangeAttr, source, target, this, simulated, typeChangeMovePowerMultiplier);
const sourceTeraType = source.getTeraType();
if (sourceTeraType !== Type.UNKNOWN && sourceTeraType === this.type && power.value < 60 && this.priority <= 0 && !this.hasAttr(MultiHitAttr) && !source.scene.findModifier(m => m instanceof PokemonMultiHitModifier && m.pokemonId === source.id)) {
power.value = 60;
}
applyPreAttackAbAttrs(VariableMovePowerAbAttr, source, target, this, power);
applyPreAttackAbAttrs(VariableMovePowerAbAttr, source, target, this, simulated, power);
if (source.getAlly()) {
applyPreAttackAbAttrs(AllyMoveCategoryPowerBoostAbAttr, source.getAlly(), target, this, power);
applyPreAttackAbAttrs(AllyMoveCategoryPowerBoostAbAttr, source.getAlly(), target, this, simulated, power);
}
const fieldAuras = new Set(
@ -745,11 +753,11 @@ export default class Move implements Localizable {
);
for (const aura of fieldAuras) {
// The only relevant values are `move` and the `power` holder
aura.applyPreAttack(null, null, null, this, [power]);
aura.applyPreAttack(null, null, simulated, null, this, [power]);
}
const alliedField: Pokemon[] = source instanceof PlayerPokemon ? source.scene.getPlayerField() : source.scene.getEnemyField();
alliedField.forEach(p => applyPreAttackAbAttrs(UserFieldMoveTypePowerBoostAbAttr, p, target, this, power));
alliedField.forEach(p => applyPreAttackAbAttrs(UserFieldMoveTypePowerBoostAbAttr, p, target, this, simulated, power));
power.value *= typeChangeMovePowerMultiplier.value;
@ -977,9 +985,9 @@ export class MoveEffectAttr extends MoveAttr {
*/
getMoveChance(user: Pokemon, target: Pokemon, move: Move, selfEffect?: Boolean, showAbility?: Boolean): integer {
const moveChance = new Utils.NumberHolder(move.chance);
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, moveChance, move, target, selfEffect, showAbility);
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, false, moveChance, move, target, selfEffect, showAbility);
if (!selfEffect) {
applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, target, user, null, null, moveChance);
applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, target, user, null, null, false, moveChance);
}
return moveChance.value;
}
@ -1155,7 +1163,7 @@ export class TargetHalfHpDamageAttr extends FixedDamageAttr {
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
(args[0] as Utils.IntegerHolder).value = Math.max(Math.floor(target.hp / 2), 1);
(args[0] as Utils.IntegerHolder).value = Utils.toDmgValue(target.hp / 2);
return true;
}
@ -1201,7 +1209,7 @@ export class CounterDamageAttr extends FixedDamageAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const damage = user.turnData.attacksReceived.filter(ar => this.moveFilter(allMoves[ar.move])).reduce((total: integer, ar: AttackMoveResult) => total + ar.damage, 0);
(args[0] as Utils.IntegerHolder).value = Math.floor(Math.max(damage * this.multiplier, 1));
(args[0] as Utils.IntegerHolder).value = Utils.toDmgValue(damage * this.multiplier);
return true;
}
@ -1227,7 +1235,7 @@ export class RandomLevelDamageAttr extends FixedDamageAttr {
}
getDamage(user: Pokemon, target: Pokemon, move: Move): number {
return Math.max(Math.floor(user.level * (user.randSeedIntRange(50, 150) * 0.01)), 1);
return Utils.toDmgValue(user.level * (user.randSeedIntRange(50, 150) * 0.01));
}
}
@ -1286,8 +1294,9 @@ export class RecoilAttr extends MoveEffectAttr {
return false;
}
const recoilDamage = Math.max(Math.floor((!this.useHp ? user.turnData.damageDealt : user.getMaxHp()) * this.damageRatio),
user.turnData.damageDealt ? 1 : 0);
const damageValue = (!this.useHp ? user.turnData.damageDealt : user.getMaxHp()) * this.damageRatio;
const minValue = user.turnData.damageDealt ? 1 : 0;
const recoilDamage = Utils.toDmgValue(damageValue, minValue);
if (!recoilDamage) {
return false;
}
@ -1408,7 +1417,7 @@ export class HalfSacrificialAttr extends MoveEffectAttr {
// Check to see if the Pokemon has an ability that blocks non-direct damage
applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled);
if (!cancelled.value) {
user.damageAndUpdate(Math.ceil(user.getMaxHp()/2), HitResult.OTHER, false, true, true);
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp()/2), HitResult.OTHER, false, true, true);
user.scene.queueMessage(i18next.t("moveTriggers:cutHpPowerUpMove", {pokemonName: getPokemonNameWithAffix(user)})); // Queue recoil message
}
return true;
@ -1459,7 +1468,7 @@ export class HealAttr extends MoveEffectAttr {
*/
addHealPhase(target: Pokemon, healRatio: number) {
target.scene.unshiftPhase(new PokemonHealPhase(target.scene, target.getBattlerIndex(),
Math.max(Math.floor(target.getMaxHp() * healRatio), 1), i18next.t("moveTriggers:healHp", {pokemonName: getPokemonNameWithAffix(target)}), true, !this.showAnim));
Utils.toDmgValue(target.getMaxHp() * healRatio), i18next.t("moveTriggers:healHp", {pokemonName: getPokemonNameWithAffix(target)}), true, !this.showAnim));
}
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
@ -1743,7 +1752,7 @@ export class HitHealAttr extends MoveEffectAttr {
message = i18next.t("battle:drainMessage", {pokemonName: getPokemonNameWithAffix(target)});
} else {
// Default healing formula used by draining moves like Absorb, Draining Kiss, Bitter Blade, etc.
healAmount = Math.max(Math.floor(user.turnData.currDamageDealt * this.healRatio), 1);
healAmount = Utils.toDmgValue(user.turnData.currDamageDealt * this.healRatio);
message = i18next.t("battle:regainHealth", {pokemonName: getPokemonNameWithAffix(user)});
}
if (reverseDrain) {
@ -1876,7 +1885,7 @@ export class MultiHitAttr extends MoveAttr {
{
const rand = user.randSeedInt(16);
const hitValue = new Utils.IntegerHolder(rand);
applyAbAttrs(MaxMultiHitAbAttr, user, null, hitValue);
applyAbAttrs(MaxMultiHitAbAttr, user, null, false, hitValue);
if (hitValue.value >= 10) {
return 2;
} else if (hitValue.value >= 4) {
@ -1947,7 +1956,7 @@ export class StatusEffectAttr extends MoveEffectAttr {
}
if ((!pokemon.status || (pokemon.status.effect === this.effect && moveChance < 0))
&& pokemon.trySetStatus(this.effect, true, user, this.cureTurn)) {
applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, this.effect);
applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, false, this.effect);
return true;
}
}
@ -2703,7 +2712,7 @@ export class CutHpStatBoostAttr extends StatChangeAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> {
return new Promise<boolean>(resolve => {
user.damageAndUpdate(Math.floor(user.getMaxHp() / this.cutRatio), HitResult.OTHER, false, true);
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / this.cutRatio), HitResult.OTHER, false, true);
user.updateInfo().then(() => {
const ret = super.apply(user, target, move, args);
if (this.messageCallback) {
@ -3183,7 +3192,7 @@ export class CompareWeightPowerAttr extends VariablePowerAttr {
export class HpPowerAttr extends VariablePowerAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
(args[0] as Utils.NumberHolder).value = Math.max(Math.floor(150 * user.getHpRatio()), 1);
(args[0] as Utils.NumberHolder).value = Utils.toDmgValue(150 * user.getHpRatio());
return true;
}
@ -3211,7 +3220,7 @@ export class OpponentHighHpPowerAttr extends VariablePowerAttr {
* @returns true
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
(args[0] as Utils.NumberHolder).value = Math.max(Math.floor(this.maxBasePower * target.getHpRatio()), 1);
(args[0] as Utils.NumberHolder).value = Utils.toDmgValue(this.maxBasePower * target.getHpRatio());
return true;
}
@ -3405,7 +3414,7 @@ export class PresentPowerAttr extends VariablePowerAttr {
// If this move is multi-hit, disable all other hits
user.stopMultiHit();
target.scene.unshiftPhase(new PokemonHealPhase(target.scene, target.getBattlerIndex(),
Math.max(Math.floor(target.getMaxHp() / 4), 1), i18next.t("moveTriggers:regainedHealth", {pokemonName: getPokemonNameWithAffix(target)}), true));
Utils.toDmgValue(target.getMaxHp() / 4), i18next.t("moveTriggers:regainedHealth", {pokemonName: getPokemonNameWithAffix(target)}), true));
}
return true;
@ -3777,6 +3786,30 @@ export class TeraBlastCategoryAttr extends VariableMoveCategoryAttr {
}
}
/**
* Increases the power of Tera Blast if the user is Terastallized into Stellar type
* @extends VariablePowerAttr
*/
export class TeraBlastPowerAttr extends VariablePowerAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
/**
* @param user {@linkcode Pokemon} Pokemon using the move
* @param target {@linkcode Pokemon} N/A
* @param move {@linkcode Move} {@linkcode Move.TERA_BLAST}
* @param {any[]} args N/A
* @returns true or false
*/
const power = args[0] as Utils.NumberHolder;
if (user.isTerastallized() && move.type === Type.STELLAR) {
//200 instead of 100 to reflect lack of stellar being 2x dmg on any type
power.value = 200;
return true;
}
return false;
}
}
/**
* Change the move category to status when used on the ally
* @extends VariableMoveCategoryAttr
@ -4030,6 +4063,28 @@ export class HiddenPowerTypeAttr extends VariableMoveTypeAttr {
}
}
/**
* Changes the type of Tera Blast to match the user's tera type
* @extends VariableMoveTypeAttr
*/
export class TeraBlastTypeAttr extends VariableMoveTypeAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
/**
* @param user {@linkcode Pokemon} the user's type is checked
* @param target {@linkcode Pokemon} N/A
* @param move {@linkcode Move} {@linkcode Move.TeraBlastTypeAttr}
* @param {any[]} args N/A
* @returns true or false
*/
if (user.isTerastallized()) {
move.type = user.getTeraType(); //changes move type to tera type
return true;
}
return false;
}
}
export class MatchUserTypeAttr extends VariableMoveTypeAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const userTypes = user.getTypes(true);
@ -4179,9 +4234,9 @@ const crashDamageFunc = (user: Pokemon, move: Move) => {
return false;
}
user.damageAndUpdate(Math.floor(user.getMaxHp() / 2), HitResult.OTHER, false, true);
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / 2), HitResult.OTHER, false, true);
user.scene.queueMessage(i18next.t("moveTriggers:keptGoingAndCrashed", {pokemonName: getPokemonNameWithAffix(user)}));
user.turnData.damageTaken += Math.floor(user.getMaxHp() / 2);
user.turnData.damageTaken += Utils.toDmgValue(user.getMaxHp() / 2);
return true;
};
@ -4431,6 +4486,39 @@ export class GulpMissileTagAttr extends MoveEffectAttr {
}
}
/**
* Attribute to implement Jaw Lock's linked trapping effect between the user and target
* @extends AddBattlerTagAttr
*/
export class JawLockAttr extends AddBattlerTagAttr {
constructor() {
super(BattlerTagType.TRAPPED);
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!super.canApply(user, target, move, args)) {
return false;
}
// If either the user or the target already has the tag, do not apply
if (user.getTag(TrappedTag) || target.getTag(TrappedTag)) {
return false;
}
const moveChance = this.getMoveChance(user, target, move, this.selfTarget);
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) {
/**
* Add the tag to both the user and the target.
* The target's tag source is considered to be the user and vice versa
*/
return target.addTag(BattlerTagType.TRAPPED, 1, move.id, user.id)
&& user.addTag(BattlerTagType.TRAPPED, 1, move.id, target.id);
}
return false;
}
}
export class CurseAttr extends MoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move:Move, args: any[]): boolean {
@ -4442,7 +4530,7 @@ export class CurseAttr extends MoveEffectAttr {
const curseRecoilDamage = Math.max(1, Math.floor(user.getMaxHp() / 2));
user.damageAndUpdate(curseRecoilDamage, HitResult.OTHER, false, true, true);
user.scene.queueMessage(
i18next.t("battle:cursedOnAdd", {
i18next.t("battlerTags:cursedOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(user),
pokemonName: getPokemonNameWithAffix(target)
})
@ -4858,8 +4946,8 @@ export class RevivalBlessingAttr extends MoveEffectAttr {
const pokemon = faintedPokemon[user.randSeedInt(faintedPokemon.length)];
const slotIndex = user.scene.getEnemyParty().findIndex(p => pokemon.id === p.id);
pokemon.resetStatus();
pokemon.heal(Math.min(Math.max(Math.ceil(Math.floor(0.5 * pokemon.getMaxHp())), 1), pokemon.getMaxHp()));
user.scene.queueMessage(`${getPokemonNameWithAffix(pokemon)} was revived!`,0,true);
pokemon.heal(Math.min(Utils.toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp()));
user.scene.queueMessage(i18next.t("moveTriggers:revivalBlessing", {pokemonName: getPokemonNameWithAffix(pokemon)}),0,true);
if (user.scene.currentBattle.double && user.scene.getEnemyParty().length > 1) {
const allyPokemon = user.getAlly();
@ -7551,7 +7639,7 @@ export function initMoves() {
.attr(OpponentHighHpPowerAttr, 120),
new AttackMove(Moves.MAGMA_STORM, Type.FIRE, MoveCategory.SPECIAL, 100, 75, 5, -1, 0, 4)
.attr(TrapAttr, BattlerTagType.MAGMA_STORM),
new StatusMove(Moves.DARK_VOID, Type.DARK, 50, 10, -1, 0, 4)
new StatusMove(Moves.DARK_VOID, Type.DARK, 80, 10, -1, 0, 4) //Accuracy from Generations 4-6
.attr(StatusEffectAttr, StatusEffect.SLEEP)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.SEED_FLARE, Type.GRASS, MoveCategory.SPECIAL, 120, 85, 5, 40, 0, 4)
@ -8390,8 +8478,7 @@ export function initMoves() {
.attr(HighCritAttr)
.attr(BypassRedirectAttr),
new AttackMove(Moves.JAW_LOCK, Type.DARK, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 8)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1, 1, false, true)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, false, 1, 1, false, true)
.attr(JawLockAttr)
.bitingMove(),
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)
@ -8836,7 +8923,10 @@ export function initMoves() {
End Unused */
new AttackMove(Moves.TERA_BLAST, Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 9)
.attr(TeraBlastCategoryAttr)
.unimplemented(),
.attr(TeraBlastTypeAttr)
.attr(TeraBlastPowerAttr)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1, true, (user, target, move) => user.isTerastallized() && user.isOfType(Type.STELLAR))
.partial(),
new SelfStatusMove(Moves.SILK_TRAP, Type.BUG, -1, 10, -1, 4, 9)
.attr(ProtectAttr, BattlerTagType.SILK_TRAP),
new AttackMove(Moves.AXE_KICK, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 90, 10, 30, 0, 9)

View File

@ -837,6 +837,8 @@ export const pokemonFormChanges: PokemonFormChanges = {
new SpeciesFormChange(Species.CRAMORANT, "", "gorging", new SpeciesFormChangeManualTrigger, true, new SpeciesFormChangeCondition(p => p.getHpRatio() < .5)),
new SpeciesFormChange(Species.CRAMORANT, "gulping", "", new SpeciesFormChangeManualTrigger, true),
new SpeciesFormChange(Species.CRAMORANT, "gorging", "", new SpeciesFormChangeManualTrigger, true),
new SpeciesFormChange(Species.CRAMORANT, "gulping", "", new SpeciesFormChangeActiveTrigger(false), true),
new SpeciesFormChange(Species.CRAMORANT, "gorging", "", new SpeciesFormChangeActiveTrigger(false), true),
]
};

View File

@ -2581,7 +2581,7 @@ export function initSpecies() {
),
new PokemonSpecies(Species.WALKING_WAKE, 9, false, false, false, "Paradox Pokémon", Type.WATER, Type.DRAGON, 3.5, 280, Abilities.PROTOSYNTHESIS, Abilities.NONE, Abilities.NONE, 590, 99, 83, 91, 125, 83, 109, 5, 0, 295, GrowthRate.SLOW, null, false),
new PokemonSpecies(Species.IRON_LEAVES, 9, false, false, false, "Paradox Pokémon", Type.GRASS, Type.PSYCHIC, 1.5, 125, Abilities.QUARK_DRIVE, Abilities.NONE, Abilities.NONE, 590, 90, 130, 88, 70, 108, 104, 5, 0, 295, GrowthRate.SLOW, null, false),
new PokemonSpecies(Species.DIPPLIN, 9, false, false, false, "Candy Apple Pokémon", Type.GRASS, Type.DRAGON, 0.4, 9.7, Abilities.SUPERSWEET_SYRUP, Abilities.GLUTTONY, Abilities.STICKY_HOLD, 485, 80, 80, 110, 95, 80, 40, 45, 50, 170, GrowthRate.ERRATIC, null, false),
new PokemonSpecies(Species.DIPPLIN, 9, false, false, false, "Candy Apple Pokémon", Type.GRASS, Type.DRAGON, 0.4, 9.7, Abilities.SUPERSWEET_SYRUP, Abilities.GLUTTONY, Abilities.STICKY_HOLD, 485, 80, 80, 110, 95, 80, 40, 45, 50, 170, GrowthRate.ERRATIC, 50, false),
new PokemonSpecies(Species.POLTCHAGEIST, 9, false, false, false, "Matcha Pokémon", Type.GRASS, Type.GHOST, 0.1, 1.1, Abilities.HOSPITALITY, Abilities.NONE, Abilities.HEATPROOF, 308, 40, 45, 45, 74, 54, 50, 120, 50, 62, GrowthRate.SLOW, null, false, false,
new PokemonForm("Counterfeit Form", "counterfeit", Type.GRASS, Type.GHOST, 0.1, 1.1, Abilities.HOSPITALITY, Abilities.NONE, Abilities.HEATPROOF, 308, 40, 45, 45, 74, 54, 50, 120, 50, 62, false, null, true),
new PokemonForm("Artisan Form", "artisan", Type.GRASS, Type.GHOST, 0.1, 1.1, Abilities.HOSPITALITY, Abilities.NONE, Abilities.HEATPROOF, 308, 40, 45, 45, 74, 54, 50, 120, 50, 62, false, null, true),
@ -3317,6 +3317,28 @@ export function getStarterValueFriendshipCap(value: integer): integer {
}
}
/**
* Method to get the daily list of starters with Pokerus.
* @param scene {@linkcode BattleScene} used as part of RNG
* @returns A list of starters with Pokerus
*/
export function getPokerusStarters(scene: BattleScene): PokemonSpecies[] {
const pokerusStarters: PokemonSpecies[] = [];
const date = new Date();
const starterCount = 3; //for easy future adjustment!
date.setUTCHours(0, 0, 0, 0);
scene.executeWithSeedOffset(() => {
while (pokerusStarters.length < starterCount) {
const randomSpeciesId = parseInt(Utils.randSeedItem(Object.keys(speciesStarters)), 10);
const species = getPokemonSpecies(randomSpeciesId);
if (!pokerusStarters.includes(species)) {
pokerusStarters.push(species);
}
}
}, 0, date.getTime().toString());
return pokerusStarters;
}
export const starterPassiveAbilities = {
[Species.BULBASAUR]: Abilities.GRASSY_SURGE,
[Species.CHARMANDER]: Abilities.BEAST_BOOST,
@ -3559,7 +3581,7 @@ export const starterPassiveAbilities = {
[Species.HEATRAN]: Abilities.EARTH_EATER,
[Species.REGIGIGAS]: Abilities.MINDS_EYE,
[Species.GIRATINA]: Abilities.SHADOW_SHIELD,
[Species.CRESSELIA]: Abilities.MAGIC_BOUNCE,
[Species.CRESSELIA]: Abilities.UNAWARE,
[Species.PHIONE]: Abilities.SIMPLE,
[Species.MANAPHY]: Abilities.PRIMORDIAL_SEA,
[Species.DARKRAI]: Abilities.UNNERVE,

View File

@ -59,7 +59,7 @@ export class Terrain {
case TerrainType.PSYCHIC:
if (!move.hasAttr(ProtectAttr)) {
const priority = new Utils.IntegerHolder(move.priority);
applyAbAttrs(ChangeMovePriorityAbAttr, user, null, move, priority);
applyAbAttrs(ChangeMovePriorityAbAttr, user, null, false, move, priority);
// Cancels move if the move has positive priority and targets a Pokemon grounded on the Psychic Terrain
return priority.value > 0 && user.getOpponents().some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded());
}

View File

@ -1577,11 +1577,11 @@ export const trainerConfigs: TrainerConfigs = {
})),
[TrainerType.RIVAL]: new TrainerConfig((t = TrainerType.RIVAL)).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setMixedBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL)
.setModifierRewardFuncs(() => modifierTypes.SUPER_EXP_CHARM, () => modifierTypes.EXP_SHARE, () => modifierTypes.SHINY_CHARM, () => modifierTypes.ABILITY_CHARM)
.setModifierRewardFuncs(() => modifierTypes.SUPER_EXP_CHARM, () => modifierTypes.EXP_SHARE)
.setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE, Species.CHIKORITA, Species.CYNDAQUIL, Species.TOTODILE, Species.TREECKO, Species.TORCHIC, Species.MUDKIP, Species.TURTWIG, Species.CHIMCHAR, Species.PIPLUP, Species.SNIVY, Species.TEPIG, Species.OSHAWOTT, Species.CHESPIN, Species.FENNEKIN, Species.FROAKIE, Species.ROWLET, Species.LITTEN, Species.POPPLIO, Species.GROOKEY, Species.SCORBUNNY, Species.SOBBLE, Species.SPRIGATITO, Species.FUECOCO, Species.QUAXLY], TrainerSlot.TRAINER, true))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.PIDGEY, Species.HOOTHOOT, Species.TAILLOW, Species.STARLY, Species.PIDOVE, Species.FLETCHLING, Species.PIKIPEK, Species.ROOKIDEE, Species.WATTREL], TrainerSlot.TRAINER, true)),
[TrainerType.RIVAL_2]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setMoneyMultiplier(1.25).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setMixedBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL_2)
.setModifierRewardFuncs(() => modifierTypes.EXP_SHARE, () => modifierTypes.SHINY_CHARM)
.setModifierRewardFuncs(() => modifierTypes.EXP_SHARE)
.setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.IVYSAUR, Species.CHARMELEON, Species.WARTORTLE, Species.BAYLEEF, Species.QUILAVA, Species.CROCONAW, Species.GROVYLE, Species.COMBUSKEN, Species.MARSHTOMP, Species.GROTLE, Species.MONFERNO, Species.PRINPLUP, Species.SERVINE, Species.PIGNITE, Species.DEWOTT, Species.QUILLADIN, Species.BRAIXEN, Species.FROGADIER, Species.DARTRIX, Species.TORRACAT, Species.BRIONNE, Species.THWACKEY, Species.RABOOT, Species.DRIZZILE, Species.FLORAGATO, Species.CROCALOR, Species.QUAXWELL], TrainerSlot.TRAINER, true))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.PIDGEOTTO, Species.HOOTHOOT, Species.TAILLOW, Species.STARAVIA, Species.TRANQUILL, Species.FLETCHINDER, Species.TRUMBEAK, Species.CORVISQUIRE, Species.WATTREL], TrainerSlot.TRAINER, true))
.setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)),

View File

@ -0,0 +1,13 @@
/**
* Determines the cursor target when entering the shop phase.
*/
export enum ShopCursorTarget {
/** Cursor points to Reroll */
REROLL,
/** Cursor points to Items */
ITEMS,
/** Cursor points to Shop */
SHOP,
/** Cursor points to Check Team */
CHECK_TEAM
}

View File

@ -4,7 +4,6 @@ import { Constructor } from "#app/utils";
import * as Utils from "../utils";
import PokemonSpecies, { getPokemonSpecies } from "../data/pokemon-species";
import { Weather, WeatherType, getTerrainClearMessage, getTerrainStartMessage, getWeatherClearMessage, getWeatherStartMessage } from "../data/weather";
import { CommonAnimPhase } from "../phases";
import { CommonAnim } from "../data/battle-anims";
import { Type } from "../data/type";
import Move from "../data/move";
@ -21,6 +20,7 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import { TimeOfDay } from "#enums/time-of-day";
import { TrainerType } from "#enums/trainer-type";
import { CommonAnimPhase } from "#app/phases/common-anim-phase.js";
export class Arena {
public scene: BattleScene;
@ -584,6 +584,10 @@ export class Arena {
return this.getTagOnSide(tagType, ArenaTagSide.BOTH);
}
hasTag(tagType: ArenaTagType) : boolean {
return !!this.getTag(tagType);
}
getTagOnSide(tagType: ArenaTagType | Constructor<ArenaTag>, side: ArenaTagSide): ArenaTag | undefined {
return typeof(tagType) === "string"
? this.tags.find(t => t.tagType === tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side))

View File

@ -17,7 +17,6 @@ import { initMoveAnim, loadMoveAnimAssets } from "../data/battle-anims";
import { Status, StatusEffect, getRandomStatus } from "../data/status-effect";
import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from "../data/pokemon-evolutions";
import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "../data/tms";
import { DamagePhase, FaintPhase, LearnMovePhase, MoveEffectPhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase, ToggleDoublePositionPhase, MoveEndPhase } from "../phases";
import { BattleStat } from "../data/battle-stat";
import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, ExposedTag } from "../data/battler-tags";
import { WeatherType } from "../data/weather";
@ -51,6 +50,15 @@ import { Biome } from "#enums/biome";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import { getPokemonNameWithAffix } from "#app/messages.js";
import { DamagePhase } from "#app/phases/damage-phase.js";
import { FaintPhase } from "#app/phases/faint-phase.js";
import { LearnMovePhase } from "#app/phases/learn-move-phase.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
import { MoveEndPhase } from "#app/phases/move-end-phase.js";
import { ObtainStatusEffectPhase } from "#app/phases/obtain-status-effect-phase.js";
import { StatChangePhase } from "#app/phases/stat-change-phase.js";
import { SwitchSummonPhase } from "#app/phases/switch-summon-phase.js";
import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase.js";
export enum FieldPosition {
CENTER,
@ -686,7 +694,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
break;
}
}
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, opponent, null, statLevel);
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, opponent, null, false, statLevel);
if (move) {
applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, opponent, move, statLevel);
}
@ -921,8 +929,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* by how many learnable moves there are for the {@linkcode Pokemon}.
*/
getLearnableLevelMoves(): Moves[] {
let levelMoves = this.getLevelMoves(1, true).map(lm => lm[1]);
if (this.metBiome === -1 && !this.scene.gameMode.isFreshStartChallenge()) {
let levelMoves = this.getLevelMoves(1, true, false, true).map(lm => lm[1]);
if (this.metBiome === -1 && !this.scene.gameMode.isFreshStartChallenge() && !this.scene.gameMode.isDaily) {
levelMoves = this.getUnlockedEggMoves().concat(levelMoves);
}
return levelMoves.filter(lm => !this.moveset.some(m => m?.moveId === lm));
@ -970,12 +978,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
// this.scene potentially can be undefined for a fainted pokemon in doubles
// use optional chaining to avoid runtime errors
if (forDefend && (this.getTag(GroundedTag) || this.scene?.arena.getTag(ArenaTagType.GRAVITY))) {
const flyingIndex = types.indexOf(Type.FLYING);
if (flyingIndex > -1) {
types.splice(flyingIndex, 1);
}
}
if (!types.length) { // become UNKNOWN if no types are present
types.push(Type.UNKNOWN);
@ -1120,10 +1122,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const suppressed = new Utils.BooleanHolder(false);
this.scene.getField(true).filter(p => p !== this).map(p => {
if (p.getAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility()) {
p.getAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, false, suppressed, [ability]));
p.getAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, false, false, suppressed, [ability]));
}
if (p.getPassiveAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility(true)) {
p.getPassiveAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, true, suppressed, [ability]));
p.getPassiveAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, true, false, suppressed, [ability]));
}
});
if (suppressed.value) {
@ -1175,7 +1177,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
getWeight(): number {
const weight = new Utils.NumberHolder(this.species.weight);
// This will trigger the ability overlay so only call this function when necessary
applyAbAttrs(WeightMultiplierAbAttr, this, null, weight);
applyAbAttrs(WeightMultiplierAbAttr, this, null, false, weight);
return weight.value;
}
@ -1210,11 +1212,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
*
* @param source - The Pokémon using the move.
* @param move - The move being used.
* @returns The type damage multiplier or undefined if it's a status move
* @returns The type damage multiplier or 1 if it's a status move
*/
getMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier | undefined {
getMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier {
if (move.getMove().category === MoveCategory.STATUS) {
return undefined;
return 1;
}
return this.getAttackMoveEffectiveness(source, move, !this.battleData?.abilityRevealed);
@ -1235,10 +1237,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const cancelled = new Utils.BooleanHolder(false);
applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier);
if (!typeless && !ignoreAbility) {
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true);
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, true, typeMultiplier);
}
if (!cancelled.value && !ignoreAbility) {
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true);
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, true, typeMultiplier);
}
return (!cancelled.value ? Number(typeMultiplier.value) : 0) as TypeDamageMultiplier;
@ -1264,12 +1266,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return this.isTerastallized() ? 2 : 1;
}
const types = this.getTypes(true, true);
const arena = this.scene.arena;
// Handle flying v ground type immunity without removing flying type so effective types are still effective
// Related to https://github.com/pagefaultgames/pokerogue/issues/524
if (moveType === Type.GROUND && (this.isGrounded() || arena.hasTag(ArenaTagType.GRAVITY))) {
const flyingIndex = types.indexOf(Type.FLYING);
if (flyingIndex > -1) {
types.splice(flyingIndex, 1);
}
}
let multiplier = types.map(defType => {
if (source) {
const ignoreImmunity = new Utils.BooleanHolder(false);
if (source.isActive(true) && source.hasAbilityWithAttr(IgnoreTypeImmunityAbAttr)) {
applyAbAttrs(IgnoreTypeImmunityAbAttr, source, ignoreImmunity, moveType, defType);
applyAbAttrs(IgnoreTypeImmunityAbAttr, source, ignoreImmunity, false, moveType, defType);
}
if (ignoreImmunity.value) {
return 1;
@ -1285,7 +1297,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}).reduce((acc, cur) => acc * cur, 1) as TypeDamageMultiplier;
// Handle strong winds lowering effectiveness of types super effective against pure flying
if (!ignoreStrongWinds && this.scene.arena.weather?.weatherType === WeatherType.STRONG_WINDS && !this.scene.arena.weather.isEffectSuppressed(this.scene) && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) {
if (!ignoreStrongWinds && arena.weather?.weatherType === WeatherType.STRONG_WINDS && !arena.weather.isEffectSuppressed(this.scene) && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) {
multiplier /= 2;
if (!simulated) {
this.scene.queueMessage(i18next.t("weather:strongWindsEffectMessage"));
@ -1910,9 +1922,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const userAccuracyLevel = new Utils.IntegerHolder(this.summonData.battleStats[BattleStat.ACC]);
const targetEvasionLevel = new Utils.IntegerHolder(target.summonData.battleStats[BattleStat.EVA]);
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, target, null, userAccuracyLevel);
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, this, null, targetEvasionLevel);
applyAbAttrs(IgnoreOpponentEvasionAbAttr, this, null, targetEvasionLevel);
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, target, null, false, userAccuracyLevel);
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, this, null, false, targetEvasionLevel);
applyAbAttrs(IgnoreOpponentEvasionAbAttr, this, null, false, targetEvasionLevel);
applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, target, sourceMove, targetEvasionLevel);
this.scene.applyModifiers(TempBattleStatBoosterModifier, this.isPlayer(), TempBattleStat.ACC, userAccuracyLevel);
@ -1927,7 +1939,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
: 3 / (3 + Math.min(targetEvasionLevel.value - userAccuracyLevel.value, 6));
}
applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, this, BattleStat.ACC, accuracyMultiplier, sourceMove);
applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, this, BattleStat.ACC, accuracyMultiplier, false, sourceMove);
const evasionMultiplier = new Utils.NumberHolder(1);
applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, target, BattleStat.EVA, evasionMultiplier);
@ -1937,6 +1949,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return accuracyMultiplier.value;
}
/**
* Apply the results of a move to this pokemon
* @param {Pokemon} source The pokemon using the move
* @param {PokemonMove} battlerMove The move being used
* @returns {HitResult} The result of the attack
*/
apply(source: Pokemon, move: Move): HitResult {
let result: HitResult;
const damage = new Utils.NumberHolder(0);
@ -1972,12 +1990,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const sourceTeraType = source.getTeraType();
if (!typeless) {
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier);
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier);
applyMoveAttrs(NeutralDamageAgainstFlyingTypeMultiplierAttr, source, this, move, typeMultiplier);
}
if (!cancelled.value) {
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier);
defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, typeMultiplier));
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier);
defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, false, typeMultiplier));
}
if (cancelled.value) {
@ -2000,7 +2018,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const critOnly = new Utils.BooleanHolder(false);
const critAlways = source.getTag(BattlerTagType.ALWAYS_CRIT);
applyMoveAttrs(CritOnlyAttr, source, this, move, critOnly);
applyAbAttrs(ConditionalCritAbAttr, source, null, critOnly, this, move);
applyAbAttrs(ConditionalCritAbAttr, source, null, false, critOnly, this, move);
if (critOnly.value || critAlways) {
isCritical = true;
} else {
@ -2010,7 +2028,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.scene.applyModifiers(TempBattleStatBoosterModifier, source.isPlayer(), TempBattleStat.CRIT, critLevel);
const bonusCrit = new Utils.BooleanHolder(false);
//@ts-ignore
if (applyAbAttrs(BonusCritAbAttr, source, null, bonusCrit)) { // TODO: resolve ts-ignore. This is a promise. Checking a promise is bogus.
if (applyAbAttrs(BonusCritAbAttr, source, null, false, bonusCrit)) { // TODO: resolve ts-ignore. This is a promise. Checking a promise is bogus.
if (bonusCrit.value) {
critLevel.value += 1;
}
@ -2028,7 +2046,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (isCritical) {
const noCritTag = this.scene.arena.getTagOnSide(NoCritTag, defendingSide);
const blockCrit = new Utils.BooleanHolder(false);
applyAbAttrs(BlockCritAbAttr, this, null, blockCrit);
applyAbAttrs(BlockCritAbAttr, this, null, false, blockCrit);
if (noCritTag || blockCrit.value) {
isCritical = false;
}
@ -2036,7 +2054,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const sourceAtk = new Utils.IntegerHolder(source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK, this, undefined, isCritical));
const targetDef = new Utils.IntegerHolder(this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF, source, move, isCritical));
const criticalMultiplier = new Utils.NumberHolder(isCritical ? 1.5 : 1);
applyAbAttrs(MultCritAbAttr, source, null, criticalMultiplier);
applyAbAttrs(MultCritAbAttr, source, null, false, criticalMultiplier);
const screenMultiplier = new Utils.NumberHolder(1);
if (!isCritical) {
this.scene.arena.applyTagsForSide(WeakenMoveScreenTag, defendingSide, move.category, this.scene.currentBattle.double, screenMultiplier);
@ -2051,7 +2069,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
stabMultiplier.value += 0.5;
}
applyAbAttrs(StabBoostAbAttr, source, null, stabMultiplier);
applyAbAttrs(StabBoostAbAttr, source, null, false, stabMultiplier);
if (sourceTeraType !== Type.UNKNOWN && matchesSourceType) {
stabMultiplier.value = Math.min(stabMultiplier.value + 0.5, 2.25);
@ -2069,12 +2087,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
numTargets = effectPhase.getTargets().length;
}
const twoStrikeMultiplier = new Utils.NumberHolder(1);
applyPreAttackAbAttrs(AddSecondStrikeAbAttr, source, this, move, numTargets, new Utils.IntegerHolder(0), twoStrikeMultiplier);
applyPreAttackAbAttrs(AddSecondStrikeAbAttr, source, this, move, false, numTargets, new Utils.IntegerHolder(0), twoStrikeMultiplier);
if (!isTypeImmune) {
const levelMultiplier = (2 * source.level / 5 + 2);
const randomMultiplier = ((this.scene.randBattleSeedInt(16) + 85) / 100);
damage.value = Math.ceil((((levelMultiplier * power * sourceAtk.value / targetDef.value) / 50) + 2)
damage.value = Utils.toDmgValue((((levelMultiplier * power * sourceAtk.value / targetDef.value) / 50) + 2)
* stabMultiplier.value
* typeMultiplier.value
* arenaAttackTypeMultiplier.value
@ -2088,14 +2106,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (isPhysical && source.status && source.status.effect === StatusEffect.BURN) {
if (!move.hasAttr(BypassBurnDamageReductionAttr)) {
const burnDamageReductionCancelled = new Utils.BooleanHolder(false);
applyAbAttrs(BypassBurnDamageReductionAbAttr, source, burnDamageReductionCancelled);
applyAbAttrs(BypassBurnDamageReductionAbAttr, source, burnDamageReductionCancelled, false);
if (!burnDamageReductionCancelled.value) {
damage.value = Math.floor(damage.value / 2);
damage.value = Utils.toDmgValue(damage.value / 2);
}
}
}
applyPreAttackAbAttrs(DamageBoostAbAttr, source, this, move, damage);
applyPreAttackAbAttrs(DamageBoostAbAttr, source, this, move, false, damage);
/**
* For each {@link HitsTagAttr} the move has, doubles the damage of the move if:
@ -2111,7 +2129,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
if (this.scene.arena.terrain?.terrainType === TerrainType.MISTY && this.isGrounded() && move.type === Type.DRAGON) {
damage.value = Math.floor(damage.value / 2);
damage.value = Utils.toDmgValue(damage.value / 2);
}
const fixedDamage = new Utils.IntegerHolder(0);
@ -2153,7 +2171,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.scene.applyModifiers(EnemyDamageReducerModifier, false, damage);
}
applyPreDefendAbAttrs(ReceivedMoveDamageMultiplierAbAttr, this, source, move, cancelled, damage);
applyPreDefendAbAttrs(ReceivedMoveDamageMultiplierAbAttr, this, source, move, cancelled, false, damage);
}
// This attribute may modify damage arbitrarily, so be careful about changing its order of application.
@ -2166,7 +2184,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (damage.value) {
if (this.isFullHp()) {
applyPreDefendAbAttrs(PreDefendFullHpEndureAbAttr, this, source, move, cancelled, damage);
applyPreDefendAbAttrs(PreDefendFullHpEndureAbAttr, this, source, move, cancelled, false, damage);
} else if (!this.isPlayer() && damage.value >= this.hp) {
this.scene.applyModifiers(EnemyEndureChanceModifier, false, this);
}
@ -2210,7 +2228,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.scene.queueMessage(i18next.t("battle:hitResultNoEffect", { pokemonName: getPokemonNameWithAffix(this) }));
break;
case HitResult.IMMUNE:
this.scene.queueMessage(`${this.name} is unaffected!`);
this.scene.queueMessage(i18next.t("battle:hitResultImmune", { pokemonName: this.name }));
break;
case HitResult.ONE_HIT_KO:
this.scene.queueMessage(i18next.t("battle:hitResultOneHitKO"));
@ -2233,11 +2251,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
break;
case MoveCategory.STATUS:
if (!typeless) {
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier);
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier);
}
if (!cancelled.value) {
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier);
defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, typeMultiplier));
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier);
defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, false, typeMultiplier));
}
if (!typeMultiplier.value) {
this.scene.queueMessage(i18next.t("battle:hitResultNoEffect", { pokemonName: getPokemonNameWithAffix(this) }));
@ -2329,6 +2347,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return maxForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && maxForms.includes(this.getFusionFormKey()!));
}
canAddTag(tagType: BattlerTagType): boolean {
if (this.getTag(tagType)) {
return false;
}
const stubTag = new BattlerTag(tagType, 0, 0);
const cancelled = new Utils.BooleanHolder(false);
applyPreApplyBattlerTagAbAttrs(BattlerTagImmunityAbAttr, this, stubTag, cancelled, true);
const userField = this.getAlliedField();
userField.forEach(pokemon => applyPreApplyBattlerTagAbAttrs(UserFieldBattlerTagImmunityAbAttr, pokemon, stubTag, cancelled, true));
return !cancelled.value;
}
addTag(tagType: BattlerTagType, turnCount: integer = 0, sourceMove?: Moves, sourceId?: integer): boolean {
const existingTag = this.getTag(tagType);
if (existingTag) {
@ -2715,7 +2749,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
// Check if the source Pokemon has an ability that cancels the Poison/Toxic immunity
const cancelImmunity = new Utils.BooleanHolder(false);
if (sourcePokemon) {
applyAbAttrs(IgnoreTypeStatusEffectImmunityAbAttr, sourcePokemon, cancelImmunity, effect, defType);
applyAbAttrs(IgnoreTypeStatusEffectImmunityAbAttr, sourcePokemon, cancelImmunity, false, effect, defType);
if (cancelImmunity.value) {
return false;
}
@ -2787,7 +2821,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (effect === StatusEffect.SLEEP) {
statusCureTurn = new Utils.IntegerHolder(this.randSeedIntRange(2, 4));
applyAbAttrs(ReduceStatusEffectDurationAbAttr, this, null, effect, statusCureTurn);
applyAbAttrs(ReduceStatusEffectDurationAbAttr, this, null, false, effect, statusCureTurn);
this.setFrameRate(4);
@ -3223,14 +3257,18 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* Causes a Pokemon to leave the field (such as in preparation for a switch out/escape).
* @param clearEffects Indicates if effects should be cleared (true) or passed
* to the next pokemon, such as during a baton pass (false)
* @param hideInfo Indicates if this should also play the animation to hide the Pokemon's
* info container.
*/
leaveField(clearEffects: boolean = true) {
leaveField(clearEffects: boolean = true, hideInfo: boolean = true) {
this.resetTurnData();
if (clearEffects) {
this.resetSummonData();
this.resetBattleData();
}
if (hideInfo) {
this.hideInfo();
}
this.setVisible(false);
this.scene.field.remove(this);
this.scene.triggerPokemonFormChange(this, SpeciesFormChangeActiveTrigger, true);
@ -3417,8 +3455,8 @@ export class PlayerPokemon extends Pokemon {
pokemon.resetTurnData();
pokemon.resetStatus();
pokemon.heal(Math.min(Math.max(Math.ceil(Math.floor(0.5 * pokemon.getMaxHp())), 1), pokemon.getMaxHp()));
this.scene.queueMessage(`${pokemon.name} was revived!`,0,true);
pokemon.heal(Math.min(Utils.toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp()));
this.scene.queueMessage(i18next.t("moveTriggers:revivalBlessing", {pokemonName: pokemon.name}),0,true);
if (this.scene.currentBattle.double && this.scene.getParty().length > 1) {
const allyPokemon = this.getAlly();
@ -3780,7 +3818,7 @@ export class EnemyPokemon extends Pokemon {
this.moveset = (formIndex !== undefined ? formIndex : this.formIndex)
? [
new PokemonMove(Moves.DYNAMAX_CANNON),
new PokemonMove(Moves.CROSS_POISON),
new PokemonMove(Moves.SLUDGE_BOMB),
new PokemonMove(Moves.FLAMETHROWER),
new PokemonMove(Moves.RECOVER, 0, -4)
]
@ -4344,7 +4382,7 @@ export class PokemonMove {
}
getMovePp(): integer {
return this.getMove().pp + this.ppUp * Math.max(Math.floor(this.getMove().pp / 5), 1);
return this.getMove().pp + this.ppUp * Utils.toDmgValue(this.getMove().pp / 5);
}
getPpRatio(): number {

View File

@ -62,7 +62,7 @@ export class GameMode implements GameModeConfig {
* @returns true if the game mode has that challenge
*/
hasChallenge(challenge: Challenges): boolean {
return this.challenges.some(c => c.id === challenge);
return this.challenges.some(c => c.id === challenge && c.value !== 0);
}
/**

View File

@ -47,6 +47,7 @@ export const abilityTriggers: SimpleTranslationEntries = {
"postFaintContactDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!",
"postFaintHpDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!",
"postSummonPressure": "{{pokemonNameWithAffix}} is exerting its Pressure!",
"weatherEffectDisappeared": "The effects of the weather disappeared.",
"postSummonMoldBreaker": "{{pokemonNameWithAffix}} breaks the mold!",
"postSummonAnticipation": "{{pokemonNameWithAffix}} shuddered!",
"postSummonTurboblaze": "{{pokemonNameWithAffix}} is radiating a blazing aura!",

View File

@ -0,0 +1,5 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const battleScene: SimpleTranslationEntries = {
"moneyOwned": "₽{{formattedMoney}}"
} as const;

View File

@ -24,6 +24,7 @@ export const battle: SimpleTranslationEntries = {
"hitResultSuperEffective": "It's super effective!",
"hitResultNotVeryEffective": "It's not very effective…",
"hitResultNoEffect": "It doesn't affect {{pokemonName}}!",
"hitResultImmune": "{{pokemonName}} is unaffected!",
"hitResultOneHitKO": "It's a one-hit KO!",
"attackFailed": "But it failed!",
"attackMissed": "{{pokemonNameWithAffix}} avoided the attack!",

View File

@ -6,6 +6,7 @@ import { arenaFlyout } from "./arena-flyout";
import { arenaTag } from "./arena-tag";
import { PGFachv, PGMachv } from "./achv";
import { battle } from "./battle";
import { battleScene } from "./battle-scene";
import { battleInfo } from "./battle-info";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { battlerTags } from "./battler-tags";
@ -60,6 +61,7 @@ export const caESConfig = {
arenaFlyout: arenaFlyout,
arenaTag: arenaTag,
battle: battle,
battleScene: battleScene,
battleInfo: battleInfo,
battleMessageUiHandler: battleMessageUiHandler,
battlePokemonForm: battlePokemonForm,

View File

@ -2573,8 +2573,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: `@c{shock}Wow… You cleaned me out.\nAre you actually a beginner?
$@c{smile}Maybe it was a bit of luck but\nWho knows you might just be able to go all the way.
$By the way, the professor asked me to give you these items. They look pretty cool.
$@c{serious_smile_fists}Good luck out there!
$@c{smile}Oh- and I hope you enjoy the event!`
$@c{serious_smile_fists}Good luck out there!`
},
},
"rival_female": {
@ -2588,8 +2587,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: `@c{shock}You just started and you're already this strong?!@d{96}\n@c{angry}You totally cheated, didn't you?
$@c{smile_wave_wink}Just kidding!@d{64} @c{smile_eclosed}I lost fair and square I have a feeling you're going to do really well out there.
$@c{smile}By the way, the professor wanted me to give you some items. Hopefully they're helpful!
$@c{smile_wave}Do your best like always! I believe in you!
$@c{smile}Oh- and I hope you enjoy the event!`
$@c{smile_wave}Do your best like always! I believe in you!`
},
},
"rival_2": {
@ -2605,7 +2603,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
$@c{smile}That's alright, though. I figured this might happen.\n@c{serious_mopen_fists}It just means I need to try harder for next time!\n
$@c{smile}Oh, not that you really need the help, but I had an extra one of these lying around and figured you might want it.\n
$@c{serious_smile_fists}Don't expect another one after this, though!\nI can't keep giving my opponent an advantage after all.
$@c{smile}Anyway, take care, and enjoy the event!`
$@c{smile}Anyway, take care!`
},
},
"rival_2_female": {
@ -2621,7 +2619,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
$@c{smile}Aw well. That just means I'll have to train even harder for next time!
$@c{smile_wave}I also got you another one of these!\n@c{smile_wave_wink}No need to thank me~.
$@c{angry_mopen}This is the last one, though! You won't be getting anymore freebies from me after this!
$@c{smile_wave}Keep at it, and enjoy the event!`
$@c{smile_wave}Keep at it!`
},
"defeat": {
1: "It's OK to lose sometimes…"

View File

@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"faintCountdown": "{{pokemonName}}\nwill faint in {{turnCount}} turns.",
"copyType": "{{pokemonName}}'s type became the same as\n{{targetPokemonName}}'s type!",
"suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!",
"revivalBlessing": "{{pokemonName}} was revived!",
"swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!",
"exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!",
} as const;

View File

@ -96,5 +96,10 @@ export const settings: SimpleTranslationEntries = {
"controller": "Controller",
"gamepadSupport": "Gamepad Support",
"showBgmBar": "Show Music Names",
"shopOverlayOpacity": "Shop Overlay Opacity"
"shopOverlayOpacity": "Shop Overlay Opacity",
"shopCursorTarget": "Shop Cursor Target",
"items": "Items",
"reroll": "Reroll",
"shop": "Shop",
"checkTeam": "Check Team"
} as const;

View File

@ -46,6 +46,7 @@ export const abilityTriggers: SimpleTranslationEntries = {
"postFaintContactDamage": "{{abilityName}} von {{pokemonNameWithAffix}} schadet seinem Angreifer!",
"postFaintHpDamage": "{{abilityName}} von {{pokemonNameWithAffix}} schadet seinem Angreifer!",
"postSummonPressure": "{{pokemonNameWithAffix}} setzt Gegner mit Erzwinger unter Druck!",
"weatherEffectDisappeared": "Jegliche wetterbedingten Effekte wurden aufgehoben!",
"postSummonMoldBreaker": "{{pokemonNameWithAffix}} gelingt es, gegnerische Fähigkeiten zu überbrücken!",
"postSummonAnticipation": "{{pokemonNameWithAffix}} erschaudert!",
"postSummonTurboblaze": "{{pokemonNameWithAffix}} strahlt eine lodernde Aura aus!",

View File

@ -0,0 +1,6 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const battleScene: SimpleTranslationEntries = {
"moneyOwned": "{{formattedMoney}} ₽"
} as const;

View File

@ -24,6 +24,7 @@ export const battle: SimpleTranslationEntries = {
"hitResultSuperEffective": "Das ist sehr effektiv!",
"hitResultNotVeryEffective": "Das ist nicht sehr effektiv…",
"hitResultNoEffect": "Es hat keine Wirkung auf {{pokemonName}}…",
"hitResultImmune": "{{pokemonName}} ist unversehrt!",
"hitResultOneHitKO": "Ein K.O.-Treffer!",
"attackFailed": "Es ist fehlgeschlagen!",
"attackMissed": "Die Attacke hat {{pokemonNameWithAffix}} verfehlt!",

View File

@ -69,5 +69,5 @@ export const battlerTags: SimpleTranslationEntries = {
"saltCuredLapse": "{{pokemonNameWithAffix}} wurde durch {{moveName}} verletzt!",
"cursedOnAdd": "{{pokemonNameWithAffix}} nimmt einen Teil seiner KP und legt einen Fluch auf {{pokemonName}}!",
"cursedLapse": "{{pokemonNameWithAffix}} wurde durch den Fluch verletzt!",
"stockpilingOnAdd": "{{pokemonNameWithAffix}} stockpiled {{stockpiledCount}}!",
"stockpilingOnAdd": "{{pokemonNameWithAffix}} hortet {{stockpiledCount}}!",
} as const;

View File

@ -4,6 +4,7 @@ import { arenaFlyout } from "./arena-flyout";
import { arenaTag } from "./arena-tag";
import { PGFachv, PGMachv } from "./achv";
import { battle } from "./battle";
import { battleScene } from "./battle-scene";
import { battleInfo } from "./battle-info";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { battlerTags } from "./battler-tags";
@ -60,6 +61,7 @@ export const deConfig = {
arenaFlyout: arenaFlyout,
arenaTag: arenaTag,
battle: battle,
battleScene: battleScene,
battleInfo: battleInfo,
battleMessageUiHandler: battleMessageUiHandler,
battlePokemonForm: battlePokemonForm,

View File

@ -2641,8 +2641,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
$@c{smile}Vielleicht war es einfach etwas Glück, aber\nWer weiß, vielleicht schaffst du es irgendwann
$ja wirklich ganz groß raus zu kommen.
$Übrigens, der Professor hat mich gebeten dir diese Items zu geben. Die sehen wirklich cool aus.
$@c{serious_smile_fists}Viel Glück da draußen!
$@c{smile}Oh-und genieße das Event!`
$@c{serious_smile_fists}Viel Glück da draußen!`
},
},
"rival_female": {
@ -2657,8 +2656,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: `@c{shock}Du hast gerade erst angefangen und bist schon so stark?!@d{96} @c{angry}Du hast sowas von betrogen, oder?
$@c{smile_wave_wink}Ich mach nur Spaß!@d{64} @c{smile_eclosed}Ich habe ehrlich verloren Ich habe das Gefühl, dass du es dort draußen weit bringen wirst.
$@c{smile}Übrigens, der Professor hat mich gebeten dir diese Items zu geben. Ich hoffe sie sind hilfreich!
$@c{smile_wave}Gib wie immer dein Bestes! Ich glaube an dich!
$@c{smile}Oh-und genieße das Event!`
$@c{smile_wave}Gib wie immer dein Bestes! Ich glaube an dich!`
},
},
"rival_2": {
@ -2676,7 +2674,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
$@c{smile}Nicht, dass du wirklich Hilfe benötigen würdest, aber ich habe hier noch eins von diesen Dingern herumliegen.
$Du kannst es haben.\n
$@c{serious_smile_fists}Erwarte aber nicht, dass ich dir noch mehr gebe!\nIch kann meinen Rivalen doch keine Vorteile verschaffen.
$@c{smile}Egal, pass auf dich auf und genieße das Event!`
$@c{smile}Egal, pass auf dich auf!`
},
},
"rival_2_female": {
@ -2692,7 +2690,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
$@c{smile}Na gut. Das bedeutet ich muss noch härter tranieren!
$@c{smile_wave}Ich habe noch eins von diesen Dingern!\n@c{smile_wave_wink}Kein Grund mir zu danken~.
$@c{angry_mopen}Das ist aber das Letzte! Du bekommst ab jett keine Geschenke mehr von mir!
$@c{smile_wave}Bleib stark und genieße das Event!`
$@c{smile_wave}Bleib stark!`
},
"defeat": {
1: "Es ist Ok manchmal zu verlieren…"

View File

@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"faintCountdown": "{{pokemonName}} geht nach {{turnCount}} Runden K.O.!",
"copyType": "{{pokemonName}} hat den Typ von {{targetPokemonName}} angenommen!",
"suppressAbilities": "Die Fähigkeit von {{pokemonName}} wirkt nicht mehr!",
"revivalBlessing": "{{pokemonName}} ist wieder fit und kampfbereit!",
"swapArenaTags": "{{pokemonName}} hat die Effekte, die auf den beiden Seiten des Kampffeldes wirken, miteinander getauscht!",
"trickOnSwap": "{{pokemonNameWithAffix}} tauscht Items mit dem Ziel!",
"trickFoeNewItem": "{{pokemonNameWithAffix}} erhält {{itemName}}.",

View File

@ -99,4 +99,9 @@ export const settings: SimpleTranslationEntries = {
"showBgmBar": "Musiknamen anzeigen",
"moveTouchControls": "Bewegung Touch Steuerung",
"shopOverlayOpacity": "Shop Overlay Deckkraft",
"shopCursorTarget": "Shop Cursor Target",
"items": "Items",
"reroll": "Reroll",
"shop": "Shop",
"checkTeam": "Check Team"
} as const;

View File

@ -7,7 +7,7 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales";
*/
export const starterSelectUiHandler: SimpleTranslationEntries = {
"confirmStartTeam": "Mit diesen Pokémon losziehen?",
"confirmExit": "Do you want to exit?",
"confirmExit": "Willst du zurück?",
"invalidParty": "Das ist kein gültiges Team!",
"gen1": "I",
"gen2": "II",
@ -28,8 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"toggleIVs": "DVs anzeigen/verbergen",
"manageMoves": "Attacken ändern",
"manageNature": "Wesen ändern",
"addToFavorites": "Add to Favorites",
"removeFromFavorites": "Remove from Favorites",
"addToFavorites": "Zu Favoriten hinzufügen",
"removeFromFavorites": "Von Favoriten entfernen",
"useCandies": "Bonbons verwenden",
"selectNature": "Wähle das neue Wesen.",
"selectMoveSwapOut": "Wähle die zu ersetzende Attacke.",

View File

@ -46,6 +46,7 @@ export const abilityTriggers: SimpleTranslationEntries = {
"postFaintContactDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!",
"postFaintHpDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!",
"postSummonPressure": "{{pokemonNameWithAffix}} is exerting its Pressure!",
"weatherEffectDisappeared": "The effects of the weather disappeared.",
"postSummonMoldBreaker": "{{pokemonNameWithAffix}} breaks the mold!",
"postSummonAnticipation": "{{pokemonNameWithAffix}} shuddered!",
"postSummonTurboblaze": "{{pokemonNameWithAffix}} is radiating a blazing aura!",

View File

@ -0,0 +1,5 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const battleScene: SimpleTranslationEntries = {
"moneyOwned": "₽{{formattedMoney}}"
} as const;

View File

@ -24,6 +24,7 @@ export const battle: SimpleTranslationEntries = {
"hitResultSuperEffective": "It's super effective!",
"hitResultNotVeryEffective": "It's not very effective…",
"hitResultNoEffect": "It doesn't affect {{pokemonName}}!",
"hitResultImmune": "{{pokemonName}} is unaffected!",
"hitResultOneHitKO": "It's a one-hit KO!",
"attackFailed": "But it failed!",
"attackMissed": "{{pokemonNameWithAffix}} avoided the attack!",

View File

@ -6,6 +6,7 @@ import { arenaFlyout } from "./arena-flyout";
import { arenaTag } from "./arena-tag";
import { PGFachv, PGMachv } from "./achv";
import { battle } from "./battle";
import { battleScene } from "./battle-scene";
import { battleInfo } from "./battle-info";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { battlerTags } from "./battler-tags";
@ -60,6 +61,7 @@ export const enConfig = {
arenaFlyout: arenaFlyout,
arenaTag: arenaTag,
battle: battle,
battleScene: battleScene,
battleInfo: battleInfo,
battleMessageUiHandler: battleMessageUiHandler,
battlePokemonForm: battlePokemonForm,

View File

@ -2574,8 +2574,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: `@c{shock}Wow… You cleaned me out.\nAre you actually a beginner?
$@c{smile}Maybe it was a bit of luck but\nWho knows you might just be able to go all the way.
$By the way, the professor asked me to give you these items. They look pretty cool.
$@c{serious_smile_fists}Good luck out there!
$@c{smile}Oh- and I hope you enjoy the event!`
$@c{serious_smile_fists}Good luck out there!`
},
},
"rival_female": {
@ -2589,8 +2588,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: `@c{shock}You just started and you're already this strong?!@d{96}\n@c{angry}You totally cheated, didn't you?
$@c{smile_wave_wink}Just kidding!@d{64} @c{smile_eclosed}I lost fair and square I have a feeling you're going to do really well out there.
$@c{smile}By the way, the professor wanted me to give you some items. Hopefully they're helpful!
$@c{smile_wave}Do your best like always! I believe in you!
$@c{smile}Oh- and I hope you enjoy the event!`
$@c{smile_wave}Do your best like always! I believe in you!`
},
},
"rival_2": {
@ -2604,9 +2602,9 @@ export const PGMdialogue: DialogueTranslationEntries = {
"victory": {
1: `@c{neutral_eclosed}Oh. I guess I was overconfident.
$@c{smile}That's alright, though. I figured this might happen.\n@c{serious_mopen_fists}It just means I need to try harder for next time!\n
$@c{smile}Oh, not that you really need the help, but I had an extra one of each of these lying around and figured you might want them.\n
$@c{smile}Oh, not that you really need the help, but I had an extra one of these lying around and figured you might want it.\n
$@c{serious_smile_fists}Don't expect another one after this, though!\nI can't keep giving my opponent an advantage after all.
$@c{smile}Anyway, take care, and enjoy the event!`
$@c{smile}Anyway, take care!`
},
},
"rival_2_female": {
@ -2620,9 +2618,9 @@ export const PGMdialogue: DialogueTranslationEntries = {
"victory": {
1: `@c{neutral}I… wasn't supposed to lose that time…
$@c{smile}Aw well. That just means I'll have to train even harder for next time!
$@c{smile_wave}I also got you another two of these!\n@c{smile_wave_wink}No need to thank me~.
$@c{smile_wave}I also got you another one of these!\n@c{smile_wave_wink}No need to thank me~.
$@c{angry_mopen}This is the last one, though! You won't be getting anymore freebies from me after this!
$@c{smile_wave}Keep at it, and enjoy the event!`
$@c{smile_wave}Keep at it!`
},
"defeat": {
1: "It's OK to lose sometimes…"

View File

@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"faintCountdown": "{{pokemonName}}\nwill faint in {{turnCount}} turns.",
"copyType": "{{pokemonName}}'s type became the same as\n{{targetPokemonName}}'s type!",
"suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!",
"revivalBlessing": "{{pokemonName}} was revived!",
"swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!",
"trickOnSwap": "{{pokemonNameWithAffix}} switched items with its target!",
"trickFoeNewItem": "{{pokemonNameWithAffix}} obtained one {{itemName}}.",

View File

@ -98,5 +98,10 @@ export const settings: SimpleTranslationEntries = {
"gamepadSupport": "Gamepad Support",
"showBgmBar": "Show Music Names",
"moveTouchControls": "Move Touch Controls",
"shopOverlayOpacity": "Shop Overlay Opacity"
"shopOverlayOpacity": "Shop Overlay Opacity",
"shopCursorTarget": "Shop Cursor Target",
"items": "Items",
"reroll": "Reroll",
"shop": "Shop",
"checkTeam": "Check Team"
} as const;

View File

@ -46,6 +46,7 @@ export const abilityTriggers: SimpleTranslationEntries = {
"postFaintContactDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!",
"postFaintHpDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!",
"postSummonPressure": "{{pokemonNameWithAffix}} is exerting its Pressure!",
"weatherEffectDisappeared": "El tiempo atmosférico ya no ejerce ninguna influencia.",
"postSummonMoldBreaker": "{{pokemonNameWithAffix}} breaks the mold!",
"postSummonAnticipation": "{{pokemonNameWithAffix}} shuddered!",
"postSummonTurboblaze": "{{pokemonNameWithAffix}} is radiating a blazing aura!",

View File

@ -0,0 +1,5 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const battleScene: SimpleTranslationEntries = {
"moneyOwned": "{{formattedMoney}} ₽"
} as const;

View File

@ -24,6 +24,7 @@ export const battle: SimpleTranslationEntries = {
"hitResultSuperEffective": "¡Es supereficaz!",
"hitResultNotVeryEffective": "No es muy eficaz…",
"hitResultNoEffect": "No afecta a {{pokemonName}}!",
"hitResultImmune": "¡No afecta a {{pokemonName}}!",
"hitResultOneHitKO": "¡KO en 1 golpe!",
"attackFailed": "¡Pero ha fallado!",
"attackMissed": "¡{{pokemonNameWithAffix}}\nha evitado el ataque!",

View File

@ -4,6 +4,7 @@ import { arenaFlyout } from "./arena-flyout";
import { arenaTag } from "./arena-tag";
import { PGFachv, PGMachv } from "./achv";
import { battle } from "./battle";
import { battleScene } from "./battle-scene";
import { battleInfo } from "./battle-info";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { battlerTags } from "./battler-tags";
@ -60,6 +61,7 @@ export const esConfig = {
arenaFlyout: arenaFlyout,
arenaTag: arenaTag,
battle: battle,
battleScene: battleScene,
battleInfo: battleInfo,
battleMessageUiHandler: battleMessageUiHandler,
battlePokemonForm: battlePokemonForm,

View File

@ -2569,8 +2569,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: `@c{shock}Wow… You cleaned me out.\nAre you actually a beginner?
$@c{smile}Maybe it was a bit of luck but\nWho knows you might just be able to go all the way.
$By the way, the professor asked me to give you these items. They look pretty cool.
$@c{serious_smile_fists}Good luck out there!
$@c{smile}Oh- and I hope you enjoy the event!`
$@c{serious_smile_fists}Good luck out there!`
},
},
"rival_female": {
@ -2584,8 +2583,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: `@c{shock}You just started and you're already this strong?!@d{96}\n@c{angry}You totally cheated, didn't you?
$@c{smile_wave_wink}Just kidding!@d{64} @c{smile_eclosed}I lost fair and square I have a feeling you're going to do really well out there.
$@c{smile}By the way, the professor wanted me to give you some items. Hopefully they're helpful!
$@c{smile_wave}Do your best like always! I believe in you!
$@c{smile}Oh- and I hope you enjoy the event!`
$@c{smile_wave}Do your best like always! I believe in you!`
},
},
"rival_2": {
@ -2601,7 +2599,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
$@c{smile}That's alright, though. I figured this might happen.\n@c{serious_mopen_fists}It just means I need to try harder for next time!\n
$@c{smile}Oh, not that you really need the help, but I had an extra one of these lying around and figured you might want it.\n
$@c{serious_smile_fists}Don't expect another one after this, though!\nI can't keep giving my opponent an advantage after all.
$@c{smile}Anyway, take care, and enjoy the event!`
$@c{smile}Anyway, take care!`
},
},
"rival_2_female": {
@ -2617,7 +2615,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
$@c{smile}Aw well. That just means I'll have to train even harder for next time!
$@c{smile_wave}I also got you another one of these!\n@c{smile_wave_wink}No need to thank me~.
$@c{angry_mopen}This is the last one, though! You won't be getting anymore freebies from me after this!
$@c{smile_wave}Keep at it, and enjoy the event!`
$@c{smile_wave}Keep at it!`
},
"defeat": {
1: "It's OK to lose sometimes…"

View File

@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"faintCountdown": "{{pokemonName}}\nwill faint in {{turnCount}} turns.",
"copyType": "{{pokemonName}}'s type\nchanged to match {{targetPokemonName}}'s!",
"suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!",
"revivalBlessing": "¡{{pokemonName}} ha revivido!",
"swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!",
"trickOnSwap": "{{pokemonNameWithAffix}} switched items with its target!",
"trickFoeNewItem": "{{pokemonNameWithAffix}} obtained one {{itemName}}.",

View File

@ -98,5 +98,10 @@ export const settings: SimpleTranslationEntries = {
"gamepadSupport": "Gamepad Support",
"showBgmBar": "Show Music Names",
"moveTouchControls": "Move Touch Controls",
"shopOverlayOpacity": "Opacidad de la fase de compra"
"shopOverlayOpacity": "Opacidad de la fase de compra",
"shopCursorTarget": "Shop Cursor Target",
"items": "Items",
"reroll": "Reroll",
"shop": "Shop",
"checkTeam": "Check Team"
} as const;

View File

@ -46,6 +46,7 @@ export const abilityTriggers: SimpleTranslationEntries = {
"postFaintContactDamage": "{{pokemonNameWithAffix}} est blessé\npar son talent {{abilityName}} !",
"postFaintHpDamage": "{{pokemonNameWithAffix}} est blessé\npar son talent {{abilityName}} !",
"postSummonPressure": "{{pokemonNameWithAffix}}\naugmente la pression !",
"weatherEffectDisappeared": "Les effets de la météo se dissipent !",
"postSummonMoldBreaker": "{{pokemonNameWithAffix}}\nbrise le moule !",
"postSummonAnticipation": "{{pokemonNameWithAffix}}\nest tout tremblant !",
"postSummonTurboblaze": "{{pokemonNameWithAffix}} dégage\nune aura de flammes incandescentes !",

View File

@ -0,0 +1,5 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const battleScene: SimpleTranslationEntries = {
"moneyOwned": "{{formattedMoney}} ₽"
} as const;

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