Compare commits

...

3 Commits

Author SHA1 Message Date
innerthunder
32d4102594
[Bug] Fix Make It Rain and Clanging Scales stat drop trigger logic (#3355)
* Fix Make It Rain + Clanging Scales stat drop logic

* Use "includes" instead of "<" for firstTarget logic instead
2024-08-05 01:19:49 -04:00
Madmadness65
b6da93a092
Add ORAS Champion theme for Mixed music (#3351) 2024-08-04 19:45:29 -05:00
José Ricardo Fleury Oliveira
a8bb6e7a0b
[Localization] Update Portuguese translation for filter-bar.ts (#3353) 2024-08-04 20:41:29 -04:00
17 changed files with 67 additions and 40 deletions

Binary file not shown.

View File

@ -1792,8 +1792,10 @@ export default class BattleScene extends SceneBase {
return 13.950;
case "battle_johto_champion": //B2W2 Johto Champion Battle
return 23.498;
case "battle_hoenn_champion": //B2W2 Hoenn Champion Battle
case "battle_hoenn_champion_g5": //B2W2 Hoenn Champion Battle
return 11.328;
case "battle_hoenn_champion_g6": //ORAS Hoenn Champion Battle
return 11.762;
case "battle_sinnoh_champion": //B2W2 Sinnoh Champion Battle
return 12.235;
case "battle_champion_alder": //BW Unova Champion Battle

View File

@ -7905,7 +7905,7 @@ export function initMoves() {
.makesContact(false)
.partial(),
new AttackMove(Moves.CLANGING_SCALES, Type.DRAGON, MoveCategory.SPECIAL, 110, 100, 5, -1, 0, 7)
.attr(StatChangeAttr, BattleStat.DEF, -1, true)
.attr(StatChangeAttr, BattleStat.DEF, -1, true, null, true, false, MoveEffectTrigger.HIT, true)
.soundBased()
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.DRAGON_HAMMER, Type.DRAGON, MoveCategory.PHYSICAL, 90, 100, 15, -1, 0, 7),

View File

@ -1404,7 +1404,7 @@ export const trainerConfigs: TrainerConfigs = {
p.generateAndPopulateMoveset();
p.generateName();
})),
[TrainerType.STEVEN]: new TrainerConfig(++t).initForChampion(signatureSpecies["STEVEN"],true).setBattleBgm("battle_hoenn_champion").setMixedBattleBgm("battle_hoenn_champion").setHasDouble("steven_wallace_double").setDoubleTrainerType(TrainerType.WALLACE).setDoubleTitle("champion_double")
[TrainerType.STEVEN]: new TrainerConfig(++t).initForChampion(signatureSpecies["STEVEN"],true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("steven_wallace_double").setDoubleTrainerType(TrainerType.WALLACE).setDoubleTitle("champion_double")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SKARMORY], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
}))
@ -1413,7 +1413,7 @@ export const trainerConfigs: TrainerConfigs = {
p.generateAndPopulateMoveset();
p.generateName();
})),
[TrainerType.WALLACE]: new TrainerConfig(++t).initForChampion(signatureSpecies["WALLACE"],true).setBattleBgm("battle_hoenn_champion").setMixedBattleBgm("battle_hoenn_champion").setHasDouble("wallace_steven_double").setDoubleTrainerType(TrainerType.STEVEN).setDoubleTitle("champion_double")
[TrainerType.WALLACE]: new TrainerConfig(++t).initForChampion(signatureSpecies["WALLACE"],true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("wallace_steven_double").setDoubleTrainerType(TrainerType.STEVEN).setDoubleTitle("champion_double")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.PELIPPER], TrainerSlot.TRAINER, true, p => {
p.abilityIndex = 1; // Drizzle
p.generateAndPopulateMoveset();

View File

@ -5,7 +5,8 @@ export const bgmName: SimpleTranslationEntries = {
"missing_entries" : "{{name}}",
"battle_kanto_champion": "S2W2 Vs. Kanto Champion",
"battle_johto_champion": "S2W2 Vs. Johto Champion",
"battle_hoenn_champion": "S2W2 Vs. Hoenn Champion",
"battle_hoenn_champion_g5": "S2W2 Vs. Hoenn Champion",
"battle_hoenn_champion_g6": "ORAS Vs. Hoenn Champion",
"battle_sinnoh_champion": "S2W2 Vs. Champion Cynthia",
"battle_champion_alder": "SW Vs. Champion Lauro",
"battle_champion_iris": "S2W2 Vs. Champion Lilia",

View File

@ -5,7 +5,8 @@ export const bgmName: SimpleTranslationEntries = {
"missing_entries" : "{{name}}",
"battle_kanto_champion": "B2W2 Kanto Champion Battle",
"battle_johto_champion": "B2W2 Johto Champion Battle",
"battle_hoenn_champion": "B2W2 Hoenn Champion Battle",
"battle_hoenn_champion_g5": "B2W2 Hoenn Champion Battle",
"battle_hoenn_champion_g6": "ORAS Hoenn Champion Battle",
"battle_sinnoh_champion": "B2W2 Sinnoh Champion Battle",
"battle_champion_alder": "BW Unova Champion Battle",
"battle_champion_iris": "B2W2 Unova Champion Battle",

View File

@ -5,7 +5,8 @@ export const bgmName: SimpleTranslationEntries = {
"missing_entries" : "{{name}}",
"battle_kanto_champion": "B2W2 - ¡Vs Campeón de Kanto!",
"battle_johto_champion": "B2W2 - ¡Vs Campeón de Johto!",
"battle_hoenn_champion": "B2W2 - ¡Vs Campeón de Hoenn!",
"battle_hoenn_champion_g5": "B2W2 - ¡Vs Campeón de Hoenn!",
"battle_hoenn_champion_g6": "ORAS - ¡Vs Campeón de Hoenn!",
"battle_sinnoh_champion": "B2W2 - ¡Vs Campeón de Sinnoh!",
"battle_champion_alder": "BW - ¡Vs Campeón de Teselia!",
"battle_champion_iris": "B2W2 - ¡Vs Campeón de Teselia!",

View File

@ -5,7 +5,8 @@ export const bgmName: SimpleTranslationEntries = {
"missing_entries" : "{{name}}",
"battle_kanto_champion": "N2B2 - Vs. Maitre de Kanto",
"battle_johto_champion": "N2B2 - Vs. Maitre de Johto",
"battle_hoenn_champion": "N2B2 - Vs. Maitre de Hoenn",
"battle_hoenn_champion_g5": "N2B2 - Vs. Maitre de Hoenn",
"battle_hoenn_champion_g6": "ROSA - Vs. Maitre de Hoenn",
"battle_sinnoh_champion": "N2B2 - Vs. Maitresse de Sinnoh",
"battle_champion_alder": "NB - Vs. Maitre dUnys",
"battle_champion_iris": "N2B2 - Vs. Maitresse dUnys",

View File

@ -5,7 +5,8 @@ export const bgmName: SimpleTranslationEntries = {
"missing_entries" : "{{name}}",
"battle_kanto_champion": "B2W2 Kanto Champion Battle",
"battle_johto_champion": "B2W2 Johto Champion Battle",
"battle_hoenn_champion": "B2W2 Hoenn Champion Battle",
"battle_hoenn_champion_g5": "B2W2 Hoenn Champion Battle",
"battle_hoenn_champion_g6": "ORAS Hoenn Champion Battle",
"battle_sinnoh_champion": "B2W2 Sinnoh Champion Battle",
"battle_champion_alder": "BW Unova Champion Battle",
"battle_champion_iris": "B2W2 Unova Champion Battle",

View File

@ -5,7 +5,8 @@ export const bgmName: SimpleTranslationEntries = {
"missing_entries" : "{{name}}",
"battle_kanto_champion": "BW2 관동 챔피언 배틀",
"battle_johto_champion": "BW2 성도 챔피언 배틀",
"battle_hoenn_champion": "BW2 호연 챔피언 배틀",
"battle_hoenn_champion_g5": "BW2 호연 챔피언 배틀",
"battle_hoenn_champion_g6": "ORAS 호연 챔피언 배틀",
"battle_sinnoh_champion": "BW2 신오 챔피언 배틀",
"battle_champion_alder": "BW 하나 챔피언 배틀",
"battle_champion_iris": "BW2 하나 챔피언 배틀",

View File

@ -5,7 +5,8 @@ export const bgmName: SimpleTranslationEntries = {
"missing_entries": "{{name}}",
"battle_kanto_champion": "B2W2 Batalha do Campeão de Kanto",
"battle_johto_champion": "B2W2 Batalha do Campeão de Johto",
"battle_hoenn_champion": "B2W2 Batalha do Campeão de Hoenn",
"battle_hoenn_champion_g5": "B2W2 Batalha do Campeão de Hoenn",
"battle_hoenn_champion_g6": "ORAS Batalha do Campeão de Hoenn",
"battle_sinnoh_champion": "B2W2 Batalha do Campeão de Sinnoh",
"battle_champion_alder": "BW Batalha do Campeão de Unova",
"battle_champion_iris": "B2W2 Batalha do Campeão de Unova",

View File

@ -4,19 +4,19 @@ export const filterBar: SimpleTranslationEntries = {
"genFilter": "Ger.",
"typeFilter": "Tipo",
"dexFilter": "Dex",
"unlocksFilter": "Outros",
"miscFilter": "Misc",
"unlocksFilter": "Desbloqueios",
"miscFilter": "Outros",
"sortFilter": "Ordem",
"all": "Tudo",
"normal": "Normal",
"uncaught": "Não Capturado",
"passive": "Passive",
"passive": "Passiva",
"passiveUnlocked": "Passiva Desbloq.",
"passiveLocked": "Passiva Bloq.",
"ribbon": "Ribbon",
"hasWon": "Ribbon - Yes",
"hasNotWon": "Ribbon - No",
"sortByNumber": "Núm.",
"ribbon": "Fita",
"hasWon": "Fita - Sim",
"hasNotWon": "Fita - Não",
"sortByNumber": "Número",
"sortByCost": "Custo",
"sortByCandies": "# Doces",
"sortByIVs": "IVs",

View File

@ -5,7 +5,8 @@ export const bgmName: SimpleTranslationEntries = {
"missing_entries" : "{{name}}",
"battle_kanto_champion": "黑2白2「决战关都冠军」",
"battle_johto_champion": "黑2白2「决战城都冠军」",
"battle_hoenn_champion": "黑2白2「决战丰缘冠军」",
"battle_hoenn_champion_g5": "黑2白2「决战丰缘冠军」",
"battle_hoenn_champion_g6": "Ω红宝石α蓝宝石「决战!丰缘冠军」",
"battle_sinnoh_champion": "黑2白2「决战神奥冠军」",
"battle_champion_alder": "黑白「决战!合众冠军」",
"battle_champion_iris": "黑2白2「决战合众冠军」",

View File

@ -5,7 +5,8 @@ export const bgmName: SimpleTranslationEntries = {
"missing_entries" : "{{name}}",
"battle_kanto_champion": "B2W2 Kanto Champion Battle",
"battle_johto_champion": "B2W2 Johto Champion Battle",
"battle_hoenn_champion": "B2W2 Hoenn Champion Battle",
"battle_hoenn_champion_g5": "B2W2 Hoenn Champion Battle",
"battle_hoenn_champion_g6": "ORAS Hoenn Champion Battle",
"battle_sinnoh_champion": "B2W2 Sinnoh Champion Battle",
"battle_champion_alder": "BW Unova Champion Battle",
"battle_champion_iris": "B2W2 Unova Champion Battle",

View File

@ -2966,6 +2966,8 @@ export class MoveEffectPhase extends PokemonPhase {
// Move animation only needs one target
new MoveAnim(move.id as Moves, user, this.getTarget()?.getBattlerIndex()).play(this.scene, () => {
/** Has the move successfully hit a target (for damage) yet? */
let hasHit: boolean = false;
for (const target of targets) {
if (!targetHitChecks[target.getBattlerIndex()]) {
this.stopMultiHit(target);
@ -2981,7 +2983,6 @@ export class MoveEffectPhase extends PokemonPhase {
const isProtected = !this.move.getMove().checkFlag(MoveFlags.IGNORE_PROTECT, user, target) && target.findTags(t => t instanceof ProtectedTag).find(t => target.lapseTag(t.tagType));
const firstHit = (user.turnData.hitsLeft === user.turnData.hitCount);
const firstTarget = (moveHistoryEntry.result === MoveResult.PENDING);
if (firstHit) {
user.pushMoveHistory(moveHistoryEntry);
@ -2991,6 +2992,18 @@ export class MoveEffectPhase extends PokemonPhase {
const hitResult = !isProtected ? target.apply(user, move) : HitResult.NO_EFFECT;
const dealsDamage = [
HitResult.EFFECTIVE,
HitResult.SUPER_EFFECTIVE,
HitResult.NOT_VERY_EFFECTIVE,
HitResult.ONE_HIT_KO
].includes(hitResult);
const firstTarget = dealsDamage && !hasHit;
if (firstTarget) {
hasHit = true;
}
const lastHit = (user.turnData.hitsLeft === 1 || !this.getTarget()?.isActive());
if (lastHit) {
@ -3008,7 +3021,7 @@ export class MoveEffectPhase extends PokemonPhase {
if (hitResult !== HitResult.NO_EFFECT) {
applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.POST_APPLY
&& !(attr as MoveEffectAttr).selfTarget && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit), user, target, this.move.getMove()).then(() => {
if (hitResult < HitResult.NO_EFFECT && !target.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr)) {
if (dealsDamage && !target.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr)) {
const flinched = new Utils.BooleanHolder(false);
user.scene.applyModifiers(FlinchChanceModifier, user.isPlayer(), user, flinched);
if (flinched.value) {

View File

@ -1,6 +1,6 @@
import { BattleStat } from "#app/data/battle-stat.js";
import {
CommandPhase,
MoveEffectPhase,
MoveEndPhase,
StatChangePhase,
} from "#app/phases";
@ -10,7 +10,7 @@ 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 { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { SPLASH_ONLY } from "../utils/testUtils";
const TIMEOUT = 20 * 1000;
@ -44,16 +44,8 @@ describe("Moves - Make It Rain", () => {
await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]);
const playerPokemon = game.scene.getPlayerField();
expect(playerPokemon.length).toBe(2);
playerPokemon.forEach(p => expect(p).toBeDefined());
const enemyPokemon = game.scene.getEnemyField();
expect(enemyPokemon.length).toBe(2);
enemyPokemon.forEach(p => expect(p).toBeDefined());
game.doAttack(getMovePosition(game.scene, 0, Moves.MAKE_IT_RAIN));
await game.phaseInterceptor.to(CommandPhase);
game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(MoveEndPhase);
@ -68,10 +60,7 @@ describe("Moves - Make It Rain", () => {
await game.startBattle([Species.CHARIZARD]);
const playerPokemon = game.scene.getPlayerPokemon();
expect(playerPokemon).toBeDefined();
const enemyPokemon = game.scene.getEnemyPokemon();
expect(enemyPokemon).toBeDefined();
game.doAttack(getMovePosition(game.scene, 0, Moves.MAKE_IT_RAIN));
@ -87,14 +76,9 @@ describe("Moves - Make It Rain", () => {
await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]);
const playerPokemon = game.scene.getPlayerField();
playerPokemon.forEach(p => expect(p).toBeDefined());
const enemyPokemon = game.scene.getEnemyField();
enemyPokemon.forEach(p => expect(p).toBeDefined());
game.doAttack(getMovePosition(game.scene, 0, Moves.MAKE_IT_RAIN));
await game.phaseInterceptor.to(CommandPhase);
game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(StatChangePhase);
@ -102,4 +86,23 @@ describe("Moves - Make It Rain", () => {
enemyPokemon.forEach(p => expect(p.isFainted()).toBe(true));
expect(playerPokemon[0].summonData.battleStats[BattleStat.SPATK]).toBe(-1);
}, TIMEOUT);
it("should reduce Sp. Atk if it only hits the second target", async () => {
await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]);
const playerPokemon = game.scene.getPlayerField();
game.doAttack(getMovePosition(game.scene, 0, Moves.MAKE_IT_RAIN));
game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
await game.phaseInterceptor.to(MoveEffectPhase, false);
// Make Make It Rain miss the first target
const moveEffectPhase = game.scene.getCurrentPhase() as MoveEffectPhase;
vi.spyOn(moveEffectPhase, "hitCheck").mockReturnValueOnce(false);
await game.phaseInterceptor.to(MoveEndPhase);
expect(playerPokemon[0].summonData.battleStats[BattleStat.SPATK]).toBe(-1);
}, TIMEOUT);
});