From 69b99887d9943e3495ef1faf452500353532cfe4 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Mon, 9 Jun 2025 10:12:17 +0200 Subject: [PATCH] Shuckle Juice and Old Gateau --- src/field/pokemon-held-item-manager.ts | 3 + src/items/held-items/base-stat-booster.ts | 7 ++ src/items/held-items/base-stat-flat.ts | 64 ++++++++++++++++++ src/items/held-items/base-stat-total.ts | 81 +++++++++++++++++++++++ src/items/held-items/incrementing-stat.ts | 61 +++++++++++++++++ 5 files changed, 216 insertions(+) create mode 100644 src/items/held-items/base-stat-flat.ts create mode 100644 src/items/held-items/base-stat-total.ts create mode 100644 src/items/held-items/incrementing-stat.ts diff --git a/src/field/pokemon-held-item-manager.ts b/src/field/pokemon-held-item-manager.ts index 24c8b1d67c5..538eabef873 100644 --- a/src/field/pokemon-held-item-manager.ts +++ b/src/field/pokemon-held-item-manager.ts @@ -1,11 +1,14 @@ import { allHeldItems } from "#app/items/all-held-items"; import type { HeldItemId } from "#app/enums/held-item-id"; import type { FormChangeItem } from "#app/data/pokemon-forms"; +import type { BASE_STAT_TOTAL_DATA } from "#app/items/held-items/base-stat-total"; +import type { BASE_STAT_FLAT_DATA } from "#app/items/held-items/base-stat-flat"; interface HeldItemProperties { stack: number; disabled: boolean; cooldown?: number; + data?: BASE_STAT_TOTAL_DATA | BASE_STAT_FLAT_DATA; } type HeldItemPropertyMap = { diff --git a/src/items/held-items/base-stat-booster.ts b/src/items/held-items/base-stat-booster.ts index f71a1b6ef5b..e024e74fd48 100644 --- a/src/items/held-items/base-stat-booster.ts +++ b/src/items/held-items/base-stat-booster.ts @@ -3,6 +3,7 @@ import { HeldItemId } from "#enums/held-item-id"; import { getStatKey, type PermanentStat, Stat } from "#enums/stat"; import i18next from "i18next"; import { HeldItem, ITEM_EFFECT } from "../held-item"; +import type { STAT_BOOST_PARAMS } from "./stat-booster"; export interface BASE_STAT_BOOSTER_PARAMS { /** The pokemon with the item */ @@ -78,4 +79,10 @@ export class BaseStatBoosterHeldItem extends HeldItem { baseStats[this.stat] = Math.floor(baseStats[this.stat] * (1 + stackCount * 0.1)); return true; } + + getMaxStackCount(params: STAT_BOOST_PARAMS): number { + const pokemon = params.pokemon; + const stackCount = pokemon.heldItemManager.getStack(this.type); + return stackCount; + } } diff --git a/src/items/held-items/base-stat-flat.ts b/src/items/held-items/base-stat-flat.ts new file mode 100644 index 00000000000..f48e597cfdf --- /dev/null +++ b/src/items/held-items/base-stat-flat.ts @@ -0,0 +1,64 @@ +import type Pokemon from "#app/field/pokemon"; +import type { HeldItemId } from "#enums/held-item-id"; +import { HeldItem, ITEM_EFFECT } from "../held-item"; +import type { Stat } from "#enums/stat"; + +export interface BASE_STAT_FLAT_PARAMS { + /** The pokemon with the item */ + pokemon: Pokemon; + /** The amount of exp to gain */ + baseStats: number[]; +} + +export interface BASE_STAT_FLAT_DATA { + statModifier: number; +} + +/** + * Currently used by Old Gateau item + */ +export class BaseStatFlatHeldItem extends HeldItem { + public effects: ITEM_EFFECT[] = [ITEM_EFFECT.BASE_STAT_FLAT]; + private stats: Stat[]; + public isTransferable = false; + + constructor(type: HeldItemId, maxStackCount = 1, stats: Stat[]) { + super(type, maxStackCount); + this.stats = stats; + } + + /** + * Checks if the {@linkcode PokemonBaseStatFlatModifier} should be applied to the {@linkcode Pokemon}. + * @param pokemon The {@linkcode Pokemon} that holds the item + * @param baseStats The base stats of the {@linkcode Pokemon} + * @returns `true` if the {@linkcode PokemonBaseStatFlatModifier} should be applied + */ + // override shouldApply(pokemon?: Pokemon, baseStats?: number[]): boolean { + // return super.shouldApply(pokemon, baseStats) && Array.isArray(baseStats); + // } + + /** + * Applies the {@linkcode PokemonBaseStatFlatModifier} + * @param _pokemon The {@linkcode Pokemon} that holds the item + * @param baseStats The base stats of the {@linkcode Pokemon} + * @returns always `true` + */ + apply(params: BASE_STAT_FLAT_PARAMS): boolean { + const pokemon = params.pokemon; + const itemData = pokemon.heldItemManager.heldItems[this.type].data; + if (!itemData) { + return false; + } + const statModifier = itemData.statModifier; + const baseStats = params.baseStats; + // Modifies the passed in baseStats[] array by a flat value, only if the stat is specified in this.stats + baseStats.forEach((v, i) => { + if (this.stats.includes(i)) { + const newVal = Math.floor(v + statModifier); + baseStats[i] = Math.min(Math.max(newVal, 1), 999999); + } + }); + + return true; + } +} diff --git a/src/items/held-items/base-stat-total.ts b/src/items/held-items/base-stat-total.ts new file mode 100644 index 00000000000..3b85a002e65 --- /dev/null +++ b/src/items/held-items/base-stat-total.ts @@ -0,0 +1,81 @@ +import type Pokemon from "#app/field/pokemon"; +import i18next from "i18next"; +import { HeldItem, ITEM_EFFECT } from "../held-item"; + +export interface BASE_STAT_TOTAL_PARAMS { + /** The pokemon with the item */ + pokemon: Pokemon; + /** The amount of exp to gain */ + baseStats: number[]; +} + +export interface BASE_STAT_TOTAL_DATA { + statModifier: number; +} + +/** + * Currently used by Shuckle Juice item + */ +export class BaseStatTotalHeldItem extends HeldItem { + public effects: ITEM_EFFECT[] = [ITEM_EFFECT.BASE_STAT_TOTAL]; + public isTransferable = false; + + get name(): string { + return i18next.t("modifierType:ModifierType.MYSTERY_ENCOUNTER_SHUCKLE_JUICE") + " (new)"; + } + + // TODO: where is this description shown? + get description(): string { + return i18next.t("modifierType:ModifierType.PokemonBaseStatTotalModifierType.description", { + increaseDecrease: i18next.t( + this.statModifier >= 0 + ? "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.increase" + : "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.decrease", + ), + blessCurse: i18next.t( + this.statModifier >= 0 + ? "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.blessed" + : "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.cursed", + ), + statValue: this.statModifier, + }); + } + + get icon(): string { + return "berry_juice"; + } + + /** + * Checks if {@linkcode PokemonBaseStatTotalModifier} should be applied to the specified {@linkcode Pokemon}. + * @param pokemon the {@linkcode Pokemon} to be modified + * @param baseStats the base stats of the {@linkcode Pokemon} + * @returns `true` if the {@linkcode Pokemon} should be modified + */ + // override shouldApply(pokemon?: Pokemon, baseStats?: number[]): boolean { + // return super.shouldApply(pokemon, baseStats) && Array.isArray(baseStats); + // } + + /** + * Applies the {@linkcode PokemonBaseStatTotalModifier} + * @param _pokemon the {@linkcode Pokemon} to be modified + * @param baseStats the base stats of the {@linkcode Pokemon} + * @returns always `true` + */ + apply(params: BASE_STAT_TOTAL_PARAMS): boolean { + const pokemon = params.pokemon; + const itemData = pokemon.heldItemManager.heldItems[this.type].data; + if (!itemData) { + return false; + } + const statModifier = itemData.statModifier; + const baseStats = params.baseStats; + // Modifies the passed in baseStats[] array + baseStats.forEach((v, i) => { + // HP is affected by half as much as other stats + const newVal = i === 0 ? Math.floor(v + statModifier / 2) : Math.floor(v + statModifier); + baseStats[i] = Math.min(Math.max(newVal, 1), 999999); + }); + + return true; + } +} diff --git a/src/items/held-items/incrementing-stat.ts b/src/items/held-items/incrementing-stat.ts new file mode 100644 index 00000000000..fa66ba7d5a1 --- /dev/null +++ b/src/items/held-items/incrementing-stat.ts @@ -0,0 +1,61 @@ +import type Pokemon from "#app/field/pokemon"; +import { HeldItem, ITEM_EFFECT } from "../held-item"; +import { Stat } from "#enums/stat"; +import type { NumberHolder } from "#app/utils/common"; + +export interface INCREMENTING_STAT_PARAMS { + /** The pokemon with the item */ + pokemon: Pokemon; + stat: Stat; + statHolder: NumberHolder; +} + +/** + * Currently used by Macho Brace item + */ +export class IncrementingStatHeldItem extends HeldItem { + public effects: ITEM_EFFECT[] = [ITEM_EFFECT.INCREMENTING_STAT]; + public isTransferable = false; + + /** + * Checks if the {@linkcode PokemonIncrementingStatModifier} should be applied to the {@linkcode Pokemon}. + * @param pokemon The {@linkcode Pokemon} that holds the item + * @param stat The affected {@linkcode Stat} + * @param statHolder The {@linkcode NumberHolder} that holds the stat + * @returns `true` if the {@linkcode PokemonBaseStatFlatModifier} should be applied + */ + // override shouldApply(pokemon?: Pokemon, stat?: Stat, statHolder?: NumberHolder): boolean { + // return super.shouldApply(pokemon, stat, statHolder) && !!statHolder; + // } + + /** + * Applies the {@linkcode PokemonIncrementingStatModifier} + * @param _pokemon The {@linkcode Pokemon} that holds the item + * @param stat The affected {@linkcode Stat} + * @param statHolder The {@linkcode NumberHolder} that holds the stat + * @returns always `true` + */ + apply(params: INCREMENTING_STAT_PARAMS): boolean { + const pokemon = params.pokemon; + const stackCount = pokemon.heldItemManager.getStack(this.type); + const statHolder = params.statHolder; + + // Modifies the passed in stat number holder by +2 per stack for HP, +1 per stack for other stats + // If the Macho Brace is at max stacks (50), adds additional 10% to total HP and 5% to other stats + const isHp = params.stat === Stat.HP; + + if (isHp) { + statHolder.value += 2 * stackCount; + if (stackCount === this.maxStackCount) { + statHolder.value = Math.floor(statHolder.value * 1.1); + } + } else { + statHolder.value += stackCount; + if (stackCount === this.maxStackCount) { + statHolder.value = Math.floor(statHolder.value * 1.05); + } + } + + return true; + } +}