Replace remaining Modifiers with Rewards (#6091)

* Changing remaining Modifiers to Consumables, and renaming ModifierType to Reward

* Renamed modifier files and moved them into items folder

* Using rewards in most places

* Removed consumables in favor of using rewards directly

* Renamed RewardTier to RarityTier

* Reward ids, function to match rewards

* Getting reward tiers from player pool still

* Messing around with parameters of Reward.apply()

* Always requiring player pokemon in rewards

* Fixing some functions in select-reward-phase and battle-scene

* Fixed various post-merge issues

* Fixed most localization strings (accidentally broken by replacing modifierType with reward)

* Fixed tests for select reward phase

* Using Pokemon.hasSpecies()

* Zero weight for trainer items rewards which are already max stack

* Cleaning up SelectRewardPhase, held item rewards behave the same as any PokemonReward

* Cleaned up some functions

* Introduced RewardCategoryId, distributed RewardIds

* Utility `is` functions for rewards

* Minor fixes

* Moved `HeldItemEffect` to its own file

* rmade some todo comments

* Adding a big comment

* Added tsdocs and removed `RewardClass`

* undid breaking changes

* added TODO

* Moved matchingRewards function to reward-utils.ts

* Added RewardGenerator classes for mints and tera shards

* Introducing default rarity tiers for trainer items and rewards

* RewardFunc now can return RewardGenerator

* Moved pool reward functions to their own file, plus other utility files

* Fixed WeightedModifier to work with the new RewardFunc

* Fixed wrong type import

* Shifting trainer item and reward ids to avoid overlaps

* Added some types

* Updated comment in reward.ts

* Added strong typing ot item maps

* added type safety to held item name map

---------

Co-authored-by: Bertie690 <taylormw163@gmail.com>
Co-authored-by: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com>
This commit is contained in:
Wlowscha 2025-07-28 02:09:21 +02:00 committed by GitHub
parent d3f2659cdf
commit 466c4aede2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
175 changed files with 4842 additions and 5112 deletions

View File

@ -183,7 +183,7 @@ input:-internal-autofill-selected {
/* Show #apadStats only in battle and shop */
#touchControls:not([data-ui-mode="COMMAND"]):not([data-ui-mode="FIGHT"]):not(
[data-ui-mode="BALL"]
):not([data-ui-mode="TARGET_SELECT"]):not([data-ui-mode="MODIFIER_SELECT"])
):not([data-ui-mode="TARGET_SELECT"]):not([data-ui-mode="REWARD_SELECT"])
#apadStats {
display: none;
}

View File

@ -24,15 +24,15 @@ export interface AbilityTranslationEntries {
[key: string]: AbilityTranslationEntry;
}
export interface ModifierTypeTranslationEntry {
export interface RewardTranslationEntry {
name?: string;
description?: string;
extra?: SimpleTranslationEntries;
}
export interface ModifierTypeTranslationEntries {
ModifierType: { [key: string]: ModifierTypeTranslationEntry };
SpeciesBoosterItem: { [key: string]: ModifierTypeTranslationEntry };
export interface RewardTranslationEntries {
Reward: { [key: string]: RewardTranslationEntry };
SpeciesBoosterItem: { [key: string]: RewardTranslationEntry };
AttackTypeBoosterItem: SimpleTranslationEntries;
TempStatStageBoosterItem: SimpleTranslationEntries;
BaseStatBoosterItem: SimpleTranslationEntries;

View File

@ -1,31 +0,0 @@
// Intentionally re-exports `ModifierConstructorMap` from `modifier.ts`
import type { Pokemon } from "#field/pokemon";
import type { ModifierConstructorMap } from "#modifiers/modifier";
import type { ModifierType, WeightedModifierType } from "#modifiers/modifier-type";
export type ModifierTypeFunc = () => ModifierType;
export type WeightedModifierTypeWeightFunc = (party: Pokemon[], rerollCount?: number) => number;
export type { ModifierConstructorMap } from "#modifiers/modifier";
/**
* Map of modifier names to their respective instance types
*/
export type ModifierInstanceMap = {
[K in keyof ModifierConstructorMap]: InstanceType<ModifierConstructorMap[K]>;
};
/**
* Union type of all modifier constructors.
*/
export type ModifierClass = ModifierConstructorMap[keyof ModifierConstructorMap];
/**
* Union type of all modifier names as strings.
*/
export type ModifierString = keyof ModifierConstructorMap;
export type ModifierPool = {
[tier: string]: WeightedModifierType[];
};

23
src/@types/rewards.ts Normal file
View File

@ -0,0 +1,23 @@
import type { HeldItemId } from "#enums/held-item-id";
import type { RewardId } from "#enums/reward-id";
import type { TrainerItemId } from "#enums/trainer-item-id";
import type { Pokemon } from "#field/pokemon";
import type { Reward, RewardGenerator } from "#items/reward";
export type RewardFunc = () => Reward | RewardGenerator;
export type WeightedRewardWeightFunc = (party: Pokemon[], rerollCount?: number) => number;
export type RewardPoolId = RewardId | HeldItemId | TrainerItemId;
export type RewardPoolEntry = {
id: RewardPoolId;
weight: number | WeightedRewardWeightFunc;
};
export type RewardPool = {
[tier: string]: RewardPoolEntry[];
};
export interface RewardPoolWeights {
[tier: string]: number[];
}

View File

@ -53,8 +53,8 @@ import { ExpGainsSpeed } from "#enums/exp-gains-speed";
import { ExpNotification } from "#enums/exp-notification";
import { FormChangeItem } from "#enums/form-change-item";
import { GameModes } from "#enums/game-modes";
import { HeldItemEffect } from "#enums/held-item-effect";
import { HeldItemId } from "#enums/held-item-id";
import { HeldItemPoolType, ModifierPoolType } from "#enums/modifier-pool-type";
import { MoneyFormat } from "#enums/money-format";
import { MoveId } from "#enums/move-id";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
@ -65,6 +65,7 @@ import { PlayerGender } from "#enums/player-gender";
import { PokeballType } from "#enums/pokeball";
import type { PokemonAnimType } from "#enums/pokemon-anim-type";
import { PokemonType } from "#enums/pokemon-type";
import { HeldItemPoolType, RewardPoolType } from "#enums/reward-pool-type";
import { ShopCursorTarget } from "#enums/shop-cursor-target";
import { SpeciesId } from "#enums/species-id";
import { StatusEffect } from "#enums/status-effect";
@ -82,9 +83,10 @@ import { PokemonSpriteSparkleHandler } from "#field/pokemon-sprite-sparkle-handl
import { Trainer } from "#field/trainer";
import { applyHeldItems } from "#items/all-held-items";
import { type ApplyTrainerItemsParams, applyTrainerItems } from "#items/apply-trainer-items";
import { HeldItemEffect } from "#items/held-item";
import type { HeldItemConfiguration } from "#items/held-item-data-types";
import { assignEnemyHeldItemsForWave, assignItemsFromConfiguration } from "#items/held-item-pool";
import type { Reward } from "#items/reward";
import { getRewardPoolForType } from "#items/reward-pool-utils";
import { type EnemyAttackStatusEffectChanceTrainerItem, TrainerItemEffect } from "#items/trainer-item";
import {
isTrainerItemPool,
@ -94,15 +96,6 @@ import {
} from "#items/trainer-item-data-types";
import { TrainerItemManager } from "#items/trainer-item-manager";
import { getNewTrainerItemFromPool } from "#items/trainer-item-pool";
import type { Modifier } from "#modifiers/modifier";
import {
ConsumableModifier,
ConsumablePokemonModifier,
FusePokemonModifier,
PokemonHpRestoreModifier,
RememberMoveModifier,
} from "#modifiers/modifier";
import { getLuckString, getLuckTextTint, getPartyLuckValue } from "#modifiers/modifier-type";
import { MysteryEncounter } from "#mystery-encounters/mystery-encounter";
import { MysteryEncounterSaveData } from "#mystery-encounters/mystery-encounter-save-data";
import { allMysteryEncounters, mysteryEncountersByBiome } from "#mystery-encounters/mystery-encounters";
@ -112,7 +105,7 @@ import { hasExpSprite } from "#sprites/sprite-utils";
import type { Variant } from "#sprites/variant";
import { clearVariantData, variantData } from "#sprites/variant";
import type { Achv } from "#system/achv";
import { achvs, HeldItemAchv, ModifierAchv, MoneyAchv } from "#system/achv";
import { achvs, HeldItemAchv, MoneyAchv } from "#system/achv";
import { GameData } from "#system/game-data";
import { initGameSpeed } from "#system/game-speed";
import type { PokemonData } from "#system/pokemon-data";
@ -148,7 +141,7 @@ import {
} from "#utils/common";
import { deepMergeSpriteData } from "#utils/data";
import { getEnumValues } from "#utils/enums";
import { getModifierPoolForType } from "#utils/modifier-utils";
import { getLuckString, getLuckTextTint, getPartyLuckValue } from "#utils/party";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import i18next from "i18next";
import Phaser from "phaser";
@ -267,7 +260,7 @@ export class BattleScene extends SceneBase {
public arena: Arena;
public gameMode: GameMode;
public score: number;
public lockModifierTiers: boolean;
public lockRarityTiers: boolean;
public trainer: Phaser.GameObjects.Sprite;
public lastEnemyTrainer: Trainer | null;
public currentBattle: Battle;
@ -480,12 +473,12 @@ export class BattleScene extends SceneBase {
this.enemyTrainerItems = new TrainerItemManager();
this.itemBar = new ItemBar();
this.itemBar.setName("modifier-bar");
this.itemBar.setName("item-bar");
this.add.existing(this.itemBar);
uiContainer.add(this.itemBar);
this.enemyItemBar = new ItemBar(true);
this.enemyItemBar.setName("enemy-modifier-bar");
this.enemyItemBar.setName("enemy-item-bar");
this.add.existing(this.enemyItemBar);
uiContainer.add(this.enemyItemBar);
@ -854,9 +847,9 @@ export class BattleScene extends SceneBase {
}
/**
* Returns the ModifierBar of this scene, which is declared private and therefore not accessible elsewhere
* Returns the ItemBar of this scene, which is declared private and therefore not accessible elsewhere
* @param isEnemy - Whether to return the enemy modifier bar instead of the player bar; default `false`
* @returns The {@linkcode ModifierBar} for the given side of the field
* @returns The {@linkcode ItemBar} for the given side of the field
*/
getItemBar(isEnemy = false): ItemBar {
return isEnemy ? this.enemyItemBar : this.itemBar;
@ -1167,7 +1160,7 @@ export class BattleScene extends SceneBase {
this.score = 0;
this.money = 0;
this.lockModifierTiers = false;
this.lockRarityTiers = false;
this.pokeballCounts = Object.fromEntries(
getEnumValues(PokeballType)
@ -1243,12 +1236,12 @@ export class BattleScene extends SceneBase {
...allSpecies,
...allMoves,
...allAbilities,
...getEnumValues(ModifierPoolType)
.map(mpt => getModifierPoolForType(mpt))
...getEnumValues(RewardPoolType)
.map(mpt => getRewardPoolForType(mpt))
.flatMap(mp =>
Object.values(mp)
.flat()
.map(mt => mt.modifierType)
.map(mt => mt.reward)
.filter(mt => "localize" in mt)
.map(lpb => lpb as unknown as Localizable),
),
@ -1987,11 +1980,11 @@ export class BattleScene extends SceneBase {
});
}
showEnemyModifierBar(): void {
showEnemyItemBar(): void {
this.enemyItemBar.setVisible(true);
}
hideEnemyModifierBar(): void {
hideEnemyItemBar(): void {
this.enemyItemBar.setVisible(false);
}
@ -2085,11 +2078,11 @@ export class BattleScene extends SceneBase {
}
updateUIPositions(): void {
const enemyModifierCount = this.enemyItemBar.totalVisibleLength;
const enemyItemCount = this.enemyItemBar.totalVisibleLength;
const biomeWaveTextHeight = this.biomeWaveText.getBottomLeft().y - this.biomeWaveText.getTopLeft().y;
this.biomeWaveText.setY(
-(this.game.canvas.height / 6) +
(enemyModifierCount ? (enemyModifierCount <= 12 ? 15 : 24) : 0) +
(enemyItemCount ? (enemyItemCount <= 12 ? 15 : 24) : 0) +
biomeWaveTextHeight / 2,
);
this.moneyText.setY(this.biomeWaveText.y + 10);
@ -2641,56 +2634,19 @@ export class BattleScene extends SceneBase {
applyTrainerItems(effect, this.trainerItems, params);
}
addModifier(modifier: Modifier | null, playSound?: boolean, instant?: boolean, cost?: number): boolean {
// We check against modifier.type to stop a bug related to loading in a pokemon that has a form change item, which prior to some patch
// that changed form change modifiers worked, had previously set the `type` field to null.
// TODO: This is not the right place to check for this; it should ideally go in a session migrator.
if (!modifier || !modifier.type) {
applyReward<T extends Reward>(reward: T, params: Parameters<T["apply"]>[0], playSound?: boolean): boolean {
const soundName = reward.soundName;
if (playSound && !this.sound.get(soundName)) {
this.playSound(soundName);
}
if (!reward.shouldApply(params)) {
return false;
}
let success = false;
const soundName = modifier.type.soundName;
this.validateAchvs(ModifierAchv, modifier);
if (modifier instanceof ConsumableModifier) {
if (playSound && !this.sound.get(soundName)) {
this.playSound(soundName);
}
if (modifier instanceof ConsumablePokemonModifier) {
for (const p in this.party) {
const pokemon = this.party[p];
const args: unknown[] = [];
if (modifier instanceof PokemonHpRestoreModifier) {
if (!(modifier as PokemonHpRestoreModifier).fainted) {
const hpRestoreMultiplier = new NumberHolder(1);
this.applyPlayerItems(TrainerItemEffect.HEALING_BOOSTER, { numberHolder: hpRestoreMultiplier });
args.push(hpRestoreMultiplier.value);
} else {
args.push(1);
}
} else if (modifier instanceof FusePokemonModifier) {
args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon);
} else if (modifier instanceof RememberMoveModifier && !isNullOrUndefined(cost)) {
args.push(cost);
}
if (modifier.shouldApply(pokemon, ...args)) {
const result = modifier.apply(pokemon, ...args);
success ||= result;
}
}
this.party.map(p => p.updateInfo(instant));
} else {
const args = [this];
if (modifier.shouldApply(...args)) {
const result = modifier.apply(...args);
success ||= result;
}
}
}
return success;
reward.apply(params);
return true;
}
addHeldItem(heldItemId: HeldItemId, pokemon: Pokemon, amount = 1, playSound?: boolean, ignoreUpdate?: boolean) {
@ -2864,7 +2820,7 @@ export class BattleScene extends SceneBase {
}
let count = 0;
for (let c = 0; c < chances; c++) {
if (!randSeedInt(this.gameMode.getEnemyModifierChance(isBoss))) {
if (!randSeedInt(this.gameMode.getEnemyItemChance(isBoss))) {
count++;
}
}
@ -2887,7 +2843,7 @@ export class BattleScene extends SceneBase {
}
/**
* Removes all modifiers from enemy pokemon of {@linkcode PersistentModifier} type
* Removes all items from enemy pokemon and trainers
*/
clearEnemyItems(): void {
this.enemyTrainerItems.clearItems();
@ -2911,7 +2867,7 @@ export class BattleScene extends SceneBase {
this.updateUIPositions();
}
setModifiersVisible(visible: boolean) {
setItemsVisible(visible: boolean) {
[this.itemBar, this.enemyItemBar].map(m => m.setVisible(visible));
}

View File

@ -10,15 +10,14 @@ import type { MoveId } from "#enums/move-id";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
import type { PokeballType } from "#enums/pokeball";
import { RewardTier } from "#enums/reward-tier";
import { SpeciesFormKey } from "#enums/species-form-key";
import { SpeciesId } from "#enums/species-id";
import { TrainerType } from "#enums/trainer-type";
import { TrainerVariant } from "#enums/trainer-variant";
import type { EnemyPokemon, PlayerPokemon, Pokemon } from "#field/pokemon";
import { Trainer } from "#field/trainer";
import type { CustomRewardSettings } from "#items/reward-pool-utils";
import { TrainerItemEffect } from "#items/trainer-item";
import type { CustomModifierSettings } from "#modifiers/modifier-type";
import type { MysteryEncounter } from "#mystery-encounters/mystery-encounter";
import i18next from "#plugins/i18n";
import { MusicPreference } from "#system/settings";
@ -481,7 +480,7 @@ export class FixedBattleConfig {
public getTrainer: GetTrainerFunc;
public getEnemyParty: GetEnemyPartyFunc;
public seedOffsetWaveIndex: number;
public customModifierRewardSettings?: CustomModifierSettings;
public customRewardSettings?: CustomRewardSettings;
setBattleType(battleType: BattleType): FixedBattleConfig {
this.battleType = battleType;
@ -508,8 +507,8 @@ export class FixedBattleConfig {
return this;
}
setCustomModifierRewards(customModifierRewardSettings: CustomModifierSettings) {
this.customModifierRewardSettings = customModifierRewardSettings;
setCustomRewards(customRewardSettings: CustomRewardSettings) {
this.customRewardSettings = customRewardSettings;
return this;
}
}

View File

@ -1,4 +1,4 @@
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id";
@ -68591,324 +68591,324 @@ function transposeTmSpecies(): SpeciesTmMoves {
export const speciesTmMoves: SpeciesTmMoves = transposeTmSpecies();
interface TmPoolTiers {
[key: number]: RewardTier
[key: number]: RarityTier
}
export const tmPoolTiers: TmPoolTiers = {
[MoveId.MEGA_PUNCH]: RewardTier.GREAT,
[MoveId.PAY_DAY]: RewardTier.ULTRA,
[MoveId.FIRE_PUNCH]: RewardTier.GREAT,
[MoveId.ICE_PUNCH]: RewardTier.GREAT,
[MoveId.THUNDER_PUNCH]: RewardTier.GREAT,
[MoveId.SWORDS_DANCE]: RewardTier.COMMON,
[MoveId.CUT]: RewardTier.COMMON,
[MoveId.FLY]: RewardTier.COMMON,
[MoveId.MEGA_KICK]: RewardTier.GREAT,
[MoveId.BODY_SLAM]: RewardTier.GREAT,
[MoveId.TAKE_DOWN]: RewardTier.GREAT,
[MoveId.DOUBLE_EDGE]: RewardTier.ULTRA,
[MoveId.PIN_MISSILE]: RewardTier.COMMON,
[MoveId.ROAR]: RewardTier.COMMON,
[MoveId.FLAMETHROWER]: RewardTier.ULTRA,
[MoveId.HYDRO_PUMP]: RewardTier.ULTRA,
[MoveId.SURF]: RewardTier.ULTRA,
[MoveId.ICE_BEAM]: RewardTier.ULTRA,
[MoveId.BLIZZARD]: RewardTier.ULTRA,
[MoveId.PSYBEAM]: RewardTier.GREAT,
[MoveId.HYPER_BEAM]: RewardTier.ULTRA,
[MoveId.LOW_KICK]: RewardTier.COMMON,
[MoveId.COUNTER]: RewardTier.COMMON,
[MoveId.STRENGTH]: RewardTier.GREAT,
[MoveId.SOLAR_BEAM]: RewardTier.ULTRA,
[MoveId.FIRE_SPIN]: RewardTier.COMMON,
[MoveId.THUNDERBOLT]: RewardTier.ULTRA,
[MoveId.THUNDER_WAVE]: RewardTier.COMMON,
[MoveId.THUNDER]: RewardTier.ULTRA,
[MoveId.EARTHQUAKE]: RewardTier.ULTRA,
[MoveId.DIG]: RewardTier.GREAT,
[MoveId.TOXIC]: RewardTier.GREAT,
[MoveId.PSYCHIC]: RewardTier.ULTRA,
[MoveId.AGILITY]: RewardTier.COMMON,
[MoveId.NIGHT_SHADE]: RewardTier.COMMON,
[MoveId.SCREECH]: RewardTier.COMMON,
[MoveId.DOUBLE_TEAM]: RewardTier.COMMON,
[MoveId.CONFUSE_RAY]: RewardTier.COMMON,
[MoveId.LIGHT_SCREEN]: RewardTier.COMMON,
[MoveId.HAZE]: RewardTier.COMMON,
[MoveId.REFLECT]: RewardTier.COMMON,
[MoveId.FOCUS_ENERGY]: RewardTier.COMMON,
[MoveId.METRONOME]: RewardTier.COMMON,
[MoveId.SELF_DESTRUCT]: RewardTier.GREAT,
[MoveId.FIRE_BLAST]: RewardTier.ULTRA,
[MoveId.WATERFALL]: RewardTier.GREAT,
[MoveId.SWIFT]: RewardTier.COMMON,
[MoveId.AMNESIA]: RewardTier.COMMON,
[MoveId.DREAM_EATER]: RewardTier.GREAT,
[MoveId.LEECH_LIFE]: RewardTier.ULTRA,
[MoveId.FLASH]: RewardTier.COMMON,
[MoveId.EXPLOSION]: RewardTier.GREAT,
[MoveId.REST]: RewardTier.COMMON,
[MoveId.ROCK_SLIDE]: RewardTier.GREAT,
[MoveId.TRI_ATTACK]: RewardTier.ULTRA,
[MoveId.SUPER_FANG]: RewardTier.COMMON,
[MoveId.SUBSTITUTE]: RewardTier.COMMON,
[MoveId.THIEF]: RewardTier.GREAT,
[MoveId.SNORE]: RewardTier.COMMON,
[MoveId.CURSE]: RewardTier.COMMON,
[MoveId.REVERSAL]: RewardTier.COMMON,
[MoveId.SPITE]: RewardTier.COMMON,
[MoveId.PROTECT]: RewardTier.COMMON,
[MoveId.SCARY_FACE]: RewardTier.COMMON,
[MoveId.SLUDGE_BOMB]: RewardTier.GREAT,
[MoveId.MUD_SLAP]: RewardTier.COMMON,
[MoveId.SPIKES]: RewardTier.COMMON,
[MoveId.ICY_WIND]: RewardTier.GREAT,
[MoveId.OUTRAGE]: RewardTier.ULTRA,
[MoveId.SANDSTORM]: RewardTier.COMMON,
[MoveId.GIGA_DRAIN]: RewardTier.ULTRA,
[MoveId.ENDURE]: RewardTier.COMMON,
[MoveId.CHARM]: RewardTier.COMMON,
[MoveId.FALSE_SWIPE]: RewardTier.COMMON,
[MoveId.SWAGGER]: RewardTier.COMMON,
[MoveId.STEEL_WING]: RewardTier.GREAT,
[MoveId.ATTRACT]: RewardTier.COMMON,
[MoveId.SLEEP_TALK]: RewardTier.COMMON,
[MoveId.HEAL_BELL]: RewardTier.COMMON,
[MoveId.RETURN]: RewardTier.ULTRA,
[MoveId.FRUSTRATION]: RewardTier.COMMON,
[MoveId.SAFEGUARD]: RewardTier.COMMON,
[MoveId.PAIN_SPLIT]: RewardTier.COMMON,
[MoveId.MEGAHORN]: RewardTier.ULTRA,
[MoveId.BATON_PASS]: RewardTier.COMMON,
[MoveId.ENCORE]: RewardTier.COMMON,
[MoveId.IRON_TAIL]: RewardTier.GREAT,
[MoveId.METAL_CLAW]: RewardTier.COMMON,
[MoveId.SYNTHESIS]: RewardTier.GREAT,
[MoveId.HIDDEN_POWER]: RewardTier.GREAT,
[MoveId.RAIN_DANCE]: RewardTier.COMMON,
[MoveId.SUNNY_DAY]: RewardTier.COMMON,
[MoveId.CRUNCH]: RewardTier.GREAT,
[MoveId.PSYCH_UP]: RewardTier.COMMON,
[MoveId.SHADOW_BALL]: RewardTier.ULTRA,
[MoveId.FUTURE_SIGHT]: RewardTier.GREAT,
[MoveId.ROCK_SMASH]: RewardTier.COMMON,
[MoveId.WHIRLPOOL]: RewardTier.COMMON,
[MoveId.BEAT_UP]: RewardTier.COMMON,
[MoveId.UPROAR]: RewardTier.GREAT,
[MoveId.HEAT_WAVE]: RewardTier.ULTRA,
[MoveId.HAIL]: RewardTier.COMMON,
[MoveId.TORMENT]: RewardTier.COMMON,
[MoveId.WILL_O_WISP]: RewardTier.COMMON,
[MoveId.FACADE]: RewardTier.GREAT,
[MoveId.FOCUS_PUNCH]: RewardTier.COMMON,
[MoveId.NATURE_POWER]: RewardTier.COMMON,
[MoveId.CHARGE]: RewardTier.COMMON,
[MoveId.TAUNT]: RewardTier.COMMON,
[MoveId.HELPING_HAND]: RewardTier.COMMON,
[MoveId.TRICK]: RewardTier.COMMON,
[MoveId.SUPERPOWER]: RewardTier.ULTRA,
[MoveId.RECYCLE]: RewardTier.COMMON,
[MoveId.REVENGE]: RewardTier.GREAT,
[MoveId.BRICK_BREAK]: RewardTier.GREAT,
[MoveId.KNOCK_OFF]: RewardTier.GREAT,
[MoveId.ENDEAVOR]: RewardTier.COMMON,
[MoveId.SKILL_SWAP]: RewardTier.COMMON,
[MoveId.IMPRISON]: RewardTier.COMMON,
[MoveId.SECRET_POWER]: RewardTier.COMMON,
[MoveId.DIVE]: RewardTier.GREAT,
[MoveId.FEATHER_DANCE]: RewardTier.COMMON,
[MoveId.BLAZE_KICK]: RewardTier.GREAT,
[MoveId.HYPER_VOICE]: RewardTier.ULTRA,
[MoveId.BLAST_BURN]: RewardTier.ULTRA,
[MoveId.HYDRO_CANNON]: RewardTier.ULTRA,
[MoveId.WEATHER_BALL]: RewardTier.COMMON,
[MoveId.FAKE_TEARS]: RewardTier.COMMON,
[MoveId.AIR_CUTTER]: RewardTier.GREAT,
[MoveId.OVERHEAT]: RewardTier.ULTRA,
[MoveId.ROCK_TOMB]: RewardTier.GREAT,
[MoveId.METAL_SOUND]: RewardTier.COMMON,
[MoveId.COSMIC_POWER]: RewardTier.COMMON,
[MoveId.SIGNAL_BEAM]: RewardTier.GREAT,
[MoveId.SAND_TOMB]: RewardTier.COMMON,
[MoveId.MUDDY_WATER]: RewardTier.GREAT,
[MoveId.BULLET_SEED]: RewardTier.GREAT,
[MoveId.AERIAL_ACE]: RewardTier.GREAT,
[MoveId.ICICLE_SPEAR]: RewardTier.GREAT,
[MoveId.IRON_DEFENSE]: RewardTier.GREAT,
[MoveId.DRAGON_CLAW]: RewardTier.ULTRA,
[MoveId.FRENZY_PLANT]: RewardTier.ULTRA,
[MoveId.BULK_UP]: RewardTier.COMMON,
[MoveId.BOUNCE]: RewardTier.GREAT,
[MoveId.MUD_SHOT]: RewardTier.GREAT,
[MoveId.POISON_TAIL]: RewardTier.GREAT,
[MoveId.COVET]: RewardTier.GREAT,
[MoveId.MAGICAL_LEAF]: RewardTier.GREAT,
[MoveId.CALM_MIND]: RewardTier.GREAT,
[MoveId.LEAF_BLADE]: RewardTier.ULTRA,
[MoveId.DRAGON_DANCE]: RewardTier.GREAT,
[MoveId.ROCK_BLAST]: RewardTier.GREAT,
[MoveId.WATER_PULSE]: RewardTier.GREAT,
[MoveId.ROOST]: RewardTier.GREAT,
[MoveId.GRAVITY]: RewardTier.COMMON,
[MoveId.GYRO_BALL]: RewardTier.COMMON,
[MoveId.BRINE]: RewardTier.GREAT,
[MoveId.PLUCK]: RewardTier.GREAT,
[MoveId.TAILWIND]: RewardTier.GREAT,
[MoveId.U_TURN]: RewardTier.GREAT,
[MoveId.CLOSE_COMBAT]: RewardTier.ULTRA,
[MoveId.PAYBACK]: RewardTier.COMMON,
[MoveId.ASSURANCE]: RewardTier.COMMON,
[MoveId.EMBARGO]: RewardTier.COMMON,
[MoveId.FLING]: RewardTier.COMMON,
[MoveId.GASTRO_ACID]: RewardTier.GREAT,
[MoveId.POWER_SWAP]: RewardTier.COMMON,
[MoveId.GUARD_SWAP]: RewardTier.COMMON,
[MoveId.WORRY_SEED]: RewardTier.GREAT,
[MoveId.TOXIC_SPIKES]: RewardTier.GREAT,
[MoveId.FLARE_BLITZ]: RewardTier.ULTRA,
[MoveId.AURA_SPHERE]: RewardTier.GREAT,
[MoveId.ROCK_POLISH]: RewardTier.COMMON,
[MoveId.POISON_JAB]: RewardTier.GREAT,
[MoveId.DARK_PULSE]: RewardTier.GREAT,
[MoveId.AQUA_TAIL]: RewardTier.GREAT,
[MoveId.SEED_BOMB]: RewardTier.GREAT,
[MoveId.AIR_SLASH]: RewardTier.GREAT,
[MoveId.X_SCISSOR]: RewardTier.GREAT,
[MoveId.BUG_BUZZ]: RewardTier.GREAT,
[MoveId.DRAGON_PULSE]: RewardTier.GREAT,
[MoveId.POWER_GEM]: RewardTier.GREAT,
[MoveId.DRAIN_PUNCH]: RewardTier.GREAT,
[MoveId.VACUUM_WAVE]: RewardTier.COMMON,
[MoveId.FOCUS_BLAST]: RewardTier.GREAT,
[MoveId.ENERGY_BALL]: RewardTier.GREAT,
[MoveId.BRAVE_BIRD]: RewardTier.ULTRA,
[MoveId.EARTH_POWER]: RewardTier.ULTRA,
[MoveId.GIGA_IMPACT]: RewardTier.GREAT,
[MoveId.NASTY_PLOT]: RewardTier.COMMON,
[MoveId.AVALANCHE]: RewardTier.GREAT,
[MoveId.SHADOW_CLAW]: RewardTier.GREAT,
[MoveId.THUNDER_FANG]: RewardTier.GREAT,
[MoveId.ICE_FANG]: RewardTier.GREAT,
[MoveId.FIRE_FANG]: RewardTier.GREAT,
[MoveId.PSYCHO_CUT]: RewardTier.GREAT,
[MoveId.ZEN_HEADBUTT]: RewardTier.GREAT,
[MoveId.FLASH_CANNON]: RewardTier.GREAT,
[MoveId.ROCK_CLIMB]: RewardTier.GREAT,
[MoveId.DEFOG]: RewardTier.COMMON,
[MoveId.TRICK_ROOM]: RewardTier.COMMON,
[MoveId.DRACO_METEOR]: RewardTier.ULTRA,
[MoveId.LEAF_STORM]: RewardTier.ULTRA,
[MoveId.POWER_WHIP]: RewardTier.ULTRA,
[MoveId.CROSS_POISON]: RewardTier.GREAT,
[MoveId.GUNK_SHOT]: RewardTier.ULTRA,
[MoveId.IRON_HEAD]: RewardTier.GREAT,
[MoveId.STONE_EDGE]: RewardTier.ULTRA,
[MoveId.STEALTH_ROCK]: RewardTier.COMMON,
[MoveId.GRASS_KNOT]: RewardTier.ULTRA,
[MoveId.BUG_BITE]: RewardTier.GREAT,
[MoveId.CHARGE_BEAM]: RewardTier.GREAT,
[MoveId.HONE_CLAWS]: RewardTier.COMMON,
[MoveId.WONDER_ROOM]: RewardTier.COMMON,
[MoveId.PSYSHOCK]: RewardTier.GREAT,
[MoveId.VENOSHOCK]: RewardTier.GREAT,
[MoveId.MAGIC_ROOM]: RewardTier.COMMON,
[MoveId.SMACK_DOWN]: RewardTier.COMMON,
[MoveId.SLUDGE_WAVE]: RewardTier.GREAT,
[MoveId.HEAVY_SLAM]: RewardTier.GREAT,
[MoveId.ELECTRO_BALL]: RewardTier.GREAT,
[MoveId.FLAME_CHARGE]: RewardTier.GREAT,
[MoveId.LOW_SWEEP]: RewardTier.GREAT,
[MoveId.ACID_SPRAY]: RewardTier.COMMON,
[MoveId.FOUL_PLAY]: RewardTier.ULTRA,
[MoveId.ROUND]: RewardTier.COMMON,
[MoveId.ECHOED_VOICE]: RewardTier.COMMON,
[MoveId.STORED_POWER]: RewardTier.COMMON,
[MoveId.ALLY_SWITCH]: RewardTier.COMMON,
[MoveId.SCALD]: RewardTier.GREAT,
[MoveId.HEX]: RewardTier.GREAT,
[MoveId.SKY_DROP]: RewardTier.GREAT,
[MoveId.INCINERATE]: RewardTier.GREAT,
[MoveId.QUASH]: RewardTier.COMMON,
[MoveId.ACROBATICS]: RewardTier.GREAT,
[MoveId.RETALIATE]: RewardTier.GREAT,
[MoveId.WATER_PLEDGE]: RewardTier.GREAT,
[MoveId.FIRE_PLEDGE]: RewardTier.GREAT,
[MoveId.GRASS_PLEDGE]: RewardTier.GREAT,
[MoveId.VOLT_SWITCH]: RewardTier.GREAT,
[MoveId.STRUGGLE_BUG]: RewardTier.COMMON,
[MoveId.BULLDOZE]: RewardTier.GREAT,
[MoveId.FROST_BREATH]: RewardTier.GREAT,
[MoveId.DRAGON_TAIL]: RewardTier.GREAT,
[MoveId.WORK_UP]: RewardTier.COMMON,
[MoveId.ELECTROWEB]: RewardTier.GREAT,
[MoveId.WILD_CHARGE]: RewardTier.GREAT,
[MoveId.DRILL_RUN]: RewardTier.GREAT,
[MoveId.RAZOR_SHELL]: RewardTier.GREAT,
[MoveId.HEAT_CRASH]: RewardTier.GREAT,
[MoveId.TAIL_SLAP]: RewardTier.GREAT,
[MoveId.HURRICANE]: RewardTier.ULTRA,
[MoveId.SNARL]: RewardTier.COMMON,
[MoveId.PHANTOM_FORCE]: RewardTier.ULTRA,
[MoveId.PETAL_BLIZZARD]: RewardTier.GREAT,
[MoveId.DISARMING_VOICE]: RewardTier.GREAT,
[MoveId.DRAINING_KISS]: RewardTier.GREAT,
[MoveId.GRASSY_TERRAIN]: RewardTier.COMMON,
[MoveId.MISTY_TERRAIN]: RewardTier.COMMON,
[MoveId.PLAY_ROUGH]: RewardTier.GREAT,
[MoveId.CONFIDE]: RewardTier.COMMON,
[MoveId.MYSTICAL_FIRE]: RewardTier.GREAT,
[MoveId.EERIE_IMPULSE]: RewardTier.COMMON,
[MoveId.VENOM_DRENCH]: RewardTier.COMMON,
[MoveId.ELECTRIC_TERRAIN]: RewardTier.COMMON,
[MoveId.DAZZLING_GLEAM]: RewardTier.ULTRA,
[MoveId.INFESTATION]: RewardTier.COMMON,
[MoveId.POWER_UP_PUNCH]: RewardTier.GREAT,
[MoveId.DARKEST_LARIAT]: RewardTier.GREAT,
[MoveId.HIGH_HORSEPOWER]: RewardTier.ULTRA,
[MoveId.SOLAR_BLADE]: RewardTier.GREAT,
[MoveId.THROAT_CHOP]: RewardTier.GREAT,
[MoveId.POLLEN_PUFF]: RewardTier.GREAT,
[MoveId.PSYCHIC_TERRAIN]: RewardTier.COMMON,
[MoveId.LUNGE]: RewardTier.GREAT,
[MoveId.SPEED_SWAP]: RewardTier.COMMON,
[MoveId.SMART_STRIKE]: RewardTier.GREAT,
[MoveId.BRUTAL_SWING]: RewardTier.GREAT,
[MoveId.AURORA_VEIL]: RewardTier.COMMON,
[MoveId.PSYCHIC_FANGS]: RewardTier.GREAT,
[MoveId.STOMPING_TANTRUM]: RewardTier.GREAT,
[MoveId.LIQUIDATION]: RewardTier.ULTRA,
[MoveId.BODY_PRESS]: RewardTier.ULTRA,
[MoveId.BREAKING_SWIPE]: RewardTier.GREAT,
[MoveId.STEEL_BEAM]: RewardTier.ULTRA,
[MoveId.EXPANDING_FORCE]: RewardTier.GREAT,
[MoveId.STEEL_ROLLER]: RewardTier.COMMON,
[MoveId.SCALE_SHOT]: RewardTier.ULTRA,
[MoveId.METEOR_BEAM]: RewardTier.GREAT,
[MoveId.MISTY_EXPLOSION]: RewardTier.COMMON,
[MoveId.GRASSY_GLIDE]: RewardTier.COMMON,
[MoveId.RISING_VOLTAGE]: RewardTier.COMMON,
[MoveId.TERRAIN_PULSE]: RewardTier.COMMON,
[MoveId.SKITTER_SMACK]: RewardTier.GREAT,
[MoveId.BURNING_JEALOUSY]: RewardTier.GREAT,
[MoveId.LASH_OUT]: RewardTier.GREAT,
[MoveId.POLTERGEIST]: RewardTier.ULTRA,
[MoveId.CORROSIVE_GAS]: RewardTier.COMMON,
[MoveId.COACHING]: RewardTier.COMMON,
[MoveId.FLIP_TURN]: RewardTier.COMMON,
[MoveId.TRIPLE_AXEL]: RewardTier.COMMON,
[MoveId.DUAL_WINGBEAT]: RewardTier.COMMON,
[MoveId.SCORCHING_SANDS]: RewardTier.GREAT,
[MoveId.TERA_BLAST]: RewardTier.GREAT,
[MoveId.ICE_SPINNER]: RewardTier.GREAT,
[MoveId.SNOWSCAPE]: RewardTier.COMMON,
[MoveId.POUNCE]: RewardTier.COMMON,
[MoveId.TRAILBLAZE]: RewardTier.COMMON,
[MoveId.CHILLING_WATER]: RewardTier.COMMON,
[MoveId.HARD_PRESS]: RewardTier.GREAT,
[MoveId.DRAGON_CHEER]: RewardTier.COMMON,
[MoveId.ALLURING_VOICE]: RewardTier.GREAT,
[MoveId.TEMPER_FLARE]: RewardTier.GREAT,
[MoveId.SUPERCELL_SLAM]: RewardTier.GREAT,
[MoveId.PSYCHIC_NOISE]: RewardTier.GREAT,
[MoveId.UPPER_HAND]: RewardTier.COMMON,
[MoveId.MEGA_PUNCH]: RarityTier.GREAT,
[MoveId.PAY_DAY]: RarityTier.ULTRA,
[MoveId.FIRE_PUNCH]: RarityTier.GREAT,
[MoveId.ICE_PUNCH]: RarityTier.GREAT,
[MoveId.THUNDER_PUNCH]: RarityTier.GREAT,
[MoveId.SWORDS_DANCE]: RarityTier.COMMON,
[MoveId.CUT]: RarityTier.COMMON,
[MoveId.FLY]: RarityTier.COMMON,
[MoveId.MEGA_KICK]: RarityTier.GREAT,
[MoveId.BODY_SLAM]: RarityTier.GREAT,
[MoveId.TAKE_DOWN]: RarityTier.GREAT,
[MoveId.DOUBLE_EDGE]: RarityTier.ULTRA,
[MoveId.PIN_MISSILE]: RarityTier.COMMON,
[MoveId.ROAR]: RarityTier.COMMON,
[MoveId.FLAMETHROWER]: RarityTier.ULTRA,
[MoveId.HYDRO_PUMP]: RarityTier.ULTRA,
[MoveId.SURF]: RarityTier.ULTRA,
[MoveId.ICE_BEAM]: RarityTier.ULTRA,
[MoveId.BLIZZARD]: RarityTier.ULTRA,
[MoveId.PSYBEAM]: RarityTier.GREAT,
[MoveId.HYPER_BEAM]: RarityTier.ULTRA,
[MoveId.LOW_KICK]: RarityTier.COMMON,
[MoveId.COUNTER]: RarityTier.COMMON,
[MoveId.STRENGTH]: RarityTier.GREAT,
[MoveId.SOLAR_BEAM]: RarityTier.ULTRA,
[MoveId.FIRE_SPIN]: RarityTier.COMMON,
[MoveId.THUNDERBOLT]: RarityTier.ULTRA,
[MoveId.THUNDER_WAVE]: RarityTier.COMMON,
[MoveId.THUNDER]: RarityTier.ULTRA,
[MoveId.EARTHQUAKE]: RarityTier.ULTRA,
[MoveId.DIG]: RarityTier.GREAT,
[MoveId.TOXIC]: RarityTier.GREAT,
[MoveId.PSYCHIC]: RarityTier.ULTRA,
[MoveId.AGILITY]: RarityTier.COMMON,
[MoveId.NIGHT_SHADE]: RarityTier.COMMON,
[MoveId.SCREECH]: RarityTier.COMMON,
[MoveId.DOUBLE_TEAM]: RarityTier.COMMON,
[MoveId.CONFUSE_RAY]: RarityTier.COMMON,
[MoveId.LIGHT_SCREEN]: RarityTier.COMMON,
[MoveId.HAZE]: RarityTier.COMMON,
[MoveId.REFLECT]: RarityTier.COMMON,
[MoveId.FOCUS_ENERGY]: RarityTier.COMMON,
[MoveId.METRONOME]: RarityTier.COMMON,
[MoveId.SELF_DESTRUCT]: RarityTier.GREAT,
[MoveId.FIRE_BLAST]: RarityTier.ULTRA,
[MoveId.WATERFALL]: RarityTier.GREAT,
[MoveId.SWIFT]: RarityTier.COMMON,
[MoveId.AMNESIA]: RarityTier.COMMON,
[MoveId.DREAM_EATER]: RarityTier.GREAT,
[MoveId.LEECH_LIFE]: RarityTier.ULTRA,
[MoveId.FLASH]: RarityTier.COMMON,
[MoveId.EXPLOSION]: RarityTier.GREAT,
[MoveId.REST]: RarityTier.COMMON,
[MoveId.ROCK_SLIDE]: RarityTier.GREAT,
[MoveId.TRI_ATTACK]: RarityTier.ULTRA,
[MoveId.SUPER_FANG]: RarityTier.COMMON,
[MoveId.SUBSTITUTE]: RarityTier.COMMON,
[MoveId.THIEF]: RarityTier.GREAT,
[MoveId.SNORE]: RarityTier.COMMON,
[MoveId.CURSE]: RarityTier.COMMON,
[MoveId.REVERSAL]: RarityTier.COMMON,
[MoveId.SPITE]: RarityTier.COMMON,
[MoveId.PROTECT]: RarityTier.COMMON,
[MoveId.SCARY_FACE]: RarityTier.COMMON,
[MoveId.SLUDGE_BOMB]: RarityTier.GREAT,
[MoveId.MUD_SLAP]: RarityTier.COMMON,
[MoveId.SPIKES]: RarityTier.COMMON,
[MoveId.ICY_WIND]: RarityTier.GREAT,
[MoveId.OUTRAGE]: RarityTier.ULTRA,
[MoveId.SANDSTORM]: RarityTier.COMMON,
[MoveId.GIGA_DRAIN]: RarityTier.ULTRA,
[MoveId.ENDURE]: RarityTier.COMMON,
[MoveId.CHARM]: RarityTier.COMMON,
[MoveId.FALSE_SWIPE]: RarityTier.COMMON,
[MoveId.SWAGGER]: RarityTier.COMMON,
[MoveId.STEEL_WING]: RarityTier.GREAT,
[MoveId.ATTRACT]: RarityTier.COMMON,
[MoveId.SLEEP_TALK]: RarityTier.COMMON,
[MoveId.HEAL_BELL]: RarityTier.COMMON,
[MoveId.RETURN]: RarityTier.ULTRA,
[MoveId.FRUSTRATION]: RarityTier.COMMON,
[MoveId.SAFEGUARD]: RarityTier.COMMON,
[MoveId.PAIN_SPLIT]: RarityTier.COMMON,
[MoveId.MEGAHORN]: RarityTier.ULTRA,
[MoveId.BATON_PASS]: RarityTier.COMMON,
[MoveId.ENCORE]: RarityTier.COMMON,
[MoveId.IRON_TAIL]: RarityTier.GREAT,
[MoveId.METAL_CLAW]: RarityTier.COMMON,
[MoveId.SYNTHESIS]: RarityTier.GREAT,
[MoveId.HIDDEN_POWER]: RarityTier.GREAT,
[MoveId.RAIN_DANCE]: RarityTier.COMMON,
[MoveId.SUNNY_DAY]: RarityTier.COMMON,
[MoveId.CRUNCH]: RarityTier.GREAT,
[MoveId.PSYCH_UP]: RarityTier.COMMON,
[MoveId.SHADOW_BALL]: RarityTier.ULTRA,
[MoveId.FUTURE_SIGHT]: RarityTier.GREAT,
[MoveId.ROCK_SMASH]: RarityTier.COMMON,
[MoveId.WHIRLPOOL]: RarityTier.COMMON,
[MoveId.BEAT_UP]: RarityTier.COMMON,
[MoveId.UPROAR]: RarityTier.GREAT,
[MoveId.HEAT_WAVE]: RarityTier.ULTRA,
[MoveId.HAIL]: RarityTier.COMMON,
[MoveId.TORMENT]: RarityTier.COMMON,
[MoveId.WILL_O_WISP]: RarityTier.COMMON,
[MoveId.FACADE]: RarityTier.GREAT,
[MoveId.FOCUS_PUNCH]: RarityTier.COMMON,
[MoveId.NATURE_POWER]: RarityTier.COMMON,
[MoveId.CHARGE]: RarityTier.COMMON,
[MoveId.TAUNT]: RarityTier.COMMON,
[MoveId.HELPING_HAND]: RarityTier.COMMON,
[MoveId.TRICK]: RarityTier.COMMON,
[MoveId.SUPERPOWER]: RarityTier.ULTRA,
[MoveId.RECYCLE]: RarityTier.COMMON,
[MoveId.REVENGE]: RarityTier.GREAT,
[MoveId.BRICK_BREAK]: RarityTier.GREAT,
[MoveId.KNOCK_OFF]: RarityTier.GREAT,
[MoveId.ENDEAVOR]: RarityTier.COMMON,
[MoveId.SKILL_SWAP]: RarityTier.COMMON,
[MoveId.IMPRISON]: RarityTier.COMMON,
[MoveId.SECRET_POWER]: RarityTier.COMMON,
[MoveId.DIVE]: RarityTier.GREAT,
[MoveId.FEATHER_DANCE]: RarityTier.COMMON,
[MoveId.BLAZE_KICK]: RarityTier.GREAT,
[MoveId.HYPER_VOICE]: RarityTier.ULTRA,
[MoveId.BLAST_BURN]: RarityTier.ULTRA,
[MoveId.HYDRO_CANNON]: RarityTier.ULTRA,
[MoveId.WEATHER_BALL]: RarityTier.COMMON,
[MoveId.FAKE_TEARS]: RarityTier.COMMON,
[MoveId.AIR_CUTTER]: RarityTier.GREAT,
[MoveId.OVERHEAT]: RarityTier.ULTRA,
[MoveId.ROCK_TOMB]: RarityTier.GREAT,
[MoveId.METAL_SOUND]: RarityTier.COMMON,
[MoveId.COSMIC_POWER]: RarityTier.COMMON,
[MoveId.SIGNAL_BEAM]: RarityTier.GREAT,
[MoveId.SAND_TOMB]: RarityTier.COMMON,
[MoveId.MUDDY_WATER]: RarityTier.GREAT,
[MoveId.BULLET_SEED]: RarityTier.GREAT,
[MoveId.AERIAL_ACE]: RarityTier.GREAT,
[MoveId.ICICLE_SPEAR]: RarityTier.GREAT,
[MoveId.IRON_DEFENSE]: RarityTier.GREAT,
[MoveId.DRAGON_CLAW]: RarityTier.ULTRA,
[MoveId.FRENZY_PLANT]: RarityTier.ULTRA,
[MoveId.BULK_UP]: RarityTier.COMMON,
[MoveId.BOUNCE]: RarityTier.GREAT,
[MoveId.MUD_SHOT]: RarityTier.GREAT,
[MoveId.POISON_TAIL]: RarityTier.GREAT,
[MoveId.COVET]: RarityTier.GREAT,
[MoveId.MAGICAL_LEAF]: RarityTier.GREAT,
[MoveId.CALM_MIND]: RarityTier.GREAT,
[MoveId.LEAF_BLADE]: RarityTier.ULTRA,
[MoveId.DRAGON_DANCE]: RarityTier.GREAT,
[MoveId.ROCK_BLAST]: RarityTier.GREAT,
[MoveId.WATER_PULSE]: RarityTier.GREAT,
[MoveId.ROOST]: RarityTier.GREAT,
[MoveId.GRAVITY]: RarityTier.COMMON,
[MoveId.GYRO_BALL]: RarityTier.COMMON,
[MoveId.BRINE]: RarityTier.GREAT,
[MoveId.PLUCK]: RarityTier.GREAT,
[MoveId.TAILWIND]: RarityTier.GREAT,
[MoveId.U_TURN]: RarityTier.GREAT,
[MoveId.CLOSE_COMBAT]: RarityTier.ULTRA,
[MoveId.PAYBACK]: RarityTier.COMMON,
[MoveId.ASSURANCE]: RarityTier.COMMON,
[MoveId.EMBARGO]: RarityTier.COMMON,
[MoveId.FLING]: RarityTier.COMMON,
[MoveId.GASTRO_ACID]: RarityTier.GREAT,
[MoveId.POWER_SWAP]: RarityTier.COMMON,
[MoveId.GUARD_SWAP]: RarityTier.COMMON,
[MoveId.WORRY_SEED]: RarityTier.GREAT,
[MoveId.TOXIC_SPIKES]: RarityTier.GREAT,
[MoveId.FLARE_BLITZ]: RarityTier.ULTRA,
[MoveId.AURA_SPHERE]: RarityTier.GREAT,
[MoveId.ROCK_POLISH]: RarityTier.COMMON,
[MoveId.POISON_JAB]: RarityTier.GREAT,
[MoveId.DARK_PULSE]: RarityTier.GREAT,
[MoveId.AQUA_TAIL]: RarityTier.GREAT,
[MoveId.SEED_BOMB]: RarityTier.GREAT,
[MoveId.AIR_SLASH]: RarityTier.GREAT,
[MoveId.X_SCISSOR]: RarityTier.GREAT,
[MoveId.BUG_BUZZ]: RarityTier.GREAT,
[MoveId.DRAGON_PULSE]: RarityTier.GREAT,
[MoveId.POWER_GEM]: RarityTier.GREAT,
[MoveId.DRAIN_PUNCH]: RarityTier.GREAT,
[MoveId.VACUUM_WAVE]: RarityTier.COMMON,
[MoveId.FOCUS_BLAST]: RarityTier.GREAT,
[MoveId.ENERGY_BALL]: RarityTier.GREAT,
[MoveId.BRAVE_BIRD]: RarityTier.ULTRA,
[MoveId.EARTH_POWER]: RarityTier.ULTRA,
[MoveId.GIGA_IMPACT]: RarityTier.GREAT,
[MoveId.NASTY_PLOT]: RarityTier.COMMON,
[MoveId.AVALANCHE]: RarityTier.GREAT,
[MoveId.SHADOW_CLAW]: RarityTier.GREAT,
[MoveId.THUNDER_FANG]: RarityTier.GREAT,
[MoveId.ICE_FANG]: RarityTier.GREAT,
[MoveId.FIRE_FANG]: RarityTier.GREAT,
[MoveId.PSYCHO_CUT]: RarityTier.GREAT,
[MoveId.ZEN_HEADBUTT]: RarityTier.GREAT,
[MoveId.FLASH_CANNON]: RarityTier.GREAT,
[MoveId.ROCK_CLIMB]: RarityTier.GREAT,
[MoveId.DEFOG]: RarityTier.COMMON,
[MoveId.TRICK_ROOM]: RarityTier.COMMON,
[MoveId.DRACO_METEOR]: RarityTier.ULTRA,
[MoveId.LEAF_STORM]: RarityTier.ULTRA,
[MoveId.POWER_WHIP]: RarityTier.ULTRA,
[MoveId.CROSS_POISON]: RarityTier.GREAT,
[MoveId.GUNK_SHOT]: RarityTier.ULTRA,
[MoveId.IRON_HEAD]: RarityTier.GREAT,
[MoveId.STONE_EDGE]: RarityTier.ULTRA,
[MoveId.STEALTH_ROCK]: RarityTier.COMMON,
[MoveId.GRASS_KNOT]: RarityTier.ULTRA,
[MoveId.BUG_BITE]: RarityTier.GREAT,
[MoveId.CHARGE_BEAM]: RarityTier.GREAT,
[MoveId.HONE_CLAWS]: RarityTier.COMMON,
[MoveId.WONDER_ROOM]: RarityTier.COMMON,
[MoveId.PSYSHOCK]: RarityTier.GREAT,
[MoveId.VENOSHOCK]: RarityTier.GREAT,
[MoveId.MAGIC_ROOM]: RarityTier.COMMON,
[MoveId.SMACK_DOWN]: RarityTier.COMMON,
[MoveId.SLUDGE_WAVE]: RarityTier.GREAT,
[MoveId.HEAVY_SLAM]: RarityTier.GREAT,
[MoveId.ELECTRO_BALL]: RarityTier.GREAT,
[MoveId.FLAME_CHARGE]: RarityTier.GREAT,
[MoveId.LOW_SWEEP]: RarityTier.GREAT,
[MoveId.ACID_SPRAY]: RarityTier.COMMON,
[MoveId.FOUL_PLAY]: RarityTier.ULTRA,
[MoveId.ROUND]: RarityTier.COMMON,
[MoveId.ECHOED_VOICE]: RarityTier.COMMON,
[MoveId.STORED_POWER]: RarityTier.COMMON,
[MoveId.ALLY_SWITCH]: RarityTier.COMMON,
[MoveId.SCALD]: RarityTier.GREAT,
[MoveId.HEX]: RarityTier.GREAT,
[MoveId.SKY_DROP]: RarityTier.GREAT,
[MoveId.INCINERATE]: RarityTier.GREAT,
[MoveId.QUASH]: RarityTier.COMMON,
[MoveId.ACROBATICS]: RarityTier.GREAT,
[MoveId.RETALIATE]: RarityTier.GREAT,
[MoveId.WATER_PLEDGE]: RarityTier.GREAT,
[MoveId.FIRE_PLEDGE]: RarityTier.GREAT,
[MoveId.GRASS_PLEDGE]: RarityTier.GREAT,
[MoveId.VOLT_SWITCH]: RarityTier.GREAT,
[MoveId.STRUGGLE_BUG]: RarityTier.COMMON,
[MoveId.BULLDOZE]: RarityTier.GREAT,
[MoveId.FROST_BREATH]: RarityTier.GREAT,
[MoveId.DRAGON_TAIL]: RarityTier.GREAT,
[MoveId.WORK_UP]: RarityTier.COMMON,
[MoveId.ELECTROWEB]: RarityTier.GREAT,
[MoveId.WILD_CHARGE]: RarityTier.GREAT,
[MoveId.DRILL_RUN]: RarityTier.GREAT,
[MoveId.RAZOR_SHELL]: RarityTier.GREAT,
[MoveId.HEAT_CRASH]: RarityTier.GREAT,
[MoveId.TAIL_SLAP]: RarityTier.GREAT,
[MoveId.HURRICANE]: RarityTier.ULTRA,
[MoveId.SNARL]: RarityTier.COMMON,
[MoveId.PHANTOM_FORCE]: RarityTier.ULTRA,
[MoveId.PETAL_BLIZZARD]: RarityTier.GREAT,
[MoveId.DISARMING_VOICE]: RarityTier.GREAT,
[MoveId.DRAINING_KISS]: RarityTier.GREAT,
[MoveId.GRASSY_TERRAIN]: RarityTier.COMMON,
[MoveId.MISTY_TERRAIN]: RarityTier.COMMON,
[MoveId.PLAY_ROUGH]: RarityTier.GREAT,
[MoveId.CONFIDE]: RarityTier.COMMON,
[MoveId.MYSTICAL_FIRE]: RarityTier.GREAT,
[MoveId.EERIE_IMPULSE]: RarityTier.COMMON,
[MoveId.VENOM_DRENCH]: RarityTier.COMMON,
[MoveId.ELECTRIC_TERRAIN]: RarityTier.COMMON,
[MoveId.DAZZLING_GLEAM]: RarityTier.ULTRA,
[MoveId.INFESTATION]: RarityTier.COMMON,
[MoveId.POWER_UP_PUNCH]: RarityTier.GREAT,
[MoveId.DARKEST_LARIAT]: RarityTier.GREAT,
[MoveId.HIGH_HORSEPOWER]: RarityTier.ULTRA,
[MoveId.SOLAR_BLADE]: RarityTier.GREAT,
[MoveId.THROAT_CHOP]: RarityTier.GREAT,
[MoveId.POLLEN_PUFF]: RarityTier.GREAT,
[MoveId.PSYCHIC_TERRAIN]: RarityTier.COMMON,
[MoveId.LUNGE]: RarityTier.GREAT,
[MoveId.SPEED_SWAP]: RarityTier.COMMON,
[MoveId.SMART_STRIKE]: RarityTier.GREAT,
[MoveId.BRUTAL_SWING]: RarityTier.GREAT,
[MoveId.AURORA_VEIL]: RarityTier.COMMON,
[MoveId.PSYCHIC_FANGS]: RarityTier.GREAT,
[MoveId.STOMPING_TANTRUM]: RarityTier.GREAT,
[MoveId.LIQUIDATION]: RarityTier.ULTRA,
[MoveId.BODY_PRESS]: RarityTier.ULTRA,
[MoveId.BREAKING_SWIPE]: RarityTier.GREAT,
[MoveId.STEEL_BEAM]: RarityTier.ULTRA,
[MoveId.EXPANDING_FORCE]: RarityTier.GREAT,
[MoveId.STEEL_ROLLER]: RarityTier.COMMON,
[MoveId.SCALE_SHOT]: RarityTier.ULTRA,
[MoveId.METEOR_BEAM]: RarityTier.GREAT,
[MoveId.MISTY_EXPLOSION]: RarityTier.COMMON,
[MoveId.GRASSY_GLIDE]: RarityTier.COMMON,
[MoveId.RISING_VOLTAGE]: RarityTier.COMMON,
[MoveId.TERRAIN_PULSE]: RarityTier.COMMON,
[MoveId.SKITTER_SMACK]: RarityTier.GREAT,
[MoveId.BURNING_JEALOUSY]: RarityTier.GREAT,
[MoveId.LASH_OUT]: RarityTier.GREAT,
[MoveId.POLTERGEIST]: RarityTier.ULTRA,
[MoveId.CORROSIVE_GAS]: RarityTier.COMMON,
[MoveId.COACHING]: RarityTier.COMMON,
[MoveId.FLIP_TURN]: RarityTier.COMMON,
[MoveId.TRIPLE_AXEL]: RarityTier.COMMON,
[MoveId.DUAL_WINGBEAT]: RarityTier.COMMON,
[MoveId.SCORCHING_SANDS]: RarityTier.GREAT,
[MoveId.TERA_BLAST]: RarityTier.GREAT,
[MoveId.ICE_SPINNER]: RarityTier.GREAT,
[MoveId.SNOWSCAPE]: RarityTier.COMMON,
[MoveId.POUNCE]: RarityTier.COMMON,
[MoveId.TRAILBLAZE]: RarityTier.COMMON,
[MoveId.CHILLING_WATER]: RarityTier.COMMON,
[MoveId.HARD_PRESS]: RarityTier.GREAT,
[MoveId.DRAGON_CHEER]: RarityTier.COMMON,
[MoveId.ALLURING_VOICE]: RarityTier.GREAT,
[MoveId.TEMPER_FLARE]: RarityTier.GREAT,
[MoveId.SUPERCELL_SLAM]: RarityTier.GREAT,
[MoveId.PSYCHIC_NOISE]: RarityTier.GREAT,
[MoveId.UPPER_HAND]: RarityTier.COMMON,
};

View File

@ -16,7 +16,7 @@ import type { MoveId } from "#enums/move-id";
import type { MoveSourceType } from "#enums/move-source-type";
import { Nature } from "#enums/nature";
import { PokemonType } from "#enums/pokemon-type";
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import { SpeciesId } from "#enums/species-id";
import { TrainerType } from "#enums/trainer-type";
import { TrainerVariant } from "#enums/trainer-variant";
@ -457,13 +457,13 @@ export class SingleGenerationChallenge extends Challenge {
.setBattleType(BattleType.TRAINER)
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
.setGetTrainerFunc(getRandomTrainerFunc(trainerTypes, true))
.setCustomModifierRewards({
guaranteedModifierTiers: [
RewardTier.ROGUE,
RewardTier.ROGUE,
RewardTier.ULTRA,
RewardTier.ULTRA,
RewardTier.ULTRA,
.setCustomRewards({
guaranteedRarityTiers: [
RarityTier.ROGUE,
RarityTier.ROGUE,
RarityTier.ULTRA,
RarityTier.ULTRA,
RarityTier.ULTRA,
],
allowLuckUpgrades: false,
});
@ -474,14 +474,14 @@ export class SingleGenerationChallenge extends Challenge {
.setBattleType(BattleType.TRAINER)
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
.setGetTrainerFunc(getRandomTrainerFunc(trainerTypes, true))
.setCustomModifierRewards({
guaranteedModifierTiers: [
RewardTier.ROGUE,
RewardTier.ROGUE,
RewardTier.ULTRA,
RewardTier.ULTRA,
RewardTier.ULTRA,
RewardTier.ULTRA,
.setCustomRewards({
guaranteedRarityTiers: [
RarityTier.ROGUE,
RarityTier.ROGUE,
RarityTier.ULTRA,
RarityTier.ULTRA,
RarityTier.ULTRA,
RarityTier.ULTRA,
],
allowLuckUpgrades: false,
});

View File

@ -3,8 +3,8 @@ import type { PokemonSpecies } from "#data/pokemon-species";
import type { HeldItemId } from "#enums/held-item-id";
import type { TrainerItemId } from "#enums/trainer-item-id";
import type { HeldItem } from "#items/held-item";
import type { Rewards } from "#items/reward";
import type { TrainerItem } from "#items/trainer-item";
import type { ModifierTypes } from "#modifiers/modifier-type";
import type { Move } from "#moves/move";
export const allAbilities: Ability[] = [];
@ -15,4 +15,4 @@ export const allHeldItems: Record<HeldItemId, HeldItem> = {};
export const allTrainerItems: Record<TrainerItemId, TrainerItem> = {};
// TODO: Figure out what this is used for and provide an appropriate tsdoc comment
export const modifierTypes = {} as ModifierTypes;
export const allRewards = {} as Rewards;

View File

@ -69,7 +69,7 @@ import { MoveUsedEvent } from "#events/battle-scene";
import type { EnemyPokemon, Pokemon } from "#field/pokemon";
import { applyHeldItems } from "#items/all-held-items";
import { BerryHeldItem, berryTypeToHeldItem } from "#items/berry";
import { HeldItemEffect } from "#items/held-item";
import { HeldItemEffect } from "#enums/held-item-effect";
import { TrainerItemEffect } from "#items/trainer-item";
import { applyMoveAttrs } from "#moves/apply-attrs";
import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSketchMoves, invalidSleepTalkMoves } from "#moves/invalid-moves";
@ -856,7 +856,7 @@ export abstract class Move implements Localizable {
if (!this.hasAttr("TypelessAttr")) {
globalScene.arena.applyTags(WeakenMoveTypeTag, simulated, typeChangeHolder.value, power);
applyHeldItems(HeldItemEffect.ATTACK_TYPE_BOOST, {
pokemon: source,
pokemon: source,
moveType: typeChangeHolder.value,
movePower: power,
});
@ -2636,14 +2636,14 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr {
}
const stolenItem = heldItems[user.randBattleSeedInt(heldItems.length)];
if (!globalScene.tryTransferHeldItem(stolenItem, target, user, false)) {
return false;
}
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:stoleItem",
{ pokemonName: getPokemonNameWithAffix(user),
targetName: getPokemonNameWithAffix(target),
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:stoleItem",
{ pokemonName: getPokemonNameWithAffix(user),
targetName: getPokemonNameWithAffix(target),
itemName: allHeldItems[stolenItem].name
}
));
@ -2719,16 +2719,16 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
globalScene.updateItems(target.isPlayer());
if (this.berriesOnly) {
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:incineratedItem",
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:incineratedItem",
{ pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: allHeldItems[removedItem].name }));
} else {
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:knockedOffItem",
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:knockedOffItem",
{ pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: allHeldItems[removedItem].name }));
}
return true;
}
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
const heldItems = target.getHeldItems();
return heldItems.length ? 5 : 0;
@ -2775,7 +2775,7 @@ export class EatBerryAttr extends MoveEffectAttr {
// check for berry pouch preservation
globalScene.applyPlayerItems(TrainerItemEffect.PRESERVE_BERRY, {pokemon: pokemon, doPreserve: preserve});
if (!preserve.value) {
this.reduceBerryModifier(pokemon);
this.reduceBerryItem(pokemon);
}
// Don't update harvest for berries preserved via Berry pouch (no item dupes lol)
@ -2788,7 +2788,7 @@ export class EatBerryAttr extends MoveEffectAttr {
return target.getHeldItems().filter(m => isItemInCategory(m, HeldItemCategoryId.BERRY));
}
reduceBerryModifier(target: Pokemon) {
reduceBerryItem(target: Pokemon) {
if (this.chosenBerry) {
target.loseHeldItem(this.chosenBerry);
}
@ -2850,7 +2850,7 @@ export class StealEatBerryAttr extends EatBerryAttr {
applyAbAttrs("PostItemLostAbAttr", {pokemon: target});
const message = i18next.t("battle:stealEatBerry", { pokemonName: user.name, targetName: target.name, berryName: allHeldItems[this.chosenBerry].name });
globalScene.phaseManager.queueMessage(message);
this.reduceBerryModifier(target);
this.reduceBerryItem(target);
this.eatBerry(user, target);
return true;

View File

@ -1,12 +1,12 @@
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { globalScene } from "#app/global-scene";
import { modifierTypes } from "#data/data-lists";
import { allRewards } from "#data/data-lists";
import type { IEggOptions } from "#data/egg";
import { EggSourceType } from "#enums/egg-source-types";
import { EggTier } from "#enums/egg-type";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import { SpeciesId } from "#enums/species-id";
import { TrainerType } from "#enums/trainer-type";
import type { EnemyPartyConfig } from "#mystery-encounters/encounter-phase-utils";
@ -150,7 +150,7 @@ export const ATrainersTestEncounter: MysteryEncounter = MysteryEncounterBuilder.
},
async () => {
const encounter = globalScene.currentBattle.mysteryEncounter!;
// Battle the stat trainer for an Egg and great rewards
// Battle the stat trainer for an Egg and great allRewards
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
await transitionMysteryEncounterIntroVisuals();
@ -164,8 +164,8 @@ export const ATrainersTestEncounter: MysteryEncounter = MysteryEncounterBuilder.
encounter.setDialogueToken("eggType", i18next.t(`${namespace}:eggTypes.epic`));
setEncounterRewards(
{
guaranteedModifierTypeFuncs: [modifierTypes.SACRED_ASH],
guaranteedModifierTiers: [RewardTier.ROGUE, RewardTier.ULTRA],
guaranteedRewardFuncs: [allRewards.SACRED_ASH],
guaranteedRarityTiers: [RarityTier.ROGUE, RarityTier.ULTRA],
fillRemaining: true,
},
[eggOptions],

View File

@ -1,7 +1,7 @@
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { globalScene } from "#app/global-scene";
import { speciesStarterCosts } from "#balance/starters";
import { allTrainerItems, modifierTypes } from "#data/data-lists";
import { allRewards, allTrainerItems } from "#data/data-lists";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
@ -136,7 +136,7 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter = MysteryEncounterB
})
.withOptionPhase(async () => {
// Give the player a Shiny Charm
globalScene.phaseManager.unshiftNew("RewardPhase", modifierTypes.SHINY_CHARM);
globalScene.phaseManager.unshiftNew("RewardPhase", allRewards.SHINY_CHARM);
leaveEncounterWithoutBattle(true);
})
.build(),
@ -184,7 +184,7 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter = MysteryEncounterB
],
},
async () => {
// Leave encounter with no rewards or exp
// Leave encounter with no allRewards or exp
leaveEncounterWithoutBattle(true);
return true;
},

View File

@ -1,22 +1,22 @@
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { globalScene } from "#app/global-scene";
import { getPokemonNameWithAffix } from "#app/messages";
import { modifierTypes } from "#data/data-lists";
import { allRewards } from "#data/data-lists";
import { BattlerTagType } from "#enums/battler-tag-type";
import { BerryType } from "#enums/berry-type";
import { ModifierPoolType } from "#enums/modifier-pool-type";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { RewardPoolType } from "#enums/reward-pool-type";
import { PERMANENT_STATS, Stat } from "#enums/stat";
import type { PlayerPokemon, Pokemon } from "#field/pokemon";
import { berryTypeToHeldItem } from "#items/berry";
import type { ModifierTypeOption } from "#modifiers/modifier-type";
import { regenerateModifierPoolThresholds } from "#modifiers/modifier-type";
import type { RewardOption } from "#items/reward";
import { generateRewardPoolWeights, getRewardPoolForType } from "#items/reward-pool-utils";
import { generateRewardOption } from "#items/reward-utils";
import { queueEncounterMessage, showEncounterText } from "#mystery-encounters/encounter-dialogue-utils";
import type { EnemyPartyConfig } from "#mystery-encounters/encounter-phase-utils";
import {
generateModifierTypeOption,
getRandomEncounterSpecies,
initBattleWithEnemyConfig,
leaveEncounterWithoutBattle,
@ -88,7 +88,7 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.
: globalScene.currentBattle.waveIndex > 40
? 4
: 2;
regenerateModifierPoolThresholds(globalScene.getPlayerParty(), ModifierPoolType.PLAYER, 0);
generateRewardPoolWeights(getRewardPoolForType(RewardPoolType.PLAYER), globalScene.getPlayerParty(), 0);
encounter.misc = { numBerries };
const { spriteKey, fileRoot } = getSpriteKeysFromPokemon(bossPokemon);
@ -159,20 +159,16 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.
}
};
const shopOptions: ModifierTypeOption[] = [];
const shopOptions: RewardOption[] = [];
for (let i = 0; i < 5; i++) {
// Generate shop berries
const mod = generateModifierTypeOption(modifierTypes.BERRY);
const mod = generateRewardOption(allRewards.BERRY);
if (mod) {
shopOptions.push(mod);
}
}
setEncounterRewards(
{ guaranteedModifierTypeOptions: shopOptions, fillRemaining: false },
undefined,
doBerryRewards,
);
setEncounterRewards({ guaranteedRewardOptions: shopOptions, fillRemaining: false }, undefined, doBerryRewards);
await initBattleWithEnemyConfig(globalScene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
},
)
@ -190,10 +186,10 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.
const speedDiff = fastestPokemon.getStat(Stat.SPD) / (enemySpeed * 1.1);
const numBerries: number = encounter.misc.numBerries;
const shopOptions: ModifierTypeOption[] = [];
const shopOptions: RewardOption[] = [];
for (let i = 0; i < 5; i++) {
// Generate shop berries
const mod = generateModifierTypeOption(modifierTypes.BERRY);
const mod = generateRewardOption(allRewards.BERRY);
if (mod) {
shopOptions.push(mod);
}
@ -246,7 +242,7 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.
};
setEncounterRewards(
{
guaranteedModifierTypeOptions: shopOptions,
guaranteedRewardOptions: shopOptions,
fillRemaining: false,
},
undefined,
@ -279,7 +275,7 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.
setEncounterExp(fastestPokemon.id, encounter.enemyPartyConfigs[0].pokemonConfigs![0].species.baseExp);
setEncounterRewards(
{
guaranteedModifierTypeOptions: shopOptions,
guaranteedRewardOptions: shopOptions,
fillRemaining: false,
},
undefined,
@ -301,7 +297,7 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.
],
},
async () => {
// Leave encounter with no rewards or exp
// Leave encounter with no allRewards or exp
leaveEncounterWithoutBattle(true);
return true;
},

View File

@ -1,6 +1,6 @@
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { globalScene } from "#app/global-scene";
import { allHeldItems, allMoves, modifierTypes } from "#data/data-lists";
import { allHeldItems, allMoves, allRewards } from "#data/data-lists";
import { HeldItemId } from "#enums/held-item-id";
import { MoveId } from "#enums/move-id";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
@ -8,18 +8,18 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { PartyMemberStrength } from "#enums/party-member-strength";
import { PokemonType } from "#enums/pokemon-type";
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import { SpeciesId } from "#enums/species-id";
import { TrainerItemId } from "#enums/trainer-item-id";
import { TrainerSlot } from "#enums/trainer-slot";
import { TrainerType } from "#enums/trainer-type";
import type { PlayerPokemon, Pokemon } from "#field/pokemon";
import type { ModifierTypeOption } from "#modifiers/modifier-type";
import type { RewardOption } from "#items/reward";
import { generateRewardOption } from "#items/reward-utils";
import { PokemonMove } from "#moves/pokemon-move";
import { getEncounterText, showEncounterDialogue } from "#mystery-encounters/encounter-dialogue-utils";
import type { EnemyPartyConfig } from "#mystery-encounters/encounter-phase-utils";
import {
generateModifierTypeOption,
initBattleWithEnemyConfig,
leaveEncounterWithoutBattle,
selectOptionThenPokemon,
@ -285,7 +285,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
moveTutorOptions,
};
// Assigns callback that teaches move before continuing to rewards
// Assigns callback that teaches move before continuing to allRewards
encounter.onRewards = doBugTypeMoveTutor;
setEncounterRewards({ fillRemaining: true });
@ -305,7 +305,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
// Player shows off their bug types
const encounter = globalScene.currentBattle.mysteryEncounter!;
// Player gets different rewards depending on the number of bug types they have
// Player gets different allRewards depending on the number of bug types they have
const numBugTypes = globalScene.getPlayerParty().filter(p => p.isOfType(PokemonType.BUG, true)).length;
const numBugTypesText = i18next.t(`${namespace}:numBugTypes`, {
count: numBugTypes,
@ -314,7 +314,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
if (numBugTypes < 2) {
setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.SUPER_LURE, modifierTypes.GREAT_BALL],
guaranteedRewardFuncs: [allRewards.SUPER_LURE, allRewards.GREAT_BALL],
fillRemaining: false,
});
encounter.selectedOption!.dialogue!.selected = [
@ -325,7 +325,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
];
} else if (numBugTypes < 4) {
setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.QUICK_CLAW, modifierTypes.MAX_LURE, modifierTypes.ULTRA_BALL],
guaranteedRewardFuncs: [allRewards.QUICK_CLAW, allRewards.MAX_LURE, allRewards.ULTRA_BALL],
fillRemaining: false,
});
encounter.selectedOption!.dialogue!.selected = [
@ -336,7 +336,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
];
} else if (numBugTypes < 6) {
setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.GRIP_CLAW, modifierTypes.MAX_LURE, modifierTypes.ROGUE_BALL],
guaranteedRewardFuncs: [allRewards.GRIP_CLAW, allRewards.MAX_LURE, allRewards.ROGUE_BALL],
fillRemaining: false,
});
encounter.selectedOption!.dialogue!.selected = [
@ -348,38 +348,38 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
} else {
// If the player has any evolution/form change items that are valid for their party,
// spawn one of those items in addition to Dynamax Band, Mega Band, and Master Ball
const modifierOptions: ModifierTypeOption[] = [generateModifierTypeOption(modifierTypes.MASTER_BALL)!];
const specialOptions: ModifierTypeOption[] = [];
const rewardOptions: RewardOption[] = [generateRewardOption(allRewards.MASTER_BALL)!];
const specialOptions: RewardOption[] = [];
if (!globalScene.trainerItems.hasItem(TrainerItemId.MEGA_BRACELET)) {
modifierOptions.push(generateModifierTypeOption(modifierTypes.MEGA_BRACELET)!);
rewardOptions.push(generateRewardOption(allRewards.MEGA_BRACELET)!);
}
if (!globalScene.trainerItems.hasItem(TrainerItemId.DYNAMAX_BAND)) {
modifierOptions.push(generateModifierTypeOption(modifierTypes.DYNAMAX_BAND)!);
rewardOptions.push(generateRewardOption(allRewards.DYNAMAX_BAND)!);
}
const nonRareEvolutionModifier = generateModifierTypeOption(modifierTypes.EVOLUTION_ITEM);
if (nonRareEvolutionModifier) {
specialOptions.push(nonRareEvolutionModifier);
const nonRareEvolutionReward = generateRewardOption(allRewards.EVOLUTION_ITEM);
if (nonRareEvolutionReward) {
specialOptions.push(nonRareEvolutionReward);
}
const rareEvolutionModifier = generateModifierTypeOption(modifierTypes.RARE_EVOLUTION_ITEM);
if (rareEvolutionModifier) {
specialOptions.push(rareEvolutionModifier);
const rareEvolutionReward = generateRewardOption(allRewards.RARE_EVOLUTION_ITEM);
if (rareEvolutionReward) {
specialOptions.push(rareEvolutionReward);
}
const formChangeModifier = generateModifierTypeOption(modifierTypes.FORM_CHANGE_ITEM);
if (formChangeModifier) {
specialOptions.push(formChangeModifier);
const formChangeReward = generateRewardOption(allRewards.FORM_CHANGE_ITEM);
if (formChangeReward) {
specialOptions.push(formChangeReward);
}
const rareFormChangeModifier = generateModifierTypeOption(modifierTypes.RARE_FORM_CHANGE_ITEM);
if (rareFormChangeModifier) {
specialOptions.push(rareFormChangeModifier);
const rareFormChangeReward = generateRewardOption(allRewards.RARE_FORM_CHANGE_ITEM);
if (rareFormChangeReward) {
specialOptions.push(rareFormChangeReward);
}
if (specialOptions.length > 0) {
// TODO: should this use `randSeedItem`?
modifierOptions.push(specialOptions[randSeedInt(specialOptions.length)]);
rewardOptions.push(specialOptions[randSeedInt(specialOptions.length)]);
}
setEncounterRewards({
guaranteedModifierTypeOptions: modifierOptions,
guaranteedRewardOptions: rewardOptions,
fillRemaining: false,
});
encounter.selectedOption!.dialogue!.selected = [
@ -465,12 +465,12 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
chosenPokemon.loseHeldItem(lostItem, false);
globalScene.updateItems(true);
const bugNet = generateModifierTypeOption(modifierTypes.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!;
bugNet.type.tier = RewardTier.ROGUE;
const bugNet = generateRewardOption(allRewards.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!;
bugNet.type.tier = RarityTier.ROGUE;
setEncounterRewards({
guaranteedModifierTypeOptions: [bugNet],
guaranteedModifierTypeFuncs: [modifierTypes.REVIVER_SEED],
guaranteedRewardOptions: [bugNet],
guaranteedRewardFuncs: [allRewards.REVIVER_SEED],
fillRemaining: false,
});
leaveEncounterWithoutBattle(true);
@ -744,7 +744,7 @@ function doBugTypeMoveTutor(): Promise<void> {
);
}
// Complete battle and go to rewards
// Complete battle and go to allRewards
resolve();
});
}

View File

@ -16,13 +16,13 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { PartyMemberStrength } from "#enums/party-member-strength";
import { PokemonType } from "#enums/pokemon-type";
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import { SpeciesId } from "#enums/species-id";
import { TrainerType } from "#enums/trainer-type";
import { UiMode } from "#enums/ui-mode";
import type { PlayerPokemon } from "#field/pokemon";
import { getHeldItemTier } from "#items/held-item-default-tiers";
import { assignItemsFromConfiguration } from "#items/held-item-pool";
import { getHeldItemTier } from "#items/held-item-tiers";
import { PokemonMove } from "#moves/pokemon-move";
import { showEncounterDialogue, showEncounterText } from "#mystery-encounters/encounter-dialogue-utils";
import type { EnemyPartyConfig } from "#mystery-encounters/encounter-phase-utils";
@ -329,11 +329,11 @@ export const ClowningAroundEncounter: MysteryEncounter = MysteryEncounterBuilder
let numRogue = 0;
for (const m of items) {
const tier = getHeldItemTier(m) ?? RewardTier.ULTRA;
const tier = getHeldItemTier(m) ?? RarityTier.ULTRA;
const stack = mostHeldItemsPokemon.heldItemManager.getStack(m);
if (tier === RewardTier.ROGUE) {
if (tier === RarityTier.ROGUE) {
numRogue += stack;
} else if (tier === RewardTier.ULTRA) {
} else if (tier === RarityTier.ULTRA) {
numUltra += stack;
}
mostHeldItemsPokemon.heldItemManager.remove(m, stack);

View File

@ -1,7 +1,7 @@
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { globalScene } from "#app/global-scene";
import { EncounterBattleAnim } from "#data/battle-anims";
import { modifierTypes } from "#data/data-lists";
import { allRewards } from "#data/data-lists";
import { BattlerIndex } from "#enums/battler-index";
import { BattlerTagType } from "#enums/battler-tag-type";
import { BiomeId } from "#enums/biome-id";
@ -219,7 +219,7 @@ export const DancingLessonsEncounter: MysteryEncounter = MysteryEncounterBuilder
await hideOricorioPokemon();
setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.BATON],
guaranteedRewardFuncs: [allRewards.BATON],
fillRemaining: true,
});
await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]);

View File

@ -1,6 +1,6 @@
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { globalScene } from "#app/global-scene";
import { modifierTypes } from "#data/data-lists";
import { allRewards } from "#data/data-lists";
import { Challenges } from "#enums/challenges";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
@ -160,7 +160,7 @@ export const DarkDealEncounter: MysteryEncounter = MysteryEncounterBuilder.withE
.withOptionPhase(async () => {
// Give the player 5 Rogue Balls
const encounter = globalScene.currentBattle.mysteryEncounter!;
globalScene.phaseManager.unshiftNew("RewardPhase", modifierTypes.ROGUE_BALL);
globalScene.phaseManager.unshiftNew("RewardPhase", allRewards.ROGUE_BALL);
// Start encounter with random legendary (7-10 starter strength) that has level additive
// If this is a mono-type challenge, always ensure the required type is filtered for
@ -204,7 +204,7 @@ export const DarkDealEncounter: MysteryEncounter = MysteryEncounterBuilder.withE
],
},
async () => {
// Leave encounter with no rewards or exp
// Leave encounter with no allRewards or exp
leaveEncounterWithoutBattle(true);
return true;
},

View File

@ -1,7 +1,7 @@
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { timedEventManager } from "#app/global-event-manager";
import { globalScene } from "#app/global-scene";
import { allHeldItems, modifierTypes } from "#data/data-lists";
import { allHeldItems, allRewards } from "#data/data-lists";
import { HeldItemCategoryId, HeldItemId, isItemInCategory } from "#enums/held-item-id";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
@ -34,7 +34,7 @@ const namespace = "mysteryEncounters/delibirdy";
/** Berries only */
const OPTION_2_ALLOWED_HELD_ITEMS = [HeldItemCategoryId.BERRY, HeldItemId.REVIVER_SEED];
/** Disallowed items are berries, Reviver Seeds, and Vitamins (form change items and fusion items are not PokemonHeldItemModifiers) */
/** Disallowed items are berries, Reviver Seeds, and Vitamins */
const OPTION_3_DISALLOWED_HELD_ITEMS = [HeldItemCategoryId.BERRY, HeldItemId.REVIVER_SEED];
const DELIBIRDY_MONEY_PRICE_MULTIPLIER = 2;
@ -61,10 +61,10 @@ const doEventReward = () => {
return !fullStack;
});
if (candidates.length > 0) {
globalScene.phaseManager.unshiftNew("RewardPhase", modifierTypes[randSeedItem(candidates)]);
globalScene.phaseManager.unshiftNew("RewardPhase", allRewards[randSeedItem(candidates)]);
} else {
// At max stacks, give a Voucher instead
globalScene.phaseManager.unshiftNew("RewardPhase", modifierTypes.VOUCHER);
globalScene.phaseManager.unshiftNew("RewardPhase", allRewards.VOUCHER);
}
}
};
@ -168,7 +168,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
// At max stacks, give the first party pokemon a Shell Bell instead
backupOption();
} else {
globalScene.phaseManager.unshiftNew("RewardPhase", modifierTypes.AMULET_COIN);
globalScene.phaseManager.unshiftNew("RewardPhase", allRewards.AMULET_COIN);
doEventReward();
}
@ -238,7 +238,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
// At max stacks, give the first party pokemon a Shell Bell instead
backupOption();
} else {
globalScene.phaseManager.unshiftNew("RewardPhase", modifierTypes.CANDY_JAR);
globalScene.phaseManager.unshiftNew("RewardPhase", allRewards.CANDY_JAR);
doEventReward();
}
} else {
@ -249,7 +249,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
// At max stacks, give the first party pokemon a Shell Bell instead
backupOption();
} else {
globalScene.phaseManager.unshiftNew("RewardPhase", modifierTypes.BERRY_POUCH);
globalScene.phaseManager.unshiftNew("RewardPhase", allRewards.BERRY_POUCH);
doEventReward();
}
}
@ -321,7 +321,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
// At max stacks, give the first party pokemon a Shell Bell instead
backupOption();
} else {
globalScene.phaseManager.unshiftNew("RewardPhase", modifierTypes.HEALING_CHARM);
globalScene.phaseManager.unshiftNew("RewardPhase", allRewards.HEALING_CHARM);
doEventReward();
}

View File

@ -1,12 +1,12 @@
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { modifierTypes } from "#data/data-lists";
import { allRewards } from "#data/data-lists";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { SpeciesId } from "#enums/species-id";
import { leaveEncounterWithoutBattle, setEncounterRewards } from "#mystery-encounters/encounter-phase-utils";
import type { MysteryEncounter } from "#mystery-encounters/mystery-encounter";
import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter";
import type { ModifierTypeFunc } from "#types/modifier-types";
import type { RewardFunc } from "#types/rewards";
import { randSeedInt } from "#utils/common";
/** i18n namespace for encounter */
@ -59,23 +59,23 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBu
},
async () => {
// Choose TMs
const modifiers: ModifierTypeFunc[] = [];
const rewards: RewardFunc[] = [];
let i = 0;
while (i < 5) {
// 2/2/1 weight on TM rarity
const roll = randSeedInt(5);
if (roll < 2) {
modifiers.push(modifierTypes.TM_COMMON);
rewards.push(allRewards.TM_COMMON);
} else if (roll < 4) {
modifiers.push(modifierTypes.TM_GREAT);
rewards.push(allRewards.TM_GREAT);
} else {
modifiers.push(modifierTypes.TM_ULTRA);
rewards.push(allRewards.TM_ULTRA);
}
i++;
}
setEncounterRewards({
guaranteedModifierTypeFuncs: modifiers,
guaranteedRewardFuncs: rewards,
fillRemaining: false,
});
leaveEncounterWithoutBattle();
@ -88,21 +88,21 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBu
},
async () => {
// Choose Vitamins
const modifiers: ModifierTypeFunc[] = [];
const rewards: RewardFunc[] = [];
let i = 0;
while (i < 3) {
// 2/1 weight on base stat booster vs PP Up
const roll = randSeedInt(3);
if (roll === 0) {
modifiers.push(modifierTypes.PP_UP);
rewards.push(allRewards.PP_UP);
} else {
modifiers.push(modifierTypes.BASE_STAT_BOOSTER);
rewards.push(allRewards.BASE_STAT_BOOSTER);
}
i++;
}
setEncounterRewards({
guaranteedModifierTypeFuncs: modifiers,
guaranteedRewardFuncs: rewards,
fillRemaining: false,
});
leaveEncounterWithoutBattle();
@ -115,21 +115,21 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBu
},
async () => {
// Choose X Items
const modifiers: ModifierTypeFunc[] = [];
const rewards: RewardFunc[] = [];
let i = 0;
while (i < 5) {
// 4/1 weight on base stat booster vs Dire Hit
const roll = randSeedInt(5);
if (roll === 0) {
modifiers.push(modifierTypes.DIRE_HIT);
rewards.push(allRewards.DIRE_HIT);
} else {
modifiers.push(modifierTypes.TEMP_STAT_STAGE_BOOSTER);
rewards.push(allRewards.TEMP_STAT_STAGE_BOOSTER);
}
i++;
}
setEncounterRewards({
guaranteedModifierTypeFuncs: modifiers,
guaranteedRewardFuncs: rewards,
fillRemaining: false,
});
leaveEncounterWithoutBattle();
@ -142,25 +142,25 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBu
},
async () => {
// Choose Pokeballs
const modifiers: ModifierTypeFunc[] = [];
const rewards: RewardFunc[] = [];
let i = 0;
while (i < 4) {
// 10/30/20/5 weight on pokeballs
const roll = randSeedInt(65);
if (roll < 10) {
modifiers.push(modifierTypes.POKEBALL);
rewards.push(allRewards.POKEBALL);
} else if (roll < 40) {
modifiers.push(modifierTypes.GREAT_BALL);
rewards.push(allRewards.GREAT_BALL);
} else if (roll < 60) {
modifiers.push(modifierTypes.ULTRA_BALL);
rewards.push(allRewards.ULTRA_BALL);
} else {
modifiers.push(modifierTypes.ROGUE_BALL);
rewards.push(allRewards.ROGUE_BALL);
}
i++;
}
setEncounterRewards({
guaranteedModifierTypeFuncs: modifiers,
guaranteedRewardFuncs: rewards,
fillRemaining: false,
});
leaveEncounterWithoutBattle();

View File

@ -1,15 +1,15 @@
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { globalScene } from "#app/global-scene";
import { modifierTypes } from "#data/data-lists";
import { allRewards } from "#data/data-lists";
import { MoveCategory } from "#enums/move-category";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { Stat } from "#enums/stat";
import type { PlayerPokemon } from "#field/pokemon";
import { generateRewardOption } from "#items/reward-utils";
import type { PokemonMove } from "#moves/pokemon-move";
import {
generateModifierTypeOption,
leaveEncounterWithoutBattle,
selectPokemonForOption,
setEncounterExp,
@ -96,15 +96,15 @@ export const FieldTripEncounter: MysteryEncounter = MysteryEncounterBuilder.with
const encounter = globalScene.currentBattle.mysteryEncounter!;
if (encounter.misc.correctMove) {
const modifiers = [
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.ATK])!,
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.DEF])!,
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!,
generateModifierTypeOption(modifierTypes.DIRE_HIT)!,
generateModifierTypeOption(modifierTypes.RARER_CANDY)!,
generateRewardOption(allRewards.TEMP_STAT_STAGE_BOOSTER, [Stat.ATK])!,
generateRewardOption(allRewards.TEMP_STAT_STAGE_BOOSTER, [Stat.DEF])!,
generateRewardOption(allRewards.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!,
generateRewardOption(allRewards.DIRE_HIT)!,
generateRewardOption(allRewards.RARER_CANDY)!,
];
setEncounterRewards({
guaranteedModifierTypeOptions: modifiers,
guaranteedRewardOptions: modifiers,
fillRemaining: false,
});
}
@ -144,15 +144,15 @@ export const FieldTripEncounter: MysteryEncounter = MysteryEncounterBuilder.with
const encounter = globalScene.currentBattle.mysteryEncounter!;
if (encounter.misc.correctMove) {
const modifiers = [
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPATK])!,
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPDEF])!,
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!,
generateModifierTypeOption(modifierTypes.DIRE_HIT)!,
generateModifierTypeOption(modifierTypes.RARER_CANDY)!,
generateRewardOption(allRewards.TEMP_STAT_STAGE_BOOSTER, [Stat.SPATK])!,
generateRewardOption(allRewards.TEMP_STAT_STAGE_BOOSTER, [Stat.SPDEF])!,
generateRewardOption(allRewards.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!,
generateRewardOption(allRewards.DIRE_HIT)!,
generateRewardOption(allRewards.RARER_CANDY)!,
];
setEncounterRewards({
guaranteedModifierTypeOptions: modifiers,
guaranteedRewardOptions: modifiers,
fillRemaining: false,
});
}
@ -192,15 +192,15 @@ export const FieldTripEncounter: MysteryEncounter = MysteryEncounterBuilder.with
const encounter = globalScene.currentBattle.mysteryEncounter!;
if (encounter.misc.correctMove) {
const modifiers = [
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.ACC])!,
generateModifierTypeOption(modifierTypes.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!,
generateModifierTypeOption(modifierTypes.GREAT_BALL)!,
generateModifierTypeOption(modifierTypes.IV_SCANNER)!,
generateModifierTypeOption(modifierTypes.RARER_CANDY)!,
generateRewardOption(allRewards.TEMP_STAT_STAGE_BOOSTER, [Stat.ACC])!,
generateRewardOption(allRewards.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!,
generateRewardOption(allRewards.GREAT_BALL)!,
generateRewardOption(allRewards.IV_SCANNER)!,
generateRewardOption(allRewards.RARER_CANDY)!,
];
setEncounterRewards({
guaranteedModifierTypeOptions: modifiers,
guaranteedRewardOptions: modifiers,
fillRemaining: false,
});
}

View File

@ -250,7 +250,7 @@ export const FieryFalloutEncounter: MysteryEncounter = MysteryEncounterBuilder.w
}
}
// No rewards
// No allRewards
leaveEncounterWithoutBattle(true);
},
)

View File

@ -1,14 +1,16 @@
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { globalScene } from "#app/global-scene";
import { BattlerTagType } from "#enums/battler-tag-type";
import { ModifierPoolType } from "#enums/modifier-pool-type";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { RewardTier } from "#enums/reward-tier";
import { RewardPoolType } from "#enums/reward-pool-type";
import { RarityTier } from "#enums/reward-tier";
import { TrainerItemId } from "#enums/trainer-item-id";
import type { Pokemon } from "#field/pokemon";
import type { ModifierTypeOption } from "#modifiers/modifier-type";
import { getPlayerModifierTypeOptions, regenerateModifierPoolThresholds } from "#modifiers/modifier-type";
import type { RewardOption, TrainerItemReward } from "#items/reward";
import { generatePlayerRewardOptions, generateRewardPoolWeights, getRewardPoolForType } from "#items/reward-pool-utils";
import { isTmReward } from "#items/reward-utils";
import { queueEncounterMessage } from "#mystery-encounters/encounter-dialogue-utils";
import type { EnemyPartyConfig } from "#mystery-encounters/encounter-phase-utils";
import {
@ -89,18 +91,18 @@ export const FightOrFlightEncounter: MysteryEncounter = MysteryEncounterBuilder.
// Waves 10-40 GREAT, 60-120 ULTRA, 120-160 ROGUE, 160-180 MASTER
const tier =
globalScene.currentBattle.waveIndex > 160
? RewardTier.MASTER
? RarityTier.MASTER
: globalScene.currentBattle.waveIndex > 120
? RewardTier.ROGUE
? RarityTier.ROGUE
: globalScene.currentBattle.waveIndex > 40
? RewardTier.ULTRA
: RewardTier.GREAT;
regenerateModifierPoolThresholds(globalScene.getPlayerParty(), ModifierPoolType.PLAYER, 0);
let item: ModifierTypeOption | null = null;
// TMs and Candy Jar excluded from possible rewards as they're too swingy in value for a singular item reward
while (!item || item.type.id.includes("TM_") || item.type.id === "CANDY_JAR") {
item = getPlayerModifierTypeOptions(1, globalScene.getPlayerParty(), [], {
guaranteedModifierTiers: [tier],
? RarityTier.ULTRA
: RarityTier.GREAT;
generateRewardPoolWeights(getRewardPoolForType(RewardPoolType.PLAYER), globalScene.getPlayerParty(), 0);
let item: RewardOption | null = null;
// TMs and Candy Jar excluded from possible allRewards as they're too swingy in value for a singular item reward
while (!item || isTmReward(item.type) || (item.type as TrainerItemReward).itemId === TrainerItemId.CANDY_JAR) {
item = generatePlayerRewardOptions(1, globalScene.getPlayerParty(), [], {
guaranteedRarityTiers: [tier],
allowLuckUpgrades: false,
})[0];
}
@ -151,9 +153,9 @@ export const FightOrFlightEncounter: MysteryEncounter = MysteryEncounterBuilder.
async () => {
// Pick battle
// Pokemon will randomly boost 1 stat by 2 stages
const item = globalScene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption;
const item = globalScene.currentBattle.mysteryEncounter!.misc as RewardOption;
setEncounterRewards({
guaranteedModifierTypeOptions: [item],
guaranteedRewardOptions: [item],
fillRemaining: false,
});
await initBattleWithEnemyConfig(globalScene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);
@ -175,9 +177,9 @@ export const FightOrFlightEncounter: MysteryEncounter = MysteryEncounterBuilder.
.withOptionPhase(async () => {
// Pick steal
const encounter = globalScene.currentBattle.mysteryEncounter!;
const item = globalScene.currentBattle.mysteryEncounter!.misc as ModifierTypeOption;
const item = globalScene.currentBattle.mysteryEncounter!.misc as RewardOption;
setEncounterRewards({
guaranteedModifierTypeOptions: [item],
guaranteedRewardOptions: [item],
fillRemaining: false,
});
@ -199,7 +201,7 @@ export const FightOrFlightEncounter: MysteryEncounter = MysteryEncounterBuilder.
],
},
async () => {
// Leave encounter with no rewards or exp
// Leave encounter with no allRewards or exp
leaveEncounterWithoutBattle(true);
return true;
},

View File

@ -1,7 +1,7 @@
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { globalScene } from "#app/global-scene";
import { getPokemonNameWithAffix } from "#app/messages";
import { modifierTypes } from "#data/data-lists";
import { allRewards } from "#data/data-lists";
import { SpeciesFormChangeActiveTrigger } from "#data/form-change-triggers";
import { getPokeballAtlasKey, getPokeballTintColor } from "#data/pokeball";
import { FieldPosition } from "#enums/field-position";
@ -160,7 +160,7 @@ export const FunAndGamesEncounter: MysteryEncounter = MysteryEncounterBuilder.wi
],
},
async () => {
// Leave encounter with no rewards or exp
// Leave encounter with no allRewards or exp
await transitionMysteryEncounterIntroVisuals(true, true);
leaveEncounterWithoutBattle(true);
return true;
@ -281,21 +281,21 @@ function handleNextTurn() {
if (healthRatio < 0.03) {
// Grand prize
setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.MULTI_LENS],
guaranteedRewardFuncs: [allRewards.MULTI_LENS],
fillRemaining: false,
});
resultMessageKey = `${namespace}:best_result`;
} else if (healthRatio < 0.15) {
// 2nd prize
setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.SCOPE_LENS],
guaranteedRewardFuncs: [allRewards.SCOPE_LENS],
fillRemaining: false,
});
resultMessageKey = `${namespace}:great_result`;
} else if (healthRatio < 0.33) {
// 3rd prize
setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.WIDE_LENS],
guaranteedRewardFuncs: [allRewards.WIDE_LENS],
fillRemaining: false,
});
resultMessageKey = `${namespace}:good_result`;

View File

@ -8,22 +8,23 @@ import { getPokeballAtlasKey, getPokeballTintColor } from "#data/pokeball";
import type { PokemonSpecies } from "#data/pokemon-species";
import { getTypeRgb } from "#data/type";
import { HeldItemCategoryId, type HeldItemId, isItemInCategory } from "#enums/held-item-id";
import { ModifierPoolType } from "#enums/modifier-pool-type";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import type { PokeballType } from "#enums/pokeball";
import { RewardTier } from "#enums/reward-tier";
import { RewardPoolType } from "#enums/reward-pool-type";
import { RarityTier } from "#enums/reward-tier";
import { SpeciesId } from "#enums/species-id";
import { TrainerSlot } from "#enums/trainer-slot";
import { TrainerType } from "#enums/trainer-type";
import { doShinySparkleAnim } from "#field/anims";
import type { PlayerPokemon, Pokemon } from "#field/pokemon";
import { EnemyPokemon } from "#field/pokemon";
import { getHeldItemTier } from "#items/held-item-tiers";
import { getHeldItemTier } from "#items/held-item-default-tiers";
import type { RewardOption } from "#items/reward";
import { generatePlayerRewardOptions, generateRewardPoolWeights, getRewardPoolForType } from "#items/reward-pool-utils";
import { isTmReward } from "#items/reward-utils";
import { TrainerItemEffect } from "#items/trainer-item";
import type { ModifierTypeOption } from "#modifiers/modifier-type";
import { getPlayerModifierTypeOptions, regenerateModifierPoolThresholds } from "#modifiers/modifier-type";
import { PokemonMove } from "#moves/pokemon-move";
import { getEncounterText, showEncounterText } from "#mystery-encounters/encounter-dialogue-utils";
import {
@ -413,26 +414,26 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon;
// Check tier of the traded item, the received item will be one tier up
let tier = getHeldItemTier(heldItemId) ?? RewardTier.GREAT;
let tier = getHeldItemTier(heldItemId) ?? RarityTier.GREAT;
// Increment tier by 1
if (tier < RewardTier.MASTER) {
if (tier < RarityTier.MASTER) {
tier++;
}
regenerateModifierPoolThresholds(party, ModifierPoolType.PLAYER, 0);
let item: ModifierTypeOption | null = null;
// TMs excluded from possible rewards
while (!item || item.type.id.includes("TM_")) {
item = getPlayerModifierTypeOptions(1, party, [], {
guaranteedModifierTiers: [tier],
generateRewardPoolWeights(getRewardPoolForType(RewardPoolType.PLAYER), party, 0);
let item: RewardOption | null = null;
// TMs excluded from possible allRewards
while (!item || isTmReward(item.type)) {
item = generatePlayerRewardOptions(1, party, [], {
guaranteedRarityTiers: [tier],
allowLuckUpgrades: false,
})[0];
}
encounter.setDialogueToken("itemName", item.type.name);
setEncounterRewards({
guaranteedModifierTypeOptions: [item],
guaranteedRewardOptions: [item],
fillRemaining: false,
});
@ -458,7 +459,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter = MysteryEncounterBuil
],
},
async () => {
// Leave encounter with no rewards or exp
// Leave encounter with no allRewards or exp
leaveEncounterWithoutBattle(true);
return true;
},

View File

@ -1,10 +1,10 @@
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { globalScene } from "#app/global-scene";
import { modifierTypes } from "#data/data-lists";
import { allRewards } from "#data/data-lists";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { PartyMemberStrength } from "#enums/party-member-strength";
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import type { EnemyPartyConfig } from "#mystery-encounters/encounter-phase-utils";
import { initBattleWithEnemyConfig, setEncounterRewards } from "#mystery-encounters/encounter-phase-utils";
import type { MysteryEncounter } from "#mystery-encounters/mystery-encounter";
@ -147,7 +147,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM],
guaranteedRewardFuncs: [allRewards.TM_COMMON, allRewards.TM_GREAT, allRewards.MEMORY_MUSHROOM],
fillRemaining: true,
});
@ -175,7 +175,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1];
setEncounterRewards({
guaranteedModifierTiers: [RewardTier.ULTRA, RewardTier.ULTRA, RewardTier.GREAT, RewardTier.GREAT],
guaranteedRarityTiers: [RarityTier.ULTRA, RarityTier.ULTRA, RarityTier.GREAT, RarityTier.GREAT],
fillRemaining: true,
});
@ -206,7 +206,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter
encounter.expMultiplier = 0.9;
setEncounterRewards({
guaranteedModifierTiers: [RewardTier.ROGUE, RewardTier.ROGUE, RewardTier.ULTRA, RewardTier.GREAT],
guaranteedRarityTiers: [RarityTier.ROGUE, RarityTier.ROGUE, RarityTier.ULTRA, RarityTier.GREAT],
fillRemaining: true,
});

View File

@ -4,7 +4,7 @@ import { MoveId } from "#enums/move-id";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import { SpeciesId } from "#enums/species-id";
import { queueEncounterMessage, showEncounterText } from "#mystery-encounters/encounter-dialogue-utils";
import type { EnemyPartyConfig } from "#mystery-encounters/encounter-phase-utils";
@ -141,25 +141,25 @@ export const MysteriousChestEncounter: MysteryEncounter = MysteryEncounterBuilde
if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT) {
// Choose between 2 COMMON / 2 GREAT tier items (20%)
setEncounterRewards({
guaranteedModifierTiers: [RewardTier.COMMON, RewardTier.COMMON, RewardTier.GREAT, RewardTier.GREAT],
guaranteedRarityTiers: [RarityTier.COMMON, RarityTier.COMMON, RarityTier.GREAT, RarityTier.GREAT],
});
// Display result message then proceed to rewards
// Display result message then proceed to allRewards
queueEncounterMessage(`${namespace}:option.1.normal`);
leaveEncounterWithoutBattle();
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT) {
// Choose between 3 ULTRA tier items (30%)
setEncounterRewards({
guaranteedModifierTiers: [RewardTier.ULTRA, RewardTier.ULTRA, RewardTier.ULTRA],
guaranteedRarityTiers: [RarityTier.ULTRA, RarityTier.ULTRA, RarityTier.ULTRA],
});
// Display result message then proceed to rewards
// Display result message then proceed to allRewards
queueEncounterMessage(`${namespace}:option.1.good`);
leaveEncounterWithoutBattle();
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT) {
// Choose between 2 ROGUE tier items (10%)
setEncounterRewards({
guaranteedModifierTiers: [RewardTier.ROGUE, RewardTier.ROGUE],
guaranteedRarityTiers: [RarityTier.ROGUE, RarityTier.ROGUE],
});
// Display result message then proceed to rewards
// Display result message then proceed to allRewards
queueEncounterMessage(`${namespace}:option.1.great`);
leaveEncounterWithoutBattle();
} else if (
@ -168,9 +168,9 @@ export const MysteriousChestEncounter: MysteryEncounter = MysteryEncounterBuilde
) {
// Choose 1 MASTER tier item (5%)
setEncounterRewards({
guaranteedModifierTiers: [RewardTier.MASTER],
guaranteedRarityTiers: [RarityTier.MASTER],
});
// Display result message then proceed to rewards
// Display result message then proceed to allRewards
queueEncounterMessage(`${namespace}:option.1.amazing`);
leaveEncounterWithoutBattle();
} else {
@ -208,7 +208,7 @@ export const MysteriousChestEncounter: MysteryEncounter = MysteryEncounterBuilde
],
},
async () => {
// Leave encounter with no rewards or exp
// Leave encounter with no allRewards or exp
leaveEncounterWithoutBattle(true);
return true;
},

View File

@ -125,7 +125,7 @@ export const SafariZoneEncounter: MysteryEncounter = MysteryEncounterBuilder.wit
],
},
async () => {
// Leave encounter with no rewards or exp
// Leave encounter with no allRewards or exp
leaveEncounterWithoutBattle(true);
return true;
},

View File

@ -227,7 +227,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter = MysteryEncounterBui
],
},
async () => {
// Leave encounter with no rewards or exp
// Leave encounter with no allRewards or exp
leaveEncounterWithoutBattle(true);
return true;
},

View File

@ -1,5 +1,5 @@
import { globalScene } from "#app/global-scene";
import { modifierTypes } from "#data/data-lists";
import { allRewards } from "#data/data-lists";
import { CustomPokemonData } from "#data/pokemon-data";
import { AiType } from "#enums/ai-type";
import { BattlerIndex } from "#enums/battler-index";
@ -116,7 +116,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil
// Pick battle
const encounter = globalScene.currentBattle.mysteryEncounter!;
setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS],
guaranteedRewardFuncs: [allRewards.LEFTOVERS],
fillRemaining: true,
});
encounter.startOfBattleEffects.push({
@ -163,7 +163,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil
// Steal the Snorlax's Leftovers
const instance = globalScene.currentBattle.mysteryEncounter!;
setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS],
guaranteedRewardFuncs: [allRewards.LEFTOVERS],
fillRemaining: false,
});
// Snorlax exp to Pokemon that did the stealing

View File

@ -1,7 +1,7 @@
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { globalScene } from "#app/global-scene";
import { getPokemonNameWithAffix } from "#app/messages";
import { modifierTypes } from "#data/data-lists";
import { allRewards } from "#data/data-lists";
import { BattlerTagType } from "#enums/battler-tag-type";
import { BiomeId } from "#enums/biome-id";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
@ -13,11 +13,10 @@ import { TrainerSlot } from "#enums/trainer-slot";
import { getBiomeKey } from "#field/arena";
import type { Pokemon } from "#field/pokemon";
import { EnemyPokemon } from "#field/pokemon";
import { getPartyLuckValue } from "#modifiers/modifier-type";
import { generateRewardOption } from "#items/reward-utils";
import { queueEncounterMessage, showEncounterText } from "#mystery-encounters/encounter-dialogue-utils";
import type { EnemyPartyConfig } from "#mystery-encounters/encounter-phase-utils";
import {
generateModifierTypeOption,
initBattleWithEnemyConfig,
setEncounterExp,
setEncounterRewards,
@ -34,6 +33,7 @@ import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encou
import { MoneyRequirement, WaveModulusRequirement } from "#mystery-encounters/mystery-encounter-requirements";
import { PokemonData } from "#system/pokemon-data";
import { randSeedInt } from "#utils/common";
import { getPartyLuckValue } from "#utils/party";
/** the i18n namespace for this encounter */
const namespace = "mysteryEncounters/teleportingHijinks";
@ -173,10 +173,10 @@ export const TeleportingHijinksEncounter: MysteryEncounter = MysteryEncounterBui
],
};
const magnet = generateModifierTypeOption(modifierTypes.ATTACK_TYPE_BOOSTER, [PokemonType.STEEL])!;
const metalCoat = generateModifierTypeOption(modifierTypes.ATTACK_TYPE_BOOSTER, [PokemonType.ELECTRIC])!;
const magnet = generateRewardOption(allRewards.ATTACK_TYPE_BOOSTER, [PokemonType.STEEL])!;
const metalCoat = generateRewardOption(allRewards.ATTACK_TYPE_BOOSTER, [PokemonType.ELECTRIC])!;
setEncounterRewards({
guaranteedModifierTypeOptions: [magnet, metalCoat],
guaranteedRewardOptions: [magnet, metalCoat],
fillRemaining: true,
});
await transitionMysteryEncounterIntroVisuals(true, true);

View File

@ -1,6 +1,6 @@
import { globalScene } from "#app/global-scene";
import { speciesStarterCosts } from "#balance/starters";
import { modifierTypes } from "#data/data-lists";
import { allRewards } from "#data/data-lists";
import type { IEggOptions } from "#data/egg";
import { getPokeballTintColor } from "#data/pokeball";
import { BiomeId } from "#enums/biome-id";
@ -294,7 +294,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = MysteryEncount
const eggOptions = getEggOptions(pokemon1CommonEggs, pokemon1RareEggs);
setEncounterRewards(
{
guaranteedModifierTypeFuncs: [modifierTypes.SOOTHE_BELL],
guaranteedRewardFuncs: [allRewards.SOOTHE_BELL],
fillRemaining: true,
},
eggOptions,
@ -304,7 +304,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = MysteryEncount
// Remove all Pokemon from the party except the chosen Pokemon
removePokemonFromPartyAndStoreHeldItems(encounter, pokemon1);
// Configure outro dialogue for egg rewards
// Configure outro dialogue for egg allRewards
encounter.dialogue.outro = [
{
speaker: trainerNameKey,
@ -353,7 +353,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = MysteryEncount
const eggOptions = getEggOptions(pokemon2CommonEggs, pokemon2RareEggs);
setEncounterRewards(
{
guaranteedModifierTypeFuncs: [modifierTypes.SOOTHE_BELL],
guaranteedRewardFuncs: [allRewards.SOOTHE_BELL],
fillRemaining: true,
},
eggOptions,
@ -363,7 +363,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = MysteryEncount
// Remove all Pokemon from the party except the chosen Pokemon
removePokemonFromPartyAndStoreHeldItems(encounter, pokemon2);
// Configure outro dialogue for egg rewards
// Configure outro dialogue for egg allRewards
encounter.dialogue.outro = [
{
speaker: trainerNameKey,
@ -412,7 +412,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = MysteryEncount
const eggOptions = getEggOptions(pokemon3CommonEggs, pokemon3RareEggs);
setEncounterRewards(
{
guaranteedModifierTypeFuncs: [modifierTypes.SOOTHE_BELL],
guaranteedRewardFuncs: [allRewards.SOOTHE_BELL],
fillRemaining: true,
},
eggOptions,
@ -422,7 +422,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = MysteryEncount
// Remove all Pokemon from the party except the chosen Pokemon
removePokemonFromPartyAndStoreHeldItems(encounter, pokemon3);
// Configure outro dialogue for egg rewards
// Configure outro dialogue for egg allRewards
encounter.dialogue.outro = [
{
speaker: trainerNameKey,
@ -640,7 +640,7 @@ function onGameOver() {
const chosenPokemon = encounter.misc.chosenPokemon;
chosenPokemon.friendship = 0;
// Clear all rewards that would have been earned
// Clear all allRewards that would have been earned
encounter.doEncounterRewards = undefined;
// Set flag that encounter was failed

View File

@ -238,7 +238,7 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui
],
},
async () => {
// Leave encounter with no rewards or exp
// Leave encounter with no allRewards or exp
leaveEncounterWithoutBattle(true);
return true;
},

View File

@ -1,6 +1,6 @@
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { globalScene } from "#app/global-scene";
import { modifierTypes } from "#data/data-lists";
import { allRewards } from "#data/data-lists";
import { CustomPokemonData } from "#data/pokemon-data";
import { BattlerIndex } from "#enums/battler-index";
import { BattlerTagType } from "#enums/battler-tag-type";
@ -193,7 +193,7 @@ export const TheStrongStuffEncounter: MysteryEncounter = MysteryEncounterBuilder
// Pick battle
const encounter = globalScene.currentBattle.mysteryEncounter!;
setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.SOUL_DEW],
guaranteedRewardFuncs: [allRewards.SOUL_DEW],
fillRemaining: true,
});
encounter.startOfBattleEffects.push(

View File

@ -1,7 +1,7 @@
import { applyAbAttrs } from "#abilities/apply-ab-attrs";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { globalScene } from "#app/global-scene";
import { modifierTypes } from "#data/data-lists";
import { allRewards } from "#data/data-lists";
import { SpeciesFormChangeAbilityTrigger } from "#data/form-change-triggers";
import { AbilityId } from "#enums/ability-id";
import { BattlerTagType } from "#enums/battler-tag-type";
@ -11,13 +11,13 @@ import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { Nature } from "#enums/nature";
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import { SpeciesId } from "#enums/species-id";
import { TrainerType } from "#enums/trainer-type";
import { generateRewardOption } from "#items/reward-utils";
import { showEncounterDialogue, showEncounterText } from "#mystery-encounters/encounter-dialogue-utils";
import type { EnemyPartyConfig } from "#mystery-encounters/encounter-phase-utils";
import {
generateModifierTypeOption,
initBattleWithEnemyConfig,
leaveEncounterWithoutBattle,
setEncounterRewards,
@ -117,7 +117,7 @@ export const TheWinstrateChallengeEncounter: MysteryEncounter = MysteryEncounter
],
},
async () => {
// Spawn 5 trainer battles back to back with Macho Brace in rewards
// Spawn 5 trainer battles back to back with Macho Brace in allRewards
globalScene.currentBattle.mysteryEncounter!.doContinueEncounter = async () => {
await endTrainerBattleAndShowDialogue();
};
@ -140,7 +140,7 @@ export const TheWinstrateChallengeEncounter: MysteryEncounter = MysteryEncounter
// Refuse the challenge, they full heal the party and give the player a Rarer Candy
globalScene.phaseManager.unshiftNew("PartyHealPhase", true);
setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.RARER_CANDY],
guaranteedRewardFuncs: [allRewards.RARER_CANDY],
fillRemaining: false,
});
leaveEncounterWithoutBattle();
@ -156,17 +156,17 @@ async function spawnNextTrainerOrEndEncounter() {
await showEncounterDialogue(`${namespace}:victory`, `${namespace}:speaker`);
// Give 10x Voucher
const newModifier = modifierTypes.VOUCHER_PREMIUM().newModifier();
globalScene.addModifier(newModifier);
const reward = allRewards.VOUCHER_PREMIUM();
globalScene.applyReward(reward, {});
globalScene.playSound("item_fanfare");
await showEncounterText(i18next.t("battle:rewardGain", { modifierName: newModifier?.type.name }));
await showEncounterText(i18next.t("battle:rewardGain", { modifierName: reward.name }));
await showEncounterDialogue(`${namespace}:victory_2`, `${namespace}:speaker`);
globalScene.ui.clearText(); // Clears "Winstrate" title from screen as rewards get animated in
const machoBrace = generateModifierTypeOption(modifierTypes.MYSTERY_ENCOUNTER_MACHO_BRACE)!;
machoBrace.type.tier = RewardTier.MASTER;
globalScene.ui.clearText(); // Clears "Winstrate" title from screen as allRewards get animated in
const machoBrace = generateRewardOption(allRewards.MYSTERY_ENCOUNTER_MACHO_BRACE)!;
machoBrace.type.tier = RarityTier.MASTER;
setEncounterRewards({
guaranteedModifierTypeOptions: [machoBrace],
guaranteedRewardOptions: [machoBrace],
fillRemaining: false,
});
encounter.doContinueEncounter = undefined;

View File

@ -346,7 +346,7 @@ export const TrainingSessionEncounter: MysteryEncounter = MysteryEncounterBuilde
],
},
async () => {
// Leave encounter with no rewards or exp
// Leave encounter with no allRewards or exp
leaveEncounterWithoutBattle(true);
return true;
},

View File

@ -8,7 +8,7 @@ import { MoveUseMode } from "#enums/move-use-mode";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import { SpeciesId } from "#enums/species-id";
import { TrainerItemId } from "#enums/trainer-item-id";
import { assignItemToFirstFreePokemon } from "#items/item-utility";
@ -167,7 +167,7 @@ export const TrashToTreasureEncounter: MysteryEncounter = MysteryEncounterBuilde
const encounter = globalScene.currentBattle.mysteryEncounter!;
setEncounterRewards({
guaranteedModifierTiers: [RewardTier.ROGUE, RewardTier.ROGUE, RewardTier.ULTRA, RewardTier.GREAT],
guaranteedRarityTiers: [RarityTier.ROGUE, RarityTier.ROGUE, RarityTier.ULTRA, RarityTier.GREAT],
fillRemaining: true,
});
encounter.startOfBattleEffects.push(

View File

@ -1,5 +1,5 @@
import { globalScene } from "#app/global-scene";
import { allSpecies, modifierTypes } from "#data/data-lists";
import { allRewards, allSpecies } from "#data/data-lists";
import { getLevelTotalExp } from "#data/exp";
import type { PokemonSpecies } from "#data/pokemon-species";
import { Challenges } from "#enums/challenges";
@ -11,7 +11,7 @@ import { Nature } from "#enums/nature";
import { PartyMemberStrength } from "#enums/party-member-strength";
import { PlayerGender } from "#enums/player-gender";
import { PokemonType } from "#enums/pokemon-type";
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import { SpeciesId } from "#enums/species-id";
import { TrainerType } from "#enums/trainer-type";
import type { PlayerPokemon, Pokemon } from "#field/pokemon";
@ -218,12 +218,12 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit
await doNewTeamPostProcess(transformations);
setEncounterRewards({
guaranteedModifierTypeFuncs: [
modifierTypes.MEMORY_MUSHROOM,
modifierTypes.ROGUE_BALL,
modifierTypes.MINT,
modifierTypes.MINT,
modifierTypes.MINT,
guaranteedRewardFuncs: [
allRewards.MEMORY_MUSHROOM,
allRewards.ROGUE_BALL,
allRewards.MINT,
allRewards.MINT,
allRewards.MINT,
],
fillRemaining: false,
});
@ -242,7 +242,7 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit
],
},
async () => {
// Battle your "future" team for some item rewards
// Battle your "future" team for some item allRewards
const transformations: PokemonTransformation[] =
globalScene.currentBattle.mysteryEncounter!.misc.teamTransformations;
@ -293,7 +293,7 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit
};
const onBeforeRewards = () => {
// Before battle rewards, unlock the passive on a pokemon in the player's team for the rest of the run (not permanently)
// Before battle allRewards, unlock the passive on a pokemon in the player's team for the rest of the run (not permanently)
// One random pokemon will get its passive unlocked
const passiveDisabledPokemon = globalScene.getPlayerParty().filter(p => !p.passive);
if (passiveDisabledPokemon?.length > 0) {
@ -306,13 +306,13 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit
setEncounterRewards(
{
guaranteedModifierTiers: [
RewardTier.ROGUE,
RewardTier.ROGUE,
RewardTier.ULTRA,
RewardTier.ULTRA,
RewardTier.GREAT,
RewardTier.GREAT,
guaranteedRarityTiers: [
RarityTier.ROGUE,
RarityTier.ROGUE,
RarityTier.ULTRA,
RarityTier.ULTRA,
RarityTier.GREAT,
RarityTier.GREAT,
],
fillRemaining: false,
},

View File

@ -173,11 +173,11 @@ export class MysteryEncounter implements IMysteryEncounter {
onVisualsStart?: () => boolean;
/** Event triggered prior to {@linkcode CommandPhase}, during {@linkcode TurnInitPhase} */
onTurnStart?: () => boolean;
/** Event prior to any rewards logic in {@linkcode MysteryEncounterRewardsPhase} */
/** Event prior to any allRewards logic in {@linkcode MysteryEncounterRewardsPhase} */
onRewards?: () => Promise<void>;
/** Will provide the player party EXP before rewards are displayed for that wave */
/** Will provide the player party EXP before allRewards are displayed for that wave */
doEncounterExp?: () => boolean;
/** Will provide the player a rewards shop for that wave */
/** Will provide the player a allRewards shop for that wave */
doEncounterRewards?: () => boolean;
/** Will execute callback during VictoryPhase of a continuousEncounter */
doContinueEncounter?: () => Promise<void>;
@ -237,10 +237,10 @@ export class MysteryEncounter implements IMysteryEncounter {
encounterMode: MysteryEncounterMode;
/**
* Flag for checking if it's the first time a shop is being shown for an encounter.
* Defaults to true so that the first shop does not override the specified rewards.
* Defaults to true so that the first shop does not override the specified allRewards.
* Will be set to false after a shop is shown (so can't reroll same rarity items for free)
*/
lockEncounterRewardTiers: boolean;
lockEncounterRarityTiers: boolean;
/**
* Will be set automatically, indicates special moves in startOfBattleEffects are complete (so will not repeat)
*/
@ -295,7 +295,7 @@ export class MysteryEncounter implements IMysteryEncounter {
// Reset any dirty flags or encounter data
this.startOfBattleEffectsComplete = false;
this.lockEncounterRewardTiers = true;
this.lockEncounterRarityTiers = true;
this.dialogueTokens = {};
this.enemyPartyConfigs = [];
this.startOfBattleEffects = [];
@ -561,7 +561,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
continuousEncounter = false;
catchAllowed = false;
fleeAllowed = true;
lockEncounterRewardTiers = false;
lockEncounterRarityTiers = false;
startOfBattleEffectsComplete = false;
hasBattleAnimationsWithoutTargets = false;
skipEnemyBattleTurns = false;
@ -928,13 +928,13 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
}
/**
* Can set custom encounter rewards via this callback function
* If rewards are always deterministic for an encounter, this is a good way to set them
* Can set custom encounter allRewards via this callback function
* If allRewards are always deterministic for an encounter, this is a good way to set them
*
* NOTE: If rewards are dependent on options selected, runtime data, etc.,
* NOTE: If allRewards are dependent on options selected, runtime data, etc.,
* It may be better to programmatically set doEncounterRewards elsewhere.
* There is a helper function in mystery-encounter utils, setEncounterRewards(), which can be called programmatically to set rewards
* @param doEncounterRewards Synchronous callback function to perform during rewards phase of the encounter
* There is a helper function in mystery-encounter utils, setEncounterRewards(), which can be called programmatically to set allRewards
* @param doEncounterRewards Synchronous callback function to perform during allRewards phase of the encounter
* @returns
*/
withRewards(doEncounterRewards: () => boolean): this & Required<Pick<IMysteryEncounter, "doEncounterRewards">> {
@ -945,10 +945,10 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
* Can set custom encounter exp via this callback function
* If exp always deterministic for an encounter, this is a good way to set them
*
* NOTE: If rewards are dependent on options selected, runtime data, etc.,
* NOTE: If allRewards are dependent on options selected, runtime data, etc.,
* It may be better to programmatically set doEncounterExp elsewhere.
* There is a helper function in mystery-encounter utils, setEncounterExp(), which can be called programmatically to set rewards
* @param doEncounterExp Synchronous callback function to perform during rewards phase of the encounter
* There is a helper function in mystery-encounter utils, setEncounterExp(), which can be called programmatically to set allRewards
* @param doEncounterExp Synchronous callback function to perform during allRewards phase of the encounter
* @returns
*/
withExp(doEncounterExp: () => boolean): this & Required<Pick<IMysteryEncounter, "doEncounterExp">> {

View File

@ -5,7 +5,6 @@ import { globalScene } from "#app/global-scene";
import { getPokemonNameWithAffix } from "#app/messages";
import { BiomePoolTier, biomeLinks } from "#balance/biomes";
import { initMoveAnim, loadMoveAnimAssets } from "#data/battle-anims";
import { modifierTypes } from "#data/data-lists";
import type { IEggOptions } from "#data/egg";
import { Egg } from "#data/egg";
import type { Gender } from "#data/gender";
@ -17,7 +16,6 @@ import type { AiType } from "#enums/ai-type";
import type { BattlerTagType } from "#enums/battler-tag-type";
import { BiomeId } from "#enums/biome-id";
import { FieldPosition } from "#enums/field-position";
import { ModifierPoolType } from "#enums/modifier-pool-type";
import type { MoveId } from "#enums/move-id";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import type { Nature } from "#enums/nature";
@ -31,8 +29,7 @@ import type { PlayerPokemon, Pokemon } from "#field/pokemon";
import { EnemyPokemon } from "#field/pokemon";
import { Trainer } from "#field/trainer";
import type { HeldItemConfiguration } from "#items/held-item-data-types";
import type { CustomModifierSettings, ModifierType } from "#modifiers/modifier-type";
import { getPartyLuckValue, ModifierTypeGenerator, ModifierTypeOption } from "#modifiers/modifier-type";
import type { CustomRewardSettings } from "#items/reward-pool-utils";
import { PokemonMove } from "#moves/pokemon-move";
import { showEncounterText } from "#mystery-encounters/encounter-dialogue-utils";
import type { MysteryEncounterOption } from "#mystery-encounters/mystery-encounter-option";
@ -44,6 +41,7 @@ import type { OptionSelectConfig, OptionSelectItem } from "#ui/abstact-option-se
import type { PartyOption, PokemonSelectFilter } from "#ui/party-ui-handler";
import { PartyUiMode } from "#ui/party-ui-handler";
import { coerceArray, isNullOrUndefined, randomString, randSeedInt, randSeedItem } from "#utils/common";
import { getPartyLuckValue } from "#utils/party";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import i18next from "i18next";
@ -474,45 +472,6 @@ export function updatePlayerMoney(changeValue: number, playSound = true, showMes
}
}
/**
* Converts modifier bullshit to an actual item
* @param modifier
* @param pregenArgs Can specify BerryType for berries, TM for TMs, AttackBoostType for item, etc.
*/
export function generateModifierType(modifier: () => ModifierType, pregenArgs?: any[]): ModifierType | null {
const modifierId = Object.keys(modifierTypes).find(k => modifierTypes[k] === modifier);
if (!modifierId) {
return null;
}
let result: ModifierType = modifierTypes[modifierId]();
// Populates item id and tier (order matters)
result = result
.withIdFromFunc(modifierTypes[modifierId])
.withTierFromPool(ModifierPoolType.PLAYER, globalScene.getPlayerParty());
return result instanceof ModifierTypeGenerator
? result.generateType(globalScene.getPlayerParty(), pregenArgs)
: result;
}
/**
* Converts modifier bullshit to an actual item
* @param modifier
* @param pregenArgs - can specify BerryType for berries, TM for TMs, AttackBoostType for item, etc.
*/
export function generateModifierTypeOption(
modifier: () => ModifierType,
pregenArgs?: any[],
): ModifierTypeOption | null {
const result = generateModifierType(modifier, pregenArgs);
if (result) {
return new ModifierTypeOption(result, 0);
}
return result;
}
/**
* This function is intended for use inside onPreOptionPhase() of an encounter option
* @param onPokemonSelected - Any logic that needs to be performed when Pokemon is chosen
@ -727,12 +686,12 @@ export function selectOptionThenPokemon(
/**
* Will initialize reward phases to follow the mystery encounter
* Can have shop displayed or skipped
* @param customShopRewards - adds a shop phase with the specified rewards / reward tiers
* @param customShopRewards - adds a shop phase with the specified allRewards / reward tiers
* @param eggRewards
* @param preRewardsCallback - can execute an arbitrary callback before the new phases if necessary (useful for updating items/party/injecting new phases before {@linkcode MysteryEncounterRewardsPhase})
*/
export function setEncounterRewards(
customShopRewards?: CustomModifierSettings,
customShopRewards?: CustomRewardSettings,
eggRewards?: IEggOptions[],
preRewardsCallback?: Function,
) {
@ -809,8 +768,8 @@ export function initSubsequentOptionSelect(optionSelectSettings: OptionSelectSet
/**
* Can be used to exit an encounter without any battles or followup
* Will skip any shops and rewards, and queue the next encounter phase as normal
* @param addHealPhase - when true, will add a shop phase to end of encounter with 0 rewards but healing items are available
* Will skip any shops and allRewards, and queue the next encounter phase as normal
* @param addHealPhase - when true, will add a shop phase to end of encounter with 0 allRewards but healing items are available
* @param encounterMode - Can set custom encounter mode if necessary (may be required for forcing Pokemon to return before next phase)
*/
export function leaveEncounterWithoutBattle(

View File

@ -4,8 +4,8 @@ import { globalScene } from "#app/global-scene";
import { randSeedInt } from "#app/utils/common";
import { BattleType } from "#enums/battle-type";
import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
import { ModifierTier } from "#enums/modifier-tier";
import { PlayerGender } from "#enums/player-gender";
import { RarityTier } from "#enums/reward-tier";
import { TrainerType } from "#enums/trainer-type";
import { TrainerVariant } from "#enums/trainer-variant";
@ -45,8 +45,8 @@ export const classicFixedBattles: FixedBattleConfigs = {
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
),
)
.setCustomModifierRewards({
guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT],
.setCustomRewards({
guaranteedRarityTiers: [RarityTier.ULTRA, RarityTier.GREAT, RarityTier.GREAT],
allowLuckUpgrades: false,
}),
[ClassicFixedBossWaves.EVIL_GRUNT_1]: new FixedBattleConfig()
@ -77,8 +77,8 @@ export const classicFixedBattles: FixedBattleConfigs = {
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
),
)
.setCustomModifierRewards({
guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT],
.setCustomRewards({
guaranteedRarityTiers: [RarityTier.ULTRA, RarityTier.ULTRA, RarityTier.GREAT, RarityTier.GREAT],
allowLuckUpgrades: false,
}),
[ClassicFixedBossWaves.EVIL_GRUNT_2]: new FixedBattleConfig()
@ -150,8 +150,8 @@ export const classicFixedBattles: FixedBattleConfigs = {
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
),
)
.setCustomModifierRewards({
guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA],
.setCustomRewards({
guaranteedRarityTiers: [RarityTier.ULTRA, RarityTier.ULTRA, RarityTier.ULTRA, RarityTier.ULTRA],
allowLuckUpgrades: false,
}),
[ClassicFixedBossWaves.EVIL_GRUNT_4]: new FixedBattleConfig()
@ -212,14 +212,8 @@ export const classicFixedBattles: FixedBattleConfigs = {
TrainerType.PENNY,
]),
)
.setCustomModifierRewards({
guaranteedModifierTiers: [
ModifierTier.ROGUE,
ModifierTier.ROGUE,
ModifierTier.ULTRA,
ModifierTier.ULTRA,
ModifierTier.ULTRA,
],
.setCustomRewards({
guaranteedRarityTiers: [RarityTier.ROGUE, RarityTier.ROGUE, RarityTier.ULTRA, RarityTier.ULTRA, RarityTier.ULTRA],
allowLuckUpgrades: false,
}),
[ClassicFixedBossWaves.RIVAL_5]: new FixedBattleConfig()
@ -231,14 +225,8 @@ export const classicFixedBattles: FixedBattleConfigs = {
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
),
)
.setCustomModifierRewards({
guaranteedModifierTiers: [
ModifierTier.ROGUE,
ModifierTier.ROGUE,
ModifierTier.ROGUE,
ModifierTier.ULTRA,
ModifierTier.ULTRA,
],
.setCustomRewards({
guaranteedRarityTiers: [RarityTier.ROGUE, RarityTier.ROGUE, RarityTier.ROGUE, RarityTier.ULTRA, RarityTier.ULTRA],
allowLuckUpgrades: false,
}),
[ClassicFixedBossWaves.EVIL_BOSS_2]: new FixedBattleConfig()
@ -258,14 +246,14 @@ export const classicFixedBattles: FixedBattleConfigs = {
TrainerType.PENNY_2,
]),
)
.setCustomModifierRewards({
guaranteedModifierTiers: [
ModifierTier.ROGUE,
ModifierTier.ROGUE,
ModifierTier.ULTRA,
ModifierTier.ULTRA,
ModifierTier.ULTRA,
ModifierTier.ULTRA,
.setCustomRewards({
guaranteedRarityTiers: [
RarityTier.ROGUE,
RarityTier.ROGUE,
RarityTier.ULTRA,
RarityTier.ULTRA,
RarityTier.ULTRA,
RarityTier.ULTRA,
],
allowLuckUpgrades: false,
}),
@ -362,14 +350,14 @@ export const classicFixedBattles: FixedBattleConfigs = {
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
),
)
.setCustomModifierRewards({
guaranteedModifierTiers: [
ModifierTier.ROGUE,
ModifierTier.ROGUE,
ModifierTier.ULTRA,
ModifierTier.ULTRA,
ModifierTier.GREAT,
ModifierTier.GREAT,
.setCustomRewards({
guaranteedRarityTiers: [
RarityTier.ROGUE,
RarityTier.ROGUE,
RarityTier.ULTRA,
RarityTier.ULTRA,
RarityTier.GREAT,
RarityTier.GREAT,
],
allowLuckUpgrades: false,
}),

View File

@ -3,7 +3,7 @@ import { globalScene } from "#app/global-scene";
import { pokemonEvolutions, pokemonPrevolutions } from "#balance/pokemon-evolutions";
import { signatureSpecies } from "#balance/signature-species";
import { tmSpecies } from "#balance/tms";
import { modifierTypes } from "#data/data-lists";
import { allRewards } from "#data/data-lists";
import { doubleBattleDialogue } from "#data/double-battle-dialogue";
import { Gender } from "#data/gender";
import type { PokemonSpecies, PokemonSpeciesFilter } from "#data/pokemon-species";
@ -31,7 +31,7 @@ import {
TrainerPartyTemplate,
trainerPartyTemplates,
} from "#trainers/trainer-party-template";
import type { ModifierTypeFunc } from "#types/modifier-types";
import type { RewardFunc } from "#types/rewards";
import type {
GenAIFunc,
GenTrainerItemsFunc,
@ -113,9 +113,9 @@ export class TrainerConfig {
public femaleEncounterBgm: string;
public doubleEncounterBgm: string;
public victoryBgm: string;
public genModifiersFunc: GenTrainerItemsFunc;
public genTrainerItemsFunc: GenTrainerItemsFunc;
public genAIFuncs: GenAIFunc[] = [];
public modifierRewardFuncs: ModifierTypeFunc[] = [];
public rewardFuncs: RewardFunc[] = [];
public partyTemplates: TrainerPartyTemplate[];
public partyTemplateFunc: PartyTemplateFunc;
public partyMemberFuncs: PartyMemberFuncs = {};
@ -465,8 +465,8 @@ export class TrainerConfig {
return this;
}
setGenModifiersFunc(genModifiersFunc: GenTrainerItemsFunc): TrainerConfig {
this.genModifiersFunc = genModifiersFunc;
setGenTrainerItemsFunc(genTrainerItemsFunc: GenTrainerItemsFunc): TrainerConfig {
this.genTrainerItemsFunc = genTrainerItemsFunc;
return this;
}
@ -476,7 +476,7 @@ export class TrainerConfig {
* @param slot Optional, a specified slot that should be terastallized. Wraps to match party size (-1 will get the last slot and so on).
* @returns this
*/
setRandomTeraModifiers(count: () => number, slot?: number): TrainerConfig {
setRandomTeraType(count: () => number, slot?: number): TrainerConfig {
this.genAIFuncs.push((party: EnemyPokemon[]) => {
const shedinjaCanTera = !this.hasSpecialtyType() || this.specialtyType === PokemonType.BUG; // Better to check one time than 6
const partyMemberIndexes = new Array(party.length)
@ -507,23 +507,11 @@ export class TrainerConfig {
return this;
}
// function getRandomTeraModifiers(party: EnemyPokemon[], count: integer, types?: Type[]): PersistentModifier[] {
// const ret: PersistentModifier[] = [];
// const partyMemberIndexes = new Array(party.length).fill(null).map((_, i) => i);
// for (let t = 0; t < Math.min(count, party.length); t++) {
// const randomIndex = Utils.randSeedItem(partyMemberIndexes);
// partyMemberIndexes.splice(partyMemberIndexes.indexOf(randomIndex), 1);
// ret.push(modifierTypes.TERA_SHARD().generateType([], [ Utils.randSeedItem(types ? types : party[randomIndex].getTypes()) ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(party[randomIndex]) as PersistentModifier); // TODO: is the bang correct?
// }
// return ret;
// }
setModifierRewardFuncs(...modifierTypeFuncs: (() => ModifierTypeFunc)[]): TrainerConfig {
this.modifierRewardFuncs = modifierTypeFuncs.map(func => () => {
const modifierTypeFunc = func();
const modifierType = modifierTypeFunc();
modifierType.withIdFromFunc(modifierTypeFunc);
return modifierType;
setRewardFuncs(...rewardFuncs: (() => RewardFunc)[]): TrainerConfig {
this.rewardFuncs = rewardFuncs.map(func => () => {
const rewardFunc = func();
const reward = rewardFunc();
return reward;
});
return this;
}
@ -689,7 +677,7 @@ export class TrainerConfig {
this.setHasVoucher(true);
this.setBattleBgm("battle_unova_gym");
this.setVictoryBgm("victory_gym");
this.setRandomTeraModifiers(
this.setRandomTeraType(
() => (ignoreMinTeraWave || globalScene.currentBattle.waveIndex >= GYM_LEADER_TERA_WAVE ? 1 : 0),
teraSlot,
);
@ -750,7 +738,7 @@ export class TrainerConfig {
this.setHasVoucher(true);
this.setBattleBgm("battle_unova_elite");
this.setVictoryBgm("victory_gym");
this.setRandomTeraModifiers(() => 1, teraSlot);
this.setRandomTeraType(() => 1, teraSlot);
return this;
}
@ -927,11 +915,11 @@ export class TrainerConfig {
clone = this.battleBgm ? clone.setBattleBgm(this.battleBgm) : clone;
clone = this.encounterBgm ? clone.setEncounterBgm(this.encounterBgm) : clone;
clone = this.victoryBgm ? clone.setVictoryBgm(this.victoryBgm) : clone;
clone = this.genModifiersFunc ? clone.setGenModifiersFunc(this.genModifiersFunc) : clone;
clone = this.genTrainerItemsFunc ? clone.setGenTrainerItemsFunc(this.genTrainerItemsFunc) : clone;
if (this.modifierRewardFuncs) {
if (this.rewardFuncs) {
// Clones array instead of passing ref
clone.modifierRewardFuncs = this.modifierRewardFuncs.slice(0);
clone.rewardFuncs = this.rewardFuncs.slice(0);
}
if (this.partyTemplates) {
@ -4443,9 +4431,9 @@ export const trainerConfigs: TrainerConfigs = {
.setBattleBgm("battle_rival")
.setMixedBattleBgm("battle_rival")
.setPartyTemplates(trainerPartyTemplates.RIVAL)
.setModifierRewardFuncs(
() => modifierTypes.SUPER_EXP_CHARM,
() => modifierTypes.EXP_SHARE,
.setRewardFuncs(
() => allRewards.SUPER_EXP_CHARM,
() => allRewards.EXP_SHARE,
)
.setPartyMemberFunc(
0,
@ -4513,7 +4501,7 @@ export const trainerConfigs: TrainerConfigs = {
.setBattleBgm("battle_rival")
.setMixedBattleBgm("battle_rival")
.setPartyTemplates(trainerPartyTemplates.RIVAL_2)
.setModifierRewardFuncs(() => modifierTypes.EXP_SHARE)
.setRewardFuncs(() => allRewards.EXP_SHARE)
.setPartyMemberFunc(
0,
getRandomPartyMemberFunc(
@ -4666,7 +4654,7 @@ export const trainerConfigs: TrainerConfigs = {
.setBattleBgm("battle_rival_2")
.setMixedBattleBgm("battle_rival_2")
.setPartyTemplates(trainerPartyTemplates.RIVAL_4)
.setModifierRewardFuncs(() => modifierTypes.TERA_ORB)
.setRewardFuncs(() => allRewards.TERA_ORB)
.setPartyMemberFunc(
0,
getRandomPartyMemberFunc(

View File

@ -0,0 +1,37 @@
import type { EnumValues } from "#types/enum-types";
/**
* Enum representing the various "classes" of item effects that can be applied.
*/
export const HeldItemEffect = {
ATTACK_TYPE_BOOST: 1,
TURN_END_HEAL: 2,
HIT_HEAL: 3,
RESET_NEGATIVE_STAT_STAGE: 4,
EXP_BOOSTER: 5,
// Should we actually distinguish different berry effects?
BERRY: 6,
BASE_STAT_BOOSTER: 7,
INSTANT_REVIVE: 8,
STAT_BOOST: 9,
CRIT_BOOST: 10,
TURN_END_STATUS: 11,
SURVIVE_CHANCE: 12,
BYPASS_SPEED_CHANCE: 13,
FLINCH_CHANCE: 14,
FIELD_EFFECT: 15,
FRIENDSHIP_BOOSTER: 16,
NATURE_WEIGHT_BOOSTER: 17,
ACCURACY_BOOSTER: 18,
MULTI_HIT: 19,
DAMAGE_MONEY_REWARD: 20,
BATON: 21,
TURN_END_ITEM_STEAL: 22,
CONTACT_ITEM_STEAL_CHANCE: 23,
EVO_TRACKER: 40,
BASE_STAT_TOTAL: 50,
BASE_STAT_FLAT: 51,
INCREMENTING_STAT: 52,
} as const;
export type HeldItemEffect = EnumValues<typeof HeldItemEffect>;

View File

@ -1,3 +1,5 @@
import type { EnumValues } from "#types/enum-types";
// TODO: make category the lower 2 bytes
export const HeldItemId = {
NONE: 0x0000,
@ -92,19 +94,24 @@ export const HeldItemId = {
GIMMIGHOUL_EVO_TRACKER: 0x0A01,
} as const;
export type HeldItemId = (typeof HeldItemId)[keyof typeof HeldItemId];
export type HeldItemId = EnumValues<typeof HeldItemId>;
type HeldItemNameMap = {
[k in HeldItemName as (typeof HeldItemId)[k]]: k
}
type HeldItemName = keyof typeof HeldItemId;
type HeldItemValue = typeof HeldItemId[HeldItemName]; // equivalent to `HeldItemId`
// Use a type-safe reducer to force number keys and values
export const HeldItemNames: Record<HeldItemValue, HeldItemName> = Object.entries(HeldItemId).reduce(
/** `const object` mapping all held item IDs to their respective names. */
// TODO: This stores names as UPPER_SNAKE_CASE, but the locales are in PascalCase...
export const HeldItemNames = Object.freeze(Object.entries(HeldItemId).reduce(
// Use a type-safe reducer to force number keys and values
(acc, [key, value]) => {
acc[value as HeldItemValue] = key as HeldItemName;
acc[value] = key;
return acc;
},
{} as Record<HeldItemValue, HeldItemName>
);
{}
)) as HeldItemNameMap;
export const HeldItemCategoryId = {
NONE: 0x0000,
@ -120,7 +127,7 @@ export const HeldItemCategoryId = {
EVO_TRACKER: 0x0A00,
} as const;
export type HeldItemCategoryId = (typeof HeldItemCategoryId)[keyof typeof HeldItemCategoryId];
export type HeldItemCategoryId = EnumValues<typeof HeldItemCategoryId>;
const ITEM_CATEGORY_MASK = 0xFF00

99
src/enums/reward-id.ts Normal file
View File

@ -0,0 +1,99 @@
import type { EnumValues } from "#types/enum-types";
export const RewardId = {
NONE: 0x0000,
POKEBALL: 0x2001,
GREAT_BALL: 0x2002,
ULTRA_BALL: 0x2003,
ROGUE_BALL: 0x2004,
MASTER_BALL: 0x2005,
VOUCHER: 0x2101,
VOUCHER_PLUS: 0x2102,
VOUCHER_PREMIUM: 0x2103,
NUGGET: 0x2201,
BIG_NUGGET: 0x2202,
RELIC_GOLD: 0x2203,
RARE_CANDY: 0x2301,
RARER_CANDY: 0x2302,
EVOLUTION_ITEM: 0x2401,
RARE_EVOLUTION_ITEM: 0x2402,
POTION: 0x2501,
SUPER_POTION: 0x2502,
HYPER_POTION: 0x2503,
MAX_POTION: 0x2504,
FULL_HEAL: 0x2505,
FULL_RESTORE: 0x2506,
REVIVE: 0x2601,
MAX_REVIVE: 0x2602,
SACRED_ASH: 0x2603,
ETHER: 0x2701,
MAX_ETHER: 0x2702,
ELIXIR: 0x2801,
MAX_ELIXIR: 0x2802,
PP_UP: 0x2901,
PP_MAX: 0x2902,
TM_COMMON: 0x2A01,
TM_GREAT: 0x2A02,
TM_ULTRA: 0x2A03,
MINT: 0x2B01,
TERA_SHARD: 0x2B02,
MEMORY_MUSHROOM: 0x2B03,
DNA_SPLICERS: 0x2B04,
HELD_ITEM: 0x2C01,
SPECIES_STAT_BOOSTER: 0x2C02,
RARE_SPECIES_STAT_BOOSTER: 0x2C03,
BASE_STAT_BOOSTER: 0x2C04,
ATTACK_TYPE_BOOSTER: 0x2C05,
BERRY: 0x2C06,
TRAINER_ITEM: 0x2D01,
TEMP_STAT_STAGE_BOOSTER: 0x2D02,
LURE: 0x2D03,
SUPER_LURE: 0x2D04,
MAX_LURE: 0x2D05,
FORM_CHANGE_ITEM: 0x2E01,
RARE_FORM_CHANGE_ITEM: 0x2E02,
} as const;
export type RewardId = EnumValues<typeof RewardId>;
export const RewardCategoryId = {
NONE: 0x0000,
POKEBALL: 0x0100,
VOUCHER: 0x0200,
MONEY: 0x0300,
CANDY: 0x0400,
EVOLUTION_ITEM: 0x0500,
HEALING: 0x0600,
REVIVE: 0x0700,
ETHER: 0x0800,
ELIXIR: 0x0900,
PP_UP: 0x0A00,
TM: 0x0B00,
OTHER: 0x0C00,
HELD_ITEM: 0x0D00,
TRAINER_ITEM: 0x0E00,
FORM_CHANGE_ITEM: 0x0F00,
} as const;
export type RewardCategoryId = EnumValues<typeof RewardCategoryId>;
const ITEM_CATEGORY_MASK = 0xFF00
export function getRewardCategory(itemId: RewardId): RewardCategoryId {
return (itemId & ITEM_CATEGORY_MASK) as RewardCategoryId;
}

View File

@ -1,4 +1,4 @@
export enum ModifierPoolType {
export enum RewardPoolType {
PLAYER,
}

View File

@ -1,4 +1,4 @@
export enum RewardTier {
export enum RarityTier {
COMMON,
GREAT,
ULTRA,

View File

@ -1,56 +1,56 @@
export const TrainerItemId = {
NONE: 0x0000,
MAP: 0x0B01,
IV_SCANNER: 0x0B02,
LOCK_CAPSULE: 0x0B03,
MEGA_BRACELET: 0x0B04,
DYNAMAX_BAND: 0x0B05,
TERA_ORB: 0x0B06,
MAP: 0x1001,
IV_SCANNER: 0x1002,
LOCK_CAPSULE: 0x1003,
MEGA_BRACELET: 0x1004,
DYNAMAX_BAND: 0x1005,
TERA_ORB: 0x1006,
GOLDEN_POKEBALL: 0x0B07,
GOLDEN_POKEBALL: 0x1007,
OVAL_CHARM: 0x0B08,
EXP_SHARE: 0x0B09,
EXP_BALANCE: 0x0B0A,
OVAL_CHARM: 0x1008,
EXP_SHARE: 0x1009,
EXP_BALANCE: 0x100A,
CANDY_JAR: 0x0B0B,
BERRY_POUCH: 0x0B0C,
CANDY_JAR: 0x100B,
BERRY_POUCH: 0x100C,
HEALING_CHARM: 0x0B0D,
EXP_CHARM: 0x0B0E,
SUPER_EXP_CHARM: 0x0B0F,
GOLDEN_EXP_CHARM: 0x0B10,
AMULET_COIN: 0x0B11,
HEALING_CHARM: 0x100D,
EXP_CHARM: 0x100E,
SUPER_EXP_CHARM: 0x100F,
GOLDEN_EXP_CHARM: 0x1010,
AMULET_COIN: 0x1011,
ABILITY_CHARM: 0x0B12,
SHINY_CHARM: 0x0B13,
CATCHING_CHARM: 0x0B14,
ABILITY_CHARM: 0x1012,
SHINY_CHARM: 0x1013,
CATCHING_CHARM: 0x1014,
BLACK_SLUDGE: 0x0B15,
GOLDEN_BUG_NET: 0x0B16,
BLACK_SLUDGE: 0x1015,
GOLDEN_BUG_NET: 0x1016,
LURE: 0x0C01,
SUPER_LURE: 0x0C02,
MAX_LURE: 0x0C03,
LURE: 0x1101,
SUPER_LURE: 0x1102,
MAX_LURE: 0x1103,
X_ATTACK: 0x0D01,
X_DEFENSE: 0x0D02,
X_SP_ATK: 0x0D03,
X_SP_DEF: 0x0D04,
X_SPEED: 0x0D05,
X_ACCURACY: 0x0D06,
DIRE_HIT: 0x0D07,
X_ATTACK: 0x1201,
X_DEFENSE: 0x1202,
X_SP_ATK: 0x1203,
X_SP_DEF: 0x1204,
X_SPEED: 0x1205,
X_ACCURACY: 0x1206,
DIRE_HIT: 0x1207,
ENEMY_DAMAGE_BOOSTER: 0x0E01,
ENEMY_DAMAGE_REDUCTION: 0x0E02,
ENEMY_HEAL: 0x0E03,
ENEMY_ATTACK_POISON_CHANCE: 0x0E04,
ENEMY_ATTACK_PARALYZE_CHANCE: 0x0E05,
ENEMY_ATTACK_BURN_CHANCE: 0x0E06,
ENEMY_STATUS_EFFECT_HEAL_CHANCE: 0x0E07,
ENEMY_ENDURE_CHANCE: 0x0E08,
ENEMY_FUSED_CHANCE: 0x0E09,
ENEMY_DAMAGE_BOOSTER: 0x1301,
ENEMY_DAMAGE_REDUCTION: 0x1302,
ENEMY_HEAL: 0x1303,
ENEMY_ATTACK_POISON_CHANCE: 0x1304,
ENEMY_ATTACK_PARALYZE_CHANCE: 0x1305,
ENEMY_ATTACK_BURN_CHANCE: 0x1306,
ENEMY_STATUS_EFFECT_HEAL_CHANCE: 0x1307,
ENEMY_ENDURE_CHANCE: 0x1308,
ENEMY_FUSED_CHANCE: 0x1309,
} as const;
export type TrainerItemId = (typeof TrainerItemId)[keyof typeof TrainerItemId];

View File

@ -5,7 +5,7 @@ export enum UiMode {
FIGHT,
BALL,
TARGET_SELECT,
MODIFIER_SELECT,
REWARD_SELECT,
SAVE_SLOT,
PARTY,
SUMMARY,

View File

@ -19,6 +19,7 @@ import { ArenaTagSide } from "#enums/arena-tag-side";
import type { ArenaTagType } from "#enums/arena-tag-type";
import type { BattlerIndex } from "#enums/battler-index";
import { BiomeId } from "#enums/biome-id";
import { HeldItemEffect } from "#enums/held-item-effect";
import { CommonAnim } from "#enums/move-anims-common";
import type { MoveId } from "#enums/move-id";
import type { PokemonType } from "#enums/pokemon-type";
@ -29,7 +30,6 @@ import { WeatherType } from "#enums/weather-type";
import { TagAddedEvent, TagRemovedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#events/arena";
import type { Pokemon } from "#field/pokemon";
import { applyHeldItems } from "#items/all-held-items";
import { HeldItemEffect } from "#items/held-item";
import type { Move } from "#moves/move";
import type { AbstractConstructor } from "#types/type-helpers";
import { type Constructor, isNullOrUndefined, NumberHolder, randSeedInt } from "#utils/common";

View File

@ -80,6 +80,7 @@ import { ChallengeType } from "#enums/challenge-type";
import { Challenges } from "#enums/challenges";
import { DexAttr } from "#enums/dex-attr";
import { FieldPosition } from "#enums/field-position";
import { HeldItemEffect } from "#enums/held-item-effect";
import { HeldItemId } from "#enums/held-item-id";
import { HitResult } from "#enums/hit-result";
import { LearnMoveSituation } from "#enums/learn-move-situation";
@ -92,7 +93,7 @@ import { Nature } from "#enums/nature";
import { PokeballType } from "#enums/pokeball";
import { PokemonAnimType } from "#enums/pokemon-anim-type";
import { PokemonType } from "#enums/pokemon-type";
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import { SpeciesFormKey } from "#enums/species-form-key";
import { SpeciesId } from "#enums/species-id";
import {
@ -111,7 +112,6 @@ import { UiMode } from "#enums/ui-mode";
import { WeatherType } from "#enums/weather-type";
import { doShinySparkleAnim } from "#field/anims";
import { applyHeldItems } from "#items/all-held-items";
import { HeldItemEffect } from "#items/held-item";
import type { HeldItemConfiguration } from "#items/held-item-data-types";
import { HeldItemManager } from "#items/held-item-manager";
import { assignItemsFromConfiguration } from "#items/held-item-pool";
@ -2882,13 +2882,13 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
*
* The base shiny odds are {@linkcode BASE_SHINY_CHANCE} / `65536`
* @param thresholdOverride number that is divided by `2^16` (`65536`) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm)
* @param applyModifiersToOverride If {@linkcode thresholdOverride} is set and this is true, will apply Shiny Charm and event modifiers to {@linkcode thresholdOverride}
* @param applyItemsToOverride If {@linkcode thresholdOverride} is set and this is true, will apply Shiny Charm and event modifiers to {@linkcode thresholdOverride}
* @returns `true` if the Pokemon has been set as a shiny, `false` otherwise
*/
public trySetShinySeed(thresholdOverride?: number, applyModifiersToOverride?: boolean): boolean {
public trySetShinySeed(thresholdOverride?: number, applyItemsToOverride?: boolean): boolean {
if (!this.shiny) {
const shinyThreshold = new NumberHolder(thresholdOverride ?? BASE_SHINY_CHANCE);
if (applyModifiersToOverride) {
if (applyItemsToOverride) {
if (timedEventManager.isEventActive()) {
shinyThreshold.value *= timedEventManager.getShinyMultiplier();
}
@ -2954,15 +2954,15 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
*
* The base hidden ability odds are {@linkcode BASE_HIDDEN_ABILITY_CHANCE} / `65536`
* @param thresholdOverride number that is divided by `2^16` (`65536`) to get the HA chance, overrides {@linkcode haThreshold} if set (bypassing HA rate modifiers such as Ability Charm)
* @param applyModifiersToOverride If {@linkcode thresholdOverride} is set and this is true, will apply Ability Charm to {@linkcode thresholdOverride}
* @param applyItemsToOverride If {@linkcode thresholdOverride} is set and this is true, will apply Ability Charm to {@linkcode thresholdOverride}
* @returns `true` if the Pokemon has been set to have its hidden ability, `false` otherwise
*/
public tryRerollHiddenAbilitySeed(thresholdOverride?: number, applyModifiersToOverride?: boolean): boolean {
public tryRerollHiddenAbilitySeed(thresholdOverride?: number, applyItemsToOverride?: boolean): boolean {
if (!this.species.abilityHidden) {
return false;
}
const haThreshold = new NumberHolder(thresholdOverride ?? BASE_HIDDEN_ABILITY_CHANCE);
if (applyModifiersToOverride) {
if (applyItemsToOverride) {
if (!this.hasTrainer()) {
globalScene.applyPlayerItems(TrainerItemEffect.HIDDEN_ABILITY_CHANCE_BOOSTER, { numberHolder: haThreshold });
}
@ -3108,11 +3108,11 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
}
}
if (compatible && !movePool.some(m => m[0] === moveId) && !allMoves[moveId].name.endsWith(" (N)")) {
if (tmPoolTiers[moveId] === RewardTier.COMMON && this.level >= 15) {
if (tmPoolTiers[moveId] === RarityTier.COMMON && this.level >= 15) {
movePool.push([moveId, 4]);
} else if (tmPoolTiers[moveId] === RewardTier.GREAT && this.level >= 30) {
} else if (tmPoolTiers[moveId] === RarityTier.GREAT && this.level >= 30) {
movePool.push([moveId, 8]);
} else if (tmPoolTiers[moveId] === RewardTier.ULTRA && this.level >= 50) {
} else if (tmPoolTiers[moveId] === RarityTier.ULTRA && this.level >= 50) {
movePool.push([moveId, 14]);
}
}

View File

@ -634,7 +634,7 @@ export class Trainer extends Phaser.GameObjects.Container {
return maxScorePartyMemberIndexes[0];
}
getPartyMemberModifierChanceMultiplier(index: number): number {
getPartyMemberItemChanceMultiplier(index: number): number {
switch (this.getPartyTemplate().getStrength(index)) {
case PartyMemberStrength.WEAKER:
return 0.75;
@ -647,14 +647,14 @@ export class Trainer extends Phaser.GameObjects.Container {
case PartyMemberStrength.STRONGER:
return 0.375;
default:
console.warn("getPartyMemberModifierChanceMultiplier not defined. Using default 0");
console.warn("getPartyMemberItemChanceMultiplier not defined. Using default 0");
return 0;
}
}
genTrainerItems(party: EnemyPokemon[]): TrainerItemConfiguration {
if (this.config.genModifiersFunc) {
return this.config.genModifiersFunc(party);
if (this.config.genTrainerItemsFunc) {
return this.config.genTrainerItemsFunc(party);
}
return [];
}

View File

@ -323,7 +323,7 @@ export class GameMode implements GameModeConfig {
}
}
getEnemyModifierChance(isBoss: boolean): number {
getEnemyItemChance(isBoss: boolean): number {
switch (this.modeId) {
case GameModes.CLASSIC:
case GameModes.CHALLENGE:

View File

@ -24,7 +24,6 @@ import { ExpBoosterHeldItem, type ExpBoostParams } from "#items/exp-booster";
import { FieldEffectHeldItem, type FieldEffectParams } from "#items/field-effect";
import { FlinchChanceHeldItem, type FlinchChanceParams } from "#items/flinch-chance";
import { FriendshipBoosterHeldItem, type FriendshipBoostParams } from "#items/friendship-booster";
import { HeldItemEffect } from "#items/held-item";
import { HitHealHeldItem, type HitHealParams } from "#items/hit-heal";
import { IncrementingStatHeldItem, type IncrementingStatParams } from "#items/incrementing-stat";
import { InstantReviveHeldItem, type InstantReviveParams } from "#items/instant-revive";
@ -36,7 +35,8 @@ import { EvolutionStatBoostHeldItem, SpeciesStatBoostHeldItem, type StatBoostPar
import { SurviveChanceHeldItem, type SurviveChanceParams } from "#items/survive-chance";
import { TurnEndHealHeldItem, type TurnEndHealParams } from "#items/turn-end-heal";
import { TurnEndStatusHeldItem, type TurnEndStatusParams } from "#items/turn-end-status";
import { getEnumValues } from "#utils/common";
import { getEnumValues } from "#utils/enums";
import { HeldItemEffect } from "./HeldItemEffect";
export function initHeldItems() {
for (const berry of getEnumValues(BerryType)) {

View File

@ -43,7 +43,7 @@ export function initTrainerItems() {
allTrainerItems[TrainerItemId.CANDY_JAR] = new LevelIncrementBoosterTrainerItem(TrainerItemId.CANDY_JAR, 99);
allTrainerItems[TrainerItemId.BERRY_POUCH] = new PreserveBerryTrainerItem(TrainerItemId.BERRY_POUCH, 3);
allTrainerItems[TrainerItemId.HEALING_CHARM] = new HealingBoosterTrainerItem(TrainerItemId.HEALING_CHARM, 1.1, 5);
allTrainerItems[TrainerItemId.HEALING_CHARM] = new HealingBoosterTrainerItem(TrainerItemId.HEALING_CHARM, 0.1, 5);
allTrainerItems[TrainerItemId.EXP_CHARM] = new ExpBoosterTrainerItem(TrainerItemId.EXP_CHARM, 25, 99);
allTrainerItems[TrainerItemId.SUPER_EXP_CHARM] = new ExpBoosterTrainerItem(TrainerItemId.SUPER_EXP_CHARM, 60, 30);
allTrainerItems[TrainerItemId.GOLDEN_EXP_CHARM] = new ExpBoosterTrainerItem(TrainerItemId.GOLDEN_EXP_CHARM, 100, 10);

View File

@ -1,13 +1,21 @@
// TODO: move to `src/@types/`
// TODO: move all types to `src/@types/` and all functions to a utility place
import type { FormChangeItem } from "#enums/form-change-item";
import type { HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
import type { RewardTier } from "#enums/reward-tier";
import type { RarityTier } from "#enums/reward-tier";
import type { Pokemon } from "#field/pokemon";
export type HeldItemData = {
stack: number;
/**
* Whether this item is currently disabled.
* @defaultValue `false`
*/
disabled?: boolean;
/**
* The item's current cooldown.
* @defaultValue `0`
*/
cooldown?: number;
};
@ -67,7 +75,7 @@ export function isHeldItemPool(value: any): value is HeldItemPool {
}
export type HeldItemTieredPool = {
[key in RewardTier]?: HeldItemPool;
[key in RarityTier]?: HeldItemPool;
};
type HeldItemConfigurationEntry = {

View File

@ -0,0 +1,47 @@
import { getHeldItemCategory, HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
import { RarityTier } from "#enums/reward-tier";
export const heldItemRarities = {
[HeldItemCategoryId.BERRY]: RarityTier.COMMON,
[HeldItemCategoryId.BASE_STAT_BOOST]: RarityTier.GREAT,
[HeldItemId.WHITE_HERB]: RarityTier.GREAT,
[HeldItemId.METAL_POWDER]: RarityTier.GREAT,
[HeldItemId.QUICK_POWDER]: RarityTier.GREAT,
[HeldItemId.DEEP_SEA_SCALE]: RarityTier.GREAT,
[HeldItemId.DEEP_SEA_TOOTH]: RarityTier.GREAT,
[HeldItemId.SOOTHE_BELL]: RarityTier.GREAT,
[HeldItemCategoryId.TYPE_ATTACK_BOOSTER]: RarityTier.ULTRA,
[HeldItemId.REVIVER_SEED]: RarityTier.ULTRA,
[HeldItemId.LIGHT_BALL]: RarityTier.ULTRA,
[HeldItemId.EVIOLITE]: RarityTier.ULTRA,
[HeldItemId.QUICK_CLAW]: RarityTier.ULTRA,
[HeldItemId.MYSTICAL_ROCK]: RarityTier.ULTRA,
[HeldItemId.WIDE_LENS]: RarityTier.ULTRA,
[HeldItemId.GOLDEN_PUNCH]: RarityTier.ULTRA,
[HeldItemId.TOXIC_ORB]: RarityTier.ULTRA,
[HeldItemId.FLAME_ORB]: RarityTier.ULTRA,
[HeldItemId.LUCKY_EGG]: RarityTier.ULTRA,
[HeldItemId.FOCUS_BAND]: RarityTier.ROGUE,
[HeldItemId.KINGS_ROCK]: RarityTier.ROGUE,
[HeldItemId.LEFTOVERS]: RarityTier.ROGUE,
[HeldItemId.SHELL_BELL]: RarityTier.ROGUE,
[HeldItemId.GRIP_CLAW]: RarityTier.ROGUE,
[HeldItemId.SOUL_DEW]: RarityTier.ROGUE,
[HeldItemId.BATON]: RarityTier.ROGUE,
[HeldItemId.GOLDEN_EGG]: RarityTier.ULTRA,
[HeldItemId.MINI_BLACK_HOLE]: RarityTier.MASTER,
[HeldItemId.MULTI_LENS]: RarityTier.MASTER,
};
export function getHeldItemTier(item: HeldItemId): RarityTier {
let tier = heldItemRarities[item];
if (!tier) {
const category = getHeldItemCategory(item);
tier = heldItemRarities[category];
}
return tier ?? RarityTier.LUXURY;
}

View File

@ -1,9 +1,9 @@
import { allHeldItems } from "#data/data-lists";
import { BerryType } from "#enums/berry-type";
import { HeldItemCategoryId, HeldItemId, HeldItemNames, isCategoryId } from "#enums/held-item-id";
import { HeldItemPoolType } from "#enums/modifier-pool-type";
import type { PokemonType } from "#enums/pokemon-type";
import { RewardTier } from "#enums/reward-tier";
import { HeldItemPoolType } from "#enums/reward-pool-type";
import { RarityTier } from "#enums/reward-tier";
import { PERMANENT_STATS } from "#enums/stat";
import type { EnemyPokemon, PlayerPokemon, Pokemon } from "#field/pokemon";
import { attackTypeToHeldItem } from "#items/attack-type-booster";
@ -21,7 +21,8 @@ import {
isHeldItemPool,
isHeldItemSpecs,
} from "#items/held-item-data-types";
import { coerceArray, getEnumValues, isNullOrUndefined, pickWeightedIndex, randSeedInt } from "#utils/common";
import { coerceArray, isNullOrUndefined, pickWeightedIndex, randSeedInt } from "#utils/common";
import { getEnumValues } from "#utils/enums";
export const wildHeldItemPool: HeldItemTieredPool = {};
@ -34,7 +35,7 @@ export function assignDailyRunStarterHeldItems(party: PlayerPokemon[]) {
for (let m = 0; m < 3; m++) {
const tierValue = randSeedInt(64);
const tier = getDailyRewardTier(tierValue);
const tier = getDailyRarityTier(tierValue);
const item = getNewHeldItemFromPool(
getHeldItemPool(HeldItemPoolType.DAILY_STARTER)[tier] as HeldItemPool,
@ -46,20 +47,20 @@ export function assignDailyRunStarterHeldItems(party: PlayerPokemon[]) {
}
}
function getDailyRewardTier(tierValue: number): RewardTier {
function getDailyRarityTier(tierValue: number): RarityTier {
if (tierValue > 25) {
return RewardTier.COMMON;
return RarityTier.COMMON;
}
if (tierValue > 12) {
return RewardTier.GREAT;
return RarityTier.GREAT;
}
if (tierValue > 4) {
return RewardTier.ULTRA;
return RarityTier.ULTRA;
}
if (tierValue > 0) {
return RewardTier.ROGUE;
return RarityTier.ROGUE;
}
return RewardTier.MASTER;
return RarityTier.MASTER;
}
function getHeldItemPool(poolType: HeldItemPoolType): HeldItemTieredPool {
@ -101,25 +102,25 @@ export function assignEnemyHeldItemsForWave(
}
}
function getRandomTier(): RewardTier {
function getRandomTier(): RarityTier {
const tierValue = randSeedInt(1024);
if (tierValue > 255) {
return RewardTier.COMMON;
return RarityTier.COMMON;
}
if (tierValue > 60) {
return RewardTier.GREAT;
return RarityTier.GREAT;
}
if (tierValue > 12) {
return RewardTier.ULTRA;
return RarityTier.ULTRA;
}
if (tierValue) {
return RewardTier.ROGUE;
return RarityTier.ROGUE;
}
return RewardTier.MASTER;
return RarityTier.MASTER;
}
function determineItemPoolTier(pool: HeldItemTieredPool, upgradeCount?: number): RewardTier {
function determineItemPoolTier(pool: HeldItemTieredPool, upgradeCount?: number): RarityTier {
let tier = getRandomTier();
if (!upgradeCount) {

View File

@ -1,47 +0,0 @@
import { getHeldItemCategory, HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
import { RewardTier } from "#enums/reward-tier";
export const heldItemTiers = {
[HeldItemCategoryId.BERRY]: RewardTier.COMMON,
[HeldItemCategoryId.BASE_STAT_BOOST]: RewardTier.GREAT,
[HeldItemId.WHITE_HERB]: RewardTier.GREAT,
[HeldItemId.METAL_POWDER]: RewardTier.GREAT,
[HeldItemId.QUICK_POWDER]: RewardTier.GREAT,
[HeldItemId.DEEP_SEA_SCALE]: RewardTier.GREAT,
[HeldItemId.DEEP_SEA_TOOTH]: RewardTier.GREAT,
[HeldItemId.SOOTHE_BELL]: RewardTier.GREAT,
[HeldItemCategoryId.TYPE_ATTACK_BOOSTER]: RewardTier.ULTRA,
[HeldItemId.REVIVER_SEED]: RewardTier.ULTRA,
[HeldItemId.LIGHT_BALL]: RewardTier.ULTRA,
[HeldItemId.EVIOLITE]: RewardTier.ULTRA,
[HeldItemId.QUICK_CLAW]: RewardTier.ULTRA,
[HeldItemId.MYSTICAL_ROCK]: RewardTier.ULTRA,
[HeldItemId.WIDE_LENS]: RewardTier.ULTRA,
[HeldItemId.GOLDEN_PUNCH]: RewardTier.ULTRA,
[HeldItemId.TOXIC_ORB]: RewardTier.ULTRA,
[HeldItemId.FLAME_ORB]: RewardTier.ULTRA,
[HeldItemId.LUCKY_EGG]: RewardTier.ULTRA,
[HeldItemId.FOCUS_BAND]: RewardTier.ROGUE,
[HeldItemId.KINGS_ROCK]: RewardTier.ROGUE,
[HeldItemId.LEFTOVERS]: RewardTier.ROGUE,
[HeldItemId.SHELL_BELL]: RewardTier.ROGUE,
[HeldItemId.GRIP_CLAW]: RewardTier.ROGUE,
[HeldItemId.SOUL_DEW]: RewardTier.ROGUE,
[HeldItemId.BATON]: RewardTier.ROGUE,
[HeldItemId.GOLDEN_EGG]: RewardTier.ULTRA,
[HeldItemId.MINI_BLACK_HOLE]: RewardTier.MASTER,
[HeldItemId.MULTI_LENS]: RewardTier.MASTER,
};
export function getHeldItemTier(item: HeldItemId): RewardTier | undefined {
let tier = heldItemTiers[item];
if (!tier) {
const category = getHeldItemCategory(item);
tier = heldItemTiers[category];
}
return tier;
}

View File

@ -4,42 +4,9 @@ import { type HeldItemId, HeldItemNames } from "#enums/held-item-id";
import type { Pokemon } from "#field/pokemon";
import i18next from "i18next";
// TODO: this should be moved to its own file
export const HeldItemEffect = {
ATTACK_TYPE_BOOST: 1,
TURN_END_HEAL: 2,
HIT_HEAL: 3,
RESET_NEGATIVE_STAT_STAGE: 4,
EXP_BOOSTER: 5,
// Should we actually distinguish different berry effects?
BERRY: 6,
BASE_STAT_BOOSTER: 7,
INSTANT_REVIVE: 8,
STAT_BOOST: 9,
CRIT_BOOST: 10,
TURN_END_STATUS: 11,
SURVIVE_CHANCE: 12,
BYPASS_SPEED_CHANCE: 13,
FLINCH_CHANCE: 14,
FIELD_EFFECT: 15,
FRIENDSHIP_BOOSTER: 16,
NATURE_WEIGHT_BOOSTER: 17,
ACCURACY_BOOSTER: 18,
MULTI_HIT: 19,
DAMAGE_MONEY_REWARD: 20,
BATON: 21,
TURN_END_ITEM_STEAL: 22,
CONTACT_ITEM_STEAL_CHANCE: 23,
EVO_TRACKER: 40,
BASE_STAT_TOTAL: 50,
BASE_STAT_FLAT: 51,
INCREMENTING_STAT: 52,
} as const;
export type HeldItemEffect = (typeof HeldItemEffect)[keyof typeof HeldItemEffect];
export class HeldItem {
// public pokemonId: number;
// TODO: Should this be readonly?
public type: HeldItemId;
public readonly maxStackCount: number;
public isTransferable = true;

View File

@ -1,6 +1,7 @@
import { HeldItemEffect } from "#enums/held-item-effect";
import type { HeldItemId } from "#enums/held-item-id";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import type { NumberHolder } from "#utils/common";
export interface AccuracyBoostParams {
@ -24,17 +25,17 @@ export class AccuracyBoosterHeldItem extends HeldItem {
}
/**
* Checks if {@linkcode PokemonMoveAccuracyBoosterModifier} should be applied
* Checks if {@linkcode PokemonMoveAccuracyBoosterHeldItem} should be applied
* @param pokemon - The {@linkcode Pokemon} to apply the move accuracy boost to
* @param moveAccuracy - {@linkcode NumberHolder} holding the move accuracy boost
* @returns `true` if {@linkcode PokemonMoveAccuracyBoosterModifier} should be applied
* @returns `true` if {@linkcode PokemonMoveAccuracyBoosterHeldItem} should be applied
*/
// override shouldApply(pokemon?: Pokemon, moveAccuracy?: NumberHolder): boolean {
// return super.shouldApply(pokemon, moveAccuracy) && !!moveAccuracy;
// }
/**
* Applies {@linkcode PokemonMoveAccuracyBoosterModifier}
* Applies {@linkcode PokemonMoveAccuracyBoosterHeldItem}
*/
apply({ pokemon, moveAccuracy }: AccuracyBoostParams): true {
const stackCount = pokemon.heldItemManager.getStack(this.type);

View File

@ -1,7 +1,8 @@
import { HeldItemEffect } from "#enums/held-item-effect";
import { HeldItemId, HeldItemNames } from "#enums/held-item-id";
import { PokemonType } from "#enums/pokemon-type";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import type { NumberHolder } from "#utils/common";
import i18next from "i18next";

View File

@ -1,7 +1,8 @@
import { HeldItemEffect } from "#enums/held-item-effect";
import { HeldItemId } from "#enums/held-item-id";
import { getStatKey, type PermanentStat, Stat } from "#enums/stat";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import i18next from "i18next";
export interface BaseStatBoosterParams {
@ -11,9 +12,9 @@ export interface BaseStatBoosterParams {
baseStats: number[];
}
interface PermanentStatToHeldItemMap {
[key: number]: HeldItemId;
}
type PermanentStatToHeldItemMap = {
[key in PermanentStat]: HeldItemId;
};
export const permanentStatToHeldItem: PermanentStatToHeldItemMap = {
[Stat.HP]: HeldItemId.HP_UP,

View File

@ -1,6 +1,7 @@
import { HeldItemEffect } from "#enums/held-item-effect";
import { Stat } from "#enums/stat";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import i18next from "i18next";
export interface BaseStatFlatParams {

View File

@ -1,6 +1,7 @@
import { HeldItemEffect } from "#enums/held-item-effect";
import type { HeldItemId } from "#enums/held-item-id";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import i18next from "i18next";
export interface BaseStatTotalParams {

View File

@ -1,5 +1,6 @@
import { HeldItemEffect } from "#enums/held-item-effect";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import type { NumberHolder } from "#utils/common";
export interface BatonParams {

View File

@ -1,18 +1,21 @@
import { globalScene } from "#app/global-scene";
import { getBerryEffectDescription, getBerryEffectFunc, getBerryName, getBerryPredicate } from "#data/berry";
import { BerryType } from "#enums/berry-type";
import { HeldItemEffect } from "#enums/held-item-effect";
import { HeldItemId } from "#enums/held-item-id";
import { BerryUsedEvent } from "#events/battle-scene";
import type { Pokemon } from "#field/pokemon";
import { ConsumableHeldItem, HeldItemEffect } from "#items/held-item";
import { ConsumableHeldItem } from "#items/held-item";
import { TrainerItemEffect } from "#items/trainer-item";
import type { EnumValues } from "#types/enum-types";
import { BooleanHolder } from "#utils/common";
interface BerryTypeToHeldItemMap {
[key: number]: HeldItemId;
}
type BerryTypeToHeldItemMap = {
[key in EnumValues<typeof BerryType>]: HeldItemId;
};
export const berryTypeToHeldItem: BerryTypeToHeldItemMap = {
// TODO: Rework this to use a bitwise XOR
export const berryTypeToHeldItem = {
[BerryType.SITRUS]: HeldItemId.SITRUS_BERRY,
[BerryType.LUM]: HeldItemId.LUM_BERRY,
[BerryType.ENIGMA]: HeldItemId.ENIGMA_BERRY,
@ -24,7 +27,7 @@ export const berryTypeToHeldItem: BerryTypeToHeldItemMap = {
[BerryType.LANSAT]: HeldItemId.LANSAT_BERRY,
[BerryType.STARF]: HeldItemId.STARF_BERRY,
[BerryType.LEPPA]: HeldItemId.LEPPA_BERRY,
};
} satisfies BerryTypeToHeldItemMap;
export interface BerryParams {
/** The pokemon with the berry */

View File

@ -1,8 +1,9 @@
import { globalScene } from "#app/global-scene";
import { getPokemonNameWithAffix } from "#app/messages";
import { Command } from "#enums/command";
import { HeldItemEffect } from "#enums/held-item-effect";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import type { BooleanHolder } from "#utils/common";
import i18next from "i18next";

View File

@ -1,7 +1,8 @@
import { HeldItemEffect } from "#enums/held-item-effect";
import type { HeldItemId } from "#enums/held-item-id";
import type { SpeciesId } from "#enums/species-id";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import type { NumberHolder } from "#utils/common";
export interface CritBoostParams {

View File

@ -1,6 +1,7 @@
import { globalScene } from "#app/global-scene";
import { HeldItemEffect } from "#enums/held-item-effect";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import { TrainerItemEffect } from "#items/trainer-item";
import { NumberHolder } from "#utils/common";

View File

@ -1,9 +1,10 @@
import { globalScene } from "#app/global-scene";
import { HeldItemEffect } from "#enums/held-item-effect";
import { HeldItemId } from "#enums/held-item-id";
import type { SpeciesId } from "#enums/species-id";
import { TrainerItemId } from "#enums/trainer-item-id";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import i18next from "i18next";
export interface EvoTrackerParams {

View File

@ -1,6 +1,7 @@
import { HeldItemEffect } from "#enums/held-item-effect";
import type { HeldItemId } from "#enums/held-item-id";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import type { NumberHolder } from "#utils/common";
import i18next from "i18next";

View File

@ -1,5 +1,6 @@
import { HeldItemEffect } from "#enums/held-item-effect";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import type { NumberHolder } from "#utils/common";
export interface FieldEffectParams {

View File

@ -1,6 +1,7 @@
import { HeldItemEffect } from "#enums/held-item-effect";
import type { HeldItemId } from "#enums/held-item-id";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import type { BooleanHolder } from "#utils/common";
export interface FlinchChanceParams {

View File

@ -1,5 +1,6 @@
import { HeldItemEffect } from "#enums/held-item-effect";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import type { NumberHolder } from "#utils/common";
import i18next from "i18next";

View File

@ -1,7 +1,8 @@
import { globalScene } from "#app/global-scene";
import { getPokemonNameWithAffix } from "#app/messages";
import { HeldItemEffect } from "#enums/held-item-effect";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import { PokemonHealPhase } from "#phases/pokemon-heal-phase";
import { toDmgValue } from "#utils/common";
import i18next from "i18next";

View File

@ -1,6 +1,7 @@
import { HeldItemEffect } from "#enums/held-item-effect";
import { Stat } from "#enums/stat";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import type { NumberHolder } from "#utils/common";
import i18next from "i18next";

View File

@ -1,8 +1,9 @@
import { applyAbAttrs } from "#abilities/apply-ab-attrs";
import { globalScene } from "#app/global-scene";
import { getPokemonNameWithAffix } from "#app/messages";
import { HeldItemEffect } from "#enums/held-item-effect";
import type { Pokemon } from "#field/pokemon";
import { ConsumableHeldItem, HeldItemEffect } from "#items/held-item";
import { ConsumableHeldItem } from "#items/held-item";
import { PokemonHealPhase } from "#phases/pokemon-heal-phase";
import { toDmgValue } from "#utils/common";
import i18next from "i18next";

View File

@ -1,9 +1,10 @@
import { globalScene } from "#app/global-scene";
import { getPokemonNameWithAffix } from "#app/messages";
import { allHeldItems } from "#data/data-lists";
import { HeldItemEffect } from "#enums/held-item-effect";
import type { HeldItemId } from "#enums/held-item-id";
import { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import { coerceArray, randSeedFloat } from "#utils/common";
import i18next from "i18next";
@ -47,7 +48,7 @@ export abstract class ItemTransferHeldItem extends HeldItem {
}
// TODO: Change this logic to use held items
const transferredModifierTypes: HeldItemId[] = [];
const transferredRewards: HeldItemId[] = [];
const heldItems = targetPokemon.heldItemManager.getTransferableHeldItems();
for (let i = 0; i < transferredItemCount; i++) {
@ -58,16 +59,16 @@ export abstract class ItemTransferHeldItem extends HeldItem {
const randItem = heldItems[randItemIndex];
// TODO: Fix this after updating the various methods in battle-scene.ts
if (globalScene.tryTransferHeldItem(randItem, targetPokemon, pokemon, false)) {
transferredModifierTypes.push(randItem);
transferredRewards.push(randItem);
heldItems.splice(randItemIndex, 1);
}
}
for (const mt of transferredModifierTypes) {
for (const mt of transferredRewards) {
globalScene.phaseManager.queueMessage(this.getTransferMessage(params, mt));
}
return !!transferredModifierTypes.length;
return !!transferredRewards.length;
}
abstract getTargets(params: ItemStealParams): Pokemon[];
@ -80,7 +81,7 @@ export abstract class ItemTransferHeldItem extends HeldItem {
/**
* Modifier for held items that steal items from the enemy at the end of
* each turn.
* @see {@linkcode modifierTypes[MINI_BLACK_HOLE]}
* @see {@linkcode allRewards[MINI_BLACK_HOLE]}
*/
export class TurnEndItemStealHeldItem extends ItemTransferHeldItem {
public effects: HeldItemEffect[] = [HeldItemEffect.TURN_END_ITEM_STEAL];
@ -121,7 +122,7 @@ export class TurnEndItemStealHeldItem extends ItemTransferHeldItem {
/**
* Modifier for held items that add a chance to steal items from the target of a
* successful attack.
* @see {@linkcode modifierTypes[GRIP_CLAW]}
* @see {@linkcode allRewards[GRIP_CLAW]}
* @see {@linkcode HeldItemTransferModifier}
*/
export class ContactItemStealChanceHeldItem extends ItemTransferHeldItem {

View File

@ -1,7 +1,8 @@
import { allMoves } from "#data/data-lists";
import { HeldItemEffect } from "#enums/held-item-effect";
import type { MoveId } from "#enums/move-id";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import { isNullOrUndefined, type NumberHolder } from "#utils/common";
import i18next from "i18next";

View File

@ -1,5 +1,6 @@
import { HeldItemEffect } from "#enums/held-item-effect";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import type { NumberHolder } from "#utils/common";
export interface NatureWeightBoostParams {

View File

@ -1,8 +1,9 @@
import { globalScene } from "#app/global-scene";
import { getPokemonNameWithAffix } from "#app/messages";
import { HeldItemEffect } from "#enums/held-item-effect";
import { BATTLE_STATS } from "#enums/stat";
import type { Pokemon } from "#field/pokemon";
import { ConsumableHeldItem, HeldItemEffect } from "#items/held-item";
import { ConsumableHeldItem } from "#items/held-item";
import i18next from "i18next";
export interface ResetNegativeStatStageParams {

View File

@ -1,9 +1,10 @@
import { pokemonEvolutions } from "#balance/pokemon-evolutions";
import { HeldItemEffect } from "#enums/held-item-effect";
import { HeldItemId } from "#enums/held-item-id";
import type { SpeciesId } from "#enums/species-id";
import type { Stat } from "#enums/stat";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import type { NumberHolder } from "#utils/common";
export interface StatBoostParams {

View File

@ -1,7 +1,8 @@
import { globalScene } from "#app/global-scene";
import { getPokemonNameWithAffix } from "#app/messages";
import { HeldItemEffect } from "#enums/held-item-effect";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import type { BooleanHolder } from "#utils/common";
import i18next from "i18next";

View File

@ -1,7 +1,8 @@
import { globalScene } from "#app/global-scene";
import { getPokemonNameWithAffix } from "#app/messages";
import { HeldItemEffect } from "#enums/held-item-effect";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
import { PokemonHealPhase } from "#phases/pokemon-heal-phase";
import { toDmgValue } from "#utils/common";
import i18next from "i18next";

View File

@ -1,7 +1,8 @@
import { HeldItemEffect } from "#enums/held-item-effect";
import type { HeldItemId } from "#enums/held-item-id";
import type { StatusEffect } from "#enums/status-effect";
import type { Pokemon } from "#field/pokemon";
import { HeldItem, HeldItemEffect } from "#items/held-item";
import { HeldItem } from "#items/held-item";
export interface TurnEndStatusParams {
/** The pokemon with the item */

View File

@ -1,42 +1,42 @@
import { HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import { dailyStarterHeldItemPool, trainerHeldItemPool, wildHeldItemPool } from "#items/held-item-pool";
/**
* Initialize the wild held item pool
*/
function initWildHeldItemPool() {
wildHeldItemPool[RewardTier.COMMON] = [{ entry: HeldItemCategoryId.BERRY, weight: 1 }];
wildHeldItemPool[RewardTier.GREAT] = [{ entry: HeldItemCategoryId.BASE_STAT_BOOST, weight: 1 }];
wildHeldItemPool[RewardTier.ULTRA] = [
wildHeldItemPool[RarityTier.COMMON] = [{ entry: HeldItemCategoryId.BERRY, weight: 1 }];
wildHeldItemPool[RarityTier.GREAT] = [{ entry: HeldItemCategoryId.BASE_STAT_BOOST, weight: 1 }];
wildHeldItemPool[RarityTier.ULTRA] = [
{ entry: HeldItemCategoryId.TYPE_ATTACK_BOOSTER, weight: 5 },
{ entry: HeldItemId.WHITE_HERB, weight: 0 },
];
wildHeldItemPool[RewardTier.ROGUE] = [{ entry: HeldItemId.LUCKY_EGG, weight: 4 }];
wildHeldItemPool[RewardTier.MASTER] = [{ entry: HeldItemId.GOLDEN_EGG, weight: 1 }];
wildHeldItemPool[RarityTier.ROGUE] = [{ entry: HeldItemId.LUCKY_EGG, weight: 4 }];
wildHeldItemPool[RarityTier.MASTER] = [{ entry: HeldItemId.GOLDEN_EGG, weight: 1 }];
}
/**
* Initialize the trainer pokemon held item pool
*/
function initTrainerHeldItemPool() {
trainerHeldItemPool[RewardTier.COMMON] = [
trainerHeldItemPool[RarityTier.COMMON] = [
{ entry: HeldItemCategoryId.BERRY, weight: 8 },
{ entry: HeldItemCategoryId.BASE_STAT_BOOST, weight: 3 },
];
trainerHeldItemPool[RewardTier.GREAT] = [{ entry: HeldItemCategoryId.BASE_STAT_BOOST, weight: 3 }];
trainerHeldItemPool[RewardTier.ULTRA] = [
trainerHeldItemPool[RarityTier.GREAT] = [{ entry: HeldItemCategoryId.BASE_STAT_BOOST, weight: 3 }];
trainerHeldItemPool[RarityTier.ULTRA] = [
{ entry: HeldItemCategoryId.TYPE_ATTACK_BOOSTER, weight: 10 },
{ entry: HeldItemId.WHITE_HERB, weight: 0 },
];
trainerHeldItemPool[RewardTier.ROGUE] = [
trainerHeldItemPool[RarityTier.ROGUE] = [
{ entry: HeldItemId.FOCUS_BAND, weight: 2 },
{ entry: HeldItemId.LUCKY_EGG, weight: 4 },
{ entry: HeldItemId.QUICK_CLAW, weight: 1 },
{ entry: HeldItemId.GRIP_CLAW, weight: 1 },
{ entry: HeldItemId.WIDE_LENS, weight: 1 },
];
trainerHeldItemPool[RewardTier.MASTER] = [
trainerHeldItemPool[RarityTier.MASTER] = [
{ entry: HeldItemId.KINGS_ROCK, weight: 1 },
{ entry: HeldItemId.LEFTOVERS, weight: 1 },
{ entry: HeldItemId.SHELL_BELL, weight: 1 },
@ -47,26 +47,26 @@ function initTrainerHeldItemPool() {
/**
* Initialize the daily starter held item pool
*/
function initDailyStarterModifierPool() {
dailyStarterHeldItemPool[RewardTier.COMMON] = [
function initDailyStarterRewardPool() {
dailyStarterHeldItemPool[RarityTier.COMMON] = [
{ entry: HeldItemCategoryId.BASE_STAT_BOOST, weight: 1 },
{ entry: HeldItemCategoryId.BERRY, weight: 3 },
];
dailyStarterHeldItemPool[RewardTier.GREAT] = [{ entry: HeldItemCategoryId.TYPE_ATTACK_BOOSTER, weight: 5 }];
dailyStarterHeldItemPool[RewardTier.ULTRA] = [
dailyStarterHeldItemPool[RarityTier.GREAT] = [{ entry: HeldItemCategoryId.TYPE_ATTACK_BOOSTER, weight: 5 }];
dailyStarterHeldItemPool[RarityTier.ULTRA] = [
{ entry: HeldItemId.REVIVER_SEED, weight: 4 },
{ entry: HeldItemId.SOOTHE_BELL, weight: 1 },
{ entry: HeldItemId.SOUL_DEW, weight: 1 },
{ entry: HeldItemId.GOLDEN_PUNCH, weight: 1 },
];
dailyStarterHeldItemPool[RewardTier.ROGUE] = [
dailyStarterHeldItemPool[RarityTier.ROGUE] = [
{ entry: HeldItemId.GRIP_CLAW, weight: 5 },
{ entry: HeldItemId.BATON, weight: 2 },
{ entry: HeldItemId.FOCUS_BAND, weight: 5 },
{ entry: HeldItemId.QUICK_CLAW, weight: 3 },
{ entry: HeldItemId.KINGS_ROCK, weight: 3 },
];
dailyStarterHeldItemPool[RewardTier.MASTER] = [
dailyStarterHeldItemPool[RarityTier.MASTER] = [
{ entry: HeldItemId.LEFTOVERS, weight: 1 },
{ entry: HeldItemId.SHELL_BELL, weight: 1 },
];
@ -76,5 +76,5 @@ export function initHeldItemPools() {
// Default held item pools for specific scenarios
initWildHeldItemPool();
initTrainerHeldItemPool();
initDailyStarterModifierPool();
initDailyStarterRewardPool();
}

View File

@ -1,37 +1,37 @@
/* biome-ignore-start lint/correctness/noUnusedImports: tsdoc imports */
import type { initModifierTypes } from "#modifiers/modifier-type";
import type { initRewards, Reward } from "#items/reward";
/* biome-ignore-end lint/correctness/noUnusedImports: tsdoc imports */
import { timedEventManager } from "#app/global-event-manager";
import { globalScene } from "#app/global-scene";
import { pokemonEvolutions } from "#balance/pokemon-evolutions";
import { allHeldItems, allTrainerItems, modifierTypes } from "#data/data-lists";
import { allHeldItems, allRewards, allTrainerItems } from "#data/data-lists";
import { MAX_PER_TYPE_POKEBALLS } from "#data/pokeball";
import { AbilityId } from "#enums/ability-id";
import { HeldItemId } from "#enums/held-item-id";
import { MoveId } from "#enums/move-id";
import { PokeballType } from "#enums/pokeball";
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import { SpeciesId } from "#enums/species-id";
import { StatusEffect } from "#enums/status-effect";
import { TrainerItemId } from "#enums/trainer-item-id";
import { Unlockables } from "#enums/unlockables";
import type { Pokemon } from "#field/pokemon";
import { WeightedReward } from "#items/reward";
import { rewardPool } from "#items/reward-pools";
import type { TurnEndStatusHeldItem } from "#items/turn-end-status";
import { modifierPool } from "#modifiers/modifier-pools";
import { WeightedModifierType } from "#modifiers/modifier-type";
import type { WeightedModifierTypeWeightFunc } from "#types/modifier-types";
import type { WeightedRewardWeightFunc } from "#types/rewards";
import { isNullOrUndefined } from "#utils/common";
/**
* Initialize the common modifier pool
*/
function initCommonModifierPool() {
modifierPool[RewardTier.COMMON] = [
new WeightedModifierType(modifierTypes.POKEBALL, () => (hasMaximumBalls(PokeballType.POKEBALL) ? 0 : 6), 6),
new WeightedModifierType(modifierTypes.RARE_CANDY, 2),
new WeightedModifierType(
modifierTypes.POTION,
function initCommonRewardPool() {
rewardPool[RarityTier.COMMON] = [
new WeightedReward(allRewards.POKEBALL, () => (hasMaximumBalls(PokeballType.POKEBALL) ? 0 : 6), 6),
new WeightedReward(allRewards.RARE_CANDY, 2),
new WeightedReward(
allRewards.POTION,
(party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min(
party.filter(p => p.getInverseHp() >= 10 && p.getHpRatio() <= 0.875 && !p.isFainted()).length,
@ -41,8 +41,8 @@ function initCommonModifierPool() {
},
9,
),
new WeightedModifierType(
modifierTypes.SUPER_POTION,
new WeightedReward(
allRewards.SUPER_POTION,
(party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min(
party.filter(p => p.getInverseHp() >= 25 && p.getHpRatio() <= 0.75 && !p.isFainted()).length,
@ -52,8 +52,8 @@ function initCommonModifierPool() {
},
3,
),
new WeightedModifierType(
modifierTypes.ETHER,
new WeightedReward(
allRewards.ETHER,
(party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min(
party.filter(
@ -71,8 +71,8 @@ function initCommonModifierPool() {
},
9,
),
new WeightedModifierType(
modifierTypes.MAX_ETHER,
new WeightedReward(
allRewards.MAX_ETHER,
(party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min(
party.filter(
@ -90,25 +90,22 @@ function initCommonModifierPool() {
},
3,
),
new WeightedModifierType(modifierTypes.LURE, lureWeightFunc(TrainerItemId.LURE, 2)),
new WeightedModifierType(modifierTypes.TEMP_STAT_STAGE_BOOSTER, 4),
new WeightedModifierType(modifierTypes.BERRY, 2),
new WeightedModifierType(modifierTypes.TM_COMMON, 2),
].map(m => {
m.setTier(RewardTier.COMMON);
return m;
});
new WeightedReward(allRewards.LURE, lureWeightFunc(TrainerItemId.LURE, 2)),
new WeightedReward(allRewards.TEMP_STAT_STAGE_BOOSTER, 4),
new WeightedReward(allRewards.BERRY, 2),
new WeightedReward(allRewards.TM_COMMON, 2),
];
}
/**
* Initialize the Great modifier pool
*/
function initGreatModifierPool() {
modifierPool[RewardTier.GREAT] = [
new WeightedModifierType(modifierTypes.GREAT_BALL, () => (hasMaximumBalls(PokeballType.GREAT_BALL) ? 0 : 6), 6),
new WeightedModifierType(modifierTypes.PP_UP, 2),
new WeightedModifierType(
modifierTypes.FULL_HEAL,
function initGreatRewardPool() {
rewardPool[RarityTier.GREAT] = [
new WeightedReward(allRewards.GREAT_BALL, () => (hasMaximumBalls(PokeballType.GREAT_BALL) ? 0 : 6), 6),
new WeightedReward(allRewards.PP_UP, 2),
new WeightedReward(
allRewards.FULL_HEAL,
(party: Pokemon[]) => {
const statusEffectPartyMemberCount = Math.min(
party.filter(
@ -126,31 +123,31 @@ function initGreatModifierPool() {
},
18,
),
new WeightedModifierType(
modifierTypes.REVIVE,
new WeightedReward(
allRewards.REVIVE,
(party: Pokemon[]) => {
const faintedPartyMemberCount = Math.min(party.filter(p => p.isFainted()).length, 3);
return faintedPartyMemberCount * 9;
},
27,
),
new WeightedModifierType(
modifierTypes.MAX_REVIVE,
new WeightedReward(
allRewards.MAX_REVIVE,
(party: Pokemon[]) => {
const faintedPartyMemberCount = Math.min(party.filter(p => p.isFainted()).length, 3);
return faintedPartyMemberCount * 3;
},
9,
),
new WeightedModifierType(
modifierTypes.SACRED_ASH,
new WeightedReward(
allRewards.SACRED_ASH,
(party: Pokemon[]) => {
return party.filter(p => p.isFainted()).length >= Math.ceil(party.length / 2) ? 1 : 0;
},
1,
),
new WeightedModifierType(
modifierTypes.HYPER_POTION,
new WeightedReward(
allRewards.HYPER_POTION,
(party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min(
party.filter(p => p.getInverseHp() >= 100 && p.getHpRatio() <= 0.625 && !p.isFainted()).length,
@ -160,8 +157,8 @@ function initGreatModifierPool() {
},
9,
),
new WeightedModifierType(
modifierTypes.MAX_POTION,
new WeightedReward(
allRewards.MAX_POTION,
(party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min(
party.filter(p => p.getInverseHp() >= 100 && p.getHpRatio() <= 0.5 && !p.isFainted()).length,
@ -171,8 +168,8 @@ function initGreatModifierPool() {
},
3,
),
new WeightedModifierType(
modifierTypes.FULL_RESTORE,
new WeightedReward(
allRewards.FULL_RESTORE,
(party: Pokemon[]) => {
const statusEffectPartyMemberCount = Math.min(
party.filter(
@ -195,8 +192,8 @@ function initGreatModifierPool() {
},
3,
),
new WeightedModifierType(
modifierTypes.ELIXIR,
new WeightedReward(
allRewards.ELIXIR,
(party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min(
party.filter(
@ -214,8 +211,8 @@ function initGreatModifierPool() {
},
9,
),
new WeightedModifierType(
modifierTypes.MAX_ELIXIR,
new WeightedReward(
allRewards.MAX_ELIXIR,
(party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min(
party.filter(
@ -233,26 +230,26 @@ function initGreatModifierPool() {
},
3,
),
new WeightedModifierType(modifierTypes.DIRE_HIT, 4),
new WeightedModifierType(modifierTypes.SUPER_LURE, lureWeightFunc(TrainerItemId.SUPER_LURE, 4)),
new WeightedModifierType(modifierTypes.NUGGET, skipInLastClassicWaveOrDefault(5)),
new WeightedModifierType(modifierTypes.SPECIES_STAT_BOOSTER, 4),
new WeightedModifierType(
modifierTypes.EVOLUTION_ITEM,
new WeightedReward(allRewards.DIRE_HIT, 4),
new WeightedReward(allRewards.SUPER_LURE, lureWeightFunc(TrainerItemId.SUPER_LURE, 4)),
new WeightedReward(allRewards.NUGGET, skipInLastClassicWaveOrDefault(5)),
new WeightedReward(allRewards.SPECIES_STAT_BOOSTER, 4),
new WeightedReward(
allRewards.EVOLUTION_ITEM,
() => {
return Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 15), 8);
},
8,
),
new WeightedModifierType(
modifierTypes.MAP,
new WeightedReward(
allRewards.MAP,
() => (globalScene.gameMode.isClassic && globalScene.currentBattle.waveIndex < 180 ? 2 : 0),
2,
),
new WeightedModifierType(modifierTypes.SOOTHE_BELL, 2),
new WeightedModifierType(modifierTypes.TM_GREAT, 3),
new WeightedModifierType(
modifierTypes.MEMORY_MUSHROOM,
new WeightedReward(allRewards.SOOTHE_BELL, 2),
new WeightedReward(allRewards.TM_GREAT, 3),
new WeightedReward(
allRewards.MEMORY_MUSHROOM,
(party: Pokemon[]) => {
if (!party.find(p => p.getLearnableLevelMoves().length)) {
return 0;
@ -264,8 +261,8 @@ function initGreatModifierPool() {
},
4,
),
new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 3),
new WeightedModifierType(modifierTypes.TERA_SHARD, (party: Pokemon[]) =>
new WeightedReward(allRewards.BASE_STAT_BOOSTER, 3),
new WeightedReward(allRewards.TERA_SHARD, (party: Pokemon[]) =>
party.filter(
p =>
!(p.hasSpecies(SpeciesId.TERAPAGOS) || p.hasSpecies(SpeciesId.OGERPON) || p.hasSpecies(SpeciesId.SHEDINJA)),
@ -273,8 +270,8 @@ function initGreatModifierPool() {
? 1
: 0,
),
new WeightedModifierType(
modifierTypes.DNA_SPLICERS,
new WeightedReward(
allRewards.DNA_SPLICERS,
(party: Pokemon[]) => {
if (party.filter(p => !p.fusionSpecies).length > 1) {
if (globalScene.gameMode.isSplicedOnly) {
@ -288,39 +285,36 @@ function initGreatModifierPool() {
},
4,
),
new WeightedModifierType(
modifierTypes.VOUCHER,
new WeightedReward(
allRewards.VOUCHER,
(_party: Pokemon[], rerollCount: number) => (!globalScene.gameMode.isDaily ? Math.max(1 - rerollCount, 0) : 0),
1,
),
].map(m => {
m.setTier(RewardTier.GREAT);
return m;
});
];
}
/**
* Initialize the Ultra modifier pool
*/
function initUltraModifierPool() {
modifierPool[RewardTier.ULTRA] = [
new WeightedModifierType(modifierTypes.ULTRA_BALL, () => (hasMaximumBalls(PokeballType.ULTRA_BALL) ? 0 : 15), 15),
new WeightedModifierType(modifierTypes.MAX_LURE, lureWeightFunc(TrainerItemId.MAX_LURE, 4)),
new WeightedModifierType(modifierTypes.BIG_NUGGET, skipInLastClassicWaveOrDefault(12)),
new WeightedModifierType(modifierTypes.PP_MAX, 3),
new WeightedModifierType(modifierTypes.MINT, 4),
new WeightedModifierType(
modifierTypes.RARE_EVOLUTION_ITEM,
function initUltraRewardPool() {
rewardPool[RarityTier.ULTRA] = [
new WeightedReward(allRewards.ULTRA_BALL, () => (hasMaximumBalls(PokeballType.ULTRA_BALL) ? 0 : 15), 15),
new WeightedReward(allRewards.MAX_LURE, lureWeightFunc(TrainerItemId.MAX_LURE, 4)),
new WeightedReward(allRewards.BIG_NUGGET, skipInLastClassicWaveOrDefault(12)),
new WeightedReward(allRewards.PP_MAX, 3),
new WeightedReward(allRewards.MINT, 4),
new WeightedReward(
allRewards.RARE_EVOLUTION_ITEM,
() => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 15) * 4, 32),
32,
),
new WeightedModifierType(
modifierTypes.FORM_CHANGE_ITEM,
new WeightedReward(
allRewards.FORM_CHANGE_ITEM,
() => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 6,
24,
),
new WeightedModifierType(modifierTypes.AMULET_COIN, skipInLastClassicWaveOrDefault(3)),
new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => {
new WeightedReward(allRewards.AMULET_COIN, skipInLastClassicWaveOrDefault(3)),
new WeightedReward(allRewards.EVIOLITE, (party: Pokemon[]) => {
const { gameMode, gameData } = globalScene;
if (gameMode.isDaily || (!gameMode.isFreshStartChallenge() && gameData.isUnlocked(Unlockables.EVIOLITE))) {
return party.some(p => {
@ -340,9 +334,9 @@ function initUltraModifierPool() {
}
return 0;
}),
new WeightedModifierType(modifierTypes.RARE_SPECIES_STAT_BOOSTER, 12),
new WeightedModifierType(
modifierTypes.LEEK,
new WeightedReward(allRewards.RARE_SPECIES_STAT_BOOSTER, 12),
new WeightedReward(
allRewards.LEEK,
(party: Pokemon[]) => {
const checkedSpecies = [SpeciesId.FARFETCHD, SpeciesId.GALAR_FARFETCHD, SpeciesId.SIRFETCHD];
// If a party member doesn't already have a Leek and is one of the relevant species, Leek can appear
@ -357,8 +351,8 @@ function initUltraModifierPool() {
},
12,
),
new WeightedModifierType(
modifierTypes.TOXIC_ORB,
new WeightedReward(
allRewards.TOXIC_ORB,
(party: Pokemon[]) => {
return party.some(p => {
const isHoldingOrb = p.getHeldItems().some(i => i in [HeldItemId.FLAME_ORB, HeldItemId.TOXIC_ORB]);
@ -403,8 +397,8 @@ function initUltraModifierPool() {
},
10,
),
new WeightedModifierType(
modifierTypes.FLAME_ORB,
new WeightedReward(
allRewards.FLAME_ORB,
(party: Pokemon[]) => {
return party.some(p => {
const isHoldingOrb = p.getHeldItems().some(i => i in [HeldItemId.FLAME_ORB, HeldItemId.TOXIC_ORB]);
@ -449,8 +443,8 @@ function initUltraModifierPool() {
},
10,
),
new WeightedModifierType(
modifierTypes.MYSTICAL_ROCK,
new WeightedReward(
allRewards.MYSTICAL_ROCK,
(party: Pokemon[]) => {
return party.some(p => {
const stack = p.heldItemManager.getStack(HeldItemId.MYSTICAL_ROCK);
@ -496,94 +490,88 @@ function initUltraModifierPool() {
},
10,
),
new WeightedModifierType(modifierTypes.REVIVER_SEED, 4),
new WeightedModifierType(modifierTypes.CANDY_JAR, skipInLastClassicWaveOrDefault(5)),
new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 9),
new WeightedModifierType(modifierTypes.TM_ULTRA, 11),
new WeightedModifierType(modifierTypes.RARER_CANDY, 4),
new WeightedModifierType(modifierTypes.GOLDEN_PUNCH, skipInLastClassicWaveOrDefault(2)),
new WeightedModifierType(modifierTypes.IV_SCANNER, skipInLastClassicWaveOrDefault(4)),
new WeightedModifierType(modifierTypes.EXP_CHARM, skipInLastClassicWaveOrDefault(8)),
new WeightedModifierType(modifierTypes.EXP_SHARE, skipInLastClassicWaveOrDefault(10)),
new WeightedModifierType(
modifierTypes.TERA_ORB,
new WeightedReward(allRewards.REVIVER_SEED, 4),
new WeightedReward(allRewards.CANDY_JAR, skipInLastClassicWaveOrDefault(5)),
new WeightedReward(allRewards.ATTACK_TYPE_BOOSTER, 9),
new WeightedReward(allRewards.TM_ULTRA, 11),
new WeightedReward(allRewards.RARER_CANDY, 4),
new WeightedReward(allRewards.GOLDEN_PUNCH, skipInLastClassicWaveOrDefault(2)),
new WeightedReward(allRewards.IV_SCANNER, skipInLastClassicWaveOrDefault(4)),
new WeightedReward(allRewards.EXP_CHARM, skipInLastClassicWaveOrDefault(8)),
new WeightedReward(allRewards.EXP_SHARE, skipInLastClassicWaveOrDefault(10)),
new WeightedReward(
allRewards.TERA_ORB,
() =>
!globalScene.gameMode.isClassic
? Math.min(Math.max(Math.floor(globalScene.currentBattle.waveIndex / 50) * 2, 1), 4)
: 0,
4,
),
new WeightedModifierType(modifierTypes.QUICK_CLAW, 3),
new WeightedModifierType(modifierTypes.WIDE_LENS, 7),
].map(m => {
m.setTier(RewardTier.ULTRA);
return m;
});
new WeightedReward(allRewards.QUICK_CLAW, 3),
new WeightedReward(allRewards.WIDE_LENS, 7),
];
}
function initRogueModifierPool() {
modifierPool[RewardTier.ROGUE] = [
new WeightedModifierType(modifierTypes.ROGUE_BALL, () => (hasMaximumBalls(PokeballType.ROGUE_BALL) ? 0 : 16), 16),
new WeightedModifierType(modifierTypes.RELIC_GOLD, skipInLastClassicWaveOrDefault(2)),
new WeightedModifierType(modifierTypes.LEFTOVERS, 3),
new WeightedModifierType(modifierTypes.SHELL_BELL, 3),
new WeightedModifierType(modifierTypes.BERRY_POUCH, 4),
new WeightedModifierType(modifierTypes.GRIP_CLAW, 5),
new WeightedModifierType(modifierTypes.SCOPE_LENS, 4),
new WeightedModifierType(modifierTypes.BATON, 2),
new WeightedModifierType(modifierTypes.SOUL_DEW, 7),
new WeightedModifierType(modifierTypes.CATCHING_CHARM, () => (!globalScene.gameMode.isClassic ? 4 : 0), 4),
new WeightedModifierType(modifierTypes.ABILITY_CHARM, skipInClassicAfterWave(189, 6)),
new WeightedModifierType(modifierTypes.FOCUS_BAND, 5),
new WeightedModifierType(modifierTypes.KINGS_ROCK, 3),
new WeightedModifierType(modifierTypes.LOCK_CAPSULE, () => (globalScene.gameMode.isClassic ? 0 : 3)),
new WeightedModifierType(modifierTypes.SUPER_EXP_CHARM, skipInLastClassicWaveOrDefault(8)),
new WeightedModifierType(
modifierTypes.RARE_FORM_CHANGE_ITEM,
function initRogueRewardPool() {
rewardPool[RarityTier.ROGUE] = [
new WeightedReward(allRewards.ROGUE_BALL, () => (hasMaximumBalls(PokeballType.ROGUE_BALL) ? 0 : 16), 16),
new WeightedReward(allRewards.RELIC_GOLD, skipInLastClassicWaveOrDefault(2)),
new WeightedReward(allRewards.LEFTOVERS, 3),
new WeightedReward(allRewards.SHELL_BELL, 3),
new WeightedReward(allRewards.BERRY_POUCH, 4),
new WeightedReward(allRewards.GRIP_CLAW, 5),
new WeightedReward(allRewards.SCOPE_LENS, 4),
new WeightedReward(allRewards.BATON, 2),
new WeightedReward(allRewards.SOUL_DEW, 7),
new WeightedReward(allRewards.CATCHING_CHARM, () => (!globalScene.gameMode.isClassic ? 4 : 0), 4),
new WeightedReward(allRewards.ABILITY_CHARM, skipInClassicAfterWave(189, 6)),
new WeightedReward(allRewards.FOCUS_BAND, 5),
new WeightedReward(allRewards.KINGS_ROCK, 3),
new WeightedReward(allRewards.LOCK_CAPSULE, () => (globalScene.gameMode.isClassic ? 0 : 3)),
new WeightedReward(allRewards.SUPER_EXP_CHARM, skipInLastClassicWaveOrDefault(8)),
new WeightedReward(
allRewards.RARE_FORM_CHANGE_ITEM,
() => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 6,
24,
),
new WeightedModifierType(
modifierTypes.MEGA_BRACELET,
new WeightedReward(
allRewards.MEGA_BRACELET,
() => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 9,
36,
),
new WeightedModifierType(
modifierTypes.DYNAMAX_BAND,
new WeightedReward(
allRewards.DYNAMAX_BAND,
() => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 9,
36,
),
new WeightedModifierType(
modifierTypes.VOUCHER_PLUS,
new WeightedReward(
allRewards.VOUCHER_PLUS,
(_party: Pokemon[], rerollCount: number) =>
!globalScene.gameMode.isDaily ? Math.max(3 - rerollCount * 1, 0) : 0,
3,
),
].map(m => {
m.setTier(RewardTier.ROGUE);
return m;
});
];
}
/**
* Initialize the Master modifier pool
*/
function initMasterModifierPool() {
modifierPool[RewardTier.MASTER] = [
new WeightedModifierType(modifierTypes.MASTER_BALL, () => (hasMaximumBalls(PokeballType.MASTER_BALL) ? 0 : 24), 24),
new WeightedModifierType(modifierTypes.SHINY_CHARM, 14),
new WeightedModifierType(modifierTypes.HEALING_CHARM, 18),
new WeightedModifierType(modifierTypes.MULTI_LENS, 18),
new WeightedModifierType(
modifierTypes.VOUCHER_PREMIUM,
function initMasterRewardPool() {
rewardPool[RarityTier.MASTER] = [
new WeightedReward(allRewards.MASTER_BALL, () => (hasMaximumBalls(PokeballType.MASTER_BALL) ? 0 : 24), 24),
new WeightedReward(allRewards.SHINY_CHARM, 14),
new WeightedReward(allRewards.HEALING_CHARM, 18),
new WeightedReward(allRewards.MULTI_LENS, 18),
new WeightedReward(
allRewards.VOUCHER_PREMIUM,
(_party: Pokemon[], rerollCount: number) =>
!globalScene.gameMode.isDaily && !globalScene.gameMode.isEndless && !globalScene.gameMode.isSplicedOnly
? Math.max(5 - rerollCount * 2, 0)
: 0,
5,
),
new WeightedModifierType(
modifierTypes.DNA_SPLICERS,
new WeightedReward(
allRewards.DNA_SPLICERS,
(party: Pokemon[]) =>
!(globalScene.gameMode.isClassic && timedEventManager.areFusionsBoosted()) &&
!globalScene.gameMode.isSplicedOnly &&
@ -592,8 +580,8 @@ function initMasterModifierPool() {
: 0,
24,
),
new WeightedModifierType(
modifierTypes.MINI_BLACK_HOLE,
new WeightedReward(
allRewards.MINI_BLACK_HOLE,
() =>
globalScene.gameMode.isDaily ||
(!globalScene.gameMode.isFreshStartChallenge() && globalScene.gameData.isUnlocked(Unlockables.MINI_BLACK_HOLE))
@ -601,33 +589,30 @@ function initMasterModifierPool() {
: 0,
1,
),
].map(m => {
m.setTier(RewardTier.MASTER);
return m;
});
];
}
/**
* Initialize {@linkcode modifierPool} with the initial set of modifier types.
* {@linkcode initModifierTypes} MUST be called before this function.
* Initialize {@linkcode rewardPool} with the initial set of modifier types.
* {@linkcode initRewards} MUST be called before this function.
*/
export function initModifierPools() {
export function initRewardPools() {
// The modifier pools the player chooses from during modifier selection
initCommonModifierPool();
initGreatModifierPool();
initUltraModifierPool();
initRogueModifierPool();
initMasterModifierPool();
initCommonRewardPool();
initGreatRewardPool();
initUltraRewardPool();
initRogueRewardPool();
initMasterRewardPool();
}
/**
* High order function that returns a WeightedModifierTypeWeightFunc that will only be applied on
* classic and skip an ModifierType if current wave is greater or equal to the one passed down
* High order function that returns a WeightedRewardWeightFunc that will only be applied on
* classic and skip an Reward if current wave is greater or equal to the one passed down
* @param wave - Wave where we should stop showing the modifier
* @param defaultWeight - ModifierType default weight
* @returns A WeightedModifierTypeWeightFunc
* @param defaultWeight - Reward default weight
* @returns A WeightedRewardWeightFunc
*/
function skipInClassicAfterWave(wave: number, defaultWeight: number): WeightedModifierTypeWeightFunc {
function skipInClassicAfterWave(wave: number, defaultWeight: number): WeightedRewardWeightFunc {
return () => {
const gameMode = globalScene.gameMode;
const currentWave = globalScene.currentBattle.waveIndex;
@ -636,23 +621,23 @@ function skipInClassicAfterWave(wave: number, defaultWeight: number): WeightedMo
}
/**
* High order function that returns a WeightedModifierTypeWeightFunc that will only be applied on
* classic and it will skip a ModifierType if it is the last wave pull.
* @param defaultWeight ModifierType default weight
* @returns A WeightedModifierTypeWeightFunc
* High order function that returns a WeightedRewardWeightFunc that will only be applied on
* classic and it will skip a Reward if it is the last wave pull.
* @param defaultWeight Reward default weight
* @returns A WeightedRewardWeightFunc
*/
function skipInLastClassicWaveOrDefault(defaultWeight: number): WeightedModifierTypeWeightFunc {
function skipInLastClassicWaveOrDefault(defaultWeight: number): WeightedRewardWeightFunc {
return skipInClassicAfterWave(199, defaultWeight);
}
/**
* High order function that returns a WeightedModifierTypeWeightFunc to ensure Lures don't spawn on Classic 199
* High order function that returns a WeightedRewardWeightFunc to ensure Lures don't spawn on Classic 199
* or if the lure still has over 60% of its duration left
* @param lureId The id of the lure type in question.
* @param weight The desired weight for the lure when it does spawn
* @returns A WeightedModifierTypeWeightFunc
* @returns A WeightedRewardWeightFunc
*/
function lureWeightFunc(lureId: TrainerItemId, weight: number): WeightedModifierTypeWeightFunc {
function lureWeightFunc(lureId: TrainerItemId, weight: number): WeightedRewardWeightFunc {
return () => {
const lureCount = globalScene.trainerItems.getStack(lureId);
return !(globalScene.gameMode.isClassic && globalScene.currentBattle.waveIndex === 199) &&

View File

@ -1,4 +1,4 @@
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import { TrainerItemId } from "#enums/trainer-item-id";
import { enemyBuffTokenPool } from "#items/trainer-item-pool";
@ -6,7 +6,7 @@ import { enemyBuffTokenPool } from "#items/trainer-item-pool";
* Initialize the enemy buff modifier pool
*/
function initEnemyBuffTokenPool() {
enemyBuffTokenPool[RewardTier.COMMON] = [
enemyBuffTokenPool[RarityTier.COMMON] = [
{ entry: TrainerItemId.ENEMY_DAMAGE_BOOSTER, weight: 9 },
{ entry: TrainerItemId.ENEMY_DAMAGE_REDUCTION, weight: 9 },
{ entry: TrainerItemId.ENEMY_ATTACK_POISON_CHANCE, weight: 3 },
@ -16,14 +16,14 @@ function initEnemyBuffTokenPool() {
{ entry: TrainerItemId.ENEMY_ENDURE_CHANCE, weight: 4 },
{ entry: TrainerItemId.ENEMY_FUSED_CHANCE, weight: 1 },
];
enemyBuffTokenPool[RewardTier.GREAT] = [
enemyBuffTokenPool[RarityTier.GREAT] = [
{ entry: TrainerItemId.ENEMY_DAMAGE_BOOSTER, weight: 5 },
{ entry: TrainerItemId.ENEMY_DAMAGE_REDUCTION, weight: 5 },
{ entry: TrainerItemId.ENEMY_STATUS_EFFECT_HEAL_CHANCE, weight: 5 },
{ entry: TrainerItemId.ENEMY_ENDURE_CHANCE, weight: 5 },
{ entry: TrainerItemId.ENEMY_FUSED_CHANCE, weight: 1 },
];
enemyBuffTokenPool[RewardTier.ULTRA] = [
enemyBuffTokenPool[RarityTier.ULTRA] = [
{ entry: TrainerItemId.ENEMY_DAMAGE_BOOSTER, weight: 10 },
{ entry: TrainerItemId.ENEMY_DAMAGE_REDUCTION, weight: 10 },
{ entry: TrainerItemId.ENEMY_HEAL, weight: 10 },
@ -31,8 +31,8 @@ function initEnemyBuffTokenPool() {
{ entry: TrainerItemId.ENEMY_ENDURE_CHANCE, weight: 10 },
{ entry: TrainerItemId.ENEMY_FUSED_CHANCE, weight: 5 },
];
enemyBuffTokenPool[RewardTier.ROGUE] = [];
enemyBuffTokenPool[RewardTier.MASTER] = [];
enemyBuffTokenPool[RarityTier.ROGUE] = [];
enemyBuffTokenPool[RarityTier.MASTER] = [];
}
export function initTrainerItemPools() {

View File

@ -0,0 +1,50 @@
import { globalScene } from "#app/global-scene";
import Overrides from "#app/overrides";
import type { Pokemon } from "#field/pokemon";
import type { HeldItemConfiguration } from "#items/held-item-data-types";
import { assignItemsFromConfiguration } from "#items/held-item-pool";
import type { TrainerItemConfiguration } from "#items/trainer-item-data-types";
/**
* Uses either `MODIFIER_OVERRIDE` in overrides.ts to set {@linkcode PersistentModifier}s for either:
* - The player
* - The enemy
* @param isPlayer {@linkcode boolean} for whether the player (`true`) or enemy (`false`) is being overridden
*/
export function overrideTrainerItems(isPlayer = true): void {
const trainerItemsOverride: TrainerItemConfiguration = isPlayer
? Overrides.STARTING_TRAINER_ITEMS_OVERRIDE
: Overrides.OPP_TRAINER_ITEMS_OVERRIDE;
if (!trainerItemsOverride || trainerItemsOverride.length === 0 || !globalScene) {
return;
}
// If it's the opponent, clear all of their current modifiers to avoid stacking
if (!isPlayer) {
globalScene.clearEnemyItems();
}
globalScene.assignTrainerItemsFromConfiguration(trainerItemsOverride, isPlayer);
}
/**
* Uses either `HELD_ITEMS_OVERRIDE` in overrides.ts to set {@linkcode PokemonHeldItemModifier}s for either:
* - The first member of the player's team when starting a new game
* - An enemy {@linkcode Pokemon} being spawned in
* @param pokemon {@linkcode Pokemon} whose held items are being overridden
* @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 {
const heldItemsOverride: HeldItemConfiguration = isPlayer
? Overrides.STARTING_HELD_ITEMS_OVERRIDE
: Overrides.OPP_HELD_ITEMS_OVERRIDE;
if (!heldItemsOverride || heldItemsOverride.length === 0 || !globalScene) {
return;
}
if (!isPlayer) {
pokemon.heldItemManager.clearItems();
}
assignItemsFromConfiguration(heldItemsOverride, pokemon);
}

View File

@ -0,0 +1,72 @@
import { RewardId } from "#enums/reward-id";
import { RarityTier } from "#enums/reward-tier";
export const rewardRarities = {
[RewardId.POKEBALL]: RarityTier.COMMON,
[RewardId.GREAT_BALL]: RarityTier.GREAT,
[RewardId.ULTRA_BALL]: RarityTier.ULTRA,
[RewardId.ROGUE_BALL]: RarityTier.ROGUE,
[RewardId.MASTER_BALL]: RarityTier.MASTER,
[RewardId.VOUCHER]: RarityTier.GREAT,
[RewardId.VOUCHER_PLUS]: RarityTier.ROGUE,
[RewardId.VOUCHER_PREMIUM]: RarityTier.MASTER,
[RewardId.NUGGET]: RarityTier.GREAT,
[RewardId.BIG_NUGGET]: RarityTier.ULTRA,
[RewardId.RELIC_GOLD]: RarityTier.ROGUE,
[RewardId.RARE_CANDY]: RarityTier.COMMON,
[RewardId.RARER_CANDY]: RarityTier.ULTRA,
[RewardId.EVOLUTION_ITEM]: RarityTier.GREAT,
[RewardId.RARE_EVOLUTION_ITEM]: RarityTier.ULTRA,
[RewardId.POTION]: RarityTier.COMMON,
[RewardId.SUPER_POTION]: RarityTier.COMMON,
[RewardId.HYPER_POTION]: RarityTier.GREAT,
[RewardId.MAX_POTION]: RarityTier.GREAT,
[RewardId.FULL_HEAL]: RarityTier.GREAT,
[RewardId.FULL_RESTORE]: RarityTier.GREAT,
[RewardId.REVIVE]: RarityTier.GREAT,
[RewardId.MAX_REVIVE]: RarityTier.GREAT,
[RewardId.SACRED_ASH]: RarityTier.GREAT,
[RewardId.ETHER]: RarityTier.COMMON,
[RewardId.MAX_ETHER]: RarityTier.COMMON,
[RewardId.ELIXIR]: RarityTier.GREAT,
[RewardId.MAX_ELIXIR]: RarityTier.GREAT,
[RewardId.PP_UP]: RarityTier.GREAT,
[RewardId.PP_MAX]: RarityTier.ULTRA,
[RewardId.TM_COMMON]: RarityTier.COMMON,
[RewardId.TM_GREAT]: RarityTier.GREAT,
[RewardId.TM_ULTRA]: RarityTier.ULTRA,
[RewardId.MINT]: RarityTier.ULTRA,
[RewardId.TERA_SHARD]: RarityTier.GREAT,
[RewardId.MEMORY_MUSHROOM]: RarityTier.GREAT,
[RewardId.DNA_SPLICERS]: RarityTier.MASTER,
[RewardId.SPECIES_STAT_BOOSTER]: RarityTier.GREAT,
[RewardId.RARE_SPECIES_STAT_BOOSTER]: RarityTier.ULTRA,
[RewardId.BASE_STAT_BOOSTER]: RarityTier.GREAT,
[RewardId.ATTACK_TYPE_BOOSTER]: RarityTier.ULTRA,
[RewardId.BERRY]: RarityTier.COMMON,
[RewardId.TEMP_STAT_STAGE_BOOSTER]: RarityTier.COMMON,
[RewardId.LURE]: RarityTier.COMMON,
[RewardId.SUPER_LURE]: RarityTier.GREAT,
[RewardId.MAX_LURE]: RarityTier.ULTRA,
[RewardId.FORM_CHANGE_ITEM]: RarityTier.ULTRA,
[RewardId.RARE_FORM_CHANGE_ITEM]: RarityTier.ROGUE,
};
export function getRewardTier(reward: RewardId): RarityTier {
const tier = rewardRarities[reward];
return tier ?? RarityTier.LUXURY;
}

View File

@ -0,0 +1,340 @@
import { globalScene } from "#app/global-scene";
import Overrides from "#app/overrides";
import { allRewards } from "#data/data-lists";
import { RewardPoolType } from "#enums/reward-pool-type";
import { RarityTier } from "#enums/reward-tier";
import type { PlayerPokemon, Pokemon } from "#field/pokemon";
import type { RewardFunc, RewardPool, RewardPoolWeights } from "#types/rewards";
import { isNullOrUndefined, pickWeightedIndex, randSeedInt } from "#utils/common";
import { getPartyLuckValue } from "#utils/party";
import { type Reward, RewardGenerator, RewardOption, type RewardOverride, TrainerItemReward } from "./reward";
import { rewardPool, rewardPoolWeights } from "./reward-pools";
import { getRewardDefaultTier } from "./reward-utils";
/*
This file still contains several functions to generate rewards from pools. The hierarchy of these functions is explained here.
At the top of the food chain is `generatePlayerRewardOptions`, which is responsible for creating item rewards for the player.
It can take a `CustomRewardSettings` to fix any number of rewards or tiers, then fills the remaining spots randomly.
Note that this function generates `RewardOption` instances, not yet `Reward`s.
Currently, there is only one reward pool, but in the future we will want to allow for custom pools.
The function `getNewRewardOption` is responsible for generating a single RewardOption from a given pool and set of weights.
Note that, in the previous system, this function could in principle generate rewards for enemies, which was used in some
cases to assign modifiers. This usage is now deprecated, as we have separate pools for held items and trainer items for enemies.
However, `getNewRewardOption` is not called directly by `generatePlayerRewardOptions`. Instead, it is filtered
by `getRewardOptionWithRetry`, which also checks existing rewards to minimize the chance of duplicates.
Note that the pool contains `WeightedReward` instances, which contain either a `Reward` or a `RewardGenerator`.
Once a pool entry is chosen, a specific `Reward` is generated accordingly and put in the returned `RewardOption`.
This will allow more customization in creating pools for challenges, MEs etc.
*/
export interface CustomRewardSettings {
guaranteedRarityTiers?: RarityTier[];
guaranteedRewardOptions?: RewardOption[];
/** If specified, will override the next X items to be auto-generated from specific reward functions (these don't have to be pre-genned). */
guaranteedRewardFuncs?: RewardFunc[];
/**
* If set to `true`, will fill the remainder of shop items that were not overridden by the 3 options above, up to the `count` param value.
* @example
* ```ts
* count = 4;
* customRewardSettings = { guaranteedRarityTiers: [RarityTier.GREAT], fillRemaining: true };
* ```
* The first item in the shop will be `GREAT` tier, and the remaining `3` items will be generated normally.
*
* If `fillRemaining: false` in the same scenario, only 1 `GREAT` tier item will appear in the shop (regardless of the value of `count`).
* @defaultValue `false`
*/
fillRemaining?: boolean;
/** If specified, can adjust the amount of money required for a shop reroll. If set to a negative value, the shop will not allow rerolls at all. */
rerollMultiplier?: number;
/**
* If `false`, will prevent set item tiers from upgrading via luck.
* @defaultValue `true`
*/
allowLuckUpgrades?: boolean;
}
/**
* Generates weights for a {@linkcode RewardPool}. An array of weights is generated for each rarity tier. Weights can be 0.
* @param pool - The pool for which weights must be generated
* @param party - Party is required for generating the weights
* @param rerollCount - (Optional) Needed for weights of vouchers.
*/
export function generateRewardPoolWeights(pool: RewardPool, party: Pokemon[], rerollCount = 0) {
for (const tier of Object.keys(pool)) {
const poolWeights = pool[tier].map(w => {
if (w.reward instanceof TrainerItemReward) {
const id = w.reward.itemId;
if (globalScene.trainerItems.isMaxStack(id)) {
return 0;
}
}
if (typeof w.weight === "number") {
return w.weight;
}
return w.weight(party, rerollCount);
});
rewardPoolWeights[tier] = poolWeights;
}
}
/**
* Generates a random RarityTier to draw rewards from the pool. The probabilities are:
* 1/1024 (Master tier)
* 12/1024 (Rogue tier)
* 48/1024 (Ultra tier)
* 195/1024 (Great tier)
* 768/1024 (Common tier)
* return {@linkcode RarityTier}
*/
function randomBaseTier(): RarityTier {
const tierValue = randSeedInt(1024);
if (tierValue > 255) {
return RarityTier.COMMON;
}
if (tierValue > 60) {
return RarityTier.GREAT;
}
if (tierValue > 12) {
return RarityTier.ULTRA;
}
if (tierValue) {
return RarityTier.ROGUE;
}
return RarityTier.MASTER;
}
/**
* Determines the upgrade count for a given rarity tier, based on the party luck. Will not update
* if the pool would have no entries at the new rarity.
* @param pool - RewardPool from which the reward will be generated
* @param baseTier - The initial tier to upgrade
* @param party - Party of the trainer using the item
* return {@linkcode RarityTier}
*/
function getRarityUpgradeCount(pool: RewardPool, baseTier: RarityTier, party: Pokemon[]): RarityTier {
let upgradeCount = 0;
if (baseTier < RarityTier.MASTER) {
const partyLuckValue = getPartyLuckValue(party);
const upgradeOdds = Math.floor(128 / ((partyLuckValue + 4) / 4));
while (pool.hasOwnProperty(baseTier + upgradeCount + 1) && pool[baseTier + upgradeCount + 1].length) {
if (randSeedInt(upgradeOdds) < 4) {
upgradeCount++;
} else {
break;
}
}
}
return upgradeCount;
}
/**
* Generates reward options for a {@linkcode SelectRewardPhase}
* @param count - Determines the number of items to generate
* @param party - Party is required for generating proper reward pools
* @param rarityTiers - (Optional) If specified, rolls items in the specified tiers. Commonly used for tier-locking with Lock Capsule.
* @param customRewardSettings - (Optional) See {@linkcode CustomRewardSettings}
*/
export function generatePlayerRewardOptions(
count: number,
party: PlayerPokemon[],
rarityTiers?: RarityTier[],
customRewardSettings?: CustomRewardSettings,
): RewardOption[] {
const options: RewardOption[] = [];
const retryCount = Math.min(count * 5, 50);
// TODO: Change this to allow for custom reward pools
const pool = getRewardPoolForType(RewardPoolType.PLAYER);
const weights = getRewardWeightsForType(RewardPoolType.PLAYER);
if (!customRewardSettings) {
for (let i = 0; i < count; i++) {
const tier = rarityTiers && rarityTiers.length > i ? rarityTiers[i] : undefined;
options.push(getRewardOptionWithRetry(pool, weights, options, retryCount, party, tier));
}
} else {
// Guaranteed mod options first
if (customRewardSettings?.guaranteedRewardOptions && customRewardSettings.guaranteedRewardOptions.length > 0) {
options.push(...customRewardSettings.guaranteedRewardOptions!);
}
// Guaranteed mod functions second
if (customRewardSettings.guaranteedRewardFuncs && customRewardSettings.guaranteedRewardFuncs.length > 0) {
customRewardSettings.guaranteedRewardFuncs!.forEach((mod, _i) => {
const rewardId = Object.keys(allRewards).find(k => allRewards[k] === mod) as string;
const guaranteedMod: Reward = allRewards[rewardId]?.();
// Populates item id and tier
const guaranteedModTier = getRewardDefaultTier(guaranteedMod);
const modType = guaranteedMod instanceof RewardGenerator ? guaranteedMod.generateReward(party) : guaranteedMod;
if (modType) {
const option = new RewardOption(modType, 0, guaranteedModTier);
options.push(option);
}
});
}
// Guaranteed tiers third
if (customRewardSettings.guaranteedRarityTiers && customRewardSettings.guaranteedRarityTiers.length > 0) {
const allowLuckUpgrades = customRewardSettings.allowLuckUpgrades ?? true;
for (const tier of customRewardSettings.guaranteedRarityTiers) {
options.push(getRewardOptionWithRetry(pool, weights, options, retryCount, party, tier, allowLuckUpgrades));
}
}
// Fill remaining
if (options.length < count && customRewardSettings.fillRemaining) {
while (options.length < count) {
options.push(getRewardOptionWithRetry(pool, weights, options, retryCount, party, undefined));
}
}
}
// Applies overrides for testing
overridePlayerRewardOptions(options, party);
return options;
}
/**
* Will generate a {@linkcode RewardOption} from the {@linkcode RewardPoolType.PLAYER} pool, attempting to retry duplicated items up to retryCount
* @param pool - {@linkcode RewardPool} to generate items from
* @param weights - {@linkcode RewardPoolWeights} to use when generating items
* @param existingOptions Currently generated options
* @param retryCount How many times to retry before allowing a dupe item
* @param party Current player party, used to calculate items in the pool
* @param tier If specified will generate item of tier
* @param allowLuckUpgrades `true` to allow items to upgrade tiers (the little animation that plays and is affected by luck)
*/
function getRewardOptionWithRetry(
pool: RewardPool,
weights: RewardPoolWeights,
existingOptions: RewardOption[],
retryCount: number,
party: PlayerPokemon[],
tier?: RarityTier,
allowLuckUpgrades?: boolean,
): RewardOption {
allowLuckUpgrades = allowLuckUpgrades ?? true;
let candidate = getNewRewardOption(pool, weights, party, tier, undefined, 0, allowLuckUpgrades);
let r = 0;
while (
existingOptions.length &&
++r < retryCount &&
//TODO: Improve this condition to refine what counts as a dupe
existingOptions.filter(o => o.type.name === candidate?.type.name || o.type.group === candidate?.type.group).length
) {
console.log("Retry count:", r);
console.log(candidate?.type.group);
console.log(candidate?.type.name);
console.log(existingOptions.filter(o => o.type.name === candidate?.type.name).length);
console.log(existingOptions.filter(o => o.type.group === candidate?.type.group).length);
candidate = getNewRewardOption(
pool,
weights,
party,
candidate?.type.tier ?? tier,
candidate?.upgradeCount,
0,
allowLuckUpgrades,
);
}
return candidate!;
}
/**
* Generates a Reward from the specified pool
* @param pool - {@linkcode RewardPool} to generate items from
* @param weights - {@linkcode RewardPoolWeights} to use when generating items
* @param party - party of the trainer using the item
* @param baseTier - If specified, will override the initial tier of an item (can still upgrade with luck)
* @param upgradeCount - If defined, means that this is a new Reward being generated to override another via luck upgrade. Used for recursive logic
* @param retryCount - Max allowed tries before the next tier down is checked for a valid Reward
* @param allowLuckUpgrades - Default true. If false, will not allow Reward to randomly upgrade to next tier
*/
function getNewRewardOption(
pool: RewardPool,
weights: RewardPoolWeights,
party: PlayerPokemon[],
baseTier?: RarityTier,
upgradeCount?: number,
retryCount = 0,
allowLuckUpgrades = true,
): RewardOption | null {
let tier = 0;
if (isNullOrUndefined(baseTier)) {
baseTier = randomBaseTier();
}
if (isNullOrUndefined(upgradeCount)) {
upgradeCount = allowLuckUpgrades ? getRarityUpgradeCount(pool, baseTier, party) : 0;
tier = baseTier + upgradeCount;
} else {
tier = baseTier;
}
const tierWeights = weights[tier];
const index = pickWeightedIndex(tierWeights);
if (index === undefined) {
return null;
}
let reward: Reward | RewardGenerator | null = pool[tier][index].reward;
if (reward instanceof RewardGenerator) {
reward = (reward as RewardGenerator).generateReward(party);
if (reward === null) {
console.log(RarityTier[tier], upgradeCount);
return getNewRewardOption(pool, weights, party, tier, upgradeCount, ++retryCount);
}
}
console.log(reward);
return new RewardOption(reward as Reward, upgradeCount!, tier); // TODO: is this bang correct?
}
/**
* Replaces the {@linkcode Reward} of the entries within {@linkcode options} with any
* {@linkcode RewardOverride} entries listed in {@linkcode Overrides.REWARD_OVERRIDE}
* up to the smallest amount of entries between {@linkcode options} and the override array.
* @param options Array of naturally rolled {@linkcode RewardOption}s
* @param party Array of the player's current party
*/
export function overridePlayerRewardOptions(options: RewardOption[], party: PlayerPokemon[]) {
const minLength = Math.min(options.length, Overrides.REWARD_OVERRIDE.length);
for (let i = 0; i < minLength; i++) {
const override: RewardOverride = Overrides.REWARD_OVERRIDE[i];
const rewardFunc = allRewards[override.name];
let reward: Reward | RewardGenerator | null = rewardFunc();
if (reward instanceof RewardGenerator) {
const pregenArgs = "type" in override && override.type !== null ? [override.type] : undefined;
reward = reward.generateReward(party, pregenArgs);
}
if (reward) {
options[i].type = reward;
options[i].tier = getRewardDefaultTier(reward);
}
}
}
export function getRewardPoolForType(poolType: RewardPoolType): RewardPool {
switch (poolType) {
case RewardPoolType.PLAYER:
return rewardPool;
}
}
export function getRewardWeightsForType(poolType: RewardPoolType): RewardPoolWeights {
switch (poolType) {
case RewardPoolType.PLAYER:
return rewardPoolWeights;
}
}

View File

@ -0,0 +1,9 @@
/*
* Contains modifier pools for different contexts in the game.
* Can be safely imported without worrying about circular dependencies.
*/
import type { RewardPool, RewardPoolWeights } from "#types/rewards";
export const rewardPool: RewardPool = {};
export const rewardPoolWeights: RewardPoolWeights = {};

115
src/items/reward-utils.ts Normal file
View File

@ -0,0 +1,115 @@
import { globalScene } from "#app/global-scene";
import { allRewards } from "#data/data-lists";
import type { HeldItemId } from "#enums/held-item-id";
import { getRewardCategory, RewardCategoryId, RewardId } from "#enums/reward-id";
import type { RarityTier } from "#enums/reward-tier";
import type { TrainerItemId } from "#enums/trainer-item-id";
import type { RewardFunc, RewardPoolId } from "#types/rewards";
import { getHeldItemTier } from "./held-item-default-tiers";
import {
type HeldItemReward,
type PokemonMoveReward,
type RememberMoveReward,
type Reward,
RewardGenerator,
RewardOption,
type TmReward,
type TrainerItemReward,
} from "./reward";
import { getRewardTier } from "./reward-defaults-tiers";
import { getTrainerItemTier } from "./trainer-item-default-tiers";
export function isTmReward(reward: Reward): reward is TmReward {
return getRewardCategory(reward.id) === RewardCategoryId.TM;
}
export function isMoveReward(reward: Reward): reward is PokemonMoveReward {
const categoryId = getRewardCategory(reward.id);
return categoryId === RewardCategoryId.ETHER || categoryId === RewardCategoryId.PP_UP;
}
export function isRememberMoveReward(reward: Reward): reward is RememberMoveReward {
return reward.id === RewardId.MEMORY_MUSHROOM;
}
/**
* Generates a Reward from a given function
* @param rewardFunc
* @param pregenArgs Can specify BerryType for berries, TM for TMs, AttackBoostType for item, etc.
*/
export function generateReward(rewardFunc: RewardFunc, pregenArgs?: any[]): Reward | null {
const reward = rewardFunc();
return reward instanceof RewardGenerator ? reward.generateReward(globalScene.getPlayerParty(), pregenArgs) : reward;
}
/**
* Generates a Reward Option from a given function
* @param rewardFunc
* @param pregenArgs - can specify BerryType for berries, TM for TMs, AttackBoostType for item, etc.
*/
export function generateRewardOption(rewardFunc: RewardFunc, pregenArgs?: any[]): RewardOption | null {
const reward = generateReward(rewardFunc, pregenArgs);
if (reward) {
const tier = getRewardDefaultTier(reward);
return new RewardOption(reward, 0, tier);
}
return null;
}
/**
* Finds the default rarity tier for a given reward. For unique held item or trainer item rewards,
* falls back to the default rarity tier for the item.
* @param reward The {@linkcode Reward} to determine the tier for.
*/
export function getRewardDefaultTier(reward: Reward): RarityTier {
if (reward.id === RewardId.HELD_ITEM) {
return getHeldItemTier((reward as HeldItemReward).itemId);
}
if (reward.id === RewardId.TRAINER_ITEM) {
return getTrainerItemTier((reward as TrainerItemReward).itemId);
}
return getRewardTier(reward.id);
}
export function getPlayerShopRewardOptionsForWave(waveIndex: number, baseCost: number): RewardOption[] {
if (!(waveIndex % 10)) {
return [];
}
const options = [
[
new RewardOption(allRewards.POTION(), 0, baseCost * 0.2),
new RewardOption(allRewards.ETHER(), 0, baseCost * 0.4),
new RewardOption(allRewards.REVIVE(), 0, baseCost * 2),
],
[
new RewardOption(allRewards.SUPER_POTION(), 0, baseCost * 0.45),
new RewardOption(allRewards.FULL_HEAL(), 0, baseCost),
],
[new RewardOption(allRewards.ELIXIR(), 0, baseCost), new RewardOption(allRewards.MAX_ETHER(), 0, baseCost)],
[
new RewardOption(allRewards.HYPER_POTION(), 0, baseCost * 0.8),
new RewardOption(allRewards.MAX_REVIVE(), 0, baseCost * 2.75),
new RewardOption(allRewards.MEMORY_MUSHROOM(), 0, baseCost * 4),
],
[
new RewardOption(allRewards.MAX_POTION(), 0, baseCost * 1.5),
new RewardOption(allRewards.MAX_ELIXIR(), 0, baseCost * 2.5),
],
[new RewardOption(allRewards.FULL_RESTORE(), 0, baseCost * 2.25)],
[new RewardOption(allRewards.SACRED_ASH(), 0, baseCost * 10)],
];
return options.slice(0, Math.ceil(Math.max(waveIndex + 10, 0) / 30)).flat();
}
export function isRewardId(id: RewardPoolId): id is RewardId {
return id > 0x2000;
}
export function isTrainerItemId(id: RewardPoolId): id is TrainerItemId {
return id > 0x1000 && id < 0x2000;
}
export function isHeldItemId(id: RewardPoolId): id is HeldItemId {
return id < 0x1000;
}

1852
src/items/reward.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
// TODO: move to `src/@types/`
import type { RewardTier } from "#enums/reward-tier";
import type { RarityTier } from "#enums/reward-tier";
import type { TrainerItemId } from "#enums/trainer-item-id";
export type TrainerItemData = {
@ -28,7 +28,7 @@ type TrainerItemPoolEntry = {
export type TrainerItemPool = TrainerItemPoolEntry[];
export type TrainerItemTieredPool = {
[key in RewardTier]?: TrainerItemPool;
[key in RarityTier]?: TrainerItemPool;
};
export function isTrainerItemPool(value: any): value is TrainerItemPool {

View File

@ -0,0 +1,50 @@
import { RarityTier } from "#enums/reward-tier";
import { TrainerItemId } from "#enums/trainer-item-id";
export const trainerItemRarities = {
[TrainerItemId.MAP]: RarityTier.COMMON,
[TrainerItemId.IV_SCANNER]: RarityTier.ULTRA,
[TrainerItemId.LOCK_CAPSULE]: RarityTier.ROGUE,
[TrainerItemId.MEGA_BRACELET]: RarityTier.ROGUE,
[TrainerItemId.DYNAMAX_BAND]: RarityTier.ROGUE,
[TrainerItemId.TERA_ORB]: RarityTier.ULTRA,
[TrainerItemId.GOLDEN_POKEBALL]: RarityTier.LUXURY,
[TrainerItemId.OVAL_CHARM]: RarityTier.LUXURY,
[TrainerItemId.EXP_SHARE]: RarityTier.ULTRA,
[TrainerItemId.EXP_BALANCE]: RarityTier.LUXURY,
[TrainerItemId.CANDY_JAR]: RarityTier.ULTRA,
[TrainerItemId.BERRY_POUCH]: RarityTier.ROGUE,
[TrainerItemId.HEALING_CHARM]: RarityTier.MASTER,
[TrainerItemId.EXP_CHARM]: RarityTier.ULTRA,
[TrainerItemId.SUPER_EXP_CHARM]: RarityTier.ROGUE,
[TrainerItemId.GOLDEN_EXP_CHARM]: RarityTier.LUXURY,
[TrainerItemId.AMULET_COIN]: RarityTier.ULTRA,
[TrainerItemId.ABILITY_CHARM]: RarityTier.ULTRA,
[TrainerItemId.SHINY_CHARM]: RarityTier.MASTER,
[TrainerItemId.CATCHING_CHARM]: RarityTier.ULTRA,
[TrainerItemId.BLACK_SLUDGE]: RarityTier.LUXURY,
[TrainerItemId.GOLDEN_BUG_NET]: RarityTier.LUXURY,
[TrainerItemId.LURE]: RarityTier.COMMON,
[TrainerItemId.SUPER_LURE]: RarityTier.GREAT,
[TrainerItemId.MAX_LURE]: RarityTier.ULTRA,
[TrainerItemId.X_ATTACK]: RarityTier.COMMON,
[TrainerItemId.X_DEFENSE]: RarityTier.COMMON,
[TrainerItemId.X_SP_ATK]: RarityTier.COMMON,
[TrainerItemId.X_SP_DEF]: RarityTier.COMMON,
[TrainerItemId.X_SPEED]: RarityTier.COMMON,
[TrainerItemId.X_ACCURACY]: RarityTier.COMMON,
[TrainerItemId.DIRE_HIT]: RarityTier.GREAT,
};
export function getTrainerItemTier(item: TrainerItemId): RarityTier {
const tier = trainerItemRarities[item];
return tier ?? RarityTier.LUXURY;
}

View File

@ -1,6 +1,6 @@
import { globalScene } from "#app/global-scene";
import { allTrainerItems } from "#data/data-lists";
import { RewardTier } from "#enums/reward-tier";
import { RarityTier } from "#enums/reward-tier";
import type { TrainerItemId } from "#enums/trainer-item-id";
import type { TrainerItemPool, TrainerItemTieredPool } from "#items/trainer-item-data-types";
import type { TrainerItemManager } from "#items/trainer-item-manager";
@ -29,13 +29,13 @@ export function getNewTrainerItemFromPool(pool: TrainerItemPool, manager: Traine
return entry as TrainerItemId;
}
export function assignEnemyBuffTokenForWave(tier: RewardTier) {
export function assignEnemyBuffTokenForWave(tier: RarityTier) {
let tierStackCount: number;
switch (tier) {
case RewardTier.ULTRA:
case RarityTier.ULTRA:
tierStackCount = 5;
break;
case RewardTier.GREAT:
case RarityTier.GREAT:
tierStackCount = 3;
break;
default:

View File

@ -297,9 +297,9 @@ export class DoubleBattleChanceBoosterTrainerItem extends LapsingTrainerItem {
}
}
interface TempStatToTrainerItemMap {
[key: number]: TrainerItemId;
}
type TempStatToTrainerItemMap = {
[key in TempBattleStat]: TrainerItemId;
};
export const tempStatToTrainerItem: TempStatToTrainerItemMap = {
[Stat.ATK]: TrainerItemId.X_ATTACK,

View File

@ -15,9 +15,9 @@ import { getBiomeHasProps } from "#field/arena";
import { initHeldItems } from "#items/all-held-items";
import { initTrainerItems } from "#items/all-trainer-items";
import { initHeldItemPools } from "#items/init-held-item-pools";
import { initRewardPools } from "#items/init-reward-pools";
import { initTrainerItemPools } from "#items/init-trainer-item-pools";
import { initModifierPools } from "#modifiers/init-modifier-pools";
import { initModifierTypes } from "#modifiers/modifier-type";
import { initRewards } from "#items/reward";
import { initMoves } from "#moves/move";
import { initMysteryEncounters } from "#mystery-encounters/mystery-encounters";
import { CacheBustedLoaderPlugin } from "#plugins/cache-busted-loader-plugin";
@ -370,8 +370,8 @@ export class LoadingScene extends SceneBase {
this.loadLoadingScreen();
initModifierTypes();
initModifierPools();
initRewards();
initRewardPools();
initHeldItemPools();
initTrainerItemPools();

View File

@ -1,8 +0,0 @@
/*
* Contains modifier pools for different contexts in the game.
* Can be safely imported without worrying about circular dependencies.
*/
import type { ModifierPool } from "#types/modifier-types";
export const modifierPool: ModifierPool = {};

Some files were not shown because too many files have changed in this diff Show More