diff --git a/src/data/move.ts b/src/data/move.ts index c8fbde17c6e..44d01c71055 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -650,7 +650,7 @@ export default class Move implements Localizable { } /** - * Applies each {@linkcode MoveCondition} of this move to the params + * Applies each {@linkcode MoveCondition} function of this move to the params, determines if the move can be used prior to calling each attribute's apply() * @param user {@linkcode Pokemon} to apply conditions to * @param target {@linkcode Pokemon} to apply conditions to * @param move {@linkcode Move} to apply conditions to @@ -5295,6 +5295,21 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { } } + +export class ChillyReceptionAttr extends ForceSwitchOutAttr { + + // using inherited constructor + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { + user.scene.arena.trySetWeather(WeatherType.SNOW, true); + return super.apply(user, target, move, args); + } + + getCondition(): MoveConditionFunc { + // chilly reception move will go through if the weather is change-able to snow, or the user can switch out, else move will fail + return (user, target, move) => user.scene.arena.trySetWeather(WeatherType.SNOW, true) || super.getSwitchOutCondition()(user, target, move); + } +} export class RemoveTypeAttr extends MoveEffectAttr { private removedType: Type; @@ -9484,10 +9499,9 @@ export function initMoves() { .makesContact(), new SelfStatusMove(Moves.SHED_TAIL, Type.NORMAL, -1, 10, -1, 0, 9) .unimplemented(), - new StatusMove(Moves.CHILLY_RECEPTION, Type.ICE, -1, 10, -1, 0, 9) - .attr(WeatherChangeAttr, WeatherType.SNOW) - .attr(ForceSwitchOutAttr, true, false) - .target(MoveTarget.BOTH_SIDES), + new SelfStatusMove(Moves.CHILLY_RECEPTION, Type.ICE, -1, 10, -1, 0, 9) + .attr(PreMoveMessageAttr, (user, move) => i18next.t("moveTriggers:chillyReception", {pokemonName: getPokemonNameWithAffix(user)})) + .attr(ChillyReceptionAttr, true, false), new SelfStatusMove(Moves.TIDY_UP, Type.NORMAL, -1, 10, -1, 0, 9) .attr(StatStageChangeAttr, [ Stat.ATK, Stat.SPD ], 1, true, null, true, true) .attr(RemoveArenaTrapAttr, true) diff --git a/src/locales/de/move-trigger.json b/src/locales/de/move-trigger.json index 01b22429fb3..9b59c4b79ed 100644 --- a/src/locales/de/move-trigger.json +++ b/src/locales/de/move-trigger.json @@ -65,6 +65,7 @@ "suppressAbilities": "Die Fähigkeit von {{pokemonName}} wirkt nicht mehr!", "revivalBlessing": "{{pokemonName}} ist wieder fit und kampfbereit!", "swapArenaTags": "{{pokemonName}} hat die Effekte, die auf den beiden Seiten des Kampffeldes wirken, miteinander getauscht!", + "chillyReception": "{{pokemonName}} erzählt einen schlechten Witz, der nicht besonders gut ankommt...", "exposedMove": "{{pokemonName}} erkennt {{targetPokemonName}}!", "safeguard": "{{targetName}} wird durch Bodyguard geschützt!", "afterYou": "{{targetName}} lässt sich auf Galanterie ein!" diff --git a/src/locales/en/move-trigger.json b/src/locales/en/move-trigger.json index bc58e2878dd..93d25e506ba 100644 --- a/src/locales/en/move-trigger.json +++ b/src/locales/en/move-trigger.json @@ -66,6 +66,7 @@ "suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!", "revivalBlessing": "{{pokemonName}} was revived!", "swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!", + "chillyReception": "{{pokemonName}} is preparing to tell a chillingly bad joke!", "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!", "safeguard": "{{targetName}} is protected by Safeguard!", "substituteOnOverlap": "{{pokemonName}} already\nhas a substitute!", diff --git a/src/locales/fr/move-trigger.json b/src/locales/fr/move-trigger.json index 6f9d9d4dd63..7564718e7ce 100644 --- a/src/locales/fr/move-trigger.json +++ b/src/locales/fr/move-trigger.json @@ -66,6 +66,7 @@ "suppressAbilities": "Le talent de {{pokemonName}}\na été rendu inactif !", "revivalBlessing": "{{pokemonName}} a repris connaissance\net est prêt à se battre de nouveau !", "swapArenaTags": "Les effets affectant chaque côté du terrain\nont été échangés par {{pokemonName}} !", + "chillyReception": "{{pokemonName}} s’apprête\nà faire un mauvais jeu de mots…", "exposedMove": "{{targetPokemonName}} est identifié\npar {{pokemonName}} !", "safeguard": "{{targetName}} est protégé\npar la capacité Rune Protect !", "substituteOnOverlap": "{{pokemonName}} a déjà\nun clone !", diff --git a/src/locales/it/move-trigger.json b/src/locales/it/move-trigger.json index c8fb390e53f..fba671a6813 100644 --- a/src/locales/it/move-trigger.json +++ b/src/locales/it/move-trigger.json @@ -66,6 +66,7 @@ "revivalBlessing": "{{pokemonName}} torna in forze!", "swapArenaTags": "{{pokemonName}} ha invertito gli effetti attivi\nnelle due metà del campo!", "exposedMove": "{{pokemonName}} ha identificato\n{{targetPokemonName}}!", + "chillyReception": "{{pokemonName}} sta per fare una battuta!", "safeguard": "Salvaguardia protegge {{targetName}}!", "afterYou": "{{pokemonName}} approfitta della cortesia!" } diff --git a/src/locales/ja/move-trigger.json b/src/locales/ja/move-trigger.json index fbefe883836..afede7edfb3 100644 --- a/src/locales/ja/move-trigger.json +++ b/src/locales/ja/move-trigger.json @@ -64,6 +64,8 @@ "copyType": "{{pokemonName}}は {{targetPokemonName}}と\n同じタイプに なった!", "suppressAbilities": "{{pokemonName}}の 特性が 効かなくなった!", "revivalBlessing": "{{pokemonName}}は\n復活して 戦えるようになった!", + "swapArenaTags": "{{pokemonName}}は\nお互いの 場の効果を 入れ替えた!", + "chillyReception": "{{pokemonName}}は\n寒い ギャグを かました!", "swapArenaTags": "{{pokemonName}}は\nお互いの 場の 効果を 入れ替えた!", "exposedMove": "{{pokemonName}}は {{targetPokemonName}}の\n正体を 見破った!", "afterYou": "{{pokemonName}}は\nお言葉に 甘えることにした!" diff --git a/src/locales/ko/move-trigger.json b/src/locales/ko/move-trigger.json index a8a6c0cf86f..12a126baf9d 100644 --- a/src/locales/ko/move-trigger.json +++ b/src/locales/ko/move-trigger.json @@ -66,6 +66,7 @@ "suppressAbilities": "{{pokemonName}}의\n특성이 효과를 발휘하지 못하게 되었다!", "revivalBlessing": "{{pokemonName}}[[는]]\n정신을 차려 싸울 수 있게 되었다!", "swapArenaTags": "{{pokemonName}}[[는]]\n서로의 필드 효과를 교체했다!", + "chillyReception": "{{pokemonName}}[[는]] 썰렁한 개그를 선보였다!", "exposedMove": "{{pokemonName}}[[는]]\n{{targetPokemonName}}의 정체를 꿰뚫어 보았다!", "safeguard": "{{targetName}}[[는]] 신비의 베일이 지켜 주고 있다!", "afterYou": "{{pokemonName}}[[는]]\n배려를 받아들이기로 했다!" diff --git a/src/locales/pt_BR/move-trigger.json b/src/locales/pt_BR/move-trigger.json index 4549f83cdf1..ed8208cac6b 100644 --- a/src/locales/pt_BR/move-trigger.json +++ b/src/locales/pt_BR/move-trigger.json @@ -61,6 +61,7 @@ "suppressAbilities": "A habilidade de {{pokemonName}}\nfoi suprimida!", "revivalBlessing": "{{pokemonName}} foi reanimado!", "swapArenaTags": "{{pokemonName}} trocou os efeitos de batalha que afetam cada lado do campo!", + "chillyReception": "{{pokemonName}} está prestes a contar uma piada gelada!", "exposedMove": "{{pokemonName}} identificou\n{{targetPokemonName}}!", "safeguard": "{{targetName}} está protegido por Safeguard!", "afterYou": "{{pokemonName}} aceitou a gentil oferta!" diff --git a/src/locales/zh_CN/move-trigger.json b/src/locales/zh_CN/move-trigger.json index 436f1805c4e..60de3591915 100644 --- a/src/locales/zh_CN/move-trigger.json +++ b/src/locales/zh_CN/move-trigger.json @@ -65,6 +65,7 @@ "suppressAbilities": "{{pokemonName}}的特性\n变得无效了!", "revivalBlessing": "{{pokemonName}}复活了!", "swapArenaTags": "{{pokemonName}}\n交换了双方的场地效果!", + "chillyReception": "{{pokemonName}}\n说出了冷笑话!", "exposedMove": "{{pokemonName}}识破了\n{{targetPokemonName}}的原型!", "safeguard": "{{targetName}}\n正受到神秘之幕的保护!", "afterYou": "{{pokemonName}}\n接受了对手的好意!" diff --git a/src/locales/zh_TW/move-trigger.json b/src/locales/zh_TW/move-trigger.json index db88f6df57f..2cd33a3a416 100644 --- a/src/locales/zh_TW/move-trigger.json +++ b/src/locales/zh_TW/move-trigger.json @@ -65,6 +65,7 @@ "suppressAbilities": "{{pokemonName}}的特性\n變得無效了!", "revivalBlessing": "{{pokemonName}}復活了!", "swapArenaTags": "{{pokemonName}}\n交換了雙方的場地效果!", + "chillyReception": "{{pokemonName}}\n說了冷笑話!", "exposedMove": "{{pokemonName}}識破了\n{{targetPokemonName}}的原形!", "safeguard": "{{targetName}}\n正受到神秘之幕的保護!", "afterYou": "{{pokemonName}}\n接受了對手的好意!" diff --git a/src/test/moves/chilly_reception.test.ts b/src/test/moves/chilly_reception.test.ts new file mode 100644 index 00000000000..969c1b97192 --- /dev/null +++ b/src/test/moves/chilly_reception.test.ts @@ -0,0 +1,71 @@ +import { Abilities } from "#app/enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { WeatherType } from "#enums/weather-type"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +const TIMEOUT = 20 * 1000; + +describe("Moves - Chilly Reception", () => { + 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") + .moveset([Moves.CHILLY_RECEPTION, Moves.SNOWSCAPE]) + .enemyMoveset(Array(4).fill(Moves.SPLASH)) + .enemyAbility(Abilities.NONE) + .ability(Abilities.NONE); + + }); + + it("should still change the weather if user can't switch out", async () => { + await game.classicMode.startBattle([Species.SLOWKING]); + + game.move.select(Moves.CHILLY_RECEPTION); + + await game.phaseInterceptor.to("BerryPhase", false); + expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SNOW); + }, TIMEOUT); + + it("should switch out even if it's snowing", async () => { + await game.classicMode.startBattle([Species.SLOWKING, Species.MEOWTH]); + // first turn set up snow with snowscape, try chilly reception on second turn + game.move.select(Moves.SNOWSCAPE); + await game.phaseInterceptor.to("BerryPhase", false); + expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SNOW); + + await game.phaseInterceptor.to("TurnInitPhase", false); + game.move.select(Moves.CHILLY_RECEPTION); + game.doSelectPartyPokemon(1); + + await game.phaseInterceptor.to("BerryPhase", false); + expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SNOW); + expect(game.scene.getPlayerField()[0].species.speciesId).toBe(Species.MEOWTH); + }, TIMEOUT); + + it("happy case - switch out and weather changes", async () => { + + await game.classicMode.startBattle([Species.SLOWKING, Species.MEOWTH]); + + game.move.select(Moves.CHILLY_RECEPTION); + game.doSelectPartyPokemon(1); + + await game.phaseInterceptor.to("BerryPhase", false); + expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SNOW); + expect(game.scene.getPlayerField()[0].species.speciesId).toBe(Species.MEOWTH); + }, TIMEOUT); +});