From 4dd694acb232c3ee8c74520ff7f6023c9689f783 Mon Sep 17 00:00:00 2001 From: Temps Ray Date: Mon, 22 Apr 2024 16:05:34 -0400 Subject: [PATCH 1/6] Implement Forewarn, Frisk, and BattlerTags for Magnet Rise (WIP) --- src/data/ability.ts | 56 ++++++++++++++++++++++++++++-- src/data/battler-tags.ts | 15 ++++++++ src/data/enums/battler-tag-type.ts | 3 +- 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index bfc608dc7e0..ed6e72e4555 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -9,7 +9,7 @@ import { BattlerTag } from "./battler-tags"; import { BattlerTagType } from "./enums/battler-tag-type"; import { StatusEffect, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect"; import { Gender } from "./gender"; -import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves } from "./move"; +import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves, StatusMove } from "./move"; import { ArenaTagSide, ArenaTrapTag } from "./arena-tag"; import { ArenaTagType } from "./enums/arena-tag-type"; import { Stat } from "./pokemon-stat"; @@ -1640,6 +1640,54 @@ function getAnticipationCondition(): AbAttrCondition { }; } +export class ForewarnAbAttr extends PostSummonAbAttr { + constructor() { + super(true); + } + + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + let maxPowerSeen = 0; + let maxMove = ""; + let movePower = 0; + for (let opponent of pokemon.getOpponents()) { + for (let move of opponent.moveset) { + if (move.getMove() instanceof StatusMove) { + movePower = 1; + } else { + if (move.getMove().hasFlag(MoveFlags.OHKO_Move)) { + movePower = 150; + } else if (move.getMove().id === Moves.COUNTER || move.getMove().id === Moves.MIRROR_COAT || move.getMove().id === Moves.METAL_BURST) { + movePower = 120; + } else if (move.getMove().power === -1) { + movePower = 80; + } else { + movePower = move.getMove().power; + } + } + if (movePower > maxPowerSeen) { + maxPowerSeen = movePower; + maxMove = move.getName(); + } + } + } + pokemon.scene.queueMessage(getPokemonMessage(pokemon, " was forewarned about " + maxMove + "!")); + return true; + } +} + +export class FriskAbAttr extends PostSummonAbAttr { + constructor() { + super(true); + } + + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + for (let opponent of pokemon.getOpponents()) { + pokemon.scene.queueMessage(getPokemonMessage(pokemon, " frisked " + opponent.name + "\'s " + opponent.getAbility().name + "!")); + } + return true; + } +} + export class PostWeatherChangeAbAttr extends AbAttr { applyPostWeatherChange(pokemon: Pokemon, passive: boolean, weather: WeatherType, args: any[]): boolean { return false; @@ -2669,7 +2717,8 @@ export function initAbilities() { .bypassFaint(), new Ability(Abilities.ANTICIPATION, "Anticipation", "The Pokémon can sense an opposing Pokémon's dangerous moves.", 4) .conditionalAttr(getAnticipationCondition(), PostSummonMessageAbAttr, (pokemon: Pokemon) => getPokemonMessage(pokemon, ' shuddered!')), - new Ability(Abilities.FOREWARN, "Forewarn (N)", "When it enters a battle, the Pokémon can tell one of the moves an opposing Pokémon has.", 4), + new Ability(Abilities.FOREWARN, "Forewarn", "When it enters a battle, the Pokémon can tell one of the moves an opposing Pokémon has.", 4) + .attr(ForewarnAbAttr), new Ability(Abilities.UNAWARE, "Unaware", "When attacking, the Pokémon ignores the target Pokémon's stat changes.", 4) .attr(IgnoreOpponentStatChangesAbAttr) .ignorable(), @@ -2695,7 +2744,8 @@ export function initAbilities() { .attr(PostSummonWeatherChangeAbAttr, WeatherType.SNOW) .attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.SNOW), new Ability(Abilities.HONEY_GATHER, "Honey Gather (N)", "The Pokémon may gather Honey after a battle.", 4), - new Ability(Abilities.FRISK, "Frisk (N)", "When it enters a battle, the Pokémon can check an opposing Pokémon's held item.", 4), + new Ability(Abilities.FRISK, "Frisk", "When it enters a battle, the Pokémon can check an opposing Pokémon's ability.", 4) + .attr(FriskAbAttr), new Ability(Abilities.RECKLESS, "Reckless", "Powers up moves that have recoil damage.", 4) .attr(MovePowerBoostAbAttr, (user, target, move) => move.getAttrs(RecoilAttr).length && move.id !== Moves.STRUGGLE, 1.2), new Ability(Abilities.MULTITYPE, "Multitype (N)", "Changes the Pokémon's type to match the Plate or Z-Crystal it holds.", 4) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 25ff41ec3e2..723ea775967 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -934,6 +934,19 @@ export class HideSpriteTag extends BattlerTag { } } +export class TypeImmuneTag extends BattlerTag { + public immuneType: Type; + constructor(tagType: BattlerTagType, sourceMove: Moves, immuneType: Type, length: number) { + super(tagType, BattlerTagLapseType.TURN_END, 1, sourceMove); + } +} + +export class MagnetRisenTag extends TypeImmuneTag { + constructor(tagType: BattlerTagType, sourceMove: Moves) { + super(tagType, sourceMove, Type.GROUND, 5); + } +} + export class TypeBoostTag extends BattlerTag { public boostedType: Type; public boostValue: number; @@ -1155,6 +1168,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.MAGNET_RISEN: + return new MagnetRisenTag(tagType, 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 9c740ef4629..fa83ad1468c 100644 --- a/src/data/enums/battler-tag-type.ts +++ b/src/data/enums/battler-tag-type.ts @@ -51,5 +51,6 @@ export enum BattlerTagType { SALT_CURED = "SALT_CURED", CURSED = "CURSED", CHARGED = "CHARGED", - GROUNDED = "GROUNDED" + GROUNDED = "GROUNDED", + MAGNET_RISEN = "MAGNET_RISEN" } From aff79e508f9b0b5622ab7a7bc1d332efe480f238 Mon Sep 17 00:00:00 2001 From: Temps Ray Date: Mon, 22 Apr 2024 16:10:37 -0400 Subject: [PATCH 2/6] Fix if/else formatting --- src/data/ability.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index ed6e72e4555..a7dadb479aa 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -1653,17 +1653,16 @@ export class ForewarnAbAttr extends PostSummonAbAttr { for (let move of opponent.moveset) { if (move.getMove() instanceof StatusMove) { movePower = 1; + } else if (move.getMove().hasFlag(MoveFlags.OHKO_Move)) { + movePower = 150; + } else if (move.getMove().id === Moves.COUNTER || move.getMove().id === Moves.MIRROR_COAT || move.getMove().id === Moves.METAL_BURST) { + movePower = 120; + } else if (move.getMove().power === -1) { + movePower = 80; } else { - if (move.getMove().hasFlag(MoveFlags.OHKO_Move)) { - movePower = 150; - } else if (move.getMove().id === Moves.COUNTER || move.getMove().id === Moves.MIRROR_COAT || move.getMove().id === Moves.METAL_BURST) { - movePower = 120; - } else if (move.getMove().power === -1) { - movePower = 80; - } else { - movePower = move.getMove().power; - } + movePower = move.getMove().power; } + if (movePower > maxPowerSeen) { maxPowerSeen = movePower; maxMove = move.getName(); From 3265ef20d4bce5e0f6d68d5f74cd21db2c3701bb Mon Sep 17 00:00:00 2001 From: Temps Ray Date: Mon, 22 Apr 2024 16:11:44 -0400 Subject: [PATCH 3/6] Forgot OHKO move flags --- src/data/move.ts | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 79364fb41d0..40391b31923 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -69,7 +69,8 @@ export enum MoveFlags { DANCE_MOVE = 4096, WIND_MOVE = 8192, TRIAGE_MOVE = 16384, - IGNORE_ABILITIES = 32768 + IGNORE_ABILITIES = 32768, + OHKO_Move = 65536 } type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean; @@ -234,6 +235,11 @@ export default class Move implements Localizable { return this; } + OHKOMove(ohko?: boolean): this { + this.setFlag(MoveFlags.OHKO_Move, ohko); + return this; + } + soundBased(soundBased?: boolean): this { this.setFlag(MoveFlags.SOUND_BASED, soundBased); return this; @@ -3709,7 +3715,8 @@ export function initMoves() { new AttackMove(Moves.VISE_GRIP, Type.NORMAL, MoveCategory.PHYSICAL, 55, 100, 30, -1, 0, 1), new AttackMove(Moves.GUILLOTINE, Type.NORMAL, MoveCategory.PHYSICAL, 200, 30, 5, -1, 0, 1) .attr(OneHitKOAttr) - .attr(OneHitKOAccuracyAttr), + .attr(OneHitKOAccuracyAttr) + .OHKOMove(), new AttackMove(Moves.RAZOR_WIND, Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 1) .attr(ChargeAttr, ChargeAnim.RAZOR_WIND_CHARGING, 'whipped\nup a whirlwind!') .attr(HighCritAttr) @@ -3758,7 +3765,8 @@ export function initMoves() { .attr(MultiHitAttr), new AttackMove(Moves.HORN_DRILL, Type.NORMAL, MoveCategory.PHYSICAL, 200, 30, 5, -1, 0, 1) .attr(OneHitKOAttr) - .attr(OneHitKOAccuracyAttr), + .attr(OneHitKOAccuracyAttr) + .OHKOMove(), new AttackMove(Moves.TACKLE, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 35, -1, 0, 1), new AttackMove(Moves.BODY_SLAM, Type.NORMAL, MoveCategory.PHYSICAL, 85, 100, 15, 30, 0, 1) .attr(StatusEffectAttr, StatusEffect.PARALYSIS), @@ -3914,7 +3922,8 @@ export function initMoves() { .attr(OneHitKOAttr) .attr(OneHitKOAccuracyAttr) .attr(HitsTagAttr, BattlerTagType.UNDERGROUND, false) - .makesContact(false), + .makesContact(false) + .OHKOMove(), new AttackMove(Moves.DIG, Type.GROUND, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 1) .attr(ChargeAttr, ChargeAnim.DIG_CHARGING, 'dug a hole!', BattlerTagType.UNDERGROUND) .ignoresVirtual(), @@ -4575,7 +4584,8 @@ export function initMoves() { .makesContact(false), new AttackMove(Moves.SHEER_COLD, Type.ICE, MoveCategory.SPECIAL, 200, 30, 5, -1, 0, 3) .attr(OneHitKOAttr) - .attr(OneHitKOAccuracyAttr), + .attr(OneHitKOAccuracyAttr) + .OHKOMove(), new AttackMove(Moves.MUDDY_WATER, Type.WATER, MoveCategory.SPECIAL, 90, 85, 10, 30, 0, 3) .attr(StatChangeAttr, BattleStat.ACC, -1) .target(MoveTarget.ALL_NEAR_ENEMIES), @@ -4757,6 +4767,10 @@ export function initMoves() { new SelfStatusMove(Moves.AQUA_RING, Type.WATER, -1, 20, -1, 0, 4) .attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, true), new SelfStatusMove(Moves.MAGNET_RISE, Type.ELECTRIC, -1, 10, -1, 0, 4) + .attr(AddBattlerTagAttr, BattlerTagType.MAGNET_RISEN, true, true) + .condition((user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY) && + !user.getTag(BattlerTagType.IGNORE_FLYING) && !user.getTag(BattlerTagType.INGRAIN) && + !user.getTag(BattlerTagType.MAGNET_RISEN)) .unimplemented(), new AttackMove(Moves.FLARE_BLITZ, Type.FIRE, MoveCategory.PHYSICAL, 120, 100, 15, 10, 0, 4) .attr(RecoilAttr, false, 0.33) From d8bb221eff45a83e8ac37b0652bdeed899e66cef Mon Sep 17 00:00:00 2001 From: Temps Ray Date: Wed, 24 Apr 2024 15:13:05 -0400 Subject: [PATCH 4/6] Remove unnecessary ohko flag --- src/data/ability.ts | 2 +- src/data/move.ts | 20 +++++--------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index a7dadb479aa..a62ac6b8e9c 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -1653,7 +1653,7 @@ export class ForewarnAbAttr extends PostSummonAbAttr { for (let move of opponent.moveset) { if (move.getMove() instanceof StatusMove) { movePower = 1; - } else if (move.getMove().hasFlag(MoveFlags.OHKO_Move)) { + } else if (move.getMove().findAttr(attr => attr instanceof OneHitKOAttr)) { movePower = 150; } else if (move.getMove().id === Moves.COUNTER || move.getMove().id === Moves.MIRROR_COAT || move.getMove().id === Moves.METAL_BURST) { movePower = 120; diff --git a/src/data/move.ts b/src/data/move.ts index 40391b31923..74f43eb2727 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -69,8 +69,7 @@ export enum MoveFlags { DANCE_MOVE = 4096, WIND_MOVE = 8192, TRIAGE_MOVE = 16384, - IGNORE_ABILITIES = 32768, - OHKO_Move = 65536 + IGNORE_ABILITIES = 32768 } type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean; @@ -235,11 +234,6 @@ export default class Move implements Localizable { return this; } - OHKOMove(ohko?: boolean): this { - this.setFlag(MoveFlags.OHKO_Move, ohko); - return this; - } - soundBased(soundBased?: boolean): this { this.setFlag(MoveFlags.SOUND_BASED, soundBased); return this; @@ -3715,8 +3709,7 @@ export function initMoves() { new AttackMove(Moves.VISE_GRIP, Type.NORMAL, MoveCategory.PHYSICAL, 55, 100, 30, -1, 0, 1), new AttackMove(Moves.GUILLOTINE, Type.NORMAL, MoveCategory.PHYSICAL, 200, 30, 5, -1, 0, 1) .attr(OneHitKOAttr) - .attr(OneHitKOAccuracyAttr) - .OHKOMove(), + .attr(OneHitKOAccuracyAttr), new AttackMove(Moves.RAZOR_WIND, Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 1) .attr(ChargeAttr, ChargeAnim.RAZOR_WIND_CHARGING, 'whipped\nup a whirlwind!') .attr(HighCritAttr) @@ -3765,8 +3758,7 @@ export function initMoves() { .attr(MultiHitAttr), new AttackMove(Moves.HORN_DRILL, Type.NORMAL, MoveCategory.PHYSICAL, 200, 30, 5, -1, 0, 1) .attr(OneHitKOAttr) - .attr(OneHitKOAccuracyAttr) - .OHKOMove(), + .attr(OneHitKOAccuracyAttr), new AttackMove(Moves.TACKLE, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 35, -1, 0, 1), new AttackMove(Moves.BODY_SLAM, Type.NORMAL, MoveCategory.PHYSICAL, 85, 100, 15, 30, 0, 1) .attr(StatusEffectAttr, StatusEffect.PARALYSIS), @@ -3922,8 +3914,7 @@ export function initMoves() { .attr(OneHitKOAttr) .attr(OneHitKOAccuracyAttr) .attr(HitsTagAttr, BattlerTagType.UNDERGROUND, false) - .makesContact(false) - .OHKOMove(), + .makesContact(false), new AttackMove(Moves.DIG, Type.GROUND, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 1) .attr(ChargeAttr, ChargeAnim.DIG_CHARGING, 'dug a hole!', BattlerTagType.UNDERGROUND) .ignoresVirtual(), @@ -4584,8 +4575,7 @@ export function initMoves() { .makesContact(false), new AttackMove(Moves.SHEER_COLD, Type.ICE, MoveCategory.SPECIAL, 200, 30, 5, -1, 0, 3) .attr(OneHitKOAttr) - .attr(OneHitKOAccuracyAttr) - .OHKOMove(), + .attr(OneHitKOAccuracyAttr), new AttackMove(Moves.MUDDY_WATER, Type.WATER, MoveCategory.SPECIAL, 90, 85, 10, 30, 0, 3) .attr(StatChangeAttr, BattleStat.ACC, -1) .target(MoveTarget.ALL_NEAR_ENEMIES), From e88b4a216a541616596594f5dafd672cee9f87a2 Mon Sep 17 00:00:00 2001 From: Temps Ray Date: Wed, 24 Apr 2024 23:04:51 -0400 Subject: [PATCH 5/6] merge --- src/data/ability.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 9244604084b..32688239342 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -9,7 +9,7 @@ import { BattlerTag } from "./battler-tags"; import { BattlerTagType } from "./enums/battler-tag-type"; import { StatusEffect, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect"; import { Gender } from "./gender"; -import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves, StatusMove } from "./move"; +import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves } from "./move"; import { ArenaTagSide, ArenaTrapTag } from "./arena-tag"; import { ArenaTagType } from "./enums/arena-tag-type"; import { Stat } from "./pokemon-stat"; @@ -2776,7 +2776,8 @@ export function initAbilities() { .bypassFaint(), new Ability(Abilities.ANTICIPATION, 4) .conditionalAttr(getAnticipationCondition(), PostSummonMessageAbAttr, (pokemon: Pokemon) => getPokemonMessage(pokemon, ' shuddered!')), - new Ability(Abilities.FOREWARN, 4), + new Ability(Abilities.FOREWARN, 4) + .unimplemented(), new Ability(Abilities.UNAWARE, 4) .attr(IgnoreOpponentStatChangesAbAttr) .ignorable(), @@ -2802,9 +2803,11 @@ export function initAbilities() { new Ability(Abilities.SNOW_WARNING, 4) .attr(PostSummonWeatherChangeAbAttr, WeatherType.SNOW) .attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.SNOW), - new Ability(Abilities.HONEY_GATHER, "Honey Gather (N)", "The Pokémon may gather Honey after a battle.", 4), - new Ability(Abilities.FRISK, "Frisk (N)", "When it enters a battle, the Pokémon can check an opposing Pokémon's held item.", 4), - new Ability(Abilities.RECKLESS, "Reckless", "Powers up moves that have recoil damage.", 4) + new Ability(Abilities.HONEY_GATHER, 4) + .unimplemented(), + new Ability(Abilities.FRISK, 4) + .attr(FriskAbAttr), + new Ability(Abilities.RECKLESS, 4) .attr(MovePowerBoostAbAttr, (user, target, move) => move.getAttrs(RecoilAttr).length && move.id !== Moves.STRUGGLE, 1.2), new Ability(Abilities.MULTITYPE, 4) .attr(UncopiableAbilityAbAttr) From 1bfd601f4c20cc738850036026ef9be4c0513a1d Mon Sep 17 00:00:00 2001 From: Temps Ray Date: Wed, 24 Apr 2024 23:06:03 -0400 Subject: [PATCH 6/6] More merge conflict grrrrrr --- src/data/ability.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 32688239342..3b9cbc448fc 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -2777,7 +2777,7 @@ export function initAbilities() { new Ability(Abilities.ANTICIPATION, 4) .conditionalAttr(getAnticipationCondition(), PostSummonMessageAbAttr, (pokemon: Pokemon) => getPokemonMessage(pokemon, ' shuddered!')), new Ability(Abilities.FOREWARN, 4) - .unimplemented(), + .attr(ForewarnAbAttr), new Ability(Abilities.UNAWARE, 4) .attr(IgnoreOpponentStatChangesAbAttr) .ignorable(),