Compare commits

..

No commits in common. "b1d4037a57c01d794a49c0f0a5d299918e153ac6" and "1487d7f51cb359d741a5ad3b3d5184ef0506a8f3" have entirely different histories.

57 changed files with 598 additions and 927 deletions

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 2.1 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

@ -1100,7 +1100,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)) {
@ -1116,7 +1116,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;
@ -1518,7 +1518,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);
@ -2136,7 +2136,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;
@ -4233,9 +4232,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;
}; };
@ -4945,7 +4944,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) {

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

@ -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);
} }
@ -1122,10 +1122,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 +1177,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 +1237,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;
@ -1281,7 +1281,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
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;
@ -1922,9 +1922,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 +1939,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 +1949,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 +1984,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 +2012,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 +2022,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 +2040,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 +2048,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 +2063,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 +2081,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 +2100,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 +2123,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 +2165,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 +2178,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 +2245,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 +2341,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 +2727,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 +2799,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 +3433,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 +4360,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

@ -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

@ -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

@ -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 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

@ -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

@ -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

@ -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

@ -6,7 +6,6 @@ import { Species } from "#enums/species";
import { StatusEffect } from "#app/data/status-effect.js"; import { StatusEffect } from "#app/data/status-effect.js";
import { BattleStat } from "#app/data/battle-stat.js"; import { BattleStat } from "#app/data/battle-stat.js";
import { SPLASH_ONLY } from "../utils/testUtils"; import { SPLASH_ONLY } from "../utils/testUtils";
import { toDmgValue } from "#app/utils";
import { Mode } from "#app/ui/ui.js"; import { Mode } from "#app/ui/ui.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
import { MoveEndPhase } from "#app/phases/move-end-phase.js"; import { MoveEndPhase } from "#app/phases/move-end-phase.js";
@ -48,7 +47,7 @@ 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);
@ -81,7 +80,7 @@ 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);
@ -122,7 +121,7 @@ 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.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));

View File

@ -8,7 +8,6 @@ import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { SPLASH_ONLY } from "#test/utils/testUtils"; import { SPLASH_ONLY } from "#test/utils/testUtils";
import { StatusEffect } from "#app/enums/status-effect.js"; import { StatusEffect } from "#app/enums/status-effect.js";
import { toDmgValue } from "#app/utils";
describe("Abilities - Heatproof", () => { describe("Abilities - Heatproof", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -73,6 +72,6 @@ describe("Abilities - Heatproof", () => {
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

@ -16,7 +16,6 @@ import { DamagePhase } from "#app/phases/damage-phase.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
import { MoveEndPhase } from "#app/phases/move-end-phase.js"; import { MoveEndPhase } from "#app/phases/move-end-phase.js";
import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import { TurnEndPhase } from "#app/phases/turn-end-phase.js";
import { toDmgValue } from "#app/utils";
const TIMEOUT = 20 * 1000; const TIMEOUT = 20 * 1000;
@ -74,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
); );
@ -304,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
); );

View File

@ -52,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;

View File

@ -67,7 +67,7 @@ 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);
@ -99,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

@ -69,8 +69,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(0); expect(chance.value).toBe(0);
expect(power.value).toBe(move.power * 5461/4096); expect(power.value).toBe(move.power * 5461/4096);
@ -108,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);
@ -147,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);
@ -191,8 +191,8 @@ 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);

View File

@ -67,8 +67,8 @@ describe("Abilities - Shield Dust", () => {
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);
applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, phase.getTarget()!, phase.getUserPokemon()!, null, null, false, chance); applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, phase.getTarget()!, phase.getUserPokemon()!, null!, null!, chance);
expect(chance.value).toBe(0); expect(chance.value).toBe(0);
}, 20000); }, 20000);

View File

@ -1,71 +0,0 @@
import { DamagePhase } from "#app/phases/damage-phase.js";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { ArenaTagType } from "#enums/arena-tag-type";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import { toDmgValue } from "#app/utils";
describe("Round Down and Minimun 1 test in Damage Calculation", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
game.override.battleType("single");
game.override.startingLevel(10);
});
it("When the user fails to use Jump Kick with Wonder Guard ability, the damage should be 1.", async () => {
game.override.enemySpecies(Species.GASTLY);
game.override.enemyMoveset(SPLASH_ONLY);
game.override.starterSpecies(Species.SHEDINJA);
game.override.moveset([Moves.JUMP_KICK]);
game.override.ability(Abilities.WONDER_GUARD);
await game.startBattle();
const shedinja = game.scene.getPlayerPokemon()!;
game.doAttack(getMovePosition(game.scene, 0, Moves.JUMP_KICK));
await game.phaseInterceptor.to(DamagePhase);
expect(shedinja.hp).toBe(shedinja.getMaxHp() - 1);
});
it("Charizard with odd HP survives Stealth Rock damage twice", async () => {
game.scene.arena.addTag(ArenaTagType.STEALTH_ROCK, 1, Moves.STEALTH_ROCK, 0);
game.override.seed("Charizard Stealth Rock test");
game.override.enemySpecies(Species.CHARIZARD);
game.override.enemyAbility(Abilities.BLAZE);
game.override.starterSpecies(Species.PIKACHU);
game.override.enemyLevel(100);
await game.startBattle();
const charizard = game.scene.getEnemyPokemon()!;
const maxHp = charizard.getMaxHp();
const damage_prediction = toDmgValue(charizard.getMaxHp() / 2);
const currentHp = charizard.hp;
const expectedHP = maxHp - damage_prediction;
expect(currentHp).toBe(expectedHP);
});
});

View File

@ -6,7 +6,6 @@ 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 { BattleStat } from "#app/data/battle-stat"; import { BattleStat } from "#app/data/battle-stat";
import { toDmgValue } from "#app/utils";
const TIMEOUT = 20 * 1000; const TIMEOUT = 20 * 1000;
// RATIO : HP Cost of Move // RATIO : HP Cost of Move
@ -45,7 +44,7 @@ describe("Moves - BELLY DRUM", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO);
game.doAttack(getMovePosition(game.scene, 0, Moves.BELLY_DRUM)); game.doAttack(getMovePosition(game.scene, 0, Moves.BELLY_DRUM));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -60,7 +59,7 @@ describe("Moves - BELLY DRUM", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO);
// Here - BattleStat.ATK -> -3 and BattleStat.SPATK -> 6 // Here - BattleStat.ATK -> -3 and BattleStat.SPATK -> 6
leadPokemon.summonData.battleStats[BattleStat.ATK] = -3; leadPokemon.summonData.battleStats[BattleStat.ATK] = -3;
@ -96,7 +95,7 @@ describe("Moves - BELLY DRUM", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO);
leadPokemon.hp = hpLost - PREDAMAGE; leadPokemon.hp = hpLost - PREDAMAGE;
game.doAttack(getMovePosition(game.scene, 0, Moves.BELLY_DRUM)); game.doAttack(getMovePosition(game.scene, 0, Moves.BELLY_DRUM));

View File

@ -7,7 +7,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { BattleStat } from "#app/data/battle-stat"; import { BattleStat } from "#app/data/battle-stat";
import { SPLASH_ONLY } from "#test/utils/testUtils"; import { SPLASH_ONLY } from "#test/utils/testUtils";
import { toDmgValue } from "#app/utils";
const TIMEOUT = 20 * 1000; const TIMEOUT = 20 * 1000;
/** HP Cost of Move */ /** HP Cost of Move */
@ -46,7 +45,7 @@ describe("Moves - CLANGOROUS_SOUL", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO);
game.doAttack(getMovePosition(game.scene, 0, Moves.CLANGOROUS_SOUL)); game.doAttack(getMovePosition(game.scene, 0, Moves.CLANGOROUS_SOUL));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -65,7 +64,7 @@ describe("Moves - CLANGOROUS_SOUL", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO);
//Here - BattleStat.SPD -> 0 and BattleStat.SPDEF -> 4 //Here - BattleStat.SPD -> 0 and BattleStat.SPDEF -> 4
leadPokemon.summonData.battleStats[BattleStat.ATK] = 6; leadPokemon.summonData.battleStats[BattleStat.ATK] = 6;
@ -114,7 +113,7 @@ describe("Moves - CLANGOROUS_SOUL", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO);
leadPokemon.hp = hpLost - PREDAMAGE; leadPokemon.hp = hpLost - PREDAMAGE;
game.doAttack(getMovePosition(game.scene, 0, Moves.CLANGOROUS_SOUL)); game.doAttack(getMovePosition(game.scene, 0, Moves.CLANGOROUS_SOUL));

View File

@ -7,7 +7,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { BattleStat } from "#app/data/battle-stat"; import { BattleStat } from "#app/data/battle-stat";
import { SPLASH_ONLY } from "#test/utils/testUtils"; import { SPLASH_ONLY } from "#test/utils/testUtils";
import { toDmgValue } from "#app/utils";
const TIMEOUT = 20 * 1000; const TIMEOUT = 20 * 1000;
/** HP Cost of Move */ /** HP Cost of Move */
@ -46,7 +45,7 @@ describe("Moves - FILLET AWAY", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO);
game.doAttack(getMovePosition(game.scene, 0, Moves.FILLET_AWAY)); game.doAttack(getMovePosition(game.scene, 0, Moves.FILLET_AWAY));
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -63,7 +62,7 @@ describe("Moves - FILLET AWAY", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO);
//Here - BattleStat.SPD -> 0 and BattleStat.SPATK -> 3 //Here - BattleStat.SPD -> 0 and BattleStat.SPATK -> 3
leadPokemon.summonData.battleStats[BattleStat.ATK] = 6; leadPokemon.summonData.battleStats[BattleStat.ATK] = 6;
@ -104,7 +103,7 @@ describe("Moves - FILLET AWAY", () => {
await game.startBattle([Species.MAGIKARP]); await game.startBattle([Species.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.scene.getPlayerPokemon()!;
const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO);
leadPokemon.hp = hpLost - PREDAMAGE; leadPokemon.hp = hpLost - PREDAMAGE;
game.doAttack(getMovePosition(game.scene, 0, Moves.FILLET_AWAY)); game.doAttack(getMovePosition(game.scene, 0, Moves.FILLET_AWAY));

View File

@ -78,6 +78,6 @@ describe("Moves - Tackle", () => {
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnEndPhase); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnEndPhase);
const hpLost = hpOpponent - game.scene.currentBattle.enemyParty[0].hp; const hpLost = hpOpponent - game.scene.currentBattle.enemyParty[0].hp;
expect(hpLost).toBeGreaterThan(0); expect(hpLost).toBeGreaterThan(0);
expect(hpLost).toBeLessThan(4); expect(hpLost).toBe(4);
}, 20000); }, 20000);
}); });

View File

@ -560,17 +560,3 @@ export function capitalizeString(str: string, sep: string, lowerFirstChar: boole
export function isNullOrUndefined(object: any): boolean { export function isNullOrUndefined(object: any): boolean {
return null === object || undefined === object; return null === object || undefined === object;
} }
/**
* This function is used in the context of a Pokémon battle game to calculate the actual integer damage value from a float result.
* Many damage calculation formulas involve various parameters and result in float values.
* The actual damage applied to a Pokémon's HP must be an integer.
* This function helps in ensuring that by flooring the float value and enforcing a minimum damage value.
*
* @param value - The float value to convert.
* @param minValue - The minimum integer value to return. Defaults to 1.
* @returns The converted value as an integer.
*/
export function toDmgValue(value: number, minValue: number = 1) {
return Math.max(Math.floor(value), minValue);
}