From 9853f4cb77bd12dbc007d4b2b3e45d7581ea79e9 Mon Sep 17 00:00:00 2001 From: Matthew Kroeger Date: Wed, 12 Jun 2024 18:44:29 -0500 Subject: [PATCH] initial commit of taunt implementation --- src/data/ability.ts | 16 ++++++++++++++++ src/data/move.ts | 22 +++++++++++++++++++++- src/field/pokemon.ts | 4 +++- src/locales/de/battle.ts | 2 ++ src/locales/en/battle.ts | 2 ++ src/locales/es/battle.ts | 2 ++ src/locales/fr/battle.ts | 2 ++ src/locales/it/battle.ts | 2 ++ src/locales/ko/battle.ts | 2 ++ src/locales/pt_BR/battle.ts | 2 ++ src/locales/zh_CN/battle.ts | 2 ++ src/locales/zh_TW/battle.ts | 2 ++ src/phases.ts | 11 ++++++++++- src/system/pokemon-data.ts | 2 ++ 14 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 5db2e34b2a0b..39d795d5f25b 100755 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -1516,6 +1516,21 @@ export class IgnoreOpponentEvasionAbAttr extends AbAttr { } } +export class TauntImmunityAbAttr extends AbAttr { + constructor() { + super(false); + } + + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + cancelled.value = true; + return true; + } + + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { + return getPokemonMessage(pokemon, `'s ${abilityName} prevented it from being Taunted!`); + } +} + export class IntimidateImmunityAbAttr extends AbAttr { constructor() { super(false); @@ -3780,6 +3795,7 @@ export function initAbilities() { new Ability(Abilities.OBLIVIOUS, 3) .attr(BattlerTagImmunityAbAttr, BattlerTagType.INFATUATED) .attr(IntimidateImmunityAbAttr) + .attr(TauntImmunityAbAttr) .ignorable(), new Ability(Abilities.CLOUD_NINE, 3) .attr(SuppressWeatherEffectAbAttr, true), diff --git a/src/data/move.ts b/src/data/move.ts index 8e1c1ad921d9..0b4045c1b2a9 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -3767,6 +3767,25 @@ export class DisableMoveAttr extends MoveEffectAttr { } } +export class TauntAttr extends MoveEffectAttr { + constructor() { + super(false); + } + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (!super.apply(user, target, move, args)) { + return false; + } + + target.summonData.isTaunted = true; + target.summonData.tauntedTurns = 3; + + user.scene.queueMessage(getPokemonMessage(target, ` fell for the taunt!`)); + + return true; + } +} + export class FrenzyAttr extends MoveEffectAttr { constructor() { super(true, MoveEffectTrigger.HIT); @@ -6163,7 +6182,8 @@ export function initMoves() { .attr(StatChangeAttr, BattleStat.SPDEF, 1, true) .attr(AddBattlerTagAttr, BattlerTagType.CHARGED, true, false), new StatusMove(Moves.TAUNT, Type.DARK, 100, 20, -1, 0, 3) - .unimplemented(), + .attr(TauntAttr) + .condition((user, target, move) => !target.summonData.isTaunted), new StatusMove(Moves.HELPING_HAND, Type.NORMAL, -1, 20, -1, 5, 3) .attr(AddBattlerTagAttr, BattlerTagType.HELPING_HAND) .target(MoveTarget.NEAR_ALLY), diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 7bf3c8ca52df..4f09f26b7e36 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3793,6 +3793,8 @@ export class PokemonSummonData { public moveQueue: QueuedMove[] = []; public disabledMove: Moves = Moves.NONE; public disabledTurns: integer = 0; + public isTaunted: boolean = false; + public tauntedTurns: integer = 0; public tags: BattlerTag[] = []; public abilitySuppressed: boolean = false; @@ -3886,7 +3888,7 @@ export class PokemonMove { } isUsable(pokemon: Pokemon, ignorePp?: boolean): boolean { - if (this.moveId && pokemon.summonData?.disabledMove === this.moveId) { + if (this.moveId && pokemon.summonData?.disabledMove === this.moveId || pokemon.summonData?.isTaunted === true && this.getMove().category === MoveCategory.STATUS) { return false; } return (ignorePp || this.ppUsed < this.getMovePp() || this.getMove().pp === -1) && !this.getMove().name.endsWith(" (N)"); diff --git a/src/locales/de/battle.ts b/src/locales/de/battle.ts index 07687f8a535b..e54182f1a13a 100644 --- a/src/locales/de/battle.ts +++ b/src/locales/de/battle.ts @@ -41,6 +41,7 @@ export const battle: SimpleTranslationEntries = { "moveNotImplemented": "{{moveName}} ist noch nicht implementiert und kann nicht ausgewählt werden.", "moveNoPP": "Es sind keine AP für\ndiese Attacke mehr übrig!", "moveDisabled": "{{moveName}} ist deaktiviert!", + "moveTaunted": "{{pokemonName}} can't use\n{{moveName}} after the taunt!", "noPokeballForce": "Eine unsichtbare Kraft\nverhindert die Nutzung von Pokébällen.", "noPokeballTrainer": "Du kannst das Pokémon\neines anderen Trainers nicht fangen!", "noPokeballMulti": "Du kannst erst einen Pokéball werfen,\nwenn nur noch ein Pokémon übrig ist!", @@ -54,6 +55,7 @@ export const battle: SimpleTranslationEntries = { "escapeVerbFlee": "flucht", "skipItemQuestion": "Bist du sicher, dass du kein Item nehmen willst?", "notDisabled": "{{pokemonName}}'s {{moveName}} ist\nnicht mehr deaktiviert!", + "notTaunted": "The {{pokemonName}} shook off the taunt!", "eggHatching": "Oh?", "ivScannerUseQuestion": "IV-Scanner auf {{pokemonName}} benutzen?", "wildPokemonWithAffix": "{{pokemonName}} (wild)", diff --git a/src/locales/en/battle.ts b/src/locales/en/battle.ts index 52b64b8b6146..d1093f2b10f2 100644 --- a/src/locales/en/battle.ts +++ b/src/locales/en/battle.ts @@ -41,6 +41,7 @@ export const battle: SimpleTranslationEntries = { "moveNotImplemented": "{{moveName}} is not yet implemented and cannot be selected.", "moveNoPP": "There's no PP left for\nthis move!", "moveDisabled": "{{moveName}} is disabled!", + "moveTaunted": "{{pokemonName}} can't use\n{{moveName}} after the taunt!", "noPokeballForce": "An unseen force\nprevents using Poké Balls.", "noPokeballTrainer": "You can't catch\nanother trainer's Pokémon!", "noPokeballMulti": "You can only throw a Poké Ball\nwhen there is one Pokémon remaining!", @@ -53,6 +54,7 @@ export const battle: SimpleTranslationEntries = { "escapeVerbSwitch": "switching", "escapeVerbFlee": "fleeing", "notDisabled": "{{pokemonName}}'s {{moveName}} is disabled\nno more!", + "notTaunted": "The {{pokemonName}} shook off the taunt!", "skipItemQuestion": "Are you sure you want to skip taking an item?", "eggHatching": "Oh?", "ivScannerUseQuestion": "Use IV Scanner on {{pokemonName}}?", diff --git a/src/locales/es/battle.ts b/src/locales/es/battle.ts index 203f42587108..a056b664d08c 100644 --- a/src/locales/es/battle.ts +++ b/src/locales/es/battle.ts @@ -41,6 +41,7 @@ export const battle: SimpleTranslationEntries = { "moveNotImplemented": "{{moveName}} aún no está implementado y no se puede seleccionar.", "moveNoPP": "¡No hay suficientes PP\npara este movimiento!", "moveDisabled": "!No puede usar {{moveName}} porque ha sido anulado!", + "moveTaunted": "{{pokemonName}} can't use\n{{moveName}} after the taunt!", "noPokeballForce": "Una fuerza misteriosa\nte impide usar Poké Balls.", "noPokeballTrainer": "¡No puedes atrapar a los\nPokémon de los demás!", "noPokeballMulti": "¡No se pueden lanzar Poké Balls\ncuando hay más de un Pokémon!", @@ -53,6 +54,7 @@ export const battle: SimpleTranslationEntries = { "escapeVerbSwitch": "cambiar", "escapeVerbFlee": "huir", "notDisabled": "¡El movimiento {{moveName}} de {{pokemonName}}\nya no está anulado!", + "notTaunted": "The {{pokemonName}} shook off the taunt!", "skipItemQuestion": "¿Estás seguro de que no quieres coger un objeto?", "eggHatching": "¿Y esto?", "ivScannerUseQuestion": "¿Quieres usar el Escáner de IVs en {{pokemonName}}?", diff --git a/src/locales/fr/battle.ts b/src/locales/fr/battle.ts index 1593bd3b21f7..b86f68dcdf05 100644 --- a/src/locales/fr/battle.ts +++ b/src/locales/fr/battle.ts @@ -41,6 +41,7 @@ export const battle: SimpleTranslationEntries = { "moveNotImplemented": "{{moveName}} n’est pas encore implémenté et ne peut pas être sélectionné.", "moveNoPP": "Il n’y a plus de PP pour\ncette capacité !", "moveDisabled": "{{moveName}} est sous entrave !", + "moveTaunted": "{{pokemonName}} can't use\n{{moveName}} after the taunt!", "noPokeballForce": "Une force mystérieuse\nempêche l’utilisation des Poké Balls.", "noPokeballTrainer": "Le Dresseur détourne la Ball\nVoler, c’est mal !", "noPokeballMulti": "Impossible ! On ne peut pas viser\nquand il y a deux Pokémon !", @@ -53,6 +54,7 @@ export const battle: SimpleTranslationEntries = { "escapeVerbSwitch": "le changement", "escapeVerbFlee": "la fuite", "notDisabled": "La capacité {{moveName}}\nde {{pokemonName}} n’est plus sous entrave !", + "notTaunted": "The {{pokemonName}} shook off the taunt!", "skipItemQuestion": "Êtes-vous sûr·e de ne pas vouloir prendre d’objet ?", "eggHatching": "Oh ?", "ivScannerUseQuestion": "Utiliser le Scanner d’IV sur {{pokemonName}} ?", diff --git a/src/locales/it/battle.ts b/src/locales/it/battle.ts index 7ef606e11cc7..af900ae9374b 100644 --- a/src/locales/it/battle.ts +++ b/src/locales/it/battle.ts @@ -41,6 +41,7 @@ export const battle: SimpleTranslationEntries = { "moveNotImplemented": "{{moveName}} non è ancora implementata e non può essere selezionata.", "moveNoPP": "Non ci sono PP rimanenti\nper questa mossa!", "moveDisabled": "{{moveName}} è disabilitata!", + "moveTaunted": "{{pokemonName}} can't use\n{{moveName}} after the taunt!", "noPokeballForce": "Una forza misteriosa\nimpedisce l'uso dell Poké Ball.", "noPokeballTrainer": "Non puoi catturare\nPokémon di altri allenatori!", "noPokeballMulti": "Puoi lanciare una Poké Ball\nquando rimane un solo Pokémon!", @@ -53,6 +54,7 @@ export const battle: SimpleTranslationEntries = { "escapeVerbSwitch": "cambiando", "escapeVerbFlee": "fuggendo", "notDisabled": "{{pokemonName}}'s {{moveName}} non è più\ndisabilitata!", + "notTaunted": "The {{pokemonName}} shook off the taunt!", "skipItemQuestion": "Sei sicuro di non voler prendere nessun oggetto?", "eggHatching": "Oh!", "ivScannerUseQuestion": "Vuoi usare lo scanner di IV su {{pokemonName}}?", diff --git a/src/locales/ko/battle.ts b/src/locales/ko/battle.ts index cd81dce400f7..0c9c11dc370e 100644 --- a/src/locales/ko/battle.ts +++ b/src/locales/ko/battle.ts @@ -41,6 +41,7 @@ export const battle: SimpleTranslationEntries = { "moveNotImplemented": "{{moveName}}[[는]] 아직 구현되지 않아 사용할 수 없다…", "moveNoPP": "기술의 남은 포인트가 없다!", "moveDisabled": "{{moveName}}[[를]] 쓸 수 없다!", + "moveTaunted": "{{pokemonName}} can't use\n{{moveName}} after the taunt!", "noPokeballForce": "본 적 없는 힘이\n볼을 사용하지 못하게 한다.", "noPokeballTrainer": "다른 트레이너의 포켓몬은 잡을 수 없다!", "noPokeballMulti": "안돼! 2마리 있어서\n목표를 정할 수가 없어…!", @@ -53,6 +54,7 @@ export const battle: SimpleTranslationEntries = { "escapeVerbSwitch": "교체할", "escapeVerbFlee": "도망칠", "notDisabled": "{{pokemonName}}의\n{{moveName}} 사슬묶기가 풀렸다!", + "notTaunted": "The {{pokemonName}} shook off the taunt!", "skipItemQuestion": "아이템을 받지 않고 넘어가시겠습니까?", "eggHatching": "어라…?", "ivScannerUseQuestion": "{{pokemonName}}에게 개체값탐지기를 사용하시겠습니까?", diff --git a/src/locales/pt_BR/battle.ts b/src/locales/pt_BR/battle.ts index 3ca43006ac60..4844620a56c3 100644 --- a/src/locales/pt_BR/battle.ts +++ b/src/locales/pt_BR/battle.ts @@ -41,6 +41,7 @@ export const battle: SimpleTranslationEntries = { "moveNotImplemented": "{{moveName}} ainda não foi implementado e não pode ser usado.", "moveNoPP": "Não há mais PP\npara esse movimento!", "moveDisabled": "Não se pode usar {{moveName}} porque foi desabilitado!", + "moveTaunted": "{{pokemonName}} can't use\n{{moveName}} after the taunt!", "noPokeballForce": "Uma força misteriosa\nte impede de usar Poké Bolas.", "noPokeballTrainer": "Não se pode capturar\nPokémon dos outros!", "noPokeballMulti": "Não se pode lançar Poké Bolas\nquando há mais de um Pokémon!", @@ -53,6 +54,7 @@ export const battle: SimpleTranslationEntries = { "escapeVerbSwitch": "trocar", "escapeVerbFlee": "fugir", "notDisabled": "O movimento {{moveName}}\nnão está mais desabilitado!", + "notTaunted": "The {{pokemonName}} shook off the taunt!", "skipItemQuestion": "Tem certeza de que não quer escolher um item?", "eggHatching": "Opa?", "ivScannerUseQuestion": "Quer usar o Scanner de IVs em {{pokemonName}}?", diff --git a/src/locales/zh_CN/battle.ts b/src/locales/zh_CN/battle.ts index 3b7451f5cde3..20058c79dfb3 100644 --- a/src/locales/zh_CN/battle.ts +++ b/src/locales/zh_CN/battle.ts @@ -41,6 +41,7 @@ export const battle: SimpleTranslationEntries = { "moveNotImplemented": "{{moveName}} 尚未实装,无法选择。", "moveNoPP": "这个技能的 PP 用完了", "moveDisabled": "{{moveName}} 被禁用!", + "moveTaunted": "{{pokemonName}} can't use\n{{moveName}} after the taunt!", "noPokeballForce": "一股无形的力量阻止了你使用精灵球。", "noPokeballTrainer": "你不能捕捉其他训练家的宝可梦!", "noPokeballMulti": "只能在剩下一只宝可梦时才能扔出精灵球!", @@ -53,6 +54,7 @@ export const battle: SimpleTranslationEntries = { "escapeVerbSwitch": "切换", "escapeVerbFlee": "逃跑", "notDisabled": "{{moveName}} 不再被禁用!", + "notTaunted": "The {{pokemonName}} shook off the taunt!", "skipItemQuestion": "你确定要跳过拾取道具吗?", "eggHatching": "咦?", "ivScannerUseQuestion": "对 {{pokemonName}} 使用个体值扫描仪?", diff --git a/src/locales/zh_TW/battle.ts b/src/locales/zh_TW/battle.ts index 086f0cf92662..9080966e7340 100644 --- a/src/locales/zh_TW/battle.ts +++ b/src/locales/zh_TW/battle.ts @@ -38,6 +38,7 @@ export const battle: SimpleTranslationEntries = { "moveNotImplemented": "{{moveName}} 未實裝,無法選擇。", "moveNoPP": "這個技能的PP用完了", "moveDisabled": "{{moveName}} 被禁用!", + "moveTaunted": "{{pokemonName}} can't use\n{{moveName}} after the taunt!", "noPokeballForce": "一股無形的力量阻止了你使用精靈球。", "noPokeballTrainer": "你不能捕捉其他訓練家的寶可夢!", "noPokeballMulti": "只能在剩下一隻寶可夢時才能扔出精靈球!", @@ -50,6 +51,7 @@ export const battle: SimpleTranslationEntries = { "escapeVerbSwitch": "切換", "escapeVerbFlee": "逃跑", "notDisabled": "{{moveName}} 不再被禁用!", + "notTaunted": "The {{pokemonName}} shook off the taunt!", "skipItemQuestion": "你要跳過拾取道具嗎?", "eggHatching": "咦?", "ivScannerUseQuestion": "對 {{pokemonName}} 使用個體值掃描?", diff --git a/src/phases.ts b/src/phases.ts index d01b83d837a4..06b9942e74e5 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -1939,8 +1939,9 @@ export class CommandPhase extends FieldPhase { const move = playerPokemon.getMoveset()[cursor]; this.scene.ui.setMode(Mode.MESSAGE); - // Decides between a Disabled, Not Implemented, or No PP translation message + // Decides between a Taunted, Disabled, Not Implemented, or No PP translation message const errorMessage = + playerPokemon.summonData.isTaunted === true ? "battle:moveTaunted": playerPokemon.summonData.disabledMove === move.moveId ? "battle:moveDisabled" : move.getName().endsWith(" (N)") ? "battle:moveNotImplemented" : "battle:moveNoPP"; const moveName = move.getName().replace(" (N)", ""); // Trims off the indicator @@ -2385,6 +2386,11 @@ export class TurnEndPhase extends FieldPhase { pokemon.summonData.disabledMove = Moves.NONE; } + if (pokemon.summonData.isTaunted && !--pokemon.summonData.tauntedTurns) { + this.scene.pushPhase(new MessagePhase(this.scene, i18next.t("battle:notTaunted", { pokemonName: getPokemonNameWithAffix(pokemon)}))); + pokemon.summonData.isTaunted = false; + } + this.scene.applyModifiers(TurnHealModifier, pokemon.isPlayer(), pokemon); if (this.scene.arena.terrain?.terrainType === TerrainType.GRASSY && pokemon.isGrounded()) { @@ -2549,6 +2555,9 @@ export class MovePhase extends BattlePhase { if (this.move.moveId && this.pokemon.summonData?.disabledMove === this.move.moveId) { this.scene.queueMessage(`${this.move.getName()} is disabled!`); } + else if (this.move.moveId && this.pokemon.summonData?.isTaunted) { + this.scene.queueMessage(`${this.pokemon.name} can't use\n${this.move.getName()} after the taunt!`); + } return this.end(); } diff --git a/src/system/pokemon-data.ts b/src/system/pokemon-data.ts index 0aa72f978012..01e1180571c0 100644 --- a/src/system/pokemon-data.ts +++ b/src/system/pokemon-data.ts @@ -120,6 +120,8 @@ export default class PokemonData { this.summonData.moveQueue = source.summonData.moveQueue; this.summonData.disabledMove = source.summonData.disabledMove; this.summonData.disabledTurns = source.summonData.disabledTurns; + this.summonData.isTaunted = source.summonData.isTaunted; + this.summonData.tauntedTurns = source.summonData.tauntedTurns; this.summonData.abilitySuppressed = source.summonData.abilitySuppressed; this.summonData.ability = source.summonData.ability;