From bce7472e3d38c5a672928da436c23394193dea18 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sat, 7 Jun 2025 23:48:35 +0200 Subject: [PATCH] Added Mystical Rock --- src/field/arena.ts | 7 +- src/items/all-held-items.ts | 3 + src/items/held-item.ts | 1 + src/items/held-items/field-effect.ts | 33 ++++++++ src/modifier/modifier.ts | 119 +-------------------------- 5 files changed, 42 insertions(+), 121 deletions(-) create mode 100644 src/items/held-items/field-effect.ts diff --git a/src/field/arena.ts b/src/field/arena.ts index 2ec98c53afa..07ac8b9cf1a 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -40,7 +40,8 @@ import { AbilityId } from "#enums/ability-id"; import { SpeciesFormChangeRevertWeatherFormTrigger, SpeciesFormChangeWeatherTrigger } from "#app/data/pokemon-forms"; import { CommonAnimPhase } from "#app/phases/common-anim-phase"; import { WeatherType } from "#enums/weather-type"; -import { FieldEffectModifier } from "#app/modifier/modifier"; +import { applyHeldItems } from "#app/items/all-held-items"; +import { ITEM_EFFECT } from "#app/items/held-item"; export class Arena { public biomeType: BiomeId; @@ -339,7 +340,7 @@ export class Arena { if (!isNullOrUndefined(user)) { weatherDuration.value = 5; - globalScene.applyModifier(FieldEffectModifier, user.isPlayer(), user, weatherDuration); + applyHeldItems(ITEM_EFFECT.FIELD_EFFECT, { pokemon: user, fieldDuration: weatherDuration }); } this.weather = weather ? new Weather(weather, weatherDuration.value) : null; @@ -420,7 +421,7 @@ export class Arena { if (!isNullOrUndefined(user)) { terrainDuration.value = 5; - globalScene.applyModifier(FieldEffectModifier, user.isPlayer(), user, terrainDuration); + applyHeldItems(ITEM_EFFECT.FIELD_EFFECT, { pokemon: user, fieldDuration: terrainDuration }); } this.terrain = terrain ? new Terrain(terrain, terrainDuration.value) : null; diff --git a/src/items/all-held-items.ts b/src/items/all-held-items.ts index 9c3f7c91473..0381f616116 100644 --- a/src/items/all-held-items.ts +++ b/src/items/all-held-items.ts @@ -20,6 +20,7 @@ import { type BERRY_PARAMS, BerryHeldItem, berryTypeToHeldItem } from "./held-it import { type BYPASS_SPEED_CHANCE_PARAMS, BypassSpeedChanceHeldItem } from "./held-items/bypass-speed-chance"; import { type CRIT_BOOST_PARAMS, CritBoostHeldItem, SpeciesCritBoostHeldItem } from "./held-items/crit-booster"; import { type EXP_BOOST_PARAMS, ExpBoosterHeldItem } from "./held-items/exp-booster"; +import { type FIELD_EFFECT_PARAMS, FieldEffectHeldItem } from "./held-items/field-effect"; import { type FLINCH_CHANCE_PARAMS, FlinchChanceHeldItem } from "./held-items/flinch-chance"; import { type HIT_HEAL_PARAMS, HitHealHeldItem } from "./held-items/hit-heal"; import { InstantReviveHeldItem, type INSTANT_REVIVE_PARAMS } from "./held-items/instant-revive"; @@ -109,6 +110,7 @@ export function initHeldItems() { allHeldItems[HeldItemId.FOCUS_BAND] = new SurviveChanceHeldItem(HeldItemId.FOCUS_BAND, 5); allHeldItems[HeldItemId.QUICK_CLAW] = new BypassSpeedChanceHeldItem(HeldItemId.QUICK_CLAW, 3); allHeldItems[HeldItemId.KINGS_ROCK] = new FlinchChanceHeldItem(HeldItemId.KINGS_ROCK, 3, 10); + allHeldItems[HeldItemId.MYSTICAL_ROCK] = new FieldEffectHeldItem(HeldItemId.MYSTICAL_ROCK, 2); allHeldItems[HeldItemId.FLAME_ORB] = new TurnEndStatusHeldItem(HeldItemId.FLAME_ORB, 1, StatusEffect.BURN); allHeldItems[HeldItemId.TOXIC_ORB] = new TurnEndStatusHeldItem(HeldItemId.TOXIC_ORB, 1, StatusEffect.TOXIC); @@ -135,6 +137,7 @@ type APPLY_HELD_ITEMS_PARAMS = { [ITEM_EFFECT.SURVIVE_CHANCE]: SURVIVE_CHANCE_PARAMS; [ITEM_EFFECT.BYPASS_SPEED_CHANCE]: BYPASS_SPEED_CHANCE_PARAMS; [ITEM_EFFECT.FLINCH_CHANCE]: FLINCH_CHANCE_PARAMS; + [ITEM_EFFECT.FIELD_EFFECT]: FIELD_EFFECT_PARAMS; }; export function applyHeldItems(effect: T, params: APPLY_HELD_ITEMS_PARAMS[T]) { diff --git a/src/items/held-item.ts b/src/items/held-item.ts index f8fd3fb592a..4acdaa1886e 100644 --- a/src/items/held-item.ts +++ b/src/items/held-item.ts @@ -20,6 +20,7 @@ export const ITEM_EFFECT = { SURVIVE_CHANCE: 12, BYPASS_SPEED_CHANCE: 13, FLINCH_CHANCE: 14, + FIELD_EFFECT: 15, } as const; export type ITEM_EFFECT = (typeof ITEM_EFFECT)[keyof typeof ITEM_EFFECT]; diff --git a/src/items/held-items/field-effect.ts b/src/items/held-items/field-effect.ts new file mode 100644 index 00000000000..babea90f4e7 --- /dev/null +++ b/src/items/held-items/field-effect.ts @@ -0,0 +1,33 @@ +import type Pokemon from "#app/field/pokemon"; +import { HeldItem, ITEM_EFFECT } from "#app/items/held-item"; +import type { NumberHolder } from "#app/utils/common"; + +export interface FIELD_EFFECT_PARAMS { + pokemon: Pokemon; + /** The pokemon with the item */ + fieldDuration: NumberHolder; +} + +/** + * Modifier used for held items, namely Mystical Rock, that extend the + * duration of weather and terrain effects. + * @extends PokemonHeldItemModifier + * @see {@linkcode apply} + */ +export class FieldEffectHeldItem extends HeldItem { + public effects: ITEM_EFFECT[] = [ITEM_EFFECT.FIELD_EFFECT]; + + /** + * Provides two more turns per stack to any weather or terrain effect caused + * by the holder. + * @param pokemon {@linkcode Pokemon} that holds the held item + * @param fieldDuration {@linkcode NumberHolder} that stores the current field effect duration + * @returns `true` if the field effect extension was applied successfully + */ + apply(params: FIELD_EFFECT_PARAMS): boolean { + const pokemon = params.pokemon; + const stackCount = pokemon.heldItemManager.getStack(this.type); + params.fieldDuration.value += 2 * stackCount; + return true; + } +} diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index c3907ef9456..7642e1b6acf 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -21,7 +21,7 @@ import type { MoveId } from "#enums/move-id"; import type { Nature } from "#enums/nature"; import type { PokeballType } from "#enums/pokeball"; import { SpeciesId } from "#enums/species-id"; -import { type PermanentStat, type TempBattleStat, BATTLE_STATS, Stat, TEMP_BATTLE_STATS } from "#enums/stat"; +import { type PermanentStat, type TempBattleStat, Stat, TEMP_BATTLE_STATS } from "#enums/stat"; import { StatusEffect } from "#enums/status-effect"; import type { PokemonType } from "#enums/pokemon-type"; import i18next from "i18next"; @@ -1027,44 +1027,6 @@ export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier { } } -export class HitHealModifier extends PokemonHeldItemModifier { - matchType(modifier: Modifier) { - return modifier instanceof HitHealModifier; - } - - clone() { - return new HitHealModifier(this.type, this.pokemonId, this.stackCount); - } - - /** - * Applies {@linkcode HitHealModifier} - * @param pokemon The {@linkcode Pokemon} that holds the item - * @returns `true` if the {@linkcode Pokemon} was healed - */ - override apply(pokemon: Pokemon): boolean { - if (pokemon.turnData.totalDamageDealt && !pokemon.isFullHp()) { - // TODO: this shouldn't be undefined AFAIK - globalScene.unshiftPhase( - new PokemonHealPhase( - pokemon.getBattlerIndex(), - toDmgValue(pokemon.turnData.totalDamageDealt / 8) * this.stackCount, - i18next.t("modifier:hitHealApply", { - pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - typeName: this.type.name, - }), - true, - ), - ); - } - - return true; - } - - getMaxHeldItemCount(_pokemon: Pokemon): number { - return 4; - } -} - export class LevelIncrementBoosterModifier extends PersistentModifier { match(modifier: Modifier) { return modifier instanceof LevelIncrementBoosterModifier; @@ -1196,85 +1158,6 @@ export class PreserveBerryModifier extends PersistentModifier { } } -/** - * Modifier used for held items, namely White Herb, that restore adverse stat - * stages in battle. - * @extends PokemonHeldItemModifier - * @see {@linkcode apply} - */ -export class ResetNegativeStatStageModifier extends PokemonHeldItemModifier { - matchType(modifier: Modifier) { - return modifier instanceof ResetNegativeStatStageModifier; - } - - clone() { - return new ResetNegativeStatStageModifier(this.type, this.pokemonId, this.stackCount); - } - - /** - * Goes through the holder's stat stages and, if any are negative, resets that - * stat stage back to 0. - * @param pokemon {@linkcode Pokemon} that holds the item - * @returns `true` if any stat stages were reset, false otherwise - */ - override apply(pokemon: Pokemon): boolean { - let statRestored = false; - - for (const s of BATTLE_STATS) { - if (pokemon.getStatStage(s) < 0) { - pokemon.setStatStage(s, 0); - statRestored = true; - } - } - - if (statRestored) { - globalScene.queueMessage( - i18next.t("modifier:resetNegativeStatStageApply", { - pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - typeName: this.type.name, - }), - ); - } - return statRestored; - } - - getMaxHeldItemCount(_pokemon: Pokemon): number { - return 2; - } -} - -/** - * Modifier used for held items, namely Mystical Rock, that extend the - * duration of weather and terrain effects. - * @extends PokemonHeldItemModifier - * @see {@linkcode apply} - */ -export class FieldEffectModifier extends PokemonHeldItemModifier { - /** - * Provides two more turns per stack to any weather or terrain effect caused - * by the holder. - * @param pokemon {@linkcode Pokemon} that holds the held item - * @param fieldDuration {@linkcode NumberHolder} that stores the current field effect duration - * @returns `true` if the field effect extension was applied successfully - */ - override apply(_pokemon: Pokemon, fieldDuration: NumberHolder): boolean { - fieldDuration.value += 2 * this.stackCount; - return true; - } - - override matchType(modifier: Modifier): boolean { - return modifier instanceof FieldEffectModifier; - } - - override clone(): FieldEffectModifier { - return new FieldEffectModifier(this.type, this.pokemonId, this.stackCount); - } - - override getMaxHeldItemCount(_pokemon?: Pokemon): number { - return 2; - } -} - export abstract class ConsumablePokemonModifier extends ConsumableModifier { public pokemonId: number;