From eeb5b37b41c40d10dcb4308088d8e03dac8cd4cb Mon Sep 17 00:00:00 2001 From: Temps Ray Date: Tue, 16 Apr 2024 18:40:36 -0400 Subject: [PATCH] Add wind abilities and charge --- src/data/ability.ts | 40 +++++++++++++++++++++++++----- src/data/battler-tags.ts | 10 ++++++-- src/data/enums/battler-tag-type.ts | 3 ++- src/data/move.ts | 6 ++--- src/field/pokemon.ts | 9 +++++-- 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 7cb03d7e7e3..9ca07286705 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -440,6 +440,25 @@ export class PostDefendStatChangeAbAttr extends PostDefendAbAttr { } } +export class PostDefendApplyBattlerTagAbAttr extends PostDefendAbAttr { + private condition: PokemonDefendCondition; + private tagType: BattlerTagType; + constructor(condition: PokemonDefendCondition, tagType: BattlerTagType) { + super(true); + + this.condition = condition; + this.tagType = tagType; + } + + 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); + return true; + } + return false; + } +} + export class PostDefendTypeChangeAbAttr extends PostDefendAbAttr { applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { if (hitResult < HitResult.NO_EFFECT) { @@ -2518,7 +2537,9 @@ export function initAbilities() { .attr(PostVictoryStatChangeAbAttr, BattleStat.ATK, 1), new Ability(Abilities.JUSTIFIED, "Justified", "Being hit by a Dark-type move boosts the Attack stat of the Pokémon, for justice.", 5) .attr(PostDefendStatChangeAbAttr, (target, user, move) => move.type === Type.DARK && move.category !== MoveCategory.STATUS, BattleStat.ATK, 1), - new Ability(Abilities.RATTLED, "Rattled (N)", "Dark-, Ghost-, and Bug-type moves scare the Pokémon and boost its Speed stat.", 5), + new Ability(Abilities.RATTLED, "Rattled (P)", "Intimidate or being hit by a Dark-, Ghost-, or Bug-type move will scare the Pokémon and boost its Speed stat.", 5) + .attr(PostDefendStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS && (move.type === Type.DARK || move.type === Type.BUG || + move.type === Type.GHOST), BattleStat.SPD, 1), new Ability(Abilities.MAGIC_BOUNCE, "Magic Bounce (N)", "Reflects status moves instead of getting hit by them.", 5) .ignorable(), new Ability(Abilities.SAP_SIPPER, "Sap Sipper", "Boosts the Attack stat if hit by a Grass-type move instead of taking damage.", 5) @@ -2542,7 +2563,8 @@ export function initAbilities() { .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) .attr(UnsuppressableAbilityAbAttr), - new Ability(Abilities.VICTORY_STAR, "Victory Star (N)", "Boosts the accuracy of its allies and itself.", 5), + new Ability(Abilities.VICTORY_STAR, "Victory Star (P)", "Boosts the accuracy of its allies and itself.", 5) + .attr(BattleStatMultiplierAbAttr, BattleStat.ACC, 1.1), new Ability(Abilities.TURBOBLAZE, "Turboblaze", "Moves can be used on the target regardless of its Abilities.", 5) .attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => getPokemonMessage(pokemon, ' is radiating a blazing aura!')) .attr(MoveAbilityBypassAbAttr), @@ -2569,7 +2591,9 @@ export function initAbilities() { .attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.BITING_MOVE), 1.5), new Ability(Abilities.REFRIGERATE, "Refrigerate", "Normal-type moves become Ice-type moves. The power of those moves is boosted a little.", 6) .attr(MoveTypeChangePowerMultiplierAbAttr, Type.NORMAL, Type.ICE, 1.2), - new Ability(Abilities.SWEET_VEIL, "Sweet Veil (N)", "Prevents itself and ally Pokémon from falling asleep.", 6) + new Ability(Abilities.SWEET_VEIL, "Sweet Veil (P)", "Prevents itself and ally Pokémon from falling asleep.", 6) + .attr(StatusEffectImmunityAbAttr, StatusEffect.SLEEP) + .attr(BattlerTagImmunityAbAttr, BattlerTagType.DROWSY) .ignorable(), new Ability(Abilities.STANCE_CHANGE, "Stance Change", "The Pokémon changes its form to Blade Forme when it uses an attack move and changes to Shield Forme when it uses King's Shield.", 6) .attr(UncopiableAbilityAbAttr) @@ -2824,13 +2848,16 @@ export function initAbilities() { new Ability(Abilities.WELL_BAKED_BODY, "Well-Baked Body", "The Pokémon takes no damage when hit by Fire-type moves. Instead, its Defense stat is sharply boosted.", 9) .attr(TypeImmunityStatChangeAbAttr, Type.FIRE, BattleStat.DEF, 2) .ignorable(), - new Ability(Abilities.WIND_RIDER, "Wind Rider (N)", "Boosts the Pokémon's Attack stat if Tailwind takes effect or if the Pokémon is hit by a wind move. The Pokémon also takes no damage from wind moves.", 9) + new Ability(Abilities.WIND_RIDER, "Wind Rider (P)", "Boosts the Pokémon's Attack stat if Tailwind takes effect or if the Pokémon is hit by a wind move. The Pokémon also takes no damage from wind moves.", 9) + .attr(MoveImmunityAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.getMove().hasFlag(MoveFlags.WIND_MOVE)) + .attr(PostDefendStatChangeAbAttr, (target, user, move) => move.hasFlag(MoveFlags.WIND_MOVE), BattleStat.ATK, 1) .ignorable(), new Ability(Abilities.GUARD_DOG, "Guard Dog (N)", "Boosts the Pokémon's Attack stat if intimidated. Moves and items that would force the Pokémon to switch out also fail to work.", 9) .ignorable(), new Ability(Abilities.ROCKY_PAYLOAD, "Rocky Payload", "Powers up Rock-type moves.", 9) .attr(MoveTypePowerBoostAbAttr, Type.ROCK), - new Ability(Abilities.WIND_POWER, "Wind Power (N)", "The Pokémon becomes charged when it is hit by a wind move, boosting the power of the next Electric-type move the Pokémon uses.", 9), + new Ability(Abilities.WIND_POWER, "Wind Power (P)", "The Pokémon becomes charged when it is hit by a wind move, boosting the power of the next Electric-type move the Pokémon uses.", 9) + .attr(PostDefendApplyBattlerTagAbAttr, (target, user, move) => move.hasFlag(MoveFlags.WIND_MOVE), BattlerTagType.CHARGED), new Ability(Abilities.ZERO_TO_HERO, "Zero to Hero (N)", "The Pokémon transforms into its Hero Form when it switches out.", 9) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) @@ -2839,7 +2866,8 @@ export function initAbilities() { new Ability(Abilities.COMMANDER, "Commander (N)", "When the Pokémon enters a battle, it goes inside the mouth of an ally Dondozo if one is on the field. The Pokémon then issues commands from there.", 9) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr), - new Ability(Abilities.ELECTROMORPHOSIS, "Electromorphosis (N)", "The Pokémon becomes charged when it takes damage, boosting the power of the next Electric-type move the Pokémon uses.", 9), + new Ability(Abilities.ELECTROMORPHOSIS, "Electromorphosis", "The Pokémon becomes charged when it takes damage, boosting the power of the next Electric-type move the Pokémon uses.", 9) + .attr(PostDefendApplyBattlerTagAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, BattlerTagType.CHARGED), new Ability(Abilities.PROTOSYNTHESIS, "Protosynthesis", "Boosts the Pokémon's most proficient stat in harsh sunlight or if the Pokémon is holding Booster Energy.", 9) .conditionalAttr(getWeatherCondition(WeatherType.SUNNY, WeatherType.HARSH_SUN), PostSummonAddBattlerTagAbAttr, BattlerTagType.PROTOSYNTHESIS, 0, true) .attr(PostWeatherChangeAddBattlerTagAttr, BattlerTagType.PROTOSYNTHESIS, 0, WeatherType.SUNNY, WeatherType.HARSH_SUN) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index a45522b5e1e..947e85c88de 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -922,11 +922,15 @@ export class HideSpriteTag extends BattlerTag { export class TypeBoostTag extends BattlerTag { public boostedType: Type; + public boostValue: number; + public oneUse: boolean; - constructor(tagType: BattlerTagType, sourceMove: Moves, boostedType: Type) { + constructor(tagType: BattlerTagType, sourceMove: Moves, boostedType: Type, boostValue: number, oneUse: boolean) { super(tagType, BattlerTagLapseType.TURN_END, 1, sourceMove); this.boostedType = boostedType; + this.boostValue = boostValue; + this.oneUse = oneUse; } lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { @@ -1080,7 +1084,7 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc case BattlerTagType.HIDDEN: return new HideSpriteTag(tagType, turnCount, sourceMove); case BattlerTagType.FIRE_BOOST: - return new TypeBoostTag(tagType, sourceMove, Type.FIRE); + return new TypeBoostTag(tagType, sourceMove, Type.FIRE, 1.5, false); case BattlerTagType.CRIT_BOOST: return new CritBoostTag(tagType, sourceMove); case BattlerTagType.ALWAYS_CRIT: @@ -1095,6 +1099,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, turnCount, sourceMove); case BattlerTagType.SALT_CURED: return new SaltCuredTag(sourceId); + case BattlerTagType.CHARGED: + return new TypeBoostTag(tagType, sourceMove, Type.ELECTRIC, 2, true); 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 85f00753457..341fe018a42 100644 --- a/src/data/enums/battler-tag-type.ts +++ b/src/data/enums/battler-tag-type.ts @@ -46,5 +46,6 @@ export enum BattlerTagType { IGNORE_ACCURACY = "IGNORE_ACCURACY", BYPASS_SLEEP = "BYPASS_SLEEP", IGNORE_FLYING = "IGNORE_FLYING", - SALT_CURED = "SALT_CURED" + SALT_CURED = "SALT_CURED", + CHARGED = "CHARGED" } diff --git a/src/data/move.ts b/src/data/move.ts index db0c062e2e8..da780f167cc 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -3877,7 +3877,6 @@ export function initMoves() { .target(MoveTarget.RANDOM_NEAR_ENEMY), new StatusMove(Moves.SANDSTORM, "Sandstorm", Type.ROCK, -1, 10, "A five-turn sandstorm is summoned to hurt all combatants except Rock, Ground, and Steel types. It raises the Sp. Def stat of Rock types.", -1, 0, 2) .attr(WeatherChangeAttr, WeatherType.SANDSTORM) - .windMove() .target(MoveTarget.BOTH_SIDES), new AttackMove(Moves.GIGA_DRAIN, "Giga Drain", Type.GRASS, MoveCategory.SPECIAL, 75, 100, 10, "A nutrient-draining attack. The user's HP is restored by half the damage taken by the target.", -1, 0, 2) .attr(HitHealAttr) @@ -4046,8 +4045,9 @@ export function initMoves() { new StatusMove(Moves.NATURE_POWER, "Nature Power", Type.NORMAL, -1, 20, "This attack makes use of nature's power. Its effects vary depending on the user's environment.", -1, 0, 3) .attr(NaturePowerAttr) .ignoresVirtual(), - new SelfStatusMove(Moves.CHARGE, "Charge (P)", Type.ELECTRIC, -1, 20, "The user boosts the power of the Electric move it uses on the next turn. This also raises the user's Sp. Def stat.", -1, 0, 3) - .attr(StatChangeAttr, BattleStat.SPDEF, 1, true), + new SelfStatusMove(Moves.CHARGE, "Charge", Type.ELECTRIC, -1, 20, "The user boosts the power of the Electric move it uses on the next turn. This also raises the user's Sp. Def stat.", -1, 0, 3) + .attr(StatChangeAttr, BattleStat.SPDEF, 1, true) + .attr(AddBattlerTagAttr, BattlerTagType.CHARGED, true, true), new StatusMove(Moves.TAUNT, "Taunt (N)", Type.DARK, 100, 20, "The target is taunted into a rage that allows it to use only attack moves for three turns.", -1, 0, 3), new StatusMove(Moves.HELPING_HAND, "Helping Hand", Type.NORMAL, -1, 20, "The user assists an ally by boosting the power of that ally's attack.", -1, 5, 3) .attr(AddBattlerTagAttr, BattlerTagType.HELPING_HAND) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 9181be78edf..57fb332363b 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1178,8 +1178,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (cancelled.value) result = HitResult.NO_EFFECT; else { - if (source.findTag(t => t instanceof TypeBoostTag && (t as TypeBoostTag).boostedType === type)) - power.value *= 1.5; + let typeBoost = source.findTag(t => t instanceof TypeBoostTag && (t as TypeBoostTag).boostedType === type) as TypeBoostTag; + if (typeBoost) { + power.value *= typeBoost.boostValue; + if (typeBoost.oneUse) { + this.removeTag(typeBoost.tagType); + } + } const arenaAttackTypeMultiplier = this.scene.arena.getAttackTypeMultiplier(type, source.isGrounded()); if (this.scene.arena.getTerrainType() === TerrainType.GRASSY && this.isGrounded() && type === Type.GROUND && move.moveTarget === MoveTarget.ALL_NEAR_OTHERS) power.value /= 2;