RewardPool now uses ids; function to generate appropriate reward from id (including held item or trainer item)

This commit is contained in:
Wlowscha 2025-08-04 00:14:21 +02:00
parent c41fdc746f
commit b293b9063e
No known key found for this signature in database
GPG Key ID: 3C8F1AD330565D04
3 changed files with 273 additions and 260 deletions

View File

@ -12,6 +12,7 @@ export type RewardPoolId = RewardId | HeldItemId | TrainerItemId;
export type RewardPoolEntry = { export type RewardPoolEntry = {
id: RewardPoolId; id: RewardPoolId;
weight: number | WeightedRewardWeightFunc; weight: number | WeightedRewardWeightFunc;
maxWeight?: number;
}; };
export type RewardPool = { export type RewardPool = {

View File

@ -1,23 +1,23 @@
/* biome-ignore-start lint/correctness/noUnusedImports: tsdoc imports */ /* 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 */ /* biome-ignore-end lint/correctness/noUnusedImports: tsdoc imports */
import { timedEventManager } from "#app/global-event-manager"; import { timedEventManager } from "#app/global-event-manager";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { pokemonEvolutions } from "#balance/pokemon-evolutions"; 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 { MAX_PER_TYPE_POKEBALLS } from "#data/pokeball";
import { AbilityId } from "#enums/ability-id"; import { AbilityId } from "#enums/ability-id";
import { HeldItemId } from "#enums/held-item-id"; import { HeldItemId } from "#enums/held-item-id";
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
import { PokeballType } from "#enums/pokeball"; import { PokeballType } from "#enums/pokeball";
import { RewardId } from "#enums/reward-id";
import { RarityTier } from "#enums/reward-tier"; import { RarityTier } from "#enums/reward-tier";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import { TrainerItemId } from "#enums/trainer-item-id"; import { TrainerItemId } from "#enums/trainer-item-id";
import { Unlockables } from "#enums/unlockables"; import { Unlockables } from "#enums/unlockables";
import type { Pokemon } from "#field/pokemon"; import type { Pokemon } from "#field/pokemon";
import { WeightedReward } from "#items/reward";
import { rewardPool } from "#items/reward-pools"; import { rewardPool } from "#items/reward-pools";
import type { TurnEndStatusHeldItem } from "#items/turn-end-status"; import type { TurnEndStatusHeldItem } from "#items/turn-end-status";
import type { WeightedRewardWeightFunc } from "#types/rewards"; import type { WeightedRewardWeightFunc } from "#types/rewards";
@ -28,33 +28,33 @@ import { isNullOrUndefined } from "#utils/common";
*/ */
function initCommonRewardPool() { function initCommonRewardPool() {
rewardPool[RarityTier.COMMON] = [ rewardPool[RarityTier.COMMON] = [
new WeightedReward(allRewards.POKEBALL, () => (hasMaximumBalls(PokeballType.POKEBALL) ? 0 : 6), 6), { id: RewardId.POKEBALL, weight: () => (hasMaximumBalls(PokeballType.POKEBALL) ? 0 : 6), maxWeight: 6 },
new WeightedReward(allRewards.RARE_CANDY, 2), { id: RewardId.RARE_CANDY, weight: 2 },
new WeightedReward( {
allRewards.POTION, id: RewardId.POTION,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min( const thresholdPartyMemberCount = Math.min(
party.filter(p => p.getInverseHp() >= 10 && p.getHpRatio() <= 0.875 && !p.isFainted()).length, party.filter(p => p.getInverseHp() >= 10 && p.getHpRatio() <= 0.875 && !p.isFainted()).length,
3, 3,
); );
return thresholdPartyMemberCount * 3; return thresholdPartyMemberCount * 3;
}, },
9, maxWeight: 9,
), },
new WeightedReward( {
allRewards.SUPER_POTION, id: RewardId.SUPER_POTION,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min( const thresholdPartyMemberCount = Math.min(
party.filter(p => p.getInverseHp() >= 25 && p.getHpRatio() <= 0.75 && !p.isFainted()).length, party.filter(p => p.getInverseHp() >= 25 && p.getHpRatio() <= 0.75 && !p.isFainted()).length,
3, 3,
); );
return thresholdPartyMemberCount; return thresholdPartyMemberCount;
}, },
3, maxWeight: 3,
), },
new WeightedReward( {
allRewards.ETHER, id: RewardId.ETHER,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min( const thresholdPartyMemberCount = Math.min(
party.filter( party.filter(
p => p =>
@ -69,11 +69,11 @@ function initCommonRewardPool() {
); );
return thresholdPartyMemberCount * 3; return thresholdPartyMemberCount * 3;
}, },
9, maxWeight: 9,
), },
new WeightedReward( {
allRewards.MAX_ETHER, id: RewardId.MAX_ETHER,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min( const thresholdPartyMemberCount = Math.min(
party.filter( party.filter(
p => p =>
@ -88,12 +88,12 @@ function initCommonRewardPool() {
); );
return thresholdPartyMemberCount; return thresholdPartyMemberCount;
}, },
3, maxWeight: 3,
), },
new WeightedReward(allRewards.LURE, lureWeightFunc(TrainerItemId.LURE, 2)), { id: RewardId.LURE, weight: lureWeightFunc(TrainerItemId.LURE, 2) },
new WeightedReward(allRewards.TEMP_STAT_STAGE_BOOSTER, 4), { id: RewardId.TEMP_STAT_STAGE_BOOSTER, weight: 4 },
new WeightedReward(allRewards.BERRY, 2), { id: RewardId.BERRY, weight: 2 },
new WeightedReward(allRewards.TM_COMMON, 2), { id: RewardId.TM_COMMON, weight: 2 },
]; ];
} }
@ -102,11 +102,11 @@ function initCommonRewardPool() {
*/ */
function initGreatRewardPool() { function initGreatRewardPool() {
rewardPool[RarityTier.GREAT] = [ rewardPool[RarityTier.GREAT] = [
new WeightedReward(allRewards.GREAT_BALL, () => (hasMaximumBalls(PokeballType.GREAT_BALL) ? 0 : 6), 6), { id: RewardId.GREAT_BALL, weight: () => (hasMaximumBalls(PokeballType.GREAT_BALL) ? 0 : 6), maxWeight: 6 },
new WeightedReward(allRewards.PP_UP, 2), { id: RewardId.PP_UP, weight: 2 },
new WeightedReward( {
allRewards.FULL_HEAL, id: RewardId.FULL_HEAL,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
const statusEffectPartyMemberCount = Math.min( const statusEffectPartyMemberCount = Math.min(
party.filter( party.filter(
p => p =>
@ -121,56 +121,56 @@ function initGreatRewardPool() {
); );
return statusEffectPartyMemberCount * 6; return statusEffectPartyMemberCount * 6;
}, },
18, maxWeight: 18,
), },
new WeightedReward( {
allRewards.REVIVE, id: RewardId.REVIVE,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
const faintedPartyMemberCount = Math.min(party.filter(p => p.isFainted()).length, 3); const faintedPartyMemberCount = Math.min(party.filter(p => p.isFainted()).length, 3);
return faintedPartyMemberCount * 9; return faintedPartyMemberCount * 9;
}, },
27, maxWeight: 27,
), },
new WeightedReward( {
allRewards.MAX_REVIVE, id: RewardId.MAX_REVIVE,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
const faintedPartyMemberCount = Math.min(party.filter(p => p.isFainted()).length, 3); const faintedPartyMemberCount = Math.min(party.filter(p => p.isFainted()).length, 3);
return faintedPartyMemberCount * 3; return faintedPartyMemberCount * 3;
}, },
9, maxWeight: 9,
), },
new WeightedReward( {
allRewards.SACRED_ASH, id: RewardId.SACRED_ASH,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
return party.filter(p => p.isFainted()).length >= Math.ceil(party.length / 2) ? 1 : 0; return party.filter(p => p.isFainted()).length >= Math.ceil(party.length / 2) ? 1 : 0;
}, },
1, maxWeight: 1,
), },
new WeightedReward( {
allRewards.HYPER_POTION, id: RewardId.HYPER_POTION,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min( const thresholdPartyMemberCount = Math.min(
party.filter(p => p.getInverseHp() >= 100 && p.getHpRatio() <= 0.625 && !p.isFainted()).length, party.filter(p => p.getInverseHp() >= 100 && p.getHpRatio() <= 0.625 && !p.isFainted()).length,
3, 3,
); );
return thresholdPartyMemberCount * 3; return thresholdPartyMemberCount * 3;
}, },
9, maxWeight: 9,
), },
new WeightedReward( {
allRewards.MAX_POTION, id: RewardId.MAX_POTION,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min( const thresholdPartyMemberCount = Math.min(
party.filter(p => p.getInverseHp() >= 100 && p.getHpRatio() <= 0.5 && !p.isFainted()).length, party.filter(p => p.getInverseHp() >= 100 && p.getHpRatio() <= 0.5 && !p.isFainted()).length,
3, 3,
); );
return thresholdPartyMemberCount; return thresholdPartyMemberCount;
}, },
3, maxWeight: 3,
), },
new WeightedReward( {
allRewards.FULL_RESTORE, id: RewardId.FULL_RESTORE,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
const statusEffectPartyMemberCount = Math.min( const statusEffectPartyMemberCount = Math.min(
party.filter( party.filter(
p => p =>
@ -190,11 +190,11 @@ function initGreatRewardPool() {
); );
return thresholdPartyMemberCount; return thresholdPartyMemberCount;
}, },
3, maxWeight: 3,
), },
new WeightedReward( {
allRewards.ELIXIR, id: RewardId.ELIXIR,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min( const thresholdPartyMemberCount = Math.min(
party.filter( party.filter(
p => p =>
@ -209,11 +209,11 @@ function initGreatRewardPool() {
); );
return thresholdPartyMemberCount * 3; return thresholdPartyMemberCount * 3;
}, },
9, maxWeight: 9,
), },
new WeightedReward( {
allRewards.MAX_ELIXIR, id: RewardId.MAX_ELIXIR,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min( const thresholdPartyMemberCount = Math.min(
party.filter( party.filter(
p => p =>
@ -228,29 +228,29 @@ function initGreatRewardPool() {
); );
return thresholdPartyMemberCount; return thresholdPartyMemberCount;
}, },
3, maxWeight: 3,
), },
new WeightedReward(allRewards.DIRE_HIT, 4), { id: RewardId.DIRE_HIT, weight: 4 },
new WeightedReward(allRewards.SUPER_LURE, lureWeightFunc(TrainerItemId.SUPER_LURE, 4)), { id: RewardId.SUPER_LURE, weight: lureWeightFunc(TrainerItemId.SUPER_LURE, 4) },
new WeightedReward(allRewards.NUGGET, skipInLastClassicWaveOrDefault(5)), { id: RewardId.NUGGET, weight: skipInLastClassicWaveOrDefault(5) },
new WeightedReward(allRewards.SPECIES_STAT_BOOSTER, 4), { id: RewardId.SPECIES_STAT_BOOSTER, weight: 4 },
new WeightedReward( {
allRewards.EVOLUTION_ITEM, id: RewardId.EVOLUTION_ITEM,
() => { weight: () => {
return Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 15), 8); return Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 15), 8);
}, },
8, maxWeight: 8,
), },
new WeightedReward( {
allRewards.MAP, id: TrainerItemId.MAP,
() => (globalScene.gameMode.isClassic && globalScene.currentBattle.waveIndex < 180 ? 2 : 0), weight: () => (globalScene.gameMode.isClassic && globalScene.currentBattle.waveIndex < 180 ? 2 : 0),
2, maxWeight: 2,
), },
new WeightedReward(allRewards.SOOTHE_BELL, 2), { id: HeldItemId.SOOTHE_BELL, weight: 2 },
new WeightedReward(allRewards.TM_GREAT, 3), { id: RewardId.TM_GREAT, weight: 3 },
new WeightedReward( {
allRewards.MEMORY_MUSHROOM, id: RewardId.MEMORY_MUSHROOM,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
if (!party.find(p => p.getLearnableLevelMoves().length)) { if (!party.find(p => p.getLearnableLevelMoves().length)) {
return 0; return 0;
} }
@ -259,20 +259,22 @@ function initGreatRewardPool() {
.reduce((highestLevel: number, level: number) => Math.max(highestLevel, level), 1); .reduce((highestLevel: number, level: number) => Math.max(highestLevel, level), 1);
return Math.min(Math.ceil(highestPartyLevel / 20), 4); return Math.min(Math.ceil(highestPartyLevel / 20), 4);
}, },
4, maxWeight: 4,
), },
new WeightedReward(allRewards.BASE_STAT_BOOSTER, 3), { id: RewardId.BASE_STAT_BOOSTER, weight: 3 },
new WeightedReward(allRewards.TERA_SHARD, (party: Pokemon[]) => {
id: RewardId.TERA_SHARD,
weight: (party: Pokemon[]) =>
party.filter( party.filter(
p => p =>
!(p.hasSpecies(SpeciesId.TERAPAGOS) || p.hasSpecies(SpeciesId.OGERPON) || p.hasSpecies(SpeciesId.SHEDINJA)), !(p.hasSpecies(SpeciesId.TERAPAGOS) || p.hasSpecies(SpeciesId.OGERPON) || p.hasSpecies(SpeciesId.SHEDINJA)),
).length > 0 ).length > 0
? 1 ? 1
: 0, : 0,
), },
new WeightedReward( {
allRewards.DNA_SPLICERS, id: RewardId.DNA_SPLICERS,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
if (party.filter(p => !p.fusionSpecies).length > 1) { if (party.filter(p => !p.fusionSpecies).length > 1) {
if (globalScene.gameMode.isSplicedOnly) { if (globalScene.gameMode.isSplicedOnly) {
return 4; return 4;
@ -283,13 +285,14 @@ function initGreatRewardPool() {
} }
return 0; return 0;
}, },
4, maxWeight: 4,
), },
new WeightedReward( {
allRewards.VOUCHER, id: RewardId.VOUCHER,
(_party: Pokemon[], rerollCount: number) => (!globalScene.gameMode.isDaily ? Math.max(1 - rerollCount, 0) : 0), weight: (_party: Pokemon[], rerollCount: number) =>
1, !globalScene.gameMode.isDaily ? Math.max(1 - rerollCount, 0) : 0,
), maxWeight: 1,
},
]; ];
} }
@ -298,23 +301,25 @@ function initGreatRewardPool() {
*/ */
function initUltraRewardPool() { function initUltraRewardPool() {
rewardPool[RarityTier.ULTRA] = [ rewardPool[RarityTier.ULTRA] = [
new WeightedReward(allRewards.ULTRA_BALL, () => (hasMaximumBalls(PokeballType.ULTRA_BALL) ? 0 : 15), 15), { id: RewardId.ULTRA_BALL, weight: () => (hasMaximumBalls(PokeballType.ULTRA_BALL) ? 0 : 15), maxWeight: 15 },
new WeightedReward(allRewards.MAX_LURE, lureWeightFunc(TrainerItemId.MAX_LURE, 4)), { id: RewardId.MAX_LURE, weight: lureWeightFunc(TrainerItemId.MAX_LURE, 4) },
new WeightedReward(allRewards.BIG_NUGGET, skipInLastClassicWaveOrDefault(12)), { id: RewardId.BIG_NUGGET, weight: skipInLastClassicWaveOrDefault(12) },
new WeightedReward(allRewards.PP_MAX, 3), { id: RewardId.PP_MAX, weight: 3 },
new WeightedReward(allRewards.MINT, 4), { id: RewardId.MINT, weight: 4 },
new WeightedReward( {
allRewards.RARE_EVOLUTION_ITEM, id: RewardId.RARE_EVOLUTION_ITEM,
() => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 15) * 4, 32), weight: () => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 15) * 4, 32),
32, maxWeight: 32,
), },
new WeightedReward( {
allRewards.FORM_CHANGE_ITEM, id: RewardId.FORM_CHANGE_ITEM,
() => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 6, weight: () => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 6,
24, maxWeight: 24,
), },
new WeightedReward(allRewards.AMULET_COIN, skipInLastClassicWaveOrDefault(3)), { id: TrainerItemId.AMULET_COIN, weight: skipInLastClassicWaveOrDefault(3) },
new WeightedReward(allRewards.EVIOLITE, (party: Pokemon[]) => { {
id: HeldItemId.EVIOLITE,
weight: (party: Pokemon[]) => {
const { gameMode, gameData } = globalScene; const { gameMode, gameData } = globalScene;
if (gameMode.isDaily || (!gameMode.isFreshStartChallenge() && gameData.isUnlocked(Unlockables.EVIOLITE))) { if (gameMode.isDaily || (!gameMode.isFreshStartChallenge() && gameData.isUnlocked(Unlockables.EVIOLITE))) {
return party.some(p => { return party.some(p => {
@ -333,11 +338,12 @@ function initUltraRewardPool() {
: 0; : 0;
} }
return 0; return 0;
}), },
new WeightedReward(allRewards.RARE_SPECIES_STAT_BOOSTER, 12), },
new WeightedReward( { id: RewardId.RARE_SPECIES_STAT_BOOSTER, weight: 12 },
allRewards.LEEK, {
(party: Pokemon[]) => { id: HeldItemId.LEEK,
weight: (party: Pokemon[]) => {
const checkedSpecies = [SpeciesId.FARFETCHD, SpeciesId.GALAR_FARFETCHD, SpeciesId.SIRFETCHD]; 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 // If a party member doesn't already have a Leek and is one of the relevant species, Leek can appear
return party.some( return party.some(
@ -349,11 +355,11 @@ function initUltraRewardPool() {
? 12 ? 12
: 0; : 0;
}, },
12, maxWeight: 12,
), },
new WeightedReward( {
allRewards.TOXIC_ORB, id: HeldItemId.TOXIC_ORB,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
return party.some(p => { return party.some(p => {
const isHoldingOrb = p.getHeldItems().some(i => i in [HeldItemId.FLAME_ORB, HeldItemId.TOXIC_ORB]); const isHoldingOrb = p.getHeldItems().some(i => i in [HeldItemId.FLAME_ORB, HeldItemId.TOXIC_ORB]);
@ -395,11 +401,11 @@ function initUltraRewardPool() {
? 10 ? 10
: 0; : 0;
}, },
10, maxWeight: 10,
), },
new WeightedReward( {
allRewards.FLAME_ORB, id: HeldItemId.FLAME_ORB,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
return party.some(p => { return party.some(p => {
const isHoldingOrb = p.getHeldItems().some(i => i in [HeldItemId.FLAME_ORB, HeldItemId.TOXIC_ORB]); const isHoldingOrb = p.getHeldItems().some(i => i in [HeldItemId.FLAME_ORB, HeldItemId.TOXIC_ORB]);
@ -441,11 +447,11 @@ function initUltraRewardPool() {
? 10 ? 10
: 0; : 0;
}, },
10, maxWeight: 10,
), },
new WeightedReward( {
allRewards.MYSTICAL_ROCK, id: HeldItemId.MYSTICAL_ROCK,
(party: Pokemon[]) => { weight: (party: Pokemon[]) => {
return party.some(p => { return party.some(p => {
const stack = p.heldItemManager.getStack(HeldItemId.MYSTICAL_ROCK); const stack = p.heldItemManager.getStack(HeldItemId.MYSTICAL_ROCK);
const isHoldingMax = stack === allHeldItems[HeldItemId.MYSTICAL_ROCK].maxStackCount; const isHoldingMax = stack === allHeldItems[HeldItemId.MYSTICAL_ROCK].maxStackCount;
@ -488,68 +494,68 @@ function initUltraRewardPool() {
? 10 ? 10
: 0; : 0;
}, },
10, maxWeight: 10,
), },
new WeightedReward(allRewards.REVIVER_SEED, 4), { id: HeldItemId.REVIVER_SEED, weight: 4 },
new WeightedReward(allRewards.CANDY_JAR, skipInLastClassicWaveOrDefault(5)), { id: TrainerItemId.CANDY_JAR, weight: skipInLastClassicWaveOrDefault(5) },
new WeightedReward(allRewards.ATTACK_TYPE_BOOSTER, 9), { id: RewardId.ATTACK_TYPE_BOOSTER, weight: 9 },
new WeightedReward(allRewards.TM_ULTRA, 11), { id: RewardId.TM_ULTRA, weight: 11 },
new WeightedReward(allRewards.RARER_CANDY, 4), { id: RewardId.RARER_CANDY, weight: 4 },
new WeightedReward(allRewards.GOLDEN_PUNCH, skipInLastClassicWaveOrDefault(2)), { id: HeldItemId.GOLDEN_PUNCH, weight: skipInLastClassicWaveOrDefault(2) },
new WeightedReward(allRewards.IV_SCANNER, skipInLastClassicWaveOrDefault(4)), { id: TrainerItemId.IV_SCANNER, weight: skipInLastClassicWaveOrDefault(4) },
new WeightedReward(allRewards.EXP_CHARM, skipInLastClassicWaveOrDefault(8)), { id: TrainerItemId.EXP_CHARM, weight: skipInLastClassicWaveOrDefault(8) },
new WeightedReward(allRewards.EXP_SHARE, skipInLastClassicWaveOrDefault(10)), { id: TrainerItemId.EXP_SHARE, weight: skipInLastClassicWaveOrDefault(10) },
new WeightedReward( {
allRewards.TERA_ORB, id: TrainerItemId.TERA_ORB,
() => weight: () =>
!globalScene.gameMode.isClassic !globalScene.gameMode.isClassic
? Math.min(Math.max(Math.floor(globalScene.currentBattle.waveIndex / 50) * 2, 1), 4) ? Math.min(Math.max(Math.floor(globalScene.currentBattle.waveIndex / 50) * 2, 1), 4)
: 0, : 0,
4, maxWeight: 4,
), },
new WeightedReward(allRewards.QUICK_CLAW, 3), { id: HeldItemId.QUICK_CLAW, weight: 3 },
new WeightedReward(allRewards.WIDE_LENS, 7), { id: HeldItemId.WIDE_LENS, weight: 7 },
]; ];
} }
function initRogueRewardPool() { function initRogueRewardPool() {
rewardPool[RarityTier.ROGUE] = [ rewardPool[RarityTier.ROGUE] = [
new WeightedReward(allRewards.ROGUE_BALL, () => (hasMaximumBalls(PokeballType.ROGUE_BALL) ? 0 : 16), 16), { id: RewardId.ROGUE_BALL, weight: () => (hasMaximumBalls(PokeballType.ROGUE_BALL) ? 0 : 16), maxWeight: 16 },
new WeightedReward(allRewards.RELIC_GOLD, skipInLastClassicWaveOrDefault(2)), { id: RewardId.RELIC_GOLD, weight: skipInLastClassicWaveOrDefault(2) },
new WeightedReward(allRewards.LEFTOVERS, 3), { id: HeldItemId.LEFTOVERS, weight: 3 },
new WeightedReward(allRewards.SHELL_BELL, 3), { id: HeldItemId.SHELL_BELL, weight: 3 },
new WeightedReward(allRewards.BERRY_POUCH, 4), { id: TrainerItemId.BERRY_POUCH, weight: 4 },
new WeightedReward(allRewards.GRIP_CLAW, 5), { id: HeldItemId.GRIP_CLAW, weight: 5 },
new WeightedReward(allRewards.SCOPE_LENS, 4), { id: HeldItemId.SCOPE_LENS, weight: 4 },
new WeightedReward(allRewards.BATON, 2), { id: HeldItemId.BATON, weight: 2 },
new WeightedReward(allRewards.SOUL_DEW, 7), { id: HeldItemId.SOUL_DEW, weight: 7 },
new WeightedReward(allRewards.CATCHING_CHARM, () => (!globalScene.gameMode.isClassic ? 4 : 0), 4), { id: TrainerItemId.CATCHING_CHARM, weight: () => (!globalScene.gameMode.isClassic ? 4 : 0), maxWeight: 4 },
new WeightedReward(allRewards.ABILITY_CHARM, skipInClassicAfterWave(189, 6)), { id: TrainerItemId.ABILITY_CHARM, weight: skipInClassicAfterWave(189, 6) },
new WeightedReward(allRewards.FOCUS_BAND, 5), { id: HeldItemId.FOCUS_BAND, weight: 5 },
new WeightedReward(allRewards.KINGS_ROCK, 3), { id: HeldItemId.KINGS_ROCK, weight: 3 },
new WeightedReward(allRewards.LOCK_CAPSULE, () => (globalScene.gameMode.isClassic ? 0 : 3)), { id: TrainerItemId.LOCK_CAPSULE, weight: () => (globalScene.gameMode.isClassic ? 0 : 3) },
new WeightedReward(allRewards.SUPER_EXP_CHARM, skipInLastClassicWaveOrDefault(8)), { id: TrainerItemId.SUPER_EXP_CHARM, weight: skipInLastClassicWaveOrDefault(8) },
new WeightedReward( {
allRewards.RARE_FORM_CHANGE_ITEM, id: RewardId.RARE_FORM_CHANGE_ITEM,
() => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 6, weight: () => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 6,
24, maxWeight: 24,
), },
new WeightedReward( {
allRewards.MEGA_BRACELET, id: TrainerItemId.MEGA_BRACELET,
() => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 9, weight: () => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 9,
36, maxWeight: 36,
), },
new WeightedReward( {
allRewards.DYNAMAX_BAND, id: TrainerItemId.DYNAMAX_BAND,
() => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 9, weight: () => Math.min(Math.ceil(globalScene.currentBattle.waveIndex / 50), 4) * 9,
36, maxWeight: 36,
), },
new WeightedReward( {
allRewards.VOUCHER_PLUS, id: RewardId.VOUCHER_PLUS,
(_party: Pokemon[], rerollCount: number) => weight: (_party: Pokemon[], rerollCount: number) =>
!globalScene.gameMode.isDaily ? Math.max(3 - rerollCount * 1, 0) : 0, !globalScene.gameMode.isDaily ? Math.max(3 - rerollCount * 1, 0) : 0,
3, maxWeight: 3,
), },
]; ];
} }
@ -558,37 +564,37 @@ function initRogueRewardPool() {
*/ */
function initMasterRewardPool() { function initMasterRewardPool() {
rewardPool[RarityTier.MASTER] = [ rewardPool[RarityTier.MASTER] = [
new WeightedReward(allRewards.MASTER_BALL, () => (hasMaximumBalls(PokeballType.MASTER_BALL) ? 0 : 24), 24), { id: RewardId.MASTER_BALL, weight: () => (hasMaximumBalls(PokeballType.MASTER_BALL) ? 0 : 24), maxWeight: 24 },
new WeightedReward(allRewards.SHINY_CHARM, 14), { id: TrainerItemId.SHINY_CHARM, weight: 14 },
new WeightedReward(allRewards.HEALING_CHARM, 18), { id: TrainerItemId.HEALING_CHARM, weight: 18 },
new WeightedReward(allRewards.MULTI_LENS, 18), { id: HeldItemId.MULTI_LENS, weight: 18 },
new WeightedReward( {
allRewards.VOUCHER_PREMIUM, id: RewardId.VOUCHER_PREMIUM,
(_party: Pokemon[], rerollCount: number) => weight: (_party: Pokemon[], rerollCount: number) =>
!globalScene.gameMode.isDaily && !globalScene.gameMode.isEndless && !globalScene.gameMode.isSplicedOnly !globalScene.gameMode.isDaily && !globalScene.gameMode.isEndless && !globalScene.gameMode.isSplicedOnly
? Math.max(5 - rerollCount * 2, 0) ? Math.max(5 - rerollCount * 2, 0)
: 0, : 0,
5, maxWeight: 5,
), },
new WeightedReward( {
allRewards.DNA_SPLICERS, id: RewardId.DNA_SPLICERS,
(party: Pokemon[]) => weight: (party: Pokemon[]) =>
!(globalScene.gameMode.isClassic && timedEventManager.areFusionsBoosted()) && !(globalScene.gameMode.isClassic && timedEventManager.areFusionsBoosted()) &&
!globalScene.gameMode.isSplicedOnly && !globalScene.gameMode.isSplicedOnly &&
party.filter(p => !p.fusionSpecies).length > 1 party.filter(p => !p.fusionSpecies).length > 1
? 24 ? 24
: 0, : 0,
24, maxWeight: 24,
), },
new WeightedReward( {
allRewards.MINI_BLACK_HOLE, id: HeldItemId.MINI_BLACK_HOLE,
() => weight: () =>
globalScene.gameMode.isDaily || globalScene.gameMode.isDaily ||
(!globalScene.gameMode.isFreshStartChallenge() && globalScene.gameData.isUnlocked(Unlockables.MINI_BLACK_HOLE)) (!globalScene.gameMode.isFreshStartChallenge() && globalScene.gameData.isUnlocked(Unlockables.MINI_BLACK_HOLE))
? 1 ? 1
: 0, : 0,
1, maxWeight: 1,
), },
]; ];
} }

View File

@ -2,22 +2,21 @@ import { globalScene } from "#app/global-scene";
import { allRewards } from "#data/data-lists"; import { allRewards } from "#data/data-lists";
import type { HeldItemId } from "#enums/held-item-id"; import type { HeldItemId } from "#enums/held-item-id";
import { getRewardCategory, RewardCategoryId, RewardId } from "#enums/reward-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 { TrainerItemId } from "#enums/trainer-item-id";
import type { RewardFunc, RewardPoolId } from "#types/rewards"; import type { RewardFunc, RewardPoolId } from "#types/rewards";
import { getHeldItemTier } from "./held-item-default-tiers"; import { heldItemRarities } from "./held-item-default-tiers";
import { import {
type HeldItemReward, HeldItemReward,
type PokemonMoveReward, type PokemonMoveReward,
type RememberMoveReward, type RememberMoveReward,
type Reward, type Reward,
RewardGenerator, RewardGenerator,
RewardOption, RewardOption,
type TmReward, type TmReward,
type TrainerItemReward, TrainerItemReward,
} from "./reward"; } from "./reward";
import { getRewardTier } from "./reward-defaults-tiers"; import { rewardRarities } from "./reward-defaults-tiers";
import { getTrainerItemTier } from "./trainer-item-default-tiers"; import { trainerItemRarities } from "./trainer-item-default-tiers";
export function isTmReward(reward: Reward): reward is TmReward { export function isTmReward(reward: Reward): reward is TmReward {
return getRewardCategory(reward.id) === RewardCategoryId.TM; return getRewardCategory(reward.id) === RewardCategoryId.TM;
@ -56,19 +55,26 @@ export function generateRewardOption(rewardFunc: RewardFunc, pregenArgs?: any[])
return null; return null;
} }
/** export function generateRewardOptionFromId(id: RewardPoolId, pregenArgs?: any[]): RewardOption | null {
* Finds the default rarity tier for a given reward. For unique held item or trainer item rewards, if (isHeldItemId(id)) {
* falls back to the default rarity tier for the item. const reward = new HeldItemReward(id);
* @param reward The {@linkcode Reward} to determine the tier for. const tier = heldItemRarities[id];
*/ return new RewardOption(reward, 0, tier);
export function getRewardDefaultTier(reward: Reward): RarityTier {
if (reward.id === RewardId.HELD_ITEM) {
return getHeldItemTier((reward as HeldItemReward).itemId);
} }
if (reward.id === RewardId.TRAINER_ITEM) {
return getTrainerItemTier((reward as TrainerItemReward).itemId); if (isTrainerItemId(id)) {
const reward = new TrainerItemReward(id);
const tier = trainerItemRarities[id];
return new RewardOption(reward, 0, tier);
} }
return getRewardTier(reward.id);
const rewardFunc = allRewards[id];
const reward = generateReward(rewardFunc, pregenArgs);
if (reward) {
const tier = rewardRarities[id];
return new RewardOption(reward, 0, tier);
}
return null;
} }
export function getPlayerShopRewardOptionsForWave(waveIndex: number, baseCost: number): RewardOption[] { export function getPlayerShopRewardOptionsForWave(waveIndex: number, baseCost: number): RewardOption[] {