mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-26 09:19:31 +02:00
Merge branch 'beta' into Spanish-Corrections
This commit is contained in:
commit
369bf9eff4
@ -2,7 +2,7 @@ import Phaser from "phaser";
|
||||
import UI from "./ui/ui";
|
||||
import Pokemon, { EnemyPokemon, PlayerPokemon } from "./field/pokemon";
|
||||
import PokemonSpecies, { allSpecies, getPokemonSpecies, PokemonSpeciesFilter } from "./data/pokemon-species";
|
||||
import { Constructor, isNullOrUndefined } from "#app/utils";
|
||||
import { Constructor, isNullOrUndefined, randSeedInt } from "#app/utils";
|
||||
import * as Utils from "./utils";
|
||||
import { ConsumableModifier, ConsumablePokemonModifier, DoubleBattleChanceBoosterModifier, ExpBalanceModifier, ExpShareModifier, FusePokemonModifier, HealingBoosterModifier, Modifier, ModifierBar, ModifierPredicate, MultipleParticipantExpBonusModifier, overrideHeldItems, overrideModifiers, PersistentModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, TerastallizeModifier, TurnHeldItemTransferModifier } from "./modifier/modifier";
|
||||
import { PokeballType } from "./data/pokeball";
|
||||
@ -1201,32 +1201,12 @@ export default class BattleScene extends SceneBase {
|
||||
|
||||
// Check for mystery encounter
|
||||
// Can only occur in place of a standard (non-boss) wild battle, waves 10-180
|
||||
const [lowestMysteryEncounterWave, highestMysteryEncounterWave] = this.gameMode.getMysteryEncounterLegalWaves();
|
||||
if (this.gameMode.hasMysteryEncounters && newBattleType === BattleType.WILD && !this.gameMode.isBoss(newWaveIndex) && newWaveIndex < highestMysteryEncounterWave && newWaveIndex > lowestMysteryEncounterWave) {
|
||||
const roll = Utils.randSeedInt(MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT);
|
||||
|
||||
// Base spawn weight is BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT/256, and increases by WEIGHT_INCREMENT_ON_SPAWN_MISS/256 for each missed attempt at spawning an encounter on a valid floor
|
||||
const sessionEncounterRate = this.mysteryEncounterSaveData.encounterSpawnChance;
|
||||
const encounteredEvents = this.mysteryEncounterSaveData.encounteredEvents;
|
||||
|
||||
// If total number of encounters is lower than expected for the run, slightly favor a new encounter spawn (reverse as well)
|
||||
// Reduces occurrence of runs with total encounters significantly different from AVERAGE_ENCOUNTERS_PER_RUN_TARGET
|
||||
const expectedEncountersByFloor = AVERAGE_ENCOUNTERS_PER_RUN_TARGET / (highestMysteryEncounterWave - lowestMysteryEncounterWave) * (newWaveIndex - lowestMysteryEncounterWave);
|
||||
const currentRunDiffFromAvg = expectedEncountersByFloor - encounteredEvents.length;
|
||||
const favoredEncounterRate = sessionEncounterRate + currentRunDiffFromAvg * ANTI_VARIANCE_WEIGHT_MODIFIER;
|
||||
|
||||
const successRate = isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE) ? favoredEncounterRate : Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE!;
|
||||
|
||||
// If the most recent ME was 3 or fewer waves ago, can never spawn a ME
|
||||
const canSpawn = encounteredEvents.length === 0 || (newWaveIndex - encounteredEvents[encounteredEvents.length - 1].waveIndex) > 3 || !isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE);
|
||||
|
||||
if (canSpawn && roll < successRate) {
|
||||
newBattleType = BattleType.MYSTERY_ENCOUNTER;
|
||||
// Reset base spawn weight
|
||||
this.mysteryEncounterSaveData.encounterSpawnChance = BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT;
|
||||
} else {
|
||||
this.mysteryEncounterSaveData.encounterSpawnChance = sessionEncounterRate + WEIGHT_INCREMENT_ON_SPAWN_MISS;
|
||||
}
|
||||
if (this.isWaveMysteryEncounter(newBattleType, newWaveIndex, mysteryEncounterType) || newBattleType === BattleType.MYSTERY_ENCOUNTER || !isNullOrUndefined(mysteryEncounterType)) {
|
||||
newBattleType = BattleType.MYSTERY_ENCOUNTER;
|
||||
// Reset base spawn weight
|
||||
this.mysteryEncounterSaveData.encounterSpawnChance = BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT;
|
||||
} else if (newBattleType === BattleType.WILD) {
|
||||
this.mysteryEncounterSaveData.encounterSpawnChance += WEIGHT_INCREMENT_ON_SPAWN_MISS;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1267,9 +1247,8 @@ export default class BattleScene extends SceneBase {
|
||||
if (newBattleType === BattleType.MYSTERY_ENCOUNTER) {
|
||||
// Disable double battle on mystery encounters (it may be re-enabled as part of encounter)
|
||||
this.currentBattle.double = false;
|
||||
this.executeWithSeedOffset(() => {
|
||||
this.currentBattle.mysteryEncounter = this.getMysteryEncounter(mysteryEncounterType);
|
||||
}, this.currentBattle.waveIndex << 4);
|
||||
// Will generate the actual Mystery Encounter during NextEncounterPhase, to ensure it uses proper biome
|
||||
this.currentBattle.mysteryEncounterType = mysteryEncounterType;
|
||||
}
|
||||
|
||||
//this.pushPhase(new TrainerMessageTestPhase(this, TrainerType.RIVAL, TrainerType.RIVAL_2, TrainerType.RIVAL_3, TrainerType.RIVAL_4, TrainerType.RIVAL_5, TrainerType.RIVAL_6));
|
||||
@ -2657,8 +2636,7 @@ export default class BattleScene extends SceneBase {
|
||||
modifier = mt.modifier as PokemonHeldItemModifier;
|
||||
modifier.pokemonId = enemyPokemon.id;
|
||||
}
|
||||
const stackCount = mt.stackCount ?? 1;
|
||||
modifier.stackCount = stackCount;
|
||||
modifier.stackCount = mt.stackCount ?? 1;
|
||||
modifier.isTransferable = mt.isTransferable ?? modifier.isTransferable;
|
||||
this.addEnemyModifier(modifier, true);
|
||||
});
|
||||
@ -3097,6 +3075,51 @@ export default class BattleScene extends SceneBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a wave should randomly generate a {@linkcode MysteryEncounter}.
|
||||
* Currently, the only modes that MEs are allowed in are Classic and Challenge.
|
||||
* Additionally, MEs cannot spawn outside of waves 10-180 in those modes
|
||||
*
|
||||
* @param newBattleType
|
||||
* @param waveIndex
|
||||
* @param sessionDataEncounterType
|
||||
*/
|
||||
private isWaveMysteryEncounter(newBattleType: BattleType, waveIndex: number, sessionDataEncounterType?: MysteryEncounterType): boolean {
|
||||
const [lowestMysteryEncounterWave, highestMysteryEncounterWave] = this.gameMode.getMysteryEncounterLegalWaves();
|
||||
if (this.gameMode.hasMysteryEncounters && newBattleType === BattleType.WILD && !this.gameMode.isBoss(waveIndex) && waveIndex < highestMysteryEncounterWave && waveIndex > lowestMysteryEncounterWave) {
|
||||
// If ME type is already defined in session data, no need to roll RNG check
|
||||
if (!isNullOrUndefined(sessionDataEncounterType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Base spawn weight is BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT/256, and increases by WEIGHT_INCREMENT_ON_SPAWN_MISS/256 for each missed attempt at spawning an encounter on a valid floor
|
||||
const sessionEncounterRate = this.mysteryEncounterSaveData.encounterSpawnChance;
|
||||
const encounteredEvents = this.mysteryEncounterSaveData.encounteredEvents;
|
||||
|
||||
// If total number of encounters is lower than expected for the run, slightly favor a new encounter spawn (reverse as well)
|
||||
// Reduces occurrence of runs with total encounters significantly different from AVERAGE_ENCOUNTERS_PER_RUN_TARGET
|
||||
const expectedEncountersByFloor = AVERAGE_ENCOUNTERS_PER_RUN_TARGET / (highestMysteryEncounterWave - lowestMysteryEncounterWave) * (waveIndex - lowestMysteryEncounterWave);
|
||||
const currentRunDiffFromAvg = expectedEncountersByFloor - encounteredEvents.length;
|
||||
const favoredEncounterRate = sessionEncounterRate + currentRunDiffFromAvg * ANTI_VARIANCE_WEIGHT_MODIFIER;
|
||||
|
||||
const successRate = isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE) ? favoredEncounterRate : Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE!;
|
||||
|
||||
// If the most recent ME was 3 or fewer waves ago, can never spawn a ME
|
||||
const canSpawn = encounteredEvents.length === 0 || (waveIndex - encounteredEvents[encounteredEvents.length - 1].waveIndex) > 3 || !isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE);
|
||||
|
||||
if (canSpawn) {
|
||||
let roll = MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT;
|
||||
// Always rolls the check on the same offset to ensure no RNG changes from reloading session
|
||||
this.executeWithSeedOffset(() => {
|
||||
roll = randSeedInt(MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT);
|
||||
}, waveIndex * 3 * 1000);
|
||||
return roll < successRate;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads or generates a mystery encounter
|
||||
* @param encounterType used to load session encounter when restarting game, etc.
|
||||
@ -3105,10 +3128,10 @@ export default class BattleScene extends SceneBase {
|
||||
getMysteryEncounter(encounterType?: MysteryEncounterType): MysteryEncounter {
|
||||
// Loading override or session encounter
|
||||
let encounter: MysteryEncounter | null;
|
||||
if (!isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_OVERRIDE) && allMysteryEncounters.hasOwnProperty(Overrides.MYSTERY_ENCOUNTER_OVERRIDE!)) {
|
||||
encounter = allMysteryEncounters[Overrides.MYSTERY_ENCOUNTER_OVERRIDE!];
|
||||
if (!isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_OVERRIDE) && allMysteryEncounters.hasOwnProperty(Overrides.MYSTERY_ENCOUNTER_OVERRIDE)) {
|
||||
encounter = allMysteryEncounters[Overrides.MYSTERY_ENCOUNTER_OVERRIDE];
|
||||
} else {
|
||||
encounter = !isNullOrUndefined(encounterType) ? allMysteryEncounters[encounterType!] : null;
|
||||
encounter = !isNullOrUndefined(encounterType) ? allMysteryEncounters[encounterType] : null;
|
||||
}
|
||||
|
||||
// Check for queued encounters first
|
||||
@ -3151,7 +3174,7 @@ export default class BattleScene extends SceneBase {
|
||||
let tier: MysteryEncounterTier | null = tierValue > commonThreshold ? MysteryEncounterTier.COMMON : tierValue > greatThreshold ? MysteryEncounterTier.GREAT : tierValue > ultraThreshold ? MysteryEncounterTier.ULTRA : MysteryEncounterTier.ROGUE;
|
||||
|
||||
if (!isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE)) {
|
||||
tier = Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE!;
|
||||
tier = Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE;
|
||||
}
|
||||
|
||||
let availableEncounters: MysteryEncounter[] = [];
|
||||
|
@ -18,6 +18,7 @@ import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
import { CustomModifierSettings } from "#app/modifier/modifier-type";
|
||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
|
||||
export enum ClassicFixedBossWaves {
|
||||
// TODO: other fixed wave battles should be added here
|
||||
@ -88,6 +89,7 @@ export default class Battle {
|
||||
public playerFaintsHistory: FaintLogEntry[] = [];
|
||||
public enemyFaintsHistory: FaintLogEntry[] = [];
|
||||
|
||||
public mysteryEncounterType?: MysteryEncounterType;
|
||||
/** If the current battle is a Mystery Encounter, this will always be defined */
|
||||
public mysteryEncounter?: MysteryEncounter;
|
||||
|
||||
|
@ -430,7 +430,7 @@ class AnimTimedAddBgEvent extends AnimTimedBgEvent {
|
||||
scene.field.add(moveAnim.bgSprite);
|
||||
const fieldPokemon = scene.getNonSwitchedEnemyPokemon() || scene.getNonSwitchedPlayerPokemon();
|
||||
if (!isNullOrUndefined(priority)) {
|
||||
scene.field.moveTo(moveAnim.bgSprite as Phaser.GameObjects.GameObject, priority!);
|
||||
scene.field.moveTo(moveAnim.bgSprite as Phaser.GameObjects.GameObject, priority);
|
||||
} else if (fieldPokemon?.isOnField()) {
|
||||
scene.field.moveBelow(moveAnim.bgSprite as Phaser.GameObjects.GameObject, fieldPokemon);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import { EggTier } from "#enums/egg-type";
|
||||
import { PartyHealPhase } from "#app/phases/party-heal-phase";
|
||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounter:aTrainersTest";
|
||||
@ -27,7 +28,7 @@ const namespace = "mysteryEncounter:aTrainersTest";
|
||||
export const ATrainersTestEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.A_TRAINERS_TEST)
|
||||
.withEncounterTier(MysteryEncounterTier.ROGUE)
|
||||
.withSceneWaveRangeRequirement(100, 180)
|
||||
.withSceneWaveRangeRequirement(100, CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES[1])
|
||||
.withIntroSpriteConfigs([]) // These are set in onInit()
|
||||
.withIntroDialogue([
|
||||
{
|
||||
|
@ -10,7 +10,7 @@ import { PersistentModifierRequirement } from "#app/data/mystery-encounters/myst
|
||||
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { BerryModifier } from "#app/modifier/modifier";
|
||||
import { BerryModifier, PokemonInstantReviveModifier } from "#app/modifier/modifier";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
@ -159,12 +159,6 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
||||
])
|
||||
.withHideWildIntroMessage(true)
|
||||
.withAutoHideIntroVisuals(false)
|
||||
.withOnVisualsStart((scene: BattleScene) => {
|
||||
doGreedentSpriteSteal(scene);
|
||||
doBerrySpritePile(scene);
|
||||
|
||||
return true;
|
||||
})
|
||||
.withIntroDialogue([
|
||||
{
|
||||
text: `${namespace}.intro`,
|
||||
@ -202,10 +196,15 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
||||
const modifierType = generateModifierType(scene, modifierTypes.BERRY, [berryMod.berryType]) as PokemonHeldItemModifierType;
|
||||
bossModifierConfigs.push({ modifier: modifierType });
|
||||
}
|
||||
|
||||
scene.removeModifier(berryMod);
|
||||
});
|
||||
|
||||
// Do NOT remove the real berries yet or else it will be persisted in the session data
|
||||
|
||||
// SpDef buff below wave 50, +1 to all stats otherwise
|
||||
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ?
|
||||
[Stat.SPDEF] :
|
||||
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD];
|
||||
|
||||
// Calculate boss mon
|
||||
const config: EnemyPartyConfig = {
|
||||
levelAdditiveModifier: 1,
|
||||
@ -214,12 +213,12 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
||||
species: getPokemonSpecies(Species.GREEDENT),
|
||||
isBoss: true,
|
||||
bossSegments: 3,
|
||||
moveSet: [Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.SLACK_OFF],
|
||||
moveSet: [Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.CRUNCH],
|
||||
modifierConfigs: bossModifierConfigs,
|
||||
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
|
||||
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
||||
queueEncounterMessage(pokemon.scene, `${namespace}.option.1.boss_enraged`);
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD], 1));
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -230,6 +229,21 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
||||
|
||||
return true;
|
||||
})
|
||||
.withOnVisualsStart((scene: BattleScene) => {
|
||||
doGreedentSpriteSteal(scene);
|
||||
doBerrySpritePile(scene);
|
||||
|
||||
// Remove the berries from the party
|
||||
// Session has been safely saved at this point, so data won't be lost
|
||||
const berryItems = scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
|
||||
berryItems.forEach(berryMod => {
|
||||
scene.removeModifier(berryMod);
|
||||
});
|
||||
|
||||
scene.updateModifiers(true);
|
||||
|
||||
return true;
|
||||
})
|
||||
.withOption(
|
||||
MysteryEncounterOptionBuilder
|
||||
.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
@ -251,7 +265,8 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
||||
const givePartyPokemonReviverSeeds = () => {
|
||||
const party = scene.getParty();
|
||||
party.forEach(p => {
|
||||
if (revSeed) {
|
||||
const heldItems = p.getHeldItems();
|
||||
if (revSeed && !heldItems.some(item => item instanceof PokemonInstantReviveModifier)) {
|
||||
const seedModifier = revSeed.newModifier(p);
|
||||
if (seedModifier) {
|
||||
encounter.setDialogueToken("foodReward", seedModifier.type.name);
|
||||
|
@ -8,7 +8,7 @@ import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/myst
|
||||
import { AbilityRequirement, CombinationPokemonRequirement, MoveRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||
import { getHighestStatTotalPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { EXTORTION_ABILITIES, EXTORTION_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { getPokemonSpecies, speciesStarters } from "#app/data/pokemon-species";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
|
||||
@ -17,6 +17,14 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
/** the i18n namespace for this encounter */
|
||||
const namespace = "mysteryEncounter:offerYouCantRefuse";
|
||||
|
||||
/**
|
||||
* Money offered starts at base value of Relic Gold, increasing linearly up to 3x Relic Gold based on the starter tier of the Pokemon being purchased
|
||||
* Starter value 1-3 -> Relic Gold
|
||||
* Starter value 10 -> 3 * Relic Gold
|
||||
*/
|
||||
const MONEY_MINIMUM_MULTIPLIER = 10;
|
||||
const MONEY_MAXIMUM_MULTIPLIER = 30;
|
||||
|
||||
/**
|
||||
* An Offer You Can't Refuse encounter.
|
||||
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3808 | GitHub Issue #3808}
|
||||
@ -61,7 +69,11 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const pokemon = getHighestStatTotalPlayerPokemon(scene, true, true);
|
||||
const price = scene.getWaveMoneyAmount(10);
|
||||
|
||||
const baseSpecies = pokemon.getSpeciesForm().getRootSpeciesId(true);
|
||||
const starterValue: number = speciesStarters[baseSpecies] ?? 1;
|
||||
const multiplier = Math.max(MONEY_MAXIMUM_MULTIPLIER / 10 * starterValue, MONEY_MINIMUM_MULTIPLIER);
|
||||
const price = scene.getWaveMoneyAmount(multiplier);
|
||||
|
||||
encounter.setDialogueToken("strongestPokemon", pokemon.getNameToRender());
|
||||
encounter.setDialogueToken("price", price.toString());
|
||||
|
@ -127,7 +127,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const numBerries = encounter.misc.numBerries;
|
||||
|
||||
const doBerryRewards = async () => {
|
||||
const doBerryRewards = () => {
|
||||
const berryText = numBerries + " " + i18next.t(`${namespace}.berries`);
|
||||
|
||||
scene.playSound("item_fanfare");
|
||||
@ -135,7 +135,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
||||
|
||||
// Generate a random berry and give it to the first Pokemon with room for it
|
||||
for (let i = 0; i < numBerries; i++) {
|
||||
await tryGiveBerry(scene);
|
||||
tryGiveBerry(scene);
|
||||
}
|
||||
};
|
||||
|
||||
@ -178,7 +178,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
||||
|
||||
if (speedDiff < 1) {
|
||||
// Caught and attacked by boss, gets +1 to all stats at start of fight
|
||||
const doBerryRewards = async () => {
|
||||
const doBerryRewards = () => {
|
||||
const berryText = numBerries + " " + i18next.t(`${namespace}.berries`);
|
||||
|
||||
scene.playSound("item_fanfare");
|
||||
@ -186,15 +186,20 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
||||
|
||||
// Generate a random berry and give it to the first Pokemon with room for it
|
||||
for (let i = 0; i < numBerries; i++) {
|
||||
await tryGiveBerry(scene);
|
||||
tryGiveBerry(scene);
|
||||
}
|
||||
};
|
||||
|
||||
// Defense/Spd buffs below wave 50, +1 to all stats otherwise
|
||||
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ?
|
||||
[Stat.DEF, Stat.SPDEF, Stat.SPD] :
|
||||
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD];
|
||||
|
||||
const config = scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0];
|
||||
config.pokemonConfigs![0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON];
|
||||
config.pokemonConfigs![0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => {
|
||||
queueEncounterMessage(pokemon.scene, `${namespace}.option.2.boss_enraged`);
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD], 1));
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
|
||||
};
|
||||
setEncounterRewards(scene, { guaranteedModifierTypeOptions: shopOptions, fillRemaining: false }, undefined, doBerryRewards);
|
||||
await showEncounterText(scene, `${namespace}.option.2.selected_bad`);
|
||||
@ -204,7 +209,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
||||
// Gains 1 berry for every 10% faster the player's pokemon is than the enemy, up to a max of numBerries, minimum of 2
|
||||
const numBerriesGrabbed = Math.max(Math.min(Math.round((speedDiff - 1)/0.08), numBerries), 2);
|
||||
encounter.setDialogueToken("numBerries", String(numBerriesGrabbed));
|
||||
const doFasterBerryRewards = async () => {
|
||||
const doFasterBerryRewards = () => {
|
||||
const berryText = numBerriesGrabbed + " " + i18next.t(`${namespace}.berries`);
|
||||
|
||||
scene.playSound("item_fanfare");
|
||||
@ -212,7 +217,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
||||
|
||||
// Generate a random berry and give it to the first Pokemon with room for it (trying to give to fastest first)
|
||||
for (let i = 0; i < numBerriesGrabbed; i++) {
|
||||
await tryGiveBerry(scene, fastestPokemon);
|
||||
tryGiveBerry(scene, fastestPokemon);
|
||||
}
|
||||
};
|
||||
|
||||
@ -242,7 +247,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
||||
)
|
||||
.build();
|
||||
|
||||
async function tryGiveBerry(scene: BattleScene, prioritizedPokemon?: PlayerPokemon) {
|
||||
function tryGiveBerry(scene: BattleScene, prioritizedPokemon?: PlayerPokemon) {
|
||||
const berryType = randSeedInt(Object.keys(BerryType).filter(s => !isNaN(Number(s))).length) as BerryType;
|
||||
const berry = generateModifierType(scene, modifierTypes.BERRY, [berryType]) as BerryModifierType;
|
||||
|
||||
@ -254,7 +259,7 @@ async function tryGiveBerry(scene: BattleScene, prioritizedPokemon?: PlayerPokem
|
||||
&& m.pokemonId === prioritizedPokemon.id && (m as BerryModifier).berryType === berryType, true) as BerryModifier;
|
||||
|
||||
if (!heldBerriesOfType || heldBerriesOfType.getStackCount() < heldBerriesOfType.getMaxStackCount(scene)) {
|
||||
await applyModifierTypeToPlayerPokemon(scene, prioritizedPokemon, berry);
|
||||
applyModifierTypeToPlayerPokemon(scene, prioritizedPokemon, berry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -265,7 +270,7 @@ async function tryGiveBerry(scene: BattleScene, prioritizedPokemon?: PlayerPokem
|
||||
&& m.pokemonId === pokemon.id && (m as BerryModifier).berryType === berryType, true) as BerryModifier;
|
||||
|
||||
if (!heldBerriesOfType || heldBerriesOfType.getStackCount() < heldBerriesOfType.getMaxStackCount(scene)) {
|
||||
await applyModifierTypeToPlayerPokemon(scene, pokemon, berry);
|
||||
applyModifierTypeToPlayerPokemon(scene, pokemon, berry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -492,7 +492,7 @@ function getTrainerConfigForWave(waveIndex: number) {
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => {
|
||||
if (!isNullOrUndefined(pool3Mon.formIndex)) {
|
||||
p.formIndex = pool3Mon.formIndex!;
|
||||
p.formIndex = pool3Mon.formIndex;
|
||||
p.generateAndPopulateMoveset();
|
||||
p.generateName();
|
||||
}
|
||||
@ -515,14 +515,14 @@ function getTrainerConfigForWave(waveIndex: number) {
|
||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => {
|
||||
if (!isNullOrUndefined(pool3Mon.formIndex)) {
|
||||
p.formIndex = pool3Mon.formIndex!;
|
||||
p.formIndex = pool3Mon.formIndex;
|
||||
p.generateAndPopulateMoveset();
|
||||
p.generateName();
|
||||
}
|
||||
}))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([pool3Mon2.species], TrainerSlot.TRAINER, true, p => {
|
||||
if (!isNullOrUndefined(pool3Mon2.formIndex)) {
|
||||
p.formIndex = pool3Mon2.formIndex!;
|
||||
p.formIndex = pool3Mon2.formIndex;
|
||||
p.generateAndPopulateMoveset();
|
||||
p.generateName();
|
||||
}
|
||||
@ -543,7 +543,7 @@ function getTrainerConfigForWave(waveIndex: number) {
|
||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => {
|
||||
if (!isNullOrUndefined(pool3Mon.formIndex)) {
|
||||
p.formIndex = pool3Mon.formIndex!;
|
||||
p.formIndex = pool3Mon.formIndex;
|
||||
p.generateAndPopulateMoveset();
|
||||
p.generateName();
|
||||
}
|
||||
@ -566,14 +566,14 @@ function getTrainerConfigForWave(waveIndex: number) {
|
||||
}))
|
||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => {
|
||||
if (!isNullOrUndefined(pool3Mon.formIndex)) {
|
||||
p.formIndex = pool3Mon.formIndex!;
|
||||
p.formIndex = pool3Mon.formIndex;
|
||||
p.generateAndPopulateMoveset();
|
||||
p.generateName();
|
||||
}
|
||||
}))
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([pool3Mon.species], TrainerSlot.TRAINER, true, p => {
|
||||
if (!isNullOrUndefined(pool3Mon.formIndex)) {
|
||||
p.formIndex = pool3Mon.formIndex!;
|
||||
p.formIndex = pool3Mon.formIndex;
|
||||
p.generateAndPopulateMoveset();
|
||||
p.generateName();
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import { CombinationPokemonRequirement, HeldItemRequirement, MoneyRequirement }
|
||||
import { getEncounterText, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { BerryModifier, HealingBoosterModifier, HiddenAbilityRateBoosterModifier, LevelIncrementBoosterModifier, PokemonHeldItemModifier, PreserveBerryModifier } from "#app/modifier/modifier";
|
||||
import { BerryModifier, HealingBoosterModifier, LevelIncrementBoosterModifier, MoneyMultiplierModifier, PokemonHeldItemModifier, PreserveBerryModifier } from "#app/modifier/modifier";
|
||||
import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import { applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import i18next from "#app/plugins/i18n";
|
||||
@ -33,7 +33,7 @@ const OPTION_3_DISALLOWED_MODIFIERS = [
|
||||
"PokemonBaseStatTotalModifier"
|
||||
];
|
||||
|
||||
const DELIBIRDY_MONEY_PRICE_MULTIPLIER = 1.5;
|
||||
const DELIBIRDY_MONEY_PRICE_MULTIPLIER = 2;
|
||||
|
||||
/**
|
||||
* Delibird-y encounter.
|
||||
@ -122,9 +122,9 @@ export const DelibirdyEncounter: MysteryEncounter =
|
||||
return true;
|
||||
})
|
||||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Give the player an Ability Charm
|
||||
// Give the player an Amulet Coin
|
||||
// Check if the player has max stacks of that item already
|
||||
const existing = scene.findModifier(m => m instanceof HiddenAbilityRateBoosterModifier) as HiddenAbilityRateBoosterModifier;
|
||||
const existing = scene.findModifier(m => m instanceof MoneyMultiplierModifier) as MoneyMultiplierModifier;
|
||||
|
||||
if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) {
|
||||
// At max stacks, give the first party pokemon a Shell Bell instead
|
||||
@ -133,7 +133,7 @@ export const DelibirdyEncounter: MysteryEncounter =
|
||||
scene.playSound("item_fanfare");
|
||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true);
|
||||
} else {
|
||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.ABILITY_CHARM));
|
||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.AMULET_COIN));
|
||||
}
|
||||
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
|
@ -63,7 +63,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter =
|
||||
// Choose TMs
|
||||
const modifiers: ModifierTypeFunc[] = [];
|
||||
let i = 0;
|
||||
while (i < 4) {
|
||||
while (i < 5) {
|
||||
// 2/2/1 weight on TM rarity
|
||||
const roll = randSeedInt(5);
|
||||
if (roll < 2) {
|
||||
|
@ -24,7 +24,7 @@ const namespace = "mysteryEncounter:fieldTrip";
|
||||
export const FieldTripEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.FIELD_TRIP)
|
||||
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||
.withSceneWaveRangeRequirement(CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES[0], 100)
|
||||
.withIntroSpriteConfigs([
|
||||
{
|
||||
spriteKey: "preschooler_m",
|
||||
|
@ -189,7 +189,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
||||
}
|
||||
|
||||
// Burn random member
|
||||
const burnable = nonFireTypes.filter(p => isNullOrUndefined(p.status) || isNullOrUndefined(p.status!.effect) || p.status?.effect === StatusEffect.NONE);
|
||||
const burnable = nonFireTypes.filter(p => isNullOrUndefined(p.status) || isNullOrUndefined(p.status.effect) || p.status.effect === StatusEffect.NONE);
|
||||
if (burnable?.length > 0) {
|
||||
const roll = randSeedInt(burnable.length);
|
||||
const chosenPokemon = burnable[roll];
|
||||
|
@ -11,9 +11,10 @@ import PokemonSpecies, { allSpecies, getPokemonSpecies } from "#app/data/pokemon
|
||||
import { getTypeRgb } from "#app/data/type";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import * as Utils from "#app/utils";
|
||||
import { IntegerHolder, isNullOrUndefined, randInt, randSeedInt, randSeedShuffle } from "#app/utils";
|
||||
import Pokemon, { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon";
|
||||
import { HiddenAbilityRateBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, SpeciesStatBoosterModifier } from "#app/modifier/modifier";
|
||||
import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import { HiddenAbilityRateBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, ShinyRateBoosterModifier, SpeciesStatBoosterModifier } from "#app/modifier/modifier";
|
||||
import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import PokemonData from "#app/system/pokemon-data";
|
||||
import i18next from "i18next";
|
||||
@ -28,6 +29,11 @@ import { addPokemonDataToDexAndValidateAchievements } from "#app/data/mystery-en
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounter:globalTradeSystem";
|
||||
|
||||
/** Base shiny chance of 512/65536 -> 1/128 odds, affected by events and Shiny Charms. Cannot exceed 1/16 odds. */
|
||||
const WONDER_TRADE_SHINY_CHANCE = 512;
|
||||
/** Max shiny chance of 4096/65536 -> 1/16 odds. */
|
||||
const MAX_WONDER_TRADE_SHINY_CHANCE = 4096;
|
||||
|
||||
const LEGENDARY_TRADE_POOLS = {
|
||||
1: [Species.RATTATA, Species.PIDGEY, Species.WEEDLE],
|
||||
2: [Species.SENTRET, Species.HOOTHOOT, Species.LEDYBA],
|
||||
@ -153,7 +159,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
||||
return true;
|
||||
},
|
||||
onHover: () => {
|
||||
const formName = tradePokemon.species.forms?.[pokemon.formIndex]?.formName;
|
||||
const formName = tradePokemon.species.forms && tradePokemon.species.forms.length > tradePokemon.formIndex ? tradePokemon.species.forms[pokemon.formIndex].formName : null;
|
||||
const line1 = i18next.t("pokemonInfoContainer:ability") + " " + tradePokemon.getAbility().name + (tradePokemon.getGender() !== Gender.GENDERLESS ? " | " + i18next.t("pokemonInfoContainer:gender") + " " + getGenderSymbol(tradePokemon.getGender()) : "");
|
||||
const line2 = i18next.t("pokemonInfoContainer:nature") + " " + getNatureName(tradePokemon.getNature()) + (formName ? " | " + i18next.t("pokemonInfoContainer:form") + " " + formName : "");
|
||||
showEncounterText(scene, `${line1}\n${line2}`, 0, 0, false);
|
||||
@ -221,21 +227,47 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
||||
const tradePokemon = new EnemyPokemon(scene, randomTradeOption, pokemon.level, TrainerSlot.NONE, false);
|
||||
// Extra shiny roll at 1/128 odds (boosted by events and charms)
|
||||
if (!tradePokemon.shiny) {
|
||||
// 512/65536 -> 1/128
|
||||
tradePokemon.trySetShinySeed(512, true);
|
||||
const shinyThreshold = new Utils.IntegerHolder(WONDER_TRADE_SHINY_CHANCE);
|
||||
if (scene.eventManager.isEventActive()) {
|
||||
shinyThreshold.value *= scene.eventManager.getShinyMultiplier();
|
||||
}
|
||||
scene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold);
|
||||
|
||||
// Base shiny chance of 512/65536 -> 1/128, affected by events and Shiny Charms
|
||||
// Maximum shiny chance of 4096/65536 -> 1/16, cannot improve further after that
|
||||
const shinyChance = Math.min(shinyThreshold.value, MAX_WONDER_TRADE_SHINY_CHANCE);
|
||||
|
||||
tradePokemon.trySetShinySeed(shinyChance, false);
|
||||
}
|
||||
|
||||
// Extra HA roll at base 1/64 odds (boosted by events and charms)
|
||||
if (pokemon.species.abilityHidden) {
|
||||
const hiddenIndex = pokemon.species.ability2 ? 2 : 1;
|
||||
if (pokemon.abilityIndex < hiddenIndex) {
|
||||
const hiddenIndex = tradePokemon.species.ability2 ? 2 : 1;
|
||||
if (tradePokemon.species.abilityHidden) {
|
||||
if (tradePokemon.abilityIndex < hiddenIndex) {
|
||||
const hiddenAbilityChance = new IntegerHolder(64);
|
||||
scene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
|
||||
|
||||
const hasHiddenAbility = !randSeedInt(hiddenAbilityChance.value);
|
||||
|
||||
if (hasHiddenAbility) {
|
||||
pokemon.abilityIndex = hiddenIndex;
|
||||
tradePokemon.abilityIndex = hiddenIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If Pokemon is still not shiny or with HA, give the Pokemon a random Common egg move in its moveset
|
||||
if (!tradePokemon.shiny && (!tradePokemon.species.abilityHidden || tradePokemon.abilityIndex < hiddenIndex)) {
|
||||
const eggMoves = tradePokemon.getEggMoves();
|
||||
if (eggMoves) {
|
||||
// Cannot gen the rare egg move, only 1 of the first 3 common moves
|
||||
const eggMove = eggMoves[randSeedInt(3)];
|
||||
if (!tradePokemon.moveset.some(m => m?.moveId === eggMove)) {
|
||||
if (tradePokemon.moveset.length < 4) {
|
||||
tradePokemon.moveset.push(new PokemonMove(eggMove));
|
||||
} else {
|
||||
const eggMoveIndex = randSeedInt(4);
|
||||
tradePokemon.moveset[eggMoveIndex] = new PokemonMove(eggMove);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -450,7 +482,7 @@ function generateTradeOption(alreadyUsedSpecies: PokemonSpecies[], originalBst?:
|
||||
if (validSpecies?.length > 20) {
|
||||
validSpecies = randSeedShuffle(validSpecies);
|
||||
newSpecies = validSpecies.pop();
|
||||
while (isNullOrUndefined(newSpecies) || alreadyUsedSpecies.includes(newSpecies!)) {
|
||||
while (isNullOrUndefined(newSpecies) || alreadyUsedSpecies.includes(newSpecies)) {
|
||||
newSpecies = validSpecies.pop();
|
||||
}
|
||||
} else {
|
||||
|
@ -19,10 +19,11 @@ import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
const namespace = "mysteryEncounter:mysteriousChest";
|
||||
|
||||
const RAND_LENGTH = 100;
|
||||
const COMMON_REWARDS_WEIGHT = 20; // 20%
|
||||
const ULTRA_REWARDS_WEIGHT = 50; // 30%
|
||||
const ROGUE_REWARDS_WEIGHT = 60; // 10%
|
||||
const MASTER_REWARDS_WEIGHT = 65; // 5%
|
||||
const TRAP_PERCENT = 35;
|
||||
const COMMON_REWARDS_PERCENT = 20;
|
||||
const ULTRA_REWARDS_PERCENT = 30;
|
||||
const ROGUE_REWARDS_PERCENT = 10;
|
||||
const MASTER_REWARDS_PERCENT = 5;
|
||||
|
||||
/**
|
||||
* Mysterious Chest encounter.
|
||||
@ -83,6 +84,11 @@ export const MysteriousChestEncounter: MysteryEncounter =
|
||||
encounter.enemyPartyConfigs = [config];
|
||||
|
||||
encounter.setDialogueToken("gimmighoulName", getPokemonSpecies(Species.GIMMIGHOUL).getName());
|
||||
encounter.setDialogueToken("trapPercent", TRAP_PERCENT.toString());
|
||||
encounter.setDialogueToken("commonPercent", COMMON_REWARDS_PERCENT.toString());
|
||||
encounter.setDialogueToken("ultraPercent", ULTRA_REWARDS_PERCENT.toString());
|
||||
encounter.setDialogueToken("roguePercent", ROGUE_REWARDS_PERCENT.toString());
|
||||
encounter.setDialogueToken("masterPercent", MASTER_REWARDS_PERCENT.toString());
|
||||
|
||||
return true;
|
||||
})
|
||||
@ -109,7 +115,7 @@ export const MysteriousChestEncounter: MysteryEncounter =
|
||||
roll
|
||||
};
|
||||
|
||||
if (roll >= MASTER_REWARDS_WEIGHT) {
|
||||
if (roll < TRAP_PERCENT) {
|
||||
// Chest is springing trap, change to red chest sprite
|
||||
const blueChestSprites = introVisuals.getSpriteAtIndex(0);
|
||||
const redChestSprites = introVisuals.getSpriteAtIndex(1);
|
||||
@ -124,7 +130,7 @@ export const MysteriousChestEncounter: MysteryEncounter =
|
||||
// Open the chest
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
const roll = encounter.misc.roll;
|
||||
if (roll < COMMON_REWARDS_WEIGHT) {
|
||||
if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT) {
|
||||
// Choose between 2 COMMON / 2 GREAT tier items (20%)
|
||||
setEncounterRewards(scene, {
|
||||
guaranteedModifierTiers: [
|
||||
@ -137,7 +143,7 @@ export const MysteriousChestEncounter: MysteryEncounter =
|
||||
// Display result message then proceed to rewards
|
||||
queueEncounterMessage(scene, `${namespace}.option.1.normal`);
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
} else if (roll < ULTRA_REWARDS_WEIGHT) {
|
||||
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT) {
|
||||
// Choose between 3 ULTRA tier items (30%)
|
||||
setEncounterRewards(scene, {
|
||||
guaranteedModifierTiers: [
|
||||
@ -149,13 +155,13 @@ export const MysteriousChestEncounter: MysteryEncounter =
|
||||
// Display result message then proceed to rewards
|
||||
queueEncounterMessage(scene, `${namespace}.option.1.good`);
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
} else if (roll < ROGUE_REWARDS_WEIGHT) {
|
||||
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT) {
|
||||
// Choose between 2 ROGUE tier items (10%)
|
||||
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE] });
|
||||
// Display result message then proceed to rewards
|
||||
queueEncounterMessage(scene, `${namespace}.option.1.great`);
|
||||
leaveEncounterWithoutBattle(scene);
|
||||
} else if (roll < MASTER_REWARDS_WEIGHT) {
|
||||
} else if (roll >= RAND_LENGTH - COMMON_REWARDS_PERCENT - ULTRA_REWARDS_PERCENT - ROGUE_REWARDS_PERCENT - MASTER_REWARDS_PERCENT) {
|
||||
// Choose 1 MASTER tier item (5%)
|
||||
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.MASTER] });
|
||||
// Display result message then proceed to rewards
|
||||
|
@ -27,6 +27,8 @@ const TRAINER_THROW_ANIMATION_TIMES = [512, 184, 768];
|
||||
|
||||
const SAFARI_MONEY_MULTIPLIER = 2;
|
||||
|
||||
const NUM_SAFARI_ENCOUNTERS = 3;
|
||||
|
||||
/**
|
||||
* Safari Zone encounter.
|
||||
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3800 | GitHub Issue #3800}
|
||||
@ -55,6 +57,10 @@ export const SafariZoneEncounter: MysteryEncounter =
|
||||
.withTitle(`${namespace}.title`)
|
||||
.withDescription(`${namespace}.description`)
|
||||
.withQuery(`${namespace}.query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
scene.currentBattle.mysteryEncounter?.setDialogueToken("numEncounters", NUM_SAFARI_ENCOUNTERS.toString());
|
||||
return true;
|
||||
})
|
||||
.withOption(MysteryEncounterOptionBuilder
|
||||
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withSceneRequirement(new MoneyRequirement(0, SAFARI_MONEY_MULTIPLIER)) // Cost equal to 1 Max Revive
|
||||
@ -72,7 +78,7 @@ export const SafariZoneEncounter: MysteryEncounter =
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
encounter.continuousEncounter = true;
|
||||
encounter.misc = {
|
||||
safariPokemonRemaining: 3
|
||||
safariPokemonRemaining: NUM_SAFARI_ENCOUNTERS
|
||||
};
|
||||
updatePlayerMoney(scene, -(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney);
|
||||
// Load bait/mud assets
|
||||
|
@ -39,7 +39,7 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
|
||||
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||
.withSceneRequirement(new WaveModulusRequirement([1, 2, 3], 10)) // Must be in first 3 waves after boss wave
|
||||
.withSceneRequirement(new MoneyRequirement(undefined, MONEY_COST_MULTIPLIER)) // Must be able to pay teleport cost
|
||||
.withSceneRequirement(new MoneyRequirement(0, MONEY_COST_MULTIPLIER)) // Must be able to pay teleport cost
|
||||
.withAutoHideIntroVisuals(false)
|
||||
.withCatchAllowed(true)
|
||||
.withIntroSpriteConfigs([
|
||||
@ -73,7 +73,7 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
|
||||
.withOption(
|
||||
MysteryEncounterOptionBuilder
|
||||
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withSceneMoneyRequirement(undefined, MONEY_COST_MULTIPLIER) // Must be able to pay teleport cost
|
||||
.withSceneMoneyRequirement(0, MONEY_COST_MULTIPLIER) // Must be able to pay teleport cost
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}.option.1.label`,
|
||||
buttonTooltip: `${namespace}.option.1.tooltip`,
|
||||
@ -172,7 +172,7 @@ async function doBiomeTransitionDialogueAndBattleInit(scene: BattleScene) {
|
||||
const bossPokemon = new EnemyPokemon(scene, bossSpecies, level, TrainerSlot.NONE, true);
|
||||
encounter.setDialogueToken("enemyPokemon", getPokemonNameWithAffix(bossPokemon));
|
||||
|
||||
// Defense/Spd buffs below wave 50, Atk/Def/Spd buffs otherwise
|
||||
// Defense/Spd buffs below wave 50, +1 to all stats otherwise
|
||||
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ?
|
||||
[Stat.DEF, Stat.SPDEF, Stat.SPD] :
|
||||
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD];
|
||||
|
@ -34,7 +34,7 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.THE_POKEMON_SALESMAN)
|
||||
.withEncounterTier(MysteryEncounterTier.ULTRA)
|
||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||
.withSceneRequirement(new MoneyRequirement(undefined, MAX_POKEMON_PRICE_MULTIPLIER)) // Some costs may not be as significant, this is the max you'd pay
|
||||
.withSceneRequirement(new MoneyRequirement(0, MAX_POKEMON_PRICE_MULTIPLIER)) // Some costs may not be as significant, this is the max you'd pay
|
||||
.withAutoHideIntroVisuals(false)
|
||||
.withIntroSpriteConfigs([
|
||||
{
|
||||
@ -59,11 +59,12 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter =
|
||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||
|
||||
let species = getPokemonSpecies(getRandomSpeciesByStarterTier([0, 5], undefined, undefined, false, false, false));
|
||||
const tries = 0;
|
||||
let tries = 0;
|
||||
|
||||
// Reroll any species that don't have HAs
|
||||
while ((isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE) && tries < 5) {
|
||||
species = getPokemonSpecies(getRandomSpeciesByStarterTier([0, 5], undefined, undefined, false, false, false));
|
||||
tries++;
|
||||
}
|
||||
|
||||
let pokemon: PlayerPokemon;
|
||||
@ -71,7 +72,7 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter =
|
||||
// If no HA mon found or you roll 1%, give shiny Magikarp
|
||||
species = getPokemonSpecies(Species.MAGIKARP);
|
||||
const hiddenIndex = species.ability2 ? 2 : 1;
|
||||
pokemon = new PlayerPokemon(scene, species, 5, hiddenIndex, species.formIndex, undefined, true);
|
||||
pokemon = new PlayerPokemon(scene, species, 5, hiddenIndex, species.formIndex, undefined, true, 0);
|
||||
} else {
|
||||
const hiddenIndex = species.ability2 ? 2 : 1;
|
||||
pokemon = new PlayerPokemon(scene, species, 5, hiddenIndex, species.formIndex);
|
||||
@ -113,7 +114,7 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter =
|
||||
MysteryEncounterOptionBuilder
|
||||
.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withHasDexProgress(true)
|
||||
.withSceneMoneyRequirement(undefined, MAX_POKEMON_PRICE_MULTIPLIER) // Wave scaling money multiplier of 2
|
||||
.withSceneMoneyRequirement(0, MAX_POKEMON_PRICE_MULTIPLIER) // Wave scaling money multiplier of 2
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}.option.1.label`,
|
||||
buttonTooltip: `${namespace}.option.1.tooltip`,
|
||||
|
@ -33,7 +33,7 @@ const BST_INCREASE_VALUE = 10;
|
||||
*/
|
||||
export const TheStrongStuffEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.THE_STRONG_STUFF)
|
||||
.withEncounterTier(MysteryEncounterTier.GREAT)
|
||||
.withEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||
.withScenePartySizeRequirement(3, 6) // Must have at least 3 pokemon in party
|
||||
.withMaxAllowedEncounters(1)
|
||||
|
@ -324,21 +324,18 @@ export const TrainingSessionEncounter: MysteryEncounter =
|
||||
const abilityIndex = encounter.misc.abilityIndex;
|
||||
if (!!playerPokemon.getFusionSpeciesForm()) {
|
||||
playerPokemon.fusionAbilityIndex = abilityIndex;
|
||||
if (!isNullOrUndefined(playerPokemon.fusionSpecies?.speciesId) && speciesStarters.hasOwnProperty(playerPokemon.fusionSpecies!.speciesId)) {
|
||||
scene.gameData.starterData[playerPokemon.fusionSpecies!.speciesId]
|
||||
if (!isNullOrUndefined(playerPokemon.fusionSpecies?.speciesId) && speciesStarters.hasOwnProperty(playerPokemon.fusionSpecies.speciesId)) {
|
||||
scene.gameData.starterData[playerPokemon.fusionSpecies.speciesId]
|
||||
.abilityAttr |=
|
||||
abilityIndex !== 1 || playerPokemon.fusionSpecies!.ability2
|
||||
abilityIndex !== 1 || playerPokemon.fusionSpecies.ability2
|
||||
? Math.pow(2, playerPokemon.fusionAbilityIndex)
|
||||
: AbilityAttr.ABILITY_HIDDEN;
|
||||
}
|
||||
} else {
|
||||
playerPokemon.abilityIndex = abilityIndex;
|
||||
if (
|
||||
speciesStarters.hasOwnProperty(playerPokemon.species.speciesId)
|
||||
) {
|
||||
scene.gameData.starterData[
|
||||
playerPokemon.species.speciesId
|
||||
].abilityAttr |=
|
||||
if (speciesStarters.hasOwnProperty(playerPokemon.species.speciesId)) {
|
||||
scene.gameData.starterData[playerPokemon.species.speciesId]
|
||||
.abilityAttr |=
|
||||
abilityIndex !== 1 || playerPokemon.species.ability2
|
||||
? Math.pow(2, playerPokemon.abilityIndex)
|
||||
: AbilityAttr.ABILITY_HIDDEN;
|
||||
|
@ -16,7 +16,6 @@ import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
import { PokemonMove } from "#app/field/pokemon";
|
||||
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
|
||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||
|
||||
/** the i18n namespace for this encounter */
|
||||
@ -24,6 +23,9 @@ const namespace = "mysteryEncounter:trashToTreasure";
|
||||
|
||||
const SOUND_EFFECT_WAIT_TIME = 700;
|
||||
|
||||
// Items will cost 2.5x as much for remainder of the run
|
||||
const SHOP_ITEM_COST_MULTIPLIER = 2.5;
|
||||
|
||||
/**
|
||||
* Trash to Treasure encounter.
|
||||
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3809 | GitHub Issue #3809}
|
||||
@ -79,6 +81,8 @@ export const TrashToTreasureEncounter: MysteryEncounter =
|
||||
scene.loadSe("PRSFX- Dig2", "battle_anims", "PRSFX- Dig2.wav");
|
||||
scene.loadSe("PRSFX- Venom Drench", "battle_anims", "PRSFX- Venom Drench.wav");
|
||||
|
||||
encounter.setDialogueToken("costMultiplier", SHOP_ITEM_COST_MULTIPLIER.toString());
|
||||
|
||||
return true;
|
||||
})
|
||||
.withOption(
|
||||
@ -102,8 +106,14 @@ export const TrashToTreasureEncounter: MysteryEncounter =
|
||||
transitionMysteryEncounterIntroVisuals(scene);
|
||||
await tryApplyDigRewardItems(scene);
|
||||
|
||||
// Give the player the Black Sludge curse
|
||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.MYSTERY_ENCOUNTER_BLACK_SLUDGE));
|
||||
const blackSludge = generateModifierType(scene, modifierTypes.MYSTERY_ENCOUNTER_BLACK_SLUDGE, [SHOP_ITEM_COST_MULTIPLIER]);
|
||||
const modifier = blackSludge?.newModifier();
|
||||
if (modifier) {
|
||||
await scene.addModifier(modifier, false, false, false, true);
|
||||
scene.playSound("battle_anims/PRSFX- Venom Drench", { volume: 2 });
|
||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: modifier.type.name }), null, undefined, true);
|
||||
}
|
||||
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
})
|
||||
.build()
|
||||
@ -180,7 +190,7 @@ async function tryApplyDigRewardItems(scene: BattleScene) {
|
||||
}
|
||||
|
||||
scene.playSound("item_fanfare");
|
||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: "2 " + leftovers.name }), null, undefined, true);
|
||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: "2x " + leftovers.name }), null, undefined, true);
|
||||
|
||||
// First Shell bell
|
||||
for (const pokemon of party) {
|
||||
@ -207,7 +217,7 @@ async function tryApplyDigRewardItems(scene: BattleScene) {
|
||||
}
|
||||
|
||||
scene.playSound("item_fanfare");
|
||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: "2 " + shellBell.name }), null, undefined, true);
|
||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: "2x " + shellBell.name }), null, undefined, true);
|
||||
}
|
||||
|
||||
async function doGarbageDig(scene: BattleScene) {
|
||||
|
@ -12,7 +12,6 @@ import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode
|
||||
import { TrainerSlot } from "#app/data/trainer-config";
|
||||
import { catchPokemon, getHighestLevelPlayerPokemon, getSpriteKeysFromPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import PokemonData from "#app/system/pokemon-data";
|
||||
import { speciesEggMoves } from "#app/data/egg-moves";
|
||||
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
@ -53,11 +52,10 @@ export const UncommonBreedEncounter: MysteryEncounter =
|
||||
const level = getHighestLevelPlayerPokemon(scene, false, true).level - 2;
|
||||
const species = scene.arena.randomSpecies(scene.currentBattle.waveIndex, level, 0, getPartyLuckValue(scene.getParty()), true);
|
||||
const pokemon = new EnemyPokemon(scene, species, level, TrainerSlot.NONE, true);
|
||||
const speciesRootForm = pokemon.species.getRootSpeciesId();
|
||||
|
||||
// Pokemon will always have one of its egg moves in its moveset
|
||||
if (speciesEggMoves.hasOwnProperty(speciesRootForm)) {
|
||||
const eggMoves: Moves[] = speciesEggMoves[speciesRootForm];
|
||||
const eggMoves = pokemon.getEggMoves();
|
||||
if (eggMoves) {
|
||||
const eggMoveIndex = randSeedInt(4);
|
||||
const randomEggMove: Moves = eggMoves[eggMoveIndex];
|
||||
encounter.misc = {
|
||||
@ -72,6 +70,11 @@ export const UncommonBreedEncounter: MysteryEncounter =
|
||||
|
||||
encounter.misc.pokemon = pokemon;
|
||||
|
||||
// Defense/Spd buffs below wave 50, +1 to all stats otherwise
|
||||
const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = scene.currentBattle.waveIndex < 50 ?
|
||||
[Stat.DEF, Stat.SPDEF, Stat.SPD] :
|
||||
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD];
|
||||
|
||||
const config: EnemyPartyConfig = {
|
||||
pokemonConfigs: [{
|
||||
level: level,
|
||||
@ -81,7 +84,7 @@ export const UncommonBreedEncounter: MysteryEncounter =
|
||||
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
|
||||
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
|
||||
queueEncounterMessage(pokemon.scene, `${namespace}.option.1.stat_boost`);
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD], 1));
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
|
||||
}
|
||||
}],
|
||||
};
|
||||
@ -193,20 +196,7 @@ export const UncommonBreedEncounter: MysteryEncounter =
|
||||
const pokemon = encounter.misc.pokemon;
|
||||
|
||||
// Give 1 additional egg move
|
||||
const previousEggMove = encounter.misc.eggMove;
|
||||
const speciesRootForm = pokemon.species.getRootSpeciesId();
|
||||
if (speciesEggMoves.hasOwnProperty(speciesRootForm)) {
|
||||
const eggMoves: Moves[] = speciesEggMoves[speciesRootForm];
|
||||
let randomEggMove: Moves = eggMoves[randSeedInt(4)];
|
||||
while (randomEggMove === previousEggMove) {
|
||||
randomEggMove = eggMoves[randSeedInt(4)];
|
||||
}
|
||||
if (pokemon.moveset.length < 4) {
|
||||
pokemon.moveset.push(new PokemonMove(randomEggMove));
|
||||
} else {
|
||||
pokemon.moveset[1] = new PokemonMove(randomEggMove);
|
||||
}
|
||||
}
|
||||
givePokemonExtraEggMove(pokemon, encounter.misc.eggMove);
|
||||
|
||||
await catchPokemon(scene, pokemon, null, PokeballType.POKEBALL, false);
|
||||
setEncounterRewards(scene, { fillRemaining: true });
|
||||
@ -235,20 +225,7 @@ export const UncommonBreedEncounter: MysteryEncounter =
|
||||
const pokemon = encounter.misc.pokemon;
|
||||
|
||||
// Give 1 additional egg move
|
||||
const previousEggMove = encounter.misc.eggMove;
|
||||
const speciesRootForm = pokemon.species.getRootSpeciesId();
|
||||
if (speciesEggMoves.hasOwnProperty(speciesRootForm)) {
|
||||
const eggMoves: Moves[] = speciesEggMoves[speciesRootForm];
|
||||
let randomEggMove: Moves = eggMoves[randSeedInt(4)];
|
||||
while (randomEggMove === previousEggMove) {
|
||||
randomEggMove = eggMoves[randSeedInt(4)];
|
||||
}
|
||||
if (pokemon.moveset.length < 4) {
|
||||
pokemon.moveset.push(new PokemonMove(randomEggMove));
|
||||
} else {
|
||||
pokemon.moveset[1] = new PokemonMove(randomEggMove);
|
||||
}
|
||||
}
|
||||
givePokemonExtraEggMove(pokemon, encounter.misc.eggMove);
|
||||
|
||||
// Roll IVs a second time
|
||||
pokemon.ivs = pokemon.ivs.map(iv => {
|
||||
@ -266,3 +243,18 @@ export const UncommonBreedEncounter: MysteryEncounter =
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
|
||||
function givePokemonExtraEggMove(pokemon: EnemyPokemon, previousEggMove: Moves) {
|
||||
const eggMoves = pokemon.getEggMoves();
|
||||
if (eggMoves) {
|
||||
let randomEggMove: Moves = eggMoves[randSeedInt(4)];
|
||||
while (randomEggMove === previousEggMove) {
|
||||
randomEggMove = eggMoves[randSeedInt(4)];
|
||||
}
|
||||
if (pokemon.moveset.length < 4) {
|
||||
pokemon.moveset.push(new PokemonMove(randomEggMove));
|
||||
} else {
|
||||
pokemon.moveset[1] = new PokemonMove(randomEggMove);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import { IntegerHolder, isNullOrUndefined, randSeedInt, randSeedShuffle } from "
|
||||
import PokemonSpecies, { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { HiddenAbilityRateBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier } from "#app/modifier/modifier";
|
||||
import { achvs } from "#app/system/achv";
|
||||
import { speciesEggMoves } from "#app/data/egg-moves";
|
||||
import { MysteryEncounterPokemonData } from "#app/data/mystery-encounters/mystery-encounter-pokemon-data";
|
||||
import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
@ -105,7 +104,7 @@ const STANDARD_BST_TRANSFORM_BASE_VALUES: [number, number] = [40, 50];
|
||||
export const WeirdDreamEncounter: MysteryEncounter =
|
||||
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.WEIRD_DREAM)
|
||||
.withEncounterTier(MysteryEncounterTier.ROGUE)
|
||||
.withDisallowedChallenges(Challenges.SINGLE_TYPE)
|
||||
.withDisallowedChallenges(Challenges.SINGLE_TYPE, Challenges.SINGLE_GENERATION)
|
||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||
.withIntroSpriteConfigs([
|
||||
{
|
||||
@ -216,7 +215,7 @@ export const WeirdDreamEncounter: MysteryEncounter =
|
||||
pokemon.levelExp = 0;
|
||||
|
||||
pokemon.calculateStats();
|
||||
pokemon.updateInfo();
|
||||
await pokemon.updateInfo();
|
||||
}
|
||||
|
||||
leaveEncounterWithoutBattle(scene, true);
|
||||
@ -346,6 +345,9 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon
|
||||
// If the previous pokemon had pokerus, transfer to new pokemon
|
||||
newPokemon.pokerus = previousPokemon.pokerus;
|
||||
|
||||
// Transfer previous Pokemon's luck value
|
||||
newPokemon.luck = previousPokemon.getLuck();
|
||||
|
||||
// If the previous pokemon had higher IVs, override to those (after updating dex IVs > prevents perfect 31s on a new unlock)
|
||||
newPokemon.ivs = newPokemon.ivs.map((iv, index) => {
|
||||
return previousPokemon.ivs[index] > iv ? previousPokemon.ivs[index] : iv;
|
||||
@ -358,44 +360,15 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon
|
||||
|
||||
// Set the moveset of the new pokemon to be the same as previous, but with 1 egg move and 1 (attempted) STAB move of the new species
|
||||
newPokemon.generateAndPopulateMoveset();
|
||||
|
||||
// Try to find a favored STAB move
|
||||
let favoredMove;
|
||||
for (const move of newPokemon.moveset) {
|
||||
// Needs to match first type, second type will be replaced
|
||||
if (move?.getMove().type === newPokemon.getTypes()[0]) {
|
||||
favoredMove = move;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If was unable to find a move, uses first move in moveset (typically a high power STAB move)
|
||||
favoredMove = favoredMove ?? newPokemon.moveset[0];
|
||||
// Store a copy of a "standard" generated moveset for the new pokemon, will be used later for finding a favored move
|
||||
const newPokemonGeneratedMoveset = newPokemon.moveset;
|
||||
|
||||
newPokemon.moveset = previousPokemon.moveset;
|
||||
let eggMoveIndex: null | number = null;
|
||||
if (speciesEggMoves.hasOwnProperty(speciesRootForm)) {
|
||||
const eggMoves = speciesEggMoves[speciesRootForm];
|
||||
const randomEggMoveIndex = randSeedInt(4);
|
||||
const randomEggMove = eggMoves[randomEggMoveIndex];
|
||||
if (newPokemon.moveset.length < 4) {
|
||||
newPokemon.moveset.push(new PokemonMove(randomEggMove));
|
||||
} else {
|
||||
eggMoveIndex = randSeedInt(4);
|
||||
newPokemon.moveset[eggMoveIndex] = new PokemonMove(randomEggMove);
|
||||
}
|
||||
// For pokemon that the player owns (including ones just caught), unlock the egg move
|
||||
if (!!scene.gameData.dexData[speciesRootForm].caughtAttr) {
|
||||
await scene.gameData.setEggMoveUnlocked(getPokemonSpecies(speciesRootForm), randomEggMoveIndex, true);
|
||||
}
|
||||
}
|
||||
if (favoredMove) {
|
||||
let favoredMoveIndex = randSeedInt(4);
|
||||
while (favoredMoveIndex === eggMoveIndex) {
|
||||
favoredMoveIndex = randSeedInt(4);
|
||||
}
|
||||
|
||||
newPokemon.moveset[favoredMoveIndex] = favoredMove;
|
||||
}
|
||||
const newEggMoveIndex = await addEggMoveToNewPokemonMoveset(scene, newPokemon, speciesRootForm);
|
||||
|
||||
// Try to add a favored STAB move (might fail if Pokemon already knows a bunch of moves from newPokemonGeneratedMoveset)
|
||||
addFavoredMoveToNewPokemonMoveset(scene, newPokemon, newPokemonGeneratedMoveset, newEggMoveIndex);
|
||||
|
||||
// Randomize the second type of the pokemon
|
||||
// If the pokemon does not normally have a second type, it will gain 1
|
||||
@ -412,7 +385,7 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon
|
||||
|
||||
for (const item of transformation.heldItems) {
|
||||
item.pokemonId = newPokemon.id;
|
||||
scene.addModifier(item, false, false, false, true);
|
||||
await scene.addModifier(item, false, false, false, true);
|
||||
}
|
||||
|
||||
// Any pokemon that is at or below 450 BST gets +20 permanent BST to 3 stats: HP (halved, +10), lowest of Atk/SpAtk, and lowest of Def/SpDef
|
||||
@ -423,11 +396,12 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon
|
||||
stats.push(baseStats[Stat.ATK] < baseStats[Stat.SPATK] ? Stat.ATK : Stat.SPATK);
|
||||
// Def or SpDef
|
||||
stats.push(baseStats[Stat.DEF] < baseStats[Stat.SPDEF] ? Stat.DEF : Stat.SPDEF);
|
||||
// const mod = modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU().newModifier(newPokemon, 20, stats);
|
||||
const modType = modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU().generateType(scene.getParty(), [20, stats]);
|
||||
const modType = modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU()
|
||||
.generateType(scene.getParty(), [20, stats])
|
||||
?.withIdFromFunc(modifierTypes.MYSTERY_ENCOUNTER_OLD_GATEAU);
|
||||
const modifier = modType?.newModifier(newPokemon);
|
||||
if (modifier) {
|
||||
scene.addModifier(modifier);
|
||||
await scene.addModifier(modifier, false, false, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -435,13 +409,15 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon
|
||||
newPokemon.passive = previousPokemon.passive;
|
||||
|
||||
newPokemon.calculateStats();
|
||||
newPokemon.initBattleInfo();
|
||||
await newPokemon.updateInfo();
|
||||
}
|
||||
|
||||
// One random pokemon will get its passive unlocked
|
||||
const passiveDisabledPokemon = scene.getParty().filter(p => !p.passive);
|
||||
if (passiveDisabledPokemon?.length > 0) {
|
||||
passiveDisabledPokemon[randSeedInt(passiveDisabledPokemon.length)].passive = true;
|
||||
const enablePassiveMon = passiveDisabledPokemon[randSeedInt(passiveDisabledPokemon.length)];
|
||||
enablePassiveMon.passive = true;
|
||||
await enablePassiveMon.updateInfo(true);
|
||||
}
|
||||
|
||||
// If at least one new starter was unlocked, play 1 fanfare
|
||||
@ -471,7 +447,7 @@ function getTransformedSpecies(originalBst: number, bstSearchRange: [number, num
|
||||
if (validSpecies?.length > 20) {
|
||||
validSpecies = randSeedShuffle(validSpecies);
|
||||
newSpecies = validSpecies.pop();
|
||||
while (isNullOrUndefined(newSpecies) || alreadyUsedSpecies.includes(newSpecies!)) {
|
||||
while (isNullOrUndefined(newSpecies) || alreadyUsedSpecies.includes(newSpecies)) {
|
||||
newSpecies = validSpecies.pop();
|
||||
}
|
||||
} else {
|
||||
@ -481,7 +457,7 @@ function getTransformedSpecies(originalBst: number, bstSearchRange: [number, num
|
||||
}
|
||||
}
|
||||
|
||||
return newSpecies!;
|
||||
return newSpecies;
|
||||
}
|
||||
|
||||
function doShowDreamBackground(scene: BattleScene) {
|
||||
@ -566,3 +542,83 @@ function doSideBySideTransformations(scene: BattleScene, transformations: Pokemo
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns index of the new egg move within the Pokemon's moveset (not the index of the move in `speciesEggMoves`)
|
||||
* @param scene
|
||||
* @param newPokemon
|
||||
* @param speciesRootForm
|
||||
*/
|
||||
async function addEggMoveToNewPokemonMoveset(scene: BattleScene, newPokemon: PlayerPokemon, speciesRootForm: Species): Promise<number | null> {
|
||||
let eggMoveIndex: null | number = null;
|
||||
const eggMoves = newPokemon.getEggMoves()?.slice(0);
|
||||
if (eggMoves) {
|
||||
const eggMoveIndices = [0, 1, 2, 3];
|
||||
randSeedShuffle(eggMoveIndices);
|
||||
let randomEggMoveIndex = eggMoveIndices.pop();
|
||||
let randomEggMove = !isNullOrUndefined(randomEggMoveIndex) ? eggMoves[randomEggMoveIndex] : null;
|
||||
let retries = 0;
|
||||
while (retries < 3 && (!randomEggMove || newPokemon.moveset.some(m => m?.moveId === randomEggMove))) {
|
||||
// If Pokemon already knows this move, roll for another egg move
|
||||
randomEggMoveIndex = eggMoveIndices.pop();
|
||||
randomEggMove = !isNullOrUndefined(randomEggMoveIndex) ? eggMoves[randomEggMoveIndex] : null;
|
||||
retries++;
|
||||
}
|
||||
|
||||
if (randomEggMove) {
|
||||
if (!newPokemon.moveset.some(m => m?.moveId === randomEggMove)) {
|
||||
if (newPokemon.moveset.length < 4) {
|
||||
newPokemon.moveset.push(new PokemonMove(randomEggMove));
|
||||
} else {
|
||||
eggMoveIndex = randSeedInt(4);
|
||||
newPokemon.moveset[eggMoveIndex] = new PokemonMove(randomEggMove);
|
||||
}
|
||||
}
|
||||
|
||||
// For pokemon that the player owns (including ones just caught), unlock the egg move
|
||||
if (!isNullOrUndefined(randomEggMoveIndex) && !!scene.gameData.dexData[speciesRootForm].caughtAttr) {
|
||||
await scene.gameData.setEggMoveUnlocked(getPokemonSpecies(speciesRootForm), randomEggMoveIndex, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return eggMoveIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns index of the new egg move within the Pokemon's moveset (not the index of the move in `speciesEggMoves`)
|
||||
* @param scene
|
||||
* @param newPokemon
|
||||
* @param newPokemonGeneratedMoveset
|
||||
* @param newEggMoveIndex
|
||||
*/
|
||||
function addFavoredMoveToNewPokemonMoveset(scene: BattleScene, newPokemon: PlayerPokemon, newPokemonGeneratedMoveset: (PokemonMove | null)[], newEggMoveIndex: number | null) {
|
||||
let favoredMove: PokemonMove | null = null;
|
||||
for (const move of newPokemonGeneratedMoveset) {
|
||||
// Needs to match first type, second type will be replaced
|
||||
if (move?.getMove().type === newPokemon.getTypes()[0] && !newPokemon.moveset.some(m => m?.moveId === move?.moveId)) {
|
||||
favoredMove = move;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If was unable to find a favored move, uses first move in moveset that isn't already known (typically a high power STAB move)
|
||||
// Otherwise, it gains no favored move
|
||||
if (!favoredMove) {
|
||||
for (const move of newPokemonGeneratedMoveset) {
|
||||
// Needs to match first type, second type will be replaced
|
||||
if (!newPokemon.moveset.some(m => m?.moveId === move?.moveId)) {
|
||||
favoredMove = move;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Finally, assign favored move to random index that isn't the new egg move index
|
||||
if (favoredMove) {
|
||||
let favoredMoveIndex = randSeedInt(4);
|
||||
while (newEggMoveIndex !== null && favoredMoveIndex === newEggMoveIndex) {
|
||||
favoredMoveIndex = randSeedInt(4);
|
||||
}
|
||||
|
||||
newPokemon.moveset[favoredMoveIndex] = favoredMove;
|
||||
}
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ export class MysteryEncounterOptionBuilder implements Partial<IMysteryEncounterO
|
||||
return Object.assign(this, { requirements: this.requirements });
|
||||
}
|
||||
|
||||
withSceneMoneyRequirement(requiredMoney?: number, scalingMultiplier?: number) {
|
||||
withSceneMoneyRequirement(requiredMoney: number, scalingMultiplier?: number) {
|
||||
return this.withSceneRequirement(new MoneyRequirement(requiredMoney, scalingMultiplier));
|
||||
}
|
||||
|
||||
|
@ -165,9 +165,9 @@ export class WaveRangeRequirement extends EncounterSceneRequirement {
|
||||
}
|
||||
|
||||
override meetsRequirement(scene: BattleScene): boolean {
|
||||
if (!isNullOrUndefined(this.waveRange) && this.waveRange?.[0] <= this.waveRange?.[1]) {
|
||||
if (!isNullOrUndefined(this.waveRange) && this.waveRange[0] <= this.waveRange[1]) {
|
||||
const waveIndex = scene.currentBattle.waveIndex;
|
||||
if (waveIndex >= 0 && (this.waveRange?.[0] >= 0 && this.waveRange?.[0] > waveIndex) || (this.waveRange?.[1] >= 0 && this.waveRange?.[1] < waveIndex)) {
|
||||
if (waveIndex >= 0 && (this.waveRange[0] >= 0 && this.waveRange[0] > waveIndex) || (this.waveRange[1] >= 0 && this.waveRange[1] < waveIndex)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -251,7 +251,7 @@ export class WeatherRequirement extends EncounterSceneRequirement {
|
||||
const currentWeather = scene.arena.weather?.weatherType;
|
||||
let token = "";
|
||||
if (!isNullOrUndefined(currentWeather)) {
|
||||
token = WeatherType[currentWeather!].replace("_", " ").toLocaleLowerCase();
|
||||
token = WeatherType[currentWeather].replace("_", " ").toLocaleLowerCase();
|
||||
}
|
||||
return ["weather", token];
|
||||
}
|
||||
@ -274,9 +274,9 @@ export class PartySizeRequirement extends EncounterSceneRequirement {
|
||||
}
|
||||
|
||||
override meetsRequirement(scene: BattleScene): boolean {
|
||||
if (!isNullOrUndefined(this.partySizeRange) && this.partySizeRange?.[0] <= this.partySizeRange?.[1]) {
|
||||
if (!isNullOrUndefined(this.partySizeRange) && this.partySizeRange[0] <= this.partySizeRange[1]) {
|
||||
const partySize = this.excludeDisallowedPokemon ? scene.getParty().filter(p => p.isAllowedInBattle()).length : scene.getParty().length;
|
||||
if (partySize >= 0 && (this.partySizeRange?.[0] >= 0 && this.partySizeRange?.[0] > partySize) || (this.partySizeRange?.[1] >= 0 && this.partySizeRange?.[1] < partySize)) {
|
||||
if (partySize >= 0 && (this.partySizeRange[0] >= 0 && this.partySizeRange[0] > partySize) || (this.partySizeRange[1] >= 0 && this.partySizeRange[1] < partySize)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -326,7 +326,7 @@ export class MoneyRequirement extends EncounterSceneRequirement {
|
||||
requiredMoney: number; // Static value
|
||||
scalingMultiplier: number; // Calculates required money based off wave index
|
||||
|
||||
constructor(requiredMoney?: number, scalingMultiplier?: number) {
|
||||
constructor(requiredMoney: number, scalingMultiplier?: number) {
|
||||
super();
|
||||
this.requiredMoney = requiredMoney ?? 0;
|
||||
this.scalingMultiplier = scalingMultiplier ?? 0;
|
||||
@ -418,8 +418,8 @@ export class NatureRequirement extends EncounterPokemonRequirement {
|
||||
}
|
||||
|
||||
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
|
||||
if (!isNullOrUndefined(pokemon?.nature) && this.requiredNature.includes(pokemon!.nature)) {
|
||||
return ["nature", Nature[pokemon!.nature]];
|
||||
if (!isNullOrUndefined(pokemon?.nature) && this.requiredNature.includes(pokemon.nature)) {
|
||||
return ["nature", Nature[pokemon.nature]];
|
||||
}
|
||||
return ["nature", ""];
|
||||
}
|
||||
@ -620,7 +620,7 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement {
|
||||
return this.requiredStatusEffect.some((statusEffect) => {
|
||||
if (statusEffect === StatusEffect.NONE) {
|
||||
// StatusEffect.NONE also checks for null or undefined status
|
||||
return isNullOrUndefined(pokemon.status) || isNullOrUndefined(pokemon.status!.effect) || pokemon.status?.effect === statusEffect;
|
||||
return isNullOrUndefined(pokemon.status) || isNullOrUndefined(pokemon.status.effect) || pokemon.status.effect === statusEffect;
|
||||
} else {
|
||||
return pokemon.status?.effect === statusEffect;
|
||||
}
|
||||
@ -628,12 +628,11 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement {
|
||||
});
|
||||
} else {
|
||||
// for an inverted query, we only want to get the pokemon that don't have ANY of the listed StatusEffects
|
||||
// return partyPokemon.filter((pokemon) => this.requiredStatusEffect.filter((statusEffect) => pokemon.status?.effect === statusEffect).length === 0);
|
||||
return partyPokemon.filter((pokemon) => {
|
||||
return !this.requiredStatusEffect.some((statusEffect) => {
|
||||
if (statusEffect === StatusEffect.NONE) {
|
||||
// StatusEffect.NONE also checks for null or undefined status
|
||||
return isNullOrUndefined(pokemon.status) || isNullOrUndefined(pokemon.status!.effect) || pokemon.status?.effect === statusEffect;
|
||||
return isNullOrUndefined(pokemon.status) || isNullOrUndefined(pokemon.status.effect) || pokemon.status.effect === statusEffect;
|
||||
} else {
|
||||
return pokemon.status?.effect === statusEffect;
|
||||
}
|
||||
@ -645,7 +644,7 @@ export class StatusEffectRequirement extends EncounterPokemonRequirement {
|
||||
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
|
||||
const reqStatus = this.requiredStatusEffect.filter((a) => {
|
||||
if (a === StatusEffect.NONE) {
|
||||
return isNullOrUndefined(pokemon?.status) || isNullOrUndefined(pokemon!.status!.effect) || pokemon!.status!.effect === a;
|
||||
return isNullOrUndefined(pokemon?.status) || isNullOrUndefined(pokemon.status.effect) || pokemon.status.effect === a;
|
||||
}
|
||||
return pokemon!.status?.effect === a;
|
||||
});
|
||||
@ -988,8 +987,9 @@ export class HealthRatioRequirement extends EncounterPokemonRequirement {
|
||||
}
|
||||
|
||||
override getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
|
||||
if (!isNullOrUndefined(pokemon?.getHpRatio())) {
|
||||
return ["healthRatio", Math.floor(pokemon!.getHpRatio() * 100).toString() + "%"];
|
||||
const hpRatio = pokemon?.getHpRatio();
|
||||
if (!isNullOrUndefined(hpRatio)) {
|
||||
return ["healthRatio", Math.floor(hpRatio * 100).toString() + "%"];
|
||||
}
|
||||
return ["healthRatio", ""];
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import { FunAndGamesEncounter } from "#app/data/mystery-encounters/encounters/fu
|
||||
import { UncommonBreedEncounter } from "#app/data/mystery-encounters/encounters/uncommon-breed-encounter";
|
||||
import { GlobalTradeSystemEncounter } from "#app/data/mystery-encounters/encounters/global-trade-system-encounter";
|
||||
import { TheExpertPokemonBreederEncounter } from "#app/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter";
|
||||
import { getBiomeName } from "#app/data/biomes";
|
||||
|
||||
/**
|
||||
* Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * <number of missed spawns>) / MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT
|
||||
@ -362,11 +363,16 @@ export function initMysteryEncounters() {
|
||||
});
|
||||
|
||||
// Add ANY biome encounters to biome map
|
||||
mysteryEncountersByBiome.forEach(biomeEncounters => {
|
||||
let encounterBiomeTableLog = "";
|
||||
mysteryEncountersByBiome.forEach((biomeEncounters, biome) => {
|
||||
anyBiomeEncounters.forEach(encounter => {
|
||||
if (!biomeEncounters.includes(encounter)) {
|
||||
biomeEncounters.push(encounter);
|
||||
}
|
||||
});
|
||||
|
||||
encounterBiomeTableLog += `${getBiomeName(biome).toUpperCase()}: [${biomeEncounters.map(type => MysteryEncounterType[type].toString().toLowerCase()).sort().join(", ")}]\n`;
|
||||
});
|
||||
|
||||
console.debug("All Mystery Encounters by Biome:\n" + encounterBiomeTableLog);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ export function getEncounterText(scene: BattleScene, keyOrString?: string, prima
|
||||
return null;
|
||||
}
|
||||
|
||||
let textString: string | null = getTextWithDialogueTokens(scene, keyOrString!);
|
||||
let textString: string | null = getTextWithDialogueTokens(scene, keyOrString);
|
||||
|
||||
// Can only color the text if a Primary Style is defined
|
||||
// primaryStyle is applied to all text that does not have its own specified style
|
||||
|
@ -135,7 +135,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
||||
scene.currentBattle.trainer.destroy();
|
||||
}
|
||||
|
||||
trainerConfig = partyConfig?.trainerConfig ? partyConfig?.trainerConfig : trainerConfigs[trainerType!];
|
||||
trainerConfig = partyTrainerConfig ? partyTrainerConfig : trainerConfigs[trainerType!];
|
||||
|
||||
const doubleTrainer = trainerConfig.doubleOnly || (trainerConfig.hasDouble && !!partyConfig.doubleBattle);
|
||||
doubleBattle = doubleTrainer;
|
||||
@ -166,7 +166,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
||||
// This can be amplified or counteracted by setting levelAdditiveModifier in config
|
||||
// levelAdditiveModifier value of 0.5 will halve the modifier scaling, 2 will double it, etc.
|
||||
// Leaving null/undefined will disable level scaling
|
||||
const mult: number = !isNullOrUndefined(partyConfig.levelAdditiveModifier) ? partyConfig.levelAdditiveModifier! : 0;
|
||||
const mult: number = !isNullOrUndefined(partyConfig.levelAdditiveModifier) ? partyConfig.levelAdditiveModifier : 0;
|
||||
const additive = Math.max(Math.round((scene.currentBattle.waveIndex / 10) * mult), 0);
|
||||
battle.enemyLevels = battle.enemyLevels.map(level => level + additive);
|
||||
|
||||
@ -226,7 +226,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
||||
|
||||
// Set form
|
||||
if (!isNullOrUndefined(config.nickname)) {
|
||||
enemyPokemon.nickname = btoa(unescape(encodeURIComponent(config.nickname!)));
|
||||
enemyPokemon.nickname = btoa(unescape(encodeURIComponent(config.nickname)));
|
||||
}
|
||||
|
||||
// Generate new id, reset status and HP in case using data source
|
||||
@ -236,29 +236,29 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
||||
|
||||
// Set form
|
||||
if (!isNullOrUndefined(config.formIndex)) {
|
||||
enemyPokemon.formIndex = config.formIndex!;
|
||||
enemyPokemon.formIndex = config.formIndex;
|
||||
}
|
||||
|
||||
// Set shiny
|
||||
if (!isNullOrUndefined(config.shiny)) {
|
||||
enemyPokemon.shiny = config.shiny!;
|
||||
enemyPokemon.shiny = config.shiny;
|
||||
}
|
||||
|
||||
// Set Variant
|
||||
if (enemyPokemon.shiny && !isNullOrUndefined(config.variant)) {
|
||||
enemyPokemon.variant = config.variant!;
|
||||
enemyPokemon.variant = config.variant;
|
||||
}
|
||||
|
||||
// Set custom mystery encounter data fields (such as sprite scale, custom abilities, types, etc.)
|
||||
if (!isNullOrUndefined(config.mysteryEncounterPokemonData)) {
|
||||
enemyPokemon.mysteryEncounterPokemonData = config.mysteryEncounterPokemonData!;
|
||||
enemyPokemon.mysteryEncounterPokemonData = config.mysteryEncounterPokemonData;
|
||||
}
|
||||
|
||||
// Set Boss
|
||||
if (config.isBoss) {
|
||||
let segments = !isNullOrUndefined(config.bossSegments) ? config.bossSegments! : scene.getEncounterBossSegments(scene.currentBattle.waveIndex, level, enemySpecies, true);
|
||||
if (!isNullOrUndefined(config.bossSegmentModifier)) {
|
||||
segments += config.bossSegmentModifier!;
|
||||
segments += config.bossSegmentModifier;
|
||||
}
|
||||
enemyPokemon.setBoss(true, segments);
|
||||
}
|
||||
@ -294,18 +294,18 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
||||
|
||||
// Set ability
|
||||
if (!isNullOrUndefined(config.abilityIndex)) {
|
||||
enemyPokemon.abilityIndex = config.abilityIndex!;
|
||||
enemyPokemon.abilityIndex = config.abilityIndex;
|
||||
}
|
||||
|
||||
// Set gender
|
||||
if (!isNullOrUndefined(config.gender)) {
|
||||
enemyPokemon.gender = config.gender!;
|
||||
enemyPokemon.summonData.gender = config.gender!;
|
||||
enemyPokemon.summonData.gender = config.gender;
|
||||
}
|
||||
|
||||
// Set AI type
|
||||
if (!isNullOrUndefined(config.aiType)) {
|
||||
enemyPokemon.aiType = config.aiType!;
|
||||
enemyPokemon.aiType = config.aiType;
|
||||
}
|
||||
|
||||
// Set moves
|
||||
|
@ -218,7 +218,7 @@ export function getRandomSpeciesByStarterTier(starterTiers: number | [number, nu
|
||||
.map(s => [getPokemonSpecies(s[0]), s[1]]);
|
||||
|
||||
if (types && types.length > 0) {
|
||||
filteredSpecies = filteredSpecies.filter(s => types.includes(s[0].type1) || (!isNullOrUndefined(s[0].type2) && types.includes(s[0].type2!)));
|
||||
filteredSpecies = filteredSpecies.filter(s => types.includes(s[0].type1) || (!isNullOrUndefined(s[0].type2) && types.includes(s[0].type2)));
|
||||
}
|
||||
|
||||
// If no filtered mons exist at specified starter tiers, will expand starter search range until there are
|
||||
@ -311,7 +311,9 @@ export function applyHealToPokemon(scene: BattleScene, pokemon: PlayerPokemon, h
|
||||
* @param value
|
||||
*/
|
||||
export async function modifyPlayerPokemonBST(pokemon: PlayerPokemon, value: number) {
|
||||
const modType = modifierTypes.MYSTERY_ENCOUNTER_SHUCKLE_JUICE().generateType(pokemon.scene.getParty(), [value]);
|
||||
const modType = modifierTypes.MYSTERY_ENCOUNTER_SHUCKLE_JUICE()
|
||||
.generateType(pokemon.scene.getParty(), [value])
|
||||
?.withIdFromFunc(modifierTypes.MYSTERY_ENCOUNTER_SHUCKLE_JUICE);
|
||||
const modifier = modType?.newModifier(pokemon);
|
||||
if (modifier) {
|
||||
await pokemon.scene.addModifier(modifier, false, false, false, true);
|
||||
@ -780,8 +782,7 @@ export function getGoldenBugNetSpecies(): PokemonSpecies {
|
||||
*/
|
||||
export function getEncounterPokemonLevelForWave(scene: BattleScene, levelAdditiveModifier: number = 0) {
|
||||
const currentBattle = scene.currentBattle;
|
||||
// Default to use the first generated level from enemyLevels, or generate a new one if it DNE
|
||||
const baseLevel = currentBattle.enemyLevels && currentBattle.enemyLevels?.length > 0 ? currentBattle.enemyLevels[0] : currentBattle.getLevelForWave();
|
||||
const baseLevel = currentBattle.getLevelForWave();
|
||||
|
||||
// Add a level scaling modifier that is (+1 level per 10 waves) * levelAdditiveModifier
|
||||
return baseLevel + Math.max(Math.round((currentBattle.waveIndex / 10) * levelAdditiveModifier), 0);
|
||||
|
@ -54,7 +54,7 @@ const commonSplashMessages = [
|
||||
...Array(BATTLES_WON_WEIGHT_MULTIPLIER).fill("battlesWon"),
|
||||
"joinTheDiscord",
|
||||
"infiniteLevels",
|
||||
"everythingStacks",
|
||||
"everythingIsStackable",
|
||||
"optionalSaveScumming",
|
||||
"biomes",
|
||||
"openSource",
|
||||
@ -66,9 +66,9 @@ const commonSplashMessages = [
|
||||
"infiniteFusionAtHome",
|
||||
"brokenEggMoves",
|
||||
"magnificent",
|
||||
"mubstitute",
|
||||
"doPeopleReadThis",
|
||||
"thatsCrazy",
|
||||
"oranceJuice",
|
||||
"gottaCatchEmAll",
|
||||
"questionableBalancing",
|
||||
"coolShaders",
|
||||
"aiFree",
|
||||
@ -77,14 +77,105 @@ const commonSplashMessages = [
|
||||
"moreAddictiveThanIntended",
|
||||
"mostlyConsistentSeeds",
|
||||
"achievementPointsDontDoAnything",
|
||||
"youDoNotStartAtLevel",
|
||||
"dontTalkAboutTheManaphyEggIncident",
|
||||
"nothingBeatsAJellyFilledDonut",
|
||||
"dontTalkAboutTheTinkatonIncident",
|
||||
"alsoTryPokengine",
|
||||
"alsoTryEmeraldRogue",
|
||||
"alsoTryRadicalRed",
|
||||
"eeveeExpo",
|
||||
"ynoproject",
|
||||
"checkOutYnoproject",
|
||||
"breedersInSpace",
|
||||
"alsoTryPokemonUnbound",
|
||||
"tryTheJohtoDragonChallenge",
|
||||
"basicReadingAbilityRecommended",
|
||||
"shoutoutsToTheArtists",
|
||||
"gamblingNotEncouraged",
|
||||
"dontForgetToTakeABreak",
|
||||
"wEvent",
|
||||
"ifItsNotAccurateItsAccurate",
|
||||
"everyLossIsProgressMade",
|
||||
"liveWoChienReaction",
|
||||
"itsAFeatureNotABug",
|
||||
"theEggsAreNotForEating",
|
||||
"7.8outOf10TooManyWaterBiomes",
|
||||
"butNothingHappened",
|
||||
"thePowerOfScienceIsAmazing",
|
||||
"freeToPlay",
|
||||
"theresATimeAndPlaceForEverything",
|
||||
"nowWithShinierShinies",
|
||||
"smilesGoForMiles",
|
||||
"certainlyNotDragonFree",
|
||||
"haveANiceDay",
|
||||
"redacted",
|
||||
"hi",
|
||||
"transRights",
|
||||
"shinyOddsHigherThanYouThink",
|
||||
"noFalseTrades",
|
||||
"notForProfit",
|
||||
"timeForYourDailyRun",
|
||||
"moreEggsThanADaycare",
|
||||
"disclaimerHarshSunDoesNotGiveVitaminD",
|
||||
"whoNeedsAMap",
|
||||
"luxrayIsNotADarkType",
|
||||
"selfDestructiveEncounters",
|
||||
"mostOptionsAreViable",
|
||||
"pokerogueMorse",
|
||||
"smiley",
|
||||
"beAwareOfPassives",
|
||||
"asSeenOnTheWorldWideWeb",
|
||||
"vaultinVeluzas",
|
||||
"tooManyStarters",
|
||||
"checkTheWiki",
|
||||
"winWithYourFavorites",
|
||||
"alsoTryPokerogueWait",
|
||||
"theWayISeeItKyogreIsSurrounded",
|
||||
"tryOutHoneyGather",
|
||||
"notForTheFaintOfHeart",
|
||||
"p",
|
||||
"flipYourDeviceToEvolveInkay",
|
||||
"inArceusWeTrust",
|
||||
"whyDidTheTorchicCrossTheRoad",
|
||||
"goodLuck",
|
||||
"fuseWisely",
|
||||
"compensation",
|
||||
"prepareForTroubleAndMakeItDouble",
|
||||
"anEggForYourTroubles",
|
||||
"regirock",
|
||||
"hereForAGoodTime",
|
||||
"getGoodOrDont",
|
||||
"checkTheSubreddit",
|
||||
"betterNerfGreninja",
|
||||
"inCaseOfUpdateClearYourCache",
|
||||
"insertTextHere",
|
||||
"endingEndlessNotFound",
|
||||
"iLikeMyEggsVouchered",
|
||||
"YOU",
|
||||
"noAddedSugar",
|
||||
"notSponsored",
|
||||
"notRated",
|
||||
"justOneMoreWaveMom",
|
||||
"saltCured",
|
||||
"onlyOnPokerogueNet",
|
||||
"pixelPerfection",
|
||||
"openSource",
|
||||
"probablyGood",
|
||||
"itsAMonsterHouse",
|
||||
"dontForgetYourPassword",
|
||||
"tripleTripleTripleAxel",
|
||||
"questionExclamation",
|
||||
"clownEncounters",
|
||||
"fullOfBerries",
|
||||
"limitsAreMeantToBeBrokenSometimes",
|
||||
"keepItCasual",
|
||||
"serversProbablyWorking",
|
||||
"mew",
|
||||
"makeItRainAndYourProblemsGoAway",
|
||||
"customMusicTracks",
|
||||
"youAreValid",
|
||||
"number591IsLookingOff",
|
||||
"timeForYourDeliDelivery",
|
||||
"goodFirstImpression",
|
||||
"iPreferRarerCandies",
|
||||
];
|
||||
|
||||
//#region Seasonal Messages
|
||||
@ -94,13 +185,13 @@ const seasonalSplashMessages: Season[] = [
|
||||
name: "Halloween",
|
||||
start: "09-15",
|
||||
end: "10-31",
|
||||
messages: ["halloween.pumpkaboosAbout", "halloween.mayContainSpiders", "halloween.spookyScaryDuskulls"],
|
||||
messages: ["halloween.pumpkabooAbout", "halloween.mayContainSpiders", "halloween.spookyScarySkeledirge", "halloween.gourgeistUsedTrickOrTreat", "halloween.letsSnuggleForever"],
|
||||
},
|
||||
{
|
||||
name: "XMAS",
|
||||
start: "12-01",
|
||||
end: "12-26",
|
||||
messages: ["xmas.happyHolidays", "xmas.delibirdSeason"],
|
||||
messages: ["xmas.happyHolidays", "xmas.unaffilicatedWithDelibirdServices", "xmas.delibirdSeason", "xmas.diamondsFromTheSky", "xmas.holidayStylePikachuNotIncluded"],
|
||||
},
|
||||
{
|
||||
name: "New Year's",
|
||||
|
@ -44,6 +44,10 @@ function getStatusEffectMessageKey(statusEffect: StatusEffect | undefined): stri
|
||||
}
|
||||
|
||||
export function getStatusEffectObtainText(statusEffect: StatusEffect | undefined, pokemonNameWithAffix: string, sourceText?: string): string {
|
||||
if (statusEffect === StatusEffect.NONE) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!sourceText) {
|
||||
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.obtain`as ParseKeys;
|
||||
return i18next.t(i18nKey, { pokemonNameWithAffix: pokemonNameWithAffix });
|
||||
@ -53,21 +57,33 @@ export function getStatusEffectObtainText(statusEffect: StatusEffect | undefined
|
||||
}
|
||||
|
||||
export function getStatusEffectActivationText(statusEffect: StatusEffect, pokemonNameWithAffix: string): string {
|
||||
if (statusEffect === StatusEffect.NONE) {
|
||||
return "";
|
||||
}
|
||||
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.activation` as ParseKeys;
|
||||
return i18next.t(i18nKey, { pokemonNameWithAffix: pokemonNameWithAffix });
|
||||
}
|
||||
|
||||
export function getStatusEffectOverlapText(statusEffect: StatusEffect, pokemonNameWithAffix: string): string {
|
||||
if (statusEffect === StatusEffect.NONE) {
|
||||
return "";
|
||||
}
|
||||
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.overlap` as ParseKeys;
|
||||
return i18next.t(i18nKey, { pokemonNameWithAffix: pokemonNameWithAffix });
|
||||
}
|
||||
|
||||
export function getStatusEffectHealText(statusEffect: StatusEffect, pokemonNameWithAffix: string): string {
|
||||
if (statusEffect === StatusEffect.NONE) {
|
||||
return "";
|
||||
}
|
||||
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.heal` as ParseKeys;
|
||||
return i18next.t(i18nKey, { pokemonNameWithAffix: pokemonNameWithAffix });
|
||||
}
|
||||
|
||||
export function getStatusEffectDescriptor(statusEffect: StatusEffect): string {
|
||||
if (statusEffect === StatusEffect.NONE) {
|
||||
return "";
|
||||
}
|
||||
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.description` as ParseKeys;
|
||||
return i18next.t(i18nKey);
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
|
||||
};
|
||||
|
||||
if (!isNullOrUndefined(result.species)) {
|
||||
const keys = getSpriteKeysFromSpecies(result.species!);
|
||||
const keys = getSpriteKeysFromSpecies(result.species);
|
||||
result.spriteKey = keys.spriteKey;
|
||||
result.fileRoot = keys.fileRoot;
|
||||
result.isPokemon = true;
|
||||
|
@ -1258,8 +1258,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
return allAbilities[Overrides.OPP_ABILITY_OVERRIDE];
|
||||
}
|
||||
if (this.isFusion()) {
|
||||
if (!isNullOrUndefined(this.fusionMysteryEncounterPokemonData?.ability) && this.fusionMysteryEncounterPokemonData!.ability !== -1) {
|
||||
return allAbilities[this.fusionMysteryEncounterPokemonData!.ability];
|
||||
if (!isNullOrUndefined(this.fusionMysteryEncounterPokemonData?.ability) && this.fusionMysteryEncounterPokemonData.ability !== -1) {
|
||||
return allAbilities[this.fusionMysteryEncounterPokemonData.ability];
|
||||
} else {
|
||||
return allAbilities[this.getFusionSpeciesForm(ignoreOverride).getAbility(this.fusionAbilityIndex)];
|
||||
}
|
||||
@ -1799,8 +1799,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
*
|
||||
* @returns list of egg moves
|
||||
*/
|
||||
getEggMoves() : Moves[] {
|
||||
return speciesEggMoves[this.species.speciesId];
|
||||
getEggMoves() : Moves[] | undefined {
|
||||
return speciesEggMoves[this.getSpeciesForm().getRootSpeciesId(true)];
|
||||
}
|
||||
|
||||
setMove(moveIndex: integer, moveId: Moves): void {
|
||||
|
@ -1,12 +1,6 @@
|
||||
{
|
||||
"none": {
|
||||
"name": "None",
|
||||
"description": "",
|
||||
"obtain": "",
|
||||
"obtainSource": "",
|
||||
"activation": "",
|
||||
"overlap": "",
|
||||
"heal": ""
|
||||
"name": "None"
|
||||
},
|
||||
"poison": {
|
||||
"name": "Gift",
|
||||
|
@ -31,7 +31,7 @@
|
||||
"option": {
|
||||
"1": {
|
||||
"label": "Accept the Challenge",
|
||||
"tooltip": "(-) Tough Battle\n(+) Gain a @[TOOLTIP_TITLE]{Very Rare Egg}"
|
||||
"tooltip": "(-) Extremely Tough Battle\n(+) Gain a @[TOOLTIP_TITLE]{Very Rare Egg}"
|
||||
},
|
||||
"2": {
|
||||
"label": "Refuse the Challenge",
|
||||
|
@ -8,7 +8,7 @@
|
||||
"option": {
|
||||
"1": {
|
||||
"label": "Offer to Battle",
|
||||
"tooltip": "(-) Challenging Battle\n(+) Teach a Pokémon a Bug Type Move",
|
||||
"tooltip": "(-) Challenging Battle\n(+) Teach any Pokémon a Bug Type Move",
|
||||
"selected": "A challenge, eh?\nMy bugs are more than ready for you!"
|
||||
},
|
||||
"2": {
|
||||
|
@ -8,23 +8,23 @@
|
||||
"option": {
|
||||
"1": {
|
||||
"label": "Battle the Clown",
|
||||
"tooltip": "(-) Strange Battle\n(?) Affects Pokémon Abilities",
|
||||
"tooltip": "(-) Strange Battle\n(?) Affects One Pokémon's Ability",
|
||||
"selected": "Your pitiful Pokémon are poised for a pathetic performance!",
|
||||
"apply_ability_dialogue": "A sensational showcase!\nYour savvy suits a sensational skill as spoils!",
|
||||
"apply_ability_dialogue": "A sensational showcase!\nYour savvy suits a special skill as spoils!",
|
||||
"apply_ability_message": "The clown is offering to permanently Skill Swap one of your Pokémon's ability to {{ability}}!",
|
||||
"ability_prompt": "Would you like to permanently teach a Pokémon the {{ability}} ability?",
|
||||
"ability_gained": "@s{level_up_fanfare}{{chosenPokemon}} gained the {{ability}} ability!"
|
||||
},
|
||||
"2": {
|
||||
"label": "Remain Unprovoked",
|
||||
"tooltip": "(-) Upsets the Clown\n(?) Affects Pokémon Items",
|
||||
"tooltip": "(?) Affects One Pokémon's Items",
|
||||
"selected": "Dismal dodger, you deny a delightful duel?\nFeel my fury!",
|
||||
"selected_2": "The clown's {{blacephalonName}} uses Trick!\nAll of your {{switchPokemon}}'s items were randomly swapped!",
|
||||
"selected_3": "Flustered fool, fall for my flawless deception!"
|
||||
},
|
||||
"3": {
|
||||
"label": "Return the Insults",
|
||||
"tooltip": "(-) Upsets the Clown\n(?) Affects Pokémon Types",
|
||||
"tooltip": "(?) Affects Your Pokémons' Types",
|
||||
"selected": "Dismal dodger, you deny a delightful duel?\nFeel my fury!",
|
||||
"selected_2": "The clown's {{blacephalonName}} uses a strange move!\nAll of your team's types were randomly swapped!",
|
||||
"selected_3": "Flustered fool, fall for my flawless deception!"
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"intro": "An {{oricorioName}} dances sadly alone, without a partner.",
|
||||
"title": "Dancing Lessons",
|
||||
"description": "The {{oricorioName}} doesn't seem aggressive, if anything it seems sad.\n\nMaybe it just wants someone to dance with...",
|
||||
"description": "The {{oricorioName}} doesn't seem aggressive, if anything it seems despondent.\n\nPerhaps it just wants someone to dance with...",
|
||||
"query": "What will you do?",
|
||||
"option": {
|
||||
"1": {
|
||||
@ -12,7 +12,7 @@
|
||||
},
|
||||
"2": {
|
||||
"label": "Learn Its Dance",
|
||||
"tooltip": "(+) Teach a Pokémon Revelation Dance",
|
||||
"tooltip": "(+) Teach any Pokémon Revelation Dance",
|
||||
"selected": "You watch the {{oricorioName}} closely as it performs its dance...$@s{level_up_fanfare}Your {{selectedPokemon}} learned from the {{oricorioName}}!"
|
||||
},
|
||||
"3": {
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
|
||||
{
|
||||
"intro": "A pack of {{delibirdName}} have appeared!",
|
||||
"intro": "A flock of {{delibirdName}} have appeared!",
|
||||
"title": "Delibir-dy",
|
||||
"description": "The {{delibirdName}}s are looking at you expectantly, as if they want something. Perhaps giving them an item or some money would satisfy them?",
|
||||
"query": "What will you give them?",
|
||||
@ -25,5 +25,5 @@
|
||||
"selected": "You toss the {{chosenItem}} to the {{delibirdName}}s,\nwho chatter amongst themselves excitedly.$They turn back to you and happily give you a present!"
|
||||
}
|
||||
},
|
||||
"outro": "The {{delibirdName}} pack happily waddles off into the distance.$What a curious little exchange!"
|
||||
"outro": "The {{delibirdName}} flock happily waddles off into the distance.$What a curious little exchange!"
|
||||
}
|
@ -11,13 +11,13 @@
|
||||
},
|
||||
"2": {
|
||||
"label": "Wonder Trade",
|
||||
"tooltip": "(+) Send one of your Pokémon to the GTS and get a random Pokémon in return"
|
||||
"tooltip": "(+) Send one of your Pokémon to the GTS and get a random special Pokémon in return"
|
||||
},
|
||||
"3": {
|
||||
"label": "Trade an Item",
|
||||
"trade_options_prompt": "Select an item to send.",
|
||||
"invalid_selection": "This Pokémon doesn't have legal items to trade.",
|
||||
"tooltip": "(+) Send one of your Items to the GTS and get a random new Item"
|
||||
"tooltip": "(+) Send one of your Items to the GTS and get a random improved Item"
|
||||
},
|
||||
"4": {
|
||||
"label": "Leave",
|
||||
|
@ -6,7 +6,7 @@
|
||||
"option": {
|
||||
"1": {
|
||||
"label": "Open It",
|
||||
"tooltip": "@[SUMMARY_BLUE]{(35%) Something terrible}\n@[SUMMARY_GREEN]{(40%) Okay Rewards}\n@[SUMMARY_GREEN]{(20%) Good Rewards}\n@[SUMMARY_GREEN]{(4%) Great Rewards}\n@[SUMMARY_GREEN]{(1%) Amazing Rewards}",
|
||||
"tooltip": "@[SUMMARY_BLUE]{({{trapPercent}}%) Something terrible}\n@[SUMMARY_GREEN]{({{commonPercent}}%) Okay Rewards}\n@[SUMMARY_GREEN]{({{ultraPercent}}%) Good Rewards}\n@[SUMMARY_GREEN]{({{roguePercent}}%) Great Rewards}\n@[SUMMARY_GREEN]{({{masterPercent}}%) Amazing Rewards}",
|
||||
"selected": "You open the chest to find...",
|
||||
"normal": "Just some normal tools and items.",
|
||||
"good": "Some pretty nice tools and items.",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"intro": "It's a safari zone!",
|
||||
"title": "The Safari Zone",
|
||||
"description": "There are all kinds of rare and special Pokémon that can be found here!\nIf you choose to enter, you'll have a time limit of 3 wild encounters where you can try to catch these special Pokémon.\n\nBeware, though. These Pokémon may flee before you're able to catch them!",
|
||||
"description": "There are all kinds of rare and special Pokémon that can be found here!\nIf you choose to enter, you'll have a time limit of @[TOOLTIP_TITLE]{{{numEncounters}} wild encounters} where you can try to catch these special Pokémon.\n\nBeware, though. These Pokémon may flee before you're able to catch them!",
|
||||
"query": "Would you like to enter?",
|
||||
"option": {
|
||||
"1": {
|
||||
|
@ -3,8 +3,8 @@
|
||||
"speaker": "Gentleman",
|
||||
"intro_dialogue": "Hello there! Have I got a deal just for YOU!",
|
||||
"title": "The Pokémon Salesman",
|
||||
"description": "\"This {{purchasePokemon}} is extremely unique and carries an ability not normally found in its species! I'll let you have this swell {{purchasePokemon}} for just {{price, money}}!\"\n\n\"What do you say?\"",
|
||||
"description_shiny": "\"This {{purchasePokemon}} is extremely unique and has a pigment not normally found in its species! I'll let you have this swell {{purchasePokemon}} for just {{price, money}}!\"\n\n\"What do you say?\"",
|
||||
"description": "\"This {{purchasePokemon}} is extremely unique and @[TOOLTIP_TITLE]{carries an ability not normally found in its species}! I'll let you have this swell {{purchasePokemon}} for just {{price, money}}!\"\n\n\"What do you say?\"",
|
||||
"description_shiny": "\"This {{purchasePokemon}} is extremely unique and @[TOOLTIP_TITLE]{has a pigment not normally found in its species}! I'll let you have this swell {{purchasePokemon}} for just {{price, money}}!\"\n\n\"What do you say?\"",
|
||||
"query": "What will you do?",
|
||||
"option": {
|
||||
"1": {
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"intro": "It's a massive {{shuckleName}} and what appears\nto be a large stash of... juice?",
|
||||
"title": "The Strong Stuff",
|
||||
"description": "The {{shuckleName}} that blocks your path looks incredibly strong. Meanwhile, the juice next to it is emanating power of some kind.\n\nThe {{shuckleName}} extends its feelers in your direction. It seems like it wants to do something...",
|
||||
"description": "The {{shuckleName}} that blocks your path looks formidable. Meanwhile, the juice next to it emanates power of some kind.\n\nThe {{shuckleName}} extends its feelers in your direction. It seems like it wants to do something...",
|
||||
"query": "What will you do?",
|
||||
"option": {
|
||||
"1": {
|
||||
|
@ -3,12 +3,12 @@
|
||||
"speaker": "The Winstrates",
|
||||
"intro_dialogue": "We're the Winstrates!$What do you say to taking on our family in a series of Pokémon battles?",
|
||||
"title": "The Winstrate Challenge",
|
||||
"description": "The Winstrates are a family of 5 trainers, and they want to battle! If you beat all of them back-to-back, they'll give you a grand prize. But can you handle the heat?",
|
||||
"description": "The Winstrates are a family of @[TOOLTIP_TITLE]{5 trainers}, and they want to battle! If you beat all of them back-to-back, they'll give you a grand prize. But can you handle the heat?",
|
||||
"query": "What will you do?",
|
||||
"option": {
|
||||
"1": {
|
||||
"label": "Accept the Challenge",
|
||||
"tooltip": "(-) Brutal Battle\n(+) Special Item Reward",
|
||||
"tooltip": "(-) Brutal Battle Against 5 Trainers\n(+) Special Item Reward",
|
||||
"selected": "Let the challenge begin!"
|
||||
},
|
||||
"2": {
|
||||
|
@ -1,24 +1,24 @@
|
||||
{
|
||||
"intro": "You've come across some\ntraining tools and supplies.",
|
||||
"title": "Training Session",
|
||||
"description": "These supplies look like they could be used to train a member of your party! There are a few ways you could train your Pokémon, by battling against it with the rest of your team.",
|
||||
"description": "These supplies look like they could be used to train a member of your party! There are a few ways you could train your Pokémon, by @[TOOLTIP_TITLE]{battling and defeating it with the rest of your team}.",
|
||||
"query": "How should you train?",
|
||||
"invalid_selection": "Pokémon must be healthy enough.",
|
||||
"option": {
|
||||
"1": {
|
||||
"label": "Light Training",
|
||||
"tooltip": "(-) Light Battle\n(+) Improve 2 Random IVs of Pokémon",
|
||||
"tooltip": "(-) Light Battle with Chosen Pokémon\n(+) Permanently Improve 2 Random IVs of Chosen Pokémon",
|
||||
"finished": "{{selectedPokemon}} returns, feeling\nworn out but accomplished!$Its {{stat1}} and {{stat2}} IVs were improved!"
|
||||
},
|
||||
"2": {
|
||||
"label": "Moderate Training",
|
||||
"tooltip": "(-) Moderate Battle\n(+) Change Pokémon's Nature",
|
||||
"tooltip": "(-) Moderate Battle with Chosen Pokémon\n(+) Permanently Change Chosen Pokémon's Nature",
|
||||
"select_prompt": "Select a new nature\nto train your Pokémon in.",
|
||||
"finished": "{{selectedPokemon}} returns, feeling\nworn out but accomplished!$Its nature was changed to {{nature}}!"
|
||||
},
|
||||
"3": {
|
||||
"label": "Heavy Training",
|
||||
"tooltip": "(-) Harsh Battle\n(+) Change Pokémon's Ability",
|
||||
"tooltip": "(-) Harsh Battle with Chosen Pokémon\n(+) Permanently Change Chosen Pokémon's Ability",
|
||||
"select_prompt": "Select a new ability\nto train your Pokémon in.",
|
||||
"finished": "{{selectedPokemon}} returns, feeling\nworn out but accomplished!$Its ability was changed to {{ability}}!"
|
||||
},
|
||||
|
@ -6,7 +6,7 @@
|
||||
"option": {
|
||||
"1": {
|
||||
"label": "Dig for Valuables",
|
||||
"tooltip": "(-) Items in Shops Cost 3x\n(+) Gain Amazing Items",
|
||||
"tooltip": "(-) Items in Shops Will Cost {{costMultiplier}}x\n(+) Gain Amazing Items",
|
||||
"selected": "You wade through the garbage pile, becoming mired in filth.$There's no way any respectable shopkeeper would\nsell you items at the normal rate in your grimy state!$You'll have to pay extra for items now.$However, you found some incredible items in the garbage!"
|
||||
},
|
||||
"2": {
|
||||
|
@ -1,10 +1,10 @@
|
||||
{
|
||||
"battlesWon": "{{count, number}} Battles Won!",
|
||||
"battlesWon": "Battles Won!",
|
||||
"joinTheDiscord": "Join the Discord!",
|
||||
"infiniteLevels": "Infinite Levels!",
|
||||
"everythingStacks": "Everything Stacks!",
|
||||
"everythingIsStackable": "Everything Is Stackable*!",
|
||||
"optionalSaveScumming": "Optional Save Scumming!",
|
||||
"biomes": "35 Biomes!",
|
||||
"biomes": "38 Biomes!",
|
||||
"openSource": "Open Source!",
|
||||
"playWithSpeed": "Play with 5x Speed!",
|
||||
"liveBugTesting": "Live Bug Testing!",
|
||||
@ -14,9 +14,9 @@
|
||||
"infiniteFusionAtHome": "Infinite Fusion at Home!",
|
||||
"brokenEggMoves": "Broken Egg Moves!",
|
||||
"magnificent": "Magnificent!",
|
||||
"mubstitute": "Mubstitute!",
|
||||
"doPeopleReadThis": "Do People Read This?",
|
||||
"thatsCrazy": "That's Crazy!",
|
||||
"oranceJuice": "Orance Juice!",
|
||||
"gottaCatchEmAll": "Gotta Catch 'Em All!",
|
||||
"questionableBalancing": "Questionable Balancing!",
|
||||
"coolShaders": "Cool Shaders!",
|
||||
"aiFree": "AI-Free!",
|
||||
@ -25,22 +25,118 @@
|
||||
"moreAddictiveThanIntended": "More Addictive than Intended!",
|
||||
"mostlyConsistentSeeds": "Mostly Consistent Seeds!",
|
||||
"achievementPointsDontDoAnything": "Achievement Points Don't Do Anything!",
|
||||
"youDoNotStartAtLevel": "You Do Not Start at Level 2000!",
|
||||
"dontTalkAboutTheManaphyEggIncident": "Don't Talk About the Manaphy Egg Incident!",
|
||||
"nothingBeatsAJellyFilledDonut": "Nothing Beats a Jelly-Filled Donut!",
|
||||
"dontTalkAboutTheTinkatonIncident": "Don't Talk About the Tinkaton Incident!",
|
||||
"alsoTryPokengine": "Also Try Pokéngine!",
|
||||
"alsoTryEmeraldRogue": "Also Try Emerald Rogue!",
|
||||
"alsoTryRadicalRed": "Also Try Radical Red!",
|
||||
"eeveeExpo": "Eevee Expo!",
|
||||
"ynoproject": "YNOproject!",
|
||||
"breedersInSpace": "Breeders in space!",
|
||||
"checkOutYnoproject": "Check out YNOproject!",
|
||||
"breedersInSpace": "Breeders in Space!",
|
||||
"alsoTryPokemonUnbound": "Also Try Pokemon Unbound!",
|
||||
"tryTheJohtoDragonChallenge": "Try the Johto Dragon Challenge!",
|
||||
"basicReadingAbilityRecommended": "Basic Reading Ability Recommended!",
|
||||
"shoutoutsToTheArtists": "Shoutouts to the Artists!",
|
||||
"gamblingNotEncouraged": "Gambling Not Encouraged!",
|
||||
"dontForgetToTakeABreak": "Don't Forget To Take a Break!",
|
||||
"wEvent": "W Event",
|
||||
"ifItsNotAccurateItsAccurate": "If It's Not 100% Accurate, It's 50%.",
|
||||
"everyLossIsProgressMade": "Every Loss Is Progress Made!",
|
||||
"liveWoChienReaction": "Live Wo-Chien Reaction:",
|
||||
"itsAFeatureNotABug": "It's a Feature, Not a Bug!",
|
||||
"theEggsAreNotForEating": "The Eggs Are Not for Eating!",
|
||||
"7.8outOf10TooManyWaterBiomes": "7.8 out of 10, Too Many Water Biomes.",
|
||||
"butNothingHappened": "But Nothing Happened!",
|
||||
"thePowerOfScienceIsAmazing": "The Power of Science Is Amazing!",
|
||||
"freeToPlay": "Free To Play!",
|
||||
"theresATimeAndPlaceForEverything": "There's a Time and Place for Everything!",
|
||||
"nowWithShinierShinies": "Now With Shinier Shinies!",
|
||||
"smilesGoForMiles": "Smiles Go for Miles!",
|
||||
"certainlyNotDragonFree": "Certainly Not Dragon Free!",
|
||||
"haveANiceDay": "Have a Nice Day!",
|
||||
"redacted": "[REDACTED]",
|
||||
"hi": "hi",
|
||||
"transRights": "Trans Rights!",
|
||||
"shinyOddsHigherThanYouThink": "Shiny Odds Higher Than You Think!",
|
||||
"noFalseTrades": "No False Trades!",
|
||||
"notForProfit": "Not for Profit!",
|
||||
"timeForYourDailyRun": "Time for Your Daily Run!",
|
||||
"moreEggsThanADaycare": "More Eggs Than a Daycare!",
|
||||
"disclaimerHarshSunDoesNotGiveVitaminD": "Disclaimer: Harsh Sun Does NOT Give Vitamin D!",
|
||||
"whoNeedsAMap": "Who Needs a Map?",
|
||||
"luxrayIsNotADarkType": "Luxray Is Not a Dark-Type!",
|
||||
"selfDestructiveEncounters": "Self-Destructive Encounters!",
|
||||
"mostOptionsAreViable": "Most Options Are Viable!",
|
||||
"pokerogueMorse": ".--. --- -.- . .-. --- --. ..- .",
|
||||
"smiley": ":)",
|
||||
"beAwareOfPassives": "Be Aware of Passives!",
|
||||
"asSeenOnTheWorldWideWeb": "As Seen on the World-Wide Web!",
|
||||
"vaultinVeluzas": "Vaultin' Veluza!",
|
||||
"tooManyStarters": "Too Many Starters!",
|
||||
"checkTheWiki": "Check the Wiki!",
|
||||
"winWithYourFavorites": "Win With Your Favorites!",
|
||||
"alsoTryPokerogueWait": "Also Try PokéRogue! Wait...",
|
||||
"theWayISeeItKyogreIsSurrounded": "The Way I See It, Kyogre Is Surrounded...",
|
||||
"tryOutHoneyGather": "Try out Honey Gather!",
|
||||
"notForTheFaintOfHeart": "Not for the Faint of Heart!",
|
||||
"p": "(P)",
|
||||
"flipYourDeviceToEvolveInkay": "Flip Your Device To Evolve Inkay!",
|
||||
"inArceusWeTrust": "In Arceus We Trust",
|
||||
"whyDidTheTorchicCrossTheRoad": "Why Did the Torchic Cross the Road?",
|
||||
"goodLuck": "Good Luck!",
|
||||
"fuseWisely": "Fuse Wisely!",
|
||||
"compensation": "Compensation?",
|
||||
"prepareForTroubleAndMakeItDouble": "Prepare for Trouble! And Make It Double!",
|
||||
"anEggForYourTroubles": "An Egg for Your Troubles?",
|
||||
"regirock": "ÜN ÜN ÜN",
|
||||
"hereForAGoodTime": "Here for a Good Time!",
|
||||
"getGoodOrDont": "Get Good! Or Don't!",
|
||||
"checkTheSubreddit": "Check out the Subreddit!",
|
||||
"betterNerfGreninja": "Better Nerf Greninja!",
|
||||
"inCaseOfUpdateClearYourCache": "In Case of Update, Clear Your Cache!",
|
||||
"insertTextHere": "insert text here",
|
||||
"endingEndlessNotFound": "ending_endless not found",
|
||||
"iLikeMyEggsVouchered": "I Like My Eggs Vouchered!",
|
||||
"YOU": "YOU!",
|
||||
"noAddedSugar": "No Added Sugar!",
|
||||
"notSponsored": "Not Sponsored!",
|
||||
"notRated": "Not Rated!",
|
||||
"justOneMoreWaveMom": "Just One More Wave, Mom!",
|
||||
"saltCured": "Salt Cured!",
|
||||
"onlyOnPokerogueNet": "Only on pokerogue.net!",
|
||||
"pixelPerfection": "Pixel Perfection!",
|
||||
"openSource": "Open Source!",
|
||||
"probablyGood": "Probably Good!",
|
||||
"itsAMonsterHouse": "It's a Monster House!",
|
||||
"dontForgetYourPassword": "Don't Forget Your Password!",
|
||||
"tripleTripleTripleAxel": "Triple- Triple- Triple Axel!",
|
||||
"questionExclamation": "?!",
|
||||
"clownEncounters": "Clown Encounters!",
|
||||
"fullOfBerries": "Full of Berries!",
|
||||
"limitsAreMeantToBeBrokenSometimes": "Limits Are Meant To Be Broken, Sometimes!",
|
||||
"keepItCasual": "Keep It Casual!",
|
||||
"serversProbablyWorking": "Servers Probably Working!",
|
||||
"mew": "Mew Probably Not Under a Truck!",
|
||||
"makeItRainAndYourProblemsGoAway": "Make it Rain and your problems go away!",
|
||||
"customMusicTracks": "Custom Music Tracks!",
|
||||
"youAreValid": "You Are Valid!",
|
||||
"number591IsLookingOff": "Number 591 Is Looking a Bit...",
|
||||
"timeForYourDeliDelivery": "Time for Your Deli-Delivery!",
|
||||
"goodFirstImpression": "Hope We Left a Good First Impression!",
|
||||
"iPreferRarerCandies": "I Prefer Rarer Candies!",
|
||||
"halloween": {
|
||||
"pumpkaboosAbout": "Pumpkaboos about!",
|
||||
"mayContainSpiders": "May contain spiders!",
|
||||
"spookyScaryDuskulls": "Spooky, Scary Duskulls!"
|
||||
"pumpkabooAbout": "Pumpkaboo About!",
|
||||
"mayContainSpiders": "May Contain Spiders!",
|
||||
"spookyScarySkeledirge": "Spooky, Scary Skeledirge!",
|
||||
"gourgeistUsedTrickOrTreat": "Gourgeist Used Trick-or-Treat!",
|
||||
"letsSnuggleForever": "Let's Snuggle Forever!"
|
||||
},
|
||||
"xmas": {
|
||||
"happyHolidays": "Happy Holidays!",
|
||||
"delibirdSeason": "Delibird Season!"
|
||||
"delibirdSeason": "Delibird Season!",
|
||||
"unaffilicatedWithDelibirdServices": "Unaffiliated With Delibird Services!",
|
||||
"diamondsFromTheSky": "Diamonds From the Sky!",
|
||||
"holidayStylePikachuNotIncluded": "Holiday Style Pikachu Not Included!"
|
||||
},
|
||||
"newYears": {
|
||||
"happyNewYear": "Happy New Year!"
|
||||
|
@ -1,12 +1,6 @@
|
||||
{
|
||||
"none": {
|
||||
"name": "None",
|
||||
"description": "",
|
||||
"obtain": "",
|
||||
"obtainSource": "",
|
||||
"activation": "",
|
||||
"overlap": "",
|
||||
"heal": ""
|
||||
"name": "None"
|
||||
},
|
||||
"poison": {
|
||||
"name": "Poison",
|
||||
|
@ -1,12 +1,6 @@
|
||||
{
|
||||
"none": {
|
||||
"name": "Ninguno",
|
||||
"description": "",
|
||||
"obtain": "",
|
||||
"obtainSource": "",
|
||||
"activation": "",
|
||||
"overlap": "",
|
||||
"heal": ""
|
||||
"name": "Ninguno"
|
||||
},
|
||||
"poison": {
|
||||
"name": "Envenenamiento",
|
||||
|
@ -1,12 +1,6 @@
|
||||
{
|
||||
"none": {
|
||||
"name": "Aucun",
|
||||
"description": "",
|
||||
"obtain": "",
|
||||
"obtainSource": "",
|
||||
"activation": "",
|
||||
"overlap": "",
|
||||
"heal": ""
|
||||
"name": "Aucun"
|
||||
},
|
||||
"poison": {
|
||||
"name": "Empoisonnement",
|
||||
|
@ -1,11 +1,5 @@
|
||||
{
|
||||
"none": {
|
||||
"name": "None",
|
||||
"description": "",
|
||||
"obtain": "",
|
||||
"obtainSource": "",
|
||||
"activation": "",
|
||||
"overlap": "",
|
||||
"heal": ""
|
||||
"name": "None"
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@
|
||||
"name_female": "ワンパンウーマン"
|
||||
},
|
||||
"HealAchv": {
|
||||
"description": "一つの 技や 特性や 持たせたアイテムで\n{{HP}}{{healAmount}}を 一気に 回復する"
|
||||
"description": "1つの 技や 特性や 持たせたアイテムで\n{{HP}}{{healAmount}}を 一気に 回復する"
|
||||
},
|
||||
"250_HEAL": {
|
||||
"name": "回復発見者"
|
||||
@ -52,7 +52,7 @@
|
||||
"name": "ジョーイさん"
|
||||
},
|
||||
"LevelAchv": {
|
||||
"description": "一つの ポケモンを Lv.{{level}}まで 上げる"
|
||||
"description": "1匹の ポケモンを Lv.{{level}}まで 上げる"
|
||||
},
|
||||
"LV_100": {
|
||||
"name": "まだまだだよ"
|
||||
@ -83,27 +83,27 @@
|
||||
},
|
||||
"TRANSFER_MAX_STAT_STAGE": {
|
||||
"name": "連係プレー",
|
||||
"description": "少なくとも 一つの 能力を 最大まで あげて\n他の 手持ちポケモンに バトンタッチする"
|
||||
"description": "少なくとも 1つの 能力を 最大まで あげて\n他の 手持ちポケモンに バトンタッチする"
|
||||
},
|
||||
"MAX_FRIENDSHIP": {
|
||||
"name": "マブ達",
|
||||
"description": "一つの 手持ちポケモンの 仲良し度を 最大に 上げる"
|
||||
"description": "1匹の 手持ちポケモンの 仲良し度を 最大に 上げる"
|
||||
},
|
||||
"MEGA_EVOLVE": {
|
||||
"name": "ザ・アブソリュート",
|
||||
"description": "一つの 手持ちポケモンを メガシンカさせる"
|
||||
"description": "1匹の 手持ちポケモンを メガシンカさせる"
|
||||
},
|
||||
"GIGANTAMAX": {
|
||||
"name": "太ーくて堪らない",
|
||||
"description": "一つの 手持ちポケモンを キョダイマックスさせる"
|
||||
"description": "1匹の 手持ちポケモンを キョダイマックスさせる"
|
||||
},
|
||||
"TERASTALLIZE": {
|
||||
"name": "一致好き",
|
||||
"description": "一つの 手持ちポケモンを テラスタルさせる"
|
||||
"description": "1匹の 手持ちポケモンを テラスタルさせる"
|
||||
},
|
||||
"STELLAR_TERASTALLIZE": {
|
||||
"name": "隠れたタイプ",
|
||||
"description": "一つの 手持ちポケモンを ステラ・テラスタルさせる"
|
||||
"description": "1匹の 手持ちポケモンを ステラ・テラスタルさせる"
|
||||
},
|
||||
"SPLICE": {
|
||||
"name": "インフィニット・フュージョン",
|
||||
@ -155,7 +155,7 @@
|
||||
},
|
||||
"PERFECT_IVS": {
|
||||
"name": "個体値の賞状",
|
||||
"description": "一つの ポケモンの 個体値を すべて 最大に する"
|
||||
"description": "1匹の ポケモンの 個体値を すべて 最大に する"
|
||||
},
|
||||
"CLASSIC_VICTORY": {
|
||||
"name": "無双",
|
||||
@ -163,7 +163,7 @@
|
||||
},
|
||||
"UNEVOLVED_CLASSIC_VICTORY": {
|
||||
"name": "はじめてのおつかい",
|
||||
"description": "少なくとも 一つの 進化していない 手持ちポケモンで\nクラシックモードを クリアする"
|
||||
"description": "少なくとも 1匹の 進化していない 手持ちポケモンで\nクラシックモードを クリアする"
|
||||
},
|
||||
"MONO_GEN_ONE": {
|
||||
"name": "原始",
|
||||
|
@ -10,7 +10,7 @@
|
||||
"hpBarSpeed": "HPバー増減の速さ",
|
||||
"expGainsSpeed": "経験値バー増加の速さ",
|
||||
"expPartyDisplay": "手持ちの経験値取得表示",
|
||||
"skipSeenDialogues": "もう見た話をスキップ",
|
||||
"skipSeenDialogues": "もう見た話を飛ばす",
|
||||
"battleStyle": "試合のルール",
|
||||
"enableRetries": "再挑戦を有効にする",
|
||||
"hideIvs": "個体値スキャナーを隠す",
|
||||
|
@ -1,12 +1,6 @@
|
||||
{
|
||||
"none": {
|
||||
"name": "なし",
|
||||
"description": "",
|
||||
"obtain": "",
|
||||
"obtainSource": "",
|
||||
"activation": "",
|
||||
"overlap": "",
|
||||
"heal": ""
|
||||
"name": "なし"
|
||||
},
|
||||
"poison": {
|
||||
"name": "どく",
|
||||
|
@ -1,105 +1,105 @@
|
||||
{
|
||||
"ace_trainer": "エリートトレーナー",
|
||||
"ace_trainer_female": "エリートトレーナー",
|
||||
"ace_duo": "エリートコンビ",
|
||||
"artist": "芸術家",
|
||||
"artist_female": "芸術家",
|
||||
"backers": "ファンクラブ",
|
||||
"backpacker": "バックパッカー",
|
||||
"backpacker_female": "バックパッカー",
|
||||
"backpackers": "バックパッカーズ",
|
||||
"baker": "ベーカリー",
|
||||
"battle_girl": "バトルガール",
|
||||
"beauty": "大人のおねえさん",
|
||||
"beginners": "初心者",
|
||||
"biker": "暴走族",
|
||||
"black_belt": "カラテ王",
|
||||
"breeder": "ポケモンブリーダー",
|
||||
"breeder_female": "ポケモンブリーダー",
|
||||
"breeders": "ブリーダーコンビ",
|
||||
"clerk": "ビジネスマン",
|
||||
"clerk_female": "OL",
|
||||
"colleagues": "ビジネスパートナー",
|
||||
"crush_kin": "格闘兄妹",
|
||||
"cyclist": "サイクリング",
|
||||
"cyclist_female": "サイクリング",
|
||||
"cyclists": "サイクリングチーム",
|
||||
"dancer": "ダンサー",
|
||||
"dancer_female": "ダンサー",
|
||||
"depot_agent": "鉄道員",
|
||||
"doctor": "ドクター",
|
||||
"doctor_female": "ドクター",
|
||||
"firebreather": "火吹きやろう",
|
||||
"fisherman": "釣り人",
|
||||
"fisherman_female": "釣り人",
|
||||
"gentleman": "ジェントルマン",
|
||||
"guitarist": "ギタリスト",
|
||||
"guitarist_female": "ギタリスト",
|
||||
"harlequin": "クラウン",
|
||||
"hiker": "山男",
|
||||
"hooligans": "バッドチーム",
|
||||
"hoopster": "バスケ選手",
|
||||
"infielder": "野球選手",
|
||||
"janitor": "清掃員",
|
||||
"lady": "お嬢さま",
|
||||
"lass": "ミニスカート",
|
||||
"linebacker": "フットボーラー",
|
||||
"maid": "メイド",
|
||||
"madame": "マダム",
|
||||
"medical_team": "医療チーム",
|
||||
"musician": "ミュージシャン",
|
||||
"hex_maniac": "オカルトマニア",
|
||||
"nurse": "ナース",
|
||||
"nursery_aide": "保育士",
|
||||
"officer": "お巡りさん",
|
||||
"parasol_lady": "パラソルおねえさん",
|
||||
"pilot": "パイロット",
|
||||
"pokéfan": "大好きクラブ",
|
||||
"pokéfan_female": "大好きクラブ",
|
||||
"pokéfan_family": "大好き夫婦",
|
||||
"preschooler": "園児",
|
||||
"preschooler_female": "園児",
|
||||
"preschoolers": "園児たち",
|
||||
"psychic": "サイキッカー",
|
||||
"psychic_female": "サイキッカー",
|
||||
"psychics": "サイキッ家",
|
||||
"pokémon_ranger": "ポケモンレンジャー",
|
||||
"pokémon_ranger_female": "ポケモンレンジャー",
|
||||
"pokémon_rangers": "レンジャーズ",
|
||||
"ranger": "レンジャー",
|
||||
"restaurant_staff": "レストランスタッフ",
|
||||
"rich": "お金持ち",
|
||||
"rich_female": "お金持ち",
|
||||
"rich_boy": "お坊っちゃま",
|
||||
"rich_couple": "お二人さま",
|
||||
"rich_kid": "ブルジョワ男子",
|
||||
"rich_kid_female": "ブルジョワ女子",
|
||||
"rich_kids": "ブルジョワ子達",
|
||||
"roughneck": "スキンヘッズ",
|
||||
"sailor": "船乗り",
|
||||
"scientist": "研究員",
|
||||
"scientist_female": "研究員",
|
||||
"scientists": "研究チーム",
|
||||
"smasher": "テニスプレイヤー",
|
||||
"snow_worker": "冷凍作業員",
|
||||
"snow_worker_female": "冷凍作業員",
|
||||
"striker": "サッカー選手",
|
||||
"school_kid": "塾帰り",
|
||||
"school_kid_female": "塾帰り",
|
||||
"school_kids": "塾生たち",
|
||||
"swimmer": "海パンやろう",
|
||||
"swimmer_female": "ビキニのおねえさん",
|
||||
"swimmers": "水着カップル",
|
||||
"twins": "双子ちゃん",
|
||||
"veteran": "ベテラントレーナー",
|
||||
"veteran_female": "ベテラントレーナー",
|
||||
"veteran_duo": "ベテランコンビ",
|
||||
"waiter": "ウエーター",
|
||||
"waitress": "ウエートレス",
|
||||
"worker": "作業員",
|
||||
"worker_female": "作業員",
|
||||
"workers": "作業班",
|
||||
"youngster": "短パン小僧",
|
||||
"ace_trainer": "エリートトレーナーの ",
|
||||
"ace_trainer_female": "エリートトレーナーの ",
|
||||
"ace_duo": "エリートコンビの ",
|
||||
"artist": "芸術家の ",
|
||||
"artist_female": "芸術家の ",
|
||||
"backers": "ファンクラブの ",
|
||||
"backpacker": "バックパッカーの ",
|
||||
"backpacker_female": "バックパッカーの ",
|
||||
"backpackers": "バックパッカーズの ",
|
||||
"baker": "ベーカリーの ",
|
||||
"battle_girl": "バトルガールの ",
|
||||
"beauty": "大人のおねえさんの ",
|
||||
"beginners": "初心者の ",
|
||||
"biker": "暴走族の ",
|
||||
"black_belt": "カラテ王の ",
|
||||
"breeder": "ポケモンブリーダーの ",
|
||||
"breeder_female": "ポケモンブリーダーの ",
|
||||
"breeders": "ブリーダーコンビの ",
|
||||
"clerk": "ビジネスマンの ",
|
||||
"clerk_female": "OLの ",
|
||||
"colleagues": "ビジネスパートナーの ",
|
||||
"crush_kin": "格闘兄妹の ",
|
||||
"cyclist": "サイクリングの ",
|
||||
"cyclist_female": "サイクリングの ",
|
||||
"cyclists": "サイクリングチームの ",
|
||||
"dancer": "ダンサーの ",
|
||||
"dancer_female": "ダンサーの ",
|
||||
"depot_agent": "鉄道員の ",
|
||||
"doctor": "ドクターの ",
|
||||
"doctor_female": "ドクターの ",
|
||||
"firebreather": "火吹きやろうの ",
|
||||
"fisherman": "釣り人の ",
|
||||
"fisherman_female": "釣り人の ",
|
||||
"gentleman": "ジェントルマンの ",
|
||||
"guitarist": "ギタリストの ",
|
||||
"guitarist_female": "ギタリストの ",
|
||||
"harlequin": "クラウンの ",
|
||||
"hiker": "山男の ",
|
||||
"hooligans": "バッドチームの ",
|
||||
"hoopster": "バスケ選手の ",
|
||||
"infielder": "野球選手の ",
|
||||
"janitor": "清掃員の ",
|
||||
"lady": "お嬢さまの ",
|
||||
"lass": "ミニスカートの ",
|
||||
"linebacker": "フットボーラーの ",
|
||||
"maid": "メイドの ",
|
||||
"madame": "マダムの ",
|
||||
"medical_team": "医療チームの ",
|
||||
"musician": "ミュージシャンの ",
|
||||
"hex_maniac": "オカルトマニアの ",
|
||||
"nurse": "ナースの ",
|
||||
"nursery_aide": "保育士の ",
|
||||
"officer": "お巡りさんの ",
|
||||
"parasol_lady": "パラソルおねえさんの ",
|
||||
"pilot": "パイロットの ",
|
||||
"pokéfan": "大好きクラブの ",
|
||||
"pokéfan_female": "大好きクラブの ",
|
||||
"pokéfan_family": "大好き夫婦の ",
|
||||
"preschooler": "園児の ",
|
||||
"preschooler_female": "園児の ",
|
||||
"preschoolers": "園児たちの ",
|
||||
"psychic": "サイキッカーの ",
|
||||
"psychic_female": "サイキッカーの ",
|
||||
"psychics": "サイキッ家の ",
|
||||
"pokémon_ranger": "ポケモンレンジャーの ",
|
||||
"pokémon_ranger_female": "ポケモンレンジャーの ",
|
||||
"pokémon_rangers": "レンジャーズの ",
|
||||
"ranger": "レンジャーの ",
|
||||
"restaurant_staff": "レストランスタッフの ",
|
||||
"rich": "お金持ちの ",
|
||||
"rich_female": "お金持ちの ",
|
||||
"rich_boy": "お坊っちゃまの ",
|
||||
"rich_couple": "お二人さまの ",
|
||||
"rich_kid": "ブルジョワ男子の ",
|
||||
"rich_kid_female": "ブルジョワ女子の ",
|
||||
"rich_kids": "ブルジョワ子達の ",
|
||||
"roughneck": "スキンヘッズの ",
|
||||
"sailor": "船乗りの ",
|
||||
"scientist": "研究員の ",
|
||||
"scientist_female": "研究員の ",
|
||||
"scientists": "研究チームの ",
|
||||
"smasher": "テニスプレイヤーの ",
|
||||
"snow_worker": "冷凍作業員の ",
|
||||
"snow_worker_female": "冷凍作業員の ",
|
||||
"striker": "サッカー選手の ",
|
||||
"school_kid": "塾帰りの ",
|
||||
"school_kid_female": "塾帰りの ",
|
||||
"school_kids": "塾生たちの ",
|
||||
"swimmer": "海パンやろうの ",
|
||||
"swimmer_female": "ビキニのおねえさんの ",
|
||||
"swimmers": "水着カップルの ",
|
||||
"twins": "双子ちゃんの ",
|
||||
"veteran": "ベテラントレーナーの ",
|
||||
"veteran_female": "ベテラントレーナーの ",
|
||||
"veteran_duo": "ベテランコンビの ",
|
||||
"waiter": "ウエーターの ",
|
||||
"waitress": "ウエートレスの ",
|
||||
"worker": "作業員の ",
|
||||
"worker_female": "作業員の ",
|
||||
"workers": "作業班の ",
|
||||
"youngster": "短パン小僧の ",
|
||||
"rocket_grunt": "ロケット団の下っ端",
|
||||
"rocket_grunts": " ロケット団の下っ端",
|
||||
"rocket_grunt_female": "ロケット団の下っ端",
|
||||
|
@ -2,9 +2,9 @@
|
||||
"intro": "PokéRogueへ ようこそ! ローグライク要素が\n加わった バトル中心の ポケモンファンゲームです。\n$このゲームは 収益を上げず、Pokémonおよび 使用される\n著作権資産に 対する所有権を 主張しません。\n$ゲームは まだ開発中ですが、完全に プレイすることが できます。\nバグ報告は ディスコードコミュニティを ご利用ください。\n$ゲームが 遅い場合は、ブラウザ設定で「ハードウェア\nアクセラレーション」が オンになっている ことを 確認してください。",
|
||||
"accessMenu": "メニューを開くには 入力待ちの間に Mキー/Escを 押してください。\nメニューには 設定や 様々な機能が 含まれています。",
|
||||
"menu": "このメニューから 設定が 開けます。\n$設定では、ゲームの速さや ウィンドウタイプなどの オプションを 変更できます。\n$ここには 様々な機能が ありますので、\nぜひ 確認してみてください!",
|
||||
"starterSelect": "この画面では Zキー/空白キーを押して ポケモンが 選択できます。\n選んだポケモンは 最初の手持ちに なります。\n$各ポケモンは ポイントが ある。最大6つを 選べますが\nポケモンのポイントが 合計10を超えては いけません。\n$ポケモンを 捕まえたり タマゴからふかしたり することで\n選択できる 性別、特性、フォルムなどの 幅を広げられます。\n$個体値も 徐々に 累積して 高くなるので、\n同じポケモンを たくさん 捕まえて みてください!",
|
||||
"starterSelect": "この画面では Zキー/空白キーを押して ポケモンが 選択できます。\n選んだポケモンは 最初の手持ちに なります。\n$各ポケモンは ポイントが ある。最大6つを 選べますが\nポケモンのポイントが 合計10を超えては いけません。\n$ポケモンを 捕まえたり タマゴからふかしたり することで\n選択できる 性別、特性、フォルムなどの 幅を広げられます。\n$個体値も 徐々に 累積して 高くなるから\n同じポケモンを たくさん 捕まえて みてください!",
|
||||
"pokerus": "毎日、無作為に スターターの\n3種類には 紫色の枠が 表示されます。\n$登録された スターターの 中に いれば、\n手持ちに加えて 強さを 確認してみましょう!",
|
||||
"statChange": "ポケモンを 入れ替えない限り、\n次のバトルでも 能力変化は なくなりません。\n$その代わりに、トレーナーバトルや 新しいバイオームに\n入る直前に 自動的に 能力変化は 元に戻ります。\n$Cキー/Shiftキーを 押し続けると、\n場にいるポケモンの 能力変化を 確認できます。\n$Vキーを押すと、\n相手が出した技も 確認できます。\n$ただし、現在のバトルでの 相手ポケモンが\nすでに使った 技のみが 表示されます。",
|
||||
"selectItem": "バトルが 終わるたびには、「ショップ」という\n画面で 3つのご褒美から 1つが選べます。\n$種類は 消耗品、ポケモンの持ち物や道具、\n永続的な パッシブアイテムなど 様々です。\n$ほとんどの 消耗しない 道具は\n効果が 累積されます。\n$例えば 進化アイテムなどの ご褒美は\n使用できる 場合にのみ 登場します。\n$持ち物や道具が\n手持ちポケモン間に 移動できる\n$持ち物や道具が あれば、ショップ画面の\n右下に「アイテム移行」が 表示されます。\n$ショップ画面で お金で 消耗品を 買えます。\nラウンドが 進むにつれて 買えるアイテムが 増えます。\n$ご褒美を 選択すると 次のラウンドに\n進むから、まず 消耗品を 買ってください。",
|
||||
"eggGacha": "この画面では、「タマゴクーポン」で\nポケモンのタマゴを 取得できます。\n$タマゴは ラウンドが進めるうちに ふかします。\nタマゴのふかは レア度によって 時間が かかります。\n$ふかしたポケモンは 手持ちに 加えられず、\nスターターに 登録されます。\n$ふかしたポケモンは 一般的に\n野生ポケモンよりも 高い個体値があります。\n$あるポケモンは タマゴからしか 手に入りません。\n$各ガチャマシンは 個性的なボーナスが あるますから、\n好きな方から 引いてみてください!,"
|
||||
"statChange": "ポケモンを 入れ替えない限り、\n次のバトルでも 能力変化は なくなりません。\n$その代わりに、トレーナーバトルや 新しいバイオームに\n入る直前に 能力変化は 自動的に 元に戻ります。\n$Cキー/Shiftキーを 押し続けると、\n場にいるポケモンの 能力変化を 確認できます。\n$Vキーを 押し続けると、\n相手が出した技と 場の効果を 確認できます。\n$ただし 現在のバトルでの 相手ポケモンが\nすでに 使った 技のみ 表示されます。",
|
||||
"selectItem": "バトルが 終わるたびには、「ショップ」という\n画面で 3つのご褒美から 1つが選べます。\n$種類は 消耗品、ポケモンの持ち物や道具、\n永続的な パッシブアイテムなど 様々です。\n$ほとんどの 消耗しない 道具は\n効果が 累積されます。\n$例えば 進化アイテムなどの ご褒美は\n使用できる 場合のみに 登場します。\n$持ち物や 道具が\n手持ちポケモン画面に 移動できます。\n$持ち物や 道具が あれば、 ショップ画面の\n右下に「アイテム移行」が 表示されます。\n$ショップ画面で お金で 消耗品を 買えます。\nラウンドが進むにつれて 買えるアイテムが 増えます。\n$ご褒美を 選択すると 次の ラウンドに 進むから\nまずは 金で買える 消耗品を 買ってください。",
|
||||
"eggGacha": "この画面では、「タマゴクーポン」で\nポケモンのタマゴを 取得できます。\n$タマゴは ラウンドが進めるうちに ふかします。\nタマゴのふかは レア度によって 時間が かかります。\n$ふかしたポケモンは 手持ちに 加えられずに\nスターターに 登録されます。\n$ふかしたポケモンは 一般的に\n野生ポケモンよりも 高い個体値が あります。\n$あるポケモンは タマゴからしか 手に入りません。\n$各ガチャマシンは 個性的な ボーナスが あるから\n好きな方から 引いてみてください!,"
|
||||
}
|
||||
|
@ -1,12 +1,6 @@
|
||||
{
|
||||
"none": {
|
||||
"name": "없음",
|
||||
"description": "",
|
||||
"obtain": "",
|
||||
"obtainSource": "",
|
||||
"activation": "",
|
||||
"overlap": "",
|
||||
"heal": ""
|
||||
"name": "없음"
|
||||
},
|
||||
"poison": {
|
||||
"name": "독",
|
||||
|
@ -1,12 +1,6 @@
|
||||
{
|
||||
"none": {
|
||||
"name": "Nenhum",
|
||||
"description": "",
|
||||
"obtain": "",
|
||||
"obtainSource": "",
|
||||
"activation": "",
|
||||
"overlap": "",
|
||||
"heal": ""
|
||||
"name": "Nenhum"
|
||||
},
|
||||
"poison": {
|
||||
"name": "Envenenamento",
|
||||
|
@ -1,12 +1,6 @@
|
||||
{
|
||||
"none": {
|
||||
"name": "无",
|
||||
"description": "",
|
||||
"obtain": "",
|
||||
"obtainSource": "",
|
||||
"activation": "",
|
||||
"overlap": "",
|
||||
"heal": ""
|
||||
"name": "无"
|
||||
},
|
||||
"poison": {
|
||||
"name": "中毒",
|
||||
|
@ -1,12 +1,6 @@
|
||||
{
|
||||
"none": {
|
||||
"name": "無",
|
||||
"description": "",
|
||||
"obtain": "",
|
||||
"obtainSource": "",
|
||||
"activation": "",
|
||||
"overlap": "",
|
||||
"heal": ""
|
||||
"name": "無"
|
||||
},
|
||||
"poison": {
|
||||
"name": "中毒",
|
||||
|
@ -1577,17 +1577,22 @@ export const modifierTypes = {
|
||||
|
||||
MYSTERY_ENCOUNTER_SHUCKLE_JUICE: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => {
|
||||
if (pregenArgs) {
|
||||
return new PokemonBaseStatTotalModifierType(pregenArgs[0] as integer);
|
||||
return new PokemonBaseStatTotalModifierType(pregenArgs[0] as number);
|
||||
}
|
||||
return new PokemonBaseStatTotalModifierType(Utils.randSeedInt(20));
|
||||
}),
|
||||
MYSTERY_ENCOUNTER_OLD_GATEAU: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => {
|
||||
if (pregenArgs) {
|
||||
return new PokemonBaseStatFlatModifierType(pregenArgs[0] as integer, pregenArgs[1] as Stat[]);
|
||||
return new PokemonBaseStatFlatModifierType(pregenArgs[0] as number, pregenArgs[1] as Stat[]);
|
||||
}
|
||||
return new PokemonBaseStatFlatModifierType(Utils.randSeedInt(20), [Stat.HP, Stat.ATK, Stat.DEF]);
|
||||
}),
|
||||
MYSTERY_ENCOUNTER_BLACK_SLUDGE: () => new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_BLACK_SLUDGE", "black_sludge", (type, _args) => new Modifiers.HealShopCostModifier(type)),
|
||||
MYSTERY_ENCOUNTER_BLACK_SLUDGE: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => {
|
||||
if (pregenArgs) {
|
||||
return new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_BLACK_SLUDGE", "black_sludge", (type, _args) => new Modifiers.HealShopCostModifier(type, pregenArgs[0] as number));
|
||||
}
|
||||
return new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_BLACK_SLUDGE", "black_sludge", (type, _args) => new Modifiers.HealShopCostModifier(type, 2.5));
|
||||
}),
|
||||
MYSTERY_ENCOUNTER_MACHO_BRACE: () => new PokemonHeldItemModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_MACHO_BRACE", "macho_brace", (type, args) => new Modifiers.PokemonIncrementingStatModifier(type, (args[0] as Pokemon).id)),
|
||||
MYSTERY_ENCOUNTER_GOLDEN_BUG_NET: () => new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET", "golden_net", (type, _args) => new Modifiers.BoostBugSpawnModifier(type)),
|
||||
};
|
||||
@ -1715,7 +1720,8 @@ const modifierPool: ModifierPool = {
|
||||
new WeightedModifierType(modifierTypes.AMULET_COIN, skipInLastClassicWaveOrDefault(3)),
|
||||
new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => {
|
||||
if (!party[0].scene.gameMode.isFreshStartChallenge() && party[0].scene.gameData.unlocks[Unlockables.EVIOLITE]) {
|
||||
return party.some(p => ((p.getSpeciesForm(true).speciesId in pokemonEvolutions) || (p.isFusion() && (p.getFusionSpeciesForm(true).speciesId in pokemonEvolutions))) && !p.getHeldItems().some(i => i instanceof Modifiers.EvolutionStatBoosterModifier)) ? 10 : 0;
|
||||
return party.some(p => ((p.getSpeciesForm(true).speciesId in pokemonEvolutions) || (p.isFusion() && (p.getFusionSpeciesForm(true).speciesId in pokemonEvolutions)))
|
||||
&& !p.getHeldItems().some(i => i instanceof Modifiers.EvolutionStatBoosterModifier) && !p.isMax()) ? 10 : 0;
|
||||
}
|
||||
return 0;
|
||||
}),
|
||||
@ -1723,19 +1729,24 @@ const modifierPool: ModifierPool = {
|
||||
new WeightedModifierType(modifierTypes.LEEK, (party: Pokemon[]) => {
|
||||
const checkedSpecies = [ Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD ];
|
||||
// If a party member doesn't already have a Leek and is one of the relevant species, Leek can appear
|
||||
return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.SpeciesCritBoosterModifier) && (checkedSpecies.includes(p.getSpeciesForm(true).speciesId) || (p.isFusion() && checkedSpecies.includes(p.getFusionSpeciesForm(true).speciesId)))) ? 12 : 0;
|
||||
return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.SpeciesCritBoosterModifier)
|
||||
&& (checkedSpecies.includes(p.getSpeciesForm(true).speciesId)
|
||||
|| (p.isFusion() && checkedSpecies.includes(p.getFusionSpeciesForm(true).speciesId)))) ? 12 : 0;
|
||||
}, 12),
|
||||
new WeightedModifierType(modifierTypes.TOXIC_ORB, (party: Pokemon[]) => {
|
||||
const checkedAbilities = [Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.TOXIC_BOOST, Abilities.POISON_HEAL, Abilities.MAGIC_GUARD];
|
||||
const checkedMoves = [Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT];
|
||||
// If a party member doesn't already have one of these two orbs and has one of the above moves or abilities, the orb can appear
|
||||
return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier) && (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0;
|
||||
return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier)
|
||||
&& (checkedAbilities.some(a => p.hasAbility(a, false, true))
|
||||
|| p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0;
|
||||
}, 10),
|
||||
new WeightedModifierType(modifierTypes.FLAME_ORB, (party: Pokemon[]) => {
|
||||
const checkedAbilities = [Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.FLARE_BOOST, Abilities.MAGIC_GUARD];
|
||||
const checkedMoves = [Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT];
|
||||
// If a party member doesn't already have one of these two orbs and has one of the above moves or abilities, the orb can appear
|
||||
return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier) && (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0;
|
||||
return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier)
|
||||
&& (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0;
|
||||
}, 10),
|
||||
new WeightedModifierType(modifierTypes.WHITE_HERB, (party: Pokemon[]) => {
|
||||
const checkedAbilities = [Abilities.WEAK_ARMOR, Abilities.CONTRARY, Abilities.MOODY, Abilities.ANGER_SHELL, Abilities.COMPETITIVE, Abilities.DEFIANT];
|
||||
@ -1790,7 +1801,8 @@ const modifierPool: ModifierPool = {
|
||||
new WeightedModifierType(modifierTypes.SHINY_CHARM, 14),
|
||||
new WeightedModifierType(modifierTypes.HEALING_CHARM, 18),
|
||||
new WeightedModifierType(modifierTypes.MULTI_LENS, 18),
|
||||
new WeightedModifierType(modifierTypes.VOUCHER_PREMIUM, (party: Pokemon[], rerollCount: integer) => !party[0].scene.gameMode.isDaily && !party[0].scene.gameMode.isEndless && !party[0].scene.gameMode.isSplicedOnly ? Math.max(5 - rerollCount * 2, 0) : 0, 5),
|
||||
new WeightedModifierType(modifierTypes.VOUCHER_PREMIUM, (party: Pokemon[], rerollCount: integer) =>
|
||||
!party[0].scene.gameMode.isDaily && !party[0].scene.gameMode.isEndless && !party[0].scene.gameMode.isSplicedOnly ? Math.max(5 - rerollCount * 2, 0) : 0, 5),
|
||||
new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => !party[0].scene.gameMode.isSplicedOnly && party.filter(p => !p.fusionSpecies).length > 1 ? 24 : 0, 24),
|
||||
new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, (party: Pokemon[]) => (!party[0].scene.gameMode.isFreshStartChallenge() && party[0].scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE]) ? 1 : 0, 1),
|
||||
].map(m => {
|
||||
|
@ -2576,8 +2576,12 @@ export class LockModifierTiersModifier extends PersistentModifier {
|
||||
* Black Sludge item
|
||||
*/
|
||||
export class HealShopCostModifier extends PersistentModifier {
|
||||
constructor(type: ModifierType, stackCount?: integer) {
|
||||
public readonly shopMultiplier: number;
|
||||
|
||||
constructor(type: ModifierType, shopMultiplier: number, stackCount?: integer) {
|
||||
super(type, stackCount);
|
||||
|
||||
this.shopMultiplier = shopMultiplier;
|
||||
}
|
||||
|
||||
match(modifier: Modifier): boolean {
|
||||
@ -2585,11 +2589,11 @@ export class HealShopCostModifier extends PersistentModifier {
|
||||
}
|
||||
|
||||
clone(): HealShopCostModifier {
|
||||
return new HealShopCostModifier(this.type, this.stackCount);
|
||||
return new HealShopCostModifier(this.type, this.shopMultiplier, this.stackCount);
|
||||
}
|
||||
|
||||
apply(args: any[]): boolean {
|
||||
(args[0] as Utils.IntegerHolder).value *= Math.pow(3, this.getStackCount());
|
||||
(args[0] as Utils.IntegerHolder).value *= this.shopMultiplier;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2608,7 +2612,7 @@ export class BoostBugSpawnModifier extends PersistentModifier {
|
||||
return modifier instanceof BoostBugSpawnModifier;
|
||||
}
|
||||
|
||||
clone(): HealShopCostModifier {
|
||||
clone(): BoostBugSpawnModifier {
|
||||
return new BoostBugSpawnModifier(this.type, this.stackCount);
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,13 @@ export class EncounterPhase extends BattlePhase {
|
||||
|
||||
const battle = this.scene.currentBattle;
|
||||
|
||||
// Init Mystery Encounter if there is one
|
||||
// Generate and Init Mystery Encounter
|
||||
if (battle.battleType === BattleType.MYSTERY_ENCOUNTER && !battle.mysteryEncounter) {
|
||||
this.scene.executeWithSeedOffset(() => {
|
||||
const currentSessionEncounterType = battle.mysteryEncounterType;
|
||||
battle.mysteryEncounter = this.scene.getMysteryEncounter(currentSessionEncounterType);
|
||||
}, battle.waveIndex << 4);
|
||||
}
|
||||
const mysteryEncounter = battle.mysteryEncounter;
|
||||
if (mysteryEncounter) {
|
||||
// If ME has an onInit() function, call it
|
||||
@ -152,13 +158,10 @@ export class EncounterPhase extends BattlePhase {
|
||||
if (battle.battleType === BattleType.TRAINER) {
|
||||
loadEnemyAssets.push(battle.trainer?.loadAssets().then(() => battle.trainer?.initSprite())!); // TODO: is this bang correct?
|
||||
} else if (battle.battleType === BattleType.MYSTERY_ENCOUNTER) {
|
||||
if (!battle.mysteryEncounter) {
|
||||
battle.mysteryEncounter = this.scene.getMysteryEncounter(mysteryEncounter?.encounterType);
|
||||
}
|
||||
if (battle.mysteryEncounter.introVisuals) {
|
||||
if (battle.mysteryEncounter?.introVisuals) {
|
||||
loadEnemyAssets.push(battle.mysteryEncounter.introVisuals.loadAssets().then(() => battle.mysteryEncounter!.introVisuals!.initSprite()));
|
||||
}
|
||||
if (battle.mysteryEncounter.loadAssets.length > 0) {
|
||||
if (battle.mysteryEncounter?.loadAssets && battle.mysteryEncounter.loadAssets.length > 0) {
|
||||
loadEnemyAssets.push(...battle.mysteryEncounter.loadAssets);
|
||||
}
|
||||
// Load Mystery Encounter Exclamation bubble and sfx
|
||||
|
@ -252,13 +252,13 @@ export class SelectModifierPhase extends BattlePhase {
|
||||
|
||||
let multiplier = 1;
|
||||
if (!isNullOrUndefined(this.customModifierSettings?.rerollMultiplier)) {
|
||||
if (this.customModifierSettings!.rerollMultiplier! < 0) {
|
||||
if (this.customModifierSettings.rerollMultiplier < 0) {
|
||||
// Completely overrides reroll cost to -1 and early exits
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Otherwise, continue with custom multiplier
|
||||
multiplier = this.customModifierSettings!.rerollMultiplier!;
|
||||
multiplier = this.customModifierSettings.rerollMultiplier;
|
||||
}
|
||||
return Math.min(Math.ceil(this.scene.currentBattle.waveIndex / 10) * baseValue * Math.pow(2, this.rerollCount) * multiplier, Number.MAX_SAFE_INTEGER);
|
||||
}
|
||||
|
@ -18,44 +18,45 @@ describe("status-effect", () => {
|
||||
mockI18next();
|
||||
|
||||
const text = getStatusEffectObtainText(statusEffect, pokemonName);
|
||||
expect(text).toBe("statusEffect:none.obtain");
|
||||
console.log("text:", text);
|
||||
expect(text).toBe("");
|
||||
|
||||
const emptySourceText = getStatusEffectObtainText(statusEffect, pokemonName, "");
|
||||
expect(emptySourceText).toBe("statusEffect:none.obtain");
|
||||
expect(emptySourceText).toBe("");
|
||||
});
|
||||
|
||||
it("should return the source-obtain text", () => {
|
||||
mockI18next();
|
||||
|
||||
const text = getStatusEffectObtainText(statusEffect, pokemonName, sourceText);
|
||||
expect(text).toBe("statusEffect:none.obtainSource");
|
||||
expect(text).toBe("");
|
||||
|
||||
const emptySourceText = getStatusEffectObtainText(statusEffect, pokemonName, "");
|
||||
expect(emptySourceText).not.toBe("statusEffect:none.obtainSource");
|
||||
expect(emptySourceText).toBe("");
|
||||
});
|
||||
|
||||
it("should return the activation text", () => {
|
||||
mockI18next();
|
||||
const text = getStatusEffectActivationText(statusEffect, pokemonName);
|
||||
expect(text).toBe("statusEffect:none.activation");
|
||||
expect(text).toBe("");
|
||||
});
|
||||
|
||||
it("should return the overlap text", () => {
|
||||
mockI18next();
|
||||
const text = getStatusEffectOverlapText(statusEffect, pokemonName);
|
||||
expect(text).toBe("statusEffect:none.overlap");
|
||||
expect(text).toBe("");
|
||||
});
|
||||
|
||||
it("should return the heal text", () => {
|
||||
mockI18next();
|
||||
const text = getStatusEffectHealText(statusEffect, pokemonName);
|
||||
expect(text).toBe("statusEffect:none.heal");
|
||||
expect(text).toBe("");
|
||||
});
|
||||
|
||||
it("should return the descriptor", () => {
|
||||
mockI18next();
|
||||
const text = getStatusEffectDescriptor(statusEffect);
|
||||
expect(text).toBe("statusEffect:none.description");
|
||||
expect(text).toBe("");
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -114,7 +114,7 @@ export async function runSelectMysteryEncounterOption(game: GameManager, optionN
|
||||
}
|
||||
|
||||
if (!isNullOrUndefined(secondaryOptionSelect?.pokemonNo)) {
|
||||
await handleSecondaryOptionSelect(game, secondaryOptionSelect!.pokemonNo, secondaryOptionSelect!.optionNo);
|
||||
await handleSecondaryOptionSelect(game, secondaryOptionSelect.pokemonNo, secondaryOptionSelect.optionNo);
|
||||
} else {
|
||||
uiHandler.processInput(Button.ACTION);
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ describe("Absolute Avarice - Mystery Encounter", () => {
|
||||
expect(enemyField[0].species.speciesId).toBe(Species.GREEDENT);
|
||||
const moveset = enemyField[0].moveset.map(m => m?.moveId);
|
||||
expect(moveset?.length).toBe(4);
|
||||
expect(moveset).toEqual([Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.SLACK_OFF]);
|
||||
expect(moveset).toEqual([Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.CRUNCH]);
|
||||
|
||||
const movePhases = phaseSpy.mock.calls.filter(p => p[0] instanceof MovePhase).map(p => p[0]);
|
||||
expect(movePhases.length).toBe(1);
|
||||
|
@ -17,6 +17,7 @@ import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encount
|
||||
import * as EncounterDialogueUtils from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { CommandPhase } from "#app/phases/command-phase";
|
||||
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
|
||||
const namespace = "mysteryEncounter:berriesAbound";
|
||||
const defaultParty = [Species.PYUKUMUKU, Species.MAGIKARP, Species.PIKACHU];
|
||||
@ -35,13 +36,15 @@ describe("Berries Abound - Mystery Encounter", () => {
|
||||
beforeEach(async () => {
|
||||
game = new GameManager(phaserGame);
|
||||
scene = game.scene;
|
||||
game.override.mysteryEncounterChance(100);
|
||||
game.override.mysteryEncounterTier(MysteryEncounterTier.COMMON);
|
||||
game.override.startingWave(defaultWave);
|
||||
game.override.startingBiome(defaultBiome);
|
||||
game.override.disableTrainerWaves();
|
||||
game.override.startingModifier([]);
|
||||
game.override.startingHeldItems([]);
|
||||
game.override.mysteryEncounterChance(100)
|
||||
.mysteryEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.startingWave(defaultWave)
|
||||
.startingBiome(defaultBiome)
|
||||
.disableTrainerWaves()
|
||||
.startingModifier([])
|
||||
.startingHeldItems([])
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyPassiveAbility(Abilities.BALL_FETCH);
|
||||
|
||||
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(
|
||||
new Map<Biome, MysteryEncounterType[]>([
|
||||
@ -168,7 +171,30 @@ describe("Berries Abound - Mystery Encounter", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should start battle if fastest pokemon is slower than boss", async () => {
|
||||
it("should start battle if fastest pokemon is slower than boss below wave 50", async () => {
|
||||
game.override.startingWave(41);
|
||||
const encounterTextSpy = vi.spyOn(EncounterDialogueUtils, "showEncounterText");
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.BERRIES_ABOUND, defaultParty);
|
||||
|
||||
const config = game.scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0];
|
||||
const speciesToSpawn = config.pokemonConfigs?.[0].species.speciesId;
|
||||
// Setting enemy's level arbitrarily high to outspeed
|
||||
config.pokemonConfigs![0].dataSource!.level = 1000;
|
||||
|
||||
await runMysteryEncounterToEnd(game, 2, undefined, true);
|
||||
|
||||
const enemyField = scene.getEnemyField();
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
|
||||
expect(enemyField.length).toBe(1);
|
||||
expect(enemyField[0].species.speciesId).toBe(speciesToSpawn);
|
||||
|
||||
// Should be enraged
|
||||
expect(enemyField[0].summonData.statStages).toEqual([0, 1, 0, 1, 1, 0, 0]);
|
||||
expect(encounterTextSpy).toHaveBeenCalledWith(expect.any(BattleScene), `${namespace}.option.2.selected_bad`);
|
||||
});
|
||||
|
||||
it("should start battle if fastest pokemon is slower than boss above wave 50", async () => {
|
||||
game.override.startingWave(57);
|
||||
const encounterTextSpy = vi.spyOn(EncounterDialogueUtils, "showEncounterText");
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.BERRIES_ABOUND, defaultParty);
|
||||
|
||||
|
@ -11,7 +11,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { DelibirdyEncounter } from "#app/data/mystery-encounters/encounters/delibirdy-encounter";
|
||||
import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters";
|
||||
import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||
import { BerryModifier, HealingBoosterModifier, HiddenAbilityRateBoosterModifier, HitHealModifier, LevelIncrementBoosterModifier, PokemonInstantReviveModifier, PokemonNatureWeightModifier, PreserveBerryModifier } from "#app/modifier/modifier";
|
||||
import { BerryModifier, HealingBoosterModifier, HitHealModifier, LevelIncrementBoosterModifier, MoneyMultiplierModifier, PokemonInstantReviveModifier, PokemonNatureWeightModifier, PreserveBerryModifier } from "#app/modifier/modifier";
|
||||
import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases";
|
||||
import { generateModifierType } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
@ -104,35 +104,35 @@ describe("Delibird-y - Mystery Encounter", () => {
|
||||
expect(scene.money).toBe(initialMoney - price);
|
||||
});
|
||||
|
||||
it("Should give the player a Hidden Ability Charm", async () => {
|
||||
it("Should give the player an Amulet Coin", async () => {
|
||||
scene.money = 200000;
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.DELIBIRDY, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
const itemModifier = scene.findModifier(m => m instanceof HiddenAbilityRateBoosterModifier) as HiddenAbilityRateBoosterModifier;
|
||||
const itemModifier = scene.findModifier(m => m instanceof MoneyMultiplierModifier) as MoneyMultiplierModifier;
|
||||
|
||||
expect(itemModifier).toBeDefined();
|
||||
expect(itemModifier?.stackCount).toBe(1);
|
||||
});
|
||||
|
||||
it("Should give the player a Shell Bell if they have max stacks of Berry Pouches", async () => {
|
||||
it("Should give the player a Shell Bell if they have max stacks of Amulet Coins", async () => {
|
||||
scene.money = 200000;
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.DELIBIRDY, defaultParty);
|
||||
|
||||
// 5 Healing Charms
|
||||
// Max Amulet Coins
|
||||
scene.modifiers = [];
|
||||
const abilityCharm = generateModifierType(scene, modifierTypes.ABILITY_CHARM)!.newModifier() as HiddenAbilityRateBoosterModifier;
|
||||
abilityCharm.stackCount = 4;
|
||||
await scene.addModifier(abilityCharm, true, false, false, true);
|
||||
const amuletCoin = generateModifierType(scene, modifierTypes.AMULET_COIN)!.newModifier() as MoneyMultiplierModifier;
|
||||
amuletCoin.stackCount = 5;
|
||||
await scene.addModifier(amuletCoin, true, false, false, true);
|
||||
await scene.updateModifiers(true);
|
||||
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
const abilityCharmAfter = scene.findModifier(m => m instanceof HiddenAbilityRateBoosterModifier);
|
||||
const amuletCoinAfter = scene.findModifier(m => m instanceof MoneyMultiplierModifier);
|
||||
const shellBellAfter = scene.findModifier(m => m instanceof HitHealModifier);
|
||||
|
||||
expect(abilityCharmAfter).toBeDefined();
|
||||
expect(abilityCharmAfter?.stackCount).toBe(4);
|
||||
expect(amuletCoinAfter).toBeDefined();
|
||||
expect(amuletCoinAfter?.stackCount).toBe(5);
|
||||
expect(shellBellAfter).toBeDefined();
|
||||
expect(shellBellAfter?.stackCount).toBe(1);
|
||||
});
|
||||
|
@ -98,7 +98,7 @@ describe("Department Store Sale - Mystery Encounter", () => {
|
||||
|
||||
expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
|
||||
const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
|
||||
expect(modifierSelectHandler.options.length).toEqual(4);
|
||||
expect(modifierSelectHandler.options.length).toEqual(5);
|
||||
for (const option of modifierSelectHandler.options) {
|
||||
expect(option.modifierTypeOption.type.id).toContain("TM_");
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ describe("Teleporting Hijinks - Mystery Encounter", () => {
|
||||
.startingWave(defaultWave)
|
||||
.startingBiome(defaultBiome)
|
||||
.disableTrainerWaves()
|
||||
.enemyPassiveAbility(Abilities.BALL_FETCH)
|
||||
.enemyAbility(Abilities.BALL_FETCH);
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyPassiveAbility(Abilities.BALL_FETCH);
|
||||
|
||||
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(
|
||||
new Map<Biome, MysteryEncounterType[]>([
|
||||
@ -258,8 +258,8 @@ describe("Teleporting Hijinks - Mystery Encounter", () => {
|
||||
|
||||
it("should start a battle against an extra enraged boss above wave 50", { retry: 5 }, async () => {
|
||||
game.override.startingWave(56);
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.TELEPORTING_HIJINKS, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 1, undefined, true);
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.TELEPORTING_HIJINKS, [Species.PIKACHU]);
|
||||
await runMysteryEncounterToEnd(game, 2, undefined, true);
|
||||
const enemyField = scene.getEnemyField();
|
||||
expect(enemyField[0].summonData.statStages).toEqual([1, 1, 1, 1, 1, 0, 0]);
|
||||
expect(enemyField[0].isBoss()).toBe(true);
|
||||
|
@ -70,7 +70,7 @@ describe("The Strong Stuff - Mystery Encounter", () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.THE_STRONG_STUFF, defaultParty);
|
||||
|
||||
expect(TheStrongStuffEncounter.encounterType).toBe(MysteryEncounterType.THE_STRONG_STUFF);
|
||||
expect(TheStrongStuffEncounter.encounterTier).toBe(MysteryEncounterTier.GREAT);
|
||||
expect(TheStrongStuffEncounter.encounterTier).toBe(MysteryEncounterTier.COMMON);
|
||||
expect(TheStrongStuffEncounter.dialogue).toBeDefined();
|
||||
expect(TheStrongStuffEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}.intro` }]);
|
||||
expect(TheStrongStuffEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}.title`);
|
||||
|
@ -24,6 +24,7 @@ import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||
import { Stat } from "#enums/stat";
|
||||
import { BerryModifier } from "#app/modifier/modifier";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
|
||||
const namespace = "mysteryEncounter:uncommonBreed";
|
||||
const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA];
|
||||
@ -42,11 +43,13 @@ describe("Uncommon Breed - Mystery Encounter", () => {
|
||||
beforeEach(async () => {
|
||||
game = new GameManager(phaserGame);
|
||||
scene = game.scene;
|
||||
game.override.mysteryEncounterChance(100);
|
||||
game.override.mysteryEncounterTier(MysteryEncounterTier.COMMON);
|
||||
game.override.startingWave(defaultWave);
|
||||
game.override.startingBiome(defaultBiome);
|
||||
game.override.disableTrainerWaves();
|
||||
game.override.mysteryEncounterChance(100)
|
||||
.mysteryEncounterTier(MysteryEncounterTier.COMMON)
|
||||
.startingWave(defaultWave)
|
||||
.startingBiome(defaultBiome)
|
||||
.disableTrainerWaves()
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyPassiveAbility(Abilities.BALL_FETCH);
|
||||
|
||||
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(
|
||||
new Map<Biome, MysteryEncounterType[]>([
|
||||
@ -107,7 +110,34 @@ describe("Uncommon Breed - Mystery Encounter", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.skip("should start a fight against the boss", async () => {
|
||||
it.skip("should start a fight against the boss below wave 50", async () => {
|
||||
const phaseSpy = vi.spyOn(scene, "pushPhase");
|
||||
const unshiftPhaseSpy = vi.spyOn(scene, "unshiftPhase");
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.UNCOMMON_BREED, defaultParty);
|
||||
|
||||
const config = game.scene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0];
|
||||
const speciesToSpawn = config.pokemonConfigs?.[0].species.speciesId;
|
||||
|
||||
await runMysteryEncounterToEnd(game, 1, undefined, true);
|
||||
|
||||
const enemyField = scene.getEnemyField();
|
||||
expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name);
|
||||
expect(enemyField.length).toBe(1);
|
||||
expect(enemyField[0].species.speciesId).toBe(speciesToSpawn);
|
||||
|
||||
const statStagePhases = unshiftPhaseSpy.mock.calls.filter(p => p[0] instanceof StatStageChangePhase)[0][0] as any;
|
||||
expect(statStagePhases.stats).toEqual([Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]);
|
||||
|
||||
// Should have used its egg move pre-battle
|
||||
const movePhases = phaseSpy.mock.calls.filter(p => p[0] instanceof MovePhase).map(p => p[0]);
|
||||
expect(movePhases.length).toBe(1);
|
||||
const eggMoves: Moves[] = speciesEggMoves[getPokemonSpecies(speciesToSpawn).getRootSpeciesId()];
|
||||
const usedMove = (movePhases[0] as MovePhase).move.moveId;
|
||||
expect(eggMoves.includes(usedMove)).toBe(true);
|
||||
});
|
||||
|
||||
it.skip("should start a fight against the boss above wave 50", async () => {
|
||||
game.override.startingWave(57);
|
||||
const phaseSpy = vi.spyOn(scene, "pushPhase");
|
||||
const unshiftPhaseSpy = vi.spyOn(scene, "unshiftPhase");
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.UNCOMMON_BREED, defaultParty);
|
||||
|
@ -195,7 +195,7 @@ export default class GameManager {
|
||||
async runToMysteryEncounter(encounterType?: MysteryEncounterType, species?: Species[]) {
|
||||
if (!isNullOrUndefined(encounterType)) {
|
||||
this.override.disableTrainerWaves();
|
||||
this.override.mysteryEncounter(encounterType!);
|
||||
this.override.mysteryEncounter(encounterType);
|
||||
}
|
||||
|
||||
await this.runToTitle();
|
||||
|
@ -95,8 +95,8 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||
super.show(args);
|
||||
|
||||
this.overrideSettings = args[0] as OptionSelectSettings ?? {};
|
||||
const showDescriptionContainer = isNullOrUndefined(this.overrideSettings?.hideDescription) ? true : !this.overrideSettings?.hideDescription;
|
||||
const slideInDescription = isNullOrUndefined(this.overrideSettings?.slideInDescription) ? true : this.overrideSettings?.slideInDescription;
|
||||
const showDescriptionContainer = isNullOrUndefined(this.overrideSettings?.hideDescription) ? true : !this.overrideSettings.hideDescription;
|
||||
const slideInDescription = isNullOrUndefined(this.overrideSettings?.slideInDescription) ? true : this.overrideSettings.slideInDescription;
|
||||
const startingCursorIndex = this.overrideSettings?.startingCursorIndex ?? 0;
|
||||
|
||||
this.cursorContainer.setVisible(true);
|
||||
|
@ -260,6 +260,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
private pokemonCandyCountText: Phaser.GameObjects.Text;
|
||||
private pokemonCaughtHatchedContainer: Phaser.GameObjects.Container;
|
||||
private pokemonCaughtCountText: Phaser.GameObjects.Text;
|
||||
private pokemonFormText: Phaser.GameObjects.Text;
|
||||
private pokemonHatchedIcon : Phaser.GameObjects.Sprite;
|
||||
private pokemonHatchedCountText: Phaser.GameObjects.Text;
|
||||
private pokemonShinyIcon: Phaser.GameObjects.Sprite;
|
||||
@ -287,7 +288,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
private starterSelectMessageBox: Phaser.GameObjects.NineSlice;
|
||||
private starterSelectMessageBoxContainer: Phaser.GameObjects.Container;
|
||||
private statsContainer: StatsContainer;
|
||||
private pokemonFormText: Phaser.GameObjects.Text;
|
||||
private moveInfoOverlay : MoveInfoOverlay;
|
||||
|
||||
private statsMode: boolean;
|
||||
@ -2288,6 +2288,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.filterInstructionRowX += 50;
|
||||
}
|
||||
}
|
||||
|
||||
updateInstructions(): void {
|
||||
this.instructionRowX = 0;
|
||||
this.instructionRowY = 0;
|
||||
@ -2826,6 +2827,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.pokemonShinyIcon.setTint(tint);
|
||||
this.pokemonShinyIcon.setVisible(defaultProps.shiny);
|
||||
this.pokemonCaughtHatchedContainer.setVisible(true);
|
||||
this.pokemonFormText.setVisible(true);
|
||||
|
||||
if (pokemonPrevolutions.hasOwnProperty(species.speciesId)) {
|
||||
this.pokemonCaughtHatchedContainer.setY(16);
|
||||
this.pokemonShinyIcon.setY(135);
|
||||
@ -2849,7 +2852,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.pokemonCandyDarknessOverlay.setVisible(true);
|
||||
this.pokemonCandyCountText.setText(`x${this.scene.gameData.starterData[species.speciesId].candyCount}`);
|
||||
this.pokemonCandyCountText.setVisible(true);
|
||||
this.pokemonFormText.setVisible(true);
|
||||
this.pokemonFormText.setY(42);
|
||||
this.pokemonHatchedIcon.setVisible(true);
|
||||
this.pokemonHatchedCountText.setVisible(true);
|
||||
|
@ -584,7 +584,7 @@ export function capitalizeString(str: string, sep: string, lowerFirstChar: boole
|
||||
* Returns if an object is null or undefined
|
||||
* @param object
|
||||
*/
|
||||
export function isNullOrUndefined(object: any): boolean {
|
||||
export function isNullOrUndefined(object: any): object is undefined | null {
|
||||
return null === object || undefined === object;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user