From 740277b2225718717dd1d073a3532a791b89a80a Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Sun, 11 Aug 2024 12:28:58 -0400 Subject: [PATCH] Extra shop predictions Now checks all luck values, showing what item tiers you'd get at each tier (exact items aren't generated yet) If no alternate tiers are shown, the wave is OK to play with shiny Pokemon --- src/battle-scene.ts | 249 +++++++++++++++++++++++++++++++++- src/modifier/modifier-type.ts | 100 ++++++++++++-- src/phases.ts | 72 +++++++++- 3 files changed, 408 insertions(+), 13 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 07fd42761c9..50e8e90efc2 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1,6 +1,6 @@ import Phaser from "phaser"; import UI from "./ui/ui"; -import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from "./phases"; +import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase, runShinyCheck } from "./phases"; import Pokemon, { PlayerPokemon, EnemyPokemon } from "./field/pokemon"; import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies } from "./data/pokemon-species"; import { Constructor } from "#app/utils"; @@ -16,7 +16,7 @@ import { TextStyle, addTextObject, getTextColor } from "./ui/text"; import { allMoves } from "./data/move"; import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getLuckString, getLuckTextTint, getModifierPoolForType, getPartyLuckValue } from "./modifier/modifier-type"; import AbilityBar from "./ui/ability-bar"; -import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, IncrementMovePriorityAbAttr, PostBattleInitAbAttr, applyAbAttrs, applyPostBattleInitAbAttrs } from "./data/ability"; +import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, IncrementMovePriorityAbAttr, PostBattleInitAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyPostBattleInitAbAttrs } from "./data/ability"; import { allAbilities } from "./data/ability"; import Battle, { BattleType, FixedBattleConfig } from "./battle"; import { GameMode, GameModes, getGameMode } from "./game-mode"; @@ -130,6 +130,8 @@ export default class BattleScene extends SceneBase { public doBiomePanels: boolean = false; public disableDailyShinies: boolean = true; // Disables shiny luck in Daily Runs to prevent affecting RNG public quickloadDisplayMode: string = "Dailies"; + public tempWaveSeed: string; + public tempRngCounter: integer = 0; /** * Determines the condition for a notification should be shown for Candy Upgrades * - 0 = 'Off' @@ -1055,6 +1057,230 @@ export default class BattleScene extends SceneBase { } } + generatePokemonForBattle(battle: Battle) { + var totalBst = 0; + battle.enemyLevels.forEach((level, e) => { + if (true) { + if (battle.battleType === BattleType.TRAINER) { + battle.enemyParty[e] = battle.trainer.genPartyMember(e); + } else { + LoggerTools.rarityslot[0] = e + const enemySpecies = this.randomSpecies(battle.waveIndex, level, true); + battle.enemyParty[e] = this.addEnemyPokemon(enemySpecies, level, TrainerSlot.NONE, !!this.getEncounterBossSegments(battle.waveIndex, level, enemySpecies)); + if (this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) { + battle.enemyParty[e].ivs = new Array(6).fill(31); + } + this.getParty().slice(0, !battle.double ? 1 : 2).reverse().forEach(playerPokemon => { + applyAbAttrs(SyncEncounterNatureAbAttr, playerPokemon, null, battle.enemyParty[e]); + }); + } + } + const enemyPokemon = battle.enemyParty[e]; + + if (enemyPokemon.species.speciesId === Species.ETERNATUS) { + if (this.gameMode.isClassic && (battle.battleSpec === BattleSpec.FINAL_BOSS || this.gameMode.isWaveFinal(battle.waveIndex))) { + if (battle.battleSpec !== BattleSpec.FINAL_BOSS) { + enemyPokemon.formIndex = 1; + } + enemyPokemon.setBoss(); + } else if (!(battle.waveIndex % 1000)) { + enemyPokemon.formIndex = 1; + } + } + + totalBst += enemyPokemon.getSpeciesForm().baseTotal; + + console.log(enemyPokemon.name); + }); + } + peekBattleContents(waveIndex: integer) { + // This function is in progress + return; + + const _startingWave = Overrides.STARTING_WAVE_OVERRIDE || startingWave; + const originalWave = ((this.currentBattle?.waveIndex || (_startingWave - 1)) + 1); + const newWaveIndex = waveIndex; + const arenaBiome = this.arena.biomeType + this.emulateReset() + let newDouble: boolean; + let newBattleType: BattleType; + let newTrainer: Trainer; + let battleConfig: FixedBattleConfig = null; + let battleType: BattleType; + let trainerData: TrainerData; + let double: boolean; + const playerField = this.getPlayerField(); + + this.arena.biomeType = Biome.END + + if (this.gameMode.isFixedBattle(newWaveIndex) && trainerData === undefined) { + battleConfig = this.gameMode.getFixedBattle(newWaveIndex); + newDouble = battleConfig.double; + newBattleType = battleConfig.battleType; + this.executeWithSeedOffset(() => newTrainer = battleConfig.getTrainer(this), (battleConfig.seedOffsetWaveIndex || newWaveIndex) << 8); + if (newTrainer) { + this.field.add(newTrainer); + } + } else { + if (!this.gameMode.hasTrainers) { + newBattleType = BattleType.WILD; + console.log("(wild battles only)") + } else if (battleType === undefined) { + newBattleType = this.gameMode.isWaveTrainer(newWaveIndex, this.arena) ? BattleType.TRAINER : BattleType.WILD; + console.log(this.gameMode.isWaveTrainer(newWaveIndex, this.arena) ? "Trainer Battle" : "Wild battle") + } else { + newBattleType = battleType; + console.log(battleType == BattleType.WILD ? "Wild (manually set)" : (battleType == BattleType.TRAINER ? "Trainer (manually set)" : "Clear (manually set)")) + } + + if (newBattleType === BattleType.TRAINER) { + const trainerType = this.arena.randomTrainerType(newWaveIndex); + let doubleTrainer = false; + if (trainerConfigs[trainerType].doubleOnly) { + doubleTrainer = true; + } else if (trainerConfigs[trainerType].hasDouble) { + const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8); + this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance); + playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance)); + doubleTrainer = !Utils.randSeedInt(doubleChance.value); + // Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance + if (trainerConfigs[trainerType].trainerTypeDouble && !(trainerType === TrainerType.TATE || trainerType === TrainerType.LIZA)) { + doubleTrainer = false; + } + } + newTrainer = trainerData !== undefined ? trainerData.toTrainer(this) : new Trainer(this, trainerType, doubleTrainer ? TrainerVariant.DOUBLE : Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT); + this.field.add(newTrainer); + } + } + + if (double === undefined && newWaveIndex > 1) { + if (newBattleType === BattleType.WILD && !this.gameMode.isWaveFinal(newWaveIndex)) { + const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8); + this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance); + playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance)); + console.log(Math.floor((1/doubleChance.value) * 100) + "% chance of a Double Battle") + newDouble = !Utils.randSeedInt(doubleChance.value); + console.log("Double Battle: " + (newDouble ? "Yes" : "No")) + } else if (newBattleType === BattleType.TRAINER) { + //console.log("[Can't determine double trainer battles yet]") + newDouble = newTrainer.variant === TrainerVariant.DOUBLE; + console.log("Trainer Double Battle: " + (newDouble ? "Yes" : "No")) + } + } else if (!battleConfig) { + newDouble = !!double; + console.log("Double Battle: " + (newDouble ? "Yes" : "No") + " (manually set)") + } + + if (Overrides.BATTLE_TYPE_OVERRIDE === "double") { + newDouble = true; + console.log("Double Battle: Yes (Player override)") + } + /* Override battles into single only if not fighting with trainers */ + if (newBattleType !== BattleType.TRAINER && Overrides.BATTLE_TYPE_OVERRIDE === "single") { + newDouble = false; + console.log("Double Battle: No (Player override)") + } + + const lastBattle = this.currentBattle; + + if (lastBattle?.double && !newDouble) { + this.tryRemovePhase(p => p instanceof SwitchPhase); + } + + const maxExpLevel = this.getMaxExpLevel(); + + this.lastEnemyTrainer = lastBattle?.trainer ?? null; + + var simBattle = undefined + this.executeWithSeedOffset(() => { + simBattle = new Battle(this.gameMode, newWaveIndex, newBattleType, newTrainer, newDouble); + }, newWaveIndex << 3, this.waveSeed); + simBattle.incrementTurn(this); + + //this.pushPhase(new TrainerMessageTestPhase(this, TrainerType.RIVAL, TrainerType.RIVAL_2, TrainerType.RIVAL_3, TrainerType.RIVAL_4, TrainerType.RIVAL_5, TrainerType.RIVAL_6)); + + if (!waveIndex && lastBattle) { + let isNewBiome = !(lastBattle.waveIndex % 10) || ((this.gameMode.hasShortBiomes || this.gameMode.isDaily) && (lastBattle.waveIndex % 50) === 49); + if (!isNewBiome && this.gameMode.hasShortBiomes && (lastBattle.waveIndex % 10) < 9) { + let w = lastBattle.waveIndex - ((lastBattle.waveIndex % 10) - 1); + let biomeWaves = 1; + while (w < lastBattle.waveIndex) { + let wasNewBiome = false; + this.executeWithSeedOffset(() => { + wasNewBiome = !Utils.randSeedInt(6 - biomeWaves); + }, w << 4); + if (wasNewBiome) { + biomeWaves = 1; + } else { + biomeWaves++; + } + w++; + } + + this.executeWithSeedOffset(() => { + isNewBiome = !Utils.randSeedInt(6 - biomeWaves); + }, lastBattle.waveIndex << 4); + if (isNewBiome) console.log("This wave attempted to switch biomes early") + } + const resetArenaState = isNewBiome || simBattle.battleType === BattleType.TRAINER || simBattle.battleSpec === BattleSpec.FINAL_BOSS; + //this.getEnemyParty().forEach(enemyPokemon => enemyPokemon.destroy()); + //this.trySpreadPokerus(); + if (!isNewBiome && (newWaveIndex % 10) === 5) { + this.arena.updatePoolsForTimeOfDay(); + } + if (resetArenaState) { + this.arena.resetArenaEffects(); + playerField.forEach((_, p) => { + //this.unshiftPhase(new ReturnPhase(this, p)) + console.log("Pushed new ReturnPhase for " + this.getParty()[p].name) + }); + + for (const pokemon of this.getParty()) { + // Only trigger form change when Eiscue is in Noice form + // Hardcoded Eiscue for now in case it is fused with another pokemon + if (pokemon.species.speciesId === Species.EISCUE && pokemon.hasAbility(Abilities.ICE_FACE) && pokemon.formIndex === 1) { + //this.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger); + console.log("Triggered form change for an Eiscue") + } + + pokemon.resetBattleData(); + applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon); + } + + //this.unshiftPhase(new ShowTrainerPhase(this)); + console.log("Inserted new ShowTrainerPhase to front of queue") + } + + for (const pokemon of this.getParty()) { + //this.triggerPokemonFormChange(pokemon, SpeciesFormChangeTimeOfDayTrigger); + } + + if (!this.gameMode.hasRandomBiomes && !isNewBiome) { + //this.pushPhase(new NextEncounterPhase(this)); + console.log("Pushed new NextEncounterPhase") + } else { + //this.pushPhase(new SelectBiomePhase(this)); + console.log("Pushed new SelectBiomePhase") + //this.pushPhase(new NewBiomeEncounterPhase(this)) + console.log("Pushed new NewBiomeEncounterPhase"); + + const newMaxExpLevel = this.getMaxExpLevel(); + if (newMaxExpLevel > maxExpLevel) { + //this.pushPhase(new LevelCapPhase(this)); + console.log("Attempted to announce level cap change (Lv. " + newMaxExpLevel + ")") + } + } + } + + this.generatePokemonForBattle(simBattle) + + console.log("Generated battle", simBattle) + + this.arena.biomeType = arenaBiome + + this.restoreSeed() + } + newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean): Battle { const _startingWave = Overrides.STARTING_WAVE_OVERRIDE || startingWave; const newWaveIndex = waveIndex || ((this.currentBattle?.waveIndex || (_startingWave - 1)) + 1); @@ -1396,6 +1622,25 @@ export default class BattleScene extends SceneBase { }); } + emulateReset(waveIndex?: integer) { + const wave = waveIndex || this.currentBattle?.waveIndex || 0; + this.tempWaveSeed = this.waveSeed; + this.tempRngCounter = this.rngCounter; + this.waveSeed = Utils.shiftCharCodes(this.seed, wave); + Phaser.Math.RND.sow([ this.waveSeed ]); + console.log("Temporarily reset wave RNG"); + this.rngCounter = 0; + //this.setScoreText("RNG: 0") + } + restoreSeed(waveIndex?: integer) { + const wave = waveIndex || this.currentBattle?.waveIndex || 0; + this.waveSeed = this.tempWaveSeed; + Phaser.Math.RND.sow([ this.waveSeed ]); + console.log("Restored wave RNG"); + this.rngCounter = this.tempRngCounter; + //this.setScoreText("RNG: 0") + } + resetSeed(waveIndex?: integer): void { const wave = waveIndex || this.currentBattle?.waveIndex || 0; this.waveSeed = Utils.shiftCharCodes(this.seed, wave); diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 395afd44711..00b4409e67b 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -2042,14 +2042,18 @@ export function getModifierTypeFuncById(id: string): ModifierTypeFunc { return modifierTypes[id]; } -export function getPlayerModifierTypeOptions(count: integer, party: PlayerPokemon[], modifierTiers?: ModifierTier[], scene?: BattleScene, shutUpBro?: boolean): ModifierTypeOption[] { +export function getPlayerModifierTypeOptions(count: integer, party: PlayerPokemon[], modifierTiers?: ModifierTier[], scene?: BattleScene, shutUpBro?: boolean, generateAltTiers?: boolean, shinyCheckOnly?: boolean): ModifierTypeOption[] { const options: ModifierTypeOption[] = []; const retryCount = Math.min(count * 5, 50); new Array(count).fill(0).map((_, i) => { - let candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, modifierTiers?.length > i ? modifierTiers[i] : undefined, undefined, undefined, scene, shutUpBro); + let candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, modifierTiers?.length > i ? modifierTiers[i] : undefined, undefined, undefined, scene, shutUpBro, generateAltTiers, shinyCheckOnly); let r = 0; + const aT = candidate.alternates while (options.length && ++r < retryCount && options.filter(o => o.type.name === candidate.type.name || o.type.group === candidate.type.group).length) { - candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, candidate.type.tier, candidate.upgradeCount, undefined, scene, shutUpBro); + candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, candidate.type.tier, candidate.upgradeCount, undefined, scene, shutUpBro, generateAltTiers, shinyCheckOnly); + } + if (candidate.alternates == undefined) { + candidate.alternates = aT } options.push(candidate); }); @@ -2105,10 +2109,14 @@ export function getEnemyBuffModifierForWave(tier: ModifierTier, enemyModifiers: const retryCount = 50; let candidate = getNewModifierTypeOption(null, ModifierPoolType.ENEMY_BUFF, tier, undefined, undefined, scene); let r = 0; + const aT = candidate.alternates let matchingModifier: Modifiers.PersistentModifier; while (++r < retryCount && (matchingModifier = enemyModifiers.find(m => m.type.id === candidate.type.id)) && matchingModifier.getMaxStackCount(scene) < matchingModifier.stackCount + (r < 10 ? tierStackCount : 1)) { candidate = getNewModifierTypeOption(null, ModifierPoolType.ENEMY_BUFF, tier, undefined, undefined, scene); } + if (candidate.alternates == undefined) { + candidate.alternates = aT + } const modifier = candidate.type.newModifier() as Modifiers.EnemyPersistentModifier; modifier.stackCount = tierStackCount; @@ -2138,7 +2146,7 @@ export function getDailyRunStarterModifiers(party: PlayerPokemon[], scene?: Batt return ret; } -function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, tier?: ModifierTier, upgradeCount?: integer, retryCount: integer = 0, scene?: BattleScene, shutUpBro?: boolean): ModifierTypeOption { +function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, tier?: ModifierTier, upgradeCount?: integer, retryCount: integer = 0, scene?: BattleScene, shutUpBro?: boolean, generateAltTiers?: boolean, shinyCheckOnly?: boolean): ModifierTypeOption { const player = !poolType; const pool = getModifierPoolForType(poolType); let thresholds: object; @@ -2159,7 +2167,49 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, thresholds = dailyStarterModifierPoolThresholds; break; } + var alternateTiers = [] if (tier === undefined) { + if (generateAltTiers) { + for (var luck = 0; luck <= 14; luck++) { + var state = Phaser.Math.RND.state() + var tierValueTemp = Utils.randSeedInt(1024); + var upgradeCountTemp = 0; + var tierTemp = undefined; + if (upgradeCount) { + upgradeCountTemp = upgradeCount; + } + if (player && tierValueTemp) { + var partyLuckValue = luck + const upgradeOddsTemp = Math.floor(128 / ((partyLuckValue + 4) / 4)); + let upgraded = false; + do { + upgraded = Utils.randSeedInt(upgradeOddsTemp) < 4; + if (upgraded) { + upgradeCountTemp++; + } + } while (upgraded); + } + tierTemp = tierValueTemp > 255 ? ModifierTier.COMMON : tierValueTemp > 60 ? ModifierTier.GREAT : tierValueTemp > 12 ? ModifierTier.ULTRA : tierValueTemp ? ModifierTier.ROGUE : ModifierTier.MASTER; + // Does this actually do anything? + if (!upgradeCountTemp) { + upgradeCountTemp = Math.min(upgradeCountTemp, ModifierTier.MASTER - tierTemp); + } + tierTemp += upgradeCountTemp; + while (tierTemp && (!modifierPool.hasOwnProperty(tierTemp) || !modifierPool[tierTemp].length)) { + tierTemp--; + if (upgradeCountTemp) { + upgradeCountTemp--; + } + } + alternateTiers[luck] = tierTemp + Phaser.Math.RND.state(state) + } + if (shinyCheckOnly) { + var O = new ModifierTypeOption(undefined, 0, 0); + O.alternates = alternateTiers; + return O; + } + } const tierValue = Utils.randSeedInt(1024); if (!upgradeCount) { upgradeCount = 0; @@ -2167,7 +2217,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, if (player && tierValue) { var partyLuckValue = getPartyLuckValue(party); if (scene) { - if (scene.gameMode.modeId == GameModes.DAILY && scene.disableDailyShinies && false) { + if (scene.gameMode.modeId == GameModes.DAILY && scene.disableDailyShinies) { partyLuckValue = 0 } } @@ -2197,10 +2247,31 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, if (tier < ModifierTier.MASTER) { var partyShinyCount = party.filter(p => p.isShiny() && !p.isFainted() && (!this.scene.disableDailyShinies || p.species.luckOverride != 0)).length; if (scene) { - if (scene.gameMode.modeId == GameModes.DAILY && scene.disableDailyShinies && false) { + if (scene.gameMode.modeId == GameModes.DAILY && scene.disableDailyShinies) { partyShinyCount = 0 } } + if (generateAltTiers) { + for (var luck = 0; luck <= 14; luck++) { + var state = Phaser.Math.RND.state() + var upgradeOddsTemp = Math.floor(32 / ((luck + 2) / 2)); + var upgradeCountTemp = 0; + while (modifierPool.hasOwnProperty(tier + upgradeCountTemp + 1) && modifierPool[tier + upgradeCountTemp + 1].length) { + if (!Utils.randSeedInt(upgradeOddsTemp)) { + upgradeCountTemp++; + } else { + break; + } + } + alternateTiers[luck] = tier + upgradeCountTemp + Phaser.Math.RND.state(state) + } + if (shinyCheckOnly) { + var O = new ModifierTypeOption(undefined, 0, 0); + O.alternates = alternateTiers; + return O; + } + } const upgradeOdds = Math.floor(32 / ((partyShinyCount + 2) / 2)); while (modifierPool.hasOwnProperty(tier + upgradeCount + 1) && modifierPool[tier + upgradeCount + 1].length) { if (!Utils.randSeedInt(upgradeOdds)) { @@ -2216,6 +2287,10 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, tier--; } + if (shinyCheckOnly) { + return new ModifierTypeOption(undefined, 0, 0); + } + const tierThresholds = Object.keys(thresholds[tier]); const totalWeight = parseInt(tierThresholds[tierThresholds.length - 1]); const value = Utils.randSeedInt(totalWeight); @@ -2242,13 +2317,21 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, if (player) { if (!shutUpBro) console.log(ModifierTier[tier], upgradeCount); } - return getNewModifierTypeOption(party, poolType, tier, upgradeCount, ++retryCount, scene, shutUpBro); + return getNewModifierTypeOption(party, poolType, tier, upgradeCount, ++retryCount, scene, shutUpBro, generateAltTiers); } } if (!shutUpBro) console.log(modifierType, !player ? "(enemy)" : ""); - return new ModifierTypeOption(modifierType as ModifierType, upgradeCount); + var Option = new ModifierTypeOption(modifierType as ModifierType, upgradeCount); + if (alternateTiers.length > 0) { + //console.log(Option.type.name, alternateTiers) + Option.alternates = alternateTiers + } + if (!generateAltTiers) { + //Option.alternates = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] + } + return Option; } export function getDefaultModifierTypeForTier(tier: ModifierTier): ModifierType { @@ -2263,6 +2346,7 @@ export class ModifierTypeOption { public type: ModifierType; public upgradeCount: integer; public cost: integer; + public alternates?: integer[]; constructor(type: ModifierType, upgradeCount: integer, cost: number = 0) { this.type = type; diff --git a/src/phases.ts b/src/phases.ts index e928a4d7fd0..bec0d6a473d 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -3803,6 +3803,8 @@ export class TurnEndPhase extends FieldPhase { this.scene.arena.trySetTerrain(TerrainType.NONE, false); } + this.scene.peekBattleContents(50) + this.end(); } } @@ -6728,6 +6730,60 @@ export class AttemptRunPhase extends PokemonPhase { //#region 71 SelectModifierPhase +const tierNames = [ + "Poké", + "Great", + "Ultra", + "Rogue", + "Master" +] +/** + * This function rolls for modifiers with a certain luck value, checking to see if shiny luck would affect your results. + * @param scene + * @param predictionCost + * @param rerollOverride + * @param modifierOverride + * @returns + */ +export function shinyCheckStep(scene: BattleScene, predictionCost: Utils.IntegerHolder, rerollOverride: integer, modifierOverride?: integer) { + var modifierPredictions = [] + const party = scene.getParty(); + regenerateModifierPoolThresholds(party, ModifierPoolType.PLAYER, rerollOverride); + const modifierCount = new Utils.IntegerHolder(3); + scene.applyModifiers(ExtraModifierModifier, true, modifierCount); + if (modifierOverride) { + //modifierCount.value = modifierOverride + } + var isOk = true; + const typeOptions: ModifierTypeOption[] = getPlayerModifierTypeOptions(modifierCount.value, scene.getParty(), undefined, scene, true, true); + typeOptions.forEach((option, idx) => { + if (option.alternates && option.alternates.length > 0) { + for (var i = 0; i < option.alternates.length; i++) { + if (option.alternates[i] > option.type.tier) { + isOk = false // Shiny Luck affects this wave in some way + } + } + } + }) + modifierPredictions.push(typeOptions) + predictionCost.value += (Math.min(Math.ceil(scene.currentBattle.waveIndex / 10) * 250 * Math.pow(2, rerollOverride), Number.MAX_SAFE_INTEGER)) + return isOk; +} +/** + * Simulates modifier rolls for as many rerolls as you can afford, checking to see if shiny luck will alter your results. + * @param scene The current `BattleScene`. + * @returns `true` if no changes were detected, `false` otherwise + */ +export function runShinyCheck(scene: BattleScene, wv?: integer) { + scene.resetSeed(wv); + const predictionCost = new Utils.IntegerHolder(0) + var isOk = true; + for (var i = 0; i < 14 && isOk; i++) { + isOk = isOk && shinyCheckStep(scene, predictionCost, i) + } + scene.resetSeed(wv); + return isOk +} export class SelectModifierPhase extends BattlePhase { private rerollCount: integer; private modifierTiers: ModifierTier[]; @@ -6759,7 +6815,7 @@ export class SelectModifierPhase extends BattlePhase { if (modifierOverride) { //modifierCount.value = modifierOverride } - const typeOptions: ModifierTypeOption[] = this.getModifierTypeOptions(modifierCount.value, true); + const typeOptions: ModifierTypeOption[] = this.getModifierTypeOptions(modifierCount.value, true, true); typeOptions.forEach((option, idx) => { //console.log(option.type.name) }) @@ -6995,6 +7051,16 @@ export class SelectModifierPhase extends BattlePhase { console.log("Rerolls: " + r) mp.forEach((m, i) => { console.log(" " + m.type.name) + if (m.alternates) { + for (var j = 0, currentTier = m.type.tier; j < m.alternates.length; j++) { + if (m.alternates[j] > currentTier) { + currentTier = m.alternates[j] + console.log(" At " + j + " luck: " + tierNames[currentTier] + "-tier item") + } + } + } else { + console.log(" No alt-luck data") + } }) }) } @@ -7026,8 +7092,8 @@ export class SelectModifierPhase extends BattlePhase { return ModifierPoolType.PLAYER; } - getModifierTypeOptions(modifierCount: integer, shutUpBro?: boolean): ModifierTypeOption[] { - return getPlayerModifierTypeOptions(modifierCount, this.scene.getParty(), this.scene.lockModifierTiers ? this.modifierTiers : undefined, this.scene, shutUpBro); + getModifierTypeOptions(modifierCount: integer, shutUpBro?: boolean, calcAllLuck?: boolean): ModifierTypeOption[] { + return getPlayerModifierTypeOptions(modifierCount, this.scene.getParty(), this.scene.lockModifierTiers ? this.modifierTiers : undefined, this.scene, shutUpBro, calcAllLuck); } addModifier(modifier: Modifier): Promise {