Held item overrides now use the new system

This commit is contained in:
Wlowscha 2025-06-17 23:37:53 +02:00
parent 7523f6d9c0
commit c58c1fd21b
No known key found for this signature in database
GPG Key ID: 3C8F1AD330565D04
3 changed files with 19 additions and 162 deletions

View File

@ -25,112 +25,23 @@ import { type TempBattleStat, Stat, TEMP_BATTLE_STATS } from "#enums/stat";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import type { PokemonType } from "#enums/pokemon-type"; import type { PokemonType } from "#enums/pokemon-type";
import i18next from "i18next"; import i18next from "i18next";
import { import type {
type DoubleBattleChanceBoosterModifierType, DoubleBattleChanceBoosterModifierType,
type EvolutionItemModifierType, EvolutionItemModifierType,
type ModifierOverride, ModifierOverride,
type ModifierType, ModifierType,
type TerastallizeModifierType, TerastallizeModifierType,
type TmModifierType, TmModifierType,
modifierTypes,
} from "./modifier-type"; } from "./modifier-type";
import { FRIENDSHIP_GAIN_FROM_RARE_CANDY } from "#app/data/balance/starters"; import { FRIENDSHIP_GAIN_FROM_RARE_CANDY } from "#app/data/balance/starters";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type { ModifierInstanceMap, ModifierString } from "#app/@types/modifier-types"; import type { ModifierInstanceMap, ModifierString } from "#app/@types/modifier-types";
import { assignItemsFromConfiguration } from "#app/items/held-item-pool";
import type { HeldItemConfiguration } from "#app/items/held-item-data-types";
import { modifierTypes } from "#app/data/data-lists";
export type ModifierPredicate = (modifier: Modifier) => boolean; export type ModifierPredicate = (modifier: Modifier) => boolean;
const iconOverflowIndex = 24;
export const modifierSortFunc = (a: Modifier, b: Modifier): number => {
const itemNameMatch = a.type.name.localeCompare(b.type.name);
const typeNameMatch = a.constructor.name.localeCompare(b.constructor.name);
//Then sort by item type
if (typeNameMatch === 0) {
return itemNameMatch;
//Finally sort by item name
}
return typeNameMatch;
};
export class ModifierBar extends Phaser.GameObjects.Container {
private player: boolean;
private modifierCache: PersistentModifier[];
constructor(enemy?: boolean) {
super(globalScene, 1 + (enemy ? 302 : 0), 2);
this.player = !enemy;
this.setScale(0.5);
}
/**
* Method to update content displayed in {@linkcode ModifierBar}
* @param {PersistentModifier[]} modifiers - The list of modifiers to be displayed in the {@linkcode ModifierBar}
* @param {boolean} hideHeldItems - If set to "true", only modifiers not assigned to a Pokémon are displayed
*/
updateModifiers(modifiers: PersistentModifier[], hideHeldItems = false) {
this.removeAll(true);
const visibleIconModifiers = modifiers.filter(m => m.isIconVisible());
const nonPokemonSpecificModifiers = visibleIconModifiers
.filter(m => !(m as PokemonHeldItemModifier).pokemonId)
.sort(modifierSortFunc);
const pokemonSpecificModifiers = visibleIconModifiers
.filter(m => (m as PokemonHeldItemModifier).pokemonId)
.sort(modifierSortFunc);
const sortedVisibleIconModifiers = hideHeldItems
? nonPokemonSpecificModifiers
: nonPokemonSpecificModifiers.concat(pokemonSpecificModifiers);
sortedVisibleIconModifiers.forEach((modifier: PersistentModifier, i: number) => {
const icon = modifier.getIcon();
if (i >= iconOverflowIndex) {
icon.setVisible(false);
}
this.add(icon);
this.setModifierIconPosition(icon, sortedVisibleIconModifiers.length);
icon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 32, 24), Phaser.Geom.Rectangle.Contains);
icon.on("pointerover", () => {
globalScene.ui.showTooltip(modifier.type.name, modifier.type.getDescription());
if (this.modifierCache && this.modifierCache.length > iconOverflowIndex) {
this.updateModifierOverflowVisibility(true);
}
});
icon.on("pointerout", () => {
globalScene.ui.hideTooltip();
if (this.modifierCache && this.modifierCache.length > iconOverflowIndex) {
this.updateModifierOverflowVisibility(false);
}
});
});
for (const icon of this.getAll()) {
this.sendToBack(icon);
}
this.modifierCache = modifiers;
}
updateModifierOverflowVisibility(ignoreLimit: boolean) {
const modifierIcons = this.getAll().reverse();
for (const modifier of modifierIcons.map(m => m as Phaser.GameObjects.Container).slice(iconOverflowIndex)) {
modifier.setVisible(ignoreLimit);
}
}
setModifierIconPosition(icon: Phaser.GameObjects.Container, modifierCount: number) {
const rowIcons: number = 12 + 6 * Math.max(Math.ceil(Math.min(modifierCount, 24) / 12) - 2, 0);
const x = ((this.getIndex(icon) % rowIcons) * 26) / (rowIcons / 12);
const y = Math.floor(this.getIndex(icon) / rowIcons) * 20;
icon.setPosition(this.player ? x : -x, y);
}
}
export abstract class Modifier { export abstract class Modifier {
public type: ModifierType; public type: ModifierType;
@ -1900,7 +1811,7 @@ export function overrideModifiers(isPlayer = true): void {
const modifierFunc = modifierTypes[item.name]; const modifierFunc = modifierTypes[item.name];
let modifierType: ModifierType | null = modifierFunc(); let modifierType: ModifierType | null = modifierFunc();
if (modifierType.is("ModifierTypeGenerator")) { if (modifierType?.is("ModifierTypeGenerator")) {
const pregenArgs = "type" in item && item.type !== null ? [item.type] : undefined; const pregenArgs = "type" in item && item.type !== null ? [item.type] : undefined;
modifierType = modifierType.generateType([], pregenArgs); modifierType = modifierType.generateType([], pregenArgs);
} }
@ -1912,7 +1823,7 @@ export function overrideModifiers(isPlayer = true): void {
if (isPlayer) { if (isPlayer) {
globalScene.addModifier(modifier, true, false, false, true); globalScene.addModifier(modifier, true, false, false, true);
} else { } else {
globalScene.addEnemyModifier(modifier, true, true); globalScene.addEnemyModifier(modifier, true);
} }
} }
} }
@ -1926,7 +1837,7 @@ export function overrideModifiers(isPlayer = true): void {
* @param isPlayer {@linkcode boolean} for whether the {@linkcode pokemon} is the player's (`true`) or an enemy (`false`) * @param isPlayer {@linkcode boolean} for whether the {@linkcode pokemon} is the player's (`true`) or an enemy (`false`)
*/ */
export function overrideHeldItems(pokemon: Pokemon, isPlayer = true): void { export function overrideHeldItems(pokemon: Pokemon, isPlayer = true): void {
const heldItemsOverride: ModifierOverride[] = isPlayer const heldItemsOverride: HeldItemConfiguration = isPlayer
? Overrides.STARTING_HELD_ITEMS_OVERRIDE ? Overrides.STARTING_HELD_ITEMS_OVERRIDE
: Overrides.OPP_HELD_ITEMS_OVERRIDE; : Overrides.OPP_HELD_ITEMS_OVERRIDE;
if (!heldItemsOverride || heldItemsOverride.length === 0 || !globalScene) { if (!heldItemsOverride || heldItemsOverride.length === 0 || !globalScene) {
@ -1934,31 +1845,10 @@ export function overrideHeldItems(pokemon: Pokemon, isPlayer = true): void {
} }
if (!isPlayer) { if (!isPlayer) {
globalScene.clearEnemyHeldItemModifiers(pokemon); pokemon.heldItemManager.clearItems();
} }
for (const item of heldItemsOverride) { assignItemsFromConfiguration(heldItemsOverride, pokemon);
const modifierFunc = modifierTypes[item.name];
let modifierType: ModifierType | null = modifierFunc();
const qty = item.count || 1;
if (modifierType.is("ModifierTypeGenerator")) {
const pregenArgs = "type" in item && item.type !== null ? [item.type] : undefined;
modifierType = modifierType.generateType([], pregenArgs);
}
const heldItemModifier =
modifierType && (modifierType.withIdFromFunc(modifierFunc).newModifier(pokemon) as PokemonHeldItemModifier);
if (heldItemModifier) {
heldItemModifier.pokemonId = pokemon.id;
heldItemModifier.stackCount = qty;
if (isPlayer) {
globalScene.addModifier(heldItemModifier, true, false, false, true);
} else {
globalScene.addEnemyModifier(heldItemModifier, true, true);
}
}
}
} }
/** /**
@ -1981,30 +1871,8 @@ const ModifierClassMap = Object.freeze({
MegaEvolutionAccessModifier, MegaEvolutionAccessModifier,
GigantamaxAccessModifier, GigantamaxAccessModifier,
TerastallizeAccessModifier, TerastallizeAccessModifier,
PokemonHeldItemModifier,
LapsingPokemonHeldItemModifier,
BaseStatModifier,
EvoTrackerModifier,
PokemonBaseStatTotalModifier,
PokemonBaseStatFlatModifier,
PokemonIncrementingStatModifier,
StatBoosterModifier,
SpeciesStatBoosterModifier,
CritBoosterModifier,
SpeciesCritBoosterModifier,
AttackTypeBoosterModifier,
SurviveDamageModifier,
BypassSpeedChanceModifier,
FlinchChanceModifier,
TurnHealModifier,
TurnStatusEffectModifier,
HitHealModifier,
LevelIncrementBoosterModifier, LevelIncrementBoosterModifier,
BerryModifier,
PreserveBerryModifier, PreserveBerryModifier,
PokemonInstantReviveModifier,
ResetNegativeStatStageModifier,
FieldEffectModifier,
ConsumablePokemonModifier, ConsumablePokemonModifier,
TerrastalizeModifier, TerrastalizeModifier,
PokemonHpRestoreModifier, PokemonHpRestoreModifier,
@ -2022,16 +1890,8 @@ const ModifierClassMap = Object.freeze({
MultipleParticipantExpBonusModifier, MultipleParticipantExpBonusModifier,
HealingBoosterModifier, HealingBoosterModifier,
ExpBoosterModifier, ExpBoosterModifier,
PokemonExpBoosterModifier,
ExpShareModifier, ExpShareModifier,
ExpBalanceModifier, ExpBalanceModifier,
PokemonFriendshipBoosterModifier,
PokemonNatureWeightModifier,
PokemonMoveAccuracyBoosterModifier,
PokemonMultiHitModifier,
PokemonFormChangeItemModifier,
MoneyRewardModifier,
DamageMoneyRewardModifier,
MoneyInterestModifier, MoneyInterestModifier,
HiddenAbilityRateBoosterModifier, HiddenAbilityRateBoosterModifier,
ShinyRateBoosterModifier, ShinyRateBoosterModifier,
@ -2039,10 +1899,6 @@ const ModifierClassMap = Object.freeze({
LockModifierTiersModifier, LockModifierTiersModifier,
HealShopCostModifier, HealShopCostModifier,
BoostBugSpawnModifier, BoostBugSpawnModifier,
SwitchEffectTransferModifier,
HeldItemTransferModifier,
TurnHeldItemTransferModifier,
ContactHeldItemTransferChanceModifier,
IvScannerModifier, IvScannerModifier,
ExtraModifierModifier, ExtraModifierModifier,
TempExtraModifierModifier, TempExtraModifierModifier,

View File

@ -22,6 +22,7 @@ import { TimeOfDay } from "#enums/time-of-day";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
import { VariantTier } from "#enums/variant-tier"; import { VariantTier } from "#enums/variant-tier";
import { WeatherType } from "#enums/weather-type"; import { WeatherType } from "#enums/weather-type";
import { HeldItemConfiguration } from "./items/held-item-data-types";
/** /**
* This comment block exists to prevent IDEs from automatically removing unused imports * This comment block exists to prevent IDEs from automatically removing unused imports
@ -255,9 +256,9 @@ class DefaultOverrides {
readonly OPP_MODIFIER_OVERRIDE: ModifierOverride[] = []; readonly OPP_MODIFIER_OVERRIDE: ModifierOverride[] = [];
/** Override array of {@linkcode ModifierOverride}s used to provide held items to first party member when starting a new game. */ /** Override array of {@linkcode ModifierOverride}s used to provide held items to first party member when starting a new game. */
readonly STARTING_HELD_ITEMS_OVERRIDE: ModifierOverride[] = []; readonly STARTING_HELD_ITEMS_OVERRIDE: HeldItemConfiguration = [];
/** Override array of {@linkcode ModifierOverride}s used to provide held items to enemies on spawn. */ /** Override array of {@linkcode ModifierOverride}s used to provide held items to enemies on spawn. */
readonly OPP_HELD_ITEMS_OVERRIDE: ModifierOverride[] = []; readonly OPP_HELD_ITEMS_OVERRIDE: HeldItemConfiguration = [];
/** /**
* Override array of {@linkcode ModifierOverride}s used to replace the generated item rolls after a wave. * Override array of {@linkcode ModifierOverride}s used to replace the generated item rolls after a wave.

View File

@ -253,7 +253,7 @@ export class TitlePhase extends Phase {
for (const m of modifiers) { for (const m of modifiers) {
globalScene.addModifier(m, true, false, false, true); globalScene.addModifier(m, true, false, false, true);
} }
globalScene.updateModifiers(true, true); globalScene.updateModifiers(true);
Promise.all(loadPokemonAssets).then(() => { Promise.all(loadPokemonAssets).then(() => {
globalScene.time.delayedCall(500, () => globalScene.playBgm()); globalScene.time.delayedCall(500, () => globalScene.playBgm());