[Beta][Bug] Major/minor ME bug fixes (#4451)
* major/minor ME bug fixes * potential fix for failed save with rental pokemon * Update src/system/game-data.ts Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> * Update src/system/game-data.ts Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> * more bug fix cleanup and PR feedback * fix Uncommon Breed ME crash * real fix to Fun and Games force switch issues * add isBattleMysteryEncounter() helper function * add isBattleMysteryEncounter() helper function * fix unintentional replace all errors * fix catches not updating dex --------- Co-authored-by: ImperialSympathizer <imperialsympathizer@gmail.com> Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>
This commit is contained in:
parent
6e18c76e25
commit
5997744aa2
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 1.1 KiB |
|
@ -1201,7 +1201,7 @@ export default class BattleScene extends SceneBase {
|
||||||
|
|
||||||
// Check for mystery encounter
|
// Check for mystery encounter
|
||||||
// Can only occur in place of a standard (non-boss) wild battle, waves 10-180
|
// Can only occur in place of a standard (non-boss) wild battle, waves 10-180
|
||||||
if (this.isWaveMysteryEncounter(newBattleType, newWaveIndex, mysteryEncounterType) || newBattleType === BattleType.MYSTERY_ENCOUNTER || !isNullOrUndefined(mysteryEncounterType)) {
|
if (this.isWaveMysteryEncounter(newBattleType, newWaveIndex, mysteryEncounterType) || newBattleType === BattleType.MYSTERY_ENCOUNTER) {
|
||||||
newBattleType = BattleType.MYSTERY_ENCOUNTER;
|
newBattleType = BattleType.MYSTERY_ENCOUNTER;
|
||||||
// Reset base spawn weight
|
// Reset base spawn weight
|
||||||
this.mysteryEncounterSaveData.encounterSpawnChance = BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT;
|
this.mysteryEncounterSaveData.encounterSpawnChance = BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT;
|
||||||
|
@ -3002,7 +3002,7 @@ export default class BattleScene extends SceneBase {
|
||||||
if (participantIds.size > 0) {
|
if (participantIds.size > 0) {
|
||||||
if (this.currentBattle.battleType === BattleType.TRAINER || this.currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
|
if (this.currentBattle.battleType === BattleType.TRAINER || this.currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
|
||||||
expValue = Math.floor(expValue * 1.5);
|
expValue = Math.floor(expValue * 1.5);
|
||||||
} else if (this.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && this.currentBattle.mysteryEncounter) {
|
} else if (this.currentBattle.isBattleMysteryEncounter() && this.currentBattle.mysteryEncounter) {
|
||||||
expValue = Math.floor(expValue * this.currentBattle.mysteryEncounter.expMultiplier);
|
expValue = Math.floor(expValue * this.currentBattle.mysteryEncounter.expMultiplier);
|
||||||
}
|
}
|
||||||
for (const partyMember of nonFaintedPartyMembers) {
|
for (const partyMember of nonFaintedPartyMembers) {
|
||||||
|
@ -3102,9 +3102,10 @@ export default class BattleScene extends SceneBase {
|
||||||
|
|
||||||
// If total number of encounters is lower than expected for the run, slightly favor a new encounter spawn (reverse as well)
|
// 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
|
// Reduces occurrence of runs with total encounters significantly different from AVERAGE_ENCOUNTERS_PER_RUN_TARGET
|
||||||
|
// Favored rate changes can never exceed 50%. So if base rate is 15/256 and favored rate would add 200/256, result will be (15 + 128)/256
|
||||||
const expectedEncountersByFloor = AVERAGE_ENCOUNTERS_PER_RUN_TARGET / (highestMysteryEncounterWave - lowestMysteryEncounterWave) * (waveIndex - lowestMysteryEncounterWave);
|
const expectedEncountersByFloor = AVERAGE_ENCOUNTERS_PER_RUN_TARGET / (highestMysteryEncounterWave - lowestMysteryEncounterWave) * (waveIndex - lowestMysteryEncounterWave);
|
||||||
const currentRunDiffFromAvg = expectedEncountersByFloor - encounteredEvents.length;
|
const currentRunDiffFromAvg = expectedEncountersByFloor - encounteredEvents.length;
|
||||||
const favoredEncounterRate = sessionEncounterRate + currentRunDiffFromAvg * ANTI_VARIANCE_WEIGHT_MODIFIER;
|
const favoredEncounterRate = sessionEncounterRate + Math.min(currentRunDiffFromAvg * ANTI_VARIANCE_WEIGHT_MODIFIER, MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT / 2);
|
||||||
|
|
||||||
const successRate = isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE) ? favoredEncounterRate : Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE!;
|
const successRate = isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE) ? favoredEncounterRate : Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE!;
|
||||||
|
|
||||||
|
|
|
@ -213,7 +213,7 @@ export default class Battle {
|
||||||
|
|
||||||
getBgmOverride(scene: BattleScene): string | null {
|
getBgmOverride(scene: BattleScene): string | null {
|
||||||
const battlers = this.enemyParty.slice(0, this.getBattlerCount());
|
const battlers = this.enemyParty.slice(0, this.getBattlerCount());
|
||||||
if (this.battleType === BattleType.MYSTERY_ENCOUNTER && this.mysteryEncounter?.encounterMode === MysteryEncounterMode.DEFAULT) {
|
if (this.isBattleMysteryEncounter() && this.mysteryEncounter?.encounterMode === MysteryEncounterMode.DEFAULT) {
|
||||||
// Music is overridden for MEs during ME onInit()
|
// Music is overridden for MEs during ME onInit()
|
||||||
// Should not use any BGM overrides before swapping from DEFAULT mode
|
// Should not use any BGM overrides before swapping from DEFAULT mode
|
||||||
return null;
|
return null;
|
||||||
|
@ -409,6 +409,13 @@ export default class Battle {
|
||||||
scene.rngSeedOverride = tempSeedOverride;
|
scene.rngSeedOverride = tempSeedOverride;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the battle is of type {@linkcode BattleType.MYSTERY_ENCOUNTER}
|
||||||
|
*/
|
||||||
|
isBattleMysteryEncounter(): boolean {
|
||||||
|
return this.battleType === BattleType.MYSTERY_ENCOUNTER;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FixedBattle extends Battle {
|
export class FixedBattle extends Battle {
|
||||||
|
|
|
@ -5290,6 +5290,11 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!player && user.scene.currentBattle.isBattleMysteryEncounter() && !user.scene.currentBattle.mysteryEncounter?.fleeAllowed) {
|
||||||
|
// Don't allow wild opponents to be force switched during MEs with flee disabled
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const blockedByAbility = new Utils.BooleanHolder(false);
|
const blockedByAbility = new Utils.BooleanHolder(false);
|
||||||
applyAbAttrs(ForceSwitchOutImmunityAbAttr, target, blockedByAbility);
|
applyAbAttrs(ForceSwitchOutImmunityAbAttr, target, blockedByAbility);
|
||||||
return !blockedByAbility.value;
|
return !blockedByAbility.value;
|
||||||
|
|
|
@ -24,6 +24,7 @@ import { BerryType } from "#enums/berry-type";
|
||||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||||
import { Stat } from "#enums/stat";
|
import { Stat } from "#enums/stat";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
/** the i18n namespace for this encounter */
|
/** the i18n namespace for this encounter */
|
||||||
const namespace = "mysteryEncounter:absoluteAvarice";
|
const namespace = "mysteryEncounter:absoluteAvarice";
|
||||||
|
@ -38,6 +39,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
||||||
.withEncounterTier(MysteryEncounterTier.GREAT)
|
.withEncounterTier(MysteryEncounterTier.GREAT)
|
||||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||||
.withSceneRequirement(new PersistentModifierRequirement("BerryModifier", 4)) // Must have at least 4 berries to spawn
|
.withSceneRequirement(new PersistentModifierRequirement("BerryModifier", 4)) // Must have at least 4 berries to spawn
|
||||||
|
.withFleeAllowed(false)
|
||||||
.withIntroSpriteConfigs([
|
.withIntroSpriteConfigs([
|
||||||
{
|
{
|
||||||
// This sprite has the shadow
|
// This sprite has the shadow
|
||||||
|
@ -262,15 +264,13 @@ export const AbsoluteAvariceEncounter: MysteryEncounter =
|
||||||
|
|
||||||
// Provides 1x Reviver Seed to each party member at end of battle
|
// Provides 1x Reviver Seed to each party member at end of battle
|
||||||
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED);
|
const revSeed = generateModifierType(scene, modifierTypes.REVIVER_SEED);
|
||||||
|
encounter.setDialogueToken("foodReward", revSeed?.name ?? i18next.t("modifierType:ModifierType.REVIVER_SEED.name"));
|
||||||
const givePartyPokemonReviverSeeds = () => {
|
const givePartyPokemonReviverSeeds = () => {
|
||||||
const party = scene.getParty();
|
const party = scene.getParty();
|
||||||
party.forEach(p => {
|
party.forEach(p => {
|
||||||
const heldItems = p.getHeldItems();
|
const heldItems = p.getHeldItems();
|
||||||
if (revSeed && !heldItems.some(item => item instanceof PokemonInstantReviveModifier)) {
|
if (revSeed && !heldItems.some(item => item instanceof PokemonInstantReviveModifier)) {
|
||||||
const seedModifier = revSeed.newModifier(p);
|
const seedModifier = revSeed.newModifier(p);
|
||||||
if (seedModifier) {
|
|
||||||
encounter.setDialogueToken("foodReward", seedModifier.type.name);
|
|
||||||
}
|
|
||||||
scene.addModifier(seedModifier, false, false, false, true);
|
scene.addModifier(seedModifier, false, false, false, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -70,7 +70,7 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter =
|
||||||
const encounter = scene.currentBattle.mysteryEncounter!;
|
const encounter = scene.currentBattle.mysteryEncounter!;
|
||||||
const pokemon = getHighestStatTotalPlayerPokemon(scene, true, true);
|
const pokemon = getHighestStatTotalPlayerPokemon(scene, true, true);
|
||||||
|
|
||||||
const baseSpecies = pokemon.getSpeciesForm().getRootSpeciesId(true);
|
const baseSpecies = pokemon.getSpeciesForm().getRootSpeciesId();
|
||||||
const starterValue: number = speciesStarters[baseSpecies] ?? 1;
|
const starterValue: number = speciesStarters[baseSpecies] ?? 1;
|
||||||
const multiplier = Math.max(MONEY_MAXIMUM_MULTIPLIER / 10 * starterValue, MONEY_MINIMUM_MULTIPLIER);
|
const multiplier = Math.max(MONEY_MAXIMUM_MULTIPLIER / 10 * starterValue, MONEY_MINIMUM_MULTIPLIER);
|
||||||
const price = scene.getWaveMoneyAmount(multiplier);
|
const price = scene.getWaveMoneyAmount(multiplier);
|
||||||
|
|
|
@ -46,6 +46,7 @@ export const BerriesAboundEncounter: MysteryEncounter =
|
||||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||||
.withCatchAllowed(true)
|
.withCatchAllowed(true)
|
||||||
.withHideWildIntroMessage(true)
|
.withHideWildIntroMessage(true)
|
||||||
|
.withFleeAllowed(false)
|
||||||
.withIntroSpriteConfigs([]) // Set in onInit()
|
.withIntroSpriteConfigs([]) // Set in onInit()
|
||||||
.withIntroDialogue([
|
.withIntroDialogue([
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,6 +49,7 @@ import MoveInfoOverlay from "#app/ui/move-info-overlay";
|
||||||
import { allMoves } from "#app/data/move";
|
import { allMoves } from "#app/data/move";
|
||||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
||||||
|
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounter:bugTypeSuperfan";
|
const namespace = "mysteryEncounter:bugTypeSuperfan";
|
||||||
|
@ -177,9 +178,14 @@ const MISC_TUTOR_MOVES = [
|
||||||
Moves.U_TURN
|
Moves.U_TURN
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wave breakpoints that determine how strong to make the Bug-Type Superfan's team
|
||||||
|
*/
|
||||||
|
const WAVE_LEVEL_BREAKPOINTS = [30, 50, 70, 100, 120, 140, 160];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bug Type Superfan encounter.
|
* Bug Type Superfan encounter.
|
||||||
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3810 | GitHub Issue #3810}
|
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3820 | GitHub Issue #3820}
|
||||||
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
|
||||||
*/
|
*/
|
||||||
export const BugTypeSuperfanEncounter: MysteryEncounter =
|
export const BugTypeSuperfanEncounter: MysteryEncounter =
|
||||||
|
@ -216,11 +222,46 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
||||||
female: true,
|
female: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let beedrillKeys: { spriteKey: string, fileRoot: string }, butterfreeKeys: { spriteKey: string, fileRoot: string };
|
||||||
|
if (scene.currentBattle.waveIndex < WAVE_LEVEL_BREAKPOINTS[3]) {
|
||||||
|
beedrillKeys = getSpriteKeysFromSpecies(Species.BEEDRILL, false);
|
||||||
|
butterfreeKeys = getSpriteKeysFromSpecies(Species.BUTTERFREE, false);
|
||||||
|
} else {
|
||||||
|
// Mega Beedrill/Gmax Butterfree
|
||||||
|
beedrillKeys = getSpriteKeysFromSpecies(Species.BEEDRILL, false, 1);
|
||||||
|
butterfreeKeys = getSpriteKeysFromSpecies(Species.BUTTERFREE, false, 1);
|
||||||
|
}
|
||||||
|
|
||||||
encounter.spriteConfigs = [
|
encounter.spriteConfigs = [
|
||||||
|
{
|
||||||
|
spriteKey: beedrillKeys.spriteKey,
|
||||||
|
fileRoot: beedrillKeys.fileRoot,
|
||||||
|
hasShadow: true,
|
||||||
|
repeat: true,
|
||||||
|
isPokemon: true,
|
||||||
|
x: -30,
|
||||||
|
tint: 0.15,
|
||||||
|
y: -4,
|
||||||
|
yShadow: -4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spriteKey: butterfreeKeys.spriteKey,
|
||||||
|
fileRoot: butterfreeKeys.fileRoot,
|
||||||
|
hasShadow: true,
|
||||||
|
repeat: true,
|
||||||
|
isPokemon: true,
|
||||||
|
x: 30,
|
||||||
|
tint: 0.15,
|
||||||
|
y: -4,
|
||||||
|
yShadow: -4
|
||||||
|
},
|
||||||
{
|
{
|
||||||
spriteKey: spriteKey,
|
spriteKey: spriteKey,
|
||||||
fileRoot: "trainer",
|
fileRoot: "trainer",
|
||||||
hasShadow: true,
|
hasShadow: true,
|
||||||
|
x: 4,
|
||||||
|
y: 7,
|
||||||
|
yShadow: 7
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -330,6 +371,10 @@ export const BugTypeSuperfanEncounter: MysteryEncounter =
|
||||||
if (formChangeModifier) {
|
if (formChangeModifier) {
|
||||||
specialOptions.push(formChangeModifier);
|
specialOptions.push(formChangeModifier);
|
||||||
}
|
}
|
||||||
|
const rareFormChangeModifier = generateModifierTypeOption(scene, modifierTypes.RARE_FORM_CHANGE_ITEM);
|
||||||
|
if (rareFormChangeModifier) {
|
||||||
|
specialOptions.push(rareFormChangeModifier);
|
||||||
|
}
|
||||||
if (specialOptions.length > 0) {
|
if (specialOptions.length > 0) {
|
||||||
modifierOptions.push(specialOptions[randSeedInt(specialOptions.length)]);
|
modifierOptions.push(specialOptions[randSeedInt(specialOptions.length)]);
|
||||||
}
|
}
|
||||||
|
@ -445,29 +490,29 @@ function getTrainerConfigForWave(waveIndex: number) {
|
||||||
const config = trainerConfigs[TrainerType.BUG_TYPE_SUPERFAN].clone();
|
const config = trainerConfigs[TrainerType.BUG_TYPE_SUPERFAN].clone();
|
||||||
config.name = i18next.t("trainerNames:bug_type_superfan");
|
config.name = i18next.t("trainerNames:bug_type_superfan");
|
||||||
|
|
||||||
const pool3Copy = POOL_3_POKEMON.slice(0);
|
let pool3Copy = POOL_3_POKEMON.slice(0);
|
||||||
randSeedShuffle(pool3Copy);
|
pool3Copy = randSeedShuffle(pool3Copy);
|
||||||
const pool3Mon = pool3Copy.pop()!;
|
const pool3Mon = pool3Copy.pop()!;
|
||||||
|
|
||||||
if (waveIndex < 30) {
|
if (waveIndex < WAVE_LEVEL_BREAKPOINTS[0]) {
|
||||||
// Use default template (2 AVG)
|
// Use default template (2 AVG)
|
||||||
config
|
config
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true))
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUTTERFREE ], TrainerSlot.TRAINER, true));
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUTTERFREE ], TrainerSlot.TRAINER, true));
|
||||||
} else if (waveIndex < 50) {
|
} else if (waveIndex < WAVE_LEVEL_BREAKPOINTS[1]) {
|
||||||
config
|
config
|
||||||
.setPartyTemplates(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE))
|
.setPartyTemplates(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE))
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true))
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUTTERFREE ], TrainerSlot.TRAINER, true))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUTTERFREE ], TrainerSlot.TRAINER, true))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_1_POKEMON, TrainerSlot.TRAINER, true));
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_1_POKEMON, TrainerSlot.TRAINER, true));
|
||||||
} else if (waveIndex < 70) {
|
} else if (waveIndex < WAVE_LEVEL_BREAKPOINTS[2]) {
|
||||||
config
|
config
|
||||||
.setPartyTemplates(new TrainerPartyTemplate(4, PartyMemberStrength.AVERAGE))
|
.setPartyTemplates(new TrainerPartyTemplate(4, PartyMemberStrength.AVERAGE))
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true))
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true))
|
||||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUTTERFREE ], TrainerSlot.TRAINER, true))
|
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BUTTERFREE ], TrainerSlot.TRAINER, true))
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_1_POKEMON, TrainerSlot.TRAINER, true))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_1_POKEMON, TrainerSlot.TRAINER, true))
|
||||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true));
|
.setPartyMemberFunc(3, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true));
|
||||||
} else if (waveIndex < 100) {
|
} else if (waveIndex < WAVE_LEVEL_BREAKPOINTS[3]) {
|
||||||
config
|
config
|
||||||
.setPartyTemplates(new TrainerPartyTemplate(5, PartyMemberStrength.AVERAGE))
|
.setPartyTemplates(new TrainerPartyTemplate(5, PartyMemberStrength.AVERAGE))
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true))
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true))
|
||||||
|
@ -475,7 +520,7 @@ function getTrainerConfigForWave(waveIndex: number) {
|
||||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_1_POKEMON, TrainerSlot.TRAINER, true))
|
.setPartyMemberFunc(2, getRandomPartyMemberFunc(POOL_1_POKEMON, TrainerSlot.TRAINER, true))
|
||||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
|
.setPartyMemberFunc(3, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true))
|
||||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true));
|
.setPartyMemberFunc(4, getRandomPartyMemberFunc(POOL_2_POKEMON, TrainerSlot.TRAINER, true));
|
||||||
} else if (waveIndex < 120) {
|
} else if (waveIndex < WAVE_LEVEL_BREAKPOINTS[4]) {
|
||||||
config
|
config
|
||||||
.setPartyTemplates(new TrainerPartyTemplate(5, PartyMemberStrength.AVERAGE))
|
.setPartyTemplates(new TrainerPartyTemplate(5, PartyMemberStrength.AVERAGE))
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true, p => {
|
||||||
|
@ -497,8 +542,8 @@ function getTrainerConfigForWave(waveIndex: number) {
|
||||||
p.generateName();
|
p.generateName();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
} else if (waveIndex < 140) {
|
} else if (waveIndex < WAVE_LEVEL_BREAKPOINTS[5]) {
|
||||||
randSeedShuffle(pool3Copy);
|
pool3Copy = randSeedShuffle(pool3Copy);
|
||||||
const pool3Mon2 = pool3Copy.pop()!;
|
const pool3Mon2 = pool3Copy.pop()!;
|
||||||
config
|
config
|
||||||
.setPartyTemplates(new TrainerPartyTemplate(5, PartyMemberStrength.AVERAGE))
|
.setPartyTemplates(new TrainerPartyTemplate(5, PartyMemberStrength.AVERAGE))
|
||||||
|
@ -527,7 +572,7 @@ function getTrainerConfigForWave(waveIndex: number) {
|
||||||
p.generateName();
|
p.generateName();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
} else if (waveIndex < 160) {
|
} else if (waveIndex < WAVE_LEVEL_BREAKPOINTS[6]) {
|
||||||
config
|
config
|
||||||
.setPartyTemplates(new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(4, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)))
|
.setPartyTemplates(new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(4, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)))
|
||||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true, p => {
|
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BEEDRILL ], TrainerSlot.TRAINER, true, p => {
|
||||||
|
@ -629,27 +674,7 @@ function doBugTypeMoveTutor(scene: BattleScene): Promise<void> {
|
||||||
moveInfoOverlay.setVisible(false);
|
moveInfoOverlay.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add menu to confirm player doesn't want to teach a move
|
// TODO: add menu to confirm player doesn't want to teach a move?
|
||||||
// while (!result && !forceExit) {
|
|
||||||
// // Didn't teach a move, ask the player to confirm they don't want to teach a move
|
|
||||||
// await showEncounterDialogue(scene, `${namespace}.confirm_no_teach`, `${namespace}.speaker`);
|
|
||||||
// const confirm = await new Promise<boolean>(confirmResolve => {
|
|
||||||
// scene.ui.setMode(Mode.CONFIRM, () => confirmResolve(true), () => confirmResolve(false));
|
|
||||||
// });
|
|
||||||
// scene.ui.clearText();
|
|
||||||
// await scene.ui.setMode(Mode.MESSAGE);
|
|
||||||
// if (confirm) {
|
|
||||||
// // No teach, break out of loop
|
|
||||||
// forceExit = true;
|
|
||||||
// } else {
|
|
||||||
// // Re-show learn menu
|
|
||||||
// result = await selectOptionThenPokemon(scene, optionSelectItems, `${namespace}.teach_move_prompt`, undefined, onHoverOverCancel);
|
|
||||||
// if (!result) {
|
|
||||||
// moveInfoOverlay.active = false;
|
|
||||||
// moveInfoOverlay.setVisible(false);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Option select complete, handle if they are learning a move
|
// Option select complete, handle if they are learning a move
|
||||||
if (result && result.selectedOptionIndex < moveOptions.length) {
|
if (result && result.selectedOptionIndex < moveOptions.length) {
|
||||||
|
|
|
@ -336,8 +336,8 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
||||||
.filter(move => move && !originalTypes.includes(move.getMove().type) && move.getMove().category !== MoveCategory.STATUS)
|
.filter(move => move && !originalTypes.includes(move.getMove().type) && move.getMove().category !== MoveCategory.STATUS)
|
||||||
.map(move => move!.getMove().type);
|
.map(move => move!.getMove().type);
|
||||||
if (priorityTypes?.length > 0) {
|
if (priorityTypes?.length > 0) {
|
||||||
priorityTypes = [...new Set(priorityTypes)];
|
priorityTypes = [...new Set(priorityTypes)].sort();
|
||||||
randSeedShuffle(priorityTypes);
|
priorityTypes = randSeedShuffle(priorityTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newTypes = [originalTypes[0]];
|
const newTypes = [originalTypes[0]];
|
||||||
|
@ -494,9 +494,13 @@ function generateItemsOfTier(scene: BattleScene, pokemon: PlayerPokemon, numItem
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < numItems; i++) {
|
for (let i = 0; i < numItems; i++) {
|
||||||
|
if (pool.length === 0) {
|
||||||
|
// Stop generating new items if somehow runs out of items to spawn
|
||||||
|
return;
|
||||||
|
}
|
||||||
const randIndex = randSeedInt(pool.length);
|
const randIndex = randSeedInt(pool.length);
|
||||||
const newItemType = pool[randIndex];
|
const newItemType = pool[randIndex];
|
||||||
let newMod;
|
let newMod: PokemonHeldItemModifierType;
|
||||||
if (tier === "Berries") {
|
if (tier === "Berries") {
|
||||||
newMod = generateModifierType(scene, modifierTypes.BERRY, [newItemType[0]]) as PokemonHeldItemModifierType;
|
newMod = generateModifierType(scene, modifierTypes.BERRY, [newItemType[0]]) as PokemonHeldItemModifierType;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -90,6 +90,7 @@ export const DancingLessonsEncounter: MysteryEncounter =
|
||||||
.withHideWildIntroMessage(true)
|
.withHideWildIntroMessage(true)
|
||||||
.withAutoHideIntroVisuals(false)
|
.withAutoHideIntroVisuals(false)
|
||||||
.withCatchAllowed(true)
|
.withCatchAllowed(true)
|
||||||
|
.withFleeAllowed(false)
|
||||||
.withOnVisualsStart((scene: BattleScene) => {
|
.withOnVisualsStart((scene: BattleScene) => {
|
||||||
const danceAnim = new EncounterBattleAnim(EncounterAnim.DANCE, scene.getEnemyPokemon()!, scene.getParty()[0]);
|
const danceAnim = new EncounterBattleAnim(EncounterAnim.DANCE, scene.getEnemyPokemon()!, scene.getParty()[0]);
|
||||||
danceAnim.play(scene);
|
danceAnim.play(scene);
|
||||||
|
|
|
@ -46,6 +46,7 @@ export const FieryFalloutEncounter: MysteryEncounter =
|
||||||
.withIntroSpriteConfigs([]) // Set in onInit()
|
.withIntroSpriteConfigs([]) // Set in onInit()
|
||||||
.withAnimations(EncounterAnim.MAGMA_BG, EncounterAnim.MAGMA_SPOUT)
|
.withAnimations(EncounterAnim.MAGMA_BG, EncounterAnim.MAGMA_SPOUT)
|
||||||
.withAutoHideIntroVisuals(false)
|
.withAutoHideIntroVisuals(false)
|
||||||
|
.withFleeAllowed(false)
|
||||||
.withIntroDialogue([
|
.withIntroDialogue([
|
||||||
{
|
{
|
||||||
text: `${namespace}.intro`,
|
text: `${namespace}.intro`,
|
||||||
|
|
|
@ -44,6 +44,7 @@ export const FightOrFlightEncounter: MysteryEncounter =
|
||||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||||
.withCatchAllowed(true)
|
.withCatchAllowed(true)
|
||||||
.withHideWildIntroMessage(true)
|
.withHideWildIntroMessage(true)
|
||||||
|
.withFleeAllowed(false)
|
||||||
.withIntroSpriteConfigs([]) // Set in onInit()
|
.withIntroSpriteConfigs([]) // Set in onInit()
|
||||||
.withIntroDialogue([
|
.withIntroDialogue([
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,6 +44,7 @@ export const FunAndGamesEncounter: MysteryEncounter =
|
||||||
.withSkipEnemyBattleTurns(true)
|
.withSkipEnemyBattleTurns(true)
|
||||||
// Will skip COMMAND selection menu and go straight to FIGHT (move select) menu
|
// Will skip COMMAND selection menu and go straight to FIGHT (move select) menu
|
||||||
.withSkipToFightInput(true)
|
.withSkipToFightInput(true)
|
||||||
|
.withFleeAllowed(false)
|
||||||
.withIntroSpriteConfigs([
|
.withIntroSpriteConfigs([
|
||||||
{
|
{
|
||||||
spriteKey: "fun_and_games_game",
|
spriteKey: "fun_and_games_game",
|
||||||
|
|
|
@ -34,6 +34,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter =
|
||||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||||
.withCatchAllowed(true)
|
.withCatchAllowed(true)
|
||||||
.withHideWildIntroMessage(true)
|
.withHideWildIntroMessage(true)
|
||||||
|
.withFleeAllowed(false)
|
||||||
.withIntroSpriteConfigs([
|
.withIntroSpriteConfigs([
|
||||||
{
|
{
|
||||||
spriteKey: Species.SNORLAX.toString(),
|
spriteKey: Species.SNORLAX.toString(),
|
||||||
|
|
|
@ -42,6 +42,7 @@ export const TeleportingHijinksEncounter: MysteryEncounter =
|
||||||
.withSceneRequirement(new MoneyRequirement(0, 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)
|
.withAutoHideIntroVisuals(false)
|
||||||
.withCatchAllowed(true)
|
.withCatchAllowed(true)
|
||||||
|
.withFleeAllowed(false)
|
||||||
.withIntroSpriteConfigs([
|
.withIntroSpriteConfigs([
|
||||||
{
|
{
|
||||||
spriteKey: "teleporting_hijinks_teleporter",
|
spriteKey: "teleporting_hijinks_teleporter",
|
||||||
|
|
|
@ -437,8 +437,7 @@ function getPartyConfig(scene: BattleScene): EnemyPartyConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSpeciesFromPool(speciesPool: (Species | BreederSpeciesEvolution)[][], waveIndex: number): Species {
|
function getSpeciesFromPool(speciesPool: (Species | BreederSpeciesEvolution)[][], waveIndex: number): Species {
|
||||||
const poolCopy = speciesPool.slice(0);
|
const poolCopy = randSeedShuffle(speciesPool.slice(0));
|
||||||
randSeedShuffle(poolCopy);
|
|
||||||
const speciesEvolutions = poolCopy.pop()!.slice(0);
|
const speciesEvolutions = poolCopy.pop()!.slice(0);
|
||||||
let speciesObject = speciesEvolutions.pop()!;
|
let speciesObject = speciesEvolutions.pop()!;
|
||||||
while (speciesObject instanceof BreederSpeciesEvolution && speciesObject.evolution > waveIndex) {
|
while (speciesObject instanceof BreederSpeciesEvolution && speciesObject.evolution > waveIndex) {
|
||||||
|
@ -452,7 +451,7 @@ function calculateEggRewardsForPokemon(pokemon: PlayerPokemon): [number, number]
|
||||||
// 1 point for every 20 points below 680 BST the pokemon is, (max 18, min 1)
|
// 1 point for every 20 points below 680 BST the pokemon is, (max 18, min 1)
|
||||||
const pointsFromBst = Math.min(Math.max(Math.floor((680 - bst) / 20), 1), 18);
|
const pointsFromBst = Math.min(Math.max(Math.floor((680 - bst) / 20), 1), 18);
|
||||||
|
|
||||||
const rootSpecies = pokemon.species.getRootSpeciesId(true);
|
const rootSpecies = pokemon.species.getRootSpeciesId();
|
||||||
let pointsFromStarterTier = 0;
|
let pointsFromStarterTier = 0;
|
||||||
// 2 points for every 1 below 7 that the pokemon's starter tier is (max 12, min 0)
|
// 2 points for every 1 below 7 that the pokemon's starter tier is (max 12, min 0)
|
||||||
if (speciesStarters.hasOwnProperty(rootSpecies)) {
|
if (speciesStarters.hasOwnProperty(rootSpecies)) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ export const TheStrongStuffEncounter: MysteryEncounter =
|
||||||
.withMaxAllowedEncounters(1)
|
.withMaxAllowedEncounters(1)
|
||||||
.withHideWildIntroMessage(true)
|
.withHideWildIntroMessage(true)
|
||||||
.withAutoHideIntroVisuals(false)
|
.withAutoHideIntroVisuals(false)
|
||||||
|
.withFleeAllowed(false)
|
||||||
.withIntroSpriteConfigs([
|
.withIntroSpriteConfigs([
|
||||||
{
|
{
|
||||||
spriteKey: "berry_juice",
|
spriteKey: "berry_juice",
|
||||||
|
|
|
@ -101,7 +101,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
|
||||||
encounter.setDialogueToken("stat1", "-");
|
encounter.setDialogueToken("stat1", "-");
|
||||||
encounter.setDialogueToken("stat2", "-");
|
encounter.setDialogueToken("stat2", "-");
|
||||||
// Add the pokemon back to party with IV boost
|
// Add the pokemon back to party with IV boost
|
||||||
const ivIndexes: any[] = [];
|
let ivIndexes: any[] = [];
|
||||||
playerPokemon.ivs.forEach((iv, index) => {
|
playerPokemon.ivs.forEach((iv, index) => {
|
||||||
if (iv < 31) {
|
if (iv < 31) {
|
||||||
ivIndexes.push({ iv: iv, index: index });
|
ivIndexes.push({ iv: iv, index: index });
|
||||||
|
@ -117,7 +117,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
|
||||||
// 25-27 starting IV caps in 2 encounters
|
// 25-27 starting IV caps in 2 encounters
|
||||||
let improvedCount = 0;
|
let improvedCount = 0;
|
||||||
while (ivIndexes.length > 0 && improvedCount < 2) {
|
while (ivIndexes.length > 0 && improvedCount < 2) {
|
||||||
randSeedShuffle(ivIndexes);
|
ivIndexes = randSeedShuffle(ivIndexes);
|
||||||
const ivToChange = ivIndexes.pop();
|
const ivToChange = ivIndexes.pop();
|
||||||
let newVal = ivToChange.iv;
|
let newVal = ivToChange.iv;
|
||||||
if (improvedCount === 0) {
|
if (improvedCount === 0) {
|
||||||
|
@ -145,10 +145,7 @@ export const TrainingSessionEncounter: MysteryEncounter =
|
||||||
|
|
||||||
if (improvedCount > 0) {
|
if (improvedCount > 0) {
|
||||||
playerPokemon.calculateStats();
|
playerPokemon.calculateStats();
|
||||||
scene.gameData.updateSpeciesDexIvs(
|
scene.gameData.updateSpeciesDexIvs(playerPokemon.species.getRootSpeciesId(true), playerPokemon.ivs);
|
||||||
playerPokemon.species.getRootSpeciesId(true),
|
|
||||||
playerPokemon.ivs
|
|
||||||
);
|
|
||||||
scene.gameData.setPokemonCaught(playerPokemon, false);
|
scene.gameData.setPokemonCaught(playerPokemon, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,27 +319,23 @@ export const TrainingSessionEncounter: MysteryEncounter =
|
||||||
queueEncounterMessage(scene, `${namespace}.option.3.finished`);
|
queueEncounterMessage(scene, `${namespace}.option.3.finished`);
|
||||||
// Add the pokemon back to party with ability change
|
// Add the pokemon back to party with ability change
|
||||||
const abilityIndex = encounter.misc.abilityIndex;
|
const abilityIndex = encounter.misc.abilityIndex;
|
||||||
|
|
||||||
if (!!playerPokemon.getFusionSpeciesForm()) {
|
if (!!playerPokemon.getFusionSpeciesForm()) {
|
||||||
playerPokemon.fusionAbilityIndex = abilityIndex;
|
playerPokemon.fusionAbilityIndex = abilityIndex;
|
||||||
if (!isNullOrUndefined(playerPokemon.fusionSpecies?.speciesId) && speciesStarters.hasOwnProperty(playerPokemon.fusionSpecies.speciesId)) {
|
|
||||||
scene.gameData.starterData[playerPokemon.fusionSpecies.speciesId]
|
// Only update the fusion's dex data if the Pokemon is already caught in dex (ignore rentals)
|
||||||
.abilityAttr |=
|
const rootFusionSpecies = playerPokemon.fusionSpecies?.getRootSpeciesId();
|
||||||
abilityIndex !== 1 || playerPokemon.fusionSpecies.ability2
|
if (!isNullOrUndefined(rootFusionSpecies)
|
||||||
? Math.pow(2, playerPokemon.fusionAbilityIndex)
|
&& speciesStarters.hasOwnProperty(rootFusionSpecies)
|
||||||
: AbilityAttr.ABILITY_HIDDEN;
|
&& !!scene.gameData.dexData[rootFusionSpecies].caughtAttr) {
|
||||||
|
scene.gameData.starterData[rootFusionSpecies].abilityAttr |= playerPokemon.fusionAbilityIndex !== 1 || playerPokemon.fusionSpecies?.ability2
|
||||||
|
? 1 << playerPokemon.fusionAbilityIndex
|
||||||
|
: AbilityAttr.ABILITY_HIDDEN;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
playerPokemon.abilityIndex = abilityIndex;
|
playerPokemon.abilityIndex = abilityIndex;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
playerPokemon.getAbility();
|
|
||||||
playerPokemon.calculateStats();
|
playerPokemon.calculateStats();
|
||||||
scene.gameData.setPokemonCaught(playerPokemon, false);
|
scene.gameData.setPokemonCaught(playerPokemon, false);
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ export const TrashToTreasureEncounter: MysteryEncounter =
|
||||||
.withEncounterTier(MysteryEncounterTier.ULTRA)
|
.withEncounterTier(MysteryEncounterTier.ULTRA)
|
||||||
.withSceneWaveRangeRequirement(60, CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES[1])
|
.withSceneWaveRangeRequirement(60, CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES[1])
|
||||||
.withMaxAllowedEncounters(1)
|
.withMaxAllowedEncounters(1)
|
||||||
|
.withFleeAllowed(false)
|
||||||
.withIntroSpriteConfigs([
|
.withIntroSpriteConfigs([
|
||||||
{
|
{
|
||||||
spriteKey: Species.GARBODOR.toString() + "-gigantamax",
|
spriteKey: Species.GARBODOR.toString() + "-gigantamax",
|
||||||
|
|
|
@ -38,6 +38,7 @@ export const UncommonBreedEncounter: MysteryEncounter =
|
||||||
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
|
||||||
.withCatchAllowed(true)
|
.withCatchAllowed(true)
|
||||||
.withHideWildIntroMessage(true)
|
.withHideWildIntroMessage(true)
|
||||||
|
.withFleeAllowed(false)
|
||||||
.withIntroSpriteConfigs([]) // Set in onInit()
|
.withIntroSpriteConfigs([]) // Set in onInit()
|
||||||
.withIntroDialogue([
|
.withIntroDialogue([
|
||||||
{
|
{
|
||||||
|
@ -59,17 +60,18 @@ export const UncommonBreedEncounter: MysteryEncounter =
|
||||||
const eggMoveIndex = randSeedInt(4);
|
const eggMoveIndex = randSeedInt(4);
|
||||||
const randomEggMove: Moves = eggMoves[eggMoveIndex];
|
const randomEggMove: Moves = eggMoves[eggMoveIndex];
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
eggMove: randomEggMove
|
eggMove: randomEggMove,
|
||||||
|
pokemon: pokemon
|
||||||
};
|
};
|
||||||
if (pokemon.moveset.length < 4) {
|
if (pokemon.moveset.length < 4) {
|
||||||
pokemon.moveset.push(new PokemonMove(randomEggMove));
|
pokemon.moveset.push(new PokemonMove(randomEggMove));
|
||||||
} else {
|
} else {
|
||||||
pokemon.moveset[0] = new PokemonMove(randomEggMove);
|
pokemon.moveset[0] = new PokemonMove(randomEggMove);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
encounter.misc.pokemon = pokemon;
|
||||||
}
|
}
|
||||||
|
|
||||||
encounter.misc.pokemon = pokemon;
|
|
||||||
|
|
||||||
// Defense/Spd buffs below wave 50, +1 to all stats 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 ?
|
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.DEF, Stat.SPDEF, Stat.SPD] :
|
||||||
|
|
|
@ -368,7 +368,7 @@ async function doNewTeamPostProcess(scene: BattleScene, transformations: Pokemon
|
||||||
const newEggMoveIndex = await addEggMoveToNewPokemonMoveset(scene, newPokemon, speciesRootForm);
|
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)
|
// Try to add a favored STAB move (might fail if Pokemon already knows a bunch of moves from newPokemonGeneratedMoveset)
|
||||||
addFavoredMoveToNewPokemonMoveset(scene, newPokemon, newPokemonGeneratedMoveset, newEggMoveIndex);
|
addFavoredMoveToNewPokemonMoveset(newPokemon, newPokemonGeneratedMoveset, newEggMoveIndex);
|
||||||
|
|
||||||
// Randomize the second type of the pokemon
|
// Randomize the second type of the pokemon
|
||||||
// If the pokemon does not normally have a second type, it will gain 1
|
// If the pokemon does not normally have a second type, it will gain 1
|
||||||
|
@ -553,8 +553,7 @@ async function addEggMoveToNewPokemonMoveset(scene: BattleScene, newPokemon: Pla
|
||||||
let eggMoveIndex: null | number = null;
|
let eggMoveIndex: null | number = null;
|
||||||
const eggMoves = newPokemon.getEggMoves()?.slice(0);
|
const eggMoves = newPokemon.getEggMoves()?.slice(0);
|
||||||
if (eggMoves) {
|
if (eggMoves) {
|
||||||
const eggMoveIndices = [0, 1, 2, 3];
|
const eggMoveIndices = randSeedShuffle([0, 1, 2, 3]);
|
||||||
randSeedShuffle(eggMoveIndices);
|
|
||||||
let randomEggMoveIndex = eggMoveIndices.pop();
|
let randomEggMoveIndex = eggMoveIndices.pop();
|
||||||
let randomEggMove = !isNullOrUndefined(randomEggMoveIndex) ? eggMoves[randomEggMoveIndex] : null;
|
let randomEggMove = !isNullOrUndefined(randomEggMoveIndex) ? eggMoves[randomEggMoveIndex] : null;
|
||||||
let retries = 0;
|
let retries = 0;
|
||||||
|
@ -587,12 +586,11 @@ async function addEggMoveToNewPokemonMoveset(scene: BattleScene, newPokemon: Pla
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns index of the new egg move within the Pokemon's moveset (not the index of the move in `speciesEggMoves`)
|
* 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 newPokemon
|
||||||
* @param newPokemonGeneratedMoveset
|
* @param newPokemonGeneratedMoveset
|
||||||
* @param newEggMoveIndex
|
* @param newEggMoveIndex
|
||||||
*/
|
*/
|
||||||
function addFavoredMoveToNewPokemonMoveset(scene: BattleScene, newPokemon: PlayerPokemon, newPokemonGeneratedMoveset: (PokemonMove | null)[], newEggMoveIndex: number | null) {
|
function addFavoredMoveToNewPokemonMoveset(newPokemon: PlayerPokemon, newPokemonGeneratedMoveset: (PokemonMove | null)[], newEggMoveIndex: number | null) {
|
||||||
let favoredMove: PokemonMove | null = null;
|
let favoredMove: PokemonMove | null = null;
|
||||||
for (const move of newPokemonGeneratedMoveset) {
|
for (const move of newPokemonGeneratedMoveset) {
|
||||||
// Needs to match first type, second type will be replaced
|
// Needs to match first type, second type will be replaced
|
||||||
|
@ -614,11 +612,15 @@ function addFavoredMoveToNewPokemonMoveset(scene: BattleScene, newPokemon: Playe
|
||||||
}
|
}
|
||||||
// Finally, assign favored move to random index that isn't the new egg move index
|
// Finally, assign favored move to random index that isn't the new egg move index
|
||||||
if (favoredMove) {
|
if (favoredMove) {
|
||||||
let favoredMoveIndex = randSeedInt(4);
|
if (newPokemon.moveset.length < 4) {
|
||||||
while (newEggMoveIndex !== null && favoredMoveIndex === newEggMoveIndex) {
|
newPokemon.moveset.push(favoredMove);
|
||||||
favoredMoveIndex = randSeedInt(4);
|
} else {
|
||||||
}
|
let favoredMoveIndex = randSeedInt(4);
|
||||||
|
while (newEggMoveIndex !== null && favoredMoveIndex === newEggMoveIndex) {
|
||||||
|
favoredMoveIndex = randSeedInt(4);
|
||||||
|
}
|
||||||
|
|
||||||
newPokemon.moveset[favoredMoveIndex] = favoredMove;
|
newPokemon.moveset[favoredMoveIndex] = favoredMove;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -832,7 +832,7 @@ export function transitionMysteryEncounterIntroVisuals(scene: BattleScene, hide:
|
||||||
*/
|
*/
|
||||||
export function handleMysteryEncounterBattleStartEffects(scene: BattleScene) {
|
export function handleMysteryEncounterBattleStartEffects(scene: BattleScene) {
|
||||||
const encounter = scene.currentBattle.mysteryEncounter;
|
const encounter = scene.currentBattle.mysteryEncounter;
|
||||||
if (scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && encounter && encounter.encounterMode !== MysteryEncounterMode.NO_BATTLE && !encounter.startOfBattleEffectsComplete) {
|
if (scene.currentBattle.isBattleMysteryEncounter() && encounter && encounter.encounterMode !== MysteryEncounterMode.NO_BATTLE && !encounter.startOfBattleEffectsComplete) {
|
||||||
const effects = encounter.startOfBattleEffects;
|
const effects = encounter.startOfBattleEffects;
|
||||||
effects.forEach(effect => {
|
effects.forEach(effect => {
|
||||||
let source;
|
let source;
|
||||||
|
@ -871,7 +871,7 @@ export function handleMysteryEncounterBattleStartEffects(scene: BattleScene) {
|
||||||
*/
|
*/
|
||||||
export function handleMysteryEncounterTurnStartEffects(scene: BattleScene): boolean {
|
export function handleMysteryEncounterTurnStartEffects(scene: BattleScene): boolean {
|
||||||
const encounter = scene.currentBattle.mysteryEncounter;
|
const encounter = scene.currentBattle.mysteryEncounter;
|
||||||
if (scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && encounter && encounter.onTurnStart) {
|
if (scene.currentBattle.isBattleMysteryEncounter() && encounter && encounter.onTurnStart) {
|
||||||
return encounter.onTurnStart(scene);
|
return encounter.onTurnStart(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -210,10 +210,10 @@ export function getRandomSpeciesByStarterTier(starterTiers: number | [number, nu
|
||||||
.map(s => [parseInt(s) as Species, speciesStarters[s] as number])
|
.map(s => [parseInt(s) as Species, speciesStarters[s] as number])
|
||||||
.filter(s => {
|
.filter(s => {
|
||||||
const pokemonSpecies = getPokemonSpecies(s[0]);
|
const pokemonSpecies = getPokemonSpecies(s[0]);
|
||||||
return pokemonSpecies && (!excludedSpecies || !excludedSpecies.includes(s[0])
|
return pokemonSpecies && (!excludedSpecies || !excludedSpecies.includes(s[0]))
|
||||||
&& (allowSubLegendary || !pokemonSpecies.subLegendary)
|
&& (allowSubLegendary || !pokemonSpecies.subLegendary)
|
||||||
&& (allowLegendary || !pokemonSpecies.legendary)
|
&& (allowLegendary || !pokemonSpecies.legendary)
|
||||||
&& (allowMythical || !pokemonSpecies.mythical));
|
&& (allowMythical || !pokemonSpecies.mythical);
|
||||||
})
|
})
|
||||||
.map(s => [getPokemonSpecies(s[0]), s[1]]);
|
.map(s => [getPokemonSpecies(s[0]), s[1]]);
|
||||||
|
|
||||||
|
@ -757,9 +757,10 @@ const GOLDEN_BUG_NET_SPECIES_POOL: [Species, number][] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will randomly return one of the species from GOLDEN_BUG_NET_SPECIES_POOL, based on their weights
|
* Will randomly return one of the species from GOLDEN_BUG_NET_SPECIES_POOL, based on their weights.
|
||||||
|
* Will also check for and evolve pokemon based on level.
|
||||||
*/
|
*/
|
||||||
export function getGoldenBugNetSpecies(): PokemonSpecies {
|
export function getGoldenBugNetSpecies(level: number): PokemonSpecies {
|
||||||
const totalWeight = GOLDEN_BUG_NET_SPECIES_POOL.reduce((a, b) => a + b[1], 0);
|
const totalWeight = GOLDEN_BUG_NET_SPECIES_POOL.reduce((a, b) => a + b[1], 0);
|
||||||
const roll = randSeedInt(totalWeight);
|
const roll = randSeedInt(totalWeight);
|
||||||
|
|
||||||
|
@ -767,7 +768,8 @@ export function getGoldenBugNetSpecies(): PokemonSpecies {
|
||||||
for (const speciesWeightPair of GOLDEN_BUG_NET_SPECIES_POOL) {
|
for (const speciesWeightPair of GOLDEN_BUG_NET_SPECIES_POOL) {
|
||||||
w += speciesWeightPair[1];
|
w += speciesWeightPair[1];
|
||||||
if (roll < w) {
|
if (roll < w) {
|
||||||
return getPokemonSpecies(speciesWeightPair[0]);
|
const initialSpecies = getPokemonSpecies(speciesWeightPair[0]);
|
||||||
|
return getPokemonSpecies(initialSpecies.getSpeciesForLevel(level, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1801,7 +1801,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
* @returns list of egg moves
|
* @returns list of egg moves
|
||||||
*/
|
*/
|
||||||
getEggMoves() : Moves[] | undefined {
|
getEggMoves() : Moves[] | undefined {
|
||||||
return speciesEggMoves[this.getSpeciesForm().getRootSpeciesId(true)];
|
return speciesEggMoves[this.getSpeciesForm().getRootSpeciesId()];
|
||||||
}
|
}
|
||||||
|
|
||||||
setMove(moveIndex: integer, moveId: Moves): void {
|
setMove(moveIndex: integer, moveId: Moves): void {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"intro": "It's a safari zone!",
|
"intro": "It's a safari zone!",
|
||||||
"title": "The 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 @[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!",
|
"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?",
|
"query": "Would you like to enter?",
|
||||||
"option": {
|
"option": {
|
||||||
"1": {
|
"1": {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import * as ModifierTypes from "./modifier-type";
|
import * as ModifierTypes from "./modifier-type";
|
||||||
|
import { ModifierType, modifierTypes } from "./modifier-type";
|
||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../battle-scene";
|
||||||
import { getLevelTotalExp } from "../data/exp";
|
import { getLevelTotalExp } from "../data/exp";
|
||||||
import { MAX_PER_TYPE_POKEBALLS, PokeballType } from "../data/pokeball";
|
import { MAX_PER_TYPE_POKEBALLS, PokeballType } from "../data/pokeball";
|
||||||
|
@ -12,16 +13,15 @@ import * as Utils from "../utils";
|
||||||
import { getBerryEffectFunc, getBerryPredicate } from "../data/berry";
|
import { getBerryEffectFunc, getBerryPredicate } from "../data/berry";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { BerryType } from "#enums/berry-type";
|
import { BerryType } from "#enums/berry-type";
|
||||||
import { StatusEffect, getStatusEffectHealText } from "../data/status-effect";
|
import { getStatusEffectHealText, StatusEffect } from "#app/data/status-effect";
|
||||||
import { achvs } from "../system/achv";
|
import { achvs } from "../system/achv";
|
||||||
import { VoucherType } from "../system/voucher";
|
import { VoucherType } from "../system/voucher";
|
||||||
import { FormChangeItem, SpeciesFormChangeItemTrigger, SpeciesFormChangeLapseTeraTrigger, SpeciesFormChangeTeraTrigger } from "../data/pokemon-forms";
|
import { FormChangeItem, SpeciesFormChangeItemTrigger, SpeciesFormChangeLapseTeraTrigger, SpeciesFormChangeTeraTrigger } from "../data/pokemon-forms";
|
||||||
import { Nature } from "#app/data/nature";
|
import { Nature } from "#app/data/nature";
|
||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import { ModifierType, modifierTypes } from "./modifier-type";
|
|
||||||
import { Command } from "#app/ui/command-ui-handler";
|
import { Command } from "#app/ui/command-ui-handler";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { Stat, type PermanentStat, type TempBattleStat, BATTLE_STATS, TEMP_BATTLE_STATS } from "#app/enums/stat";
|
import { BATTLE_STATS, type PermanentStat, Stat, TEMP_BATTLE_STATS, type TempBattleStat } from "#app/enums/stat";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
import { allMoves } from "#app/data/move";
|
import { allMoves } from "#app/data/move";
|
||||||
|
@ -882,7 +882,7 @@ export class PokemonBaseStatTotalModifier extends PokemonHeldItemModifier {
|
||||||
private statModifier: integer;
|
private statModifier: integer;
|
||||||
public isTransferable: boolean = false;
|
public isTransferable: boolean = false;
|
||||||
|
|
||||||
constructor(type: ModifierTypes.PokemonBaseStatTotalModifierType, pokemonId: integer, statModifier: integer, stackCount?: integer) {
|
constructor(type: ModifierTypes.PokemonBaseStatTotalModifierType, pokemonId: number, statModifier: number, stackCount?: integer) {
|
||||||
super(type, pokemonId, stackCount);
|
super(type, pokemonId, stackCount);
|
||||||
this.statModifier = statModifier;
|
this.statModifier = statModifier;
|
||||||
}
|
}
|
||||||
|
@ -927,11 +927,11 @@ export class PokemonBaseStatTotalModifier extends PokemonHeldItemModifier {
|
||||||
* Currently used by Old Gateau item
|
* Currently used by Old Gateau item
|
||||||
*/
|
*/
|
||||||
export class PokemonBaseStatFlatModifier extends PokemonHeldItemModifier {
|
export class PokemonBaseStatFlatModifier extends PokemonHeldItemModifier {
|
||||||
private statModifier: integer;
|
private statModifier: number;
|
||||||
private stats: Stat[];
|
private stats: Stat[];
|
||||||
public isTransferable: boolean = false;
|
public isTransferable: boolean = false;
|
||||||
|
|
||||||
constructor (type: ModifierType, pokemonId: integer, statModifier: integer, stats: Stat[], stackCount?: integer) {
|
constructor (type: ModifierType, pokemonId: number, statModifier: number, stats: Stat[], stackCount?: number) {
|
||||||
super(type, pokemonId, stackCount);
|
super(type, pokemonId, stackCount);
|
||||||
|
|
||||||
this.statModifier = statModifier;
|
this.statModifier = statModifier;
|
||||||
|
@ -947,7 +947,7 @@ export class PokemonBaseStatFlatModifier extends PokemonHeldItemModifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
override getArgs(): any[] {
|
override getArgs(): any[] {
|
||||||
return super.getArgs().concat(this.statModifier, this.stats);
|
return [ ...super.getArgs(), this.statModifier, this.stats ];
|
||||||
}
|
}
|
||||||
|
|
||||||
override shouldApply(args: any[]): boolean {
|
override shouldApply(args: any[]): boolean {
|
||||||
|
@ -989,8 +989,8 @@ export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier {
|
||||||
return modifier instanceof PokemonIncrementingStatModifier;
|
return modifier instanceof PokemonIncrementingStatModifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
clone(): PersistentModifier {
|
clone(): PokemonIncrementingStatModifier {
|
||||||
return new PokemonIncrementingStatModifier(this.type, this.pokemonId);
|
return new PokemonIncrementingStatModifier(this.type, this.pokemonId, this.stackCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
getArgs(): any[] {
|
getArgs(): any[] {
|
||||||
|
@ -1004,14 +1004,19 @@ export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier {
|
||||||
apply(args: any[]): boolean {
|
apply(args: any[]): boolean {
|
||||||
// Modifies the passed in stats[] array by +1 per stack for HP, +2 per stack for other stats
|
// Modifies the passed in stats[] array by +1 per stack for HP, +2 per stack for other stats
|
||||||
// If the Macho Brace is at max stacks (50), adds additional 5% to total HP and 10% to other stats
|
// If the Macho Brace is at max stacks (50), adds additional 5% to total HP and 10% to other stats
|
||||||
|
const targetToApply = args[0] as Pokemon;
|
||||||
|
|
||||||
args[1].forEach((v, i) => {
|
args[1].forEach((v, i) => {
|
||||||
const isHp = i === 0;
|
const isHp = i === 0;
|
||||||
let mult = 1;
|
// Doesn't modify HP if holder has Wonder Guard
|
||||||
if (this.stackCount === this.getMaxHeldItemCount()) {
|
if (!isHp || !targetToApply.hasAbility(Abilities.WONDER_GUARD)) {
|
||||||
mult = isHp ? 1.05 : 1.1;
|
let mult = 1;
|
||||||
|
if (this.stackCount === this.getMaxHeldItemCount()) {
|
||||||
|
mult = isHp ? 1.05 : 1.1;
|
||||||
|
}
|
||||||
|
const newVal = Math.floor((v + this.stackCount * (isHp ? 1 : 2)) * mult);
|
||||||
|
args[1][i] = Math.min(Math.max(newVal, 1), 999999);
|
||||||
}
|
}
|
||||||
const newVal = Math.floor((v + this.stackCount * (isHp ? 1 : 2)) * mult);
|
|
||||||
args[1][i] = Math.min(Math.max(newVal, 1), 999999);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -70,7 +70,7 @@ export class CommandPhase extends FieldPhase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && this.scene.currentBattle.mysteryEncounter?.skipToFightInput) {
|
if (this.scene.currentBattle.isBattleMysteryEncounter() && this.scene.currentBattle.mysteryEncounter?.skipToFightInput) {
|
||||||
this.scene.ui.clearText();
|
this.scene.ui.clearText();
|
||||||
this.scene.ui.setMode(Mode.FIGHT, this.fieldIndex);
|
this.scene.ui.setMode(Mode.FIGHT, this.fieldIndex);
|
||||||
} else {
|
} else {
|
||||||
|
@ -141,7 +141,7 @@ export class CommandPhase extends FieldPhase {
|
||||||
this.scene.ui.showText("", 0);
|
this.scene.ui.showText("", 0);
|
||||||
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
|
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
|
||||||
}, null, true);
|
}, null, true);
|
||||||
} else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && !this.scene.currentBattle.mysteryEncounter!.catchAllowed) {
|
} else if (this.scene.currentBattle.isBattleMysteryEncounter() && !this.scene.currentBattle.mysteryEncounter!.catchAllowed) {
|
||||||
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
|
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
|
||||||
this.scene.ui.setMode(Mode.MESSAGE);
|
this.scene.ui.setMode(Mode.MESSAGE);
|
||||||
this.scene.ui.showText(i18next.t("battle:noPokeballMysteryEncounter"), null, () => {
|
this.scene.ui.showText(i18next.t("battle:noPokeballMysteryEncounter"), null, () => {
|
||||||
|
|
|
@ -34,6 +34,7 @@ import { doTrainerExclamation } from "#app/data/mystery-encounters/utils/encount
|
||||||
import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases";
|
import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases";
|
||||||
import { getGoldenBugNetSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
import { getGoldenBugNetSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
|
import { Biome } from "#enums/biome";
|
||||||
|
|
||||||
export class EncounterPhase extends BattlePhase {
|
export class EncounterPhase extends BattlePhase {
|
||||||
private loaded: boolean;
|
private loaded: boolean;
|
||||||
|
@ -63,7 +64,7 @@ export class EncounterPhase extends BattlePhase {
|
||||||
const battle = this.scene.currentBattle;
|
const battle = this.scene.currentBattle;
|
||||||
|
|
||||||
// Generate and Init Mystery Encounter
|
// Generate and Init Mystery Encounter
|
||||||
if (battle.battleType === BattleType.MYSTERY_ENCOUNTER && !battle.mysteryEncounter) {
|
if (battle.isBattleMysteryEncounter() && !battle.mysteryEncounter) {
|
||||||
this.scene.executeWithSeedOffset(() => {
|
this.scene.executeWithSeedOffset(() => {
|
||||||
const currentSessionEncounterType = battle.mysteryEncounterType;
|
const currentSessionEncounterType = battle.mysteryEncounterType;
|
||||||
battle.mysteryEncounter = this.scene.getMysteryEncounter(currentSessionEncounterType);
|
battle.mysteryEncounter = this.scene.getMysteryEncounter(currentSessionEncounterType);
|
||||||
|
@ -79,7 +80,7 @@ export class EncounterPhase extends BattlePhase {
|
||||||
mysteryEncounter.onInit(this.scene);
|
mysteryEncounter.onInit(this.scene);
|
||||||
}
|
}
|
||||||
mysteryEncounter.populateDialogueTokensFromRequirements(this.scene);
|
mysteryEncounter.populateDialogueTokensFromRequirements(this.scene);
|
||||||
}, this.scene.currentBattle.waveIndex);
|
}, battle.waveIndex);
|
||||||
|
|
||||||
// Add any special encounter animations to load
|
// Add any special encounter animations to load
|
||||||
if (mysteryEncounter.encounterAnimations && mysteryEncounter.encounterAnimations.length > 0) {
|
if (mysteryEncounter.encounterAnimations && mysteryEncounter.encounterAnimations.length > 0) {
|
||||||
|
@ -94,7 +95,7 @@ export class EncounterPhase extends BattlePhase {
|
||||||
let totalBst = 0;
|
let totalBst = 0;
|
||||||
|
|
||||||
battle.enemyLevels?.every((level, e) => {
|
battle.enemyLevels?.every((level, e) => {
|
||||||
if (battle.battleType === BattleType.MYSTERY_ENCOUNTER) {
|
if (battle.isBattleMysteryEncounter()) {
|
||||||
// Skip enemy loading for MEs, those are loaded elsewhere
|
// Skip enemy loading for MEs, those are loaded elsewhere
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -103,9 +104,12 @@ export class EncounterPhase extends BattlePhase {
|
||||||
battle.enemyParty[e] = battle.trainer?.genPartyMember(e)!; // TODO:: is the bang correct here?
|
battle.enemyParty[e] = battle.trainer?.genPartyMember(e)!; // TODO:: is the bang correct here?
|
||||||
} else {
|
} else {
|
||||||
let enemySpecies = this.scene.randomSpecies(battle.waveIndex, level, true);
|
let enemySpecies = this.scene.randomSpecies(battle.waveIndex, level, true);
|
||||||
// If player has golden bug net, rolls 10% chance to replace with species from the golden bug net bug pool
|
// If player has golden bug net, rolls 10% chance to replace non-boss wave wild species from the golden bug net bug pool
|
||||||
if (this.scene.findModifier(m => m instanceof BoostBugSpawnModifier) && randSeedInt(10) === 0) {
|
if (this.scene.findModifier(m => m instanceof BoostBugSpawnModifier)
|
||||||
enemySpecies = getGoldenBugNetSpecies();
|
&& !this.scene.gameMode.isBoss(battle.waveIndex)
|
||||||
|
&& this.scene.arena.biomeType !== Biome.END
|
||||||
|
&& randSeedInt(10) === 0) {
|
||||||
|
enemySpecies = getGoldenBugNetSpecies(level);
|
||||||
}
|
}
|
||||||
battle.enemyParty[e] = this.scene.addEnemyPokemon(enemySpecies, level, TrainerSlot.NONE, !!this.scene.getEncounterBossSegments(battle.waveIndex, level, enemySpecies));
|
battle.enemyParty[e] = this.scene.addEnemyPokemon(enemySpecies, level, TrainerSlot.NONE, !!this.scene.getEncounterBossSegments(battle.waveIndex, level, enemySpecies));
|
||||||
if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
|
if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
|
||||||
|
@ -157,7 +161,7 @@ export class EncounterPhase extends BattlePhase {
|
||||||
|
|
||||||
if (battle.battleType === BattleType.TRAINER) {
|
if (battle.battleType === BattleType.TRAINER) {
|
||||||
loadEnemyAssets.push(battle.trainer?.loadAssets().then(() => battle.trainer?.initSprite())!); // TODO: is this bang correct?
|
loadEnemyAssets.push(battle.trainer?.loadAssets().then(() => battle.trainer?.initSprite())!); // TODO: is this bang correct?
|
||||||
} else if (battle.battleType === BattleType.MYSTERY_ENCOUNTER) {
|
} else if (battle.isBattleMysteryEncounter()) {
|
||||||
if (battle.mysteryEncounter?.introVisuals) {
|
if (battle.mysteryEncounter?.introVisuals) {
|
||||||
loadEnemyAssets.push(battle.mysteryEncounter.introVisuals.loadAssets().then(() => battle.mysteryEncounter!.introVisuals!.initSprite()));
|
loadEnemyAssets.push(battle.mysteryEncounter.introVisuals.loadAssets().then(() => battle.mysteryEncounter!.introVisuals!.initSprite()));
|
||||||
}
|
}
|
||||||
|
@ -189,7 +193,7 @@ export class EncounterPhase extends BattlePhase {
|
||||||
|
|
||||||
Promise.all(loadEnemyAssets).then(() => {
|
Promise.all(loadEnemyAssets).then(() => {
|
||||||
battle.enemyParty.every((enemyPokemon, e) => {
|
battle.enemyParty.every((enemyPokemon, e) => {
|
||||||
if (battle.battleType === BattleType.MYSTERY_ENCOUNTER) {
|
if (battle.isBattleMysteryEncounter()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (e < (battle.double ? 2 : 1)) {
|
if (e < (battle.double ? 2 : 1)) {
|
||||||
|
@ -363,7 +367,7 @@ export class EncounterPhase extends BattlePhase {
|
||||||
showDialogueAndSummon();
|
showDialogueAndSummon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && this.scene.currentBattle.mysteryEncounter) {
|
} else if (this.scene.currentBattle.isBattleMysteryEncounter() && this.scene.currentBattle.mysteryEncounter) {
|
||||||
const encounter = this.scene.currentBattle.mysteryEncounter;
|
const encounter = this.scene.currentBattle.mysteryEncounter;
|
||||||
const introVisuals = encounter.introVisuals;
|
const introVisuals = encounter.introVisuals;
|
||||||
introVisuals?.playAnim();
|
introVisuals?.playAnim();
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { StatusEffect } from "#app/enums/status-effect";
|
||||||
import { PokemonPhase } from "./pokemon-phase";
|
import { PokemonPhase } from "./pokemon-phase";
|
||||||
import { MysteryEncounterPostSummonTag } from "#app/data/battler-tags";
|
import { MysteryEncounterPostSummonTag } from "#app/data/battler-tags";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { BattleType } from "#app/battle";
|
|
||||||
|
|
||||||
export class PostSummonPhase extends PokemonPhase {
|
export class PostSummonPhase extends PokemonPhase {
|
||||||
constructor(scene: BattleScene, battlerIndex: BattlerIndex) {
|
constructor(scene: BattleScene, battlerIndex: BattlerIndex) {
|
||||||
|
@ -24,7 +23,7 @@ export class PostSummonPhase extends PokemonPhase {
|
||||||
this.scene.arena.applyTags(ArenaTrapTag, pokemon);
|
this.scene.arena.applyTags(ArenaTrapTag, pokemon);
|
||||||
|
|
||||||
// If this is mystery encounter and has post summon phase tag, apply post summon effects
|
// If this is mystery encounter and has post summon phase tag, apply post summon effects
|
||||||
if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && pokemon.findTags(t => t instanceof MysteryEncounterPostSummonTag).length > 0) {
|
if (this.scene.currentBattle.isBattleMysteryEncounter() && pokemon.findTags(t => t instanceof MysteryEncounterPostSummonTag).length > 0) {
|
||||||
pokemon.lapseTag(BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON);
|
pokemon.lapseTag(BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ export class SummonPhase extends PartyMemberPokemonPhase {
|
||||||
|
|
||||||
this.scene.pbTrayEnemy.hide();
|
this.scene.pbTrayEnemy.hide();
|
||||||
this.scene.ui.showText(message, null, () => this.summon());
|
this.scene.ui.showText(message, null, () => this.summon());
|
||||||
} else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER) {
|
} else if (this.scene.currentBattle.isBattleMysteryEncounter()) {
|
||||||
this.scene.pbTrayEnemy.hide();
|
this.scene.pbTrayEnemy.hide();
|
||||||
this.summonWild();
|
this.summonWild();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ export class VictoryPhase extends PokemonPhase {
|
||||||
const expValue = this.getPokemon().getExpValue();
|
const expValue = this.getPokemon().getExpValue();
|
||||||
this.scene.applyPartyExp(expValue, true);
|
this.scene.applyPartyExp(expValue, true);
|
||||||
|
|
||||||
if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER) {
|
if (this.scene.currentBattle.isBattleMysteryEncounter()) {
|
||||||
handleMysteryEncounterVictory(this.scene, false, this.isExpOnly);
|
handleMysteryEncounterVictory(this.scene, false, this.isExpOnly);
|
||||||
return this.end();
|
return this.end();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import BattleScene, { PokeballCounts, bypassLogin } from "../battle-scene";
|
import BattleScene, { bypassLogin, PokeballCounts } from "../battle-scene";
|
||||||
import Pokemon, { EnemyPokemon, PlayerPokemon } from "../field/pokemon";
|
import Pokemon, { EnemyPokemon, PlayerPokemon } from "../field/pokemon";
|
||||||
import { pokemonPrevolutions } from "../data/pokemon-evolutions";
|
import { pokemonPrevolutions } from "../data/pokemon-evolutions";
|
||||||
import PokemonSpecies, { allSpecies, getPokemonSpecies, noStarterFormKeys, speciesStarters } from "../data/pokemon-species";
|
import PokemonSpecies, { allSpecies, getPokemonSpecies, noStarterFormKeys, speciesStarters } from "../data/pokemon-species";
|
||||||
|
@ -13,11 +13,11 @@ import { GameModes, getGameMode } from "../game-mode";
|
||||||
import { BattleType } from "../battle";
|
import { BattleType } from "../battle";
|
||||||
import TrainerData from "./trainer-data";
|
import TrainerData from "./trainer-data";
|
||||||
import { trainerConfigs } from "../data/trainer-config";
|
import { trainerConfigs } from "../data/trainer-config";
|
||||||
import { SettingKeys, resetSettings, setSetting } from "./settings/settings";
|
import { resetSettings, setSetting, SettingKeys } from "./settings/settings";
|
||||||
import { achvs } from "./achv";
|
import { achvs } from "./achv";
|
||||||
import EggData from "./egg-data";
|
import EggData from "./egg-data";
|
||||||
import { Egg } from "../data/egg";
|
import { Egg } from "../data/egg";
|
||||||
import { VoucherType, vouchers } from "./voucher";
|
import { vouchers, VoucherType } from "./voucher";
|
||||||
import { AES, enc } from "crypto-js";
|
import { AES, enc } from "crypto-js";
|
||||||
import { Mode } from "../ui/ui";
|
import { Mode } from "../ui/ui";
|
||||||
import { clientSessionId, loggedInUser, updateUserInfo } from "../account";
|
import { clientSessionId, loggedInUser, updateUserInfo } from "../account";
|
||||||
|
@ -28,8 +28,8 @@ import { speciesEggMoves } from "../data/egg-moves";
|
||||||
import { allMoves } from "../data/move";
|
import { allMoves } from "../data/move";
|
||||||
import { TrainerVariant } from "../field/trainer";
|
import { TrainerVariant } from "../field/trainer";
|
||||||
import { Variant } from "#app/data/variant";
|
import { Variant } from "#app/data/variant";
|
||||||
import {setSettingGamepad, SettingGamepad, settingGamepadDefaults} from "./settings/settings-gamepad";
|
import { setSettingGamepad, SettingGamepad, settingGamepadDefaults } from "./settings/settings-gamepad";
|
||||||
import {setSettingKeyboard, SettingKeyboard} from "#app/system/settings/settings-keyboard";
|
import { setSettingKeyboard, SettingKeyboard } from "#app/system/settings/settings-keyboard";
|
||||||
import { TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena";
|
import { TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena";
|
||||||
import * as Modifier from "../modifier/modifier";
|
import * as Modifier from "../modifier/modifier";
|
||||||
import { StatusEffect } from "#app/data/status-effect";
|
import { StatusEffect } from "#app/data/status-effect";
|
||||||
|
@ -1583,12 +1583,20 @@ export class GameData {
|
||||||
* @returns `true` if Pokemon catch unlocked a new starter, `false` if Pokemon catch did not unlock a starter
|
* @returns `true` if Pokemon catch unlocked a new starter, `false` if Pokemon catch did not unlock a starter
|
||||||
*/
|
*/
|
||||||
setPokemonCaught(pokemon: Pokemon, incrementCount: boolean = true, fromEgg: boolean = false, showMessage: boolean = true): Promise<boolean> {
|
setPokemonCaught(pokemon: Pokemon, incrementCount: boolean = true, fromEgg: boolean = false, showMessage: boolean = true): Promise<boolean> {
|
||||||
return this.setPokemonSpeciesCaught(pokemon, pokemon.species, incrementCount, fromEgg, showMessage);
|
// If incrementCount === false (not a catch scenario), only update the pokemon's dex data if the Pokemon has already been marked as caught in dex
|
||||||
|
// Prevents form changes, nature changes, etc. from unintentionally updating the dex data of a "rental" pokemon
|
||||||
|
const speciesRootForm = pokemon.species.getRootSpeciesId();
|
||||||
|
if (!incrementCount && !this.scene.gameData.dexData[speciesRootForm].caughtAttr) {
|
||||||
|
return Promise.resolve(false);
|
||||||
|
} else {
|
||||||
|
return this.setPokemonSpeciesCaught(pokemon, pokemon.species, incrementCount, fromEgg, showMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param pokemon
|
* @param pokemon
|
||||||
|
* @param species
|
||||||
* @param incrementCount
|
* @param incrementCount
|
||||||
* @param fromEgg
|
* @param fromEgg
|
||||||
* @param showMessage
|
* @param showMessage
|
||||||
|
@ -1604,12 +1612,18 @@ export class GameData {
|
||||||
}
|
}
|
||||||
const dexAttr = pokemon.getDexAttr();
|
const dexAttr = pokemon.getDexAttr();
|
||||||
pokemon.formIndex = formIndex;
|
pokemon.formIndex = formIndex;
|
||||||
|
|
||||||
|
// Mark as caught
|
||||||
dexEntry.caughtAttr |= dexAttr;
|
dexEntry.caughtAttr |= dexAttr;
|
||||||
|
|
||||||
|
// Unlock ability
|
||||||
if (speciesStarters.hasOwnProperty(species.speciesId)) {
|
if (speciesStarters.hasOwnProperty(species.speciesId)) {
|
||||||
this.starterData[species.speciesId].abilityAttr |= pokemon.abilityIndex !== 1 || pokemon.species.ability2
|
this.starterData[species.speciesId].abilityAttr |= pokemon.abilityIndex !== 1 || pokemon.species.ability2
|
||||||
? 1 << pokemon.abilityIndex
|
? 1 << pokemon.abilityIndex
|
||||||
: AbilityAttr.ABILITY_HIDDEN;
|
: AbilityAttr.ABILITY_HIDDEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unlock nature
|
||||||
dexEntry.natureAttr |= 1 << (pokemon.nature + 1);
|
dexEntry.natureAttr |= 1 << (pokemon.nature + 1);
|
||||||
|
|
||||||
const hasPrevolution = pokemonPrevolutions.hasOwnProperty(species.speciesId);
|
const hasPrevolution = pokemonPrevolutions.hasOwnProperty(species.speciesId);
|
||||||
|
@ -1704,9 +1718,19 @@ export class GameData {
|
||||||
return ++this.starterData[speciesIdToIncrement].classicWinCount;
|
return ++this.starterData[speciesIdToIncrement].classicWinCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a candy to the player's game data for a given {@linkcode PokemonSpecies}.
|
||||||
|
* Will do nothing if the player does not have the Pokemon owned in their system save data.
|
||||||
|
* @param species
|
||||||
|
* @param count
|
||||||
|
*/
|
||||||
addStarterCandy(species: PokemonSpecies, count: integer): void {
|
addStarterCandy(species: PokemonSpecies, count: integer): void {
|
||||||
this.scene.candyBar.showStarterSpeciesCandy(species.speciesId, count);
|
// Only gain candies if the Pokemon has already been marked as caught in dex (ignore "rental" pokemon)
|
||||||
this.starterData[species.speciesId].candyCount += count;
|
const speciesRootForm = species.getRootSpeciesId();
|
||||||
|
if (this.scene.gameData.dexData[speciesRootForm].caughtAttr) {
|
||||||
|
this.scene.candyBar.showStarterSpeciesCandy(species.speciesId, count);
|
||||||
|
this.starterData[species.speciesId].candyCount += count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue