Revert "Update src/locales/ko/settings.ts"

This reverts commit 08c0b89f4caf7c33f49722200d7aeb20b79b0ba5.
This commit is contained in:
torranx 2024-08-22 23:23:52 +08:00
parent 4de3b784c6
commit a57d8777f2
237 changed files with 3067 additions and 3277 deletions

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

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

View File

@ -1102,7 +1102,7 @@ export default class BattleScene extends SceneBase {
} else if (trainerConfigs[trainerType].hasDouble) { } else if (trainerConfigs[trainerType].hasDouble) {
const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8); const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8);
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance); this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance)); playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance));
doubleTrainer = !Utils.randSeedInt(doubleChance.value); 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 // 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)) { if (trainerConfigs[trainerType].trainerTypeDouble && ![ TrainerType.TATE, TrainerType.LIZA ].includes(trainerType)) {
@ -1118,7 +1118,7 @@ export default class BattleScene extends SceneBase {
if (newBattleType === BattleType.WILD && !this.gameMode.isWaveFinal(newWaveIndex)) { if (newBattleType === BattleType.WILD && !this.gameMode.isWaveFinal(newWaveIndex)) {
const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8); const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8);
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance); this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance)); playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance));
newDouble = !Utils.randSeedInt(doubleChance.value); newDouble = !Utils.randSeedInt(doubleChance.value);
} else if (newBattleType === BattleType.TRAINER) { } else if (newBattleType === BattleType.TRAINER) {
newDouble = newTrainer?.variant === TrainerVariant.DOUBLE; newDouble = newTrainer?.variant === TrainerVariant.DOUBLE;
@ -1520,7 +1520,7 @@ export default class BattleScene extends SceneBase {
return; return;
} }
const formattedMoney = Utils.formatMoney(this.moneyFormat, this.money); const formattedMoney = Utils.formatMoney(this.moneyFormat, this.money);
this.moneyText.setText(i18next.t("battleScene:moneyOwned", { formattedMoney })); this.moneyText.setText(`${formattedMoney}`);
this.fieldUI.moveAbove(this.moneyText, this.luckText); this.fieldUI.moveAbove(this.moneyText, this.luckText);
if (forceVisible) { if (forceVisible) {
this.moneyText.setVisible(true); this.moneyText.setVisible(true);
@ -2138,7 +2138,7 @@ export default class BattleScene extends SceneBase {
pushMovePhase(movePhase: MovePhase, priorityOverride?: integer): void { pushMovePhase(movePhase: MovePhase, priorityOverride?: integer): void {
const movePriority = new Utils.IntegerHolder(priorityOverride !== undefined ? priorityOverride : movePhase.move.getMove().priority); const movePriority = new Utils.IntegerHolder(priorityOverride !== undefined ? priorityOverride : movePhase.move.getMove().priority);
applyAbAttrs(ChangeMovePriorityAbAttr, movePhase.pokemon, null, false, movePhase.move.getMove(), movePriority); applyAbAttrs(ChangeMovePriorityAbAttr, movePhase.pokemon, null, movePhase.move.getMove(), movePriority);
const lowerPriorityPhase = this.phaseQueue.find(p => p instanceof MovePhase && p.move.getMove().priority < movePriority.value); const lowerPriorityPhase = this.phaseQueue.find(p => p instanceof MovePhase && p.move.getMove().priority < movePriority.value);
if (lowerPriorityPhase) { if (lowerPriorityPhase) {
this.phaseQueue.splice(this.phaseQueue.indexOf(lowerPriorityPhase), 0, movePhase); this.phaseQueue.splice(this.phaseQueue.indexOf(lowerPriorityPhase), 0, movePhase);

File diff suppressed because it is too large Load Diff

View File

@ -269,7 +269,7 @@ const QuickGuardConditionFunc: ProtectConditionFunc = (arena, moveId) => {
if (effectPhase instanceof MoveEffectPhase) { if (effectPhase instanceof MoveEffectPhase) {
const attacker = effectPhase.getUserPokemon()!; const attacker = effectPhase.getUserPokemon()!;
applyMoveAttrs(IncrementMovePriorityAttr, attacker, null, move, priority); applyMoveAttrs(IncrementMovePriorityAttr, attacker, null, move, priority);
applyAbAttrs(ChangeMovePriorityAbAttr, attacker, null, false, move, priority); applyAbAttrs(ChangeMovePriorityAbAttr, attacker, null, move, priority);
} }
return priority.value > 0; return priority.value > 0;
}; };
@ -427,7 +427,7 @@ class WishTag extends ArenaTag {
if (user) { if (user) {
this.battlerIndex = user.getBattlerIndex(); this.battlerIndex = user.getBattlerIndex();
this.triggerMessage = i18next.t("arenaTag:wishTagOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(user) }); this.triggerMessage = i18next.t("arenaTag:wishTagOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(user) });
this.healHp = Utils.toDmgValue(user.getMaxHp() / 2); this.healHp = Math.max(Math.floor(user.getMaxHp() / 2), 1);
} else { } else {
console.warn("Failed to get source for WishTag onAdd"); console.warn("Failed to get source for WishTag onAdd");
} }
@ -585,7 +585,7 @@ class SpikesTag extends ArenaTrapTag {
if (!cancelled.value) { if (!cancelled.value) {
const damageHpRatio = 1 / (10 - 2 * this.layers); const damageHpRatio = 1 / (10 - 2 * this.layers);
const damage = Utils.toDmgValue(pokemon.getMaxHp() * damageHpRatio); const damage = Math.ceil(pokemon.getMaxHp() * damageHpRatio);
pokemon.scene.queueMessage(i18next.t("arenaTag:spikesActivateTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); pokemon.scene.queueMessage(i18next.t("arenaTag:spikesActivateTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
pokemon.damageAndUpdate(damage, HitResult.OTHER); pokemon.damageAndUpdate(damage, HitResult.OTHER);
@ -745,7 +745,7 @@ class StealthRockTag extends ArenaTrapTag {
const damageHpRatio = this.getDamageHpRatio(pokemon); const damageHpRatio = this.getDamageHpRatio(pokemon);
if (damageHpRatio) { if (damageHpRatio) {
const damage = Utils.toDmgValue(pokemon.getMaxHp() * damageHpRatio); const damage = Math.ceil(pokemon.getMaxHp() * damageHpRatio);
pokemon.scene.queueMessage(i18next.t("arenaTag:stealthRockActivateTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); pokemon.scene.queueMessage(i18next.t("arenaTag:stealthRockActivateTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
pokemon.damageAndUpdate(damage, HitResult.OTHER); pokemon.damageAndUpdate(damage, HitResult.OTHER);
if (pokemon.turnData) { if (pokemon.turnData) {

View File

@ -347,7 +347,7 @@ export class ConfusedTag extends BattlerTag {
if (pokemon.randSeedInt(3) === 0) { if (pokemon.randSeedInt(3) === 0) {
const atk = pokemon.getBattleStat(Stat.ATK); const atk = pokemon.getBattleStat(Stat.ATK);
const def = pokemon.getBattleStat(Stat.DEF); const def = pokemon.getBattleStat(Stat.DEF);
const damage = Utils.toDmgValue(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100)); const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100));
pokemon.scene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself")); pokemon.scene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself"));
pokemon.damageAndUpdate(damage); pokemon.damageAndUpdate(damage);
pokemon.battleData.hitCount++; pokemon.battleData.hitCount++;
@ -524,7 +524,7 @@ export class SeedTag extends BattlerTag {
if (!cancelled.value) { if (!cancelled.value) {
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED)); pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED));
const damage = pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / 8)); const damage = pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 8), 1));
const reverseDrain = pokemon.hasAbilityWithAttr(ReverseDrainAbAttr, false); const reverseDrain = pokemon.hasAbilityWithAttr(ReverseDrainAbAttr, false);
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, source.getBattlerIndex(), pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, source.getBattlerIndex(),
!reverseDrain ? damage : damage * -1, !reverseDrain ? damage : damage * -1,
@ -570,7 +570,7 @@ export class NightmareTag extends BattlerTag {
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
if (!cancelled.value) { if (!cancelled.value) {
pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / 4)); pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / 4));
} }
} }
@ -714,7 +714,7 @@ export class IngrainTag extends TrappedTag {
new PokemonHealPhase( new PokemonHealPhase(
pokemon.scene, pokemon.scene,
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
Utils.toDmgValue(pokemon.getMaxHp() / 16), Math.floor(pokemon.getMaxHp() / 16),
i18next.t("battlerTags:ingrainLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), i18next.t("battlerTags:ingrainLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }),
true true
) )
@ -777,7 +777,7 @@ export class AquaRingTag extends BattlerTag {
new PokemonHealPhase( new PokemonHealPhase(
pokemon.scene, pokemon.scene,
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
Utils.toDmgValue(pokemon.getMaxHp() / 16), Math.floor(pokemon.getMaxHp() / 16),
i18next.t("battlerTags:aquaRingLapse", { i18next.t("battlerTags:aquaRingLapse", {
moveName: this.getMoveName(), moveName: this.getMoveName(),
pokemonName: getPokemonNameWithAffix(pokemon) pokemonName: getPokemonNameWithAffix(pokemon)
@ -883,7 +883,7 @@ export abstract class DamagingTrapTag extends TrappedTag {
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
if (!cancelled.value) { if (!cancelled.value) {
pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / 8)); pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / 8));
} }
} }
@ -1067,7 +1067,7 @@ export class ContactDamageProtectedTag extends ProtectedTag {
if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) { if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) {
const attacker = effectPhase.getPokemon(); const attacker = effectPhase.getPokemon();
if (!attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { if (!attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) {
attacker.damageAndUpdate(Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); attacker.damageAndUpdate(Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER);
} }
} }
} }
@ -1541,7 +1541,7 @@ export class SaltCuredTag extends BattlerTag {
if (!cancelled.value) { if (!cancelled.value) {
const pokemonSteelOrWater = pokemon.isOfType(Type.STEEL) || pokemon.isOfType(Type.WATER); const pokemonSteelOrWater = pokemon.isOfType(Type.STEEL) || pokemon.isOfType(Type.WATER);
pokemon.damageAndUpdate(Utils.toDmgValue(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8)); pokemon.damageAndUpdate(Math.max(Math.floor(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8), 1));
pokemon.scene.queueMessage( pokemon.scene.queueMessage(
i18next.t("battlerTags:saltCuredLapse", { i18next.t("battlerTags:saltCuredLapse", {
@ -1587,7 +1587,7 @@ export class CursedTag extends BattlerTag {
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
if (!cancelled.value) { if (!cancelled.value) {
pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / 4)); pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 4), 1));
pokemon.scene.queueMessage(i18next.t("battlerTags:cursedLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); pokemon.scene.queueMessage(i18next.t("battlerTags:cursedLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
} }
} }

View File

@ -36,25 +36,25 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate {
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25); const threshold = new Utils.NumberHolder(0.25);
const battleStat = (berryType - BerryType.LIECHI) as BattleStat; const battleStat = (berryType - BerryType.LIECHI) as BattleStat;
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
return pokemon.getHpRatio() < threshold.value && pokemon.summonData.battleStats[battleStat] < 6; return pokemon.getHpRatio() < threshold.value && pokemon.summonData.battleStats[battleStat] < 6;
}; };
case BerryType.LANSAT: case BerryType.LANSAT:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25); const threshold = new Utils.NumberHolder(0.25);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
return pokemon.getHpRatio() < 0.25 && !pokemon.getTag(BattlerTagType.CRIT_BOOST); return pokemon.getHpRatio() < 0.25 && !pokemon.getTag(BattlerTagType.CRIT_BOOST);
}; };
case BerryType.STARF: case BerryType.STARF:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25); const threshold = new Utils.NumberHolder(0.25);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
return pokemon.getHpRatio() < 0.25; return pokemon.getHpRatio() < 0.25;
}; };
case BerryType.LEPPA: case BerryType.LEPPA:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25); const threshold = new Utils.NumberHolder(0.25);
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
return !!pokemon.getMoveset().find(m => !m?.getPpRatio()); return !!pokemon.getMoveset().find(m => !m?.getPpRatio());
}; };
} }
@ -70,8 +70,8 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
if (pokemon.battleData) { if (pokemon.battleData) {
pokemon.battleData.berriesEaten.push(berryType); pokemon.battleData.berriesEaten.push(berryType);
} }
const hpHealed = new Utils.NumberHolder(Utils.toDmgValue(pokemon.getMaxHp() / 4)); const hpHealed = new Utils.NumberHolder(Math.floor(pokemon.getMaxHp() / 4));
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, hpHealed); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, hpHealed);
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(),
hpHealed.value, i18next.t("battle:hpHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), berryName: getBerryName(berryType) }), true)); hpHealed.value, i18next.t("battle:hpHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), berryName: getBerryName(berryType) }), true));
}; };
@ -97,7 +97,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
} }
const battleStat = (berryType - BerryType.LIECHI) as BattleStat; const battleStat = (berryType - BerryType.LIECHI) as BattleStat;
const statLevels = new Utils.NumberHolder(1); const statLevels = new Utils.NumberHolder(1);
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statLevels); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, statLevels);
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ battleStat ], statLevels.value)); pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ battleStat ], statLevels.value));
}; };
case BerryType.LANSAT: case BerryType.LANSAT:
@ -113,7 +113,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
pokemon.battleData.berriesEaten.push(berryType); pokemon.battleData.berriesEaten.push(berryType);
} }
const statLevels = new Utils.NumberHolder(2); const statLevels = new Utils.NumberHolder(2);
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statLevels); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, statLevels);
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ BattleStat.RAND ], statLevels.value)); pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ BattleStat.RAND ], statLevels.value));
}; };
case BerryType.LEPPA: case BerryType.LEPPA:

View File

@ -590,7 +590,7 @@ export default class Move implements Localizable {
case MoveFlags.IGNORE_ABILITIES: case MoveFlags.IGNORE_ABILITIES:
if (user.hasAbilityWithAttr(MoveAbilityBypassAbAttr)) { if (user.hasAbilityWithAttr(MoveAbilityBypassAbAttr)) {
const abilityEffectsIgnored = new Utils.BooleanHolder(false); const abilityEffectsIgnored = new Utils.BooleanHolder(false);
applyAbAttrs(MoveAbilityBypassAbAttr, user, abilityEffectsIgnored, false, this); applyAbAttrs(MoveAbilityBypassAbAttr, user, abilityEffectsIgnored, this);
if (abilityEffectsIgnored.value) { if (abilityEffectsIgnored.value) {
return true; return true;
} }
@ -686,11 +686,11 @@ export default class Move implements Localizable {
* @param target {@linkcode Pokemon} The Pokémon being targeted by the move. * @param target {@linkcode Pokemon} The Pokémon being targeted by the move.
* @returns The calculated accuracy of the move. * @returns The calculated accuracy of the move.
*/ */
calculateBattleAccuracy(user: Pokemon, target: Pokemon, simulated: boolean = false) { calculateBattleAccuracy(user: Pokemon, target: Pokemon) {
const moveAccuracy = new Utils.NumberHolder(this.accuracy); const moveAccuracy = new Utils.NumberHolder(this.accuracy);
applyMoveAttrs(VariableAccuracyAttr, user, target, this, moveAccuracy); applyMoveAttrs(VariableAccuracyAttr, user, target, this, moveAccuracy);
applyPreDefendAbAttrs(WonderSkinAbAttr, target, user, this, { value: false }, simulated, moveAccuracy); applyPreDefendAbAttrs(WonderSkinAbAttr, target, user, this, { value: false }, moveAccuracy);
if (moveAccuracy.value === -1) { if (moveAccuracy.value === -1) {
return moveAccuracy.value; return moveAccuracy.value;
@ -724,7 +724,7 @@ export default class Move implements Localizable {
* @param target {@linkcode Pokemon} The Pokémon being targeted by the move. * @param target {@linkcode Pokemon} The Pokémon being targeted by the move.
* @returns The calculated power of the move. * @returns The calculated power of the move.
*/ */
calculateBattlePower(source: Pokemon, target: Pokemon, simulated: boolean = false): number { calculateBattlePower(source: Pokemon, target: Pokemon): number {
if (this.category === MoveCategory.STATUS) { if (this.category === MoveCategory.STATUS) {
return -1; return -1;
} }
@ -732,17 +732,17 @@ export default class Move implements Localizable {
const power = new Utils.NumberHolder(this.power); const power = new Utils.NumberHolder(this.power);
const typeChangeMovePowerMultiplier = new Utils.NumberHolder(1); const typeChangeMovePowerMultiplier = new Utils.NumberHolder(1);
applyPreAttackAbAttrs(MoveTypeChangeAttr, source, target, this, simulated, typeChangeMovePowerMultiplier); applyPreAttackAbAttrs(MoveTypeChangeAttr, source, target, this, typeChangeMovePowerMultiplier);
const sourceTeraType = source.getTeraType(); 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)) { 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; power.value = 60;
} }
applyPreAttackAbAttrs(VariableMovePowerAbAttr, source, target, this, simulated, power); applyPreAttackAbAttrs(VariableMovePowerAbAttr, source, target, this, power);
if (source.getAlly()) { if (source.getAlly()) {
applyPreAttackAbAttrs(AllyMoveCategoryPowerBoostAbAttr, source.getAlly(), target, this, simulated, power); applyPreAttackAbAttrs(AllyMoveCategoryPowerBoostAbAttr, source.getAlly(), target, this, power);
} }
const fieldAuras = new Set( const fieldAuras = new Set(
@ -752,11 +752,11 @@ export default class Move implements Localizable {
); );
for (const aura of fieldAuras) { for (const aura of fieldAuras) {
// The only relevant values are `move` and the `power` holder // The only relevant values are `move` and the `power` holder
aura.applyPreAttack(null, null, simulated, null, this, [power]); aura.applyPreAttack(null, null, null, this, [power]);
} }
const alliedField: Pokemon[] = source instanceof PlayerPokemon ? source.scene.getPlayerField() : source.scene.getEnemyField(); const alliedField: Pokemon[] = source instanceof PlayerPokemon ? source.scene.getPlayerField() : source.scene.getEnemyField();
alliedField.forEach(p => applyPreAttackAbAttrs(UserFieldMoveTypePowerBoostAbAttr, p, target, this, simulated, power)); alliedField.forEach(p => applyPreAttackAbAttrs(UserFieldMoveTypePowerBoostAbAttr, p, target, this, power));
power.value *= typeChangeMovePowerMultiplier.value; power.value *= typeChangeMovePowerMultiplier.value;
@ -984,9 +984,9 @@ export class MoveEffectAttr extends MoveAttr {
*/ */
getMoveChance(user: Pokemon, target: Pokemon, move: Move, selfEffect?: Boolean, showAbility?: Boolean): integer { getMoveChance(user: Pokemon, target: Pokemon, move: Move, selfEffect?: Boolean, showAbility?: Boolean): integer {
const moveChance = new Utils.NumberHolder(move.chance); const moveChance = new Utils.NumberHolder(move.chance);
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, false, moveChance, move, target, selfEffect, showAbility); applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, moveChance, move, target, selfEffect, showAbility);
if (!selfEffect) { if (!selfEffect) {
applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, target, user, null, null, false, moveChance); applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, target, user, null, null, moveChance);
} }
return moveChance.value; return moveChance.value;
} }
@ -1162,7 +1162,7 @@ export class TargetHalfHpDamageAttr extends FixedDamageAttr {
} }
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
(args[0] as Utils.IntegerHolder).value = Utils.toDmgValue(target.hp / 2); (args[0] as Utils.IntegerHolder).value = Math.max(Math.floor(target.hp / 2), 1);
return true; return true;
} }
@ -1208,7 +1208,7 @@ export class CounterDamageAttr extends FixedDamageAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { 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); 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 = Utils.toDmgValue(damage * this.multiplier); (args[0] as Utils.IntegerHolder).value = Math.floor(Math.max(damage * this.multiplier, 1));
return true; return true;
} }
@ -1234,7 +1234,7 @@ export class RandomLevelDamageAttr extends FixedDamageAttr {
} }
getDamage(user: Pokemon, target: Pokemon, move: Move): number { getDamage(user: Pokemon, target: Pokemon, move: Move): number {
return Utils.toDmgValue(user.level * (user.randSeedIntRange(50, 150) * 0.01)); return Math.max(Math.floor(user.level * (user.randSeedIntRange(50, 150) * 0.01)), 1);
} }
} }
@ -1293,9 +1293,8 @@ export class RecoilAttr extends MoveEffectAttr {
return false; return false;
} }
const damageValue = (!this.useHp ? user.turnData.damageDealt : user.getMaxHp()) * this.damageRatio; const recoilDamage = Math.max(Math.floor((!this.useHp ? user.turnData.damageDealt : user.getMaxHp()) * this.damageRatio),
const minValue = user.turnData.damageDealt ? 1 : 0; user.turnData.damageDealt ? 1 : 0);
const recoilDamage = Utils.toDmgValue(damageValue, minValue);
if (!recoilDamage) { if (!recoilDamage) {
return false; return false;
} }
@ -1416,7 +1415,7 @@ export class HalfSacrificialAttr extends MoveEffectAttr {
// Check to see if the Pokemon has an ability that blocks non-direct damage // Check to see if the Pokemon has an ability that blocks non-direct damage
applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled); applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled);
if (!cancelled.value) { if (!cancelled.value) {
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp()/2), HitResult.OTHER, false, true, true); user.damageAndUpdate(Math.ceil(user.getMaxHp()/2), HitResult.OTHER, false, true, true);
user.scene.queueMessage(i18next.t("moveTriggers:cutHpPowerUpMove", {pokemonName: getPokemonNameWithAffix(user)})); // Queue recoil message user.scene.queueMessage(i18next.t("moveTriggers:cutHpPowerUpMove", {pokemonName: getPokemonNameWithAffix(user)})); // Queue recoil message
} }
return true; return true;
@ -1467,7 +1466,7 @@ export class HealAttr extends MoveEffectAttr {
*/ */
addHealPhase(target: Pokemon, healRatio: number) { addHealPhase(target: Pokemon, healRatio: number) {
target.scene.unshiftPhase(new PokemonHealPhase(target.scene, target.getBattlerIndex(), target.scene.unshiftPhase(new PokemonHealPhase(target.scene, target.getBattlerIndex(),
Utils.toDmgValue(target.getMaxHp() * healRatio), i18next.t("moveTriggers:healHp", {pokemonName: getPokemonNameWithAffix(target)}), true, !this.showAnim)); Math.max(Math.floor(target.getMaxHp() * healRatio), 1), i18next.t("moveTriggers:healHp", {pokemonName: getPokemonNameWithAffix(target)}), true, !this.showAnim));
} }
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer { getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
@ -1751,7 +1750,7 @@ export class HitHealAttr extends MoveEffectAttr {
message = i18next.t("battle:drainMessage", {pokemonName: getPokemonNameWithAffix(target)}); message = i18next.t("battle:drainMessage", {pokemonName: getPokemonNameWithAffix(target)});
} else { } else {
// Default healing formula used by draining moves like Absorb, Draining Kiss, Bitter Blade, etc. // Default healing formula used by draining moves like Absorb, Draining Kiss, Bitter Blade, etc.
healAmount = Utils.toDmgValue(user.turnData.currDamageDealt * this.healRatio); healAmount = Math.max(Math.floor(user.turnData.currDamageDealt * this.healRatio), 1);
message = i18next.t("battle:regainHealth", {pokemonName: getPokemonNameWithAffix(user)}); message = i18next.t("battle:regainHealth", {pokemonName: getPokemonNameWithAffix(user)});
} }
if (reverseDrain) { if (reverseDrain) {
@ -1884,7 +1883,7 @@ export class MultiHitAttr extends MoveAttr {
{ {
const rand = user.randSeedInt(16); const rand = user.randSeedInt(16);
const hitValue = new Utils.IntegerHolder(rand); const hitValue = new Utils.IntegerHolder(rand);
applyAbAttrs(MaxMultiHitAbAttr, user, null, false, hitValue); applyAbAttrs(MaxMultiHitAbAttr, user, null, hitValue);
if (hitValue.value >= 10) { if (hitValue.value >= 10) {
return 2; return 2;
} else if (hitValue.value >= 4) { } else if (hitValue.value >= 4) {
@ -1955,7 +1954,7 @@ export class StatusEffectAttr extends MoveEffectAttr {
} }
if ((!pokemon.status || (pokemon.status.effect === this.effect && moveChance < 0)) if ((!pokemon.status || (pokemon.status.effect === this.effect && moveChance < 0))
&& pokemon.trySetStatus(this.effect, true, user, this.cureTurn)) { && pokemon.trySetStatus(this.effect, true, user, this.cureTurn)) {
applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, false, this.effect); applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, this.effect);
return true; return true;
} }
} }
@ -2711,7 +2710,7 @@ export class CutHpStatBoostAttr extends StatChangeAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> {
return new Promise<boolean>(resolve => { return new Promise<boolean>(resolve => {
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / this.cutRatio), HitResult.OTHER, false, true); user.damageAndUpdate(Math.floor(user.getMaxHp() / this.cutRatio), HitResult.OTHER, false, true);
user.updateInfo().then(() => { user.updateInfo().then(() => {
const ret = super.apply(user, target, move, args); const ret = super.apply(user, target, move, args);
if (this.messageCallback) { if (this.messageCallback) {
@ -3191,7 +3190,7 @@ export class CompareWeightPowerAttr extends VariablePowerAttr {
export class HpPowerAttr extends VariablePowerAttr { export class HpPowerAttr extends VariablePowerAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
(args[0] as Utils.NumberHolder).value = Utils.toDmgValue(150 * user.getHpRatio()); (args[0] as Utils.NumberHolder).value = Math.max(Math.floor(150 * user.getHpRatio()), 1);
return true; return true;
} }
@ -3219,7 +3218,7 @@ export class OpponentHighHpPowerAttr extends VariablePowerAttr {
* @returns true * @returns true
*/ */
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
(args[0] as Utils.NumberHolder).value = Utils.toDmgValue(this.maxBasePower * target.getHpRatio()); (args[0] as Utils.NumberHolder).value = Math.max(Math.floor(this.maxBasePower * target.getHpRatio()), 1);
return true; return true;
} }
@ -3413,7 +3412,7 @@ export class PresentPowerAttr extends VariablePowerAttr {
// If this move is multi-hit, disable all other hits // If this move is multi-hit, disable all other hits
user.stopMultiHit(); user.stopMultiHit();
target.scene.unshiftPhase(new PokemonHealPhase(target.scene, target.getBattlerIndex(), target.scene.unshiftPhase(new PokemonHealPhase(target.scene, target.getBattlerIndex(),
Utils.toDmgValue(target.getMaxHp() / 4), i18next.t("moveTriggers:regainedHealth", {pokemonName: getPokemonNameWithAffix(target)}), true)); Math.max(Math.floor(target.getMaxHp() / 4), 1), i18next.t("moveTriggers:regainedHealth", {pokemonName: getPokemonNameWithAffix(target)}), true));
} }
return true; return true;
@ -3785,30 +3784,6 @@ 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 * Change the move category to status when used on the ally
* @extends VariableMoveCategoryAttr * @extends VariableMoveCategoryAttr
@ -4062,28 +4037,6 @@ 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 { export class MatchUserTypeAttr extends VariableMoveTypeAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const userTypes = user.getTypes(true); const userTypes = user.getTypes(true);
@ -4233,9 +4186,9 @@ const crashDamageFunc = (user: Pokemon, move: Move) => {
return false; return false;
} }
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / 2), HitResult.OTHER, false, true); user.damageAndUpdate(Math.floor(user.getMaxHp() / 2), HitResult.OTHER, false, true);
user.scene.queueMessage(i18next.t("moveTriggers:keptGoingAndCrashed", {pokemonName: getPokemonNameWithAffix(user)})); user.scene.queueMessage(i18next.t("moveTriggers:keptGoingAndCrashed", {pokemonName: getPokemonNameWithAffix(user)}));
user.turnData.damageTaken += Utils.toDmgValue(user.getMaxHp() / 2); user.turnData.damageTaken += Math.floor(user.getMaxHp() / 2);
return true; return true;
}; };
@ -4485,39 +4438,6 @@ 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 { export class CurseAttr extends MoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move:Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move:Move, args: any[]): boolean {
@ -4945,7 +4865,7 @@ export class RevivalBlessingAttr extends MoveEffectAttr {
const pokemon = faintedPokemon[user.randSeedInt(faintedPokemon.length)]; const pokemon = faintedPokemon[user.randSeedInt(faintedPokemon.length)];
const slotIndex = user.scene.getEnemyParty().findIndex(p => pokemon.id === p.id); const slotIndex = user.scene.getEnemyParty().findIndex(p => pokemon.id === p.id);
pokemon.resetStatus(); pokemon.resetStatus();
pokemon.heal(Math.min(Utils.toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp())); 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); user.scene.queueMessage(`${getPokemonNameWithAffix(pokemon)} was revived!`,0,true);
if (user.scene.currentBattle.double && user.scene.getEnemyParty().length > 1) { if (user.scene.currentBattle.double && user.scene.getEnemyParty().length > 1) {
@ -8393,7 +8313,8 @@ export function initMoves() {
.attr(HighCritAttr) .attr(HighCritAttr)
.attr(BypassRedirectAttr), .attr(BypassRedirectAttr),
new AttackMove(Moves.JAW_LOCK, Type.DARK, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 8) new AttackMove(Moves.JAW_LOCK, Type.DARK, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 8)
.attr(JawLockAttr) .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1, 1, false, true)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, false, 1, 1, false, true)
.bitingMove(), .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 new SelfStatusMove(Moves.STUFF_CHEEKS, Type.NORMAL, -1, 10, -1, 0, 8) // TODO: Stuff Cheeks should not be selectable when the user does not have a berry, see wiki
.attr(EatBerryAttr) .attr(EatBerryAttr)
@ -8838,10 +8759,7 @@ export function initMoves() {
End Unused */ End Unused */
new AttackMove(Moves.TERA_BLAST, Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 9) new AttackMove(Moves.TERA_BLAST, Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 9)
.attr(TeraBlastCategoryAttr) .attr(TeraBlastCategoryAttr)
.attr(TeraBlastTypeAttr) .unimplemented(),
.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) new SelfStatusMove(Moves.SILK_TRAP, Type.BUG, -1, 10, -1, 4, 9)
.attr(ProtectAttr, BattlerTagType.SILK_TRAP), .attr(ProtectAttr, BattlerTagType.SILK_TRAP),
new AttackMove(Moves.AXE_KICK, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 90, 10, 30, 0, 9) new AttackMove(Moves.AXE_KICK, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 90, 10, 30, 0, 9)

View File

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

View File

@ -584,10 +584,6 @@ export class Arena {
return this.getTagOnSide(tagType, ArenaTagSide.BOTH); return this.getTagOnSide(tagType, ArenaTagSide.BOTH);
} }
hasTag(tagType: ArenaTagType) : boolean {
return !!this.getTag(tagType);
}
getTagOnSide(tagType: ArenaTagType | Constructor<ArenaTag>, side: ArenaTagSide): ArenaTag | undefined { getTagOnSide(tagType: ArenaTagType | Constructor<ArenaTag>, side: ArenaTagSide): ArenaTag | undefined {
return typeof(tagType) === "string" return typeof(tagType) === "string"
? this.tags.find(t => t.tagType === tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side)) ? this.tags.find(t => t.tagType === tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side))

View File

@ -694,7 +694,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
break; break;
} }
} }
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, opponent, null, false, statLevel); applyAbAttrs(IgnoreOpponentStatChangesAbAttr, opponent, null, statLevel);
if (move) { if (move) {
applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, opponent, move, statLevel); applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, opponent, move, statLevel);
} }
@ -978,6 +978,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
// this.scene potentially can be undefined for a fainted pokemon in doubles // this.scene potentially can be undefined for a fainted pokemon in doubles
// use optional chaining to avoid runtime errors // 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 if (!types.length) { // become UNKNOWN if no types are present
types.push(Type.UNKNOWN); types.push(Type.UNKNOWN);
@ -1122,10 +1128,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const suppressed = new Utils.BooleanHolder(false); const suppressed = new Utils.BooleanHolder(false);
this.scene.getField(true).filter(p => p !== this).map(p => { this.scene.getField(true).filter(p => p !== this).map(p => {
if (p.getAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility()) { if (p.getAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility()) {
p.getAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, false, false, suppressed, [ability])); p.getAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, false, suppressed, [ability]));
} }
if (p.getPassiveAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility(true)) { if (p.getPassiveAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility(true)) {
p.getPassiveAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, true, false, suppressed, [ability])); p.getPassiveAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, true, suppressed, [ability]));
} }
}); });
if (suppressed.value) { if (suppressed.value) {
@ -1177,7 +1183,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
getWeight(): number { getWeight(): number {
const weight = new Utils.NumberHolder(this.species.weight); const weight = new Utils.NumberHolder(this.species.weight);
// This will trigger the ability overlay so only call this function when necessary // This will trigger the ability overlay so only call this function when necessary
applyAbAttrs(WeightMultiplierAbAttr, this, null, false, weight); applyAbAttrs(WeightMultiplierAbAttr, this, null, weight);
return weight.value; return weight.value;
} }
@ -1237,10 +1243,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const cancelled = new Utils.BooleanHolder(false); const cancelled = new Utils.BooleanHolder(false);
applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier); applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier);
if (!typeless && !ignoreAbility) { if (!typeless && !ignoreAbility) {
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, true, typeMultiplier); applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true);
} }
if (!cancelled.value && !ignoreAbility) { if (!cancelled.value && !ignoreAbility) {
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, true, typeMultiplier); applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true);
} }
return (!cancelled.value ? Number(typeMultiplier.value) : 0) as TypeDamageMultiplier; return (!cancelled.value ? Number(typeMultiplier.value) : 0) as TypeDamageMultiplier;
@ -1266,22 +1272,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return this.isTerastallized() ? 2 : 1; return this.isTerastallized() ? 2 : 1;
} }
const types = this.getTypes(true, true); 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 => { let multiplier = types.map(defType => {
if (source) { if (source) {
const ignoreImmunity = new Utils.BooleanHolder(false); const ignoreImmunity = new Utils.BooleanHolder(false);
if (source.isActive(true) && source.hasAbilityWithAttr(IgnoreTypeImmunityAbAttr)) { if (source.isActive(true) && source.hasAbilityWithAttr(IgnoreTypeImmunityAbAttr)) {
applyAbAttrs(IgnoreTypeImmunityAbAttr, source, ignoreImmunity, false, moveType, defType); applyAbAttrs(IgnoreTypeImmunityAbAttr, source, ignoreImmunity, moveType, defType);
} }
if (ignoreImmunity.value) { if (ignoreImmunity.value) {
return 1; return 1;
@ -1297,7 +1293,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}).reduce((acc, cur) => acc * cur, 1) as TypeDamageMultiplier; }).reduce((acc, cur) => acc * cur, 1) as TypeDamageMultiplier;
// Handle strong winds lowering effectiveness of types super effective against pure flying // Handle strong winds lowering effectiveness of types super effective against pure flying
if (!ignoreStrongWinds && arena.weather?.weatherType === WeatherType.STRONG_WINDS && !arena.weather.isEffectSuppressed(this.scene) && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) { if (!ignoreStrongWinds && this.scene.arena.weather?.weatherType === WeatherType.STRONG_WINDS && !this.scene.arena.weather.isEffectSuppressed(this.scene) && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) {
multiplier /= 2; multiplier /= 2;
if (!simulated) { if (!simulated) {
this.scene.queueMessage(i18next.t("weather:strongWindsEffectMessage")); this.scene.queueMessage(i18next.t("weather:strongWindsEffectMessage"));
@ -1922,9 +1918,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const userAccuracyLevel = new Utils.IntegerHolder(this.summonData.battleStats[BattleStat.ACC]); const userAccuracyLevel = new Utils.IntegerHolder(this.summonData.battleStats[BattleStat.ACC]);
const targetEvasionLevel = new Utils.IntegerHolder(target.summonData.battleStats[BattleStat.EVA]); const targetEvasionLevel = new Utils.IntegerHolder(target.summonData.battleStats[BattleStat.EVA]);
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, target, null, false, userAccuracyLevel); applyAbAttrs(IgnoreOpponentStatChangesAbAttr, target, null, userAccuracyLevel);
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, this, null, false, targetEvasionLevel); applyAbAttrs(IgnoreOpponentStatChangesAbAttr, this, null, targetEvasionLevel);
applyAbAttrs(IgnoreOpponentEvasionAbAttr, this, null, false, targetEvasionLevel); applyAbAttrs(IgnoreOpponentEvasionAbAttr, this, null, targetEvasionLevel);
applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, target, sourceMove, targetEvasionLevel); applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, target, sourceMove, targetEvasionLevel);
this.scene.applyModifiers(TempBattleStatBoosterModifier, this.isPlayer(), TempBattleStat.ACC, userAccuracyLevel); this.scene.applyModifiers(TempBattleStatBoosterModifier, this.isPlayer(), TempBattleStat.ACC, userAccuracyLevel);
@ -1939,7 +1935,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
: 3 / (3 + Math.min(targetEvasionLevel.value - userAccuracyLevel.value, 6)); : 3 / (3 + Math.min(targetEvasionLevel.value - userAccuracyLevel.value, 6));
} }
applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, this, BattleStat.ACC, accuracyMultiplier, false, sourceMove); applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, this, BattleStat.ACC, accuracyMultiplier, sourceMove);
const evasionMultiplier = new Utils.NumberHolder(1); const evasionMultiplier = new Utils.NumberHolder(1);
applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, target, BattleStat.EVA, evasionMultiplier); applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, target, BattleStat.EVA, evasionMultiplier);
@ -1949,12 +1945,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return accuracyMultiplier.value; 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 { apply(source: Pokemon, move: Move): HitResult {
let result: HitResult; let result: HitResult;
const damage = new Utils.NumberHolder(0); const damage = new Utils.NumberHolder(0);
@ -1990,12 +1980,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const sourceTeraType = source.getTeraType(); const sourceTeraType = source.getTeraType();
if (!typeless) { if (!typeless) {
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier); applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier);
applyMoveAttrs(NeutralDamageAgainstFlyingTypeMultiplierAttr, source, this, move, typeMultiplier); applyMoveAttrs(NeutralDamageAgainstFlyingTypeMultiplierAttr, source, this, move, typeMultiplier);
} }
if (!cancelled.value) { if (!cancelled.value) {
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier); applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier);
defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, false, typeMultiplier)); defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, typeMultiplier));
} }
if (cancelled.value) { if (cancelled.value) {
@ -2018,7 +2008,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const critOnly = new Utils.BooleanHolder(false); const critOnly = new Utils.BooleanHolder(false);
const critAlways = source.getTag(BattlerTagType.ALWAYS_CRIT); const critAlways = source.getTag(BattlerTagType.ALWAYS_CRIT);
applyMoveAttrs(CritOnlyAttr, source, this, move, critOnly); applyMoveAttrs(CritOnlyAttr, source, this, move, critOnly);
applyAbAttrs(ConditionalCritAbAttr, source, null, false, critOnly, this, move); applyAbAttrs(ConditionalCritAbAttr, source, null, critOnly, this, move);
if (critOnly.value || critAlways) { if (critOnly.value || critAlways) {
isCritical = true; isCritical = true;
} else { } else {
@ -2028,7 +2018,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.scene.applyModifiers(TempBattleStatBoosterModifier, source.isPlayer(), TempBattleStat.CRIT, critLevel); this.scene.applyModifiers(TempBattleStatBoosterModifier, source.isPlayer(), TempBattleStat.CRIT, critLevel);
const bonusCrit = new Utils.BooleanHolder(false); const bonusCrit = new Utils.BooleanHolder(false);
//@ts-ignore //@ts-ignore
if (applyAbAttrs(BonusCritAbAttr, source, null, false, bonusCrit)) { // TODO: resolve ts-ignore. This is a promise. Checking a promise is bogus. if (applyAbAttrs(BonusCritAbAttr, source, null, bonusCrit)) { // TODO: resolve ts-ignore. This is a promise. Checking a promise is bogus.
if (bonusCrit.value) { if (bonusCrit.value) {
critLevel.value += 1; critLevel.value += 1;
} }
@ -2046,7 +2036,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (isCritical) { if (isCritical) {
const noCritTag = this.scene.arena.getTagOnSide(NoCritTag, defendingSide); const noCritTag = this.scene.arena.getTagOnSide(NoCritTag, defendingSide);
const blockCrit = new Utils.BooleanHolder(false); const blockCrit = new Utils.BooleanHolder(false);
applyAbAttrs(BlockCritAbAttr, this, null, false, blockCrit); applyAbAttrs(BlockCritAbAttr, this, null, blockCrit);
if (noCritTag || blockCrit.value) { if (noCritTag || blockCrit.value) {
isCritical = false; isCritical = false;
} }
@ -2054,7 +2044,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 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 targetDef = new Utils.IntegerHolder(this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF, source, move, isCritical));
const criticalMultiplier = new Utils.NumberHolder(isCritical ? 1.5 : 1); const criticalMultiplier = new Utils.NumberHolder(isCritical ? 1.5 : 1);
applyAbAttrs(MultCritAbAttr, source, null, false, criticalMultiplier); applyAbAttrs(MultCritAbAttr, source, null, criticalMultiplier);
const screenMultiplier = new Utils.NumberHolder(1); const screenMultiplier = new Utils.NumberHolder(1);
if (!isCritical) { if (!isCritical) {
this.scene.arena.applyTagsForSide(WeakenMoveScreenTag, defendingSide, move.category, this.scene.currentBattle.double, screenMultiplier); this.scene.arena.applyTagsForSide(WeakenMoveScreenTag, defendingSide, move.category, this.scene.currentBattle.double, screenMultiplier);
@ -2069,7 +2059,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
stabMultiplier.value += 0.5; stabMultiplier.value += 0.5;
} }
applyAbAttrs(StabBoostAbAttr, source, null, false, stabMultiplier); applyAbAttrs(StabBoostAbAttr, source, null, stabMultiplier);
if (sourceTeraType !== Type.UNKNOWN && matchesSourceType) { if (sourceTeraType !== Type.UNKNOWN && matchesSourceType) {
stabMultiplier.value = Math.min(stabMultiplier.value + 0.5, 2.25); stabMultiplier.value = Math.min(stabMultiplier.value + 0.5, 2.25);
@ -2087,12 +2077,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
numTargets = effectPhase.getTargets().length; numTargets = effectPhase.getTargets().length;
} }
const twoStrikeMultiplier = new Utils.NumberHolder(1); const twoStrikeMultiplier = new Utils.NumberHolder(1);
applyPreAttackAbAttrs(AddSecondStrikeAbAttr, source, this, move, false, numTargets, new Utils.IntegerHolder(0), twoStrikeMultiplier); applyPreAttackAbAttrs(AddSecondStrikeAbAttr, source, this, move, numTargets, new Utils.IntegerHolder(0), twoStrikeMultiplier);
if (!isTypeImmune) { if (!isTypeImmune) {
const levelMultiplier = (2 * source.level / 5 + 2); const levelMultiplier = (2 * source.level / 5 + 2);
const randomMultiplier = ((this.scene.randBattleSeedInt(16) + 85) / 100); const randomMultiplier = ((this.scene.randBattleSeedInt(16) + 85) / 100);
damage.value = Utils.toDmgValue((((levelMultiplier * power * sourceAtk.value / targetDef.value) / 50) + 2) damage.value = Math.ceil((((levelMultiplier * power * sourceAtk.value / targetDef.value) / 50) + 2)
* stabMultiplier.value * stabMultiplier.value
* typeMultiplier.value * typeMultiplier.value
* arenaAttackTypeMultiplier.value * arenaAttackTypeMultiplier.value
@ -2106,14 +2096,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (isPhysical && source.status && source.status.effect === StatusEffect.BURN) { if (isPhysical && source.status && source.status.effect === StatusEffect.BURN) {
if (!move.hasAttr(BypassBurnDamageReductionAttr)) { if (!move.hasAttr(BypassBurnDamageReductionAttr)) {
const burnDamageReductionCancelled = new Utils.BooleanHolder(false); const burnDamageReductionCancelled = new Utils.BooleanHolder(false);
applyAbAttrs(BypassBurnDamageReductionAbAttr, source, burnDamageReductionCancelled, false); applyAbAttrs(BypassBurnDamageReductionAbAttr, source, burnDamageReductionCancelled);
if (!burnDamageReductionCancelled.value) { if (!burnDamageReductionCancelled.value) {
damage.value = Utils.toDmgValue(damage.value / 2); damage.value = Math.floor(damage.value / 2);
} }
} }
} }
applyPreAttackAbAttrs(DamageBoostAbAttr, source, this, move, false, damage); applyPreAttackAbAttrs(DamageBoostAbAttr, source, this, move, damage);
/** /**
* For each {@link HitsTagAttr} the move has, doubles the damage of the move if: * For each {@link HitsTagAttr} the move has, doubles the damage of the move if:
@ -2129,7 +2119,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
if (this.scene.arena.terrain?.terrainType === TerrainType.MISTY && this.isGrounded() && move.type === Type.DRAGON) { if (this.scene.arena.terrain?.terrainType === TerrainType.MISTY && this.isGrounded() && move.type === Type.DRAGON) {
damage.value = Utils.toDmgValue(damage.value / 2); damage.value = Math.floor(damage.value / 2);
} }
const fixedDamage = new Utils.IntegerHolder(0); const fixedDamage = new Utils.IntegerHolder(0);
@ -2171,7 +2161,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.scene.applyModifiers(EnemyDamageReducerModifier, false, damage); this.scene.applyModifiers(EnemyDamageReducerModifier, false, damage);
} }
applyPreDefendAbAttrs(ReceivedMoveDamageMultiplierAbAttr, this, source, move, cancelled, false, damage); applyPreDefendAbAttrs(ReceivedMoveDamageMultiplierAbAttr, this, source, move, cancelled, damage);
} }
// This attribute may modify damage arbitrarily, so be careful about changing its order of application. // This attribute may modify damage arbitrarily, so be careful about changing its order of application.
@ -2184,7 +2174,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (damage.value) { if (damage.value) {
if (this.isFullHp()) { if (this.isFullHp()) {
applyPreDefendAbAttrs(PreDefendFullHpEndureAbAttr, this, source, move, cancelled, false, damage); applyPreDefendAbAttrs(PreDefendFullHpEndureAbAttr, this, source, move, cancelled, damage);
} else if (!this.isPlayer() && damage.value >= this.hp) { } else if (!this.isPlayer() && damage.value >= this.hp) {
this.scene.applyModifiers(EnemyEndureChanceModifier, false, this); this.scene.applyModifiers(EnemyEndureChanceModifier, false, this);
} }
@ -2251,11 +2241,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
break; break;
case MoveCategory.STATUS: case MoveCategory.STATUS:
if (!typeless) { if (!typeless) {
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier); applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier);
} }
if (!cancelled.value) { if (!cancelled.value) {
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier); applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier);
defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, false, typeMultiplier)); defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, typeMultiplier));
} }
if (!typeMultiplier.value) { if (!typeMultiplier.value) {
this.scene.queueMessage(i18next.t("battle:hitResultNoEffect", { pokemonName: getPokemonNameWithAffix(this) })); this.scene.queueMessage(i18next.t("battle:hitResultNoEffect", { pokemonName: getPokemonNameWithAffix(this) }));
@ -2347,22 +2337,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return maxForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && maxForms.includes(this.getFusionFormKey()!)); 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 { addTag(tagType: BattlerTagType, turnCount: integer = 0, sourceMove?: Moves, sourceId?: integer): boolean {
const existingTag = this.getTag(tagType); const existingTag = this.getTag(tagType);
if (existingTag) { if (existingTag) {
@ -2749,7 +2723,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
// Check if the source Pokemon has an ability that cancels the Poison/Toxic immunity // Check if the source Pokemon has an ability that cancels the Poison/Toxic immunity
const cancelImmunity = new Utils.BooleanHolder(false); const cancelImmunity = new Utils.BooleanHolder(false);
if (sourcePokemon) { if (sourcePokemon) {
applyAbAttrs(IgnoreTypeStatusEffectImmunityAbAttr, sourcePokemon, cancelImmunity, false, effect, defType); applyAbAttrs(IgnoreTypeStatusEffectImmunityAbAttr, sourcePokemon, cancelImmunity, effect, defType);
if (cancelImmunity.value) { if (cancelImmunity.value) {
return false; return false;
} }
@ -2821,7 +2795,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (effect === StatusEffect.SLEEP) { if (effect === StatusEffect.SLEEP) {
statusCureTurn = new Utils.IntegerHolder(this.randSeedIntRange(2, 4)); statusCureTurn = new Utils.IntegerHolder(this.randSeedIntRange(2, 4));
applyAbAttrs(ReduceStatusEffectDurationAbAttr, this, null, false, effect, statusCureTurn); applyAbAttrs(ReduceStatusEffectDurationAbAttr, this, null, effect, statusCureTurn);
this.setFrameRate(4); this.setFrameRate(4);
@ -3455,7 +3429,7 @@ export class PlayerPokemon extends Pokemon {
pokemon.resetTurnData(); pokemon.resetTurnData();
pokemon.resetStatus(); pokemon.resetStatus();
pokemon.heal(Math.min(Utils.toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp())); pokemon.heal(Math.min(Math.max(Math.ceil(Math.floor(0.5 * pokemon.getMaxHp())), 1), pokemon.getMaxHp()));
this.scene.queueMessage(`${pokemon.name} was revived!`,0,true); this.scene.queueMessage(`${pokemon.name} was revived!`,0,true);
if (this.scene.currentBattle.double && this.scene.getParty().length > 1) { if (this.scene.currentBattle.double && this.scene.getParty().length > 1) {
@ -4382,7 +4356,7 @@ export class PokemonMove {
} }
getMovePp(): integer { getMovePp(): integer {
return this.getMove().pp + this.ppUp * Utils.toDmgValue(this.getMove().pp / 5); return this.getMove().pp + this.ppUp * Math.max(Math.floor(this.getMove().pp / 5), 1);
} }
getPpRatio(): number { getPpRatio(): number {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -25,39 +25,39 @@ export const abilityTriggers: SimpleTranslationEntries = {
"postAttackStealHeldItem": "{{pokemonNameWithAffix}} ruba\n{{stolenItemType}} di {{defenderName}}!", "postAttackStealHeldItem": "{{pokemonNameWithAffix}} ruba\n{{stolenItemType}} di {{defenderName}}!",
"postDefendStealHeldItem": "{{pokemonNameWithAffix}} ruba\n{{stolenItemType}} di {{attackerName}}!", "postDefendStealHeldItem": "{{pokemonNameWithAffix}} ruba\n{{stolenItemType}} di {{attackerName}}!",
"copyFaintedAllyAbility": "L'abilità {{abilityName}} di {{pokemonNameWithAffix}} è passata all'alleato!", "copyFaintedAllyAbility": "L'abilità {{abilityName}} di {{pokemonNameWithAffix}} è passata all'alleato!",
"intimidateImmunity": "{{abilityName}} impedisce a {{pokemonNameWithAffix}} di\nessere intimidito!", "intimidateImmunity": "{{pokemonNameWithAffix}}'s {{abilityName}} prevented it from being Intimidated!",
"postSummonAllyHeal": "{{pokemonNameWithAffix}} beve il\ntè che {{pokemonName}} gli ha preparato!", "postSummonAllyHeal": "{{pokemonNameWithAffix}} drank down all the\nmatcha that {{pokemonName}} made!",
"postSummonClearAllyStats": "Le statistiche di {{pokemonNameWithAffix}}\ntornano alla normalità!", "postSummonClearAllyStats": "{{pokemonNameWithAffix}}'s stat changes\nwere removed!",
"postSummonTransform": "{{pokemonNameWithAffix}} assume le sembianze\ndi {{targetName}}!", "postSummonTransform": "{{pokemonNameWithAffix}} transformed\ninto {{targetName}}!",
"protectStat": "{{abilityName}} di {{pokemonNameWithAffix}}\npreviene la riduzione del/della suo/a {{statName}}!", "protectStat": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents lowering its {{statName}}!",
"statusEffectImmunityWithName": "{{abilityName}} di {{pokemonNameWithAffix}}\nnon gli fa subire il/lo/la {{statusEffectName}}!", "statusEffectImmunityWithName": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents {{statusEffectName}}!",
"statusEffectImmunity": "{{abilityName}} di {{pokemonNameWithAffix}}\npreviene i problemi di stato!", "statusEffectImmunity": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents status problems!",
"battlerTagImmunity": "{{abilityName}} di {{pokemonNameWithAffix}}\npreviene {{battlerTagName}}!", "battlerTagImmunity": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents {{battlerTagName}}!",
"forewarn": "{{pokemonNameWithAffix}} è stato messo in guardia da {{moveName}}!", "forewarn": "{{pokemonNameWithAffix}} was forewarned about {{moveName}}!",
"frisk": "{{pokemonNameWithAffix}} perquisice {{opponentName}}\ne trova la sua abilità, {{opponentAbilityName}}!", "frisk": "{{pokemonNameWithAffix}} frisked {{opponentName}}'s {{opponentAbilityName}}!",
"postWeatherLapseHeal": "{{pokemonNameWithAffix}} recupera alcuni PS\ncon {{abilityName}}!", "postWeatherLapseHeal": "{{pokemonNameWithAffix}}'s {{abilityName}}\nrestored its HP a little!",
"postWeatherLapseDamage": "{{pokemonNameWithAffix}} subisce danni\na causa della sua abilità, {{abilityName}}!", "postWeatherLapseDamage": "{{pokemonNameWithAffix}} is hurt\nby its {{abilityName}}!",
"postTurnLootCreateEatenBerry": "{{pokemonNameWithAffix}} raccoglie una {{berryName}}!", "postTurnLootCreateEatenBerry": "{{pokemonNameWithAffix}} harvested one {{berryName}}!",
"postTurnHeal": "{{pokemonNameWithAffix}} recupera alcuni PS\ncon {{abilityName}}!", "postTurnHeal": "{{pokemonNameWithAffix}}'s {{abilityName}}\nrestored its HP a little!",
"fetchBall": "{{pokemonNameWithAffix}} ha trovato una\n{{pokeballName}}!", "fetchBall": "{{pokemonNameWithAffix}} found a\n{{pokeballName}}!",
"healFromBerryUse": "{{abilityName}} di {{pokemonNameWithAffix}}\nristabilisce parte dei PS!", "healFromBerryUse": "{{pokemonNameWithAffix}}'s {{abilityName}}\nrestored its HP!",
"arenaTrap": "Labilità {{abilityName}} di {{pokemonNameWithAffix}}\nimpedisce la sostituzione!", "arenaTrap": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents switching!",
"postBattleLoot": "{{pokemonNameWithAffix}} ha raccolto\nil/l'/lo/la {{itemName}}!", "postBattleLoot": "{{pokemonNameWithAffix}} picked up\n{{itemName}}!",
"postFaintContactDamage": "{{abilityName}} di {{pokemonNameWithAffix}}\nferisce il Pokémon che lo ha attaccato!", "postFaintContactDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!",
"postFaintHpDamage": "{{abilityName}} di {{pokemonNameWithAffix}}\nferisce il Pokémon che lo ha attaccato!", "postFaintHpDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!",
"postSummonPressure": "{{pokemonNameWithAffix}} fa pressione!", "postSummonPressure": "{{pokemonNameWithAffix}} is exerting its Pressure!",
"postSummonMoldBreaker": "{{pokemonNameWithAffix}} ha labilità Rompiforma!", "postSummonMoldBreaker": "{{pokemonNameWithAffix}} breaks the mold!",
"postSummonAnticipation": "{{pokemonNameWithAffix}} rabbrividisce!", "postSummonAnticipation": "{{pokemonNameWithAffix}} shuddered!",
"postSummonTurboblaze": "{{pokemonNameWithAffix}} emana unaura infuocata!", "postSummonTurboblaze": "{{pokemonNameWithAffix}} is radiating a blazing aura!",
"postSummonTeravolt": "{{pokemonNameWithAffix}} emana unaura repulsiva!", "postSummonTeravolt": "{{pokemonNameWithAffix}} is radiating a bursting aura!",
"postSummonDarkAura": "Labilità Auratetra di {{pokemonNameWithAffix}} è attiva.", "postSummonDarkAura": "{{pokemonNameWithAffix}} is radiating a Dark Aura!",
"postSummonFairyAura": "Labilità Aurafolletto di {{pokemonNameWithAffix}} è attiva.", "postSummonFairyAura": "{{pokemonNameWithAffix}} is radiating a Fairy Aura!",
"postSummonNeutralizingGas": "Il Gas Reagente di {{pokemonNameWithAffix}}\nsi diffonde tuttintorno!", "postSummonNeutralizingGas": "{{pokemonNameWithAffix}}'s Neutralizing Gas filled the area!",
"postSummonAsOneGlastrier": "{{pokemonNameWithAffix}} ha due abilità!", "postSummonAsOneGlastrier": "{{pokemonNameWithAffix}} has two Abilities!",
"postSummonAsOneSpectrier": "{{pokemonNameWithAffix}} ha due abilità!", "postSummonAsOneSpectrier": "{{pokemonNameWithAffix}} has two Abilities!",
"postSummonVesselOfRuin": "La/l'{{statName}} dei Pokémon intorno si indebolisce a causa\ndell'abilità Vaso Nefasto di {{pokemonNameWithAffix}}!", "postSummonVesselOfRuin": "{{pokemonNameWithAffix}}'s Vessel of Ruin lowered the {{statName}}\nof all surrounding Pokémon!",
"postSummonSwordOfRuin": "La/l'{{statName}} dei Pokémon intorno si indebolisce a causa\ndell'abilità Spada Nefasta di {{pokemonNameWithAffix}}!", "postSummonSwordOfRuin": "{{pokemonNameWithAffix}}'s Sword of Ruin lowered the {{statName}}\nof all surrounding Pokémon!",
"postSummonTabletsOfRuin": "La/l'{{statName}} dei Pokémon intorno si indebolisce a causa\ndell'abilità Amuleto Nefasto di {{pokemonNameWithAffix}}!", "postSummonTabletsOfRuin": "{{pokemonNameWithAffix}}'s Tablets of Ruin lowered the {{statName}}\nof all surrounding Pokémon!",
"postSummonBeadsOfRuin": "La/l'{{statName}} dei Pokémon intorno si indebolisce a causa\ndell'abilità Monile Nefasto di {{pokemonNameWithAffix}}!", "postSummonBeadsOfRuin": "{{pokemonNameWithAffix}}'s Beads of Ruin lowered the {{statName}}\nof all surrounding Pokémon!",
"preventBerryUse": "{{pokemonNameWithAffix}} non riesce a\nmangiare le bacche per l'agitazione!", "preventBerryUse": "{{pokemonNameWithAffix}} non riesce a\nmangiare le bacche per l'agitazione!",
} as const; } as const;

View File

@ -170,8 +170,8 @@ export const PGMachv: AchievementTranslationEntries = {
description: "Vinci in modalità classica", description: "Vinci in modalità classica",
}, },
"UNEVOLVED_CLASSIC_VICTORY": { "UNEVOLVED_CLASSIC_VICTORY": {
name: "Alternanza scuola-lavoro", name: "Bring Your Child To Work Day",
description: "Completa la modalità classica con almeno un membro della squadra non evoluto completamente." description: "Beat the game in Classic Mode with at least one unevolved party member."
}, },
"MONO_GEN_ONE": { "MONO_GEN_ONE": {
@ -269,8 +269,8 @@ export const PGMachv: AchievementTranslationEntries = {
name: "Follettini e follettine", name: "Follettini e follettine",
}, },
"FRESH_START": { "FRESH_START": {
name: "Buona la prima!", name: "First Try!",
description: "Completa la modalità sfida 'Un nuovo inizio'." description: "Complete the Fresh Start challenge."
} }
} as const; } as const;

View File

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

View File

@ -74,22 +74,22 @@ export const battle: SimpleTranslationEntries = {
"fainted": "{{pokemonNameWithAffix}} non è più in\ngrado di combattere!", "fainted": "{{pokemonNameWithAffix}} non è più in\ngrado di combattere!",
"statsAnd": "e", "statsAnd": "e",
"stats": "statistiche", "stats": "statistiche",
"statRose_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} è aumentata!", "statRose_one": "{{pokemonNameWithAffix}}'s {{stats}} è aumentato/a!",
"statRose_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} sono aumentate!", "statRose_other": "{{pokemonNameWithAffix}}'s {{stats}} rose!",
"statSharplyRose_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} è aumentata molto!", "statSharplyRose_one": "{{pokemonNameWithAffix}}'s {{stats}} è aumentato/a molto!",
"statSharplyRose_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} sono aumentate molto!", "statSharplyRose_other": "{{pokemonNameWithAffix}}'s {{stats}} sharply rose!",
"statRoseDrastically_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} è aumentata drasticamente!", "statRoseDrastically_one": "{{pokemonNameWithAffix}}'s {{stats}} è aumentato/a drasticamente!",
"statRoseDrastically_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} sono aumentate drasticamente!", "statRoseDrastically_other": "{{pokemonNameWithAffix}}'s {{stats}} rose drastically!",
"statWontGoAnyHigher_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} non può aumentare di più!", "statWontGoAnyHigher_one": "{{pokemonNameWithAffix}}'s {{stats}} non può aumentare più di così!",
"statWontGoAnyHigher_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} non possono aumentare di più!", "statWontGoAnyHigher_other": "{{pokemonNameWithAffix}}'s {{stats}} won't go any higher!",
"statFell_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} è diminuita!", "statFell_one": "{{pokemonNameWithAffix}}'s {{stats}} è diminuito/a!",
"statFell_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} sono diminuite!", "statFell_other": "{{pokemonNameWithAffix}}'s {{stats}} fell!",
"statHarshlyFell_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} è diminuita molto!", "statHarshlyFell_one": "{{pokemonNameWithAffix}}'s {{stats}} è diminuito/a molto!",
"statHarshlyFell_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} sono diminuite molto!", "statHarshlyFell_other": "{{pokemonNameWithAffix}}'s {{stats}} harshly fell!",
"statSeverelyFell_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} è diminuita drasticamente!", "statSeverelyFell_one": "{{pokemonNameWithAffix}}'s {{stats}} è diminuito/a drasticamente!",
"statSeverelyFell_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} sono diminuite drasticamente!", "statSeverelyFell_other": "{{pokemonNameWithAffix}}'s {{stats}} severely fell!",
"statWontGoAnyLower_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} non può diminuire di più!", "statWontGoAnyLower_one": "{{pokemonNameWithAffix}}'s {{stats}} non può diminuire più di così!",
"statWontGoAnyLower_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} non possono diminuire di più!", "statWontGoAnyLower_other": "{{pokemonNameWithAffix}}'s {{stats}} won't go any lower!",
"transformedIntoType": "{{pokemonName}} diventa\ndi tipo {{type}} type!", "transformedIntoType": "{{pokemonName}} diventa\ndi tipo {{type}} type!",
"retryBattle": "Vuoi riprovare dall'inizio della lotta?", "retryBattle": "Vuoi riprovare dall'inizio della lotta?",
"unlockedSomething": "{{unlockedThing}}\nè stato/a sbloccato/a.", "unlockedSomething": "{{unlockedThing}}\nè stato/a sbloccato/a.",

View File

@ -1,14 +1,14 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const battlerTags: SimpleTranslationEntries = { export const battlerTags: SimpleTranslationEntries = {
"trappedDesc": "intrappolando", "trappedDesc": "trapping",
"flinchedDesc": "tentennando", "flinchedDesc": "flinching",
"confusedDesc": "confuso", "confusedDesc": "confusion",
"infatuatedDesc": "infatuato", "infatuatedDesc": "infatuation",
"seedDesc": "pieno di semi", "seedDesc": "seeding",
"nightmareDesc": "incubi", "nightmareDesc": "nightmares",
"ingrainDesc": "radici", "ingrainDesc": "roots",
"drowsyDesc": "assonnato", "drowsyDesc": "drowsiness",
"rechargingLapse": "{{pokemonNameWithAffix}} deve\nricaricarsi!", "rechargingLapse": "{{pokemonNameWithAffix}} deve\nricaricarsi!",
"trappedOnAdd": "{{pokemonNameWithAffix}} non può\npiù fuggire!", "trappedOnAdd": "{{pokemonNameWithAffix}} non può\npiù fuggire!",
"trappedOnRemove": "{{pokemonNameWithAffix}} è stato liberato\nda {{moveName}}", "trappedOnRemove": "{{pokemonNameWithAffix}} è stato liberato\nda {{moveName}}",

View File

@ -2,7 +2,7 @@ import { TranslationEntries } from "#app/interfaces/locales";
export const challenges: TranslationEntries = { export const challenges: TranslationEntries = {
"title": "Modificatori delle sfide", "title": "Modificatori delle sfide",
"illegalEvolution": "{{pokemon}} non è più utilizzabile\nsecondo le regole della sfida!", "illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!",
"singleGeneration": { "singleGeneration": {
"name": "Mono gen", "name": "Mono gen",
"desc": "Puoi usare solo Pokémon di {{gen}} generazione.", "desc": "Puoi usare solo Pokémon di {{gen}} generazione.",
@ -23,8 +23,8 @@ export const challenges: TranslationEntries = {
"desc_default": "Puoi usare solo Pokémon del tipo selezionato." "desc_default": "Puoi usare solo Pokémon del tipo selezionato."
}, },
"freshStart": { "freshStart": {
"name": "Un nuovo inizio", "name": "Fresh Start",
"desc": "Puoi usare solo gli starter originali, e come se avessi appena cominciato Pokérogue.", "desc": "You can only use the original starters, and only as if you had just started PokéRogue.",
"value.0": "Off", "value.0": "Off",
"value.1": "On", "value.1": "On",
} }

View File

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

View File

@ -25,5 +25,5 @@ export const menuUiHandler: SimpleTranslationEntries = {
"unlinkGoogle": "Scollega Google", "unlinkGoogle": "Scollega Google",
"cancel": "Annulla", "cancel": "Annulla",
"losingProgressionWarning": "Perderai tutti i progressi dall'inizio della battaglia. Confermi?", "losingProgressionWarning": "Perderai tutti i progressi dall'inizio della battaglia. Confermi?",
"noEggs": "Non stai schiudendo\nuova al momento!" "noEggs": "You are not hatching\nany eggs at the moment!"
} as const; } as const;

View File

@ -17,7 +17,7 @@ export const menu: SimpleTranslationEntries = {
"username": "Nome utente", "username": "Nome utente",
"password": "Password", "password": "Password",
"login": "Accedi", "login": "Accedi",
"orUse": "O usa", "orUse": "Or use",
"register": "Registrati", "register": "Registrati",
"emptyUsername": "Nome utente mancante!", "emptyUsername": "Nome utente mancante!",
"invalidLoginUsername": "Nome utente non valido!", "invalidLoginUsername": "Nome utente non valido!",
@ -39,9 +39,9 @@ export const menu: SimpleTranslationEntries = {
"weeklyRankings": "Classifica settimanale", "weeklyRankings": "Classifica settimanale",
"noRankings": "Nessuna classifica", "noRankings": "Nessuna classifica",
"positionIcon": "#", "positionIcon": "#",
"usernameScoreboard": "Nome utente", "usernameScoreboard": "Username",
"score": "Punteggio", "score": "Score",
"wave": "Onda", "wave": "Wave",
"loading": "Caricamento…", "loading": "Caricamento…",
"loadingAsset": "Caricamento asset: {{assetName}}", "loadingAsset": "Caricamento asset: {{assetName}}",
"playersOnline": "Giocatori online", "playersOnline": "Giocatori online",

View File

@ -101,7 +101,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
}, },
"TmModifierTypeWithInfo": { "TmModifierTypeWithInfo": {
name: "MT{{moveId}} - {{moveName}}", name: "MT{{moveId}} - {{moveName}}",
description: "Insegna {{moveName}} a un Pokémon\n(Tieni premuto C o Shift per maggiori informazioni).", description: "Insegna {{moveName}} a un Pokémon\n(Hold C or Shift for more info).",
}, },
"EvolutionItemModifierType": { "EvolutionItemModifierType": {
description: "Fa evolvere determinate specie di Pokémon.", description: "Fa evolvere determinate specie di Pokémon.",
@ -153,7 +153,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
"REVIVER_SEED": { name: "Revitalseme", description: "Il possessore recupera 1/2 di PS in caso di KO causato da un colpo diretto." }, "REVIVER_SEED": { name: "Revitalseme", description: "Il possessore recupera 1/2 di PS in caso di KO causato da un colpo diretto." },
"WHITE_HERB": { name: "Erbachiara", description: "Strumento da dare a un Pokémon. Ripristina le statistiche ridotte in lotta." }, "WHITE_HERB": { name: "Erbachiara", description: "An item to be held by a Pokémon. It will restore any lowered stat in battle." },
"ETHER": { name: "Etere" }, "ETHER": { name: "Etere" },
"MAX_ETHER": { name: "Etere max" }, "MAX_ETHER": { name: "Etere max" },

View File

@ -1,14 +1,14 @@
import { SimpleTranslationEntries } from "#app/interfaces/locales"; import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const modifier: SimpleTranslationEntries = { export const modifier: SimpleTranslationEntries = {
"surviveDamageApply": "{{pokemonNameWithAffix}} resiste\ngrazie al/alla suo/a {{typeName}}!", "surviveDamageApply": "{{pokemonNameWithAffix}} hung on\nusing its {{typeName}}!",
"turnHealApply": "{{pokemonNameWithAffix}} recupera alcuni PS con\nil/la suo/a {{typeName}}!", "turnHealApply": "{{pokemonNameWithAffix}} restored a little HP using\nits {{typeName}}!",
"hitHealApply": "{{pokemonNameWithAffix}} recupera alcuni PS con\nil/la suo/a {{typeName}}!", "hitHealApply": "{{pokemonNameWithAffix}} restored a little HP using\nits {{typeName}}!",
"pokemonInstantReviveApply": "{{pokemonNameWithAffix}} torna in forze\ngrazie al/alla suo/a {{typeName}}!", "pokemonInstantReviveApply": "{{pokemonNameWithAffix}} was revived\nby its {{typeName}}!",
"pokemonResetNegativeStatStageApply": "La riduzione alle statistiche di {{pokemonNameWithAffix}}\nviene annullata grazie al/alla suo/a {{typeName}}!", "pokemonResetNegativeStatStageApply": "{{pokemonNameWithAffix}}'s lowered stats were restored\nby its {{typeName}}!",
"moneyInterestApply": "Ricevi un interesse pari a {{moneyAmount}}₽\ngrazie al/allo/a {{typeName}}!", "moneyInterestApply": "You received interest of ₽{{moneyAmount}}\nfrom the {{typeName}}!",
"turnHeldItemTransferApply": "Il/l'/lo/la {{itemName}} di {{pokemonNameWithAffix}} è stato assorbito\ndal {{typeName}} di {{pokemonName}}!", "turnHeldItemTransferApply": "{{pokemonNameWithAffix}}'s {{itemName}} was absorbed\nby {{pokemonName}}'s {{typeName}}!",
"contactHeldItemTransferApply": "Il/l'/lo/la {{itemName}} di {{pokemonNameWithAffix}} è stato rubato\nda {{pokemonName}} con {{typeName}}!", "contactHeldItemTransferApply": "{{pokemonNameWithAffix}}'s {{itemName}} was snatched\nby {{pokemonName}}'s {{typeName}}!",
"enemyTurnHealApply": "{{pokemonNameWithAffix}}\nristabilisce parte dei PS!", "enemyTurnHealApply": "{{pokemonNameWithAffix}}\nrestored some HP!",
"bypassSpeedChanceApply": "{{pokemonName}} agisce più rapidamente del normale grazie al suo {{itemName}}!", "bypassSpeedChanceApply": "{{pokemonName}} agisce più rapidamente del normale grazie al suo {{itemName}}!",
} as const; } as const;

View File

@ -57,10 +57,10 @@ export const moveTriggers: SimpleTranslationEntries = {
"sacrificialFullRestore": "{{pokemonName}} riceve i benefici\neffetti di Curardore!", "sacrificialFullRestore": "{{pokemonName}} riceve i benefici\neffetti di Curardore!",
"invertStats": "Le modifiche alle statistiche di {{pokemonName}}\nvengono invertite!", "invertStats": "Le modifiche alle statistiche di {{pokemonName}}\nvengono invertite!",
"resetStats": "Tutte le modifiche alle statistiche sono state annullate!", "resetStats": "Tutte le modifiche alle statistiche sono state annullate!",
"statEliminated": "Tutte le modifiche alle statistiche sono state annullate!", "statEliminated": "All stat changes were eliminated!",
"faintCountdown": "{{pokemonName}}\nandrà KO dopo {{turnCount}} turni.", "faintCountdown": "{{pokemonName}}\nandrà KO dopo {{turnCount}} turni.",
"copyType": "{{pokemonName}} assume il tipo\ndi {{targetPokemonName}}!", "copyType": "{{pokemonName}} assume il tipo\ndi {{targetPokemonName}}!",
"suppressAbilities": "Labilità di {{pokemonName}}\nperde ogni efficacia!", "suppressAbilities": "Labilità di {{pokemonName}}\nperde ogni efficacia!",
"swapArenaTags": "{{pokemonName}} ha invertito gli effetti attivi\nnelle due metà del campo!", "swapArenaTags": "{{pokemonName}} ha invertito gli effetti attivi\nnelle due metà del campo!",
"exposedMove": "{{pokemonName}} ha identificato\n{{targetPokemonName}}!", "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!",
} as const; } as const;

View File

@ -2915,7 +2915,7 @@ export const move: MoveTranslationEntries = {
}, },
zippyZap: { zippyZap: {
name: "Sprintaboom", name: "Sprintaboom",
effect: "Un attacco elettrico ad altissima velocità. Questa mossa ha priorità alta e aumenta l'elusione dell'utilizzatore.", effect: "The user attacks the target with bursts of electricity at high speed. This move always goes first and raises the user's evasiveness.",
}, },
splishySplash: { splishySplash: {
name: "Surfasplash", name: "Surfasplash",

View File

@ -99,9 +99,9 @@ export const settings: SimpleTranslationEntries = {
"showBgmBar": "Mostra Nomi Musica", "showBgmBar": "Mostra Nomi Musica",
"moveTouchControls": "Move Touch Controls", "moveTouchControls": "Move Touch Controls",
"shopOverlayOpacity": "Opacità Finestra Negozio", "shopOverlayOpacity": "Opacità Finestra Negozio",
"shopCursorTarget": "Target Cursore Negozio", "shopCursorTarget": "Shop Cursor Target",
"items": "Oggetti", "items": "Items",
"reroll": "Rerolla", "reroll": "Reroll",
"shop": "Negozio", "shop": "Shop",
"checkTeam": "Squadra" "checkTeam": "Check Team"
} as const; } as const;

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ export const moveTriggers: SimpleTranslationEntries = {
"goingAllOutForAttack": "{{pokemonName}}[[는]]\n전력을 다하기 시작했다!", "goingAllOutForAttack": "{{pokemonName}}[[는]]\n전력을 다하기 시작했다!",
"regainedHealth": "{{pokemonName}}[[는]]\n기력을 회복했다!", "regainedHealth": "{{pokemonName}}[[는]]\n기력을 회복했다!",
"keptGoingAndCrashed": "{{pokemonName}}[[는]]\n의욕이 넘쳐서 땅에 부딪쳤다!", "keptGoingAndCrashed": "{{pokemonName}}[[는]]\n의욕이 넘쳐서 땅에 부딪쳤다!",
"fled": "{{pokemonName}}[[는]]\n도망쳤다!", "fled": "{{pokemonName}}[[는]]\N도망쳤다!",
"cannotBeSwitchedOut": "{{pokemonName}}[[를]]\n돌아오게 할 수 없습니다!", "cannotBeSwitchedOut": "{{pokemonName}}[[를]]\n돌아오게 할 수 없습니다!",
"swappedAbilitiesWithTarget": "{{pokemonName}}[[는]]\n서로의 특성을 교체했다!", "swappedAbilitiesWithTarget": "{{pokemonName}}[[는]]\n서로의 특성을 교체했다!",
"coinsScatteredEverywhere": "돈이 주위에 흩어졌다!", "coinsScatteredEverywhere": "돈이 주위에 흩어졌다!",

View File

@ -99,9 +99,9 @@ export const settings: SimpleTranslationEntries = {
"showBgmBar": "BGM 제목 보여주기", "showBgmBar": "BGM 제목 보여주기",
"moveTouchControls": "터치 컨트롤 이동", "moveTouchControls": "터치 컨트롤 이동",
"shopOverlayOpacity": "상점 오버레이 투명도", "shopOverlayOpacity": "상점 오버레이 투명도",
"shopCursorTarget": "상점 커서 위치", "shopCursorTarget": "Shop Cursor Target",
"items": "아이템", "items": "Items",
"reroll": "갱신", "reroll": "Reroll",
"shop": "상점", "shop": "Shop",
"checkTeam": "파티 확인" "checkTeam": "Check Team"
} as const; } as const;

View File

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

View File

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

View File

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

View File

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

View File

@ -99,9 +99,9 @@ export const settings: SimpleTranslationEntries = {
"showBgmBar": "显示音乐名称", "showBgmBar": "显示音乐名称",
"moveTouchControls": "移动触摸控制", "moveTouchControls": "移动触摸控制",
"shopOverlayOpacity": "商店显示不透明度", "shopOverlayOpacity": "商店显示不透明度",
"shopCursorTarget": "商店指针位置", "shopCursorTarget": "Shop Cursor Target",
"items": "道具", "items": "Items",
"reroll": "刷新", "reroll": "Reroll",
"shop": "购买", "shop": "Shop",
"checkTeam": "检查队伍" "checkTeam": "Check Team"
} as const; } as const;

View File

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

View File

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

View File

@ -1160,7 +1160,7 @@ export class TurnHealModifier extends PokemonHeldItemModifier {
if (!pokemon.isFullHp()) { if (!pokemon.isFullHp()) {
const scene = pokemon.scene; const scene = pokemon.scene;
scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(),
Utils.toDmgValue(pokemon.getMaxHp() / 16) * this.stackCount, i18next.t("modifier:turnHealApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), true)); Math.max(Math.floor(pokemon.getMaxHp() / 16) * this.stackCount, 1), i18next.t("modifier:turnHealApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), true));
return true; return true;
} }
@ -1251,7 +1251,7 @@ export class HitHealModifier extends PokemonHeldItemModifier {
if (pokemon.turnData.damageDealt && !pokemon.isFullHp()) { if (pokemon.turnData.damageDealt && !pokemon.isFullHp()) {
const scene = pokemon.scene; const scene = pokemon.scene;
scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(),
Utils.toDmgValue(pokemon.turnData.damageDealt / 8) * this.stackCount, i18next.t("modifier:hitHealApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), true)); Math.max(Math.floor(pokemon.turnData.damageDealt / 8) * this.stackCount, 1), i18next.t("modifier:hitHealApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), true));
} }
return true; return true;
@ -1386,7 +1386,7 @@ export class PokemonInstantReviveModifier extends PokemonHeldItemModifier {
const pokemon = args[0] as Pokemon; const pokemon = args[0] as Pokemon;
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(),
Utils.toDmgValue(pokemon.getMaxHp() / 2), i18next.t("modifier:pokemonInstantReviveApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), false, false, true)); Math.max(Math.floor(pokemon.getMaxHp() / 2), 1), i18next.t("modifier:pokemonInstantReviveApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), false, false, true));
pokemon.resetStatus(true, false, true); pokemon.resetStatus(true, false, true);
return true; return true;

View File

@ -23,7 +23,7 @@ export class AttemptRunPhase extends PokemonPhase {
const enemySpeed = enemyField.reduce((total: integer, enemyPokemon: Pokemon) => total + enemyPokemon.getStat(Stat.SPD), 0) / enemyField.length; const enemySpeed = enemyField.reduce((total: integer, enemyPokemon: Pokemon) => total + enemyPokemon.getStat(Stat.SPD), 0) / enemyField.length;
const escapeChance = new Utils.IntegerHolder((((playerPokemon.getStat(Stat.SPD) * 128) / enemySpeed) + (30 * this.scene.currentBattle.escapeAttempts++)) % 256); const escapeChance = new Utils.IntegerHolder((((playerPokemon.getStat(Stat.SPD) * 128) / enemySpeed) + (30 * this.scene.currentBattle.escapeAttempts++)) % 256);
applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, false, escapeChance); applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, escapeChance);
if (playerPokemon.randSeedInt(256) < escapeChance.value) { if (playerPokemon.randSeedInt(256) < escapeChance.value) {
this.scene.playSound("flee"); this.scene.playSound("flee");

View File

@ -189,7 +189,7 @@ export class CommandPhase extends FieldPhase {
const batonPass = isSwitch && args[0] as boolean; const batonPass = isSwitch && args[0] as boolean;
const trappedAbMessages: string[] = []; const trappedAbMessages: string[] = [];
if (!batonPass) { if (!batonPass) {
enemyField.forEach(enemyPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, enemyPokemon, trapped, playerPokemon, trappedAbMessages, true)); enemyField.forEach(enemyPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, enemyPokemon, trapped, playerPokemon, true, trappedAbMessages));
} }
if (batonPass || (!trapTag && !trapped.value)) { if (batonPass || (!trapTag && !trapped.value)) {
this.scene.currentBattle.turnCommands[this.fieldIndex] = isSwitch this.scene.currentBattle.turnCommands[this.fieldIndex] = isSwitch

View File

@ -67,7 +67,7 @@ export class EncounterPhase extends BattlePhase {
battle.enemyParty[e].ivs = new Array(6).fill(31); battle.enemyParty[e].ivs = new Array(6).fill(31);
} }
this.scene.getParty().slice(0, !battle.double ? 1 : 2).reverse().forEach(playerPokemon => { this.scene.getParty().slice(0, !battle.double ? 1 : 2).reverse().forEach(playerPokemon => {
applyAbAttrs(SyncEncounterNatureAbAttr, playerPokemon, null, false, battle.enemyParty[e]); applyAbAttrs(SyncEncounterNatureAbAttr, playerPokemon, null, battle.enemyParty[e]);
}); });
} }
} }

View File

@ -47,7 +47,7 @@ export class EnemyCommandPhase extends FieldPhase {
const trapTag = enemyPokemon.findTag(t => t instanceof TrappedTag) as TrappedTag; const trapTag = enemyPokemon.findTag(t => t instanceof TrappedTag) as TrappedTag;
const trapped = new Utils.BooleanHolder(false); const trapped = new Utils.BooleanHolder(false);
opponents.forEach(playerPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, playerPokemon, trapped, enemyPokemon, [], true)); opponents.forEach(playerPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, playerPokemon, trapped, enemyPokemon, true, []));
if (!trapTag && !trapped.value) { if (!trapTag && !trapped.value) {
const partyMemberScores = trainer.getPartyMemberMatchupScores(enemyPokemon.trainerSlot, true); const partyMemberScores = trainer.getPartyMemberMatchupScores(enemyPokemon.trainerSlot, true);

View File

@ -74,7 +74,7 @@ export class MoveEffectPhase extends PokemonPhase {
// Assume single target for multi hit // Assume single target for multi hit
applyMoveAttrs(MultiHitAttr, user, this.getTarget() ?? null, move, hitCount); applyMoveAttrs(MultiHitAttr, user, this.getTarget() ?? null, move, hitCount);
// If Parental Bond is applicable, double the hit count // If Parental Bond is applicable, double the hit count
applyPreAttackAbAttrs(AddSecondStrikeAbAttr, user, null, move, false, targets.length, hitCount, new Utils.IntegerHolder(0)); applyPreAttackAbAttrs(AddSecondStrikeAbAttr, user, null, move, targets.length, hitCount, new Utils.IntegerHolder(0));
// If Multi-Lens is applicable, multiply the hit count by 1 + the number of Multi-Lenses held by the user // If Multi-Lens is applicable, multiply the hit count by 1 + the number of Multi-Lenses held by the user
if (move instanceof AttackMove && !move.hasAttr(FixedDamageAttr)) { if (move instanceof AttackMove && !move.hasAttr(FixedDamageAttr)) {
this.scene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, hitCount, new Utils.IntegerHolder(0)); this.scene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, hitCount, new Utils.IntegerHolder(0));

View File

@ -90,7 +90,7 @@ export class MovePhase extends BattlePhase {
: null; : null;
if (moveTarget) { if (moveTarget) {
const oldTarget = moveTarget.value; const oldTarget = moveTarget.value;
this.scene.getField(true).filter(p => p !== this.pokemon).forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, false, this.move.moveId, moveTarget)); this.scene.getField(true).filter(p => p !== this.pokemon).forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, this.move.moveId, moveTarget));
this.pokemon.getOpponents().forEach(p => { this.pokemon.getOpponents().forEach(p => {
const redirectTag = p.getTag(CenterOfAttentionTag) as CenterOfAttentionTag; const redirectTag = p.getTag(CenterOfAttentionTag) as CenterOfAttentionTag;
if (redirectTag && (!redirectTag.powder || (!this.pokemon.isOfType(Type.GRASS) && !this.pokemon.hasAbility(Abilities.OVERCOAT)))) { if (redirectTag && (!redirectTag.powder || (!this.pokemon.isOfType(Type.GRASS) && !this.pokemon.hasAbility(Abilities.OVERCOAT)))) {

View File

@ -34,7 +34,7 @@ export class PostTurnStatusEffectPhase extends PokemonPhase {
break; break;
case StatusEffect.BURN: case StatusEffect.BURN:
damage.value = Math.max(pokemon.getMaxHp() >> 4, 1); damage.value = Math.max(pokemon.getMaxHp() >> 4, 1);
applyAbAttrs(ReduceBurnDamageAbAttr, pokemon, null, false, damage); applyAbAttrs(ReduceBurnDamageAbAttr, pokemon, null, damage);
break; break;
} }
if (damage.value) { if (damage.value) {

View File

@ -68,7 +68,7 @@ export class StatChangePhase extends PokemonPhase {
const levels = new Utils.IntegerHolder(this.levels); const levels = new Utils.IntegerHolder(this.levels);
if (!this.ignoreAbilities) { if (!this.ignoreAbilities) {
applyAbAttrs(StatChangeMultiplierAbAttr, pokemon, null, false, levels); applyAbAttrs(StatChangeMultiplierAbAttr, pokemon, null, levels);
} }
const battleStats = this.getPokemon().summonData.battleStats; const battleStats = this.getPokemon().summonData.battleStats;
@ -90,7 +90,7 @@ export class StatChangePhase extends PokemonPhase {
if (levels.value > 0 && this.canBeCopied) { if (levels.value > 0 && this.canBeCopied) {
for (const opponent of pokemon.getOpponents()) { for (const opponent of pokemon.getOpponents()) {
applyAbAttrs(StatChangeCopyAbAttr, opponent, null, false, this.stats, levels.value); applyAbAttrs(StatChangeCopyAbAttr, opponent, null, this.stats, levels.value);
} }
} }

View File

@ -34,8 +34,8 @@ export class TurnStartPhase extends FieldPhase {
this.scene.getField(true).filter(p => p.summonData).map(p => { this.scene.getField(true).filter(p => p.summonData).map(p => {
const bypassSpeed = new Utils.BooleanHolder(false); const bypassSpeed = new Utils.BooleanHolder(false);
const canCheckHeldItems = new Utils.BooleanHolder(true); const canCheckHeldItems = new Utils.BooleanHolder(true);
applyAbAttrs(BypassSpeedChanceAbAttr, p, null, false, bypassSpeed); applyAbAttrs(BypassSpeedChanceAbAttr, p, null, bypassSpeed);
applyAbAttrs(PreventBypassSpeedChanceAbAttr, p, null, false, bypassSpeed, canCheckHeldItems); applyAbAttrs(PreventBypassSpeedChanceAbAttr, p, null, bypassSpeed, canCheckHeldItems);
if (canCheckHeldItems.value) { if (canCheckHeldItems.value) {
this.scene.applyModifiers(BypassSpeedChanceModifier, p.isPlayer(), p, bypassSpeed); this.scene.applyModifiers(BypassSpeedChanceModifier, p.isPlayer(), p, bypassSpeed);
} }
@ -64,8 +64,8 @@ export class TurnStartPhase extends FieldPhase {
applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); //TODO: is the bang correct here? applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); //TODO: is the bang correct here?
applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); //TODO: is the bang correct here? applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); //TODO: is the bang correct here?
applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, false, aMove, aPriority); //TODO: is the bang correct here? applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); //TODO: is the bang correct here?
applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, false, bMove, bPriority); //TODO: is the bang correct here? applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); //TODO: is the bang correct here?
if (aPriority.value !== bPriority.value) { if (aPriority.value !== bPriority.value) {
const bracketDifference = Math.ceil(aPriority.value) - Math.ceil(bPriority.value); const bracketDifference = Math.ceil(aPriority.value) - Math.ceil(bPriority.value);

View File

@ -26,7 +26,6 @@ const unicodeRanges = {
kana: "U+3040-30FF", kana: "U+3040-30FF",
CJKCommon: "U+2E80-2EFF,U+3000-303F,U+31C0-31EF,U+3200-32FF,U+3400-4DBF,U+F900-FAFF,U+FE30-FE4F", CJKCommon: "U+2E80-2EFF,U+3000-303F,U+31C0-31EF,U+3200-32FF,U+3400-4DBF,U+F900-FAFF,U+FE30-FE4F",
CJKIdeograph: "U+4E00-9FFF", CJKIdeograph: "U+4E00-9FFF",
specialCharacters: "U+266A,U+2605,U+2665,U+2663" //♪.★,♥,♣
}; };
const rangesByLanguage = { const rangesByLanguage = {
korean: [unicodeRanges.CJKCommon, unicodeRanges.hangul].join(","), korean: [unicodeRanges.CJKCommon, unicodeRanges.hangul].join(","),
@ -35,15 +34,6 @@ const rangesByLanguage = {
}; };
const fonts: Array<LoadingFontFaceProperty> = [ const fonts: Array<LoadingFontFaceProperty> = [
// unicode (special character from PokePT)
{
face: new FontFace("emerald", "url(./fonts/PokePT_Wansung.woff2)", { unicodeRange: unicodeRanges.specialCharacters }),
},
{
face: new FontFace("pkmnems", "url(./fonts/PokePT_Wansung.woff2)", { unicodeRange: unicodeRanges.specialCharacters }),
extraOptions: { sizeAdjust: "133%" },
},
// unicode (korean)
{ {
face: new FontFace("emerald", "url(./fonts/PokePT_Wansung.woff2)", { unicodeRange: rangesByLanguage.korean }), face: new FontFace("emerald", "url(./fonts/PokePT_Wansung.woff2)", { unicodeRange: rangesByLanguage.korean }),
}, },

View File

@ -1,15 +1,15 @@
import { CommandPhase } from "#app/phases/command-phase";
import { MessagePhase } from "#app/phases/message-phase";
import { TurnInitPhase } from "#app/phases/turn-init-phase";
import i18next, { initI18n } from "#app/plugins/i18n"; import i18next, { initI18n } from "#app/plugins/i18n";
import GameManager from "#test/utils/gameManager";
import { Mode } from "#app/ui/ui"; import { Mode } from "#app/ui/ui";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import { CommandPhase } from "#app/phases/command-phase.js";
import { MessagePhase } from "#app/phases/message-phase.js";
import { TurnInitPhase } from "#app/phases/turn-init-phase.js";
describe("Ability Timing", () => { describe("Ability Timing", () => {

View File

@ -1,18 +1,19 @@
import { allMoves } from "#app/data/move"; import { allMoves } from "#app/data/move.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
describe("Abilities - Aura Break", () => { describe("Abilities - Aura Break", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
let game: GameManager; let game: GameManager;
const auraBreakMultiplier = 9 / 16 * 4 / 3; const auraBreakMultiplier = 9/16 * 4/3;
beforeAll(() => { beforeAll(() => {
phaserGame = new Phaser.Game({ phaserGame = new Phaser.Game({
@ -41,7 +42,7 @@ describe("Abilities - Aura Break", () => {
vi.spyOn(moveToCheck, "calculateBattlePower"); vi.spyOn(moveToCheck, "calculateBattlePower");
await game.startBattle([Species.PIKACHU]); await game.startBattle([Species.PIKACHU]);
game.move.select(Moves.MOONBLAST); game.doAttack(getMovePosition(game.scene, 0, Moves.MOONBLAST));
await game.phaseInterceptor.to(MoveEffectPhase); await game.phaseInterceptor.to(MoveEffectPhase);
expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(expect.closeTo(basePower * auraBreakMultiplier)); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(expect.closeTo(basePower * auraBreakMultiplier));
@ -55,7 +56,7 @@ describe("Abilities - Aura Break", () => {
vi.spyOn(moveToCheck, "calculateBattlePower"); vi.spyOn(moveToCheck, "calculateBattlePower");
await game.startBattle([Species.PIKACHU]); await game.startBattle([Species.PIKACHU]);
game.move.select(Moves.DARK_PULSE); game.doAttack(getMovePosition(game.scene, 0, Moves.DARK_PULSE));
await game.phaseInterceptor.to(MoveEffectPhase); await game.phaseInterceptor.to(MoveEffectPhase);
expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(expect.closeTo(basePower * auraBreakMultiplier)); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(expect.closeTo(basePower * auraBreakMultiplier));

View File

@ -1,13 +1,14 @@
import { allMoves } from "#app/data/move"; import { allMoves } from "#app/data/move.js";
import { Abilities } from "#app/enums/abilities"; import { Abilities } from "#app/enums/abilities.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import GameManager from "#test/utils/gameManager";
import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
describe("Abilities - Battery", () => { describe("Abilities - Battery", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -42,8 +43,8 @@ describe("Abilities - Battery", () => {
await game.startBattle([Species.PIKACHU, Species.CHARJABUG]); await game.startBattle([Species.PIKACHU, Species.CHARJABUG]);
game.move.select(Moves.DAZZLING_GLEAM); game.doAttack(getMovePosition(game.scene, 0, Moves.DAZZLING_GLEAM));
game.move.select(Moves.SPLASH, 1); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(MoveEffectPhase); await game.phaseInterceptor.to(MoveEffectPhase);
expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower * batteryMultiplier); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower * batteryMultiplier);
@ -57,8 +58,8 @@ describe("Abilities - Battery", () => {
await game.startBattle([Species.PIKACHU, Species.CHARJABUG]); await game.startBattle([Species.PIKACHU, Species.CHARJABUG]);
game.move.select(Moves.BREAKING_SWIPE); game.doAttack(getMovePosition(game.scene, 0, Moves.BREAKING_SWIPE));
game.move.select(Moves.SPLASH, 1); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(MoveEffectPhase); await game.phaseInterceptor.to(MoveEffectPhase);
expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower);
@ -72,8 +73,8 @@ describe("Abilities - Battery", () => {
await game.startBattle([Species.CHARJABUG, Species.PIKACHU]); await game.startBattle([Species.CHARJABUG, Species.PIKACHU]);
game.move.select(Moves.DAZZLING_GLEAM); game.doAttack(getMovePosition(game.scene, 0, Moves.DAZZLING_GLEAM));
game.move.select(Moves.SPLASH, 1); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower);

View File

@ -1,10 +1,11 @@
import { Status, StatusEffect } from "#app/data/status-effect"; import { Status, StatusEffect } from "#app/data/status-effect.js";
import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager"; import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
const TIMEOUT = 20 * 1000; const TIMEOUT = 20 * 1000;
@ -52,7 +53,7 @@ describe("Abilities - BATTLE BOND", () => {
greninja!.status = new Status(StatusEffect.FAINT); greninja!.status = new Status(StatusEffect.FAINT);
expect(greninja!.isFainted()).toBe(true); expect(greninja!.isFainted()).toBe(true);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.doKillOpponents(); await game.doKillOpponents();
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
game.doSelectModifier(); game.doSelectModifier();

View File

@ -1,13 +1,14 @@
import { BattleStat } from "#app/data/battle-stat"; import { BattleStat } from "#app/data/battle-stat.js";
import { Abilities } from "#app/enums/abilities"; import { Abilities } from "#app/enums/abilities.js";
import { Moves } from "#app/enums/moves"; import { Moves } from "#app/enums/moves.js";
import { Species } from "#app/enums/species"; import { Species } from "#app/enums/species.js";
import { CommandPhase } from "#app/phases/command-phase";
import { MessagePhase } from "#app/phases/message-phase";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import { CommandPhase } from "#app/phases/command-phase.js";
import { MessagePhase } from "#app/phases/message-phase.js";
const TIMEOUT = 20 * 1000; const TIMEOUT = 20 * 1000;
@ -43,15 +44,15 @@ describe("Abilities - COSTAR", () => {
let [leftPokemon, rightPokemon] = game.scene.getPlayerField(); let [leftPokemon, rightPokemon] = game.scene.getPlayerField();
game.move.select(Moves.NASTY_PLOT); game.doAttack(getMovePosition(game.scene, 0, Moves.NASTY_PLOT));
await game.phaseInterceptor.to(CommandPhase); await game.phaseInterceptor.to(CommandPhase);
game.move.select(Moves.SPLASH, 1); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.toNextTurn(); await game.toNextTurn();
expect(leftPokemon.summonData.battleStats[BattleStat.SPATK]).toBe(+2); expect(leftPokemon.summonData.battleStats[BattleStat.SPATK]).toBe(+2);
expect(rightPokemon.summonData.battleStats[BattleStat.SPATK]).toBe(0); expect(rightPokemon.summonData.battleStats[BattleStat.SPATK]).toBe(0);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(CommandPhase); await game.phaseInterceptor.to(CommandPhase);
game.doSwitchPokemon(2); game.doSwitchPokemon(2);
await game.phaseInterceptor.to(MessagePhase); await game.phaseInterceptor.to(MessagePhase);
@ -75,7 +76,7 @@ describe("Abilities - COSTAR", () => {
expect(leftPokemon.summonData.battleStats[BattleStat.ATK]).toBe(-2); expect(leftPokemon.summonData.battleStats[BattleStat.ATK]).toBe(-2);
expect(leftPokemon.summonData.battleStats[BattleStat.ATK]).toBe(-2); expect(leftPokemon.summonData.battleStats[BattleStat.ATK]).toBe(-2);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(CommandPhase); await game.phaseInterceptor.to(CommandPhase);
game.doSwitchPokemon(2); game.doSwitchPokemon(2);
await game.phaseInterceptor.to(MessagePhase); await game.phaseInterceptor.to(MessagePhase);

View File

@ -1,17 +1,17 @@
import { BattleStat } from "#app/data/battle-stat"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { StatusEffect } from "#app/data/status-effect"; import GameManager from "#test/utils/gameManager";
import { CommandPhase } from "#app/phases/command-phase"; import { getMovePosition } from "#test/utils/gameManagerUtils";
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { MoveEndPhase } from "#app/phases/move-end-phase";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { TurnInitPhase } from "#app/phases/turn-init-phase";
import { Mode } from "#app/ui/ui";
import { toDmgValue } from "#app/utils";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager"; import { StatusEffect } from "#app/data/status-effect.js";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { BattleStat } from "#app/data/battle-stat.js";
import { SPLASH_ONLY } from "../utils/testUtils"; import { SPLASH_ONLY } from "../utils/testUtils";
import { Mode } from "#app/ui/ui.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
import { MoveEndPhase } from "#app/phases/move-end-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
import { TurnInitPhase } from "#app/phases/turn-init-phase.js";
import { CommandPhase } from "#app/phases/command-phase.js";
const TIMEOUT = 20 * 1000; const TIMEOUT = 20 * 1000;
@ -47,11 +47,11 @@ describe("Abilities - Disguise", () => {
const mimikyu = game.scene.getEnemyPokemon()!; const mimikyu = game.scene.getEnemyPokemon()!;
const maxHp = mimikyu.getMaxHp(); const maxHp = mimikyu.getMaxHp();
const disguiseDamage = toDmgValue(maxHp / 8); const disguiseDamage = Math.floor(maxHp / 8);
expect(mimikyu.formIndex).toBe(disguisedForm); expect(mimikyu.formIndex).toBe(disguisedForm);
game.move.select(Moves.SHADOW_SNEAK); game.doAttack(getMovePosition(game.scene, 0, Moves.SHADOW_SNEAK));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
@ -66,7 +66,7 @@ describe("Abilities - Disguise", () => {
expect(mimikyu.formIndex).toBe(disguisedForm); expect(mimikyu.formIndex).toBe(disguisedForm);
game.move.select(Moves.VACUUM_WAVE); game.doAttack(getMovePosition(game.scene, 0, Moves.VACUUM_WAVE));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
@ -80,11 +80,11 @@ describe("Abilities - Disguise", () => {
const mimikyu = game.scene.getEnemyPokemon()!; const mimikyu = game.scene.getEnemyPokemon()!;
const maxHp = mimikyu.getMaxHp(); const maxHp = mimikyu.getMaxHp();
const disguiseDamage = toDmgValue(maxHp / 8); const disguiseDamage = Math.floor(maxHp / 8);
expect(mimikyu.formIndex).toBe(disguisedForm); expect(mimikyu.formIndex).toBe(disguisedForm);
game.move.select(Moves.SURGING_STRIKES); game.doAttack(getMovePosition(game.scene, 0, Moves.SURGING_STRIKES));
// First hit // First hit
await game.phaseInterceptor.to(MoveEffectPhase); await game.phaseInterceptor.to(MoveEffectPhase);
@ -103,7 +103,7 @@ describe("Abilities - Disguise", () => {
const mimikyu = game.scene.getEnemyPokemon()!; const mimikyu = game.scene.getEnemyPokemon()!;
expect(mimikyu.hp).toBe(mimikyu.getMaxHp()); expect(mimikyu.hp).toBe(mimikyu.getMaxHp());
game.move.select(Moves.TOXIC_THREAD); game.doAttack(getMovePosition(game.scene, 0, Moves.TOXIC_THREAD));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -121,9 +121,9 @@ describe("Abilities - Disguise", () => {
const mimikyu = game.scene.getPlayerPokemon()!; const mimikyu = game.scene.getPlayerPokemon()!;
const maxHp = mimikyu.getMaxHp(); const maxHp = mimikyu.getMaxHp();
const disguiseDamage = toDmgValue(maxHp / 8); const disguiseDamage = Math.floor(maxHp / 8);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -148,7 +148,7 @@ describe("Abilities - Disguise", () => {
const mimikyu = game.scene.getParty()[1]!; const mimikyu = game.scene.getParty()[1]!;
expect(mimikyu.formIndex).toBe(bustedForm); expect(mimikyu.formIndex).toBe(bustedForm);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.doKillOpponents(); await game.doKillOpponents();
await game.toNextWave(); await game.toNextWave();
@ -168,7 +168,7 @@ describe("Abilities - Disguise", () => {
expect(mimikyu.formIndex).toBe(bustedForm); expect(mimikyu.formIndex).toBe(bustedForm);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.doKillOpponents(); await game.doKillOpponents();
await game.toNextWave(); await game.toNextWave();
@ -188,11 +188,11 @@ describe("Abilities - Disguise", () => {
expect(mimikyu1.formIndex).toBe(bustedForm); expect(mimikyu1.formIndex).toBe(bustedForm);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.killPokemon(mimikyu1); await game.killPokemon(mimikyu1);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
await game.toNextTurn(); await game.toNextTurn();
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.doKillOpponents(); await game.doKillOpponents();
game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { // TODO: Make tests run in set mode instead of switch mode game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { // TODO: Make tests run in set mode instead of switch mode
game.setMode(Mode.MESSAGE); game.setMode(Mode.MESSAGE);

View File

@ -1,11 +1,12 @@
import { Species } from "#app/enums/species"; import { Species } from "#app/enums/species.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase"; import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
describe("Abilities - Dry Skin", () => { describe("Abilities - Dry Skin", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -42,13 +43,13 @@ describe("Abilities - Dry Skin", () => {
// first turn // first turn
let previousEnemyHp = enemy.hp; let previousEnemyHp = enemy.hp;
game.move.select(Moves.SUNNY_DAY); game.doAttack(getMovePosition(game.scene, 0, Moves.SUNNY_DAY));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(enemy.hp).toBeLessThan(previousEnemyHp); expect(enemy.hp).toBeLessThan(previousEnemyHp);
// second turn // second turn
previousEnemyHp = enemy.hp; previousEnemyHp = enemy.hp;
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(enemy.hp).toBeLessThan(previousEnemyHp); expect(enemy.hp).toBeLessThan(previousEnemyHp);
}); });
@ -65,13 +66,13 @@ describe("Abilities - Dry Skin", () => {
// first turn // first turn
let previousEnemyHp = enemy.hp; let previousEnemyHp = enemy.hp;
game.move.select(Moves.RAIN_DANCE); game.doAttack(getMovePosition(game.scene, 0, Moves.RAIN_DANCE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(enemy.hp).toBeGreaterThan(previousEnemyHp); expect(enemy.hp).toBeGreaterThan(previousEnemyHp);
// second turn // second turn
previousEnemyHp = enemy.hp; previousEnemyHp = enemy.hp;
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(enemy.hp).toBeGreaterThan(previousEnemyHp); expect(enemy.hp).toBeGreaterThan(previousEnemyHp);
}); });
@ -86,7 +87,7 @@ describe("Abilities - Dry Skin", () => {
enemy.hp = initialHP; enemy.hp = initialHP;
// first turn // first turn
game.move.select(Moves.FLAMETHROWER); game.doAttack(getMovePosition(game.scene, 0, Moves.FLAMETHROWER));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
const fireDamageTakenWithDrySkin = initialHP - enemy.hp; const fireDamageTakenWithDrySkin = initialHP - enemy.hp;
@ -95,7 +96,7 @@ describe("Abilities - Dry Skin", () => {
game.override.enemyAbility(Abilities.NONE); game.override.enemyAbility(Abilities.NONE);
// second turn // second turn
game.move.select(Moves.FLAMETHROWER); game.doAttack(getMovePosition(game.scene, 0, Moves.FLAMETHROWER));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
const fireDamageTakenWithoutDrySkin = initialHP - enemy.hp; const fireDamageTakenWithoutDrySkin = initialHP - enemy.hp;
@ -112,7 +113,7 @@ describe("Abilities - Dry Skin", () => {
enemy.hp = 1; enemy.hp = 1;
game.move.select(Moves.WATER_GUN); game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_GUN));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(enemy.hp).toBeGreaterThan(1); expect(enemy.hp).toBeGreaterThan(1);
}); });
@ -128,7 +129,7 @@ describe("Abilities - Dry Skin", () => {
enemy.hp = 1; enemy.hp = 1;
game.override.enemyMoveset([Moves.PROTECT, Moves.PROTECT, Moves.PROTECT, Moves.PROTECT]); game.override.enemyMoveset([Moves.PROTECT, Moves.PROTECT, Moves.PROTECT, Moves.PROTECT]);
game.move.select(Moves.WATER_GUN); game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_GUN));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(enemy.hp).toBe(1); expect(enemy.hp).toBe(1);
}); });
@ -144,14 +145,14 @@ describe("Abilities - Dry Skin", () => {
enemy.hp = 1; enemy.hp = 1;
// first turn // first turn
game.move.select(Moves.WATER_SHURIKEN); game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_SHURIKEN));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
const healthGainedFromWaterShuriken = enemy.hp - 1; const healthGainedFromWaterShuriken = enemy.hp - 1;
enemy.hp = 1; enemy.hp = 1;
// second turn // second turn
game.move.select(Moves.WATER_GUN); game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_GUN));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
const healthGainedFromWaterGun = enemy.hp - 1; const healthGainedFromWaterGun = enemy.hp - 1;

View File

@ -1,15 +1,16 @@
import { BattlerIndex } from "#app/battle"; import { Species } from "#app/enums/species.js";
import { StatusEffect } from "#app/data/status-effect"; import GameManager from "#test/utils/gameManager";
import { BattlerTagType } from "#app/enums/battler-tag-type";
import { Species } from "#app/enums/species";
import { MovePhase } from "#app/phases/move-phase";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { StatusEffect } from "#app/data/status-effect.js";
import { BattlerTagType } from "#app/enums/battler-tag-type.js";
import { BattlerIndex } from "#app/battle.js";
import { MovePhase } from "#app/phases/move-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
describe("Abilities - Flash Fire", () => { describe("Abilities - Flash Fire", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -37,35 +38,35 @@ describe("Abilities - Flash Fire", () => {
}); });
it("immune to Fire-type moves", async () => { it("immune to Fire-type moves", async() => {
game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset(SPLASH_ONLY); game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset(SPLASH_ONLY);
await game.startBattle([Species.BLISSEY]); await game.startBattle([Species.BLISSEY]);
const blissey = game.scene.getPlayerPokemon()!; const blissey = game.scene.getPlayerPokemon()!;
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(blissey.hp).toBe(blissey.getMaxHp()); expect(blissey.hp).toBe(blissey.getMaxHp());
}, 20000); }, 20000);
it("not activate if the Pokémon is protected from the Fire-type move", async () => { it("not activate if the Pokémon is protected from the Fire-type move", async() => {
game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset([Moves.PROTECT]); game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset([Moves.PROTECT]);
await game.startBattle([Species.BLISSEY]); await game.startBattle([Species.BLISSEY]);
const blissey = game.scene.getPlayerPokemon()!; const blissey = game.scene.getPlayerPokemon()!;
game.move.select(Moves.PROTECT); game.doAttack(getMovePosition(game.scene, 0, Moves.PROTECT));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(blissey!.getTag(BattlerTagType.FIRE_BOOST)).toBeUndefined(); expect(blissey!.getTag(BattlerTagType.FIRE_BOOST)).toBeUndefined();
}, 20000); }, 20000);
it("activated by Will-O-Wisp", async () => { it("activated by Will-O-Wisp", async() => {
game.override.enemyMoveset(Array(4).fill(Moves.WILL_O_WISP)).moveset(SPLASH_ONLY); game.override.enemyMoveset(Array(4).fill(Moves.WILL_O_WISP)).moveset(SPLASH_ONLY);
await game.startBattle([Species.BLISSEY]); await game.startBattle([Species.BLISSEY]);
const blissey = game.scene.getPlayerPokemon()!; const blissey = game.scene.getPlayerPokemon()!;
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.move.forceHit(); await game.move.forceHit();
await game.phaseInterceptor.to(MovePhase, false); await game.phaseInterceptor.to(MovePhase, false);
await game.move.forceHit(); await game.move.forceHit();
@ -74,25 +75,25 @@ describe("Abilities - Flash Fire", () => {
expect(blissey!.getTag(BattlerTagType.FIRE_BOOST)).toBeDefined(); expect(blissey!.getTag(BattlerTagType.FIRE_BOOST)).toBeDefined();
}, 20000); }, 20000);
it("activated after being frozen", async () => { it("activated after being frozen", async() => {
game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset(SPLASH_ONLY); game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset(SPLASH_ONLY);
game.override.statusEffect(StatusEffect.FREEZE); game.override.statusEffect(StatusEffect.FREEZE);
await game.startBattle([Species.BLISSEY]); await game.startBattle([Species.BLISSEY]);
const blissey = game.scene.getPlayerPokemon()!; const blissey = game.scene.getPlayerPokemon()!;
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(blissey!.getTag(BattlerTagType.FIRE_BOOST)).toBeDefined(); expect(blissey!.getTag(BattlerTagType.FIRE_BOOST)).toBeDefined();
}, 20000); }, 20000);
it("not passing with baton pass", async () => { it("not passing with baton pass", async() => {
game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset([Moves.BATON_PASS]); game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset([Moves.BATON_PASS]);
await game.startBattle([Species.BLISSEY, Species.CHANSEY]); await game.startBattle([Species.BLISSEY, Species.CHANSEY]);
// ensure use baton pass after enemy moved // ensure use baton pass after enemy moved
game.move.select(Moves.BATON_PASS); game.doAttack(getMovePosition(game.scene, 0, Moves.BATON_PASS));
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
@ -103,7 +104,7 @@ describe("Abilities - Flash Fire", () => {
expect(chansey!.getTag(BattlerTagType.FIRE_BOOST)).toBeUndefined(); expect(chansey!.getTag(BattlerTagType.FIRE_BOOST)).toBeUndefined();
}, 20000); }, 20000);
it("boosts Fire-type move when the ability is activated", async () => { it("boosts Fire-type move when the ability is activated", async() => {
game.override.enemyMoveset(Array(4).fill(Moves.FIRE_PLEDGE)).moveset([Moves.EMBER, Moves.SPLASH]); game.override.enemyMoveset(Array(4).fill(Moves.FIRE_PLEDGE)).moveset([Moves.EMBER, Moves.SPLASH]);
game.override.enemyAbility(Abilities.FLASH_FIRE).ability(Abilities.NONE); game.override.enemyAbility(Abilities.FLASH_FIRE).ability(Abilities.NONE);
await game.startBattle([Species.BLISSEY]); await game.startBattle([Species.BLISSEY]);
@ -112,7 +113,7 @@ describe("Abilities - Flash Fire", () => {
blissey.hp = initialHP; blissey.hp = initialHP;
// first turn // first turn
game.move.select(Moves.EMBER); game.doAttack(getMovePosition(game.scene, 0, Moves.EMBER));
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
const originalDmg = initialHP - blissey.hp; const originalDmg = initialHP - blissey.hp;
@ -121,7 +122,7 @@ describe("Abilities - Flash Fire", () => {
blissey.hp = initialHP; blissey.hp = initialHP;
// second turn // second turn
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
const flashFireDmg = initialHP - blissey.hp; const flashFireDmg = initialHP - blissey.hp;

View File

@ -1,18 +1,19 @@
import { BattleStat } from "#app/data/battle-stat"; import { BattlerTagType } from "#app/enums/battler-tag-type.js";
import { BattlerTagType } from "#app/enums/battler-tag-type";
import { StatusEffect } from "#app/enums/status-effect";
import Pokemon from "#app/field/pokemon";
import { BerryPhase } from "#app/phases/berry-phase";
import { MoveEndPhase } from "#app/phases/move-end-phase";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { TurnStartPhase } from "#app/phases/turn-start-phase";
import GameManager from "#app/test/utils/gameManager"; import GameManager from "#app/test/utils/gameManager";
import { getMovePosition } from "#app/test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { SPLASH_ONLY } from "../utils/testUtils"; import { SPLASH_ONLY } from "../utils/testUtils";
import { BattleStat } from "#app/data/battle-stat.js";
import { StatusEffect } from "#app/enums/status-effect.js";
import Pokemon from "#app/field/pokemon.js";
import { BerryPhase } from "#app/phases/berry-phase.js";
import { MoveEndPhase } from "#app/phases/move-end-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
import { TurnStartPhase } from "#app/phases/turn-start-phase.js";
describe("Abilities - Gulp Missile", () => { describe("Abilities - Gulp Missile", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -29,7 +30,7 @@ describe("Abilities - Gulp Missile", () => {
* @returns The effect damage of Gulp Missile * @returns The effect damage of Gulp Missile
*/ */
const getEffectDamage = (pokemon: Pokemon): number => { const getEffectDamage = (pokemon: Pokemon): number => {
return Math.max(1, Math.floor(pokemon.getMaxHp() * 1 / 4)); return Math.max(1, Math.floor(pokemon.getMaxHp() * 1/4));
}; };
beforeAll(() => { beforeAll(() => {
@ -57,9 +58,9 @@ describe("Abilities - Gulp Missile", () => {
await game.startBattle([Species.CRAMORANT]); await game.startBattle([Species.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.scene.getPlayerPokemon()!;
game.move.select(Moves.DIVE); game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE));
await game.toNextTurn(); await game.toNextTurn();
game.move.select(Moves.DIVE); game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
expect(cramorant.getHpRatio()).toBeGreaterThanOrEqual(.5); expect(cramorant.getHpRatio()).toBeGreaterThanOrEqual(.5);
@ -74,7 +75,7 @@ describe("Abilities - Gulp Missile", () => {
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.49); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.49);
expect(cramorant.getHpRatio()).toBe(.49); expect(cramorant.getHpRatio()).toBe(.49);
game.move.select(Moves.SURF); game.doAttack(getMovePosition(game.scene, 0, Moves.SURF));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_PIKACHU)).toBeDefined(); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_PIKACHU)).toBeDefined();
@ -85,7 +86,7 @@ describe("Abilities - Gulp Missile", () => {
await game.startBattle([Species.CRAMORANT, Species.MAGIKARP]); await game.startBattle([Species.CRAMORANT, Species.MAGIKARP]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.scene.getPlayerPokemon()!;
game.move.select(Moves.SURF); game.doAttack(getMovePosition(game.scene, 0, Moves.SURF));
await game.toNextTurn(); await game.toNextTurn();
game.doSwitchPokemon(1); game.doSwitchPokemon(1);
@ -100,7 +101,7 @@ describe("Abilities - Gulp Missile", () => {
await game.startBattle([Species.CRAMORANT]); await game.startBattle([Species.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.scene.getPlayerPokemon()!;
game.move.select(Moves.DIVE); game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined(); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
@ -114,7 +115,7 @@ describe("Abilities - Gulp Missile", () => {
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.scene.getEnemyPokemon()!;
vi.spyOn(enemy, "damageAndUpdate"); vi.spyOn(enemy, "damageAndUpdate");
game.move.select(Moves.SURF); game.doAttack(getMovePosition(game.scene, 0, Moves.SURF));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(enemy.damageAndUpdate).toHaveReturnedWith(getEffectDamage(enemy)); expect(enemy.damageAndUpdate).toHaveReturnedWith(getEffectDamage(enemy));
@ -127,7 +128,7 @@ describe("Abilities - Gulp Missile", () => {
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.scene.getPlayerPokemon()!;
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
game.move.select(Moves.SURF); game.doAttack(getMovePosition(game.scene, 0, Moves.SURF));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined(); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
@ -149,7 +150,7 @@ describe("Abilities - Gulp Missile", () => {
vi.spyOn(enemy, "damageAndUpdate"); vi.spyOn(enemy, "damageAndUpdate");
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
game.move.select(Moves.SURF); game.doAttack(getMovePosition(game.scene, 0, Moves.SURF));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined(); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
@ -173,7 +174,7 @@ describe("Abilities - Gulp Missile", () => {
vi.spyOn(enemy, "damageAndUpdate"); vi.spyOn(enemy, "damageAndUpdate");
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.45); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.45);
game.move.select(Moves.SURF); game.doAttack(getMovePosition(game.scene, 0, Moves.SURF));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_PIKACHU)).toBeDefined(); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_PIKACHU)).toBeDefined();
@ -193,7 +194,7 @@ describe("Abilities - Gulp Missile", () => {
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.scene.getPlayerPokemon()!;
game.move.select(Moves.DIVE); game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE));
await game.phaseInterceptor.to(BerryPhase, false); await game.phaseInterceptor.to(BerryPhase, false);
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined(); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
@ -209,7 +210,7 @@ describe("Abilities - Gulp Missile", () => {
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
game.move.select(Moves.SURF); game.doAttack(getMovePosition(game.scene, 0, Moves.SURF));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
const enemyHpPreEffect = enemy.hp; const enemyHpPreEffect = enemy.hp;
@ -231,7 +232,7 @@ describe("Abilities - Gulp Missile", () => {
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.scene.getPlayerPokemon()!;
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
game.move.select(Moves.SURF); game.doAttack(getMovePosition(game.scene, 0, Moves.SURF));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined(); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
@ -251,7 +252,7 @@ describe("Abilities - Gulp Missile", () => {
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.scene.getPlayerPokemon()!;
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55);
game.move.select(Moves.SURF); game.doAttack(getMovePosition(game.scene, 0, Moves.SURF));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined(); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined();
@ -268,7 +269,7 @@ describe("Abilities - Gulp Missile", () => {
game.override.enemyAbility(Abilities.TRACE); game.override.enemyAbility(Abilities.TRACE);
await game.startBattle([Species.CRAMORANT]); await game.startBattle([Species.CRAMORANT]);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnStartPhase); await game.phaseInterceptor.to(TurnStartPhase);
expect(game.scene.getEnemyPokemon()?.hasAbility(Abilities.GULP_MISSILE)).toBe(false); expect(game.scene.getEnemyPokemon()?.hasAbility(Abilities.GULP_MISSILE)).toBe(false);

View File

@ -1,13 +1,13 @@
import { Species } from "#app/enums/species"; import { Species } from "#app/enums/species.js";
import { StatusEffect } from "#app/enums/status-effect"; import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase"; import GameManager from "#test/utils/gameManager";
import { toDmgValue } from "#app/utils"; import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import { StatusEffect } from "#app/enums/status-effect.js";
describe("Abilities - Heatproof", () => { describe("Abilities - Heatproof", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -45,14 +45,14 @@ describe("Abilities - Heatproof", () => {
const initialHP = 1000; const initialHP = 1000;
enemy.hp = initialHP; enemy.hp = initialHP;
game.move.select(Moves.FLAMETHROWER); game.doAttack(getMovePosition(game.scene, 0, Moves.FLAMETHROWER));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
const heatproofDamage = initialHP - enemy.hp; const heatproofDamage = initialHP - enemy.hp;
enemy.hp = initialHP; enemy.hp = initialHP;
game.override.enemyAbility(Abilities.BALL_FETCH); game.override.enemyAbility(Abilities.BALL_FETCH);
game.move.select(Moves.FLAMETHROWER); game.doAttack(getMovePosition(game.scene, 0, Moves.FLAMETHROWER));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
const regularDamage = initialHP - enemy.hp; const regularDamage = initialHP - enemy.hp;
@ -68,10 +68,10 @@ describe("Abilities - Heatproof", () => {
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.scene.getEnemyPokemon()!;
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.toNextTurn(); await game.toNextTurn();
// Normal burn damage is /16 // Normal burn damage is /16
expect(enemy.hp).toBe(enemy.getMaxHp() - toDmgValue(enemy.getMaxHp() / 32)); expect(enemy.hp).toBe(enemy.getMaxHp() - Math.floor(enemy.getMaxHp() / 32));
}); });
}); });

View File

@ -1,14 +1,15 @@
import { allMoves } from "#app/data/move"; import { allMoves } from "#app/data/move.js";
import { Abilities } from "#app/enums/abilities"; import { Abilities } from "#app/enums/abilities.js";
import { Stat } from "#app/enums/stat"; import { Stat } from "#app/enums/stat.js";
import { DamagePhase } from "#app/phases/damage-phase"; import GameManager from "#test/utils/gameManager";
import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import { DamagePhase } from "#app/phases/damage-phase.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
describe("Abilities - Hustle", () => { describe("Abilities - Hustle", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -43,7 +44,7 @@ describe("Abilities - Hustle", () => {
vi.spyOn(pikachu, "getBattleStat"); vi.spyOn(pikachu, "getBattleStat");
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.move.forceHit(); await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase); await game.phaseInterceptor.to(DamagePhase);
@ -56,7 +57,7 @@ describe("Abilities - Hustle", () => {
vi.spyOn(pikachu, "getAccuracyMultiplier"); vi.spyOn(pikachu, "getAccuracyMultiplier");
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(MoveEffectPhase); await game.phaseInterceptor.to(MoveEffectPhase);
expect(pikachu.getAccuracyMultiplier).toHaveReturnedWith(0.8); expect(pikachu.getAccuracyMultiplier).toHaveReturnedWith(0.8);
@ -70,7 +71,7 @@ describe("Abilities - Hustle", () => {
vi.spyOn(pikachu, "getBattleStat"); vi.spyOn(pikachu, "getBattleStat");
vi.spyOn(pikachu, "getAccuracyMultiplier"); vi.spyOn(pikachu, "getAccuracyMultiplier");
game.move.select(Moves.GIGA_DRAIN); game.doAttack(getMovePosition(game.scene, 0, Moves.GIGA_DRAIN));
await game.phaseInterceptor.to(DamagePhase); await game.phaseInterceptor.to(DamagePhase);
expect(pikachu.getBattleStat).toHaveReturnedWith(spatk); expect(pikachu.getBattleStat).toHaveReturnedWith(spatk);
@ -88,7 +89,7 @@ describe("Abilities - Hustle", () => {
vi.spyOn(pikachu, "getAccuracyMultiplier"); vi.spyOn(pikachu, "getAccuracyMultiplier");
vi.spyOn(allMoves[Moves.FISSURE], "calculateBattleAccuracy"); vi.spyOn(allMoves[Moves.FISSURE], "calculateBattleAccuracy");
game.move.select(Moves.FISSURE); game.doAttack(getMovePosition(game.scene, 0, Moves.FISSURE));
await game.phaseInterceptor.to(DamagePhase); await game.phaseInterceptor.to(DamagePhase);
expect(enemyPokemon.turnData.damageTaken).toBe(enemyPokemon.getMaxHp()); expect(enemyPokemon.turnData.damageTaken).toBe(enemyPokemon.getMaxHp());

View File

@ -3,6 +3,7 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager"; import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils"; import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@ -39,16 +40,16 @@ describe("Abilities - Hyper Cutter", () => {
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.scene.getEnemyPokemon()!;
game.move.select(Moves.OCTOLOCK); game.doAttack(getMovePosition(game.scene, 0, Moves.OCTOLOCK));
await game.toNextTurn(); await game.toNextTurn();
game.move.select(Moves.DEFOG); game.doAttack(getMovePosition(game.scene, 0, Moves.DEFOG));
await game.toNextTurn(); await game.toNextTurn();
game.move.select(Moves.NOBLE_ROAR); game.doAttack(getMovePosition(game.scene, 0, Moves.NOBLE_ROAR));
await game.toNextTurn(); await game.toNextTurn();
game.move.select(Moves.SAND_ATTACK); game.doAttack(getMovePosition(game.scene, 0, Moves.SAND_ATTACK));
await game.toNextTurn(); await game.toNextTurn();
game.override.moveset([Moves.STRING_SHOT]); game.override.moveset([Moves.STRING_SHOT]);
game.move.select(Moves.STRING_SHOT); game.doAttack(getMovePosition(game.scene, 0, Moves.STRING_SHOT));
await game.toNextTurn(); await game.toNextTurn();
expect(enemy.summonData.battleStats[BattleStat.ATK]).toEqual(0); expect(enemy.summonData.battleStats[BattleStat.ATK]).toEqual(0);

View File

@ -1,15 +1,16 @@
import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import GameManager from "#test/utils/gameManager";
import { MoveEndPhase } from "#app/phases/move-end-phase"; import { getMovePosition } from "#test/utils/gameManagerUtils";
import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { TurnInitPhase } from "#app/phases/turn-init-phase";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
import { MoveEndPhase } from "#app/phases/move-end-phase.js";
import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
import { TurnInitPhase } from "#app/phases/turn-init-phase.js";
describe("Abilities - Ice Face", () => { describe("Abilities - Ice Face", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -38,7 +39,7 @@ describe("Abilities - Ice Face", () => {
it("takes no damage from physical move and transforms to Noice", async () => { it("takes no damage from physical move and transforms to Noice", async () => {
await game.startBattle([Species.HITMONLEE]); await game.startBattle([Species.HITMONLEE]);
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
@ -54,7 +55,7 @@ describe("Abilities - Ice Face", () => {
game.override.enemyLevel(1); game.override.enemyLevel(1);
await game.startBattle([Species.HITMONLEE]); await game.startBattle([Species.HITMONLEE]);
game.move.select(Moves.SURGING_STRIKES); game.doAttack(getMovePosition(game.scene, 0, Moves.SURGING_STRIKES));
const eiscue = game.scene.getEnemyPokemon()!; const eiscue = game.scene.getEnemyPokemon()!;
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeDefined(); expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeDefined();
@ -80,7 +81,7 @@ describe("Abilities - Ice Face", () => {
it("takes damage from special moves", async () => { it("takes damage from special moves", async () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
game.move.select(Moves.ICE_BEAM); game.doAttack(getMovePosition(game.scene, 0, Moves.ICE_BEAM));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
@ -94,7 +95,7 @@ describe("Abilities - Ice Face", () => {
it("takes effects from status moves", async () => { it("takes effects from status moves", async () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
game.move.select(Moves.TOXIC_THREAD); game.doAttack(getMovePosition(game.scene, 0, Moves.TOXIC_THREAD));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
@ -110,7 +111,7 @@ describe("Abilities - Ice Face", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
game.move.select(Moves.QUICK_ATTACK); game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
@ -132,7 +133,7 @@ describe("Abilities - Ice Face", () => {
await game.startBattle([Species.EISCUE, Species.NINJASK]); await game.startBattle([Species.EISCUE, Species.NINJASK]);
game.move.select(Moves.SNOWSCAPE); game.doAttack(getMovePosition(game.scene, 0, Moves.SNOWSCAPE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
let eiscue = game.scene.getPlayerPokemon()!; let eiscue = game.scene.getPlayerPokemon()!;
@ -159,7 +160,7 @@ describe("Abilities - Ice Face", () => {
await game.startBattle([Species.EISCUE]); await game.startBattle([Species.EISCUE]);
game.move.select(Moves.HAIL); game.doAttack(getMovePosition(game.scene, 0, Moves.HAIL));
const eiscue = game.scene.getPlayerPokemon()!; const eiscue = game.scene.getPlayerPokemon()!;
await game.phaseInterceptor.to(QuietFormChangePhase); await game.phaseInterceptor.to(QuietFormChangePhase);
@ -178,7 +179,7 @@ describe("Abilities - Ice Face", () => {
await game.startBattle([Species.EISCUE, Species.MAGIKARP]); await game.startBattle([Species.EISCUE, Species.MAGIKARP]);
game.move.select(Moves.ICE_BEAM); game.doAttack(getMovePosition(game.scene, 0, Moves.ICE_BEAM));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
let eiscue = game.scene.getPlayerPokemon()!; let eiscue = game.scene.getPlayerPokemon()!;
@ -212,7 +213,7 @@ describe("Abilities - Ice Face", () => {
expect(eiscue.formIndex).toBe(noiceForm); expect(eiscue.formIndex).toBe(noiceForm);
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined();
game.move.select(Moves.ICE_BEAM); game.doAttack(getMovePosition(game.scene, 0, Moves.ICE_BEAM));
await game.doKillOpponents(); await game.doKillOpponents();
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
game.doSelectModifier(); game.doSelectModifier();
@ -227,7 +228,7 @@ describe("Abilities - Ice Face", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
game.move.select(Moves.GASTRO_ACID); game.doAttack(getMovePosition(game.scene, 0, Moves.GASTRO_ACID));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -243,7 +244,7 @@ describe("Abilities - Ice Face", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
game.move.select(Moves.SKILL_SWAP); game.doAttack(getMovePosition(game.scene, 0, Moves.SKILL_SWAP));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -259,7 +260,7 @@ describe("Abilities - Ice Face", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
game.move.select(Moves.SIMPLE_BEAM); game.doAttack(getMovePosition(game.scene, 0, Moves.SIMPLE_BEAM));
await game.phaseInterceptor.to(TurnInitPhase); await game.phaseInterceptor.to(TurnInitPhase);

View File

@ -1,21 +1,22 @@
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import Phaser from "phaser";
import GameManager from "#test/utils/gameManager";
import { Mode } from "#app/ui/ui";
import { BattleStat } from "#app/data/battle-stat"; import { BattleStat } from "#app/data/battle-stat";
import { generateStarter, getMovePosition } from "#test/utils/gameManagerUtils";
import { Command } from "#app/ui/command-ui-handler";
import { Status, StatusEffect } from "#app/data/status-effect"; import { Status, StatusEffect } from "#app/data/status-effect";
import { GameModes, getGameMode } from "#app/game-mode"; import { GameModes, getGameMode } from "#app/game-mode";
import { CommandPhase } from "#app/phases/command-phase";
import { DamagePhase } from "#app/phases/damage-phase";
import { EncounterPhase } from "#app/phases/encounter-phase";
import { EnemyCommandPhase } from "#app/phases/enemy-command-phase";
import { SelectStarterPhase } from "#app/phases/select-starter-phase";
import { TurnInitPhase } from "#app/phases/turn-init-phase";
import { Mode } from "#app/ui/ui";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { generateStarter } from "#test/utils/gameManagerUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils"; import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser"; import { CommandPhase } from "#app/phases/command-phase.js";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { DamagePhase } from "#app/phases/damage-phase.js";
import { EncounterPhase } from "#app/phases/encounter-phase.js";
import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js";
import { SelectStarterPhase } from "#app/phases/select-starter-phase.js";
import { TurnInitPhase } from "#app/phases/turn-init-phase.js";
describe("Abilities - Intimidate", () => { describe("Abilities - Intimidate", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -216,7 +217,13 @@ describe("Abilities - Intimidate", () => {
let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1);
game.move.select(Moves.AERIAL_ACE); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(DamagePhase); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(DamagePhase);
await game.killPokemon(game.scene.currentBattle.enemyParty[0]); await game.killPokemon(game.scene.currentBattle.enemyParty[0]);
expect(game.scene.currentBattle.enemyParty[0].isFainted()).toBe(true); expect(game.scene.currentBattle.enemyParty[0].isFainted()).toBe(true);
@ -236,7 +243,13 @@ describe("Abilities - Intimidate", () => {
let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1);
game.move.select(Moves.AERIAL_ACE); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
console.log("===to new turn==="); console.log("===to new turn===");
await game.toNextTurn(); await game.toNextTurn();
battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
@ -255,7 +268,13 @@ describe("Abilities - Intimidate", () => {
let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1);
game.move.select(Moves.AERIAL_ACE); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
console.log("===to new turn==="); console.log("===to new turn===");
await game.toNextTurn(); await game.toNextTurn();
battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
@ -263,7 +282,13 @@ describe("Abilities - Intimidate", () => {
battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;
expect(battleStatsOpponent[BattleStat.ATK]).toBe(0); expect(battleStatsOpponent[BattleStat.ATK]).toBe(0);
game.move.select(Moves.AERIAL_ACE); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
console.log("===to new turn==="); console.log("===to new turn===");
await game.toNextTurn(); await game.toNextTurn();
battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
@ -282,7 +307,13 @@ describe("Abilities - Intimidate", () => {
let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1);
game.move.select(Moves.AERIAL_ACE); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
console.log("===to new turn==="); console.log("===to new turn===");
await game.toNextTurn(); await game.toNextTurn();
battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
@ -290,7 +321,13 @@ describe("Abilities - Intimidate", () => {
battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;
expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1);
game.move.select(Moves.AERIAL_ACE); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
console.log("===to new turn==="); console.log("===to new turn===");
await game.toNextTurn(); await game.toNextTurn();
battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;

View File

@ -1,10 +1,10 @@
import { BattleStat } from "#app/data/battle-stat"; import { BattleStat } from "#app/data/battle-stat";
import { CommandPhase } from "#app/phases/command-phase"; import GameManager from "#test/utils/gameManager";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { CommandPhase } from "#app/phases/command-phase.js";
describe("Abilities - Intrepid Sword", () => { describe("Abilities - Intrepid Sword", () => {

View File

@ -1,17 +1,18 @@
import { allMoves } from "#app/data/move"; import { allMoves } from "#app/data/move.js";
import { Type } from "#app/data/type"; import { Type } from "#app/data/type.js";
import { Weather, WeatherType } from "#app/data/weather"; import { Weather, WeatherType } from "#app/data/weather.js";
import { PlayerPokemon } from "#app/field/pokemon"; import { PlayerPokemon } from "#app/field/pokemon.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { Biome } from "#enums/biome"; import { Biome } from "#enums/biome";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
const TIMEOUT = 20 * 1000; const TIMEOUT = 20 * 1000;
@ -48,7 +49,7 @@ describe("Abilities - Libero", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH);
@ -66,12 +67,12 @@ describe("Abilities - Libero", () => {
let leadPokemon = game.scene.getPlayerPokemon()!; let leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH);
game.move.select(Moves.AGILITY); game.doAttack(getMovePosition(game.scene, 0, Moves.AGILITY));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(leadPokemon.summonData.abilitiesApplied.filter((a) => a === Abilities.LIBERO)).toHaveLength(1); expect(leadPokemon.summonData.abilitiesApplied.filter((a) => a === Abilities.LIBERO)).toHaveLength(1);
@ -88,7 +89,7 @@ describe("Abilities - Libero", () => {
leadPokemon = game.scene.getPlayerPokemon()!; leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH);
@ -107,7 +108,7 @@ describe("Abilities - Libero", () => {
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.scene.arena.weather = new Weather(WeatherType.SUNNY); game.scene.arena.weather = new Weather(WeatherType.SUNNY);
game.move.select(Moves.WEATHER_BALL); game.doAttack(getMovePosition(game.scene, 0, Moves.WEATHER_BALL));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.LIBERO); expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.LIBERO);
@ -130,7 +131,7 @@ describe("Abilities - Libero", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.LIBERO); expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.LIBERO);
@ -153,7 +154,7 @@ describe("Abilities - Libero", () => {
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.scene.arena.biomeType = Biome.MOUNTAIN; game.scene.arena.biomeType = Biome.MOUNTAIN;
game.move.select(Moves.NATURE_POWER); game.doAttack(getMovePosition(game.scene, 0, Moves.NATURE_POWER));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.AIR_SLASH); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.AIR_SLASH);
@ -171,7 +172,7 @@ describe("Abilities - Libero", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.DIG); game.doAttack(getMovePosition(game.scene, 0, Moves.DIG));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.DIG); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.DIG);
@ -190,7 +191,7 @@ describe("Abilities - Libero", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.move.forceMiss(); await game.move.forceMiss();
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -212,7 +213,7 @@ describe("Abilities - Libero", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE);
@ -231,7 +232,7 @@ describe("Abilities - Libero", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE);
@ -250,7 +251,7 @@ describe("Abilities - Libero", () => {
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
leadPokemon.summonData.types = [allMoves[Moves.SPLASH].defaultType]; leadPokemon.summonData.types = [allMoves[Moves.SPLASH].defaultType];
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO);
@ -270,7 +271,7 @@ describe("Abilities - Libero", () => {
vi.spyOn(leadPokemon, "isTerastallized").mockReturnValue(true); vi.spyOn(leadPokemon, "isTerastallized").mockReturnValue(true);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO);
@ -288,7 +289,7 @@ describe("Abilities - Libero", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.STRUGGLE); game.doAttack(getMovePosition(game.scene, 0, Moves.STRUGGLE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO);
@ -306,7 +307,7 @@ describe("Abilities - Libero", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.BURN_UP); game.doAttack(getMovePosition(game.scene, 0, Moves.BURN_UP));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO);
@ -325,7 +326,7 @@ describe("Abilities - Libero", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.TRICK_OR_TREAT); game.doAttack(getMovePosition(game.scene, 0, Moves.TRICK_OR_TREAT));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TRICK_OR_TREAT); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TRICK_OR_TREAT);
@ -343,7 +344,7 @@ describe("Abilities - Libero", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.CURSE); game.doAttack(getMovePosition(game.scene, 0, Moves.CURSE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.CURSE); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.CURSE);

View File

@ -1,16 +1,17 @@
import { ArenaTagSide, getArenaTag } from "#app/data/arena-tag";
import { StatusEffect, getStatusEffectCatchRateMultiplier } from "#app/data/status-effect";
import { WeatherType } from "#app/data/weather";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
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 { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import Phaser from "phaser";
import GameManager from "#test/utils/gameManager";
import { Species } from "#enums/species";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
import { Moves } from "#enums/moves";
import { ArenaTagType } from "#enums/arena-tag-type";
import { ArenaTagSide, getArenaTag } from "#app/data/arena-tag";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities";
import { WeatherType } from "#app/data/weather.js";
import { StatusEffect, getStatusEffectCatchRateMultiplier } from "#app/data/status-effect";
import { BattlerTagType } from "#enums/battler-tag-type";
import { SPLASH_ONLY } from "#test/utils/testUtils";
const TIMEOUT = 20 * 1000; // 20 sec timeout const TIMEOUT = 20 * 1000; // 20 sec timeout
@ -57,7 +58,7 @@ describe("Abilities - Magic Guard", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).toBeDefined(); expect(enemyPokemon).toBeDefined();
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -81,7 +82,7 @@ describe("Abilities - Magic Guard", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -98,14 +99,14 @@ describe("Abilities - Magic Guard", () => {
it( it(
"ability effect should not persist when the ability is replaced", "ability effect should not persist when the ability is replaced",
async () => { async () => {
game.override.enemyMoveset([Moves.WORRY_SEED, Moves.WORRY_SEED, Moves.WORRY_SEED, Moves.WORRY_SEED]); game.override.enemyMoveset([Moves.WORRY_SEED,Moves.WORRY_SEED,Moves.WORRY_SEED,Moves.WORRY_SEED]);
game.override.statusEffect(StatusEffect.POISON); game.override.statusEffect(StatusEffect.POISON);
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -125,7 +126,7 @@ describe("Abilities - Magic Guard", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
@ -149,7 +150,7 @@ describe("Abilities - Magic Guard", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
@ -179,7 +180,7 @@ describe("Abilities - Magic Guard", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
@ -205,7 +206,7 @@ describe("Abilities - Magic Guard", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
@ -232,7 +233,7 @@ describe("Abilities - Magic Guard", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
game.move.select(Moves.CURSE); game.doAttack(getMovePosition(game.scene, 0, Moves.CURSE));
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
@ -256,7 +257,7 @@ describe("Abilities - Magic Guard", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
game.move.select(Moves.HIGH_JUMP_KICK); game.doAttack(getMovePosition(game.scene, 0, Moves.HIGH_JUMP_KICK));
await game.move.forceMiss(); await game.move.forceMiss();
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -275,7 +276,7 @@ describe("Abilities - Magic Guard", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
game.move.select(Moves.TAKE_DOWN); game.doAttack(getMovePosition(game.scene, 0, Moves.TAKE_DOWN));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -293,7 +294,7 @@ describe("Abilities - Magic Guard", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
game.move.select(Moves.STRUGGLE); game.doAttack(getMovePosition(game.scene, 0, Moves.STRUGGLE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -312,7 +313,7 @@ describe("Abilities - Magic Guard", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
game.move.select(Moves.STEEL_BEAM); game.doAttack(getMovePosition(game.scene, 0, Moves.STEEL_BEAM));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -328,7 +329,7 @@ describe("Abilities - Magic Guard", () => {
it("Magic Guard does not prevent self-damage from confusion", async () => { it("Magic Guard does not prevent self-damage from confusion", async () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
game.move.select(Moves.CHARM); game.doAttack(getMovePosition(game.scene, 0, Moves.CHARM));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
}); });
@ -340,7 +341,7 @@ describe("Abilities - Magic Guard", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
game.move.select(Moves.BELLY_DRUM); game.doAttack(getMovePosition(game.scene, 0, Moves.BELLY_DRUM));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -352,7 +353,7 @@ describe("Abilities - Magic Guard", () => {
}, TIMEOUT }, TIMEOUT
); );
it("Magic Guard prevents damage from abilities with PostTurnHurtIfSleepingAbAttr", async () => { it("Magic Guard prevents damage from abilities with PostTurnHurtIfSleepingAbAttr", async() => {
//Tests the ability Bad Dreams //Tests the ability Bad Dreams
game.override.statusEffect(StatusEffect.SLEEP); game.override.statusEffect(StatusEffect.SLEEP);
//enemy pokemon is given Spore just in case player pokemon somehow awakens during test //enemy pokemon is given Spore just in case player pokemon somehow awakens during test
@ -363,7 +364,7 @@ describe("Abilities - Magic Guard", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -377,7 +378,7 @@ describe("Abilities - Magic Guard", () => {
}, TIMEOUT }, TIMEOUT
); );
it("Magic Guard prevents damage from abilities with PostFaintContactDamageAbAttr", async () => { it("Magic Guard prevents damage from abilities with PostFaintContactDamageAbAttr", async() => {
//Tests the abilities Innards Out/Aftermath //Tests the abilities Innards Out/Aftermath
game.override.moveset([Moves.TACKLE]); game.override.moveset([Moves.TACKLE]);
game.override.enemyAbility(Abilities.AFTERMATH); game.override.enemyAbility(Abilities.AFTERMATH);
@ -389,7 +390,7 @@ describe("Abilities - Magic Guard", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
enemyPokemon.hp = 1; enemyPokemon.hp = 1;
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
/** /**
@ -402,7 +403,7 @@ describe("Abilities - Magic Guard", () => {
}, TIMEOUT }, TIMEOUT
); );
it("Magic Guard prevents damage from abilities with PostDefendContactDamageAbAttr", async () => { it("Magic Guard prevents damage from abilities with PostDefendContactDamageAbAttr", async() => {
//Tests the abilities Iron Barbs/Rough Skin //Tests the abilities Iron Barbs/Rough Skin
game.override.moveset([Moves.TACKLE]); game.override.moveset([Moves.TACKLE]);
game.override.enemyAbility(Abilities.IRON_BARBS); game.override.enemyAbility(Abilities.IRON_BARBS);
@ -413,7 +414,7 @@ describe("Abilities - Magic Guard", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
/** /**
@ -426,7 +427,7 @@ describe("Abilities - Magic Guard", () => {
}, TIMEOUT }, TIMEOUT
); );
it("Magic Guard prevents damage from abilities with ReverseDrainAbAttr", async () => { it("Magic Guard prevents damage from abilities with ReverseDrainAbAttr", async() => {
//Tests the ability Liquid Ooze //Tests the ability Liquid Ooze
game.override.moveset([Moves.ABSORB]); game.override.moveset([Moves.ABSORB]);
game.override.enemyAbility(Abilities.LIQUID_OOZE); game.override.enemyAbility(Abilities.LIQUID_OOZE);
@ -437,7 +438,7 @@ describe("Abilities - Magic Guard", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
game.move.select(Moves.ABSORB); game.doAttack(getMovePosition(game.scene, 0, Moves.ABSORB));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
/** /**
@ -450,14 +451,14 @@ describe("Abilities - Magic Guard", () => {
}, TIMEOUT }, TIMEOUT
); );
it("Magic Guard prevents HP loss from abilities with PostWeatherLapseDamageAbAttr", async () => { it("Magic Guard prevents HP loss from abilities with PostWeatherLapseDamageAbAttr", async() => {
//Tests the abilities Solar Power/Dry Skin //Tests the abilities Solar Power/Dry Skin
game.override.passiveAbility(Abilities.SOLAR_POWER); game.override.passiveAbility(Abilities.SOLAR_POWER);
game.override.weather(WeatherType.SUNNY); game.override.weather(WeatherType.SUNNY);
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
/** /**

View File

@ -1,13 +1,17 @@
import { BattleStat } from "#app/data/battle-stat"; import { BattleStat } from "#app/data/battle-stat";
import { Stat } from "#app/data/pokemon-stat"; import { Stat } from "#app/data/pokemon-stat";
import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; import GameManager from "#test/utils/gameManager";
import { VictoryPhase } from "#app/phases/victory-phase"; import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Command } from "#app/ui/command-ui-handler";
import { Mode } from "#app/ui/ui";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { CommandPhase } from "#app/phases/command-phase.js";
import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js";
import { VictoryPhase } from "#app/phases/victory-phase.js";
describe("Abilities - Moxie", () => { describe("Abilities - Moxie", () => {
@ -33,10 +37,10 @@ describe("Abilities - Moxie", () => {
game.override.ability(Abilities.MOXIE); game.override.ability(Abilities.MOXIE);
game.override.startingLevel(2000); game.override.startingLevel(2000);
game.override.moveset([moveToUse]); game.override.moveset([moveToUse]);
game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]);
}); });
it("MOXIE", async () => { it("MOXIE", async() => {
const moveToUse = Moves.AERIAL_ACE; const moveToUse = Moves.AERIAL_ACE;
await game.startBattle([ await game.startBattle([
Species.MIGHTYENA, Species.MIGHTYENA,
@ -46,7 +50,13 @@ describe("Abilities - Moxie", () => {
let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
expect(battleStatsPokemon[Stat.ATK]).toBe(0); expect(battleStatsPokemon[Stat.ATK]).toBe(0);
game.move.select(moveToUse); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(VictoryPhase); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(VictoryPhase);
battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
expect(battleStatsPokemon[BattleStat.ATK]).toBe(1); expect(battleStatsPokemon[BattleStat.ATK]).toBe(1);

View File

@ -1,10 +1,11 @@
import { BattleStat } from "#app/data/battle-stat"; import { MovePhase } from "#app/phases/move-phase.js";
import { MovePhase } from "#app/phases/move-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase"; import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { BattleStat } from "#app/data/battle-stat";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@ -41,14 +42,14 @@ describe("Abilities - Mycelium Might", () => {
* https://www.smogon.com/forums/threads/scarlet-violet-battle-mechanics-research.3709545/page-24 * https://www.smogon.com/forums/threads/scarlet-violet-battle-mechanics-research.3709545/page-24
**/ **/
it("will move last in its priority bracket and ignore protective abilities", async () => { it("If a Pokemon with Mycelium Might uses a status move, it will always move last but the status move will ignore protective abilities", async() => {
await game.startBattle([Species.REGIELEKI]); await game.startBattle([ Species.REGIELEKI ]);
const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex();
const enemyPokemon = game.scene.getEnemyPokemon(); const enemyPokemon = game.scene.getEnemyPokemon();
const enemyIndex = enemyPokemon?.getBattlerIndex(); const enemyIndex = enemyPokemon?.getBattlerIndex();
game.move.select(Moves.BABY_DOLL_EYES); game.doAttack(getMovePosition(game.scene, 0, Moves.BABY_DOLL_EYES));
await game.phaseInterceptor.to(MovePhase, false); await game.phaseInterceptor.to(MovePhase, false);
// The opponent Pokemon (without Mycelium Might) goes first despite having lower speed than the player Pokemon. // The opponent Pokemon (without Mycelium Might) goes first despite having lower speed than the player Pokemon.
@ -63,15 +64,15 @@ describe("Abilities - Mycelium Might", () => {
expect(enemyPokemon?.summonData.battleStats[BattleStat.ATK]).toBe(-1); expect(enemyPokemon?.summonData.battleStats[BattleStat.ATK]).toBe(-1);
}, 20000); }, 20000);
it("will still go first if a status move that is in a higher priority bracket than the opponent's move is used", async () => { it("Pokemon with Mycelium Might will go first if a status move that is in a higher priority bracket than the opponent's move is used", async() => {
game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
await game.startBattle([Species.REGIELEKI]); await game.startBattle([ Species.REGIELEKI ]);
const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex();
const enemyPokemon = game.scene.getEnemyPokemon(); const enemyPokemon = game.scene.getEnemyPokemon();
const enemyIndex = enemyPokemon?.getBattlerIndex(); const enemyIndex = enemyPokemon?.getBattlerIndex();
game.move.select(Moves.BABY_DOLL_EYES); game.doAttack(getMovePosition(game.scene, 0, Moves.BABY_DOLL_EYES));
await game.phaseInterceptor.to(MovePhase, false); await game.phaseInterceptor.to(MovePhase, false);
// The player Pokemon (with M.M.) goes first because its move is still within a higher priority bracket than its opponent. // The player Pokemon (with M.M.) goes first because its move is still within a higher priority bracket than its opponent.
@ -85,13 +86,13 @@ describe("Abilities - Mycelium Might", () => {
expect(enemyPokemon?.summonData.battleStats[BattleStat.ATK]).toBe(-1); expect(enemyPokemon?.summonData.battleStats[BattleStat.ATK]).toBe(-1);
}, 20000); }, 20000);
it("will not affect non-status moves", async () => { it("Order is established normally if the Pokemon uses a non-status move", async() => {
await game.startBattle([Species.REGIELEKI]); await game.startBattle([ Species.REGIELEKI ]);
const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex();
const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex();
game.move.select(Moves.QUICK_ATTACK); game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK));
await game.phaseInterceptor.to(MovePhase, false); await game.phaseInterceptor.to(MovePhase, false);
// The player Pokemon (with M.M.) goes first because it has a higher speed and did not use a status move. // The player Pokemon (with M.M.) goes first because it has a higher speed and did not use a status move.

View File

@ -1,21 +1,21 @@
import { BattleStat } from "#app/data/battle-stat"; import { BattleStat } from "#app/data/battle-stat.js";
import { StatusEffect } from "#app/data/status-effect"; import { StatusEffect } from "#app/data/status-effect.js";
import { Type } from "#app/data/type"; import { Type } from "#app/data/type.js";
import { BattlerTagType } from "#app/enums/battler-tag-type"; import { BattlerTagType } from "#app/enums/battler-tag-type.js";
import { BerryPhase } from "#app/phases/berry-phase";
import { CommandPhase } from "#app/phases/command-phase";
import { DamagePhase } from "#app/phases/damage-phase";
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { MoveEndPhase } from "#app/phases/move-end-phase";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { toDmgValue } from "#app/utils";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import { BerryPhase } from "#app/phases/berry-phase.js";
import { CommandPhase } from "#app/phases/command-phase.js";
import { DamagePhase } from "#app/phases/damage-phase.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
import { MoveEndPhase } from "#app/phases/move-end-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
const TIMEOUT = 20 * 1000; const TIMEOUT = 20 * 1000;
@ -60,7 +60,7 @@ describe("Abilities - Parental Bond", () => {
let enemyStartingHp = enemyPokemon.hp; let enemyStartingHp = enemyPokemon.hp;
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(MoveEffectPhase, false); await game.phaseInterceptor.to(MoveEffectPhase, false);
@ -73,7 +73,7 @@ describe("Abilities - Parental Bond", () => {
const secondStrikeDamage = enemyStartingHp - enemyPokemon.hp; const secondStrikeDamage = enemyStartingHp - enemyPokemon.hp;
expect(leadPokemon.turnData.hitCount).toBe(2); expect(leadPokemon.turnData.hitCount).toBe(2);
expect(secondStrikeDamage).toBe(toDmgValue(0.25 * firstStrikeDamage)); expect(secondStrikeDamage).toBe(Math.ceil(0.25 * firstStrikeDamage));
}, TIMEOUT }, TIMEOUT
); );
@ -91,7 +91,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.POWER_UP_PUNCH); game.doAttack(getMovePosition(game.scene, 0, Moves.POWER_UP_PUNCH));
await game.phaseInterceptor.to(BerryPhase, false); await game.phaseInterceptor.to(BerryPhase, false);
@ -113,7 +113,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.BABY_DOLL_EYES); game.doAttack(getMovePosition(game.scene, 0, Moves.BABY_DOLL_EYES));
await game.phaseInterceptor.to(BerryPhase, false); await game.phaseInterceptor.to(BerryPhase, false);
expect(enemyPokemon.summonData.battleStats[BattleStat.ATK]).toBe(-1); expect(enemyPokemon.summonData.battleStats[BattleStat.ATK]).toBe(-1);
@ -133,7 +133,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.DOUBLE_HIT); game.doAttack(getMovePosition(game.scene, 0, Moves.DOUBLE_HIT));
await game.move.forceHit(); await game.move.forceHit();
await game.phaseInterceptor.to(BerryPhase, false); await game.phaseInterceptor.to(BerryPhase, false);
@ -155,7 +155,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.SELF_DESTRUCT); game.doAttack(getMovePosition(game.scene, 0, Moves.SELF_DESTRUCT));
await game.phaseInterceptor.to(DamagePhase, false); await game.phaseInterceptor.to(DamagePhase, false);
@ -176,7 +176,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.ROLLOUT); game.doAttack(getMovePosition(game.scene, 0, Moves.ROLLOUT));
await game.move.forceHit(); await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase, false); await game.phaseInterceptor.to(DamagePhase, false);
@ -200,7 +200,7 @@ describe("Abilities - Parental Bond", () => {
const enemyStartingHp = enemyPokemon.hp; const enemyStartingHp = enemyPokemon.hp;
game.move.select(Moves.DRAGON_RAGE); game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE));
await game.phaseInterceptor.to(BerryPhase, false); await game.phaseInterceptor.to(BerryPhase, false);
expect(enemyPokemon.hp).toBe(enemyStartingHp - 80); expect(enemyPokemon.hp).toBe(enemyStartingHp - 80);
@ -211,7 +211,7 @@ describe("Abilities - Parental Bond", () => {
"ability should not apply multiplier to counter moves", "ability should not apply multiplier to counter moves",
async () => { async () => {
game.override.moveset([Moves.COUNTER]); game.override.moveset([Moves.COUNTER]);
game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]);
await game.startBattle([Species.CHARIZARD]); await game.startBattle([Species.CHARIZARD]);
@ -224,14 +224,14 @@ describe("Abilities - Parental Bond", () => {
const playerStartingHp = leadPokemon.hp; const playerStartingHp = leadPokemon.hp;
const enemyStartingHp = enemyPokemon.hp; const enemyStartingHp = enemyPokemon.hp;
game.move.select(Moves.COUNTER); game.doAttack(getMovePosition(game.scene, 0, Moves.COUNTER));
await game.phaseInterceptor.to(DamagePhase); await game.phaseInterceptor.to(DamagePhase);
const playerDamage = playerStartingHp - leadPokemon.hp; const playerDamage = playerStartingHp - leadPokemon.hp;
await game.phaseInterceptor.to(BerryPhase, false); await game.phaseInterceptor.to(BerryPhase, false);
expect(enemyPokemon.hp).toBe(enemyStartingHp - 4 * playerDamage); expect(enemyPokemon.hp).toBe(enemyStartingHp - 4*playerDamage);
}, TIMEOUT }, TIMEOUT
); );
@ -251,10 +251,10 @@ describe("Abilities - Parental Bond", () => {
expect(enemyPokemon.length).toBe(2); expect(enemyPokemon.length).toBe(2);
enemyPokemon.forEach(p => expect(p).not.toBe(undefined)); enemyPokemon.forEach(p => expect(p).not.toBe(undefined));
game.move.select(Moves.EARTHQUAKE); game.doAttack(getMovePosition(game.scene, 0, Moves.EARTHQUAKE));
await game.phaseInterceptor.to(CommandPhase); await game.phaseInterceptor.to(CommandPhase);
game.move.select(Moves.EARTHQUAKE, 1); game.doAttack(getMovePosition(game.scene, 1, Moves.EARTHQUAKE));
await game.phaseInterceptor.to(BerryPhase, false); await game.phaseInterceptor.to(BerryPhase, false);
playerPokemon.forEach(p => expect(p.turnData.hitCount).toBe(1)); playerPokemon.forEach(p => expect(p.turnData.hitCount).toBe(1));
@ -274,7 +274,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.EARTHQUAKE); game.doAttack(getMovePosition(game.scene, 0, Moves.EARTHQUAKE));
await game.phaseInterceptor.to(DamagePhase, false); await game.phaseInterceptor.to(DamagePhase, false);
expect(leadPokemon.turnData.hitCount).toBe(2); expect(leadPokemon.turnData.hitCount).toBe(2);
@ -294,7 +294,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.MIND_BLOWN); game.doAttack(getMovePosition(game.scene, 0, Moves.MIND_BLOWN));
await game.phaseInterceptor.to(DamagePhase, false); await game.phaseInterceptor.to(DamagePhase, false);
@ -303,7 +303,7 @@ describe("Abilities - Parental Bond", () => {
// This test will time out if the user faints // This test will time out if the user faints
await game.phaseInterceptor.to(BerryPhase, false); await game.phaseInterceptor.to(BerryPhase, false);
expect(leadPokemon.hp).toBe(toDmgValue(leadPokemon.getMaxHp() / 2)); expect(leadPokemon.hp).toBe(Math.floor(leadPokemon.getMaxHp()/2));
}, TIMEOUT }, TIMEOUT
); );
@ -320,7 +320,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.BURN_UP); game.doAttack(getMovePosition(game.scene, 0, Moves.BURN_UP));
await game.phaseInterceptor.to(DamagePhase); await game.phaseInterceptor.to(DamagePhase);
@ -338,7 +338,7 @@ describe("Abilities - Parental Bond", () => {
"Moves boosted by this ability and Multi-Lens should strike 4 times", "Moves boosted by this ability and Multi-Lens should strike 4 times",
async () => { async () => {
game.override.moveset([Moves.TACKLE]); game.override.moveset([Moves.TACKLE]);
game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); game.override.startingHeldItems([{name: "MULTI_LENS", count: 1}]);
await game.startBattle([Species.CHARIZARD]); await game.startBattle([Species.CHARIZARD]);
@ -348,7 +348,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(DamagePhase); await game.phaseInterceptor.to(DamagePhase);
@ -360,7 +360,7 @@ describe("Abilities - Parental Bond", () => {
"Super Fang boosted by this ability and Multi-Lens should strike twice", "Super Fang boosted by this ability and Multi-Lens should strike twice",
async () => { async () => {
game.override.moveset([Moves.SUPER_FANG]); game.override.moveset([Moves.SUPER_FANG]);
game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); game.override.startingHeldItems([{name: "MULTI_LENS", count: 1}]);
await game.startBattle([Species.CHARIZARD]); await game.startBattle([Species.CHARIZARD]);
@ -372,7 +372,7 @@ describe("Abilities - Parental Bond", () => {
const enemyStartingHp = enemyPokemon.hp; const enemyStartingHp = enemyPokemon.hp;
game.move.select(Moves.SUPER_FANG); game.doAttack(getMovePosition(game.scene, 0, Moves.SUPER_FANG));
await game.move.forceHit(); await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase); await game.phaseInterceptor.to(DamagePhase);
@ -389,7 +389,7 @@ describe("Abilities - Parental Bond", () => {
"Seismic Toss boosted by this ability and Multi-Lens should strike twice", "Seismic Toss boosted by this ability and Multi-Lens should strike twice",
async () => { async () => {
game.override.moveset([Moves.SEISMIC_TOSS]); game.override.moveset([Moves.SEISMIC_TOSS]);
game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); game.override.startingHeldItems([{name: "MULTI_LENS", count: 1}]);
await game.startBattle([Species.CHARIZARD]); await game.startBattle([Species.CHARIZARD]);
@ -401,7 +401,7 @@ describe("Abilities - Parental Bond", () => {
const enemyStartingHp = enemyPokemon.hp; const enemyStartingHp = enemyPokemon.hp;
game.move.select(Moves.SEISMIC_TOSS); game.doAttack(getMovePosition(game.scene, 0, Moves.SEISMIC_TOSS));
await game.move.forceHit(); await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase); await game.phaseInterceptor.to(DamagePhase);
@ -427,7 +427,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.HYPER_BEAM); game.doAttack(getMovePosition(game.scene, 0, Moves.HYPER_BEAM));
await game.move.forceHit(); await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase); await game.phaseInterceptor.to(DamagePhase);
@ -455,7 +455,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.ANCHOR_SHOT); game.doAttack(getMovePosition(game.scene, 0, Moves.ANCHOR_SHOT));
await game.move.forceHit(); await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase); await game.phaseInterceptor.to(DamagePhase);
@ -485,7 +485,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.SMACK_DOWN); game.doAttack(getMovePosition(game.scene, 0, Moves.SMACK_DOWN));
await game.move.forceHit(); await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase); await game.phaseInterceptor.to(DamagePhase);
@ -512,7 +512,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.U_TURN); game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN));
await game.move.forceHit(); await game.move.forceHit();
await game.phaseInterceptor.to(MoveEffectPhase); await game.phaseInterceptor.to(MoveEffectPhase);
@ -536,7 +536,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.WAKE_UP_SLAP); game.doAttack(getMovePosition(game.scene, 0, Moves.WAKE_UP_SLAP));
await game.move.forceHit(); await game.move.forceHit();
await game.phaseInterceptor.to(DamagePhase); await game.phaseInterceptor.to(DamagePhase);
@ -554,7 +554,7 @@ describe("Abilities - Parental Bond", () => {
"ability should not cause user to hit into King's Shield more than once", "ability should not cause user to hit into King's Shield more than once",
async () => { async () => {
game.override.moveset([Moves.TACKLE]); game.override.moveset([Moves.TACKLE]);
game.override.enemyMoveset([Moves.KINGS_SHIELD, Moves.KINGS_SHIELD, Moves.KINGS_SHIELD, Moves.KINGS_SHIELD]); game.override.enemyMoveset([Moves.KINGS_SHIELD,Moves.KINGS_SHIELD,Moves.KINGS_SHIELD,Moves.KINGS_SHIELD]);
await game.startBattle([Species.CHARIZARD]); await game.startBattle([Species.CHARIZARD]);
@ -564,7 +564,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(BerryPhase, false); await game.phaseInterceptor.to(BerryPhase, false);
@ -586,7 +586,7 @@ describe("Abilities - Parental Bond", () => {
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
game.move.select(Moves.WATER_GUN); game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_GUN));
await game.phaseInterceptor.to(BerryPhase, false); await game.phaseInterceptor.to(BerryPhase, false);
@ -599,7 +599,7 @@ describe("Abilities - Parental Bond", () => {
async () => { async () => {
game.override.battleType("double"); game.override.battleType("double");
game.override.moveset([Moves.EARTHQUAKE, Moves.SPLASH]); game.override.moveset([Moves.EARTHQUAKE, Moves.SPLASH]);
game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); game.override.startingHeldItems([{name: "MULTI_LENS", count: 1}]);
await game.startBattle([Species.CHARIZARD, Species.PIDGEOT]); await game.startBattle([Species.CHARIZARD, Species.PIDGEOT]);
@ -613,10 +613,10 @@ describe("Abilities - Parental Bond", () => {
const enemyStartingHp = enemyPokemon.map(p => p.hp); const enemyStartingHp = enemyPokemon.map(p => p.hp);
game.move.select(Moves.EARTHQUAKE); game.doAttack(getMovePosition(game.scene, 0, Moves.EARTHQUAKE));
await game.phaseInterceptor.to(CommandPhase); await game.phaseInterceptor.to(CommandPhase);
game.move.select(Moves.SPLASH, 1); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(MoveEffectPhase, false); await game.phaseInterceptor.to(MoveEffectPhase, false);
@ -625,7 +625,7 @@ describe("Abilities - Parental Bond", () => {
await game.phaseInterceptor.to(BerryPhase, false); await game.phaseInterceptor.to(BerryPhase, false);
enemyPokemon.forEach((p, i) => expect(enemyStartingHp[i] - p.hp).toBe(2 * enemyFirstHitDamage[i])); enemyPokemon.forEach((p, i) => expect(enemyStartingHp[i] - p.hp).toBe(2*enemyFirstHitDamage[i]));
}, TIMEOUT }, TIMEOUT
); );

View File

@ -1,14 +1,15 @@
import { BattlerIndex } from "#app/battle"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { StatusEffect } from "#app/data/status-effect";
import { Abilities } from "#app/enums/abilities";
import { CommandPhase } from "#app/phases/command-phase";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "../utils/testUtils"; import { Species } from "#enums/species";
import { Moves } from "#enums/moves";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { StatusEffect } from "#app/data/status-effect.js";
import { allAbilities } from "#app/data/ability.js";
import { Abilities } from "#app/enums/abilities.js";
import { BattlerIndex } from "#app/battle.js";
import { CommandPhase } from "#app/phases/command-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
describe("Abilities - Pastel Veil", () => { describe("Abilities - Pastel Veil", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -26,49 +27,50 @@ describe("Abilities - Pastel Veil", () => {
beforeEach(() => { beforeEach(() => {
game = new GameManager(phaserGame); game = new GameManager(phaserGame);
game.override game.override.battleType("double");
.battleType("double") game.override.moveset([Moves.SPLASH]);
.moveset([Moves.TOXIC_THREAD, Moves.SPLASH]) game.override.enemyAbility(Abilities.BALL_FETCH);
.enemyAbility(Abilities.BALL_FETCH) game.override.enemySpecies(Species.MAGIKARP);
.enemySpecies(Species.SUNKERN) game.override.enemyMoveset([Moves.TOXIC_THREAD, Moves.TOXIC_THREAD, Moves.TOXIC_THREAD, Moves.TOXIC_THREAD]);
.enemyMoveset(SPLASH_ONLY);
}); });
it("prevents the user and its allies from being afflicted by poison", async () => { it("prevents the user and its allies from being afflicted by poison", async () => {
await game.startBattle([Species.MAGIKARP, Species.GALAR_PONYTA]); await game.startBattle([Species.GALAR_PONYTA, Species.MAGIKARP]);
const ponyta = game.scene.getPlayerField()[1]; const ponyta = game.scene.getPlayerField()[0];
const magikarp = game.scene.getPlayerField()[0];
ponyta.abilityIndex = 1; vi.spyOn(ponyta, "getAbility").mockReturnValue(allAbilities[Abilities.PASTEL_VEIL]);
expect(ponyta.hasAbility(Abilities.PASTEL_VEIL)).toBe(true); expect(ponyta.hasAbility(Abilities.PASTEL_VEIL)).toBe(true);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
game.move.select(Moves.TOXIC_THREAD, 1, BattlerIndex.PLAYER); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(magikarp.status?.effect).toBeUndefined(); expect(game.scene.getPlayerField().every(p => p.status?.effect)).toBe(false);
}); });
it("it heals the poisoned status condition of allies if user is sent out into battle", async () => { it("it heals the poisoned status condition of allies if user is sent out into battle", async () => {
await game.startBattle([Species.MAGIKARP, Species.FEEBAS, Species.GALAR_PONYTA]); await game.startBattle([Species.MAGIKARP, Species.MAGIKARP, Species.GALAR_PONYTA]);
const ponyta = game.scene.getParty()[2]; const ponyta = game.scene.getParty().find(p => p.species.speciesId === Species.GALAR_PONYTA)!;
const magikarp = game.scene.getPlayerField()[0];
ponyta.abilityIndex = 1; vi.spyOn(ponyta, "getAbility").mockReturnValue(allAbilities[Abilities.PASTEL_VEIL]);
expect(ponyta.hasAbility(Abilities.PASTEL_VEIL)).toBe(true); expect(ponyta.hasAbility(Abilities.PASTEL_VEIL)).toBe(true);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
game.move.select(Moves.TOXIC_THREAD, 1, BattlerIndex.PLAYER); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(magikarp.status?.effect).toBe(StatusEffect.POISON); expect(game.scene.getPlayerField().some(p => p.status?.effect === StatusEffect.POISON)).toBe(true);
const poisonedMon = game.scene.getPlayerField().find(p => p.status?.effect === StatusEffect.POISON);
await game.phaseInterceptor.to(CommandPhase); await game.phaseInterceptor.to(CommandPhase);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, (poisonedMon!.getBattlerIndex() as BattlerIndex.PLAYER | BattlerIndex.PLAYER_2), Moves.SPLASH));
game.doSwitchPokemon(2); game.doSwitchPokemon(2);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(magikarp.status?.effect).toBeUndefined(); expect(game.scene.getPlayerField().every(p => p.status?.effect)).toBe(false);
}); });
}); });

View File

@ -1,10 +1,11 @@
import { Status, StatusEffect } from "#app/data/status-effect"; import { Status, StatusEffect } from "#app/data/status-effect.js";
import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager"; import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
const TIMEOUT = 20 * 1000; const TIMEOUT = 20 * 1000;
@ -52,7 +53,7 @@ describe("Abilities - POWER CONSTRUCT", () => {
zygarde!.status = new Status(StatusEffect.FAINT); zygarde!.status = new Status(StatusEffect.FAINT);
expect(zygarde!.isFainted()).toBe(true); expect(zygarde!.isFainted()).toBe(true);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.doKillOpponents(); await game.doKillOpponents();
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
game.doSelectModifier(); game.doSelectModifier();

View File

@ -1,13 +1,14 @@
import { allMoves } from "#app/data/move"; import { allMoves } from "#app/data/move.js";
import { Abilities } from "#app/enums/abilities"; import { Abilities } from "#app/enums/abilities.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import GameManager from "#test/utils/gameManager";
import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
describe("Abilities - Power Spot", () => { describe("Abilities - Power Spot", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -41,8 +42,8 @@ describe("Abilities - Power Spot", () => {
vi.spyOn(moveToCheck, "calculateBattlePower"); vi.spyOn(moveToCheck, "calculateBattlePower");
await game.startBattle([Species.REGIELEKI, Species.STONJOURNER]); await game.startBattle([Species.REGIELEKI, Species.STONJOURNER]);
game.move.select(Moves.DAZZLING_GLEAM); game.doAttack(getMovePosition(game.scene, 0, Moves.DAZZLING_GLEAM));
game.move.select(Moves.SPLASH, 1); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(MoveEffectPhase); await game.phaseInterceptor.to(MoveEffectPhase);
expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower * powerSpotMultiplier); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower * powerSpotMultiplier);
@ -55,8 +56,8 @@ describe("Abilities - Power Spot", () => {
vi.spyOn(moveToCheck, "calculateBattlePower"); vi.spyOn(moveToCheck, "calculateBattlePower");
await game.startBattle([Species.REGIELEKI, Species.STONJOURNER]); await game.startBattle([Species.REGIELEKI, Species.STONJOURNER]);
game.move.select(Moves.BREAKING_SWIPE); game.doAttack(getMovePosition(game.scene, 0, Moves.BREAKING_SWIPE));
game.move.select(Moves.SPLASH, 1); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(MoveEffectPhase); await game.phaseInterceptor.to(MoveEffectPhase);
expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower * powerSpotMultiplier); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower * powerSpotMultiplier);
@ -69,8 +70,8 @@ describe("Abilities - Power Spot", () => {
vi.spyOn(moveToCheck, "calculateBattlePower"); vi.spyOn(moveToCheck, "calculateBattlePower");
await game.startBattle([Species.STONJOURNER, Species.REGIELEKI]); await game.startBattle([Species.STONJOURNER, Species.REGIELEKI]);
game.move.select(Moves.BREAKING_SWIPE); game.doAttack(getMovePosition(game.scene, 0, Moves.BREAKING_SWIPE));
game.move.select(Moves.SPLASH, 1); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower);

View File

@ -1,17 +1,18 @@
import { allMoves } from "#app/data/move"; import { allMoves } from "#app/data/move.js";
import { Type } from "#app/data/type"; import { Type } from "#app/data/type.js";
import { Weather, WeatherType } from "#app/data/weather"; import { Weather, WeatherType } from "#app/data/weather.js";
import { PlayerPokemon } from "#app/field/pokemon"; import { PlayerPokemon } from "#app/field/pokemon.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { Biome } from "#enums/biome"; import { Biome } from "#enums/biome";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
const TIMEOUT = 20 * 1000; const TIMEOUT = 20 * 1000;
@ -48,7 +49,7 @@ describe("Abilities - Protean", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH);
@ -66,12 +67,12 @@ describe("Abilities - Protean", () => {
let leadPokemon = game.scene.getPlayerPokemon()!; let leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH);
game.move.select(Moves.AGILITY); game.doAttack(getMovePosition(game.scene, 0, Moves.AGILITY));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(leadPokemon.summonData.abilitiesApplied.filter((a) => a === Abilities.PROTEAN)).toHaveLength(1); expect(leadPokemon.summonData.abilitiesApplied.filter((a) => a === Abilities.PROTEAN)).toHaveLength(1);
@ -88,7 +89,7 @@ describe("Abilities - Protean", () => {
leadPokemon = game.scene.getPlayerPokemon()!; leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH);
@ -107,7 +108,7 @@ describe("Abilities - Protean", () => {
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.scene.arena.weather = new Weather(WeatherType.SUNNY); game.scene.arena.weather = new Weather(WeatherType.SUNNY);
game.move.select(Moves.WEATHER_BALL); game.doAttack(getMovePosition(game.scene, 0, Moves.WEATHER_BALL));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.PROTEAN); expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.PROTEAN);
@ -130,7 +131,7 @@ describe("Abilities - Protean", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.PROTEAN); expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.PROTEAN);
@ -153,7 +154,7 @@ describe("Abilities - Protean", () => {
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.scene.arena.biomeType = Biome.MOUNTAIN; game.scene.arena.biomeType = Biome.MOUNTAIN;
game.move.select(Moves.NATURE_POWER); game.doAttack(getMovePosition(game.scene, 0, Moves.NATURE_POWER));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.AIR_SLASH); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.AIR_SLASH);
@ -171,7 +172,7 @@ describe("Abilities - Protean", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.DIG); game.doAttack(getMovePosition(game.scene, 0, Moves.DIG));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.DIG); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.DIG);
@ -190,7 +191,7 @@ describe("Abilities - Protean", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.move.forceMiss(); await game.move.forceMiss();
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -212,7 +213,7 @@ describe("Abilities - Protean", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE);
@ -231,7 +232,7 @@ describe("Abilities - Protean", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE);
@ -250,7 +251,7 @@ describe("Abilities - Protean", () => {
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
leadPokemon.summonData.types = [allMoves[Moves.SPLASH].defaultType]; leadPokemon.summonData.types = [allMoves[Moves.SPLASH].defaultType];
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN);
@ -270,7 +271,7 @@ describe("Abilities - Protean", () => {
vi.spyOn(leadPokemon, "isTerastallized").mockReturnValue(true); vi.spyOn(leadPokemon, "isTerastallized").mockReturnValue(true);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN);
@ -288,7 +289,7 @@ describe("Abilities - Protean", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.STRUGGLE); game.doAttack(getMovePosition(game.scene, 0, Moves.STRUGGLE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN);
@ -306,7 +307,7 @@ describe("Abilities - Protean", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.BURN_UP); game.doAttack(getMovePosition(game.scene, 0, Moves.BURN_UP));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN);
@ -325,7 +326,7 @@ describe("Abilities - Protean", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.TRICK_OR_TREAT); game.doAttack(getMovePosition(game.scene, 0, Moves.TRICK_OR_TREAT));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TRICK_OR_TREAT); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TRICK_OR_TREAT);
@ -343,7 +344,7 @@ describe("Abilities - Protean", () => {
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
game.move.select(Moves.CURSE); game.doAttack(getMovePosition(game.scene, 0, Moves.CURSE));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.CURSE); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.CURSE);

View File

@ -1,11 +1,12 @@
import { allAbilities, BypassSpeedChanceAbAttr } from "#app/data/ability"; import { allAbilities, BypassSpeedChanceAbAttr } from "#app/data/ability";
import { FaintPhase } from "#app/phases/faint-phase"; import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import { FaintPhase } from "#app/phases/faint-phase.js";
describe("Abilities - Quick Draw", () => { describe("Abilities - Quick Draw", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -46,7 +47,7 @@ describe("Abilities - Quick Draw", () => {
pokemon.hp = 1; pokemon.hp = 1;
enemy.hp = 1; enemy.hp = 1;
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(FaintPhase, false); await game.phaseInterceptor.to(FaintPhase, false);
expect(pokemon.isFainted()).toBe(false); expect(pokemon.isFainted()).toBe(false);
@ -66,7 +67,7 @@ describe("Abilities - Quick Draw", () => {
pokemon.hp = 1; pokemon.hp = 1;
enemy.hp = 1; enemy.hp = 1;
game.move.select(Moves.TAIL_WHIP); game.doAttack(getMovePosition(game.scene, 0, Moves.TAIL_WHIP));
await game.phaseInterceptor.to(FaintPhase, false); await game.phaseInterceptor.to(FaintPhase, false);
expect(pokemon.isFainted()).toBe(true); expect(pokemon.isFainted()).toBe(true);
@ -86,7 +87,7 @@ describe("Abilities - Quick Draw", () => {
pokemon.hp = 1; pokemon.hp = 1;
enemy.hp = 1; enemy.hp = 1;
game.move.select(Moves.TACKLE); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
await game.phaseInterceptor.to(FaintPhase, false); await game.phaseInterceptor.to(FaintPhase, false);
expect(pokemon.isFainted()).toBe(true); expect(pokemon.isFainted()).toBe(true);

View File

@ -1,10 +1,11 @@
import { WeatherType } from "#app/enums/weather-type"; import GameManager from "#test/utils/gameManager";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { WeatherType } from "#app/enums/weather-type.js";
describe("Abilities - Sand Spit", () => { describe("Abilities - Sand Spit", () => {
@ -34,21 +35,21 @@ describe("Abilities - Sand Spit", () => {
game.override.moveset([Moves.SPLASH, Moves.COIL]); game.override.moveset([Moves.SPLASH, Moves.COIL]);
}); });
it("should trigger when hit with damaging move", async () => { it("should trigger when hit with damaging move", async() => {
game.override.enemyMoveset(Array(4).fill(Moves.TACKLE)); game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
await game.startBattle(); await game.startBattle();
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.toNextTurn(); await game.toNextTurn();
expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SANDSTORM); expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SANDSTORM);
}, 20000); }, 20000);
it("should not trigger when targetted with status moves", async () => { it("should not trigger when targetted with status moves", async() => {
game.override.enemyMoveset(Array(4).fill(Moves.GROWL)); game.override.enemyMoveset(Array(4).fill(Moves.GROWL));
await game.startBattle(); await game.startBattle();
game.move.select(Moves.COIL); game.doAttack(getMovePosition(game.scene, 0, Moves.COIL));
await game.toNextTurn(); await game.toNextTurn();
expect(game.scene.arena.weather?.weatherType).not.toBe(WeatherType.SANDSTORM); expect(game.scene.arena.weather?.weatherType).not.toBe(WeatherType.SANDSTORM);

View File

@ -1,15 +1,16 @@
import { BattleStatMultiplierAbAttr, allAbilities } from "#app/data/ability"; import { BattleStatMultiplierAbAttr, allAbilities } from "#app/data/ability.js";
import { BattleStat } from "#app/data/battle-stat"; import { BattleStat } from "#app/data/battle-stat.js";
import { WeatherType } from "#app/data/weather"; import { WeatherType } from "#app/data/weather.js";
import { CommandPhase } from "#app/phases/command-phase";
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { MoveEndPhase } from "#app/phases/move-end-phase";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { CommandPhase } from "#app/phases/command-phase.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
import { MoveEndPhase } from "#app/phases/move-end-phase.js";
const TIMEOUT = 20 * 1000; const TIMEOUT = 20 * 1000;
@ -51,7 +52,7 @@ describe("Abilities - Sand Veil", () => {
const sandVeilAttr = allAbilities[Abilities.SAND_VEIL].getAttrs(BattleStatMultiplierAbAttr)[0]; const sandVeilAttr = allAbilities[Abilities.SAND_VEIL].getAttrs(BattleStatMultiplierAbAttr)[0];
vi.spyOn(sandVeilAttr, "applyBattleStat").mockImplementation( vi.spyOn(sandVeilAttr, "applyBattleStat").mockImplementation(
(pokemon, passive, simulated, battleStat, statValue, args) => { (pokemon, passive, battleStat, statValue, args) => {
if (battleStat === BattleStat.EVA && game.scene.arena.weather?.weatherType === WeatherType.SANDSTORM) { if (battleStat === BattleStat.EVA && game.scene.arena.weather?.weatherType === WeatherType.SANDSTORM) {
statValue.value *= -1; // will make all attacks miss statValue.value *= -1; // will make all attacks miss
return true; return true;
@ -63,11 +64,11 @@ describe("Abilities - Sand Veil", () => {
expect(leadPokemon[0].hasAbility(Abilities.SAND_VEIL)).toBe(true); expect(leadPokemon[0].hasAbility(Abilities.SAND_VEIL)).toBe(true);
expect(leadPokemon[1].hasAbility(Abilities.SAND_VEIL)).toBe(false); expect(leadPokemon[1].hasAbility(Abilities.SAND_VEIL)).toBe(false);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(CommandPhase); await game.phaseInterceptor.to(CommandPhase);
game.move.select(Moves.SPLASH, 1); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(MoveEffectPhase, false); await game.phaseInterceptor.to(MoveEffectPhase, false);

View File

@ -1,14 +1,15 @@
import { BattleStat } from "#app/data/battle-stat"; import { BattleStat } from "#app/data/battle-stat.js";
import { TerrainType } from "#app/data/terrain"; import { TerrainType } from "#app/data/terrain.js";
import { MoveEndPhase } from "#app/phases/move-end-phase"; import GameManager from "#test/utils/gameManager";
import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { MoveEndPhase } from "#app/phases/move-end-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
// See also: TypeImmunityAbAttr // See also: TypeImmunityAbAttr
describe("Abilities - Sap Sipper", () => { describe("Abilities - Sap Sipper", () => {
@ -31,7 +32,7 @@ describe("Abilities - Sap Sipper", () => {
game.override.disableCrits(); game.override.disableCrits();
}); });
it("raise attack 1 level and block effects when activated against a grass attack", async () => { it("raise attack 1 level and block effects when activated against a grass attack", async() => {
const moveToUse = Moves.LEAFAGE; const moveToUse = Moves.LEAFAGE;
const enemyAbility = Abilities.SAP_SIPPER; const enemyAbility = Abilities.SAP_SIPPER;
@ -44,7 +45,7 @@ describe("Abilities - Sap Sipper", () => {
const startingOppHp = game.scene.currentBattle.enemyParty[0].hp; const startingOppHp = game.scene.currentBattle.enemyParty[0].hp;
game.move.select(moveToUse); game.doAttack(getMovePosition(game.scene, 0, moveToUse));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -52,7 +53,7 @@ describe("Abilities - Sap Sipper", () => {
expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(1); expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(1);
}); });
it("raise attack 1 level and block effects when activated against a grass status move", async () => { it("raise attack 1 level and block effects when activated against a grass status move", async() => {
const moveToUse = Moves.SPORE; const moveToUse = Moves.SPORE;
const enemyAbility = Abilities.SAP_SIPPER; const enemyAbility = Abilities.SAP_SIPPER;
@ -63,7 +64,7 @@ describe("Abilities - Sap Sipper", () => {
await game.startBattle(); await game.startBattle();
game.move.select(moveToUse); game.doAttack(getMovePosition(game.scene, 0, moveToUse));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -71,7 +72,7 @@ describe("Abilities - Sap Sipper", () => {
expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(1); expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(1);
}); });
it("do not activate against status moves that target the field", async () => { it("do not activate against status moves that target the field", async() => {
const moveToUse = Moves.GRASSY_TERRAIN; const moveToUse = Moves.GRASSY_TERRAIN;
const enemyAbility = Abilities.SAP_SIPPER; const enemyAbility = Abilities.SAP_SIPPER;
@ -82,7 +83,7 @@ describe("Abilities - Sap Sipper", () => {
await game.startBattle(); await game.startBattle();
game.move.select(moveToUse); game.doAttack(getMovePosition(game.scene, 0, moveToUse));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -91,7 +92,7 @@ describe("Abilities - Sap Sipper", () => {
expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(0); expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(0);
}); });
it("activate once against multi-hit grass attacks", async () => { it("activate once against multi-hit grass attacks", async() => {
const moveToUse = Moves.BULLET_SEED; const moveToUse = Moves.BULLET_SEED;
const enemyAbility = Abilities.SAP_SIPPER; const enemyAbility = Abilities.SAP_SIPPER;
@ -104,7 +105,7 @@ describe("Abilities - Sap Sipper", () => {
const startingOppHp = game.scene.currentBattle.enemyParty[0].hp; const startingOppHp = game.scene.currentBattle.enemyParty[0].hp;
game.move.select(moveToUse); game.doAttack(getMovePosition(game.scene, 0, moveToUse));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -112,7 +113,7 @@ describe("Abilities - Sap Sipper", () => {
expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(1); expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(1);
}); });
it("do not activate against status moves that target the user", async () => { it("do not activate against status moves that target the user", async() => {
const moveToUse = Moves.SPIKY_SHIELD; const moveToUse = Moves.SPIKY_SHIELD;
const ability = Abilities.SAP_SIPPER; const ability = Abilities.SAP_SIPPER;
@ -124,7 +125,7 @@ describe("Abilities - Sap Sipper", () => {
await game.startBattle(); await game.startBattle();
game.move.select(moveToUse); game.doAttack(getMovePosition(game.scene, 0, moveToUse));
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
@ -138,7 +139,7 @@ describe("Abilities - Sap Sipper", () => {
// TODO Add METRONOME outcome override // TODO Add METRONOME outcome override
// To run this testcase, manually modify the METRONOME move to always give SAP_SIPPER, then uncomment // To run this testcase, manually modify the METRONOME move to always give SAP_SIPPER, then uncomment
it.todo("activate once against multi-hit grass attacks (metronome)", async () => { it.todo("activate once against multi-hit grass attacks (metronome)", async() => {
const moveToUse = Moves.METRONOME; const moveToUse = Moves.METRONOME;
const enemyAbility = Abilities.SAP_SIPPER; const enemyAbility = Abilities.SAP_SIPPER;
@ -151,7 +152,7 @@ describe("Abilities - Sap Sipper", () => {
const startingOppHp = game.scene.currentBattle.enemyParty[0].hp; const startingOppHp = game.scene.currentBattle.enemyParty[0].hp;
game.move.select(moveToUse); game.doAttack(getMovePosition(game.scene, 0, moveToUse));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);

View File

@ -1,10 +1,11 @@
import { Status, StatusEffect } from "#app/data/status-effect"; import { Status, StatusEffect } from "#app/data/status-effect.js";
import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager"; import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
const TIMEOUT = 20 * 1000; const TIMEOUT = 20 * 1000;
@ -52,7 +53,7 @@ describe("Abilities - SCHOOLING", () => {
wishiwashi.status = new Status(StatusEffect.FAINT); wishiwashi.status = new Status(StatusEffect.FAINT);
expect(wishiwashi.isFainted()).toBe(true); expect(wishiwashi.isFainted()).toBe(true);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.doKillOpponents(); await game.doKillOpponents();
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
game.doSelectModifier(); game.doSelectModifier();

View File

@ -1,12 +1,13 @@
import { ArenaTagType } from "#app/enums/arena-tag-type"; import { ArenaTagType } from "#app/enums/arena-tag-type.js";
import { PostSummonPhase } from "#app/phases/post-summon-phase"; import GameManager from "#test/utils/gameManager";
import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { PostSummonPhase } from "#app/phases/post-summon-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
describe("Abilities - Screen Cleaner", () => { describe("Abilities - Screen Cleaner", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -35,7 +36,7 @@ describe("Abilities - Screen Cleaner", () => {
await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]);
game.move.select(Moves.HAIL); game.doAttack(getMovePosition(game.scene, 0, Moves.HAIL));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.arena.getTag(ArenaTagType.AURORA_VEIL)).toBeDefined(); expect(game.scene.arena.getTag(ArenaTagType.AURORA_VEIL)).toBeDefined();
@ -52,7 +53,7 @@ describe("Abilities - Screen Cleaner", () => {
await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.arena.getTag(ArenaTagType.LIGHT_SCREEN)).toBeDefined(); expect(game.scene.arena.getTag(ArenaTagType.LIGHT_SCREEN)).toBeDefined();
@ -69,7 +70,7 @@ describe("Abilities - Screen Cleaner", () => {
await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]);
game.move.select(Moves.SPLASH); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.arena.getTag(ArenaTagType.REFLECT)).toBeDefined(); expect(game.scene.arena.getTag(ArenaTagType.REFLECT)).toBeDefined();

View File

@ -1,14 +1,18 @@
import { BattlerIndex } from "#app/battle";
import { applyAbAttrs, MoveEffectChanceMultiplierAbAttr } from "#app/data/ability"; import { applyAbAttrs, MoveEffectChanceMultiplierAbAttr } from "#app/data/ability";
import { Stat } from "#app/data/pokemon-stat"; import { Stat } from "#app/data/pokemon-stat";
import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Command } from "#app/ui/command-ui-handler";
import { Mode } from "#app/ui/ui";
import * as Utils from "#app/utils"; import * as Utils from "#app/utils";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { BattlerIndex } from "#app/battle.js";
import { CommandPhase } from "#app/phases/command-phase.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
describe("Abilities - Serene Grace", () => { describe("Abilities - Serene Grace", () => {
@ -32,10 +36,10 @@ describe("Abilities - Serene Grace", () => {
game.override.enemySpecies(Species.ONIX); game.override.enemySpecies(Species.ONIX);
game.override.startingLevel(100); game.override.startingLevel(100);
game.override.moveset(movesToUse); game.override.moveset(movesToUse);
game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]);
}); });
it("Move chance without Serene Grace", async () => { it("Move chance without Serene Grace", async() => {
const moveToUse = Moves.AIR_SLASH; const moveToUse = Moves.AIR_SLASH;
await game.startBattle([ await game.startBattle([
Species.PIDGEOT Species.PIDGEOT
@ -45,7 +49,13 @@ describe("Abilities - Serene Grace", () => {
game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000; game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000;
expect(game.scene.getParty()[0].formIndex).toBe(0); expect(game.scene.getParty()[0].formIndex).toBe(0);
game.move.select(moveToUse); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false); await game.phaseInterceptor.to(MoveEffectPhase, false);
@ -57,12 +67,12 @@ describe("Abilities - Serene Grace", () => {
const chance = new Utils.IntegerHolder(move.chance); const chance = new Utils.IntegerHolder(move.chance);
console.log(move.chance + " Their ability is " + phase.getUserPokemon()!.getAbility().name); console.log(move.chance + " Their ability is " + phase.getUserPokemon()!.getAbility().name);
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false); applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false);
expect(chance.value).toBe(30); expect(chance.value).toBe(30);
}, 20000); }, 20000);
it("Move chance with Serene Grace", async () => { it("Move chance with Serene Grace", async() => {
const moveToUse = Moves.AIR_SLASH; const moveToUse = Moves.AIR_SLASH;
game.override.ability(Abilities.SERENE_GRACE); game.override.ability(Abilities.SERENE_GRACE);
await game.startBattle([ await game.startBattle([
@ -72,7 +82,13 @@ describe("Abilities - Serene Grace", () => {
game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000; game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000;
expect(game.scene.getParty()[0].formIndex).toBe(0); expect(game.scene.getParty()[0].formIndex).toBe(0);
game.move.select(moveToUse); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false); await game.phaseInterceptor.to(MoveEffectPhase, false);
@ -83,7 +99,7 @@ describe("Abilities - Serene Grace", () => {
expect(move.id).toBe(Moves.AIR_SLASH); expect(move.id).toBe(Moves.AIR_SLASH);
const chance = new Utils.IntegerHolder(move.chance); const chance = new Utils.IntegerHolder(move.chance);
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false); applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false);
expect(chance.value).toBe(60); expect(chance.value).toBe(60);
}, 20000); }, 20000);

View File

@ -1,14 +1,18 @@
import { BattlerIndex } from "#app/battle";
import { applyAbAttrs, applyPostDefendAbAttrs, applyPreAttackAbAttrs, MoveEffectChanceMultiplierAbAttr, MovePowerBoostAbAttr, PostDefendTypeChangeAbAttr } from "#app/data/ability"; import { applyAbAttrs, applyPostDefendAbAttrs, applyPreAttackAbAttrs, MoveEffectChanceMultiplierAbAttr, MovePowerBoostAbAttr, PostDefendTypeChangeAbAttr } from "#app/data/ability";
import { Stat } from "#app/data/pokemon-stat"; import { Stat } from "#app/data/pokemon-stat";
import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { CommandPhase } from "#app/phases/command-phase.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Command } from "#app/ui/command-ui-handler";
import { Mode } from "#app/ui/ui";
import * as Utils from "#app/utils"; import * as Utils from "#app/utils";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { BattlerIndex } from "#app/battle.js";
describe("Abilities - Sheer Force", () => { describe("Abilities - Sheer Force", () => {
@ -32,10 +36,10 @@ describe("Abilities - Sheer Force", () => {
game.override.enemySpecies(Species.ONIX); game.override.enemySpecies(Species.ONIX);
game.override.startingLevel(100); game.override.startingLevel(100);
game.override.moveset(movesToUse); game.override.moveset(movesToUse);
game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]);
}); });
it("Sheer Force", async () => { it("Sheer Force", async() => {
const moveToUse = Moves.AIR_SLASH; const moveToUse = Moves.AIR_SLASH;
game.override.ability(Abilities.SHEER_FORCE); game.override.ability(Abilities.SHEER_FORCE);
await game.startBattle([ await game.startBattle([
@ -46,7 +50,13 @@ describe("Abilities - Sheer Force", () => {
game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000; game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000;
expect(game.scene.getParty()[0].formIndex).toBe(0); expect(game.scene.getParty()[0].formIndex).toBe(0);
game.move.select(moveToUse); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false); await game.phaseInterceptor.to(MoveEffectPhase, false);
@ -59,16 +69,16 @@ describe("Abilities - Sheer Force", () => {
const power = new Utils.IntegerHolder(move.power); const power = new Utils.IntegerHolder(move.power);
const chance = new Utils.IntegerHolder(move.chance); const chance = new Utils.IntegerHolder(move.chance);
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false); applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false);
applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, false, power); applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, power);
expect(chance.value).toBe(0); expect(chance.value).toBe(0);
expect(power.value).toBe(move.power * 5461 / 4096); expect(power.value).toBe(move.power * 5461/4096);
}, 20000); }, 20000);
it("Sheer Force with exceptions including binding moves", async () => { it("Sheer Force with exceptions including binding moves", async() => {
const moveToUse = Moves.BIND; const moveToUse = Moves.BIND;
game.override.ability(Abilities.SHEER_FORCE); game.override.ability(Abilities.SHEER_FORCE);
await game.startBattle([ await game.startBattle([
@ -79,7 +89,13 @@ describe("Abilities - Sheer Force", () => {
game.scene.getEnemyParty()[0].stats[Stat.DEF] = 10000; game.scene.getEnemyParty()[0].stats[Stat.DEF] = 10000;
expect(game.scene.getParty()[0].formIndex).toBe(0); expect(game.scene.getParty()[0].formIndex).toBe(0);
game.move.select(moveToUse); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false); await game.phaseInterceptor.to(MoveEffectPhase, false);
@ -92,8 +108,8 @@ describe("Abilities - Sheer Force", () => {
const power = new Utils.IntegerHolder(move.power); const power = new Utils.IntegerHolder(move.power);
const chance = new Utils.IntegerHolder(move.chance); const chance = new Utils.IntegerHolder(move.chance);
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false); applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false);
applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, false, power); applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, power);
expect(chance.value).toBe(-1); expect(chance.value).toBe(-1);
expect(power.value).toBe(move.power); expect(power.value).toBe(move.power);
@ -101,7 +117,7 @@ describe("Abilities - Sheer Force", () => {
}, 20000); }, 20000);
it("Sheer Force with moves with no secondary effect", async () => { it("Sheer Force with moves with no secondary effect", async() => {
const moveToUse = Moves.TACKLE; const moveToUse = Moves.TACKLE;
game.override.ability(Abilities.SHEER_FORCE); game.override.ability(Abilities.SHEER_FORCE);
await game.startBattle([ await game.startBattle([
@ -112,7 +128,13 @@ describe("Abilities - Sheer Force", () => {
game.scene.getEnemyParty()[0].stats[Stat.DEF] = 10000; game.scene.getEnemyParty()[0].stats[Stat.DEF] = 10000;
expect(game.scene.getParty()[0].formIndex).toBe(0); expect(game.scene.getParty()[0].formIndex).toBe(0);
game.move.select(moveToUse); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false); await game.phaseInterceptor.to(MoveEffectPhase, false);
@ -125,8 +147,8 @@ describe("Abilities - Sheer Force", () => {
const power = new Utils.IntegerHolder(move.power); const power = new Utils.IntegerHolder(move.power);
const chance = new Utils.IntegerHolder(move.chance); const chance = new Utils.IntegerHolder(move.chance);
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false); applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false);
applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, false, power); applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, power);
expect(chance.value).toBe(-1); expect(chance.value).toBe(-1);
expect(power.value).toBe(move.power); expect(power.value).toBe(move.power);
@ -134,10 +156,10 @@ describe("Abilities - Sheer Force", () => {
}, 20000); }, 20000);
it("Sheer Force Disabling Specific Abilities", async () => { it("Sheer Force Disabling Specific Abilities", async() => {
const moveToUse = Moves.CRUSH_CLAW; const moveToUse = Moves.CRUSH_CLAW;
game.override.enemyAbility(Abilities.COLOR_CHANGE); game.override.enemyAbility(Abilities.COLOR_CHANGE);
game.override.startingHeldItems([{ name: "KINGS_ROCK", count: 1 }]); game.override.startingHeldItems([{name: "KINGS_ROCK", count: 1}]);
game.override.ability(Abilities.SHEER_FORCE); game.override.ability(Abilities.SHEER_FORCE);
await game.startBattle([ await game.startBattle([
Species.PIDGEOT Species.PIDGEOT
@ -147,7 +169,13 @@ describe("Abilities - Sheer Force", () => {
game.scene.getEnemyParty()[0].stats[Stat.DEF] = 10000; game.scene.getEnemyParty()[0].stats[Stat.DEF] = 10000;
expect(game.scene.getParty()[0].formIndex).toBe(0); expect(game.scene.getParty()[0].formIndex).toBe(0);
game.move.select(moveToUse); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
});
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
const movePosition = getMovePosition(game.scene, 0, moveToUse);
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
});
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to(MoveEffectPhase, false); await game.phaseInterceptor.to(MoveEffectPhase, false);
@ -163,12 +191,12 @@ describe("Abilities - Sheer Force", () => {
const target = phase.getTarget()!; const target = phase.getTarget()!;
const opponentType = target.getTypes()[0]; const opponentType = target.getTypes()[0];
applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, false, chance, move, target, false); applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, chance, move, target, false);
applyPreAttackAbAttrs(MovePowerBoostAbAttr, user, target, move, false, power); applyPreAttackAbAttrs(MovePowerBoostAbAttr, user, target, move, power);
applyPostDefendAbAttrs(PostDefendTypeChangeAbAttr, target, user, move, target.apply(user, move)); applyPostDefendAbAttrs(PostDefendTypeChangeAbAttr, target, user, move, target.apply(user, move));
expect(chance.value).toBe(0); expect(chance.value).toBe(0);
expect(power.value).toBe(move.power * 5461 / 4096); expect(power.value).toBe(move.power * 5461/4096);
expect(target.getTypes().length).toBe(2); expect(target.getTypes().length).toBe(2);
expect(target.getTypes()[0]).toBe(opponentType); expect(target.getTypes()[0]).toBe(opponentType);

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