From f88f01554ae4e63ccf60b506268ba122d3dda0b9 Mon Sep 17 00:00:00 2001 From: Reldnahc Date: Wed, 1 May 2024 23:04:15 -0500 Subject: [PATCH] start for magic coat. Currently, when used on an arena trap the arena tag is getting set on both sides. --- src/data/battler-tags.ts | 8 ++++++ src/data/enums/battler-tag-type.ts | 3 ++- src/data/move.ts | 39 +++++++++++++++++++++++------- src/phases.ts | 7 +++++- 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index aaab9f9a4a2..147dc7499ff 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -761,6 +761,12 @@ export class ContactBurnProtectedTag extends ProtectedTag { } } +export class BounceTag extends BattlerTag { + constructor(sourceMove: Moves, tagType: BattlerTagType = BattlerTagType.BOUNCE) { + super(tagType, BattlerTagLapseType.CUSTOM, 0, sourceMove); + } +} + export class EnduringTag extends BattlerTag { constructor(sourceMove: Moves) { super(BattlerTagType.ENDURING, BattlerTagLapseType.TURN_END, 0, sourceMove); @@ -1178,6 +1184,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc return new CursedTag(sourceId); case BattlerTagType.CHARGED: return new TypeBoostTag(tagType, sourceMove, Type.ELECTRIC, 2, true); + case BattlerTagType.BOUNCE: + return new BounceTag(sourceMove); case BattlerTagType.NONE: default: return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId); diff --git a/src/data/enums/battler-tag-type.ts b/src/data/enums/battler-tag-type.ts index 4d810b737aa..91e61c6c282 100644 --- a/src/data/enums/battler-tag-type.ts +++ b/src/data/enums/battler-tag-type.ts @@ -52,5 +52,6 @@ export enum BattlerTagType { SALT_CURED = "SALT_CURED", CURSED = "CURSED", CHARGED = "CHARGED", - GROUNDED = "GROUNDED" + GROUNDED = "GROUNDED", + BOUNCE = "BOUNCE" } diff --git a/src/data/move.ts b/src/data/move.ts index 5d5fec95729..c1a3146d9b6 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -69,7 +69,9 @@ export enum MoveFlags { DANCE_MOVE = 4096, WIND_MOVE = 8192, TRIAGE_MOVE = 16384, - IGNORE_ABILITIES = 32768 + IGNORE_ABILITIES = 32768, + MAGIC_COAT_MOVE = 65536 + } type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean; @@ -294,6 +296,11 @@ export default class Move implements Localizable { return this; } + magicCoatMove(magicCoatMove?: boolean): this { + this.setFlag(MoveFlags.MAGIC_COAT_MOVE, magicCoatMove); + return this; + } + ignoresAbilities(ignoresAbilities?: boolean): this { this.setFlag(MoveFlags.IGNORE_ABILITIES, ignoresAbilities); return this; @@ -3868,7 +3875,8 @@ export function initMoves() { .attr(FixedDamageAttr, 20), new StatusMove(Moves.DISABLE, Type.NORMAL, 100, 20, -1, 0, 1) .attr(DisableMoveAttr) - .condition(failOnMaxCondition), + .condition(failOnMaxCondition) + .magicCoatMove(), new AttackMove(Moves.ACID, Type.POISON, MoveCategory.SPECIAL, 40, 100, 30, 10, 0, 1) .attr(StatChangeAttr, BattleStat.SPDEF, -1) .target(MoveTarget.ALL_NEAR_ENEMIES), @@ -3980,6 +3988,7 @@ export function initMoves() { .attr(ChargeAttr, ChargeAnim.DIG_CHARGING, 'dug a hole!', BattlerTagType.UNDERGROUND) .ignoresVirtual(), new StatusMove(Moves.TOXIC, Type.POISON, 90, 10, -1, 0, 1) + .magicCoatMove() .attr(StatusEffectAttr, StatusEffect.TOXIC) .attr(ToxicAccuracyAttr), new AttackMove(Moves.CONFUSION, Type.PSYCHIC, MoveCategory.SPECIAL, 50, 100, 25, 10, 0, 1) @@ -4018,7 +4027,8 @@ export function initMoves() { new StatusMove(Moves.SMOKESCREEN, Type.NORMAL, 100, 20, -1, 0, 1) .attr(StatChangeAttr, BattleStat.ACC, -1), new StatusMove(Moves.CONFUSE_RAY, Type.GHOST, 100, 10, -1, 0, 1) - .attr(ConfuseAttr), + .attr(ConfuseAttr) + .magicCoatMove(), new SelfStatusMove(Moves.WITHDRAW, Type.WATER, -1, 40, -1, 0, 1) .attr(StatChangeAttr, BattleStat.DEF, 1, true), new SelfStatusMove(Moves.DEFENSE_CURL, Type.NORMAL, -1, 40, -1, 0, 1) @@ -4221,7 +4231,8 @@ export function initMoves() { new StatusMove(Moves.COTTON_SPORE, Type.GRASS, 100, 40, -1, 0, 2) .attr(StatChangeAttr, BattleStat.SPD, -2) .powderMove() - .target(MoveTarget.ALL_NEAR_ENEMIES), + .target(MoveTarget.ALL_NEAR_ENEMIES) + .magicCoatMove(), new AttackMove(Moves.REVERSAL, Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 15, -1, 0, 2) .attr(LowHpPowerAttr), new StatusMove(Moves.SPITE, Type.GHOST, 100, 10, -1, 0, 2) @@ -4290,6 +4301,7 @@ export function initMoves() { new SelfStatusMove(Moves.ENDURE, Type.NORMAL, -1, 10, -1, 4, 2) .attr(EndureAttr), new StatusMove(Moves.CHARM, Type.FAIRY, 100, 20, -1, 0, 2) + .magicCoatMove() .attr(StatChangeAttr, BattleStat.ATK, -2), new AttackMove(Moves.ROLLOUT, Type.ROCK, MoveCategory.PHYSICAL, 30, 90, 20, -1, 0, 2) .attr(ConsecutiveUseDoublePowerAttr, 5, true, true, Moves.DEFENSE_CURL), @@ -4311,6 +4323,7 @@ export function initMoves() { new StatusMove(Moves.MEAN_LOOK, Type.NORMAL, -1, 5, -1, 0, 2) .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1), new StatusMove(Moves.ATTRACT, Type.NORMAL, 100, 15, -1, 0, 2) + .magicCoatMove() .attr(AddBattlerTagAttr, BattlerTagType.INFATUATED) .condition((user, target, move) => user.isOppositeGender(target)), new SelfStatusMove(Moves.SLEEP_TALK, Type.NORMAL, -1, 10, -1, 0, 2) @@ -4502,7 +4515,7 @@ export function initMoves() { new AttackMove(Moves.SUPERPOWER, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, 100, 0, 3) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1, true), new SelfStatusMove(Moves.MAGIC_COAT, Type.PSYCHIC, -1, 15, -1, 4, 3) - .unimplemented(), + .attr(AddBattlerTagAttr, BattlerTagType.BOUNCE), new SelfStatusMove(Moves.RECYCLE, Type.NORMAL, -1, 10, -1, 0, 3) .unimplemented(), new AttackMove(Moves.REVENGE, Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, -4, 3) @@ -4655,6 +4668,7 @@ export function initMoves() { new SelfStatusMove(Moves.IRON_DEFENSE, Type.STEEL, -1, 15, -1, 0, 3) .attr(StatChangeAttr, BattleStat.DEF, 2, true), new StatusMove(Moves.BLOCK, Type.NORMAL, -1, 5, -1, 0, 3) + .magicCoatMove() .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1), new StatusMove(Moves.HOWL, Type.NORMAL, -1, 40, -1, 0, 3) .attr(StatChangeAttr, BattleStat.ATK, 1) @@ -4814,6 +4828,7 @@ export function initMoves() { new AttackMove(Moves.SUCKER_PUNCH, Type.DARK, MoveCategory.PHYSICAL, 70, 100, 5, -1, 1, 4) .condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].category !== MoveCategory.STATUS), new StatusMove(Moves.TOXIC_SPIKES, Type.POISON, -1, 20, -1, 0, 4) + .magicCoatMove() .attr(AddArenaTrapTagAttr, ArenaTagType.TOXIC_SPIKES) .target(MoveTarget.ENEMY_SIDE), new StatusMove(Moves.HEART_SWAP, Type.PSYCHIC, -1, 10, -1, 0, 4) @@ -4920,7 +4935,8 @@ export function initMoves() { .attr(StatChangeAttr, BattleStat.EVA, -1) .attr(ClearWeatherAttr, WeatherType.FOG) .attr(ClearTerrainAttr) - .attr(RemoveScreensAttr, true), + .attr(RemoveScreensAttr, true) + .magicCoatMove(), new StatusMove(Moves.TRICK_ROOM, Type.PSYCHIC, -1, 5, -1, -7, 4) .attr(AddArenaTagAttr, ArenaTagType.TRICK_ROOM, 5) .ignoresProtect() @@ -4958,10 +4974,12 @@ export function initMoves() { new StatusMove(Moves.CAPTIVATE, Type.NORMAL, 100, 20, -1, 0, 4) .attr(StatChangeAttr, BattleStat.SPATK, -2) .condition((user, target, move) => target.isOppositeGender(user)) - .target(MoveTarget.ALL_NEAR_ENEMIES), + .target(MoveTarget.ALL_NEAR_ENEMIES) + .magicCoatMove(), new StatusMove(Moves.STEALTH_ROCK, Type.ROCK, -1, 20, -1, 0, 4) .attr(AddArenaTrapTagAttr, ArenaTagType.STEALTH_ROCK) - .target(MoveTarget.ENEMY_SIDE), + .target(MoveTarget.ENEMY_SIDE) + .magicCoatMove(), new AttackMove(Moves.GRASS_KNOT, Type.GRASS, MoveCategory.SPECIAL, -1, 100, 20, -1, 0, 4) .attr(WeightPowerAttr) .makesContact() @@ -5005,7 +5023,8 @@ export function initMoves() { .attr(TrapAttr, BattlerTagType.MAGMA_STORM), new StatusMove(Moves.DARK_VOID, Type.DARK, 50, 10, -1, 0, 4) .attr(StatusEffectAttr, StatusEffect.SLEEP) - .target(MoveTarget.ALL_NEAR_ENEMIES), + .target(MoveTarget.ALL_NEAR_ENEMIES) + .magicCoatMove(), new AttackMove(Moves.SEED_FLARE, Type.GRASS, MoveCategory.SPECIAL, 120, 85, 5, 40, 0, 4) .attr(StatChangeAttr, BattleStat.SPDEF, -1), new AttackMove(Moves.OMINOUS_WIND, Type.GHOST, MoveCategory.SPECIAL, 60, 100, 5, 10, 0, 4) @@ -5392,6 +5411,7 @@ export function initMoves() { new StatusMove(Moves.HOLD_HANDS, Type.NORMAL, -1, 40, -1, 0, 6) .target(MoveTarget.NEAR_ALLY), new StatusMove(Moves.BABY_DOLL_EYES, Type.FAIRY, 100, 30, -1, 1, 6) + .magicCoatMove() .attr(StatChangeAttr, BattleStat.ATK, -1), new AttackMove(Moves.NUZZLE, Type.ELECTRIC, MoveCategory.PHYSICAL, 20, 100, 20, 100, 0, 6) .attr(StatusEffectAttr, StatusEffect.PARALYSIS), @@ -5931,6 +5951,7 @@ export function initMoves() { .partial(), new StatusMove(Moves.CORROSIVE_GAS, Type.POISON, 100, 40, -1, 0, 8) .target(MoveTarget.ALL_NEAR_OTHERS) + .magicCoatMove() .unimplemented(), new StatusMove(Moves.COACHING, Type.FIGHTING, -1, 10, 100, 0, 8) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], 1) diff --git a/src/phases.ts b/src/phases.ts index 8eda33de20e..a120e5224d2 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -21,7 +21,7 @@ import { Biome } from "./data/enums/biome"; import { ModifierTier } from "./modifier/modifier-tier"; import { FusePokemonModifierType, ModifierPoolType, ModifierType, ModifierTypeFunc, ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, RememberMoveModifierType, TmModifierType, getDailyRunStarterModifiers, getEnemyBuffModifierForWave, getModifierType, getPlayerModifierTypeOptions, getPlayerShopModifierTypeOptionsForWave, modifierTypes, regenerateModifierPoolThresholds } from "./modifier/modifier-type"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; -import { BattlerTagLapseType, EncoreTag, HideSpriteTag as HiddenTag, ProtectedTag, TrappedTag } from "./data/battler-tags"; +import { BattlerTagLapseType, BounceTag, EncoreTag, HideSpriteTag as HiddenTag, ProtectedTag, TrappedTag } from "./data/battler-tags"; import { BattlerTagType } from "./data/enums/battler-tag-type"; import { getPokemonMessage } from "./messages"; import { Starter } from "./ui/starter-select-ui-handler"; @@ -2262,11 +2262,16 @@ export class MovePhase extends BattlePhase { // Assume conditions affecting targets only apply to moves with a single target let success = this.move.getMove().applyConditions(this.pokemon, targets[0], this.move.getMove()); let failedText = null; + const isBounced = this.move.getMove().hasFlag(MoveFlags.MAGIC_COAT_MOVE) && targets[0].findTags(t => t instanceof BounceTag).find(t => targets[0].lapseTag(t.tagType)); if (success && this.scene.arena.isMoveWeatherCancelled(this.move.getMove())) success = false; else if (success && this.scene.arena.isMoveTerrainCancelled(this.pokemon, this.move.getMove())) { success = false; failedText = getTerrainBlockMessage(targets[0], this.scene.arena.terrain.terrainType); + } else if (success && isBounced) { + this.showFailedText(this.pokemon.getOpponentDescriptor() + "\nbounced the move back!"); + this.targets = [this.pokemon.getBattlerIndex()]; + this.pokemon = targets[0]; } if (success) this.scene.unshiftPhase(this.getEffectPhase());