diff --git a/src/@types/rewards.ts b/src/@types/rewards.ts index ad938a60164..acf4749a3da 100644 --- a/src/@types/rewards.ts +++ b/src/@types/rewards.ts @@ -9,9 +9,18 @@ export type WeightedRewardWeightFunc = (party: Pokemon[], rerollCount?: number) export type RewardPoolId = RewardId | HeldItemId | TrainerItemId; +export type RewardGeneratorSpecs = { + id: RewardId; + args: RewardGeneratorArgs; +}; +// TODO: fix this with correctly typed args for different RewardIds + +export type RewardSpecs = RewardPoolId | RewardGeneratorSpecs; + export type RewardPoolEntry = { id: RewardPoolId; weight: number | WeightedRewardWeightFunc; + maxWeight?: number; }; export type RewardPool = { diff --git a/src/data/data-lists.ts b/src/data/data-lists.ts index 85f5a0e6b20..a8db163fa69 100644 --- a/src/data/data-lists.ts +++ b/src/data/data-lists.ts @@ -1,11 +1,12 @@ import type { Ability } from "#abilities/ability"; import type { PokemonSpecies } from "#data/pokemon-species"; 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 { HeldItem } from "#items/held-item"; -import type { Rewards } from "#items/reward"; import type { TrainerItem } from "#items/trainer-item"; import type { Move } from "#moves/move"; +import type { RewardFunc } from "#types/rewards"; export const allAbilities: Ability[] = []; export const allMoves: Move[] = []; @@ -13,6 +14,4 @@ export const allSpecies: PokemonSpecies[] = []; export const allHeldItems: Record = {}; export const allTrainerItems: Record = {}; - -// TODO: Figure out what this is used for and provide an appropriate tsdoc comment -export const allRewards = {} as Rewards; +export const allRewards: Record = {}; diff --git a/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts b/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts index 57a78f5f9d0..4bbabe73ee4 100644 --- a/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts +++ b/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts @@ -1,11 +1,11 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { globalScene } from "#app/global-scene"; -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 { RewardId } from "#enums/reward-id"; import { RarityTier } from "#enums/reward-tier"; import { SpeciesId } from "#enums/species-id"; import { TrainerType } from "#enums/trainer-type"; @@ -164,7 +164,7 @@ export const ATrainersTestEncounter: MysteryEncounter = MysteryEncounterBuilder. encounter.setDialogueToken("eggType", i18next.t(`${namespace}:eggTypes.epic`)); setEncounterRewards( { - guaranteedRewardFuncs: [allRewards.SACRED_ASH], + guaranteedRewardSpecs: [RewardId.SACRED_ASH], guaranteedRarityTiers: [RarityTier.ROGUE, RarityTier.ULTRA], fillRemaining: true, }, diff --git a/src/data/mystery-encounters/encounters/berries-abound-encounter.ts b/src/data/mystery-encounters/encounters/berries-abound-encounter.ts index ed581c8f544..2abfc81b1ea 100644 --- a/src/data/mystery-encounters/encounters/berries-abound-encounter.ts +++ b/src/data/mystery-encounters/encounters/berries-abound-encounter.ts @@ -1,19 +1,19 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { globalScene } from "#app/global-scene"; import { getPokemonNameWithAffix } from "#app/messages"; -import { allRewards } from "#data/data-lists"; import { BattlerTagType } from "#enums/battler-tag-type"; import { BerryType } from "#enums/berry-type"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; +import { RewardId } from "#enums/reward-id"; 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 { RewardOption } from "#items/reward"; import { generateRewardPoolWeights, getRewardPoolForType } from "#items/reward-pool-utils"; -import { generateRewardOption } from "#items/reward-utils"; +import { generateRewardOptionFromId } from "#items/reward-utils"; import { queueEncounterMessage, showEncounterText } from "#mystery-encounters/encounter-dialogue-utils"; import type { EnemyPartyConfig } from "#mystery-encounters/encounter-phase-utils"; import { @@ -162,7 +162,7 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder. const shopOptions: RewardOption[] = []; for (let i = 0; i < 5; i++) { // Generate shop berries - const mod = generateRewardOption(allRewards.BERRY); + const mod = generateRewardOptionFromId(RewardId.BERRY); if (mod) { shopOptions.push(mod); } @@ -189,7 +189,7 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder. const shopOptions: RewardOption[] = []; for (let i = 0; i < 5; i++) { // Generate shop berries - const mod = generateRewardOption(allRewards.BERRY); + const mod = generateRewardOptionFromId(RewardId.BERRY); if (mod) { shopOptions.push(mod); } diff --git a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts index b526be72ea0..8b9edd9f51e 100644 --- a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts +++ b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts @@ -1,6 +1,6 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { globalScene } from "#app/global-scene"; -import { allHeldItems, allMoves, allRewards } from "#data/data-lists"; +import { allHeldItems, allMoves } 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,6 +8,7 @@ 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 { RewardId } from "#enums/reward-id"; import { RarityTier } from "#enums/reward-tier"; import { SpeciesId } from "#enums/species-id"; import { TrainerItemId } from "#enums/trainer-item-id"; @@ -15,7 +16,7 @@ import { TrainerSlot } from "#enums/trainer-slot"; import { TrainerType } from "#enums/trainer-type"; import type { PlayerPokemon, Pokemon } from "#field/pokemon"; import type { RewardOption } from "#items/reward"; -import { generateRewardOption } from "#items/reward-utils"; +import { generateRewardOptionFromId } 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"; @@ -285,7 +286,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde moveTutorOptions, }; - // Assigns callback that teaches move before continuing to allRewards + // Assigns callback that teaches move before continuing to RewardId encounter.onRewards = doBugTypeMoveTutor; setEncounterRewards({ fillRemaining: true }); @@ -305,7 +306,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde // Player shows off their bug types const encounter = globalScene.currentBattle.mysteryEncounter!; - // Player gets different allRewards depending on the number of bug types they have + // Player gets different RewardId 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 +315,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde if (numBugTypes < 2) { setEncounterRewards({ - guaranteedRewardFuncs: [allRewards.SUPER_LURE, allRewards.GREAT_BALL], + guaranteedRewardSpecs: [RewardId.SUPER_LURE, RewardId.GREAT_BALL], fillRemaining: false, }); encounter.selectedOption!.dialogue!.selected = [ @@ -325,7 +326,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde ]; } else if (numBugTypes < 4) { setEncounterRewards({ - guaranteedRewardFuncs: [allRewards.QUICK_CLAW, allRewards.MAX_LURE, allRewards.ULTRA_BALL], + guaranteedRewardSpecs: [HeldItemId.QUICK_CLAW, RewardId.MAX_LURE, RewardId.ULTRA_BALL], fillRemaining: false, }); encounter.selectedOption!.dialogue!.selected = [ @@ -336,7 +337,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde ]; } else if (numBugTypes < 6) { setEncounterRewards({ - guaranteedRewardFuncs: [allRewards.GRIP_CLAW, allRewards.MAX_LURE, allRewards.ROGUE_BALL], + guaranteedRewardSpecs: [HeldItemId.GRIP_CLAW, RewardId.MAX_LURE, RewardId.ROGUE_BALL], fillRemaining: false, }); encounter.selectedOption!.dialogue!.selected = [ @@ -348,28 +349,28 @@ 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 rewardOptions: RewardOption[] = [generateRewardOption(allRewards.MASTER_BALL)!]; + const rewardOptions: RewardOption[] = [generateRewardOptionFromId(RewardId.MASTER_BALL)!]; const specialOptions: RewardOption[] = []; if (!globalScene.trainerItems.hasItem(TrainerItemId.MEGA_BRACELET)) { - rewardOptions.push(generateRewardOption(allRewards.MEGA_BRACELET)!); + rewardOptions.push(generateRewardOptionFromId(TrainerItemId.MEGA_BRACELET)!); } if (!globalScene.trainerItems.hasItem(TrainerItemId.DYNAMAX_BAND)) { - rewardOptions.push(generateRewardOption(allRewards.DYNAMAX_BAND)!); + rewardOptions.push(generateRewardOptionFromId(TrainerItemId.DYNAMAX_BAND)!); } - const nonRareEvolutionReward = generateRewardOption(allRewards.EVOLUTION_ITEM); + const nonRareEvolutionReward = generateRewardOptionFromId(RewardId.EVOLUTION_ITEM); if (nonRareEvolutionReward) { specialOptions.push(nonRareEvolutionReward); } - const rareEvolutionReward = generateRewardOption(allRewards.RARE_EVOLUTION_ITEM); + const rareEvolutionReward = generateRewardOptionFromId(RewardId.RARE_EVOLUTION_ITEM); if (rareEvolutionReward) { specialOptions.push(rareEvolutionReward); } - const formChangeReward = generateRewardOption(allRewards.FORM_CHANGE_ITEM); + const formChangeReward = generateRewardOptionFromId(RewardId.FORM_CHANGE_ITEM); if (formChangeReward) { specialOptions.push(formChangeReward); } - const rareFormChangeReward = generateRewardOption(allRewards.RARE_FORM_CHANGE_ITEM); + const rareFormChangeReward = generateRewardOptionFromId(RewardId.RARE_FORM_CHANGE_ITEM); if (rareFormChangeReward) { specialOptions.push(rareFormChangeReward); } @@ -465,12 +466,12 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde chosenPokemon.loseHeldItem(lostItem, false); globalScene.updateItems(true); - const bugNet = generateRewardOption(allRewards.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!; + const bugNet = generateRewardOptionFromId(TrainerItemId.GOLDEN_BUG_NET)!; bugNet.type.tier = RarityTier.ROGUE; setEncounterRewards({ guaranteedRewardOptions: [bugNet], - guaranteedRewardFuncs: [allRewards.REVIVER_SEED], + guaranteedRewardSpecs: [HeldItemId.REVIVER_SEED], fillRemaining: false, }); leaveEncounterWithoutBattle(true); @@ -744,7 +745,7 @@ function doBugTypeMoveTutor(): Promise { ); } - // Complete battle and go to allRewards + // Complete battle and go to RewardId resolve(); }); } diff --git a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts index 56b21490f29..2db0580fccc 100644 --- a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts +++ b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts @@ -1,11 +1,11 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { globalScene } from "#app/global-scene"; import { EncounterBattleAnim } from "#data/battle-anims"; -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"; import { EncounterAnim } from "#enums/encounter-anims"; +import { HeldItemId } from "#enums/held-item-id"; import { MoveId } from "#enums/move-id"; import { MoveUseMode } from "#enums/move-use-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; @@ -219,7 +219,7 @@ export const DancingLessonsEncounter: MysteryEncounter = MysteryEncounterBuilder await hideOricorioPokemon(); setEncounterRewards({ - guaranteedRewardFuncs: [allRewards.BATON], + guaranteedRewardSpecs: [HeldItemId.BATON], fillRemaining: true, }); await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]); diff --git a/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts b/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts index 28de326cf46..bb645c5d004 100644 --- a/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts +++ b/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts @@ -1,12 +1,12 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; -import { allRewards } from "#data/data-lists"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; +import { RewardId } from "#enums/reward-id"; 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 { RewardFunc } from "#types/rewards"; +import type { RewardSpecs } 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 rewards: RewardFunc[] = []; + const rewards: RewardSpecs[] = []; let i = 0; while (i < 5) { // 2/2/1 weight on TM rarity const roll = randSeedInt(5); if (roll < 2) { - rewards.push(allRewards.TM_COMMON); + rewards.push(RewardId.TM_COMMON); } else if (roll < 4) { - rewards.push(allRewards.TM_GREAT); + rewards.push(RewardId.TM_GREAT); } else { - rewards.push(allRewards.TM_ULTRA); + rewards.push(RewardId.TM_ULTRA); } i++; } setEncounterRewards({ - guaranteedRewardFuncs: rewards, + guaranteedRewardSpecs: rewards, fillRemaining: false, }); leaveEncounterWithoutBattle(); @@ -88,21 +88,21 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBu }, async () => { // Choose Vitamins - const rewards: RewardFunc[] = []; + const rewards: RewardSpecs[] = []; let i = 0; while (i < 3) { // 2/1 weight on base stat booster vs PP Up const roll = randSeedInt(3); if (roll === 0) { - rewards.push(allRewards.PP_UP); + rewards.push(RewardId.PP_UP); } else { - rewards.push(allRewards.BASE_STAT_BOOSTER); + rewards.push(RewardId.BASE_STAT_BOOSTER); } i++; } setEncounterRewards({ - guaranteedRewardFuncs: rewards, + guaranteedRewardSpecs: rewards, fillRemaining: false, }); leaveEncounterWithoutBattle(); @@ -115,21 +115,21 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBu }, async () => { // Choose X Items - const rewards: RewardFunc[] = []; + const rewards: RewardSpecs[] = []; let i = 0; while (i < 5) { // 4/1 weight on base stat booster vs Dire Hit const roll = randSeedInt(5); if (roll === 0) { - rewards.push(allRewards.DIRE_HIT); + rewards.push(RewardId.DIRE_HIT); } else { - rewards.push(allRewards.TEMP_STAT_STAGE_BOOSTER); + rewards.push(RewardId.TEMP_STAT_STAGE_BOOSTER); } i++; } setEncounterRewards({ - guaranteedRewardFuncs: rewards, + guaranteedRewardSpecs: rewards, fillRemaining: false, }); leaveEncounterWithoutBattle(); @@ -142,25 +142,25 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = MysteryEncounterBu }, async () => { // Choose Pokeballs - const rewards: RewardFunc[] = []; + const rewards: RewardSpecs[] = []; let i = 0; while (i < 4) { // 10/30/20/5 weight on pokeballs const roll = randSeedInt(65); if (roll < 10) { - rewards.push(allRewards.POKEBALL); + rewards.push(RewardId.POKEBALL); } else if (roll < 40) { - rewards.push(allRewards.GREAT_BALL); + rewards.push(RewardId.GREAT_BALL); } else if (roll < 60) { - rewards.push(allRewards.ULTRA_BALL); + rewards.push(RewardId.ULTRA_BALL); } else { - rewards.push(allRewards.ROGUE_BALL); + rewards.push(RewardId.ROGUE_BALL); } i++; } setEncounterRewards({ - guaranteedRewardFuncs: rewards, + guaranteedRewardSpecs: rewards, fillRemaining: false, }); leaveEncounterWithoutBattle(); diff --git a/src/data/mystery-encounters/encounters/field-trip-encounter.ts b/src/data/mystery-encounters/encounters/field-trip-encounter.ts index 35485fba083..34b13527cfd 100644 --- a/src/data/mystery-encounters/encounters/field-trip-encounter.ts +++ b/src/data/mystery-encounters/encounters/field-trip-encounter.ts @@ -1,13 +1,11 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { globalScene } from "#app/global-scene"; -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 { leaveEncounterWithoutBattle, @@ -96,11 +94,11 @@ export const FieldTripEncounter: MysteryEncounter = MysteryEncounterBuilder.with const encounter = globalScene.currentBattle.mysteryEncounter!; if (encounter.misc.correctMove) { const modifiers = [ - 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)!, + generateRewardOptionFromId(RewardId.TEMP_STAT_STAGE_BOOSTER, [Stat.ATK])!, + generateRewardOptionFromId(RewardId.TEMP_STAT_STAGE_BOOSTER, [Stat.DEF])!, + generateRewardOptionFromId(RewardId.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!, + generateRewardOptionFromId(RewardId.DIRE_HIT)!, + generateRewardOptionFromId(RewardId.RARER_CANDY)!, ]; setEncounterRewards({ @@ -144,11 +142,11 @@ export const FieldTripEncounter: MysteryEncounter = MysteryEncounterBuilder.with const encounter = globalScene.currentBattle.mysteryEncounter!; if (encounter.misc.correctMove) { const modifiers = [ - 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)!, + generateRewardOptionFromId(RewardId.TEMP_STAT_STAGE_BOOSTER, [Stat.SPATK])!, + generateRewardOptionFromId(RewardId.TEMP_STAT_STAGE_BOOSTER, [Stat.SPDEF])!, + generateRewardOptionFromId(RewardId.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!, + generateRewardOptionFromId(RewardId.DIRE_HIT)!, + generateRewardOptionFromId(RewardId.RARER_CANDY)!, ]; setEncounterRewards({ @@ -192,11 +190,11 @@ export const FieldTripEncounter: MysteryEncounter = MysteryEncounterBuilder.with const encounter = globalScene.currentBattle.mysteryEncounter!; if (encounter.misc.correctMove) { const modifiers = [ - 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)!, + generateRewardOptionFromId(RewardId.TEMP_STAT_STAGE_BOOSTER, [Stat.ACC])!, + generateRewardOptionFromId(RewardId.TEMP_STAT_STAGE_BOOSTER, [Stat.SPD])!, + generateRewardOptionFromId(RewardId.GREAT_BALL)!, + generateRewardOptionFromId(RewardId.IV_SCANNER)!, + generateRewardOptionFromId(RewardId.RARER_CANDY)!, ]; setEncounterRewards({ diff --git a/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts b/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts index 8fb63b16085..51bfeea397c 100644 --- a/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts +++ b/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts @@ -1,10 +1,10 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { globalScene } from "#app/global-scene"; import { getPokemonNameWithAffix } from "#app/messages"; -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"; +import { HeldItemId } from "#enums/held-item-id"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; @@ -160,7 +160,7 @@ export const FunAndGamesEncounter: MysteryEncounter = MysteryEncounterBuilder.wi ], }, async () => { - // Leave encounter with no allRewards or exp + // Leave encounter with no RewardId or exp await transitionMysteryEncounterIntroVisuals(true, true); leaveEncounterWithoutBattle(true); return true; @@ -281,21 +281,21 @@ function handleNextTurn() { if (healthRatio < 0.03) { // Grand prize setEncounterRewards({ - guaranteedRewardFuncs: [allRewards.MULTI_LENS], + guaranteedRewardSpecs: [HeldItemId.MULTI_LENS], fillRemaining: false, }); resultMessageKey = `${namespace}:best_result`; } else if (healthRatio < 0.15) { // 2nd prize setEncounterRewards({ - guaranteedRewardFuncs: [allRewards.SCOPE_LENS], + guaranteedRewardSpecs: [HeldItemId.SCOPE_LENS], fillRemaining: false, }); resultMessageKey = `${namespace}:great_result`; } else if (healthRatio < 0.33) { // 3rd prize setEncounterRewards({ - guaranteedRewardFuncs: [allRewards.WIDE_LENS], + guaranteedRewardSpecs: [HeldItemId.WIDE_LENS], fillRemaining: false, }); resultMessageKey = `${namespace}:good_result`; diff --git a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts index ec26298bf93..4d7a03485c7 100644 --- a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts +++ b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts @@ -1,9 +1,9 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { globalScene } from "#app/global-scene"; -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 { RewardId } from "#enums/reward-id"; import { RarityTier } from "#enums/reward-tier"; import type { EnemyPartyConfig } from "#mystery-encounters/encounter-phase-utils"; import { initBattleWithEnemyConfig, setEncounterRewards } from "#mystery-encounters/encounter-phase-utils"; @@ -147,7 +147,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0]; setEncounterRewards({ - guaranteedRewardFuncs: [allRewards.TM_COMMON, allRewards.TM_GREAT, allRewards.MEMORY_MUSHROOM], + guaranteedRewardSpecs: [RewardId.TM_COMMON, RewardId.TM_GREAT, RewardId.MEMORY_MUSHROOM], fillRemaining: true, }); diff --git a/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts b/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts index e3d55b6724b..62f864bb464 100644 --- a/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts +++ b/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts @@ -1,5 +1,4 @@ import { globalScene } from "#app/global-scene"; -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 +115,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil // Pick battle const encounter = globalScene.currentBattle.mysteryEncounter!; setEncounterRewards({ - guaranteedRewardFuncs: [allRewards.LEFTOVERS], + guaranteedRewardSpecs: [HeldItemId.LEFTOVERS], fillRemaining: true, }); encounter.startOfBattleEffects.push({ @@ -163,7 +162,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil // Steal the Snorlax's Leftovers const instance = globalScene.currentBattle.mysteryEncounter!; setEncounterRewards({ - guaranteedRewardFuncs: [allRewards.LEFTOVERS], + guaranteedRewardSpecs: [HeldItemId.LEFTOVERS], fillRemaining: false, }); // Snorlax exp to Pokemon that did the stealing diff --git a/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts b/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts index 5239da1512b..4579ad1246b 100644 --- a/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts +++ b/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts @@ -1,9 +1,9 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { globalScene } from "#app/global-scene"; import { getPokemonNameWithAffix } from "#app/messages"; -import { allRewards } from "#data/data-lists"; import { BattlerTagType } from "#enums/battler-tag-type"; import { BiomeId } from "#enums/biome-id"; +import { HeldItemId } from "#enums/held-item-id"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; @@ -13,7 +13,6 @@ import { TrainerSlot } from "#enums/trainer-slot"; import { getBiomeKey } from "#field/arena"; import type { Pokemon } from "#field/pokemon"; import { EnemyPokemon } from "#field/pokemon"; -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 { @@ -173,10 +172,8 @@ export const TeleportingHijinksEncounter: MysteryEncounter = MysteryEncounterBui ], }; - const magnet = generateRewardOption(allRewards.ATTACK_TYPE_BOOSTER, [PokemonType.STEEL])!; - const metalCoat = generateRewardOption(allRewards.ATTACK_TYPE_BOOSTER, [PokemonType.ELECTRIC])!; setEncounterRewards({ - guaranteedRewardOptions: [magnet, metalCoat], + guaranteedRewardSpecs: [HeldItemId.MAGNET, HeldItemId.METAL_COAT], fillRemaining: true, }); await transitionMysteryEncounterIntroVisuals(true, true); diff --git a/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts b/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts index 4eb63d94af0..5e1e50e2c41 100644 --- a/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts @@ -1,11 +1,11 @@ import { globalScene } from "#app/global-scene"; import { speciesStarterCosts } from "#balance/starters"; -import { allRewards } from "#data/data-lists"; import type { IEggOptions } from "#data/egg"; import { getPokeballTintColor } from "#data/pokeball"; import { BiomeId } from "#enums/biome-id"; import { EggSourceType } from "#enums/egg-source-types"; import { EggTier } from "#enums/egg-type"; +import { HeldItemId } from "#enums/held-item-id"; import { MoveId } from "#enums/move-id"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; @@ -294,7 +294,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = MysteryEncount const eggOptions = getEggOptions(pokemon1CommonEggs, pokemon1RareEggs); setEncounterRewards( { - guaranteedRewardFuncs: [allRewards.SOOTHE_BELL], + guaranteedRewardSpecs: [HeldItemId.SOOTHE_BELL], fillRemaining: true, }, eggOptions, @@ -353,7 +353,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = MysteryEncount const eggOptions = getEggOptions(pokemon2CommonEggs, pokemon2RareEggs); setEncounterRewards( { - guaranteedRewardFuncs: [allRewards.SOOTHE_BELL], + guaranteedRewardSpecs: [HeldItemId.SOOTHE_BELL], fillRemaining: true, }, eggOptions, @@ -412,7 +412,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = MysteryEncount const eggOptions = getEggOptions(pokemon3CommonEggs, pokemon3RareEggs); setEncounterRewards( { - guaranteedRewardFuncs: [allRewards.SOOTHE_BELL], + guaranteedRewardSpecs: [HeldItemId.SOOTHE_BELL], fillRemaining: true, }, eggOptions, diff --git a/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts b/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts index fd1e6268132..3ce4aeb6412 100644 --- a/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts @@ -1,6 +1,5 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { globalScene } from "#app/global-scene"; -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 +192,7 @@ export const TheStrongStuffEncounter: MysteryEncounter = MysteryEncounterBuilder // Pick battle const encounter = globalScene.currentBattle.mysteryEncounter!; setEncounterRewards({ - guaranteedRewardFuncs: [allRewards.SOUL_DEW], + guaranteedRewardSpecs: [HeldItemId.SOUL_DEW], fillRemaining: true, }); encounter.startOfBattleEffects.push( diff --git a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts index 8c2e422aa35..e6754a5b4bb 100644 --- a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts @@ -11,10 +11,12 @@ 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 { RewardId } from "#enums/reward-id"; 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 type { Reward } from "#items/reward"; +import { generateRewardOptionFromId } from "#items/reward-utils"; import { showEncounterDialogue, showEncounterText } from "#mystery-encounters/encounter-dialogue-utils"; import type { EnemyPartyConfig } from "#mystery-encounters/encounter-phase-utils"; import { @@ -140,7 +142,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({ - guaranteedRewardFuncs: [allRewards.RARER_CANDY], + guaranteedRewardSpecs: [RewardId.RARER_CANDY], fillRemaining: false, }); leaveEncounterWithoutBattle(); @@ -156,14 +158,14 @@ async function spawnNextTrainerOrEndEncounter() { await showEncounterDialogue(`${namespace}:victory`, `${namespace}:speaker`); // Give 10x Voucher - const reward = allRewards.VOUCHER_PREMIUM(); - globalScene.applyReward(reward, {}); + const reward = allRewards[RewardId.VOUCHER_PREMIUM](); + globalScene.applyReward(reward as Reward, {}); globalScene.playSound("item_fanfare"); - await showEncounterText(i18next.t("battle:rewardGain", { modifierName: reward.name })); + await showEncounterText(i18next.t("battle:rewardGain", { modifierName: (reward as Reward).name })); await showEncounterDialogue(`${namespace}:victory_2`, `${namespace}:speaker`); globalScene.ui.clearText(); // Clears "Winstrate" title from screen as allRewards get animated in - const machoBrace = generateRewardOption(allRewards.MYSTERY_ENCOUNTER_MACHO_BRACE)!; + const machoBrace = generateRewardOptionFromId(HeldItemId.MACHO_BRACE)!; machoBrace.type.tier = RarityTier.MASTER; setEncounterRewards({ guaranteedRewardOptions: [machoBrace], diff --git a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts index 9876b47696c..b172748f1ef 100644 --- a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts +++ b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts @@ -1,5 +1,5 @@ import { globalScene } from "#app/global-scene"; -import { allRewards, allSpecies } from "#data/data-lists"; +import { allSpecies } from "#data/data-lists"; import { getLevelTotalExp } from "#data/exp"; import type { PokemonSpecies } from "#data/pokemon-species"; import { Challenges } from "#enums/challenges"; @@ -11,6 +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 { RewardId } from "#enums/reward-id"; import { RarityTier } from "#enums/reward-tier"; import { SpeciesId } from "#enums/species-id"; import { TrainerType } from "#enums/trainer-type"; @@ -218,12 +219,12 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit await doNewTeamPostProcess(transformations); setEncounterRewards({ - guaranteedRewardFuncs: [ - allRewards.MEMORY_MUSHROOM, - allRewards.ROGUE_BALL, - allRewards.MINT, - allRewards.MINT, - allRewards.MINT, + guaranteedRewardSpecs: [ + RewardId.MEMORY_MUSHROOM, + RewardId.ROGUE_BALL, + RewardId.MINT, + RewardId.MINT, + RewardId.MINT, ], fillRemaining: false, }); @@ -242,7 +243,7 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit ], }, async () => { - // Battle your "future" team for some item allRewards + // Battle your "future" team for some item RewardId const transformations: PokemonTransformation[] = globalScene.currentBattle.mysteryEncounter!.misc.teamTransformations; @@ -293,7 +294,7 @@ export const WeirdDreamEncounter: MysteryEncounter = MysteryEncounterBuilder.wit }; const onBeforeRewards = () => { - // Before battle allRewards, unlock the passive on a pokemon in the player's team for the rest of the run (not permanently) + // Before battle RewardId, 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) { diff --git a/src/enums/reward-id.ts b/src/enums/reward-id.ts index 145bad98914..f8179828665 100644 --- a/src/enums/reward-id.ts +++ b/src/enums/reward-id.ts @@ -61,9 +61,10 @@ export const RewardId = { TRAINER_ITEM: 0x2D01, TEMP_STAT_STAGE_BOOSTER: 0x2D02, - LURE: 0x2D03, - SUPER_LURE: 0x2D04, - MAX_LURE: 0x2D05, + DIRE_HIT: 0x2D03, + LURE: 0x2D04, + SUPER_LURE: 0x2D05, + MAX_LURE: 0x2D06, FORM_CHANGE_ITEM: 0x2E01, RARE_FORM_CHANGE_ITEM: 0x2E02, diff --git a/src/init/init.ts b/src/init/init.ts index 35896005b98..4f6731213da 100644 --- a/src/init/init.ts +++ b/src/init/init.ts @@ -7,11 +7,11 @@ import { initChallenges } from "#data/challenge"; import { initTrainerTypeDialogue } from "#data/dialogue"; import { initPokemonForms } from "#data/pokemon-forms"; import { initHeldItems } from "#items/all-held-items"; +import { initRewards } from "#items/all-rewards"; 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 { initRewards } from "#items/reward"; import { initMoves } from "#moves/move"; import { initMysteryEncounters } from "#mystery-encounters/mystery-encounters"; import { initAchievements } from "#system/achv"; diff --git a/src/items/all-held-items.ts b/src/items/all-held-items.ts index fa3c8d8cebe..d505a28bb52 100644 --- a/src/items/all-held-items.ts +++ b/src/items/all-held-items.ts @@ -1,5 +1,6 @@ import { allHeldItems } from "#data/data-lists"; import { BerryType } from "#enums/berry-type"; +import { HeldItemEffect } from "#enums/held-item-effect"; import { HeldItemId } from "#enums/held-item-id"; import type { PokemonType } from "#enums/pokemon-type"; import { SpeciesId } from "#enums/species-id"; @@ -36,7 +37,6 @@ import { SurviveChanceHeldItem, type SurviveChanceParams } from "#items/survive- import { TurnEndHealHeldItem, type TurnEndHealParams } from "#items/turn-end-heal"; import { TurnEndStatusHeldItem, type TurnEndStatusParams } from "#items/turn-end-status"; import { getEnumValues } from "#utils/enums"; -import { HeldItemEffect } from "./HeldItemEffect"; export function initHeldItems() { for (const berry of getEnumValues(BerryType)) { diff --git a/src/items/all-rewards.ts b/src/items/all-rewards.ts new file mode 100644 index 00000000000..4ab8def39a1 --- /dev/null +++ b/src/items/all-rewards.ts @@ -0,0 +1,182 @@ +import { allRewards } from "#data/data-lists"; +import { PokeballType } from "#enums/pokeball"; +import { RewardId } from "#enums/reward-id"; +import { RarityTier } from "#enums/reward-tier"; +import { TrainerItemId } from "#enums/trainer-item-id"; +import { VoucherType } from "#system/voucher"; +import { + AddMoneyReward, + AddPokeballReward, + AddVoucherReward, + AllPokemonFullReviveReward, + AllPokemonLevelIncrementReward, + AttackTypeBoosterRewardGenerator, + BaseStatBoosterRewardGenerator, + BerryRewardGenerator, + EvolutionItemRewardGenerator, + FormChangeItemRewardGenerator, + FusePokemonReward, + LapsingTrainerItemReward, + MintRewardGenerator, + PokemonAllMovePpRestoreReward, + PokemonHpRestoreReward, + PokemonLevelIncrementReward, + PokemonPpRestoreReward, + PokemonPpUpReward, + PokemonReviveReward, + PokemonStatusHealReward, + RememberMoveReward, + SpeciesStatBoosterRewardGenerator, + TempStatStageBoosterRewardGenerator, + TeraTypeRewardGenerator, + TmRewardGenerator, +} from "./reward"; + +export function initRewards() { + // Pokeball rewards + allRewards[RewardId.POKEBALL] = () => new AddPokeballReward("pb", PokeballType.POKEBALL, 5, RewardId.POKEBALL); + allRewards[RewardId.GREAT_BALL] = () => new AddPokeballReward("gb", PokeballType.GREAT_BALL, 5, RewardId.GREAT_BALL); + allRewards[RewardId.ULTRA_BALL] = () => new AddPokeballReward("ub", PokeballType.ULTRA_BALL, 5, RewardId.ULTRA_BALL); + allRewards[RewardId.ROGUE_BALL] = () => new AddPokeballReward("rb", PokeballType.ROGUE_BALL, 5, RewardId.ROGUE_BALL); + allRewards[RewardId.MASTER_BALL] = () => + new AddPokeballReward("mb", PokeballType.MASTER_BALL, 1, RewardId.MASTER_BALL); + + // Voucher rewards + allRewards[RewardId.VOUCHER] = () => new AddVoucherReward(VoucherType.REGULAR, 1, RewardId.VOUCHER); + allRewards[RewardId.VOUCHER_PLUS] = () => new AddVoucherReward(VoucherType.PLUS, 1, RewardId.VOUCHER_PLUS); + allRewards[RewardId.VOUCHER_PREMIUM] = () => new AddVoucherReward(VoucherType.PREMIUM, 1, RewardId.VOUCHER_PREMIUM); + + // Money rewards + allRewards[RewardId.NUGGET] = () => + new AddMoneyReward( + "modifierType:ModifierType.NUGGET", + "nugget", + 1, + "modifierType:ModifierType.MoneyRewardModifierType.extra.small", + RewardId.NUGGET, + ); + allRewards[RewardId.BIG_NUGGET] = () => + new AddMoneyReward( + "modifierType:ModifierType.BIG_NUGGET", + "big_nugget", + 2.5, + "modifierType:ModifierType.MoneyRewardModifierType.extra.moderate", + RewardId.BIG_NUGGET, + ); + allRewards[RewardId.RELIC_GOLD] = () => + new AddMoneyReward( + "modifierType:ModifierType.RELIC_GOLD", + "relic_gold", + 10, + "modifierType:ModifierType.MoneyRewardModifierType.extra.large", + RewardId.RELIC_GOLD, + ); + + // Party-wide consumables + allRewards[RewardId.RARER_CANDY] = () => + new AllPokemonLevelIncrementReward("modifierType:ModifierType.RARER_CANDY", "rarer_candy"); + allRewards[RewardId.SACRED_ASH] = () => + new AllPokemonFullReviveReward("modifierType:ModifierType.SACRED_ASH", "sacred_ash"); + + // Pokemon consumables + allRewards[RewardId.RARE_CANDY] = () => + new PokemonLevelIncrementReward("modifierType:ModifierType.RARE_CANDY", "rare_candy"); + + allRewards[RewardId.EVOLUTION_ITEM] = () => new EvolutionItemRewardGenerator(false, RewardId.EVOLUTION_ITEM); + allRewards[RewardId.RARE_EVOLUTION_ITEM] = () => new EvolutionItemRewardGenerator(true, RewardId.RARE_EVOLUTION_ITEM); + + allRewards[RewardId.POTION] = () => + new PokemonHpRestoreReward("modifierType:ModifierType.POTION", "potion", RewardId.POTION, 20, 10); + allRewards[RewardId.SUPER_POTION] = () => + new PokemonHpRestoreReward("modifierType:ModifierType.SUPER_POTION", "super_potion", RewardId.SUPER_POTION, 50, 25); + allRewards[RewardId.HYPER_POTION] = () => + new PokemonHpRestoreReward( + "modifierType:ModifierType.HYPER_POTION", + "hyper_potion", + RewardId.HYPER_POTION, + 200, + 50, + ); + allRewards[RewardId.MAX_POTION] = () => + new PokemonHpRestoreReward("modifierType:ModifierType.MAX_POTION", "max_potion", RewardId.MAX_POTION, 0, 100); + allRewards[RewardId.FULL_RESTORE] = () => + new PokemonHpRestoreReward( + "modifierType:ModifierType.FULL_RESTORE", + "full_restore", + RewardId.FULL_RESTORE, + 0, + 100, + true, + ); + + allRewards[RewardId.REVIVE] = () => + new PokemonReviveReward("modifierType:ModifierType.REVIVE", "revive", RewardId.REVIVE, 50); + allRewards[RewardId.MAX_REVIVE] = () => + new PokemonReviveReward("modifierType:ModifierType.MAX_REVIVE", "max_revive", RewardId.MAX_REVIVE, 100); + + allRewards[RewardId.FULL_HEAL] = () => + new PokemonStatusHealReward("modifierType:ModifierType.FULL_HEAL", "full_heal"); + + allRewards[RewardId.ETHER] = () => + new PokemonPpRestoreReward("modifierType:ModifierType.ETHER", "ether", RewardId.ETHER, 10); + allRewards[RewardId.MAX_ETHER] = () => + new PokemonPpRestoreReward("modifierType:ModifierType.MAX_ETHER", "max_ether", RewardId.MAX_ETHER, -1); + + allRewards[RewardId.ELIXIR] = () => + new PokemonAllMovePpRestoreReward("modifierType:ModifierType.ELIXIR", "elixir", RewardId.ELIXIR, 10); + allRewards[RewardId.MAX_ELIXIR] = () => + new PokemonAllMovePpRestoreReward("modifierType:ModifierType.MAX_ELIXIR", "max_elixir", RewardId.MAX_ELIXIR, -1); + + allRewards[RewardId.PP_UP] = () => + new PokemonPpUpReward("modifierType:ModifierType.PP_UP", "pp_up", RewardId.PP_UP, 1); + allRewards[RewardId.PP_MAX] = () => + new PokemonPpUpReward("modifierType:ModifierType.PP_MAX", "pp_max", RewardId.PP_MAX, 3); + + /*REPEL] = () => new DoubleBattleChanceBoosterReward('Repel', 5), + SUPER_REPEL] = () => new DoubleBattleChanceBoosterReward('Super Repel', 10), + MAX_REPEL] = () => new DoubleBattleChanceBoosterReward('Max Repel', 25),*/ + + allRewards[RewardId.MINT] = () => new MintRewardGenerator(); + + allRewards[RewardId.TERA_SHARD] = () => new TeraTypeRewardGenerator(); + + allRewards[RewardId.TM_COMMON] = () => new TmRewardGenerator(RarityTier.COMMON); + allRewards[RewardId.TM_GREAT] = () => new TmRewardGenerator(RarityTier.GREAT); + allRewards[RewardId.TM_ULTRA] = () => new TmRewardGenerator(RarityTier.ULTRA); + + allRewards[RewardId.MEMORY_MUSHROOM] = () => + new RememberMoveReward("modifierType:ModifierType.MEMORY_MUSHROOM", "big_mushroom"); + + allRewards[RewardId.DNA_SPLICERS] = () => + new FusePokemonReward("modifierType:ModifierType.DNA_SPLICERS", "dna_splicers"); + + // Form change items + allRewards[RewardId.FORM_CHANGE_ITEM] = () => new FormChangeItemRewardGenerator(false, RewardId.FORM_CHANGE_ITEM); + allRewards[RewardId.RARE_FORM_CHANGE_ITEM] = () => + new FormChangeItemRewardGenerator(true, RewardId.RARE_FORM_CHANGE_ITEM); + + // Held items + + allRewards[RewardId.SPECIES_STAT_BOOSTER] = () => new SpeciesStatBoosterRewardGenerator(false); + allRewards[RewardId.RARE_SPECIES_STAT_BOOSTER] = () => new SpeciesStatBoosterRewardGenerator(true); + + allRewards[RewardId.BASE_STAT_BOOSTER] = () => new BaseStatBoosterRewardGenerator(); + + allRewards[RewardId.ATTACK_TYPE_BOOSTER] = () => new AttackTypeBoosterRewardGenerator(); + + allRewards[RewardId.BERRY] = () => new BerryRewardGenerator(); + + // MINI_BLACK_HOLE] = () => new HeldItemReward(HeldItemId.MINI_BLACK_HOLE), + + // Trainer items + + allRewards[RewardId.LURE] = () => new LapsingTrainerItemReward(TrainerItemId.LURE, RewardId.LURE); + allRewards[RewardId.SUPER_LURE] = () => new LapsingTrainerItemReward(TrainerItemId.SUPER_LURE, RewardId.SUPER_LURE); + allRewards[RewardId.MAX_LURE] = () => new LapsingTrainerItemReward(TrainerItemId.MAX_LURE, RewardId.MAX_LURE); + + allRewards[RewardId.TEMP_STAT_STAGE_BOOSTER] = () => new TempStatStageBoosterRewardGenerator(); + + allRewards[RewardId.DIRE_HIT] = () => + new LapsingTrainerItemReward(TrainerItemId.DIRE_HIT, RewardId.TEMP_STAT_STAGE_BOOSTER); + // GOLDEN_POKEBALL] = () => new TrainerItemReward(TrainerItemId.GOLDEN_POKEBALL), +} diff --git a/src/items/init-reward-pools.ts b/src/items/init-reward-pools.ts index ec1f8ee50ff..0517e4421cd 100644 --- a/src/items/init-reward-pools.ts +++ b/src/items/init-reward-pools.ts @@ -1,23 +1,23 @@ /* biome-ignore-start lint/correctness/noUnusedImports: tsdoc imports */ -import type { initRewards, Reward } from "#items/reward"; +import { 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, allRewards, allTrainerItems } from "#data/data-lists"; +import { allHeldItems, 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 { RewardId } from "#enums/reward-id"; 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 type { WeightedRewardWeightFunc } from "#types/rewards"; @@ -28,33 +28,33 @@ import { isNullOrUndefined } from "#utils/common"; */ 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[]) => { + { id: RewardId.POKEBALL, weight: () => (hasMaximumBalls(PokeballType.POKEBALL) ? 0 : 6), maxWeight: 6 }, + { id: RewardId.RARE_CANDY, weight: 2 }, + { + id: RewardId.POTION, + weight: (party: Pokemon[]) => { const thresholdPartyMemberCount = Math.min( party.filter(p => p.getInverseHp() >= 10 && p.getHpRatio() <= 0.875 && !p.isFainted()).length, 3, ); return thresholdPartyMemberCount * 3; }, - 9, - ), - new WeightedReward( - allRewards.SUPER_POTION, - (party: Pokemon[]) => { + maxWeight: 9, + }, + { + id: RewardId.SUPER_POTION, + weight: (party: Pokemon[]) => { const thresholdPartyMemberCount = Math.min( party.filter(p => p.getInverseHp() >= 25 && p.getHpRatio() <= 0.75 && !p.isFainted()).length, 3, ); return thresholdPartyMemberCount; }, - 3, - ), - new WeightedReward( - allRewards.ETHER, - (party: Pokemon[]) => { + maxWeight: 3, + }, + { + id: RewardId.ETHER, + weight: (party: Pokemon[]) => { const thresholdPartyMemberCount = Math.min( party.filter( p => @@ -69,11 +69,11 @@ function initCommonRewardPool() { ); return thresholdPartyMemberCount * 3; }, - 9, - ), - new WeightedReward( - allRewards.MAX_ETHER, - (party: Pokemon[]) => { + maxWeight: 9, + }, + { + id: RewardId.MAX_ETHER, + weight: (party: Pokemon[]) => { const thresholdPartyMemberCount = Math.min( party.filter( p => @@ -88,12 +88,12 @@ function initCommonRewardPool() { ); return thresholdPartyMemberCount; }, - 3, - ), - 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), + maxWeight: 3, + }, + { id: RewardId.LURE, weight: lureWeightFunc(TrainerItemId.LURE, 2) }, + { id: RewardId.TEMP_STAT_STAGE_BOOSTER, weight: 4 }, + { id: RewardId.BERRY, weight: 2 }, + { id: RewardId.TM_COMMON, weight: 2 }, ]; } @@ -102,11 +102,11 @@ function initCommonRewardPool() { */ 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[]) => { + { id: RewardId.GREAT_BALL, weight: () => (hasMaximumBalls(PokeballType.GREAT_BALL) ? 0 : 6), maxWeight: 6 }, + { id: RewardId.PP_UP, weight: 2 }, + { + id: RewardId.FULL_HEAL, + weight: (party: Pokemon[]) => { const statusEffectPartyMemberCount = Math.min( party.filter( p => @@ -121,56 +121,56 @@ function initGreatRewardPool() { ); return statusEffectPartyMemberCount * 6; }, - 18, - ), - new WeightedReward( - allRewards.REVIVE, - (party: Pokemon[]) => { + maxWeight: 18, + }, + { + id: RewardId.REVIVE, + weight: (party: Pokemon[]) => { const faintedPartyMemberCount = Math.min(party.filter(p => p.isFainted()).length, 3); return faintedPartyMemberCount * 9; }, - 27, - ), - new WeightedReward( - allRewards.MAX_REVIVE, - (party: Pokemon[]) => { + maxWeight: 27, + }, + { + id: RewardId.MAX_REVIVE, + weight: (party: Pokemon[]) => { const faintedPartyMemberCount = Math.min(party.filter(p => p.isFainted()).length, 3); return faintedPartyMemberCount * 3; }, - 9, - ), - new WeightedReward( - allRewards.SACRED_ASH, - (party: Pokemon[]) => { + maxWeight: 9, + }, + { + id: RewardId.SACRED_ASH, + weight: (party: Pokemon[]) => { return party.filter(p => p.isFainted()).length >= Math.ceil(party.length / 2) ? 1 : 0; }, - 1, - ), - new WeightedReward( - allRewards.HYPER_POTION, - (party: Pokemon[]) => { + maxWeight: 1, + }, + { + id: RewardId.HYPER_POTION, + weight: (party: Pokemon[]) => { const thresholdPartyMemberCount = Math.min( party.filter(p => p.getInverseHp() >= 100 && p.getHpRatio() <= 0.625 && !p.isFainted()).length, 3, ); return thresholdPartyMemberCount * 3; }, - 9, - ), - new WeightedReward( - allRewards.MAX_POTION, - (party: Pokemon[]) => { + maxWeight: 9, + }, + { + id: RewardId.MAX_POTION, + weight: (party: Pokemon[]) => { const thresholdPartyMemberCount = Math.min( party.filter(p => p.getInverseHp() >= 100 && p.getHpRatio() <= 0.5 && !p.isFainted()).length, 3, ); return thresholdPartyMemberCount; }, - 3, - ), - new WeightedReward( - allRewards.FULL_RESTORE, - (party: Pokemon[]) => { + maxWeight: 3, + }, + { + id: RewardId.FULL_RESTORE, + weight: (party: Pokemon[]) => { const statusEffectPartyMemberCount = Math.min( party.filter( p => @@ -190,11 +190,11 @@ function initGreatRewardPool() { ); return thresholdPartyMemberCount; }, - 3, - ), - new WeightedReward( - allRewards.ELIXIR, - (party: Pokemon[]) => { + maxWeight: 3, + }, + { + id: RewardId.ELIXIR, + weight: (party: Pokemon[]) => { const thresholdPartyMemberCount = Math.min( party.filter( p => @@ -209,11 +209,11 @@ function initGreatRewardPool() { ); return thresholdPartyMemberCount * 3; }, - 9, - ), - new WeightedReward( - allRewards.MAX_ELIXIR, - (party: Pokemon[]) => { + maxWeight: 9, + }, + { + id: RewardId.MAX_ELIXIR, + weight: (party: Pokemon[]) => { const thresholdPartyMemberCount = Math.min( party.filter( p => @@ -228,29 +228,29 @@ function initGreatRewardPool() { ); return thresholdPartyMemberCount; }, - 3, - ), - 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, - () => { + maxWeight: 3, + }, + { id: RewardId.DIRE_HIT, weight: 4 }, + { id: RewardId.SUPER_LURE, weight: lureWeightFunc(TrainerItemId.SUPER_LURE, 4) }, + { id: RewardId.NUGGET, weight: skipInLastClassicWaveOrDefault(5) }, + { id: RewardId.SPECIES_STAT_BOOSTER, weight: 4 }, + { + id: RewardId.EVOLUTION_ITEM, + weight: () => { return Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 15), 8); }, - 8, - ), - new WeightedReward( - allRewards.MAP, - () => (globalScene.gameMode.isClassic && globalScene.currentBattle.waveIndex < 180 ? 2 : 0), - 2, - ), - new WeightedReward(allRewards.SOOTHE_BELL, 2), - new WeightedReward(allRewards.TM_GREAT, 3), - new WeightedReward( - allRewards.MEMORY_MUSHROOM, - (party: Pokemon[]) => { + maxWeight: 8, + }, + { + id: TrainerItemId.MAP, + weight: () => (globalScene.gameMode.isClassic && globalScene.currentBattle.waveIndex < 180 ? 2 : 0), + maxWeight: 2, + }, + { id: HeldItemId.SOOTHE_BELL, weight: 2 }, + { id: RewardId.TM_GREAT, weight: 3 }, + { + id: RewardId.MEMORY_MUSHROOM, + weight: (party: Pokemon[]) => { if (!party.find(p => p.getLearnableLevelMoves().length)) { return 0; } @@ -259,20 +259,22 @@ function initGreatRewardPool() { .reduce((highestLevel: number, level: number) => Math.max(highestLevel, level), 1); return Math.min(Math.ceil(highestPartyLevel / 20), 4); }, - 4, - ), - 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)), - ).length > 0 - ? 1 - : 0, - ), - new WeightedReward( - allRewards.DNA_SPLICERS, - (party: Pokemon[]) => { + maxWeight: 4, + }, + { id: RewardId.BASE_STAT_BOOSTER, weight: 3 }, + { + id: RewardId.TERA_SHARD, + weight: (party: Pokemon[]) => + party.filter( + p => + !(p.hasSpecies(SpeciesId.TERAPAGOS) || p.hasSpecies(SpeciesId.OGERPON) || p.hasSpecies(SpeciesId.SHEDINJA)), + ).length > 0 + ? 1 + : 0, + }, + { + id: RewardId.DNA_SPLICERS, + weight: (party: Pokemon[]) => { if (party.filter(p => !p.fusionSpecies).length > 1) { if (globalScene.gameMode.isSplicedOnly) { return 4; @@ -283,13 +285,14 @@ function initGreatRewardPool() { } return 0; }, - 4, - ), - new WeightedReward( - allRewards.VOUCHER, - (_party: Pokemon[], rerollCount: number) => (!globalScene.gameMode.isDaily ? Math.max(1 - rerollCount, 0) : 0), - 1, - ), + maxWeight: 4, + }, + { + id: RewardId.VOUCHER, + weight: (_party: Pokemon[], rerollCount: number) => + !globalScene.gameMode.isDaily ? Math.max(1 - rerollCount, 0) : 0, + maxWeight: 1, + }, ]; } @@ -298,46 +301,49 @@ function initGreatRewardPool() { */ 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 WeightedReward( - allRewards.FORM_CHANGE_ITEM, - () => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 6, - 24, - ), - 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 => { - // Check if Pokemon's species (or fusion species, if applicable) can evolve or if they're G-Max'd - if ( - !p.isMax() && - (p.getSpeciesForm(true).speciesId in pokemonEvolutions || - (p.isFusion() && p.getFusionSpeciesForm(true).speciesId in pokemonEvolutions)) - ) { - // Check if Pokemon is already holding an Eviolite - return !p.heldItemManager.hasItem(HeldItemId.EVIOLITE); - } - return false; - }) - ? 10 - : 0; - } - return 0; - }), - new WeightedReward(allRewards.RARE_SPECIES_STAT_BOOSTER, 12), - new WeightedReward( - allRewards.LEEK, - (party: Pokemon[]) => { + { id: RewardId.ULTRA_BALL, weight: () => (hasMaximumBalls(PokeballType.ULTRA_BALL) ? 0 : 15), maxWeight: 15 }, + { id: RewardId.MAX_LURE, weight: lureWeightFunc(TrainerItemId.MAX_LURE, 4) }, + { id: RewardId.BIG_NUGGET, weight: skipInLastClassicWaveOrDefault(12) }, + { id: RewardId.PP_MAX, weight: 3 }, + { id: RewardId.MINT, weight: 4 }, + { + id: RewardId.RARE_EVOLUTION_ITEM, + weight: () => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 15) * 4, 32), + maxWeight: 32, + }, + { + id: RewardId.FORM_CHANGE_ITEM, + weight: () => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 6, + maxWeight: 24, + }, + { id: TrainerItemId.AMULET_COIN, weight: skipInLastClassicWaveOrDefault(3) }, + { + id: HeldItemId.EVIOLITE, + weight: (party: Pokemon[]) => { + const { gameMode, gameData } = globalScene; + if (gameMode.isDaily || (!gameMode.isFreshStartChallenge() && gameData.isUnlocked(Unlockables.EVIOLITE))) { + return party.some(p => { + // Check if Pokemon's species (or fusion species, if applicable) can evolve or if they're G-Max'd + if ( + !p.isMax() && + (p.getSpeciesForm(true).speciesId in pokemonEvolutions || + (p.isFusion() && p.getFusionSpeciesForm(true).speciesId in pokemonEvolutions)) + ) { + // Check if Pokemon is already holding an Eviolite + return !p.heldItemManager.hasItem(HeldItemId.EVIOLITE); + } + return false; + }) + ? 10 + : 0; + } + return 0; + }, + }, + { id: RewardId.RARE_SPECIES_STAT_BOOSTER, weight: 12 }, + { + id: HeldItemId.LEEK, + weight: (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 return party.some( @@ -349,11 +355,11 @@ function initUltraRewardPool() { ? 12 : 0; }, - 12, - ), - new WeightedReward( - allRewards.TOXIC_ORB, - (party: Pokemon[]) => { + maxWeight: 12, + }, + { + id: HeldItemId.TOXIC_ORB, + weight: (party: Pokemon[]) => { return party.some(p => { const isHoldingOrb = p.getHeldItems().some(i => i in [HeldItemId.FLAME_ORB, HeldItemId.TOXIC_ORB]); @@ -395,11 +401,11 @@ function initUltraRewardPool() { ? 10 : 0; }, - 10, - ), - new WeightedReward( - allRewards.FLAME_ORB, - (party: Pokemon[]) => { + maxWeight: 10, + }, + { + id: HeldItemId.FLAME_ORB, + weight: (party: Pokemon[]) => { return party.some(p => { const isHoldingOrb = p.getHeldItems().some(i => i in [HeldItemId.FLAME_ORB, HeldItemId.TOXIC_ORB]); @@ -441,11 +447,11 @@ function initUltraRewardPool() { ? 10 : 0; }, - 10, - ), - new WeightedReward( - allRewards.MYSTICAL_ROCK, - (party: Pokemon[]) => { + maxWeight: 10, + }, + { + id: HeldItemId.MYSTICAL_ROCK, + weight: (party: Pokemon[]) => { return party.some(p => { const stack = p.heldItemManager.getStack(HeldItemId.MYSTICAL_ROCK); const isHoldingMax = stack === allHeldItems[HeldItemId.MYSTICAL_ROCK].maxStackCount; @@ -488,68 +494,68 @@ function initUltraRewardPool() { ? 10 : 0; }, - 10, - ), - 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, - () => + maxWeight: 10, + }, + { id: HeldItemId.REVIVER_SEED, weight: 4 }, + { id: TrainerItemId.CANDY_JAR, weight: skipInLastClassicWaveOrDefault(5) }, + { id: RewardId.ATTACK_TYPE_BOOSTER, weight: 9 }, + { id: RewardId.TM_ULTRA, weight: 11 }, + { id: RewardId.RARER_CANDY, weight: 4 }, + { id: HeldItemId.GOLDEN_PUNCH, weight: skipInLastClassicWaveOrDefault(2) }, + { id: TrainerItemId.IV_SCANNER, weight: skipInLastClassicWaveOrDefault(4) }, + { id: TrainerItemId.EXP_CHARM, weight: skipInLastClassicWaveOrDefault(8) }, + { id: TrainerItemId.EXP_SHARE, weight: skipInLastClassicWaveOrDefault(10) }, + { + id: TrainerItemId.TERA_ORB, + weight: () => !globalScene.gameMode.isClassic ? Math.min(Math.max(Math.floor(globalScene.currentBattle.waveIndex / 50) * 2, 1), 4) : 0, - 4, - ), - new WeightedReward(allRewards.QUICK_CLAW, 3), - new WeightedReward(allRewards.WIDE_LENS, 7), + maxWeight: 4, + }, + { id: HeldItemId.QUICK_CLAW, weight: 3 }, + { id: HeldItemId.WIDE_LENS, weight: 7 }, ]; } 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 WeightedReward( - allRewards.MEGA_BRACELET, - () => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 9, - 36, - ), - new WeightedReward( - allRewards.DYNAMAX_BAND, - () => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 9, - 36, - ), - new WeightedReward( - allRewards.VOUCHER_PLUS, - (_party: Pokemon[], rerollCount: number) => + { id: RewardId.ROGUE_BALL, weight: () => (hasMaximumBalls(PokeballType.ROGUE_BALL) ? 0 : 16), maxWeight: 16 }, + { id: RewardId.RELIC_GOLD, weight: skipInLastClassicWaveOrDefault(2) }, + { id: HeldItemId.LEFTOVERS, weight: 3 }, + { id: HeldItemId.SHELL_BELL, weight: 3 }, + { id: TrainerItemId.BERRY_POUCH, weight: 4 }, + { id: HeldItemId.GRIP_CLAW, weight: 5 }, + { id: HeldItemId.SCOPE_LENS, weight: 4 }, + { id: HeldItemId.BATON, weight: 2 }, + { id: HeldItemId.SOUL_DEW, weight: 7 }, + { id: TrainerItemId.CATCHING_CHARM, weight: () => (!globalScene.gameMode.isClassic ? 4 : 0), maxWeight: 4 }, + { id: TrainerItemId.ABILITY_CHARM, weight: skipInClassicAfterWave(189, 6) }, + { id: HeldItemId.FOCUS_BAND, weight: 5 }, + { id: HeldItemId.KINGS_ROCK, weight: 3 }, + { id: TrainerItemId.LOCK_CAPSULE, weight: () => (globalScene.gameMode.isClassic ? 0 : 3) }, + { id: TrainerItemId.SUPER_EXP_CHARM, weight: skipInLastClassicWaveOrDefault(8) }, + { + id: RewardId.RARE_FORM_CHANGE_ITEM, + weight: () => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 6, + maxWeight: 24, + }, + { + id: TrainerItemId.MEGA_BRACELET, + weight: () => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 9, + maxWeight: 36, + }, + { + id: TrainerItemId.DYNAMAX_BAND, + weight: () => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 9, + maxWeight: 36, + }, + { + id: RewardId.VOUCHER_PLUS, + weight: (_party: Pokemon[], rerollCount: number) => !globalScene.gameMode.isDaily ? Math.max(3 - rerollCount * 1, 0) : 0, - 3, - ), + maxWeight: 3, + }, ]; } @@ -558,37 +564,37 @@ function initRogueRewardPool() { */ 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) => + { id: RewardId.MASTER_BALL, weight: () => (hasMaximumBalls(PokeballType.MASTER_BALL) ? 0 : 24), maxWeight: 24 }, + { id: TrainerItemId.SHINY_CHARM, weight: 14 }, + { id: TrainerItemId.HEALING_CHARM, weight: 18 }, + { id: HeldItemId.MULTI_LENS, weight: 18 }, + { + id: RewardId.VOUCHER_PREMIUM, + weight: (_party: Pokemon[], rerollCount: number) => !globalScene.gameMode.isDaily && !globalScene.gameMode.isEndless && !globalScene.gameMode.isSplicedOnly ? Math.max(5 - rerollCount * 2, 0) : 0, - 5, - ), - new WeightedReward( - allRewards.DNA_SPLICERS, - (party: Pokemon[]) => + maxWeight: 5, + }, + { + id: RewardId.DNA_SPLICERS, + weight: (party: Pokemon[]) => !(globalScene.gameMode.isClassic && timedEventManager.areFusionsBoosted()) && !globalScene.gameMode.isSplicedOnly && party.filter(p => !p.fusionSpecies).length > 1 ? 24 : 0, - 24, - ), - new WeightedReward( - allRewards.MINI_BLACK_HOLE, - () => + maxWeight: 24, + }, + { + id: HeldItemId.MINI_BLACK_HOLE, + weight: () => globalScene.gameMode.isDaily || (!globalScene.gameMode.isFreshStartChallenge() && globalScene.gameData.isUnlocked(Unlockables.MINI_BLACK_HOLE)) ? 1 : 0, - 1, - ), + maxWeight: 1, + }, ]; } diff --git a/src/items/reward-pool-utils.ts b/src/items/reward-pool-utils.ts index 7a9886a76f2..4ad5df55b9a 100644 --- a/src/items/reward-pool-utils.ts +++ b/src/items/reward-pool-utils.ts @@ -1,15 +1,14 @@ 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 type { RewardPool, RewardPoolWeights, RewardSpecs } 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 type { RewardOption } from "./reward"; import { rewardPool, rewardPoolWeights } from "./reward-pools"; -import { getRewardDefaultTier } from "./reward-utils"; +import { generateRewardOptionFromId, generateRewardOptionFromSpecs, isTrainerItemId } from "./reward-utils"; /* This file still contains several functions to generate rewards from pools. The hierarchy of these functions is explained here. @@ -26,9 +25,6 @@ cases to assign modifiers. This usage is now deprecated, as we have separate poo 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. */ @@ -36,7 +32,7 @@ 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[]; + guaranteedRewardSpecs?: RewardSpecs[]; /** * 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 @@ -68,9 +64,8 @@ export interface CustomRewardSettings { 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)) { + if (isTrainerItemId(w.id)) { + if (globalScene.trainerItems.isMaxStack(w.id)) { return 0; } } @@ -158,26 +153,18 @@ export function generatePlayerRewardOptions( options.push(getRewardOptionWithRetry(pool, weights, options, retryCount, party, tier)); } } else { - // Guaranteed mod options first + // Guaranteed reward 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); + if (customRewardSettings?.guaranteedRewardSpecs && customRewardSettings.guaranteedRewardSpecs.length > 0) { + for (const specs of customRewardSettings.guaranteedRewardSpecs) { + const rewardOption = generateRewardOptionFromSpecs(specs); + if (rewardOption) { + options.push(rewardOption); } - }); + } } // Guaranteed tiers third @@ -285,42 +272,30 @@ function getNewRewardOption( 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); - } + const rewardOption = generateRewardOptionFromId(pool[tier][index].id, 0, tier, upgradeCount); + if (rewardOption === null) { + console.log(RarityTier[tier], upgradeCount); + return getNewRewardOption(pool, weights, party, tier, upgradeCount, ++retryCount); } - console.log(reward); + console.log(rewardOption); - return new RewardOption(reward as Reward, upgradeCount!, tier); // TODO: is this bang correct? + return rewardOption; } /** * 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[]) { +export function overridePlayerRewardOptions(options: RewardOption[]) { 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); + const specs: RewardSpecs = Overrides.REWARD_OVERRIDE[i]; + const rewardOption = generateRewardOptionFromSpecs(specs); + if (rewardOption) { + options[i] = rewardOption; } } } diff --git a/src/items/reward-utils.ts b/src/items/reward-utils.ts index f9872738fe9..7f229b65c94 100644 --- a/src/items/reward-utils.ts +++ b/src/items/reward-utils.ts @@ -4,20 +4,20 @@ 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 { RewardFunc, RewardPoolId, RewardSpecs } from "#types/rewards"; +import { heldItemRarities } from "./held-item-default-tiers"; import { - type HeldItemReward, + HeldItemReward, type PokemonMoveReward, type RememberMoveReward, type Reward, RewardGenerator, RewardOption, type TmReward, - type TrainerItemReward, + TrainerItemReward, } from "./reward"; -import { getRewardTier } from "./reward-defaults-tiers"; -import { getTrainerItemTier } from "./trainer-item-default-tiers"; +import { rewardRarities } from "./reward-defaults-tiers"; +import { trainerItemRarities } from "./trainer-item-default-tiers"; export function isTmReward(reward: Reward): reward is TmReward { return getRewardCategory(reward.id) === RewardCategoryId.TM; @@ -42,33 +42,43 @@ export function generateReward(rewardFunc: RewardFunc, pregenArgs?: any[]): Rewa 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 { +export function generateRewardOptionFromId( + id: RewardPoolId, + cost = 0, + tierOverride?: RarityTier, + upgradeCount = 0, + pregenArgs?: any[], +): RewardOption | null { + if (isHeldItemId(id)) { + const reward = new HeldItemReward(id); + const tier = tierOverride ?? heldItemRarities[id]; + return new RewardOption(reward, upgradeCount, tier, cost); + } + + if (isTrainerItemId(id)) { + const reward = new TrainerItemReward(id); + const tier = tierOverride ?? trainerItemRarities[id]; + return new RewardOption(reward, upgradeCount, tier, cost); + } + + const rewardFunc = allRewards[id]; const reward = generateReward(rewardFunc, pregenArgs); if (reward) { - const tier = getRewardDefaultTier(reward); - return new RewardOption(reward, 0, tier); + const tier = tierOverride ?? rewardRarities[id]; + return new RewardOption(reward, upgradeCount, tier, cost); } 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); +export function generateRewardOptionFromSpecs( + specs: RewardSpecs, + cost = 0, + overrideTier?: RarityTier, +): RewardOption | null { + if (typeof specs === "number") { + return generateRewardOptionFromId(specs, cost, overrideTier); } - if (reward.id === RewardId.TRAINER_ITEM) { - return getTrainerItemTier((reward as TrainerItemReward).itemId); - } - return getRewardTier(reward.id); + return generateRewardOptionFromId(specs.id, cost, overrideTier, 0, specs.args); } export function getPlayerShopRewardOptionsForWave(waveIndex: number, baseCost: number): RewardOption[] { @@ -78,26 +88,26 @@ export function getPlayerShopRewardOptionsForWave(waveIndex: number, baseCost: n 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), + generateRewardOptionFromId(RewardId.POTION, baseCost * 0.2), + generateRewardOptionFromId(RewardId.ETHER, baseCost * 0.4), + generateRewardOptionFromId(RewardId.REVIVE, baseCost * 2), ], [ - new RewardOption(allRewards.SUPER_POTION(), 0, baseCost * 0.45), - new RewardOption(allRewards.FULL_HEAL(), 0, baseCost), + generateRewardOptionFromId(RewardId.SUPER_POTION, baseCost * 0.45), + generateRewardOptionFromId(RewardId.FULL_HEAL, baseCost), ], - [new RewardOption(allRewards.ELIXIR(), 0, baseCost), new RewardOption(allRewards.MAX_ETHER(), 0, baseCost)], + [generateRewardOptionFromId(RewardId.ELIXIR, baseCost), generateRewardOptionFromId(RewardId.MAX_ETHER, 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), + generateRewardOptionFromId(RewardId.HYPER_POTION, baseCost * 0.8), + generateRewardOptionFromId(RewardId.MAX_REVIVE, baseCost * 2.75), + generateRewardOptionFromId(RewardId.MEMORY_MUSHROOM, baseCost * 4), ], [ - new RewardOption(allRewards.MAX_POTION(), 0, baseCost * 1.5), - new RewardOption(allRewards.MAX_ELIXIR(), 0, baseCost * 2.5), + generateRewardOptionFromId(RewardId.MAX_POTION, baseCost * 1.5), + generateRewardOptionFromId(RewardId.MAX_ELIXIR, baseCost * 2.5), ], - [new RewardOption(allRewards.FULL_RESTORE(), 0, baseCost * 2.25)], - [new RewardOption(allRewards.SACRED_ASH(), 0, baseCost * 10)], + [generateRewardOptionFromId(RewardId.FULL_RESTORE, baseCost * 2.25)], + [generateRewardOptionFromId(RewardId.SACRED_ASH, baseCost * 10)], ]; return options.slice(0, Math.ceil(Math.max(waveIndex + 10, 0) / 30)).flat(); } diff --git a/src/items/reward.ts b/src/items/reward.ts index 244b80e1314..b4fcc9a1735 100644 --- a/src/items/reward.ts +++ b/src/items/reward.ts @@ -4,7 +4,7 @@ import { getPokemonNameWithAffix } from "#app/messages"; import { EvolutionItem, FusionSpeciesFormEvolution, pokemonEvolutions } from "#balance/pokemon-evolutions"; import { FRIENDSHIP_GAIN_FROM_RARE_CANDY } from "#balance/starters"; import { tmPoolTiers, tmSpecies } from "#balance/tms"; -import { allHeldItems, allMoves, allRewards, allTrainerItems } from "#data/data-lists"; +import { allHeldItems, allMoves, allTrainerItems } from "#data/data-lists"; import { getLevelTotalExp } from "#data/exp"; import { SpeciesFormChangeItemTrigger } from "#data/form-change-triggers"; import { getNatureName, getNatureStatMultiplier } from "#data/nature"; @@ -17,7 +17,7 @@ import { HeldItemId } from "#enums/held-item-id"; import { LearnMoveType } from "#enums/learn-move-type"; import { MoveId } from "#enums/move-id"; import { Nature } from "#enums/nature"; -import { PokeballType } from "#enums/pokeball"; +import type { PokeballType } from "#enums/pokeball"; import { PokemonType } from "#enums/pokemon-type"; import { RewardId } from "#enums/reward-id"; import { RarityTier } from "#enums/reward-tier"; @@ -32,15 +32,10 @@ import { permanentStatToHeldItem, statBoostItems } from "#items/base-stat-booste import { berryTypeToHeldItem } from "#items/berry"; import { getNewAttackTypeBoosterHeldItem, getNewBerryHeldItem, getNewVitaminHeldItem } from "#items/held-item-pool"; import { formChangeItemName } from "#items/item-utility"; -import { - SPECIES_STAT_BOOSTER_ITEMS, - type SpeciesStatBoosterItemId, - type SpeciesStatBoostHeldItem, -} from "#items/stat-booster"; +import { SPECIES_STAT_BOOSTER_ITEMS, type SpeciesStatBoostHeldItem } from "#items/stat-booster"; import { TrainerItemEffect, tempStatToTrainerItem } from "#items/trainer-item"; import type { PokemonMove } from "#moves/pokemon-move"; -import { getVoucherTypeIcon, getVoucherTypeName, VoucherType } from "#system/voucher"; -import type { RewardFunc, WeightedRewardWeightFunc } from "#types/rewards"; +import { getVoucherTypeIcon, getVoucherTypeName, type VoucherType } from "#system/voucher"; import type { Exact } from "#types/type-helpers"; import type { PokemonMoveSelectFilter, PokemonSelectFilter } from "#ui/party-ui-handler"; import { PartyUiHandler } from "#ui/party-ui-handler"; @@ -90,7 +85,6 @@ for example. The entries of rewardInitObj are used in the RewardPool. There are some more derived classes, in particular: RewardGenerator, which creates Reward instances from a certain group (e.g. TMs, nature mints, or berries); -WeightedReward, which is a Reward with an attached weight or weight function to be used in pools; and RewardOption, which is displayed during the select reward phase at the end of each encounter. */ @@ -589,7 +583,7 @@ export class PokemonReviveReward extends PokemonHpRestoreReward { } } -class AllPokemonFullReviveReward extends Reward { +export class AllPokemonFullReviveReward extends Reward { constructor(localeKey: string, iconImage: string) { super(localeKey, iconImage, "modifierType:ModifierType.AllPokemonFullReviveModifierType"); this.id = RewardId.SACRED_ASH; @@ -863,7 +857,7 @@ export class RememberMoveReward extends PokemonReward { } } -class BerryRewardGenerator extends RewardGenerator { +export class BerryRewardGenerator extends RewardGenerator { constructor() { super((_party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs && pregenArgs.length === 1 && pregenArgs[0] in BerryType) { @@ -877,7 +871,7 @@ class BerryRewardGenerator extends RewardGenerator { } } -class MintRewardGenerator extends RewardGenerator { +export class MintRewardGenerator extends RewardGenerator { constructor() { super((_party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs && pregenArgs.length === 1 && pregenArgs[0] in Nature) { @@ -889,7 +883,7 @@ class MintRewardGenerator extends RewardGenerator { } } -class TeraTypeRewardGenerator extends RewardGenerator { +export class TeraTypeRewardGenerator extends RewardGenerator { constructor() { super((party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs && pregenArgs.length === 1 && pregenArgs[0] in PokemonType) { @@ -1225,7 +1219,7 @@ export class FusePokemonReward extends PokemonReward { } } -class AttackTypeBoosterRewardGenerator extends RewardGenerator { +export class AttackTypeBoosterRewardGenerator extends RewardGenerator { constructor() { super((party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs && pregenArgs.length === 1 && pregenArgs[0] in PokemonType) { @@ -1240,7 +1234,7 @@ class AttackTypeBoosterRewardGenerator extends RewardGenerator { } } -class BaseStatBoosterRewardGenerator extends RewardGenerator { +export class BaseStatBoosterRewardGenerator extends RewardGenerator { constructor() { super((_party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs) { @@ -1252,7 +1246,7 @@ class BaseStatBoosterRewardGenerator extends RewardGenerator { } } -class TempStatStageBoosterRewardGenerator extends RewardGenerator { +export class TempStatStageBoosterRewardGenerator extends RewardGenerator { public static readonly items: Record = { [Stat.ATK]: "x_attack", [Stat.DEF]: "x_defense", @@ -1280,7 +1274,7 @@ class TempStatStageBoosterRewardGenerator extends RewardGenerator { * the current list of {@linkcode items}. * @extends RewardGenerator */ -class SpeciesStatBoosterRewardGenerator extends RewardGenerator { +export class SpeciesStatBoosterRewardGenerator extends RewardGenerator { /** Object comprised of the currently available species-based stat boosting held items */ constructor(rare: boolean) { @@ -1347,7 +1341,7 @@ class SpeciesStatBoosterRewardGenerator extends RewardGenerator { } } -class TmRewardGenerator extends RewardGenerator { +export class TmRewardGenerator extends RewardGenerator { constructor(tier: RarityTier) { super((party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs && pregenArgs.length === 1 && pregenArgs[0] in MoveId) { @@ -1380,7 +1374,7 @@ class TmRewardGenerator extends RewardGenerator { } } -class EvolutionItemRewardGenerator extends RewardGenerator { +export class EvolutionItemRewardGenerator extends RewardGenerator { constructor(rare: boolean, id: RewardId) { super((party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs && pregenArgs.length === 1 && pregenArgs[0] in EvolutionItem) { @@ -1512,305 +1506,6 @@ export class FormChangeItemRewardGenerator extends RewardGenerator { } } -export class WeightedReward { - public reward: Reward | RewardGenerator; - public weight: number | WeightedRewardWeightFunc; - public maxWeight: number | WeightedRewardWeightFunc; - - constructor( - rewardFunc: RewardFunc, - weight: number | WeightedRewardWeightFunc, - maxWeight?: number | WeightedRewardWeightFunc, - ) { - this.reward = rewardFunc(); - this.weight = weight; - this.maxWeight = maxWeight || (!(weight instanceof Function) ? weight : 0); - } -} - -type BaseRewardOverride = { - name: Exclude; - count?: number; -}; - -/** Type for modifiers and held items that are constructed via {@linkcode RewardGenerator}. */ -export type GeneratorRewardOverride = { - count?: number; -} & ( - | { - name: keyof Pick; - type?: SpeciesStatBoosterItemId; - } - | { - name: keyof Pick; - type?: TempBattleStat; - } - | { - name: keyof Pick; - type?: Stat; - } - | { - name: keyof Pick; - type?: Nature; - } - | { - name: keyof Pick; - type?: PokemonType; - } - | { - name: keyof Pick; - type?: BerryType; - } - | { - name: keyof Pick; - type?: EvolutionItem; - } - | { - name: keyof Pick; - type?: FormChangeItem; - } - | { - name: keyof Pick; - type?: MoveId; - } -); - -/** Type used to construct modifiers and held items for overriding purposes. */ -export type RewardOverride = GeneratorRewardOverride | BaseRewardOverride; - -const rewardInitObj = Object.freeze({ - // Pokeball rewards - POKEBALL: () => new AddPokeballReward("pb", PokeballType.POKEBALL, 5, RewardId.POKEBALL), - GREAT_BALL: () => new AddPokeballReward("gb", PokeballType.GREAT_BALL, 5, RewardId.GREAT_BALL), - ULTRA_BALL: () => new AddPokeballReward("ub", PokeballType.ULTRA_BALL, 5, RewardId.ULTRA_BALL), - ROGUE_BALL: () => new AddPokeballReward("rb", PokeballType.ROGUE_BALL, 5, RewardId.ROGUE_BALL), - MASTER_BALL: () => new AddPokeballReward("mb", PokeballType.MASTER_BALL, 1, RewardId.MASTER_BALL), - - // Voucher rewards - VOUCHER: () => new AddVoucherReward(VoucherType.REGULAR, 1, RewardId.VOUCHER), - VOUCHER_PLUS: () => new AddVoucherReward(VoucherType.PLUS, 1, RewardId.VOUCHER_PLUS), - VOUCHER_PREMIUM: () => new AddVoucherReward(VoucherType.PREMIUM, 1, RewardId.VOUCHER_PREMIUM), - - // Money rewards - NUGGET: () => - new AddMoneyReward( - "modifierType:ModifierType.NUGGET", - "nugget", - 1, - "modifierType:ModifierType.MoneyRewardModifierType.extra.small", - RewardId.NUGGET, - ), - BIG_NUGGET: () => - new AddMoneyReward( - "modifierType:ModifierType.BIG_NUGGET", - "big_nugget", - 2.5, - "modifierType:ModifierType.MoneyRewardModifierType.extra.moderate", - RewardId.BIG_NUGGET, - ), - RELIC_GOLD: () => - new AddMoneyReward( - "modifierType:ModifierType.RELIC_GOLD", - "relic_gold", - 10, - "modifierType:ModifierType.MoneyRewardModifierType.extra.large", - RewardId.RELIC_GOLD, - ), - - // Party-wide consumables - RARER_CANDY: () => new AllPokemonLevelIncrementReward("modifierType:ModifierType.RARER_CANDY", "rarer_candy"), - SACRED_ASH: () => new AllPokemonFullReviveReward("modifierType:ModifierType.SACRED_ASH", "sacred_ash"), - - // Pokemon consumables - RARE_CANDY: () => new PokemonLevelIncrementReward("modifierType:ModifierType.RARE_CANDY", "rare_candy"), - - EVOLUTION_ITEM: () => new EvolutionItemRewardGenerator(false, RewardId.EVOLUTION_ITEM), - RARE_EVOLUTION_ITEM: () => new EvolutionItemRewardGenerator(true, RewardId.RARE_EVOLUTION_ITEM), - - POTION: () => new PokemonHpRestoreReward("modifierType:ModifierType.POTION", "potion", RewardId.POTION, 20, 10), - SUPER_POTION: () => - new PokemonHpRestoreReward("modifierType:ModifierType.SUPER_POTION", "super_potion", RewardId.SUPER_POTION, 50, 25), - HYPER_POTION: () => - new PokemonHpRestoreReward( - "modifierType:ModifierType.HYPER_POTION", - "hyper_potion", - RewardId.HYPER_POTION, - 200, - 50, - ), - MAX_POTION: () => - new PokemonHpRestoreReward("modifierType:ModifierType.MAX_POTION", "max_potion", RewardId.MAX_POTION, 0, 100), - FULL_RESTORE: () => - new PokemonHpRestoreReward( - "modifierType:ModifierType.FULL_RESTORE", - "full_restore", - RewardId.FULL_RESTORE, - 0, - 100, - true, - ), - - REVIVE: () => new PokemonReviveReward("modifierType:ModifierType.REVIVE", "revive", RewardId.REVIVE, 50), - MAX_REVIVE: () => - new PokemonReviveReward("modifierType:ModifierType.MAX_REVIVE", "max_revive", RewardId.MAX_REVIVE, 100), - - FULL_HEAL: () => new PokemonStatusHealReward("modifierType:ModifierType.FULL_HEAL", "full_heal"), - - ETHER: () => new PokemonPpRestoreReward("modifierType:ModifierType.ETHER", "ether", RewardId.ETHER, 10), - MAX_ETHER: () => - new PokemonPpRestoreReward("modifierType:ModifierType.MAX_ETHER", "max_ether", RewardId.MAX_ETHER, -1), - - ELIXIR: () => new PokemonAllMovePpRestoreReward("modifierType:ModifierType.ELIXIR", "elixir", RewardId.ELIXIR, 10), - MAX_ELIXIR: () => - new PokemonAllMovePpRestoreReward("modifierType:ModifierType.MAX_ELIXIR", "max_elixir", RewardId.MAX_ELIXIR, -1), - - PP_UP: () => new PokemonPpUpReward("modifierType:ModifierType.PP_UP", "pp_up", RewardId.PP_UP, 1), - PP_MAX: () => new PokemonPpUpReward("modifierType:ModifierType.PP_MAX", "pp_max", RewardId.PP_MAX, 3), - - /*REPEL: () => new DoubleBattleChanceBoosterReward('Repel', 5), - SUPER_REPEL: () => new DoubleBattleChanceBoosterReward('Super Repel', 10), - MAX_REPEL: () => new DoubleBattleChanceBoosterReward('Max Repel', 25),*/ - - MINT: () => new MintRewardGenerator(), - - TERA_SHARD: () => new TeraTypeRewardGenerator(), - - TM_COMMON: () => new TmRewardGenerator(RarityTier.COMMON), - TM_GREAT: () => new TmRewardGenerator(RarityTier.GREAT), - TM_ULTRA: () => new TmRewardGenerator(RarityTier.ULTRA), - - MEMORY_MUSHROOM: () => new RememberMoveReward("modifierType:ModifierType.MEMORY_MUSHROOM", "big_mushroom"), - - DNA_SPLICERS: () => new FusePokemonReward("modifierType:ModifierType.DNA_SPLICERS", "dna_splicers"), - - // Form change items - FORM_CHANGE_ITEM: () => new FormChangeItemRewardGenerator(false, RewardId.FORM_CHANGE_ITEM), - RARE_FORM_CHANGE_ITEM: () => new FormChangeItemRewardGenerator(true, RewardId.RARE_FORM_CHANGE_ITEM), - - // Held items - REVIVER_SEED: () => new HeldItemReward(HeldItemId.REVIVER_SEED), - - WHITE_HERB: () => new HeldItemReward(HeldItemId.WHITE_HERB), - - SPECIES_STAT_BOOSTER: () => new SpeciesStatBoosterRewardGenerator(false), - RARE_SPECIES_STAT_BOOSTER: () => new SpeciesStatBoosterRewardGenerator(true), - - BASE_STAT_BOOSTER: () => new BaseStatBoosterRewardGenerator(), - - ATTACK_TYPE_BOOSTER: () => new AttackTypeBoosterRewardGenerator(), - - MYSTICAL_ROCK: () => new HeldItemReward(HeldItemId.MYSTICAL_ROCK), - - BERRY: () => new BerryRewardGenerator(), - - LUCKY_EGG: () => new HeldItemReward(HeldItemId.LUCKY_EGG), - GOLDEN_EGG: () => new HeldItemReward(HeldItemId.GOLDEN_EGG), - - SOOTHE_BELL: () => new HeldItemReward(HeldItemId.SOOTHE_BELL), - - SCOPE_LENS: () => new HeldItemReward(HeldItemId.SCOPE_LENS), - LEEK: () => new HeldItemReward(HeldItemId.LEEK), - - EVIOLITE: () => new HeldItemReward(HeldItemId.EVIOLITE), - - SOUL_DEW: () => new HeldItemReward(HeldItemId.SOUL_DEW), - - GOLDEN_PUNCH: () => new HeldItemReward(HeldItemId.GOLDEN_PUNCH), - - GRIP_CLAW: () => new HeldItemReward(HeldItemId.GRIP_CLAW), - WIDE_LENS: () => new HeldItemReward(HeldItemId.WIDE_LENS), - - MULTI_LENS: () => new HeldItemReward(HeldItemId.MULTI_LENS), - - FOCUS_BAND: () => new HeldItemReward(HeldItemId.FOCUS_BAND), - - QUICK_CLAW: () => new HeldItemReward(HeldItemId.QUICK_CLAW), - - KINGS_ROCK: () => new HeldItemReward(HeldItemId.KINGS_ROCK), - - LEFTOVERS: () => new HeldItemReward(HeldItemId.LEFTOVERS), - - SHELL_BELL: () => new HeldItemReward(HeldItemId.SHELL_BELL), - - TOXIC_ORB: () => new HeldItemReward(HeldItemId.TOXIC_ORB), - - FLAME_ORB: () => new HeldItemReward(HeldItemId.FLAME_ORB), - - BATON: () => new HeldItemReward(HeldItemId.BATON), - - MINI_BLACK_HOLE: () => new HeldItemReward(HeldItemId.MINI_BLACK_HOLE), - - // Trainer items - MEGA_BRACELET: () => new TrainerItemReward(TrainerItemId.MEGA_BRACELET), - DYNAMAX_BAND: () => new TrainerItemReward(TrainerItemId.DYNAMAX_BAND), - TERA_ORB: () => new TrainerItemReward(TrainerItemId.TERA_ORB), - - MAP: () => new TrainerItemReward(TrainerItemId.MAP), - - LURE: () => new LapsingTrainerItemReward(TrainerItemId.LURE, RewardId.LURE), - SUPER_LURE: () => new LapsingTrainerItemReward(TrainerItemId.SUPER_LURE, RewardId.SUPER_LURE), - MAX_LURE: () => new LapsingTrainerItemReward(TrainerItemId.MAX_LURE, RewardId.MAX_LURE), - - TEMP_STAT_STAGE_BOOSTER: () => new TempStatStageBoosterRewardGenerator(), - - DIRE_HIT: () => new LapsingTrainerItemReward(TrainerItemId.DIRE_HIT, RewardId.TEMP_STAT_STAGE_BOOSTER), - - EXP_SHARE: () => new TrainerItemReward(TrainerItemId.EXP_SHARE), - EXP_BALANCE: () => new TrainerItemReward(TrainerItemId.EXP_BALANCE), - - OVAL_CHARM: () => new TrainerItemReward(TrainerItemId.OVAL_CHARM), - - EXP_CHARM: () => new TrainerItemReward(TrainerItemId.EXP_CHARM), - SUPER_EXP_CHARM: () => new TrainerItemReward(TrainerItemId.SUPER_EXP_CHARM), - - AMULET_COIN: () => new TrainerItemReward(TrainerItemId.AMULET_COIN), - - LOCK_CAPSULE: () => new TrainerItemReward(TrainerItemId.LOCK_CAPSULE), - - HEALING_CHARM: () => new TrainerItemReward(TrainerItemId.HEALING_CHARM), - CANDY_JAR: () => new TrainerItemReward(TrainerItemId.CANDY_JAR), - - BERRY_POUCH: () => new TrainerItemReward(TrainerItemId.BERRY_POUCH), - - SHINY_CHARM: () => new TrainerItemReward(TrainerItemId.SHINY_CHARM), - ABILITY_CHARM: () => new TrainerItemReward(TrainerItemId.ABILITY_CHARM), - CATCHING_CHARM: () => new TrainerItemReward(TrainerItemId.CATCHING_CHARM), - - IV_SCANNER: () => new TrainerItemReward(TrainerItemId.IV_SCANNER), - - GOLDEN_POKEBALL: () => new TrainerItemReward(TrainerItemId.GOLDEN_POKEBALL), - - // Tokens //TODO: do we even need them here? - ENEMY_DAMAGE_BOOSTER: () => new TrainerItemReward(TrainerItemId.ENEMY_DAMAGE_BOOSTER), - ENEMY_DAMAGE_REDUCTION: () => new TrainerItemReward(TrainerItemId.ENEMY_DAMAGE_REDUCTION), - //ENEMY_SUPER_EFFECT_BOOSTER: () => new Reward('Type Advantage Token', 'Increases damage of super effective attacks by 30%', (type, _args) => new EnemySuperEffectiveDamageBoosterModifier(type, 30), 'wl_custom_super_effective'), - ENEMY_HEAL: () => new TrainerItemReward(TrainerItemId.ENEMY_HEAL), - ENEMY_ATTACK_POISON_CHANCE: () => new TrainerItemReward(TrainerItemId.ENEMY_ATTACK_POISON_CHANCE), - ENEMY_ATTACK_PARALYZE_CHANCE: () => new TrainerItemReward(TrainerItemId.ENEMY_ATTACK_PARALYZE_CHANCE), - ENEMY_ATTACK_BURN_CHANCE: () => new TrainerItemReward(TrainerItemId.ENEMY_ATTACK_BURN_CHANCE), - ENEMY_STATUS_EFFECT_HEAL_CHANCE: () => new TrainerItemReward(TrainerItemId.ENEMY_STATUS_EFFECT_HEAL_CHANCE), - ENEMY_ENDURE_CHANCE: () => new TrainerItemReward(TrainerItemId.ENEMY_ENDURE_CHANCE), - ENEMY_FUSED_CHANCE: () => new TrainerItemReward(TrainerItemId.ENEMY_FUSED_CHANCE), - - // Items from mystery encounters - MYSTERY_ENCOUNTER_SHUCKLE_JUICE_GOOD: () => new HeldItemReward(HeldItemId.SHUCKLE_JUICE_GOOD), - MYSTERY_ENCOUNTER_SHUCKLE_JUICE_BAD: () => new HeldItemReward(HeldItemId.SHUCKLE_JUICE_BAD), - - MYSTERY_ENCOUNTER_OLD_GATEAU: () => new HeldItemReward(HeldItemId.OLD_GATEAU), - - MYSTERY_ENCOUNTER_BLACK_SLUDGE: () => new TrainerItemReward(TrainerItemId.BLACK_SLUDGE), - - MYSTERY_ENCOUNTER_MACHO_BRACE: () => new HeldItemReward(HeldItemId.MACHO_BRACE), - - MYSTERY_ENCOUNTER_GOLDEN_BUG_NET: () => new TrainerItemReward(TrainerItemId.GOLDEN_BUG_NET), -}); - -/** - * The initial set of modifier types, used to generate the modifier pool. - */ -export type Rewards = typeof rewardInitObj; -export type RewardKeys = keyof typeof rewardInitObj; - export class RewardOption { public type: Reward; public upgradeCount: number; @@ -1825,12 +1520,6 @@ export class RewardOption { } } -export function initRewards() { - for (const [key, value] of Object.entries(rewardInitObj)) { - allRewards[key] = value; - } -} - // TODO: If necessary, add the rest of the modifier types here. // For now, doing the minimal work until the modifier rework lands. const RewardConstructorMap = Object.freeze({ diff --git a/src/overrides.ts b/src/overrides.ts index 3a96a1c7bea..a21ae28b3a2 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -22,9 +22,9 @@ import { Unlockables } from "#enums/unlockables"; import { VariantTier } from "#enums/variant-tier"; import { WeatherType } from "#enums/weather-type"; import { HeldItemConfiguration } from "#items/held-item-data-types"; -import { type RewardOverride } from "#items/reward"; import { TrainerItemConfiguration } from "#items/trainer-item-data-types"; import { Variant } from "#sprites/variant"; +import { RewardSpecs } from "#types/rewards"; /** * This comment block exists to prevent IDEs from automatically removing unused imports @@ -273,25 +273,18 @@ class DefaultOverrides { * STARTING_HELD_ITEM_OVERRIDE = [{name: "BERRY"}] * ``` */ - /** Override array of {@linkcode RewardOverride}s used to provide held items to first party member when starting a new game. */ readonly STARTING_TRAINER_ITEMS_OVERRIDE: TrainerItemConfiguration = []; - /** Override array of {@linkcode RewardOverride}s used to provide held items to enemies on spawn. */ readonly OPP_TRAINER_ITEMS_OVERRIDE: TrainerItemConfiguration = []; - - /** Override array of {@linkcode RewardOverride}s used to provide held items to first party member when starting a new game. */ readonly STARTING_HELD_ITEMS_OVERRIDE: HeldItemConfiguration = []; - /** Override array of {@linkcode RewardOverride}s used to provide held items to enemies on spawn. */ readonly OPP_HELD_ITEMS_OVERRIDE: HeldItemConfiguration = []; /** - * Override array of {@linkcode RewardOverride}s used to replace the generated reward rolls after a wave. - * * If less entries are listed than rolled, only those entries will be used to replace the corresponding items while the rest randomly generated. * If more entries are listed than rolled, only the first X entries will be used, where X is the number of items rolled. * * Note that, for all items in the array, `count` is not used. */ - readonly REWARD_OVERRIDE: RewardOverride[] = []; + readonly REWARD_OVERRIDE: RewardSpecs[] = []; /** * If `true`, disable all non-scripted opponent trainer encounters. diff --git a/src/phases/select-reward-phase.ts b/src/phases/select-reward-phase.ts index 4c5e080733c..e552b209666 100644 --- a/src/phases/select-reward-phase.ts +++ b/src/phases/select-reward-phase.ts @@ -373,7 +373,7 @@ export class SelectRewardPhase extends BattlePhase { const newItemCount = (this.customRewardSettings.guaranteedRarityTiers?.length ?? 0) + (this.customRewardSettings.guaranteedRewardOptions?.length ?? 0) + - (this.customRewardSettings.guaranteedRewardFuncs?.length ?? 0); + (this.customRewardSettings.guaranteedRewardSpecs?.length ?? 0); if (this.customRewardSettings.fillRemaining) { const originalCount = rewardCountHolder.value; rewardCountHolder.value = originalCount > newItemCount ? originalCount : newItemCount; diff --git a/test/phases/select-reward-phase.test.ts b/test/phases/select-reward-phase.test.ts index ed664cf1aff..9bd17f434db 100644 --- a/test/phases/select-reward-phase.test.ts +++ b/test/phases/select-reward-phase.test.ts @@ -155,7 +155,7 @@ describe("SelectRewardPhase", () => { await game.classicMode.startBattle([SpeciesId.ABRA, SpeciesId.VOLCARONA]); scene.money = 1000000; const customRewards: CustomRewardSettings = { - guaranteedRewardFuncs: [ + guaranteedRewardSpecs: [ allRewards.MEMORY_MUSHROOM, allRewards.TM_ULTRA, allRewards.LEFTOVERS, @@ -238,7 +238,7 @@ describe("SelectRewardPhase", () => { await game.classicMode.startBattle([SpeciesId.ABRA, SpeciesId.VOLCARONA]); scene.money = 1000000; const customRewards: CustomRewardSettings = { - guaranteedRewardFuncs: [allRewards.MEMORY_MUSHROOM, allRewards.TM_COMMON], + guaranteedRewardSpecs: [allRewards.MEMORY_MUSHROOM, allRewards.TM_COMMON], guaranteedRarityTiers: [RarityTier.MASTER, RarityTier.MASTER], }; const selectRewardPhase = new SelectRewardPhase(0, undefined, customRewards); @@ -261,7 +261,7 @@ describe("SelectRewardPhase", () => { await game.classicMode.startBattle([SpeciesId.ABRA, SpeciesId.VOLCARONA]); scene.money = 1000000; const customRewards: CustomRewardSettings = { - guaranteedRewardFuncs: [allRewards.MEMORY_MUSHROOM], + guaranteedRewardSpecs: [allRewards.MEMORY_MUSHROOM], guaranteedRarityTiers: [RarityTier.MASTER], fillRemaining: true, }; diff --git a/test/test-utils/helpers/overrides-helper.ts b/test/test-utils/helpers/overrides-helper.ts index ec4519753fc..e02d63c1804 100644 --- a/test/test-utils/helpers/overrides-helper.ts +++ b/test/test-utils/helpers/overrides-helper.ts @@ -18,10 +18,10 @@ import { StatusEffect } from "#enums/status-effect"; import type { Unlockables } from "#enums/unlockables"; import { WeatherType } from "#enums/weather-type"; import type { HeldItemConfiguration } from "#items/held-item-data-types"; -import type { RewardOverride } from "#items/reward"; import type { TrainerItemConfiguration } from "#items/trainer-item-data-types"; import type { Variant } from "#sprites/variant"; import { GameManagerHelper } from "#test/test-utils/helpers/game-manager-helper"; +import type { RewardSpecs } from "#types/rewards"; import { coerceArray, shiftCharCodes } from "#utils/common"; import { vi } from "vitest"; @@ -557,7 +557,7 @@ export class OverridesHelper extends GameManagerHelper { * @param items - The items to be rolled * @returns `this` */ - public itemRewards(items: RewardOverride[]): this { + public rewards(items: RewardSpecs[]): this { vi.spyOn(Overrides, "REWARD_OVERRIDE", "get").mockReturnValue(items); this.log("Item allRewards set to:", items); return this;