From 31e3293c51e096541fc050d3f123b75b7c6153bd Mon Sep 17 00:00:00 2001 From: Adrian T <68144167+torranx@users.noreply.github.com> Date: Fri, 31 May 2024 05:42:46 +0800 Subject: [PATCH] [Ability][Move] Finish wind rider/power + tailwind implementation (#1566) * finish wind moves + tailwind implementation * move code and add documentations * remove partial tag of wind_power * add translations, fix move bugs * fix ability trigger message * fix ability trigger message * add es localization * move out of else statement --- src/data/ability.ts | 58 +++++++++++++++++++++++++--- src/data/arena-tag.ts | 21 +++++++++- src/locales/de/ability-trigger.ts | 1 + src/locales/en/ability-trigger.ts | 1 + src/locales/es/ability-trigger.ts | 3 +- src/locales/fr/ability-trigger.ts | 3 +- src/locales/it/ability-trigger.ts | 1 + src/locales/pt_BR/ability-trigger.ts | 1 + src/locales/zh_CN/ability-trigger.ts | 3 +- src/locales/zh_TW/ability-trigger.ts | 1 + 10 files changed, 83 insertions(+), 10 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 9cb03a5bc44..bef81a0220f 100755 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -674,7 +674,10 @@ export class PostDefendApplyBattlerTagAbAttr extends PostDefendAbAttr { applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { if (this.condition(pokemon, attacker, move.getMove())) { - pokemon.addTag(this.tagType, undefined, undefined, pokemon.id); + if (!pokemon.getTag(this.tagType)) { + pokemon.addTag(this.tagType, undefined, undefined, pokemon.id); + pokemon.scene.queueMessage(i18next.t("abilityTriggers:windPowerCharged", { pokemonName: pokemon.name, moveName: move.getName() })); + } return true; } return false; @@ -3200,6 +3203,50 @@ export class MoneyAbAttr extends PostBattleAbAttr { } } +/** + * Applies a stat change after a Pokémon is summoned, + * conditioned on the presence of a specific arena tag. + * + * @extends {PostSummonStatChangeAbAttr} + */ +export class PostSummonStatChangeOnArenaAbAttr extends PostSummonStatChangeAbAttr { + /** + * The type of arena tag that conditions the stat change. + * @private + * @type {ArenaTagType} + */ + private tagType: ArenaTagType; + + /** + * Creates an instance of PostSummonStatChangeOnArenaAbAttr. + * Initializes the stat change to increase Attack by 1 stage if the specified arena tag is present. + * + * @param {ArenaTagType} tagType - The type of arena tag to check for. + */ + constructor(tagType: ArenaTagType) { + super([BattleStat.ATK], 1, true, false); + this.tagType = tagType; + } + + /** + * Applies the post-summon stat change if the specified arena tag is present on pokemon's side. + * This is used in Wind Rider ability. + * + * @param {Pokemon} pokemon - The Pokémon being summoned. + * @param {boolean} passive - Whether the effect is passive. + * @param {any[]} args - Additional arguments. + * @returns {boolean} - Returns true if the stat change was applied, otherwise false. + */ + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + const side = pokemon.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; + + if (pokemon.scene.arena.getTagOnSide(this.tagType, side)) { + return super.applyPostSummon(pokemon, passive, args); + } + return false; + } +} + function applyAbAttrsInternal(attrType: { new(...args: any[]): TAttr }, pokemon: Pokemon, applyFunc: AbAttrApplyFunc, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise { return new Promise(resolve => { @@ -4270,9 +4317,9 @@ export function initAbilities() { .attr(TypeImmunityStatChangeAbAttr, Type.FIRE, BattleStat.DEF, 2) .ignorable(), new Ability(Abilities.WIND_RIDER, 9) - .attr(MoveImmunityStatChangeAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.getMove().hasFlag(MoveFlags.WIND_MOVE), BattleStat.ATK, 1) - .ignorable() - .partial(), + .attr(MoveImmunityStatChangeAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.getMove().hasFlag(MoveFlags.WIND_MOVE) && move.getMove().category !== MoveCategory.STATUS, BattleStat.ATK, 1) + .attr(PostSummonStatChangeOnArenaAbAttr, ArenaTagType.TAILWIND) + .ignorable(), new Ability(Abilities.GUARD_DOG, 9) .attr(PostIntimidateStatChangeAbAttr, [BattleStat.ATK], 1, true) .attr(ForceSwitchOutImmunityAbAttr) @@ -4280,8 +4327,7 @@ export function initAbilities() { new Ability(Abilities.ROCKY_PAYLOAD, 9) .attr(MoveTypePowerBoostAbAttr, Type.ROCK), new Ability(Abilities.WIND_POWER, 9) - .attr(PostDefendApplyBattlerTagAbAttr, (target, user, move) => move.hasFlag(MoveFlags.WIND_MOVE), BattlerTagType.CHARGED) - .partial(), + .attr(PostDefendApplyBattlerTagAbAttr, (target, user, move) => move.hasFlag(MoveFlags.WIND_MOVE), BattlerTagType.CHARGED), new Ability(Abilities.ZERO_TO_HERO, 9) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index 3057132cafc..37de1af2efa 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -4,7 +4,7 @@ import * as Utils from "../utils"; import { MoveCategory, allMoves, MoveTarget } from "./move"; import { getPokemonMessage } from "../messages"; import Pokemon, { HitResult, PokemonMove } from "../field/pokemon"; -import { MoveEffectPhase, PokemonHealPhase, StatChangePhase} from "../phases"; +import { MoveEffectPhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase} from "../phases"; import { StatusEffect } from "./status-effect"; import { BattlerIndex } from "../battle"; import { Moves } from "./enums/moves"; @@ -12,6 +12,9 @@ import { ArenaTagType } from "./enums/arena-tag-type"; import { BlockNonDirectDamageAbAttr, ProtectStatAbAttr, applyAbAttrs } from "./ability"; import { BattleStat } from "./battle-stat"; import { CommonAnim, CommonBattleAnim } from "./battle-anims"; +import { Abilities } from "./enums/abilities"; +import { BattlerTagType } from "./enums/battler-tag-type"; +import i18next from "i18next"; export enum ArenaTagSide { BOTH, @@ -625,6 +628,22 @@ class TailwindTag extends ArenaTag { onAdd(arena: Arena): void { arena.scene.queueMessage(`The Tailwind blew from behind${this.side === ArenaTagSide.PLAYER ? "\nyour" : this.side === ArenaTagSide.ENEMY ? "\nthe opposing" : ""} team!`); + + const source = arena.scene.getPokemonById(this.sourceId); + const party = source.isPlayer() ? source.scene.getPlayerField() : source.scene.getEnemyField(); + + for (const pokemon of party) { + // Apply the CHARGED tag to party members with the WIND_POWER ability + if (pokemon.hasAbility(Abilities.WIND_POWER) && !pokemon.getTag(BattlerTagType.CHARGED)) { + pokemon.addTag(BattlerTagType.CHARGED); + pokemon.scene.queueMessage(i18next.t("abilityTriggers:windPowerCharged", { pokemonName: pokemon.name, moveName: this.getMoveName() })); + } + // Raise attack by one stage if party member has WIND_RIDER ability + if (pokemon.hasAbility(Abilities.WIND_RIDER)) { + pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.getBattlerIndex())); + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [BattleStat.ATK], 1, true)); + } + } } onRemove(arena: Arena): void { diff --git a/src/locales/de/ability-trigger.ts b/src/locales/de/ability-trigger.ts index da8ef3f7ab0..07853233a01 100644 --- a/src/locales/de/ability-trigger.ts +++ b/src/locales/de/ability-trigger.ts @@ -3,4 +3,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { "blockRecoilDamage" : "{{pokemonName}} wurde durch {{abilityName}}\nvor Rückstoß geschützt!", "badDreams": "{{pokemonName}} ist in einem Alptraum gefangen!", + "windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!", } as const; diff --git a/src/locales/en/ability-trigger.ts b/src/locales/en/ability-trigger.ts index e7542eee4e3..36aee70de47 100644 --- a/src/locales/en/ability-trigger.ts +++ b/src/locales/en/ability-trigger.ts @@ -3,5 +3,6 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { "blockRecoilDamage" : "{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!", "badDreams": "{{pokemonName}} is tormented!", + "windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!", "perishBody": "{{pokemonName}}'s {{abilityName}}\n will faint both pokemon in 3 turns!", } as const; diff --git a/src/locales/es/ability-trigger.ts b/src/locales/es/ability-trigger.ts index bc6a9d4678a..594a67628e8 100644 --- a/src/locales/es/ability-trigger.ts +++ b/src/locales/es/ability-trigger.ts @@ -2,5 +2,6 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { "blockRecoilDamage" : "¡{{abilityName}} de {{pokemonName}}\nlo protegió del daño de retroceso!", - "badDreams": "¡{{pokemonName}} está atormentado!" + "badDreams": "¡{{pokemonName}} está atormentado!", + "windPowerCharged": "¡{{pokemonName}} se ha cargado de electricidad gracias a {{moveName}}!", } as const; diff --git a/src/locales/fr/ability-trigger.ts b/src/locales/fr/ability-trigger.ts index c350a127fa9..eb450117238 100644 --- a/src/locales/fr/ability-trigger.ts +++ b/src/locales/fr/ability-trigger.ts @@ -2,5 +2,6 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { "blockRecoilDamage" : "{{abilityName}}\nde {{pokemonName}} le protège du contrecoup !", - "badDreams": "{{pokemonName}} a le sommeil agité !" + "badDreams": "{{pokemonName}} a le sommeil agité !", + "windPowerCharged": "{{pokemonName}} a été touché par la capacité {{moveName}} et se charge en électricité !" } as const; diff --git a/src/locales/it/ability-trigger.ts b/src/locales/it/ability-trigger.ts index 599235e6195..61053896c49 100644 --- a/src/locales/it/ability-trigger.ts +++ b/src/locales/it/ability-trigger.ts @@ -3,4 +3,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { "blockRecoilDamage" : "{{abilityName}} di {{pokemonName}}\nl'ha protetto dal contraccolpo!", "badDreams": "{{pokemonName}} è tormentato!", + "windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!", } as const; diff --git a/src/locales/pt_BR/ability-trigger.ts b/src/locales/pt_BR/ability-trigger.ts index 8851c885157..6e7dd96646a 100644 --- a/src/locales/pt_BR/ability-trigger.ts +++ b/src/locales/pt_BR/ability-trigger.ts @@ -3,4 +3,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { "blockRecoilDamage" : "{{abilityName}} de {{pokemonName}}\nprotegeu-o do dano de recuo!", "badDreams": "{{pokemonName}} está tendo pesadelos!", + "windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!" } as const; diff --git a/src/locales/zh_CN/ability-trigger.ts b/src/locales/zh_CN/ability-trigger.ts index c8d4a2f6ee2..643952ad352 100644 --- a/src/locales/zh_CN/ability-trigger.ts +++ b/src/locales/zh_CN/ability-trigger.ts @@ -2,5 +2,6 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { "blockRecoilDamage" : "{{pokemonName}} 的 {{abilityName}}\n抵消了反作用力!", - "badDreams": "{{pokemonName}} 被折磨着!" + "badDreams": "{{pokemonName}} 被折磨着!", + "windPowerCharged": "受 {{moveName}} 的影响, {{pokemonName}} 提升了能力!" } as const; diff --git a/src/locales/zh_TW/ability-trigger.ts b/src/locales/zh_TW/ability-trigger.ts index 6c8f4bc4512..1d9a3446785 100644 --- a/src/locales/zh_TW/ability-trigger.ts +++ b/src/locales/zh_TW/ability-trigger.ts @@ -3,4 +3,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { "blockRecoilDamage" : "{{pokemonName}} 的 {{abilityName}}\n抵消了反作用力!", "badDreams": "{{pokemonName}} 被折磨着!", + "windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!" } as const;