stash PR feedback and bugfixes
This commit is contained in:
parent
08e023e220
commit
c9d6995f58
|
@ -486,7 +486,7 @@ function doBerrySpritePile(scene: BattleScene, isEat: boolean = false) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function doBerryBounce(scene: BattleScene, berrySprites: Phaser.GameObjects.Sprite[], yd: number, baseBounceDuration: integer) {
|
function doBerryBounce(scene: BattleScene, berrySprites: Phaser.GameObjects.Sprite[], yd: number, baseBounceDuration: number) {
|
||||||
let bouncePower = 1;
|
let bouncePower = 1;
|
||||||
let bounceYOffset = yd;
|
let bounceYOffset = yd;
|
||||||
|
|
||||||
|
|
|
@ -582,7 +582,7 @@ function getTrainerConfigForWave(waveIndex: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRandomPartyMemberFunc(speciesPool: Species[], trainerSlot: TrainerSlot = TrainerSlot.TRAINER, ignoreEvolution: boolean = false, postProcess?: (enemyPokemon: EnemyPokemon) => void) {
|
function getRandomPartyMemberFunc(speciesPool: Species[], trainerSlot: TrainerSlot = TrainerSlot.TRAINER, ignoreEvolution: boolean = false, postProcess?: (enemyPokemon: EnemyPokemon) => void) {
|
||||||
return (scene: BattleScene, level: integer, strength: PartyMemberStrength) => {
|
return (scene: BattleScene, level: number, strength: PartyMemberStrength) => {
|
||||||
let species = Utils.randSeedItem(speciesPool);
|
let species = Utils.randSeedItem(speciesPool);
|
||||||
if (!ignoreEvolution) {
|
if (!ignoreEvolution) {
|
||||||
species = getPokemonSpecies(species).getTrainerSpeciesForLevel(level, true, strength);
|
species = getPokemonSpecies(species).getTrainerSpeciesForLevel(level, true, strength);
|
||||||
|
|
|
@ -382,7 +382,7 @@ async function handleSwapAbility(scene: BattleScene) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function displayYesNoOptions(scene: BattleScene, resolve) {
|
function displayYesNoOptions(scene: BattleScene, resolve) {
|
||||||
showEncounterText(scene, `${namespace}.option.1.ability_prompt`, 500, false);
|
showEncounterText(scene, `${namespace}.option.1.ability_prompt`, null, 500, false);
|
||||||
const fullOptions = [
|
const fullOptions = [
|
||||||
{
|
{
|
||||||
label: i18next.t("menu:yes"),
|
label: i18next.t("menu:yes"),
|
||||||
|
@ -429,7 +429,7 @@ function onYesAbilitySwap(scene: BattleScene, resolve) {
|
||||||
selectPokemonForOption(scene, onPokemonSelected, onPokemonNotSelected);
|
selectPokemonForOption(scene, onPokemonSelected, onPokemonNotSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateItemsOfTier(scene: BattleScene, pokemon: PlayerPokemon, numItems: integer, tier: ModifierTier | "Berries") {
|
function generateItemsOfTier(scene: BattleScene, pokemon: PlayerPokemon, numItems: number, tier: ModifierTier | "Berries") {
|
||||||
// These pools have to be defined at runtime so that modifierTypes exist
|
// These pools have to be defined at runtime so that modifierTypes exist
|
||||||
// Pools have instances of the modifier type equal to the max stacks that modifier can be applied to any one pokemon
|
// Pools have instances of the modifier type equal to the max stacks that modifier can be applied to any one pokemon
|
||||||
// This is to prevent "over-generating" a random item of a certain type during item swaps
|
// This is to prevent "over-generating" a random item of a certain type during item swaps
|
||||||
|
|
|
@ -122,7 +122,7 @@ export const DelibirdyEncounter: MysteryEncounter =
|
||||||
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||||
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
|
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
|
||||||
scene.playSound("item_fanfare");
|
scene.playSound("item_fanfare");
|
||||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), undefined, true);
|
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true);
|
||||||
} else {
|
} else {
|
||||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.ABILITY_CHARM));
|
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.ABILITY_CHARM));
|
||||||
}
|
}
|
||||||
|
@ -197,7 +197,7 @@ export const DelibirdyEncounter: MysteryEncounter =
|
||||||
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||||
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
|
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
|
||||||
scene.playSound("item_fanfare");
|
scene.playSound("item_fanfare");
|
||||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), undefined, true);
|
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true);
|
||||||
} else {
|
} else {
|
||||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.CANDY_JAR));
|
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.CANDY_JAR));
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ export const DelibirdyEncounter: MysteryEncounter =
|
||||||
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||||
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
|
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
|
||||||
scene.playSound("item_fanfare");
|
scene.playSound("item_fanfare");
|
||||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), undefined, true);
|
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true);
|
||||||
} else {
|
} else {
|
||||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.HEALING_CHARM));
|
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.HEALING_CHARM));
|
||||||
}
|
}
|
||||||
|
@ -290,7 +290,7 @@ export const DelibirdyEncounter: MysteryEncounter =
|
||||||
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
const shellBell = generateModifierType(scene, modifierTypes.SHELL_BELL) as PokemonHeldItemModifierType;
|
||||||
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
|
await applyModifierTypeToPlayerPokemon(scene, scene.getParty()[0], shellBell);
|
||||||
scene.playSound("item_fanfare");
|
scene.playSound("item_fanfare");
|
||||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), undefined, true);
|
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: shellBell.name }), null, undefined, true);
|
||||||
} else {
|
} else {
|
||||||
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.BERRY_POUCH));
|
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.BERRY_POUCH));
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,7 +157,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
||||||
const formName = tradePokemon.species.forms?.[pokemon.formIndex]?.formName;
|
const formName = tradePokemon.species.forms?.[pokemon.formIndex]?.formName;
|
||||||
const line1 = i18next.t("pokemonInfoContainer:ability") + " " + tradePokemon.getAbility().name + (tradePokemon.getGender() !== Gender.GENDERLESS ? " | " + i18next.t("pokemonInfoContainer:gender") + " " + getGenderSymbol(tradePokemon.getGender()) : "");
|
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 : "");
|
const line2 = i18next.t("pokemonInfoContainer:nature") + " " + getNatureName(tradePokemon.getNature()) + (formName ? " | " + i18next.t("pokemonInfoContainer:form") + " " + formName : "");
|
||||||
scene.ui.showText(`${line1}\n${line2}`, 0);
|
showEncounterText(scene, `${line1}\n${line2}`, 0);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return option;
|
return option;
|
||||||
|
@ -195,7 +195,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
||||||
// Show the trade animation
|
// Show the trade animation
|
||||||
await showTradeBackground(scene);
|
await showTradeBackground(scene);
|
||||||
await doPokemonTradeSequence(scene, tradedPokemon, newPlayerPokemon);
|
await doPokemonTradeSequence(scene, tradedPokemon, newPlayerPokemon);
|
||||||
await showEncounterText(scene, `${namespace}.trade_received`, 0, true, 4000);
|
await showEncounterText(scene, `${namespace}.trade_received`, null, 0, true, 4000);
|
||||||
scene.playBgm("mystery_encounter_gts");
|
scene.playBgm("mystery_encounter_gts");
|
||||||
await hideTradeBackground(scene);
|
await hideTradeBackground(scene);
|
||||||
tradedPokemon.destroy();
|
tradedPokemon.destroy();
|
||||||
|
@ -278,7 +278,7 @@ export const GlobalTradeSystemEncounter: MysteryEncounter =
|
||||||
// Show the trade animation
|
// Show the trade animation
|
||||||
await showTradeBackground(scene);
|
await showTradeBackground(scene);
|
||||||
await doPokemonTradeSequence(scene, tradedPokemon, newPlayerPokemon);
|
await doPokemonTradeSequence(scene, tradedPokemon, newPlayerPokemon);
|
||||||
await showEncounterText(scene, `${namespace}.trade_received`, 0, true, 4000);
|
await showEncounterText(scene, `${namespace}.trade_received`, null, 0, true, 4000);
|
||||||
scene.playBgm("mystery_encounter_gts");
|
scene.playBgm("mystery_encounter_gts");
|
||||||
await hideTradeBackground(scene);
|
await hideTradeBackground(scene);
|
||||||
tradedPokemon.destroy();
|
tradedPokemon.destroy();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { getPokemonSpecies } from "#app/data/pokemon-species.js";
|
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||||
import { Moves } from "#app/enums/moves";
|
import { Moves } from "#app/enums/moves";
|
||||||
import { Species } from "#app/enums/species.js";
|
import { Species } from "#app/enums/species";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import BattleScene from "#app/battle-scene";
|
import BattleScene from "#app/battle-scene";
|
||||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-enco
|
||||||
import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import { getHighestLevelPlayerPokemon, koPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
import { getHighestLevelPlayerPokemon, koPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||||
import { randSeedInt } from "#app/utils.js";
|
import { randSeedInt } from "#app/utils";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import BattleScene from "#app/battle-scene";
|
import BattleScene from "#app/battle-scene";
|
||||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||||
|
|
|
@ -175,9 +175,9 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
|
||||||
// 80% chance to increase flee stage +1
|
// 80% chance to increase flee stage +1
|
||||||
const fleeChangeResult = tryChangeFleeStage(scene, 1, 8);
|
const fleeChangeResult = tryChangeFleeStage(scene, 1, 8);
|
||||||
if (!fleeChangeResult) {
|
if (!fleeChangeResult) {
|
||||||
await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.busy_eating`) ?? "", 1000, false );
|
await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.busy_eating`) ?? "", null, 1000, false );
|
||||||
} else {
|
} else {
|
||||||
await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.eating`) ?? "", 1000, false);
|
await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.eating`) ?? "", null, 1000, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
await doEndTurn(scene, 1);
|
await doEndTurn(scene, 1);
|
||||||
|
@ -204,9 +204,9 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
|
||||||
// 80% chance to decrease catch stage -1
|
// 80% chance to decrease catch stage -1
|
||||||
const catchChangeResult = tryChangeCatchStage(scene, -1, 8);
|
const catchChangeResult = tryChangeCatchStage(scene, -1, 8);
|
||||||
if (!catchChangeResult) {
|
if (!catchChangeResult) {
|
||||||
await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.beside_itself_angry`) ?? "", 1000, false );
|
await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.beside_itself_angry`) ?? "", null, 1000, false );
|
||||||
} else {
|
} else {
|
||||||
await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.angry`) ?? "", 1000, false );
|
await showEncounterText(scene, getEncounterText(scene, `${namespace}.safari.angry`) ?? "", null, 1000, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
await doEndTurn(scene, 2);
|
await doEndTurn(scene, 2);
|
||||||
|
@ -291,7 +291,7 @@ async function summonSafariPokemon(scene: BattleScene) {
|
||||||
scene.unshiftPhase(new SummonPhase(scene, 0, false));
|
scene.unshiftPhase(new SummonPhase(scene, 0, false));
|
||||||
|
|
||||||
encounter.setDialogueToken("pokemonName", getPokemonNameWithAffix(pokemon));
|
encounter.setDialogueToken("pokemonName", getPokemonNameWithAffix(pokemon));
|
||||||
showEncounterText(scene, getEncounterText(scene, "battle:singleWildAppeared") ?? "", 1500, false)
|
showEncounterText(scene, getEncounterText(scene, "battle:singleWildAppeared") ?? "", null, 1500, false)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const ivScannerModifier = scene.findModifier(m => m instanceof IvScannerModifier);
|
const ivScannerModifier = scene.findModifier(m => m instanceof IvScannerModifier);
|
||||||
if (ivScannerModifier) {
|
if (ivScannerModifier) {
|
||||||
|
|
|
@ -156,7 +156,7 @@ export const TheStrongStuffEncounter: MysteryEncounter =
|
||||||
|
|
||||||
encounter.setDialogueToken("reductionValue", HIGH_BST_REDUCTION_VALUE.toString());
|
encounter.setDialogueToken("reductionValue", HIGH_BST_REDUCTION_VALUE.toString());
|
||||||
encounter.setDialogueToken("increaseValue", BST_INCREASE_VALUE.toString());
|
encounter.setDialogueToken("increaseValue", BST_INCREASE_VALUE.toString());
|
||||||
await showEncounterText(scene, `${namespace}.option.1.selected_2`, undefined, true);
|
await showEncounterText(scene, `${namespace}.option.1.selected_2`, null, undefined, true);
|
||||||
|
|
||||||
setEncounterRewards(scene, { fillRemaining: true });
|
setEncounterRewards(scene, { fillRemaining: true });
|
||||||
leaveEncounterWithoutBattle(scene, true);
|
leaveEncounterWithoutBattle(scene, true);
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import BattleScene from "#app/battle-scene";
|
import BattleScene from "#app/battle-scene";
|
||||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||||
import { getEncounterText, queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
import { getEncounterText, queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import HeldModifierConfig from "#app/interfaces/held-modifier-config";
|
import HeldModifierConfig from "#app/interfaces/held-modifier-config";
|
||||||
|
@ -286,27 +286,33 @@ export const TrainingSessionEncounter: MysteryEncounter =
|
||||||
? pokemon.getFusionSpeciesForm()
|
? pokemon.getFusionSpeciesForm()
|
||||||
: pokemon.getSpeciesForm();
|
: pokemon.getSpeciesForm();
|
||||||
const abilityCount = speciesForm.getAbilityCount();
|
const abilityCount = speciesForm.getAbilityCount();
|
||||||
const abilities = new Array(abilityCount)
|
const abilities: Ability[] = new Array(abilityCount)
|
||||||
.fill(null)
|
.fill(null)
|
||||||
.map((val, i) => allAbilities[speciesForm.getAbility(i)]);
|
.map((val, i) => allAbilities[speciesForm.getAbility(i)]);
|
||||||
return abilities.map((ability: Ability, index) => {
|
|
||||||
const option: OptionSelectItem = {
|
const optionSelectItems: OptionSelectItem[] = [];
|
||||||
label: ability.name,
|
abilities.forEach((ability: Ability, index) => {
|
||||||
handler: () => {
|
if (!optionSelectItems.some(o => o.label === ability.name)) {
|
||||||
// Pokemon and ability selected
|
const option: OptionSelectItem = {
|
||||||
encounter.setDialogueToken("ability", ability.name);
|
label: ability.name,
|
||||||
encounter.misc = {
|
handler: () => {
|
||||||
playerPokemon: pokemon,
|
// Pokemon and ability selected
|
||||||
abilityIndex: index,
|
encounter.setDialogueToken("ability", ability.name);
|
||||||
};
|
encounter.misc = {
|
||||||
return true;
|
playerPokemon: pokemon,
|
||||||
},
|
abilityIndex: index,
|
||||||
onHover: () => {
|
};
|
||||||
scene.ui.showText(ability.description);
|
return true;
|
||||||
},
|
},
|
||||||
};
|
onHover: () => {
|
||||||
return option;
|
showEncounterText(scene, ability.description, 0);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
optionSelectItems.push(option);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return optionSelectItems;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only Pokemon that are not KOed/legal can be trained
|
// Only Pokemon that are not KOed/legal can be trained
|
||||||
|
|
|
@ -179,7 +179,7 @@ async function tryApplyDigRewardItems(scene: BattleScene) {
|
||||||
}
|
}
|
||||||
|
|
||||||
scene.playSound("item_fanfare");
|
scene.playSound("item_fanfare");
|
||||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: "2 " + leftovers.name }), undefined, true);
|
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: "2 " + leftovers.name }), null, undefined, true);
|
||||||
|
|
||||||
// First Shell bell
|
// First Shell bell
|
||||||
for (const pokemon of party) {
|
for (const pokemon of party) {
|
||||||
|
@ -206,7 +206,7 @@ async function tryApplyDigRewardItems(scene: BattleScene) {
|
||||||
}
|
}
|
||||||
|
|
||||||
scene.playSound("item_fanfare");
|
scene.playSound("item_fanfare");
|
||||||
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: "2 " + shellBell.name }), undefined, true);
|
await showEncounterText(scene, i18next.t("battle:rewardGain", { modifierName: "2 " + shellBell.name }), null, undefined, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doGarbageDig(scene: BattleScene) {
|
async function doGarbageDig(scene: BattleScene) {
|
||||||
|
|
|
@ -22,7 +22,17 @@ export interface EncounterRequirement {
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class EncounterSceneRequirement implements EncounterRequirement {
|
export abstract class EncounterSceneRequirement implements EncounterRequirement {
|
||||||
|
/**
|
||||||
|
* Returns whether the EncounterSceneRequirement's... requirements, are met by the given scene
|
||||||
|
* @param partyPokemon
|
||||||
|
*/
|
||||||
abstract meetsRequirement(scene: BattleScene): boolean;
|
abstract meetsRequirement(scene: BattleScene): boolean;
|
||||||
|
/**
|
||||||
|
* Returns a dialogue token key/value pair for a given Requirement.
|
||||||
|
* Should be overridden by child Requirement classes.
|
||||||
|
* @param scene
|
||||||
|
* @param pokemon
|
||||||
|
*/
|
||||||
abstract getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string];
|
abstract getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +44,7 @@ export class CombinationSceneRequirement extends EncounterSceneRequirement {
|
||||||
this.orRequirements = orRequirements;
|
this.orRequirements = orRequirements;
|
||||||
}
|
}
|
||||||
|
|
||||||
meetsRequirement(scene: BattleScene): boolean {
|
override meetsRequirement(scene: BattleScene): boolean {
|
||||||
for (const req of this.orRequirements) {
|
for (const req of this.orRequirements) {
|
||||||
if (req.meetsRequirement(scene)) {
|
if (req.meetsRequirement(scene)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -58,6 +68,10 @@ export abstract class EncounterPokemonRequirement implements EncounterRequiremen
|
||||||
public minNumberOfPokemon: number;
|
public minNumberOfPokemon: number;
|
||||||
public invertQuery: boolean;
|
public invertQuery: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the EncounterPokemonRequirement's... requirements, are met by the given scene
|
||||||
|
* @param partyPokemon
|
||||||
|
*/
|
||||||
abstract meetsRequirement(scene: BattleScene): boolean;
|
abstract meetsRequirement(scene: BattleScene): boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,6 +80,12 @@ export abstract class EncounterPokemonRequirement implements EncounterRequiremen
|
||||||
*/
|
*/
|
||||||
abstract queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[];
|
abstract queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a dialogue token key/value pair for a given Requirement.
|
||||||
|
* Should be overridden by child Requirement classes.
|
||||||
|
* @param scene
|
||||||
|
* @param pokemon
|
||||||
|
*/
|
||||||
abstract getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string];
|
abstract getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -281,11 +281,17 @@ export default class MysteryEncounter implements IMysteryEncounter {
|
||||||
return sceneReq && secReqs && priReqs;
|
return sceneReq && secReqs && priReqs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a specific player pokemon meets all given primary EncounterPokemonRequirements
|
||||||
|
* Used automatically as part of {@linkcode meetsRequirements}, but can also be used to manually check certain Pokemon where needed
|
||||||
|
* @param scene
|
||||||
|
* @param pokemon
|
||||||
|
*/
|
||||||
pokemonMeetsPrimaryRequirements(scene: BattleScene, pokemon: Pokemon) {
|
pokemonMeetsPrimaryRequirements(scene: BattleScene, pokemon: Pokemon) {
|
||||||
return !this.primaryPokemonRequirements.some(req => !req.queryParty(scene.getParty()).map(p => p.id).includes(pokemon.id));
|
return !this.primaryPokemonRequirements.some(req => !req.queryParty(scene.getParty()).map(p => p.id).includes(pokemon.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
meetsPrimaryRequirementAndPrimaryPokemonSelected(scene: BattleScene): boolean {
|
private meetsPrimaryRequirementAndPrimaryPokemonSelected(scene: BattleScene): boolean {
|
||||||
if (!this.primaryPokemonRequirements || this.primaryPokemonRequirements.length === 0) {
|
if (!this.primaryPokemonRequirements || this.primaryPokemonRequirements.length === 0) {
|
||||||
const activeMon = scene.getParty().filter(p => p.isActive(true));
|
const activeMon = scene.getParty().filter(p => p.isActive(true));
|
||||||
if (activeMon.length > 0) {
|
if (activeMon.length > 0) {
|
||||||
|
@ -342,7 +348,7 @@ export default class MysteryEncounter implements IMysteryEncounter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
meetsSecondaryRequirementAndSecondaryPokemonSelected(scene: BattleScene): boolean {
|
private meetsSecondaryRequirementAndSecondaryPokemonSelected(scene: BattleScene): boolean {
|
||||||
if (!this.secondaryPokemonRequirements || this.secondaryPokemonRequirements.length === 0) {
|
if (!this.secondaryPokemonRequirements || this.secondaryPokemonRequirements.length === 0) {
|
||||||
this.secondaryPokemon = [];
|
this.secondaryPokemon = [];
|
||||||
return true;
|
return true;
|
||||||
|
@ -446,6 +452,14 @@ export default class MysteryEncounter implements IMysteryEncounter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to cache a dialogue token for the encounter.
|
||||||
|
* Tokens will be auto-injected via the `{{key}}` pattern with `value`,
|
||||||
|
* when using the {@link showEncounterText} and {@link showEncounterDialogue} helper functions.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
setDialogueToken(key: string, value: string): void {
|
setDialogueToken(key: string, value: string): void {
|
||||||
this.dialogueTokens[key] = value;
|
this.dialogueTokens[key] = value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,14 @@ import { UiTheme } from "#enums/ui-theme";
|
||||||
import { isNullOrUndefined } from "#app/utils";
|
import { isNullOrUndefined } from "#app/utils";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will inject all relevant dialogue tokens that exist in the {@link BattleScene.currentBattle.mysteryEncounter.dialogueTokens}, into i18n text.
|
||||||
|
* Also adds BBCodeText fragments for colored text, if applicable
|
||||||
|
* @param scene
|
||||||
|
* @param keyOrString
|
||||||
|
* @param primaryStyle - can define a text style to be applied to the entire string. Must be defined for BBCodeText styles to be applied correctly
|
||||||
|
* @param uiTheme
|
||||||
|
*/
|
||||||
export function getEncounterText(scene: BattleScene, keyOrString?: string, primaryStyle?: TextStyle, uiTheme: UiTheme = UiTheme.DEFAULT): string | null {
|
export function getEncounterText(scene: BattleScene, keyOrString?: string, primaryStyle?: TextStyle, uiTheme: UiTheme = UiTheme.DEFAULT): string | null {
|
||||||
if (isNullOrUndefined(keyOrString)) {
|
if (isNullOrUndefined(keyOrString)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -20,6 +28,11 @@ export function getEncounterText(scene: BattleScene, keyOrString?: string, prima
|
||||||
return textString;
|
return textString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to inject {@link BattleScene.currentBattle.mysteryEncounter.dialogueTokens} into a given content string
|
||||||
|
* @param scene
|
||||||
|
* @param keyOrString
|
||||||
|
*/
|
||||||
function getTextWithDialogueTokens(scene: BattleScene, keyOrString?: string): string | null {
|
function getTextWithDialogueTokens(scene: BattleScene, keyOrString?: string): string | null {
|
||||||
if (isNullOrUndefined(keyOrString)) {
|
if (isNullOrUndefined(keyOrString)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -51,14 +64,15 @@ export function queueEncounterMessage(scene: BattleScene, contentKey: string): v
|
||||||
* Will display a message in UI with injected encounter data tokens
|
* Will display a message in UI with injected encounter data tokens
|
||||||
* @param scene
|
* @param scene
|
||||||
* @param contentKey
|
* @param contentKey
|
||||||
|
* @param delay
|
||||||
* @param prompt
|
* @param prompt
|
||||||
* @param callbackDelay
|
* @param callbackDelay
|
||||||
* @param promptDelay
|
* @param promptDelay
|
||||||
*/
|
*/
|
||||||
export function showEncounterText(scene: BattleScene, contentKey: string, callbackDelay: number = 0, prompt: boolean = true, promptDelay: number | null = null): Promise<void> {
|
export function showEncounterText(scene: BattleScene, contentKey: string, delay: number | null = null, callbackDelay: number = 0, prompt: boolean = true, promptDelay: number | null = null): Promise<void> {
|
||||||
return new Promise<void>(resolve => {
|
return new Promise<void>(resolve => {
|
||||||
const text: string | null = getEncounterText(scene, contentKey);
|
const text: string | null = getEncounterText(scene, contentKey);
|
||||||
scene.ui.showText(text ?? "", null, () => resolve(), callbackDelay, prompt, promptDelay);
|
scene.ui.showText(text ?? "", delay, () => resolve(), callbackDelay, prompt, promptDelay);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,13 +80,14 @@ export function showEncounterText(scene: BattleScene, contentKey: string, callba
|
||||||
* Will display a dialogue (with speaker title) in UI with injected encounter data tokens
|
* Will display a dialogue (with speaker title) in UI with injected encounter data tokens
|
||||||
* @param scene
|
* @param scene
|
||||||
* @param textContentKey
|
* @param textContentKey
|
||||||
|
* @param delay
|
||||||
* @param speakerContentKey
|
* @param speakerContentKey
|
||||||
* @param callbackDelay
|
* @param callbackDelay
|
||||||
*/
|
*/
|
||||||
export function showEncounterDialogue(scene: BattleScene, textContentKey: string, speakerContentKey: string, callbackDelay: number = 0): Promise<void> {
|
export function showEncounterDialogue(scene: BattleScene, textContentKey: string, speakerContentKey: string, delay: number | null = null, callbackDelay: number = 0): Promise<void> {
|
||||||
return new Promise<void>(resolve => {
|
return new Promise<void>(resolve => {
|
||||||
const text: string | null = getEncounterText(scene, textContentKey);
|
const text: string | null = getEncounterText(scene, textContentKey);
|
||||||
const speaker: string | null = getEncounterText(scene, speakerContentKey);
|
const speaker: string | null = getEncounterText(scene, speakerContentKey);
|
||||||
scene.ui.showDialogue(text ?? "", speaker ?? "", null, () => resolve(), callbackDelay);
|
scene.ui.showDialogue(text ?? "", speaker ?? "", delay, () => resolve(), callbackDelay);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ export interface EnemyPokemonConfig {
|
||||||
passive?: boolean;
|
passive?: boolean;
|
||||||
moveSet?: Moves[];
|
moveSet?: Moves[];
|
||||||
nature?: Nature;
|
nature?: Nature;
|
||||||
ivs?: [integer, integer, integer, integer, integer, integer];
|
ivs?: [number, number, number, number, number, number];
|
||||||
shiny?: boolean;
|
shiny?: boolean;
|
||||||
/** Can set just the status, or pass a timer on the status turns */
|
/** Can set just the status, or pass a timer on the status turns */
|
||||||
status?: StatusEffect | [StatusEffect, number];
|
status?: StatusEffect | [StatusEffect, number];
|
||||||
|
@ -422,7 +422,7 @@ export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (p
|
||||||
const modeToSetOnExit = scene.ui.getMode();
|
const modeToSetOnExit = scene.ui.getMode();
|
||||||
|
|
||||||
// Open party screen to choose pokemon
|
// Open party screen to choose pokemon
|
||||||
scene.ui.setMode(Mode.PARTY, PartyUiMode.SELECT, -1, (slotIndex: integer, option: PartyOption) => {
|
scene.ui.setMode(Mode.PARTY, PartyUiMode.SELECT, -1, (slotIndex: number, option: PartyOption) => {
|
||||||
if (slotIndex < scene.getParty().length) {
|
if (slotIndex < scene.getParty().length) {
|
||||||
scene.ui.setMode(modeToSetOnExit).then(() => {
|
scene.ui.setMode(modeToSetOnExit).then(() => {
|
||||||
const pokemon = scene.getParty()[slotIndex];
|
const pokemon = scene.getParty()[slotIndex];
|
||||||
|
@ -456,7 +456,7 @@ export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (p
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
onHover: () => {
|
onHover: () => {
|
||||||
scene.ui.showText(i18next.t("mysteryEncounterMessages:cancel_option"));
|
showEncounterText(scene, i18next.t("mysteryEncounterMessages:cancel_option"), 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -534,7 +534,7 @@ export function selectOptionThenPokemon(scene: BattleScene, options: OptionSelec
|
||||||
|
|
||||||
const selectPokemonAfterOption = (selectedOptionIndex: number) => {
|
const selectPokemonAfterOption = (selectedOptionIndex: number) => {
|
||||||
// Open party screen to choose a Pokemon
|
// Open party screen to choose a Pokemon
|
||||||
scene.ui.setMode(Mode.PARTY, PartyUiMode.SELECT, -1, (slotIndex: integer, option: PartyOption) => {
|
scene.ui.setMode(Mode.PARTY, PartyUiMode.SELECT, -1, (slotIndex: number, option: PartyOption) => {
|
||||||
if (slotIndex < scene.getParty().length) {
|
if (slotIndex < scene.getParty().length) {
|
||||||
// Pokemon and option selected
|
// Pokemon and option selected
|
||||||
scene.ui.setMode(modeToSetOnExit).then(() => {
|
scene.ui.setMode(modeToSetOnExit).then(() => {
|
||||||
|
@ -852,7 +852,7 @@ export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: n
|
||||||
if (Array.isArray(biomeLinks[currentBiome])) {
|
if (Array.isArray(biomeLinks[currentBiome])) {
|
||||||
let biomes: Biome[];
|
let biomes: Biome[];
|
||||||
scene.executeWithSeedOffset(() => {
|
scene.executeWithSeedOffset(() => {
|
||||||
biomes = (biomeLinks[currentBiome] as (Biome | [Biome, integer])[])
|
biomes = (biomeLinks[currentBiome] as (Biome | [Biome, number])[])
|
||||||
.filter(b => {
|
.filter(b => {
|
||||||
return !Array.isArray(b) || !Utils.randSeedInt(b[1]);
|
return !Array.isArray(b) || !Utils.randSeedInt(b[1]);
|
||||||
})
|
})
|
||||||
|
|
|
@ -20,12 +20,24 @@ import { Gender } from "#app/data/gender";
|
||||||
import { PermanentStat } from "#enums/stat";
|
import { PermanentStat } from "#enums/stat";
|
||||||
import { VictoryPhase } from "#app/phases/victory-phase";
|
import { VictoryPhase } from "#app/phases/victory-phase";
|
||||||
|
|
||||||
export function getSpriteKeysFromSpecies(species: Species, female?: boolean, formIndex?: integer, shiny?: boolean, variant?: integer): { spriteKey: string, fileRoot: string } {
|
/**
|
||||||
|
* Gets the sprite key and file root for a given PokemonSpecies (accounts for gender, shiny, variants, forms, and experimental)
|
||||||
|
* @param species
|
||||||
|
* @param female
|
||||||
|
* @param formIndex
|
||||||
|
* @param shiny
|
||||||
|
* @param variant
|
||||||
|
*/
|
||||||
|
export function getSpriteKeysFromSpecies(species: Species, female?: boolean, formIndex?: number, shiny?: boolean, variant?: number): { spriteKey: string, fileRoot: string } {
|
||||||
const spriteKey = getPokemonSpecies(species).getSpriteKey(female ?? false, formIndex ?? 0, shiny ?? false, variant ?? 0);
|
const spriteKey = getPokemonSpecies(species).getSpriteKey(female ?? false, formIndex ?? 0, shiny ?? false, variant ?? 0);
|
||||||
const fileRoot = getPokemonSpecies(species).getSpriteAtlasPath(female ?? false, formIndex ?? 0, shiny ?? false, variant ?? 0);
|
const fileRoot = getPokemonSpecies(species).getSpriteAtlasPath(female ?? false, formIndex ?? 0, shiny ?? false, variant ?? 0);
|
||||||
return { spriteKey, fileRoot };
|
return { spriteKey, fileRoot };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the sprite key and file root for a given Pokemon (accounts for gender, shiny, variants, forms, and experimental)
|
||||||
|
* @param pokemon
|
||||||
|
*/
|
||||||
export function getSpriteKeysFromPokemon(pokemon: Pokemon): { spriteKey: string, fileRoot: string } {
|
export function getSpriteKeysFromPokemon(pokemon: Pokemon): { spriteKey: string, fileRoot: string } {
|
||||||
const spriteKey = pokemon.getSpeciesForm().getSpriteKey(pokemon.getGender() === Gender.FEMALE, pokemon.formIndex, pokemon.shiny, pokemon.variant);
|
const spriteKey = pokemon.getSpeciesForm().getSpriteKey(pokemon.getGender() === Gender.FEMALE, pokemon.formIndex, pokemon.shiny, pokemon.variant);
|
||||||
const fileRoot = pokemon.getSpeciesForm().getSpriteAtlasPath(pokemon.getGender() === Gender.FEMALE, pokemon.formIndex, pokemon.shiny, pokemon.variant);
|
const fileRoot = pokemon.getSpeciesForm().getSpriteAtlasPath(pokemon.getGender() === Gender.FEMALE, pokemon.formIndex, pokemon.shiny, pokemon.variant);
|
||||||
|
@ -442,6 +454,14 @@ export function trainerThrowPokeball(scene: BattleScene, pokemon: EnemyPokemon,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animates pokeball opening and messages when an attempted catch fails
|
||||||
|
* @param scene
|
||||||
|
* @param pokemon
|
||||||
|
* @param originalY
|
||||||
|
* @param pokeball
|
||||||
|
* @param pokeballType
|
||||||
|
*/
|
||||||
function failCatch(scene: BattleScene, pokemon: EnemyPokemon, originalY: number, pokeball: Phaser.GameObjects.Sprite, pokeballType: PokeballType) {
|
function failCatch(scene: BattleScene, pokemon: EnemyPokemon, originalY: number, pokeball: Phaser.GameObjects.Sprite, pokeballType: PokeballType) {
|
||||||
return new Promise<void>(resolve => {
|
return new Promise<void>(resolve => {
|
||||||
scene.playSound("se/pb_rel");
|
scene.playSound("se/pb_rel");
|
||||||
|
@ -541,7 +561,7 @@ export async function catchPokemon(scene: BattleScene, pokemon: EnemyPokemon, po
|
||||||
scene.ui.showText(i18next.t("battle:partyFull", { pokemonName: pokemon.getNameToRender() }), null, () => {
|
scene.ui.showText(i18next.t("battle:partyFull", { pokemonName: pokemon.getNameToRender() }), null, () => {
|
||||||
scene.pokemonInfoContainer.makeRoomForConfirmUi();
|
scene.pokemonInfoContainer.makeRoomForConfirmUi();
|
||||||
scene.ui.setMode(Mode.CONFIRM, () => {
|
scene.ui.setMode(Mode.CONFIRM, () => {
|
||||||
scene.ui.setMode(Mode.PARTY, PartyUiMode.RELEASE, 0, (slotIndex: integer, _option: PartyOption) => {
|
scene.ui.setMode(Mode.PARTY, PartyUiMode.RELEASE, 0, (slotIndex: number, _option: PartyOption) => {
|
||||||
scene.ui.setMode(Mode.MESSAGE).then(() => {
|
scene.ui.setMode(Mode.MESSAGE).then(() => {
|
||||||
if (slotIndex < 6) {
|
if (slotIndex < 6) {
|
||||||
addToParty();
|
addToParty();
|
||||||
|
@ -573,6 +593,11 @@ export async function catchPokemon(scene: BattleScene, pokemon: EnemyPokemon, po
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animates pokeball disappearing then destroys the object
|
||||||
|
* @param scene
|
||||||
|
* @param pokeball
|
||||||
|
*/
|
||||||
function removePb(scene: BattleScene, pokeball: Phaser.GameObjects.Sprite) {
|
function removePb(scene: BattleScene, pokeball: Phaser.GameObjects.Sprite) {
|
||||||
if (pokeball) {
|
if (pokeball) {
|
||||||
scene.tweens.add({
|
scene.tweens.add({
|
||||||
|
@ -588,6 +613,11 @@ function removePb(scene: BattleScene, pokeball: Phaser.GameObjects.Sprite) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animates a wild pokemon "fleeing", including sfx and messaging
|
||||||
|
* @param scene
|
||||||
|
* @param pokemon
|
||||||
|
*/
|
||||||
export async function doPokemonFlee(scene: BattleScene, pokemon: EnemyPokemon): Promise<void> {
|
export async function doPokemonFlee(scene: BattleScene, pokemon: EnemyPokemon): Promise<void> {
|
||||||
await new Promise<void>(resolve => {
|
await new Promise<void>(resolve => {
|
||||||
scene.playSound("se/flee");
|
scene.playSound("se/flee");
|
||||||
|
@ -603,7 +633,7 @@ export async function doPokemonFlee(scene: BattleScene, pokemon: EnemyPokemon):
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
pokemon.setVisible(false);
|
pokemon.setVisible(false);
|
||||||
scene.field.remove(pokemon, true);
|
scene.field.remove(pokemon, true);
|
||||||
showEncounterText(scene, i18next.t("battle:pokemonFled", { pokemonName: pokemon.getNameToRender() }), 600, false)
|
showEncounterText(scene, i18next.t("battle:pokemonFled", { pokemonName: pokemon.getNameToRender() }), null, 600, false)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
@ -612,6 +642,11 @@ export async function doPokemonFlee(scene: BattleScene, pokemon: EnemyPokemon):
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the player fleeing from a wild pokemon, including sfx and messaging
|
||||||
|
* @param scene
|
||||||
|
* @param pokemon
|
||||||
|
*/
|
||||||
export function doPlayerFlee(scene: BattleScene, pokemon: EnemyPokemon): Promise<void> {
|
export function doPlayerFlee(scene: BattleScene, pokemon: EnemyPokemon): Promise<void> {
|
||||||
return new Promise<void>(resolve => {
|
return new Promise<void>(resolve => {
|
||||||
// Ease pokemon out
|
// Ease pokemon out
|
||||||
|
@ -626,7 +661,7 @@ export function doPlayerFlee(scene: BattleScene, pokemon: EnemyPokemon): Promise
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
pokemon.setVisible(false);
|
pokemon.setVisible(false);
|
||||||
scene.field.remove(pokemon, true);
|
scene.field.remove(pokemon, true);
|
||||||
showEncounterText(scene, i18next.t("battle:playerFled", { pokemonName: pokemon.getNameToRender() }), 600, false)
|
showEncounterText(scene, i18next.t("battle:playerFled", { pokemonName: pokemon.getNameToRender() }), null, 600, false)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
@ -635,7 +670,9 @@ export function doPlayerFlee(scene: BattleScene, pokemon: EnemyPokemon): Promise
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bug Species and their corresponding weights
|
/**
|
||||||
|
* Bug Species and their corresponding weights
|
||||||
|
*/
|
||||||
const GOLDEN_BUG_NET_SPECIES_POOL: [Species, number][] = [
|
const GOLDEN_BUG_NET_SPECIES_POOL: [Species, number][] = [
|
||||||
[Species.SCYTHER, 40],
|
[Species.SCYTHER, 40],
|
||||||
[Species.SCIZOR, 40],
|
[Species.SCIZOR, 40],
|
||||||
|
@ -666,7 +703,10 @@ const GOLDEN_BUG_NET_SPECIES_POOL: [Species, number][] = [
|
||||||
[Species.PHEROMOSA, 1],
|
[Species.PHEROMOSA, 1],
|
||||||
];
|
];
|
||||||
|
|
||||||
export function getGoldenBugNetSpecies(scene: BattleScene, waveIndex: integer, level: integer): PokemonSpecies {
|
/**
|
||||||
|
* Will randomly return one of the species from GOLDEN_BUG_NET_SPECIES_POOL, based on their weights
|
||||||
|
*/
|
||||||
|
export function getGoldenBugNetSpecies(): 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);
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ export function doPokemonTransformationSequence(scene: BattleScene, previousPoke
|
||||||
scene.time.delayedCall(1000, () => {
|
scene.time.delayedCall(1000, () => {
|
||||||
pokemonEvoTintSprite.setScale(0.25);
|
pokemonEvoTintSprite.setScale(0.25);
|
||||||
pokemonEvoTintSprite.setVisible(true);
|
pokemonEvoTintSprite.setVisible(true);
|
||||||
doCycle(scene, 2, 6, pokemonTintSprite, pokemonEvoTintSprite).then(success => {
|
doCycle(scene, 2, 6, pokemonTintSprite, pokemonEvoTintSprite).then(() => {
|
||||||
pokemonEvoSprite.setVisible(true);
|
pokemonEvoSprite.setVisible(true);
|
||||||
doCircleInward(scene, transformationBaseBg, transformationContainer, xOffset, yOffset);
|
doCircleInward(scene, transformationBaseBg, transformationContainer, xOffset, yOffset);
|
||||||
|
|
||||||
|
@ -143,7 +143,15 @@ export function doPokemonTransformationSequence(scene: BattleScene, previousPoke
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function doSpiralUpward(scene: BattleScene, transformationBaseBg, transformationContainer, xOffset: number, yOffset: number) {
|
/**
|
||||||
|
* Animates particles that "spiral" upwards at start of transform animation
|
||||||
|
* @param scene
|
||||||
|
* @param transformationBaseBg
|
||||||
|
* @param transformationContainer
|
||||||
|
* @param xOffset
|
||||||
|
* @param yOffset
|
||||||
|
*/
|
||||||
|
function doSpiralUpward(scene: BattleScene, transformationBaseBg: Phaser.GameObjects.Image, transformationContainer: Phaser.GameObjects.Container, xOffset: number, yOffset: number) {
|
||||||
let f = 0;
|
let f = 0;
|
||||||
|
|
||||||
scene.tweens.addCounter({
|
scene.tweens.addCounter({
|
||||||
|
@ -162,7 +170,15 @@ function doSpiralUpward(scene: BattleScene, transformationBaseBg, transformation
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function doArcDownward(scene: BattleScene, transformationBaseBg, transformationContainer, xOffset: number, yOffset: number) {
|
/**
|
||||||
|
* Animates particles that arc downwards after the upwards spiral
|
||||||
|
* @param scene
|
||||||
|
* @param transformationBaseBg
|
||||||
|
* @param transformationContainer
|
||||||
|
* @param xOffset
|
||||||
|
* @param yOffset
|
||||||
|
*/
|
||||||
|
function doArcDownward(scene: BattleScene, transformationBaseBg: Phaser.GameObjects.Image, transformationContainer: Phaser.GameObjects.Container, xOffset: number, yOffset: number) {
|
||||||
let f = 0;
|
let f = 0;
|
||||||
|
|
||||||
scene.tweens.addCounter({
|
scene.tweens.addCounter({
|
||||||
|
@ -181,7 +197,15 @@ function doArcDownward(scene: BattleScene, transformationBaseBg, transformationC
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function doCycle(scene: BattleScene, l: number, lastCycle: integer, pokemonTintSprite, pokemonEvoTintSprite): Promise<boolean> {
|
/**
|
||||||
|
* Animates the transformation between the old pokemon form and new pokemon form
|
||||||
|
* @param scene
|
||||||
|
* @param l
|
||||||
|
* @param lastCycle
|
||||||
|
* @param pokemonTintSprite
|
||||||
|
* @param pokemonEvoTintSprite
|
||||||
|
*/
|
||||||
|
function doCycle(scene: BattleScene, l: number, lastCycle: number, pokemonTintSprite: Phaser.GameObjects.Sprite, pokemonEvoTintSprite: Phaser.GameObjects.Sprite): Promise<boolean> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const isLastCycle = l === lastCycle;
|
const isLastCycle = l === lastCycle;
|
||||||
scene.tweens.add({
|
scene.tweens.add({
|
||||||
|
@ -209,7 +233,15 @@ function doCycle(scene: BattleScene, l: number, lastCycle: integer, pokemonTintS
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function doCircleInward(scene: BattleScene, transformationBaseBg, transformationContainer, xOffset: number, yOffset: number) {
|
/**
|
||||||
|
* Animates particles in a circle pattern
|
||||||
|
* @param scene
|
||||||
|
* @param transformationBaseBg
|
||||||
|
* @param transformationContainer
|
||||||
|
* @param xOffset
|
||||||
|
* @param yOffset
|
||||||
|
*/
|
||||||
|
function doCircleInward(scene: BattleScene, transformationBaseBg: Phaser.GameObjects.Image, transformationContainer: Phaser.GameObjects.Container, xOffset: number, yOffset: number) {
|
||||||
let f = 0;
|
let f = 0;
|
||||||
|
|
||||||
scene.tweens.addCounter({
|
scene.tweens.addCounter({
|
||||||
|
@ -230,7 +262,16 @@ function doCircleInward(scene: BattleScene, transformationBaseBg, transformation
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function doSpiralUpwardParticle(scene: BattleScene, trigIndex: integer, transformationBaseBg, transformationContainer, xOffset: number, yOffset: number) {
|
/**
|
||||||
|
* Helper function for {@link doSpiralUpward}, handles a single particle
|
||||||
|
* @param scene
|
||||||
|
* @param trigIndex
|
||||||
|
* @param transformationBaseBg
|
||||||
|
* @param transformationContainer
|
||||||
|
* @param xOffset
|
||||||
|
* @param yOffset
|
||||||
|
*/
|
||||||
|
function doSpiralUpwardParticle(scene: BattleScene, trigIndex: number, transformationBaseBg: Phaser.GameObjects.Image, transformationContainer: Phaser.GameObjects.Container, xOffset: number, yOffset: number) {
|
||||||
const initialX = transformationBaseBg.displayWidth / 2 + xOffset;
|
const initialX = transformationBaseBg.displayWidth / 2 + xOffset;
|
||||||
const particle = scene.add.image(initialX, 0, "evo_sparkle");
|
const particle = scene.add.image(initialX, 0, "evo_sparkle");
|
||||||
transformationContainer.add(particle);
|
transformationContainer.add(particle);
|
||||||
|
@ -266,7 +307,16 @@ function doSpiralUpwardParticle(scene: BattleScene, trigIndex: integer, transfor
|
||||||
updateParticle();
|
updateParticle();
|
||||||
}
|
}
|
||||||
|
|
||||||
function doArcDownParticle(scene: BattleScene, trigIndex: integer, transformationBaseBg, transformationContainer, xOffset: number, yOffset: number) {
|
/**
|
||||||
|
* Helper function for {@link doArcDownward}, handles a single particle
|
||||||
|
* @param scene
|
||||||
|
* @param trigIndex
|
||||||
|
* @param transformationBaseBg
|
||||||
|
* @param transformationContainer
|
||||||
|
* @param xOffset
|
||||||
|
* @param yOffset
|
||||||
|
*/
|
||||||
|
function doArcDownParticle(scene: BattleScene, trigIndex: number, transformationBaseBg: Phaser.GameObjects.Image, transformationContainer: Phaser.GameObjects.Container, xOffset: number, yOffset: number) {
|
||||||
const initialX = transformationBaseBg.displayWidth / 2 + xOffset;
|
const initialX = transformationBaseBg.displayWidth / 2 + xOffset;
|
||||||
const particle = scene.add.image(initialX, 0, "evo_sparkle");
|
const particle = scene.add.image(initialX, 0, "evo_sparkle");
|
||||||
particle.setScale(0.5);
|
particle.setScale(0.5);
|
||||||
|
@ -299,7 +349,17 @@ function doArcDownParticle(scene: BattleScene, trigIndex: integer, transformatio
|
||||||
updateParticle();
|
updateParticle();
|
||||||
}
|
}
|
||||||
|
|
||||||
function doCircleInwardParticle(scene: BattleScene, trigIndex: integer, speed: integer, transformationBaseBg, transformationContainer, xOffset: number, yOffset: number) {
|
/**
|
||||||
|
* Helper function for @{link doCircleInward}, handles a single particle
|
||||||
|
* @param scene
|
||||||
|
* @param trigIndex
|
||||||
|
* @param speed
|
||||||
|
* @param transformationBaseBg
|
||||||
|
* @param transformationContainer
|
||||||
|
* @param xOffset
|
||||||
|
* @param yOffset
|
||||||
|
*/
|
||||||
|
function doCircleInwardParticle(scene: BattleScene, trigIndex: number, speed: number, transformationBaseBg: Phaser.GameObjects.Image, transformationContainer: Phaser.GameObjects.Container, xOffset: number, yOffset: number) {
|
||||||
const initialX = transformationBaseBg.displayWidth / 2 + xOffset;
|
const initialX = transformationBaseBg.displayWidth / 2 + xOffset;
|
||||||
const initialY = transformationBaseBg.displayHeight / 2 + yOffset;
|
const initialY = transformationBaseBg.displayHeight / 2 + yOffset;
|
||||||
const particle = scene.add.image(initialX, initialY, "evo_sparkle");
|
const particle = scene.add.image(initialX, initialY, "evo_sparkle");
|
||||||
|
|
|
@ -247,7 +247,7 @@ export abstract class PokemonSpeciesForm {
|
||||||
* Gets the BST for the species
|
* Gets the BST for the species
|
||||||
* @returns The species' BST.
|
* @returns The species' BST.
|
||||||
*/
|
*/
|
||||||
getBaseStatTotal(): integer {
|
getBaseStatTotal(): number {
|
||||||
return this.baseStats.reduce((i, n) => n + i);
|
return this.baseStats.reduce((i, n) => n + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,11 +256,11 @@ export abstract class PokemonSpeciesForm {
|
||||||
* @param stat The desired stat.
|
* @param stat The desired stat.
|
||||||
* @returns The species' base stat amount.
|
* @returns The species' base stat amount.
|
||||||
*/
|
*/
|
||||||
getBaseStat(stat: Stat): integer {
|
getBaseStat(stat: Stat): number {
|
||||||
return this.baseStats[stat];
|
return this.baseStats[stat];
|
||||||
}
|
}
|
||||||
|
|
||||||
getBaseExp(): integer {
|
getBaseExp(): number {
|
||||||
let ret = this.baseExp;
|
let ret = this.baseExp;
|
||||||
switch (this.getFormSpriteKey()) {
|
switch (this.getFormSpriteKey()) {
|
||||||
case SpeciesFormKey.MEGA:
|
case SpeciesFormKey.MEGA:
|
||||||
|
|
|
@ -994,6 +994,9 @@ export class TrainerConfig {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a copy of a trainer config so that it can be modified without affecting the {@link trainerConfigs} source map
|
||||||
|
*/
|
||||||
copy(): TrainerConfig {
|
copy(): TrainerConfig {
|
||||||
let copy = new TrainerConfig(this.trainerType);
|
let copy = new TrainerConfig(this.trainerType);
|
||||||
copy = this.trainerTypeDouble ? copy.setDoubleTrainerType(this.trainerTypeDouble) : copy;
|
copy = this.trainerTypeDouble ? copy.setDoubleTrainerType(this.trainerTypeDouble) : copy;
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
export enum MysteryEncounterMode {
|
export enum MysteryEncounterMode {
|
||||||
/** MysteryEncounter will always begin in this mode, but will always swap modes when an option is selected */
|
/** MysteryEncounter will always begin in this mode, but will always swap modes when an option is selected */
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
|
/** If the MysteryEncounter battle is a trainer type battle */
|
||||||
TRAINER_BATTLE,
|
TRAINER_BATTLE,
|
||||||
|
/** If the MysteryEncounter battle is a wild type battle */
|
||||||
WILD_BATTLE,
|
WILD_BATTLE,
|
||||||
/** Enables special boss music during encounter */
|
/** Enables special boss music during encounter */
|
||||||
BOSS_BATTLE,
|
BOSS_BATTLE,
|
||||||
|
/** If there is no battle in the MysteryEncounter or option selected */
|
||||||
NO_BATTLE
|
NO_BATTLE
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ export enum MysteryEncounterType {
|
||||||
SHADY_VITAMIN_DEALER,
|
SHADY_VITAMIN_DEALER,
|
||||||
FIELD_TRIP,
|
FIELD_TRIP,
|
||||||
SAFARI_ZONE,
|
SAFARI_ZONE,
|
||||||
LOST_AT_SEA, // Might be generalized later on
|
LOST_AT_SEA,
|
||||||
FIERY_FALLOUT,
|
FIERY_FALLOUT,
|
||||||
THE_STRONG_STUFF,
|
THE_STRONG_STUFF,
|
||||||
THE_POKEMON_SALESMAN,
|
THE_POKEMON_SALESMAN,
|
||||||
|
|
|
@ -175,6 +175,9 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the assets that were defined on construction (async)
|
||||||
|
*/
|
||||||
loadAssets(): Promise<void> {
|
loadAssets(): Promise<void> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
if (!this.spriteConfigs) {
|
if (!this.spriteConfigs) {
|
||||||
|
@ -226,6 +229,9 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the initial frames and tint of sprites after load
|
||||||
|
*/
|
||||||
initSprite(): void {
|
initSprite(): void {
|
||||||
if (!this.spriteConfigs) {
|
if (!this.spriteConfigs) {
|
||||||
return;
|
return;
|
||||||
|
@ -282,6 +288,9 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For sprites with animation and that do not have animation disabled, will begin frame animation
|
||||||
|
*/
|
||||||
playAnim(): void {
|
playAnim(): void {
|
||||||
if (!this.spriteConfigs) {
|
if (!this.spriteConfigs) {
|
||||||
return;
|
return;
|
||||||
|
@ -318,6 +327,9 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all non-tint sprites (these are the "real" unmodified sprites)
|
||||||
|
*/
|
||||||
getSprites(): Phaser.GameObjects.Sprite[] {
|
getSprites(): Phaser.GameObjects.Sprite[] {
|
||||||
if (!this.spriteConfigs) {
|
if (!this.spriteConfigs) {
|
||||||
return [];
|
return [];
|
||||||
|
@ -330,6 +342,9 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all tint sprites (duplicate sprites that have different alpha and fill values)
|
||||||
|
*/
|
||||||
getTintSprites(): Phaser.GameObjects.Sprite[] {
|
getTintSprites(): Phaser.GameObjects.Sprite[] {
|
||||||
if (!this.spriteConfigs) {
|
if (!this.spriteConfigs) {
|
||||||
return [];
|
return [];
|
||||||
|
@ -343,7 +358,15 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
tint(sprite, color: number, alpha?: number, duration?: integer, ease?: string): void {
|
/**
|
||||||
|
* Tints a single sprite
|
||||||
|
* @param sprite
|
||||||
|
* @param color
|
||||||
|
* @param alpha
|
||||||
|
* @param duration
|
||||||
|
* @param ease
|
||||||
|
*/
|
||||||
|
private tint(sprite, color: number, alpha?: number, duration?: integer, ease?: string): void {
|
||||||
// const tintSprites = this.getTintSprites();
|
// const tintSprites = this.getTintSprites();
|
||||||
sprite.setTintFill(color);
|
sprite.setTintFill(color);
|
||||||
sprite.setVisible(true);
|
sprite.setVisible(true);
|
||||||
|
@ -362,6 +385,13 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tints all sprites
|
||||||
|
* @param color
|
||||||
|
* @param alpha
|
||||||
|
* @param duration
|
||||||
|
* @param ease
|
||||||
|
*/
|
||||||
tintAll(color: number, alpha?: number, duration?: integer, ease?: string): void {
|
tintAll(color: number, alpha?: number, duration?: integer, ease?: string): void {
|
||||||
const tintSprites = this.getTintSprites();
|
const tintSprites = this.getTintSprites();
|
||||||
tintSprites.map(tintSprite => {
|
tintSprites.map(tintSprite => {
|
||||||
|
@ -369,7 +399,13 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
untint(sprite, duration: integer, ease?: string): void {
|
/**
|
||||||
|
* Untints a single sprite over a duration
|
||||||
|
* @param sprite
|
||||||
|
* @param duration
|
||||||
|
* @param ease
|
||||||
|
*/
|
||||||
|
private untint(sprite, duration: integer, ease?: string): void {
|
||||||
if (duration) {
|
if (duration) {
|
||||||
this.scene.tweens.add({
|
this.scene.tweens.add({
|
||||||
targets: sprite,
|
targets: sprite,
|
||||||
|
@ -387,6 +423,12 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Untints all sprites
|
||||||
|
* @param sprite
|
||||||
|
* @param duration
|
||||||
|
* @param ease
|
||||||
|
*/
|
||||||
untintAll(duration: integer, ease?: string): void {
|
untintAll(duration: integer, ease?: string): void {
|
||||||
const tintSprites = this.getTintSprites();
|
const tintSprites = this.getTintSprites();
|
||||||
tintSprites.map(tintSprite => {
|
tintSprites.map(tintSprite => {
|
||||||
|
@ -406,6 +448,9 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface is required so as not to override {@link Phaser.GameObjects.Container.scene}
|
||||||
|
*/
|
||||||
export default interface MysteryEncounterIntroVisuals {
|
export default interface MysteryEncounterIntroVisuals {
|
||||||
scene: BattleScene
|
scene: BattleScene
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import * as Utils from "./utils";
|
||||||
import { Biome } from "#enums/biome";
|
import { Biome } from "#enums/biome";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { Challenges } from "./enums/challenges";
|
import { Challenges } from "./enums/challenges";
|
||||||
import MAX_SAFE_INTEGER = Phaser.Math.MAX_SAFE_INTEGER;
|
|
||||||
|
|
||||||
export enum GameModes {
|
export enum GameModes {
|
||||||
CLASSIC,
|
CLASSIC,
|
||||||
|
@ -62,7 +61,7 @@ export class GameMode implements GameModeConfig {
|
||||||
}
|
}
|
||||||
this.battleConfig = battleConfig || {};
|
this.battleConfig = battleConfig || {};
|
||||||
this.minMysteryEncounterWave = this.minMysteryEncounterWave ?? 0;
|
this.minMysteryEncounterWave = this.minMysteryEncounterWave ?? 0;
|
||||||
this.maxMysteryEncounterWave = this.maxMysteryEncounterWave ?? MAX_SAFE_INTEGER;
|
this.maxMysteryEncounterWave = this.maxMysteryEncounterWave ?? Number.MAX_SAFE_INTEGER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -53,9 +53,48 @@ import terrain from "./terrain.json";
|
||||||
import modifierSelectUiHandler from "./modifier-select-ui-handler.json";
|
import modifierSelectUiHandler from "./modifier-select-ui-handler.json";
|
||||||
import moveTriggers from "./move-trigger.json";
|
import moveTriggers from "./move-trigger.json";
|
||||||
import runHistory from "./run-history.json";
|
import runHistory from "./run-history.json";
|
||||||
import { mysteryEncounter } from "#app/locales/en/mystery-encounter";
|
|
||||||
import mysteryEncounterMessages from "./mystery-encounter-messages.json";
|
import mysteryEncounterMessages from "./mystery-encounter-messages.json";
|
||||||
|
import lostAtSea from "./mystery-encounters/lost-at-sea-dialogue.json";
|
||||||
|
import mysteriousChest from "#app/locales/en/mystery-encounters/mysterious-chest-dialogue.json";
|
||||||
|
import mysteriousChallengers from "#app/locales/en/mystery-encounters/mysterious-challengers-dialogue.json";
|
||||||
|
import darkDeal from "#app/locales/en/mystery-encounters/dark-deal-dialogue.json";
|
||||||
|
import departmentStoreSale from "#app/locales/en/mystery-encounters/department-store-sale-dialogue.json";
|
||||||
|
import fieldTrip from "#app/locales/en/mystery-encounters/field-trip-dialogue.json";
|
||||||
|
import fieryFallout from "#app/locales/en/mystery-encounters/fiery-fallout-dialogue.json";
|
||||||
|
import fightOrFlight from "#app/locales/en/mystery-encounters/fight-or-flight-dialogue.json";
|
||||||
|
import safariZone from "#app/locales/en/mystery-encounters/safari-zone-dialogue.json";
|
||||||
|
import shadyVitaminDealer from "#app/locales/en/mystery-encounters/shady-vitamin-dealer-dialogue.json";
|
||||||
|
import slumberingSnorlax from "#app/locales/en/mystery-encounters/slumbering-snorlax-dialogue.json";
|
||||||
|
import trainingSession from "#app/locales/en/mystery-encounters/training-session-dialogue.json";
|
||||||
|
import theStrongStuff from "#app/locales/en/mystery-encounters/the-strong-stuff-dialogue.json";
|
||||||
|
import pokemonSalesman from "#app/locales/en/mystery-encounters/the-pokemon-salesman-dialogue.json";
|
||||||
|
import offerYouCantRefuse from "#app/locales/en/mystery-encounters/an-offer-you-cant-refuse-dialogue.json";
|
||||||
|
import delibirdy from "#app/locales/en/mystery-encounters/delibirdy-dialogue.json";
|
||||||
|
import absoluteAvarice from "#app/locales/en/mystery-encounters/absolute-avarice-dialogue.json";
|
||||||
|
import aTrainersTest from "#app/locales/en/mystery-encounters/a-trainers-test-dialogue.json";
|
||||||
|
import trashToTreasure from "#app/locales/en/mystery-encounters/trash-to-treasure-dialogue.json";
|
||||||
|
import berriesAbound from "#app/locales/en/mystery-encounters/berries-abound-dialogue.json";
|
||||||
|
import clowningAround from "#app/locales/en/mystery-encounters/clowning-around-dialogue.json";
|
||||||
|
import partTimer from "#app/locales/en/mystery-encounters/part-timer-dialogue.json";
|
||||||
|
import dancingLessons from "#app/locales/en/mystery-encounters/dancing-lessons-dialogue.json";
|
||||||
|
import weirdDream from "#app/locales/en/mystery-encounters/weird-dream-dialogue.json";
|
||||||
|
import theWinstrateChallenge from "#app/locales/en/mystery-encounters/the-winstrate-challenge-dialogue.json";
|
||||||
|
import teleportingHijinks from "#app/locales/en/mystery-encounters/teleporting-hijinks-dialogue.json";
|
||||||
|
import bugTypeSuperfan from "#app/locales/en/mystery-encounters/bug-type-superfan-dialogue.json";
|
||||||
|
import funAndGames from "#app/locales/en/mystery-encounters/fun-and-games-dialogue.json";
|
||||||
|
import uncommonBreed from "#app/locales/en/mystery-encounters/uncommon-breed-dialogue.json";
|
||||||
|
import globalTradeSystem from "#app/locales/en/mystery-encounters/global-trade-system-dialogue.json";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dialogue/Text token injection patterns that can be used:
|
||||||
|
* - `$` will be treated as a new line for Message and Dialogue strings.
|
||||||
|
* - `@d{<number>}` will add a time delay to text animation for Message and Dialogue strings.
|
||||||
|
* - `@s{<sound_effect_key>}` will play a specified sound effect for Message and Dialogue strings.
|
||||||
|
* - `@f{<number>}` will fade the screen to black for the given duration, then fade back in for Message and Dialogue strings.
|
||||||
|
* - `{{<token>}}` (MYSTERY ENCOUNTERS ONLY) will auto-inject the matching dialogue token value that is stored in {@link IMysteryEncounter.dialogueTokens}.
|
||||||
|
* - (see [i18next interpolations](https://www.i18next.com/translation-function/interpolation)) for more details.
|
||||||
|
* - `@[<TextStyle>]{<text>}` (STATIC TEXT ONLY, NOT USEABLE WITH {@link UI.showText()} OR {@link UI.showDialogue()}) will auto-color the given text to a specified {@link TextStyle} (e.g. `TextStyle.SUMMARY_GREEN`).
|
||||||
|
*/
|
||||||
export const enConfig = {
|
export const enConfig = {
|
||||||
ability,
|
ability,
|
||||||
abilityTriggers,
|
abilityTriggers,
|
||||||
|
@ -112,6 +151,39 @@ export const enConfig = {
|
||||||
modifierSelectUiHandler,
|
modifierSelectUiHandler,
|
||||||
moveTriggers,
|
moveTriggers,
|
||||||
runHistory,
|
runHistory,
|
||||||
mysteryEncounter: mysteryEncounter,
|
mysteryEncounter: {
|
||||||
|
// DO NOT REMOVE
|
||||||
|
"unit_test_dialogue": "{{test}}{{test}} {{test{{test}}}} {{test1}} {{test\}} {{test\\}} {{test\\\}} {test}}",
|
||||||
|
mysteriousChallengers,
|
||||||
|
mysteriousChest,
|
||||||
|
darkDeal,
|
||||||
|
fightOrFlight,
|
||||||
|
slumberingSnorlax,
|
||||||
|
trainingSession,
|
||||||
|
departmentStoreSale,
|
||||||
|
shadyVitaminDealer,
|
||||||
|
fieldTrip,
|
||||||
|
safariZone,
|
||||||
|
lostAtSea,
|
||||||
|
fieryFallout,
|
||||||
|
theStrongStuff,
|
||||||
|
pokemonSalesman,
|
||||||
|
offerYouCantRefuse,
|
||||||
|
delibirdy,
|
||||||
|
absoluteAvarice,
|
||||||
|
aTrainersTest,
|
||||||
|
trashToTreasure,
|
||||||
|
berriesAbound,
|
||||||
|
clowningAround,
|
||||||
|
partTimer,
|
||||||
|
dancingLessons,
|
||||||
|
weirdDream,
|
||||||
|
theWinstrateChallenge,
|
||||||
|
teleportingHijinks,
|
||||||
|
bugTypeSuperfan,
|
||||||
|
funAndGames,
|
||||||
|
uncommonBreed,
|
||||||
|
globalTradeSystem
|
||||||
|
},
|
||||||
mysteryEncounterMessages
|
mysteryEncounterMessages
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
import lostAtSea from "./mystery-encounters/lost-at-sea-dialogue.json";
|
|
||||||
import mysteriousChest from "#app/locales/en/mystery-encounters/mysterious-chest-dialogue.json";
|
|
||||||
import mysteriousChallengers from "#app/locales/en/mystery-encounters/mysterious-challengers-dialogue.json";
|
|
||||||
import darkDeal from "#app/locales/en/mystery-encounters/dark-deal-dialogue.json";
|
|
||||||
import departmentStoreSale from "#app/locales/en/mystery-encounters/department-store-sale-dialogue.json";
|
|
||||||
import fieldTrip from "#app/locales/en/mystery-encounters/field-trip-dialogue.json";
|
|
||||||
import fieryFallout from "#app/locales/en/mystery-encounters/fiery-fallout-dialogue.json";
|
|
||||||
import fightOrFlight from "#app/locales/en/mystery-encounters/fight-or-flight-dialogue.json";
|
|
||||||
import safariZone from "#app/locales/en/mystery-encounters/safari-zone-dialogue.json";
|
|
||||||
import shadyVitaminDealer from "#app/locales/en/mystery-encounters/shady-vitamin-dealer-dialogue.json";
|
|
||||||
import slumberingSnorlax from "#app/locales/en/mystery-encounters/slumbering-snorlax-dialogue.json";
|
|
||||||
import trainingSession from "#app/locales/en/mystery-encounters/training-session-dialogue.json";
|
|
||||||
import theStrongStuff from "#app/locales/en/mystery-encounters/the-strong-stuff-dialogue.json";
|
|
||||||
import pokemonSalesman from "#app/locales/en/mystery-encounters/the-pokemon-salesman-dialogue.json";
|
|
||||||
import offerYouCantRefuse from "#app/locales/en/mystery-encounters/an-offer-you-cant-refuse-dialogue.json";
|
|
||||||
import delibirdy from "#app/locales/en/mystery-encounters/delibirdy-dialogue.json";
|
|
||||||
import absoluteAvarice from "#app/locales/en/mystery-encounters/absolute-avarice-dialogue.json";
|
|
||||||
import aTrainersTest from "#app/locales/en/mystery-encounters/a-trainers-test-dialogue.json";
|
|
||||||
import trashToTreasure from "#app/locales/en/mystery-encounters/trash-to-treasure-dialogue.json";
|
|
||||||
import berriesAbound from "#app/locales/en/mystery-encounters/berries-abound-dialogue.json";
|
|
||||||
import clowningAround from "#app/locales/en/mystery-encounters/clowning-around-dialogue.json";
|
|
||||||
import partTimer from "#app/locales/en/mystery-encounters/part-timer-dialogue.json";
|
|
||||||
import dancingLessons from "#app/locales/en/mystery-encounters/dancing-lessons-dialogue.json";
|
|
||||||
import weirdDream from "#app/locales/en/mystery-encounters/weird-dream-dialogue.json";
|
|
||||||
import theWinstrateChallenge from "#app/locales/en/mystery-encounters/the-winstrate-challenge-dialogue.json";
|
|
||||||
import teleportingHijinks from "#app/locales/en/mystery-encounters/teleporting-hijinks-dialogue.json";
|
|
||||||
import bugTypeSuperfan from "#app/locales/en/mystery-encounters/bug-type-superfan-dialogue.json";
|
|
||||||
import funAndGames from "#app/locales/en/mystery-encounters/fun-and-games-dialogue.json";
|
|
||||||
import uncommonBreed from "#app/locales/en/mystery-encounters/uncommon-breed-dialogue.json";
|
|
||||||
import globalTradeSystem from "#app/locales/en/mystery-encounters/global-trade-system-dialogue.json";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Injection patterns that can be used:
|
|
||||||
* - `$` will be treated as a new line for Message and Dialogue strings.
|
|
||||||
* - `@d{<number>}` will add a time delay to text animation for Message and Dialogue strings.
|
|
||||||
* - `@s{<sound_effect_key>}` will play a specified sound effect for Message and Dialogue strings.
|
|
||||||
* - `@f{<number>}` will fade the screen to black for the given duration, then fade back in for Message and Dialogue strings.
|
|
||||||
* - `{{<token>}}` will auto-inject the matching dialogue token value that is stored in {@link IMysteryEncounter.dialogueTokens}.
|
|
||||||
* - (see [i18next interpolations](https://www.i18next.com/translation-function/interpolation)) for more details.
|
|
||||||
* - `@[<TextStyle>]{<text>}` will auto-color the given text to a specified {@link TextStyle} (e.g. `TextStyle.SUMMARY_GREEN`).
|
|
||||||
*
|
|
||||||
* For Option tooltips ({@link OptionTextDisplay.buttonTooltip}):
|
|
||||||
* - Any tooltip that starts with `(+)` or `(-)` at the beginning of a newline will auto-color to green/blue respectively.
|
|
||||||
* - Note, this only occurs for option tooltips, nowhere else.
|
|
||||||
* - Other types of `(...)` tooltips will have to specify the text color manually by using the `@[SUMMARY_GREEN]{<text>}` pattern.
|
|
||||||
*/
|
|
||||||
export const mysteryEncounter = {
|
|
||||||
// DO NOT REMOVE
|
|
||||||
"unit_test_dialogue": "{{test}}{{test}} {{test{{test}}}} {{test1}} {{test\}} {{test\\}} {{test\\\}} {test}}",
|
|
||||||
|
|
||||||
mysteriousChallengers,
|
|
||||||
mysteriousChest,
|
|
||||||
darkDeal,
|
|
||||||
fightOrFlight,
|
|
||||||
slumberingSnorlax,
|
|
||||||
trainingSession,
|
|
||||||
departmentStoreSale,
|
|
||||||
shadyVitaminDealer,
|
|
||||||
fieldTrip,
|
|
||||||
safariZone,
|
|
||||||
lostAtSea,
|
|
||||||
fieryFallout,
|
|
||||||
theStrongStuff,
|
|
||||||
pokemonSalesman,
|
|
||||||
offerYouCantRefuse,
|
|
||||||
delibirdy,
|
|
||||||
absoluteAvarice,
|
|
||||||
aTrainersTest,
|
|
||||||
trashToTreasure,
|
|
||||||
berriesAbound,
|
|
||||||
clowningAround,
|
|
||||||
partTimer,
|
|
||||||
dancingLessons,
|
|
||||||
weirdDream,
|
|
||||||
theWinstrateChallenge,
|
|
||||||
teleportingHijinks,
|
|
||||||
bugTypeSuperfan,
|
|
||||||
funAndGames,
|
|
||||||
uncommonBreed,
|
|
||||||
globalTradeSystem
|
|
||||||
} as const;
|
|
|
@ -166,7 +166,7 @@ export interface GeneratedPersistentModifierType {
|
||||||
getPregenArgs(): any[];
|
getPregenArgs(): any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AddPokeballModifierType extends ModifierType {
|
class AddPokeballModifierType extends ModifierType {
|
||||||
private pokeballType: PokeballType;
|
private pokeballType: PokeballType;
|
||||||
private count: integer;
|
private count: integer;
|
||||||
|
|
||||||
|
@ -647,6 +647,9 @@ export class BaseStatBoosterModifierType extends PokemonHeldItemModifierType imp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shuckle Juice item
|
||||||
|
*/
|
||||||
export class PokemonBaseStatTotalModifierType extends PokemonHeldItemModifierType implements GeneratedPersistentModifierType {
|
export class PokemonBaseStatTotalModifierType extends PokemonHeldItemModifierType implements GeneratedPersistentModifierType {
|
||||||
private readonly statModifier: integer;
|
private readonly statModifier: integer;
|
||||||
|
|
||||||
|
@ -655,7 +658,7 @@ export class PokemonBaseStatTotalModifierType extends PokemonHeldItemModifierTyp
|
||||||
this.statModifier = statModifier;
|
this.statModifier = statModifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDescription(scene: BattleScene): string {
|
override getDescription(scene: BattleScene): string {
|
||||||
return i18next.t("modifierType:ModifierType.PokemonBaseStatTotalModifierType.description", {
|
return i18next.t("modifierType:ModifierType.PokemonBaseStatTotalModifierType.description", {
|
||||||
increaseDecrease: i18next.t(this.statModifier >= 0 ? "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.increase" : "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.decrease"),
|
increaseDecrease: i18next.t(this.statModifier >= 0 ? "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.increase" : "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.decrease"),
|
||||||
blessCurse: i18next.t(this.statModifier >= 0 ? "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.blessed" : "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.cursed"),
|
blessCurse: i18next.t(this.statModifier >= 0 ? "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.blessed" : "modifierType:ModifierType.PokemonBaseStatTotalModifierType.extra.cursed"),
|
||||||
|
@ -663,11 +666,14 @@ export class PokemonBaseStatTotalModifierType extends PokemonHeldItemModifierTyp
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getPregenArgs(): any[] {
|
public getPregenArgs(): any[] {
|
||||||
return [ this.statModifier ];
|
return [ this.statModifier ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Old Gateau item
|
||||||
|
*/
|
||||||
export class PokemonBaseStatFlatModifierType extends PokemonHeldItemModifierType implements GeneratedPersistentModifierType {
|
export class PokemonBaseStatFlatModifierType extends PokemonHeldItemModifierType implements GeneratedPersistentModifierType {
|
||||||
private readonly statModifier: integer;
|
private readonly statModifier: integer;
|
||||||
private readonly stats: Stat[];
|
private readonly stats: Stat[];
|
||||||
|
@ -678,14 +684,14 @@ export class PokemonBaseStatFlatModifierType extends PokemonHeldItemModifierType
|
||||||
this.stats = stats;
|
this.stats = stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDescription(scene: BattleScene): string {
|
override getDescription(scene: BattleScene): string {
|
||||||
return i18next.t("modifierType:ModifierType.PokemonBaseStatFlatModifierType.description", {
|
return i18next.t("modifierType:ModifierType.PokemonBaseStatFlatModifierType.description", {
|
||||||
stats: this.stats.map(stat => i18next.t(getStatKey(stat))).join("/"),
|
stats: this.stats.map(stat => i18next.t(getStatKey(stat))).join("/"),
|
||||||
statValue: this.statModifier,
|
statValue: this.statModifier,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getPregenArgs(): any[] {
|
public getPregenArgs(): any[] {
|
||||||
return [ this.statModifier, this.stats ];
|
return [ this.statModifier, this.stats ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2118,6 +2124,14 @@ export function getPlayerModifierTypeOptions(count: integer, party: PlayerPokemo
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will generate a ModifierType from the ModifierPoolType.PLAYER pool, attempting to retry duplicated items up to retryCount
|
||||||
|
* @param existingOptions - currently generated options
|
||||||
|
* @param retryCount - how many times to retry before allowing a dupe item
|
||||||
|
* @param party - current player party, used to calculate items in the pool
|
||||||
|
* @param tier - If specified will generate item of tier
|
||||||
|
* @param allowLuckUpgrades - allow items to upgrade tiers (the little animation that plays and is affected by luck)
|
||||||
|
*/
|
||||||
function getModifierTypeOptionWithRetry(existingOptions: ModifierTypeOption[], retryCount: integer, party: PlayerPokemon[], tier?: ModifierTier, allowLuckUpgrades?: boolean): ModifierTypeOption {
|
function getModifierTypeOptionWithRetry(existingOptions: ModifierTypeOption[], retryCount: integer, party: PlayerPokemon[], tier?: ModifierTier, allowLuckUpgrades?: boolean): ModifierTypeOption {
|
||||||
allowLuckUpgrades = allowLuckUpgrades ?? true;
|
allowLuckUpgrades = allowLuckUpgrades ?? true;
|
||||||
let candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, tier, undefined, 0, allowLuckUpgrades);
|
let candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, tier, undefined, 0, allowLuckUpgrades);
|
||||||
|
@ -2253,6 +2267,15 @@ export function getDailyRunStarterModifiers(party: PlayerPokemon[]): Modifiers.P
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a ModifierType from the specified pool
|
||||||
|
* @param party - party of the trainer using the item
|
||||||
|
* @param poolType - PLAYER/WILD/TRAINER
|
||||||
|
* @param tier - If specified, will override the initial tier of an item (can still upgrade with luck)
|
||||||
|
* @param upgradeCount - If defined, means that this is a new ModifierType being generated to override another via luck upgrade. Used for recursive logic
|
||||||
|
* @param retryCount - Max allowed tries before the next tier down is checked for a valid ModifierType
|
||||||
|
* @param allowLuckUpgrades - Default true. If false, will not allow ModifierType to randomly upgrade to next tier
|
||||||
|
*/
|
||||||
function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, tier?: ModifierTier, upgradeCount?: integer, retryCount: integer = 0, allowLuckUpgrades: boolean = true): ModifierTypeOption | null {
|
function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, tier?: ModifierTier, upgradeCount?: integer, retryCount: integer = 0, allowLuckUpgrades: boolean = true): ModifierTypeOption | null {
|
||||||
const player = !poolType;
|
const player = !poolType;
|
||||||
const pool = getModifierPoolForType(poolType);
|
const pool = getModifierPoolForType(poolType);
|
||||||
|
|
|
@ -833,6 +833,9 @@ export class BaseStatModifier extends PokemonHeldItemModifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently used by Shuckle Juice item
|
||||||
|
*/
|
||||||
export class PokemonBaseStatTotalModifier extends PokemonHeldItemModifier {
|
export class PokemonBaseStatTotalModifier extends PokemonHeldItemModifier {
|
||||||
private statModifier: integer;
|
private statModifier: integer;
|
||||||
readonly isTransferrable: boolean = false;
|
readonly isTransferrable: boolean = false;
|
||||||
|
@ -842,23 +845,23 @@ export class PokemonBaseStatTotalModifier extends PokemonHeldItemModifier {
|
||||||
this.statModifier = statModifier;
|
this.statModifier = statModifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
matchType(modifier: Modifier): boolean {
|
override matchType(modifier: Modifier): boolean {
|
||||||
return modifier instanceof PokemonBaseStatTotalModifier;
|
return modifier instanceof PokemonBaseStatTotalModifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
clone(): PersistentModifier {
|
override clone(): PersistentModifier {
|
||||||
return new PokemonBaseStatTotalModifier(this.type as ModifierTypes.PokemonBaseStatTotalModifierType, this.pokemonId, this.statModifier, this.stackCount);
|
return new PokemonBaseStatTotalModifier(this.type as ModifierTypes.PokemonBaseStatTotalModifierType, this.pokemonId, this.statModifier, this.stackCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
getArgs(): any[] {
|
override getArgs(): any[] {
|
||||||
return super.getArgs().concat(this.statModifier);
|
return super.getArgs().concat(this.statModifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldApply(args: any[]): boolean {
|
override shouldApply(args: any[]): boolean {
|
||||||
return super.shouldApply(args) && args.length === 2 && args[1] instanceof Array;
|
return super.shouldApply(args) && args.length === 2 && args[1] instanceof Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(args: any[]): boolean {
|
override apply(args: any[]): boolean {
|
||||||
// Modifies the passed in baseStats[] array
|
// Modifies the passed in baseStats[] array
|
||||||
args[1].forEach((v, i) => {
|
args[1].forEach((v, i) => {
|
||||||
// HP is affected by half as much as other stats
|
// HP is affected by half as much as other stats
|
||||||
|
@ -869,15 +872,18 @@ export class PokemonBaseStatTotalModifier extends PokemonHeldItemModifier {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getScoreMultiplier(): number {
|
override getScoreMultiplier(): number {
|
||||||
return 1.2;
|
return 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMaxHeldItemCount(pokemon: Pokemon): integer {
|
override getMaxHeldItemCount(pokemon: Pokemon): integer {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently used by Old Gateau item
|
||||||
|
*/
|
||||||
export class PokemonBaseStatFlatModifier extends PokemonHeldItemModifier {
|
export class PokemonBaseStatFlatModifier extends PokemonHeldItemModifier {
|
||||||
private statModifier: integer;
|
private statModifier: integer;
|
||||||
private stats: Stat[];
|
private stats: Stat[];
|
||||||
|
@ -890,23 +896,23 @@ export class PokemonBaseStatFlatModifier extends PokemonHeldItemModifier {
|
||||||
this.stats = stats;
|
this.stats = stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
matchType(modifier: Modifier): boolean {
|
override matchType(modifier: Modifier): boolean {
|
||||||
return modifier instanceof PokemonBaseStatFlatModifier;
|
return modifier instanceof PokemonBaseStatFlatModifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
clone(): PersistentModifier {
|
override clone(): PersistentModifier {
|
||||||
return new PokemonBaseStatFlatModifier(this.type, this.pokemonId, this.statModifier, this.stats, this.stackCount);
|
return new PokemonBaseStatFlatModifier(this.type, this.pokemonId, this.statModifier, this.stats, this.stackCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
getArgs(): any[] {
|
override getArgs(): any[] {
|
||||||
return super.getArgs().concat(this.statModifier, this.stats);
|
return super.getArgs().concat(this.statModifier, this.stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldApply(args: any[]): boolean {
|
override shouldApply(args: any[]): boolean {
|
||||||
return super.shouldApply(args) && args.length === 2 && args[1] instanceof Array;
|
return super.shouldApply(args) && args.length === 2 && args[1] instanceof Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(args: any[]): boolean {
|
override apply(args: any[]): boolean {
|
||||||
// Modifies the passed in baseStats[] array by a flat value, only if the stat is specified in this.stats
|
// Modifies the passed in baseStats[] array by a flat value, only if the stat is specified in this.stats
|
||||||
args[1].forEach((v, i) => {
|
args[1].forEach((v, i) => {
|
||||||
if (this.stats.includes(i)) {
|
if (this.stats.includes(i)) {
|
||||||
|
@ -918,15 +924,18 @@ export class PokemonBaseStatFlatModifier extends PokemonHeldItemModifier {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getScoreMultiplier(): number {
|
override getScoreMultiplier(): number {
|
||||||
return 1.1;
|
return 1.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMaxHeldItemCount(pokemon: Pokemon): integer {
|
override getMaxHeldItemCount(pokemon: Pokemon): integer {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently used by Macho Brace item
|
||||||
|
*/
|
||||||
export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier {
|
export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier {
|
||||||
readonly isTransferrable: boolean = false;
|
readonly isTransferrable: boolean = false;
|
||||||
|
|
||||||
|
@ -2500,6 +2509,9 @@ export class LockModifierTiersModifier extends PersistentModifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Black Sludge item
|
||||||
|
*/
|
||||||
export class HealShopCostModifier extends PersistentModifier {
|
export class HealShopCostModifier extends PersistentModifier {
|
||||||
constructor(type: ModifierType, stackCount?: integer) {
|
constructor(type: ModifierType, stackCount?: integer) {
|
||||||
super(type, stackCount);
|
super(type, stackCount);
|
||||||
|
|
|
@ -99,7 +99,7 @@ export class EncounterPhase extends BattlePhase {
|
||||||
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 with 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) && randSeedInt(10) === 0) {
|
||||||
enemySpecies = getGoldenBugNetSpecies(this.scene, battle.waveIndex, level);
|
enemySpecies = getGoldenBugNetSpecies();
|
||||||
}
|
}
|
||||||
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) {
|
||||||
|
@ -433,7 +433,7 @@ export class EncounterPhase extends BattlePhase {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.scene.currentBattle.battleType !== BattleType.TRAINER && this.scene.currentBattle.battleType !== BattleType.MYSTERY_ENCOUNTER) {
|
if (![BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.scene.currentBattle.battleType)) {
|
||||||
enemyField.map(p => this.scene.pushConditionalPhase(new PostSummonPhase(this.scene, p.getBattlerIndex()), () => {
|
enemyField.map(p => this.scene.pushConditionalPhase(new PostSummonPhase(this.scene, p.getBattlerIndex()), () => {
|
||||||
// if there is not a player party, we can't continue
|
// if there is not a player party, we can't continue
|
||||||
if (!this.scene.getParty()?.length) {
|
if (!this.scene.getParty()?.length) {
|
||||||
|
|
|
@ -108,7 +108,7 @@ export class FaintPhase extends PokemonPhase {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.scene.unshiftPhase(new VictoryPhase(this.scene, this.battlerIndex));
|
this.scene.unshiftPhase(new VictoryPhase(this.scene, this.battlerIndex));
|
||||||
if (this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER) {
|
if ([BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.scene.currentBattle.battleType)) {
|
||||||
const hasReservePartyMember = !!this.scene.getEnemyParty().filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot).length;
|
const hasReservePartyMember = !!this.scene.getEnemyParty().filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot).length;
|
||||||
if (hasReservePartyMember) {
|
if (hasReservePartyMember) {
|
||||||
this.scene.pushPhase(new SwitchSummonPhase(this.scene, this.fieldIndex, -1, false, false, false));
|
this.scene.pushPhase(new SwitchSummonPhase(this.scene, this.fieldIndex, -1, false, false, false));
|
||||||
|
|
|
@ -7,7 +7,6 @@ import MysteryEncounterOption, { OptionPhaseCallback } from "../data/mystery-enc
|
||||||
import { getCharVariantFromDialogue } from "../data/dialogue";
|
import { getCharVariantFromDialogue } from "../data/dialogue";
|
||||||
import { TrainerSlot } from "../data/trainer-config";
|
import { TrainerSlot } from "../data/trainer-config";
|
||||||
import { BattleSpec } from "#enums/battle-spec";
|
import { BattleSpec } from "#enums/battle-spec";
|
||||||
import { Tutorial, handleTutorial } from "../tutorial";
|
|
||||||
import { IvScannerModifier } from "../modifier/modifier";
|
import { IvScannerModifier } from "../modifier/modifier";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { isNullOrUndefined } from "../utils";
|
import { isNullOrUndefined } from "../utils";
|
||||||
|
@ -50,6 +49,9 @@ export class MysteryEncounterPhase extends Phase {
|
||||||
this.optionSelectSettings = optionSelectSettings;
|
this.optionSelectSettings = optionSelectSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates seed offset, sets seen encounter session data, sets UI mode
|
||||||
|
*/
|
||||||
start() {
|
start() {
|
||||||
super.start();
|
super.start();
|
||||||
|
|
||||||
|
@ -70,6 +72,11 @@ export class MysteryEncounterPhase extends Phase {
|
||||||
this.scene.ui.setMode(Mode.MYSTERY_ENCOUNTER, this.optionSelectSettings);
|
this.scene.ui.setMode(Mode.MYSTERY_ENCOUNTER, this.optionSelectSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers after a player selects an option for the encounter
|
||||||
|
* @param option
|
||||||
|
* @param index
|
||||||
|
*/
|
||||||
handleOptionSelect(option: MysteryEncounterOption, index: number): boolean {
|
handleOptionSelect(option: MysteryEncounterOption, index: number): boolean {
|
||||||
// Set option selected flag
|
// Set option selected flag
|
||||||
this.scene.currentBattle.mysteryEncounter!.selectedOption = option;
|
this.scene.currentBattle.mysteryEncounter!.selectedOption = option;
|
||||||
|
@ -106,6 +113,9 @@ export class MysteryEncounterPhase extends Phase {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queues MysteryEncounterOptionSelectedPhase, displays option.selected dialogue and ends phase
|
||||||
|
*/
|
||||||
continueEncounter() {
|
continueEncounter() {
|
||||||
const endDialogueAndContinueEncounter = () => {
|
const endDialogueAndContinueEncounter = () => {
|
||||||
this.scene.pushPhase(new MysteryEncounterOptionSelectedPhase(this.scene));
|
this.scene.pushPhase(new MysteryEncounterOptionSelectedPhase(this.scene));
|
||||||
|
@ -141,10 +151,9 @@ export class MysteryEncounterPhase extends Phase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
/**
|
||||||
this.end();
|
* Ends phase
|
||||||
}
|
*/
|
||||||
|
|
||||||
end() {
|
end() {
|
||||||
this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end());
|
this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end());
|
||||||
}
|
}
|
||||||
|
@ -196,6 +205,9 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
|
||||||
super(scene);
|
super(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up TURN_END tags, any PostTurnEffectPhases, checks for Pokemon switches, then continues
|
||||||
|
*/
|
||||||
start() {
|
start() {
|
||||||
super.start();
|
super.start();
|
||||||
|
|
||||||
|
@ -231,7 +243,7 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
|
||||||
this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true));
|
this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
super.end();
|
this.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,13 +262,21 @@ export class MysteryEncounterBattlePhase extends Phase {
|
||||||
this.disableSwitch = disableSwitch;
|
this.disableSwitch = disableSwitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up a ME battle
|
||||||
|
*/
|
||||||
start() {
|
start() {
|
||||||
super.start();
|
super.start();
|
||||||
|
|
||||||
this.doMysteryEncounterBattle(this.scene);
|
this.doMysteryEncounterBattle(this.scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBattleMessage(scene: BattleScene): string {
|
/**
|
||||||
|
* Gets intro battle message for new battle
|
||||||
|
* @param scene
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private getBattleMessage(scene: BattleScene): string {
|
||||||
const enemyField = scene.getEnemyField();
|
const enemyField = scene.getEnemyField();
|
||||||
const encounterMode = scene.currentBattle.mysteryEncounter!.encounterMode;
|
const encounterMode = scene.currentBattle.mysteryEncounter!.encounterMode;
|
||||||
|
|
||||||
|
@ -278,7 +298,12 @@ export class MysteryEncounterBattlePhase extends Phase {
|
||||||
: i18next.t("battle:multiWildAppeared", { pokemonName1: enemyField[0].name, pokemonName2: enemyField[1].name });
|
: i18next.t("battle:multiWildAppeared", { pokemonName1: enemyField[0].name, pokemonName2: enemyField[1].name });
|
||||||
}
|
}
|
||||||
|
|
||||||
doMysteryEncounterBattle(scene: BattleScene) {
|
/**
|
||||||
|
* Queues SummonPhases for the new battle, and handles trainer animations/dialogue if Trainer battle
|
||||||
|
* @param scene
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private doMysteryEncounterBattle(scene: BattleScene) {
|
||||||
const encounterMode = scene.currentBattle.mysteryEncounter!.encounterMode;
|
const encounterMode = scene.currentBattle.mysteryEncounter!.encounterMode;
|
||||||
if (encounterMode === MysteryEncounterMode.WILD_BATTLE || encounterMode === MysteryEncounterMode.BOSS_BATTLE) {
|
if (encounterMode === MysteryEncounterMode.WILD_BATTLE || encounterMode === MysteryEncounterMode.BOSS_BATTLE) {
|
||||||
// Summons the wild/boss Pokemon
|
// Summons the wild/boss Pokemon
|
||||||
|
@ -342,7 +367,12 @@ export class MysteryEncounterBattlePhase extends Phase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
endBattleSetup(scene: BattleScene) {
|
/**
|
||||||
|
* Initiate SummonPhases, scanner phases, PostSummon phases, etc.
|
||||||
|
* @param scene
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private endBattleSetup(scene: BattleScene) {
|
||||||
const enemyField = scene.getEnemyField();
|
const enemyField = scene.getEnemyField();
|
||||||
const encounterMode = scene.currentBattle.mysteryEncounter!.encounterMode;
|
const encounterMode = scene.currentBattle.mysteryEncounter!.encounterMode;
|
||||||
|
|
||||||
|
@ -385,11 +415,14 @@ export class MysteryEncounterBattlePhase extends Phase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove?
|
this.end();
|
||||||
handleTutorial(this.scene, Tutorial.Access_Menu).then(() => super.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showEnemyTrainer(): void {
|
/**
|
||||||
|
* Ease in enemy trainer
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private showEnemyTrainer(): void {
|
||||||
// Show enemy trainer
|
// Show enemy trainer
|
||||||
const trainer = this.scene.currentBattle.trainer;
|
const trainer = this.scene.currentBattle.trainer;
|
||||||
if (!trainer) {
|
if (!trainer) {
|
||||||
|
@ -413,7 +446,7 @@ export class MysteryEncounterBattlePhase extends Phase {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
hideEnemyTrainer(): void {
|
private hideEnemyTrainer(): void {
|
||||||
this.scene.tweens.add({
|
this.scene.tweens.add({
|
||||||
targets: this.scene.currentBattle.trainer,
|
targets: this.scene.currentBattle.trainer,
|
||||||
x: "+=16",
|
x: "+=16",
|
||||||
|
@ -444,6 +477,9 @@ export class MysteryEncounterRewardsPhase extends Phase {
|
||||||
this.addHealPhase = addHealPhase;
|
this.addHealPhase = addHealPhase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs {@link MysteryEncounter.doContinueEncounter} and ends phase, OR {@link MysteryEncounter.onRewards} then continues encounter
|
||||||
|
*/
|
||||||
start() {
|
start() {
|
||||||
super.start();
|
super.start();
|
||||||
const encounter = this.scene.currentBattle.mysteryEncounter!;
|
const encounter = this.scene.currentBattle.mysteryEncounter!;
|
||||||
|
@ -466,6 +502,9 @@ export class MysteryEncounterRewardsPhase extends Phase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queues encounter EXP and rewards phases, PostMysteryEncounterPhase, and ends phase
|
||||||
|
*/
|
||||||
doEncounterRewardsAndContinue() {
|
doEncounterRewardsAndContinue() {
|
||||||
const encounter = this.scene.currentBattle.mysteryEncounter!;
|
const encounter = this.scene.currentBattle.mysteryEncounter!;
|
||||||
|
|
||||||
|
@ -501,6 +540,9 @@ export class PostMysteryEncounterPhase extends Phase {
|
||||||
this.onPostOptionSelect = this.scene.currentBattle.mysteryEncounter?.selectedOption?.onPostOptionPhase;
|
this.onPostOptionSelect = this.scene.currentBattle.mysteryEncounter?.selectedOption?.onPostOptionPhase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs {@link MysteryEncounter.onPostOptionSelect} then continues encounter
|
||||||
|
*/
|
||||||
start() {
|
start() {
|
||||||
super.start();
|
super.start();
|
||||||
|
|
||||||
|
@ -518,6 +560,9 @@ export class PostMysteryEncounterPhase extends Phase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queues NewBattlePhase, plays outro dialogue and ends phase
|
||||||
|
*/
|
||||||
continueEncounter() {
|
continueEncounter() {
|
||||||
const endPhase = () => {
|
const endPhase = () => {
|
||||||
this.scene.pushPhase(new NewBattlePhase(this.scene));
|
this.scene.pushPhase(new NewBattlePhase(this.scene));
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import BattleScene from "#app/battle-scene.js";
|
import BattleScene from "#app/battle-scene";
|
||||||
import { Phase } from "#app/phase";
|
import { Phase } from "#app/phase";
|
||||||
|
|
||||||
export class PartyExpPhase extends Phase {
|
export class PartyExpPhase extends Phase {
|
||||||
|
|
|
@ -232,7 +232,7 @@ export class SummonPhase extends PartyMemberPokemonPhase {
|
||||||
|
|
||||||
pokemon.resetTurnData();
|
pokemon.resetTurnData();
|
||||||
|
|
||||||
if (!this.loaded || this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER || (this.scene.currentBattle.waveIndex % 10) === 1) {
|
if (!this.loaded || [BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.scene.currentBattle.battleType) || (this.scene.currentBattle.waveIndex % 10) === 1) {
|
||||||
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
|
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
|
||||||
this.queuePostSummon();
|
this.queuePostSummon();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import BattleScene from "#app/battle-scene";
|
import BattleScene from "#app/battle-scene";
|
||||||
import { applyPreWeatherEffectAbAttrs, SuppressWeatherEffectAbAttr, PreWeatherDamageAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPostWeatherLapseAbAttrs, PostWeatherLapseAbAttr } from "#app/data/ability.js";
|
import { applyPreWeatherEffectAbAttrs, SuppressWeatherEffectAbAttr, PreWeatherDamageAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPostWeatherLapseAbAttrs, PostWeatherLapseAbAttr } from "#app/data/ability";
|
||||||
import { CommonAnim } from "#app/data/battle-anims";
|
import { CommonAnim } from "#app/data/battle-anims";
|
||||||
import { Weather, getWeatherDamageMessage, getWeatherLapseMessage } from "#app/data/weather";
|
import { Weather, getWeatherDamageMessage, getWeatherLapseMessage } from "#app/data/weather";
|
||||||
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { LostAtSeaEncounter } from "#app/data/mystery-encounters/encounters/lost-at-sea-encounter";
|
import { LostAtSeaEncounter } from "#app/data/mystery-encounters/encounters/lost-at-sea-encounter";
|
||||||
import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters";
|
import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters";
|
||||||
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import { getPokemonSpecies } from "#app/data/pokemon-species.js";
|
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||||
import { Biome } from "#app/enums/biome";
|
import { Biome } from "#app/enums/biome";
|
||||||
import { Moves } from "#app/enums/moves";
|
import { Moves } from "#app/enums/moves";
|
||||||
import { MysteryEncounterType } from "#app/enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#app/enums/mystery-encounter-type";
|
||||||
|
|
|
@ -94,6 +94,9 @@ export default class GameManager {
|
||||||
this.challengeMode = new ChallengeModeHelper(this);
|
this.challengeMode = new ChallengeModeHelper(this);
|
||||||
this.settings = new SettingsHelper(this);
|
this.settings = new SettingsHelper(this);
|
||||||
this.reload = new ReloadHelper(this);
|
this.reload = new ReloadHelper(this);
|
||||||
|
|
||||||
|
// Disables Mystery Encounters on all tests (can be overridden at test level)
|
||||||
|
this.override.mysteryEncounterChance(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -96,7 +96,7 @@ export function getMovePosition(scene: BattleScene, pokemonIndex: 0 | 1, move: M
|
||||||
* @param scene
|
* @param scene
|
||||||
* @param species
|
* @param species
|
||||||
*/
|
*/
|
||||||
export function initSceneWithoutEncounterPhase(scene, species?: Species[]) {
|
export function initSceneWithoutEncounterPhase(scene: BattleScene, species?: Species[]) {
|
||||||
const starters = generateStarter(scene, species);
|
const starters = generateStarter(scene, species);
|
||||||
starters.forEach((starter) => {
|
starters.forEach((starter) => {
|
||||||
const starterProps = scene.gameData.getSpeciesDexAttrProps(starter.species, starter.dexAttr);
|
const starterProps = scene.gameData.getSpeciesDexAttrProps(starter.species, starter.dexAttr);
|
||||||
|
@ -104,7 +104,7 @@ export function initSceneWithoutEncounterPhase(scene, species?: Species[]) {
|
||||||
const starterGender = Gender.MALE;
|
const starterGender = Gender.MALE;
|
||||||
const starterIvs = scene.gameData.dexData[starter.species.speciesId].ivs.slice(0);
|
const starterIvs = scene.gameData.dexData[starter.species.speciesId].ivs.slice(0);
|
||||||
const starterPokemon = scene.addPlayerPokemon(starter.species, scene.gameMode.getStartingLevel(), starter.abilityIndex, starterFormIndex, starterGender, starterProps.shiny, starterProps.variant, starterIvs, starter.nature);
|
const starterPokemon = scene.addPlayerPokemon(starter.species, scene.gameMode.getStartingLevel(), starter.abilityIndex, starterFormIndex, starterGender, starterProps.shiny, starterProps.variant, starterIvs, starter.nature);
|
||||||
starterPokemon.tryPopulateMoveset(starter.moveset);
|
starter.moveset && starterPokemon.tryPopulateMoveset(starter.moveset);
|
||||||
scene.getParty().push(starterPokemon);
|
scene.getParty().push(starterPokemon);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import * as GameMode from "#app/game-mode";
|
||||||
import { GameModes, getGameMode } from "#app/game-mode";
|
import { GameModes, getGameMode } from "#app/game-mode";
|
||||||
import { ModifierOverride } from "#app/modifier/modifier-type";
|
import { ModifierOverride } from "#app/modifier/modifier-type";
|
||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import { MockInstance, vi } from "vitest";
|
import { vi } from "vitest";
|
||||||
import { GameManagerHelper } from "./gameManagerHelper";
|
import { GameManagerHelper } from "./gameManagerHelper";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
|
@ -333,9 +333,9 @@ export class OverridesHelper extends GameManagerHelper {
|
||||||
mysteryEncounterChance(percentage: number) {
|
mysteryEncounterChance(percentage: number) {
|
||||||
const maxRate: number = 256; // 100%
|
const maxRate: number = 256; // 100%
|
||||||
const rate = maxRate * (percentage / 100);
|
const rate = maxRate * (percentage / 100);
|
||||||
const spy = vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_RATE_OVERRIDE", "get").mockReturnValue(rate);
|
vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_RATE_OVERRIDE", "get").mockReturnValue(rate);
|
||||||
this.log(`Mystery encounter chance set to ${percentage}% (=${rate})!`);
|
this.log(`Mystery encounter chance set to ${percentage}% (=${rate})!`);
|
||||||
return spy;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -343,10 +343,10 @@ export class OverridesHelper extends GameManagerHelper {
|
||||||
* @returns spy instance
|
* @returns spy instance
|
||||||
* @param tier
|
* @param tier
|
||||||
*/
|
*/
|
||||||
mysteryEncounterTier(tier: MysteryEncounterTier): MockInstance {
|
mysteryEncounterTier(tier: MysteryEncounterTier) {
|
||||||
const spy = vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_TIER_OVERRIDE", "get").mockReturnValue(tier);
|
vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_TIER_OVERRIDE", "get").mockReturnValue(tier);
|
||||||
this.log(`Mystery encounter tier set to ${tier}!`);
|
this.log(`Mystery encounter tier set to ${tier}!`);
|
||||||
return spy;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -355,9 +355,9 @@ export class OverridesHelper extends GameManagerHelper {
|
||||||
* @returns spy instance
|
* @returns spy instance
|
||||||
*/
|
*/
|
||||||
mysteryEncounter(encounterType: MysteryEncounterType) {
|
mysteryEncounter(encounterType: MysteryEncounterType) {
|
||||||
const spy = vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_OVERRIDE", "get").mockReturnValue(encounterType);
|
vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_OVERRIDE", "get").mockReturnValue(encounterType);
|
||||||
this.log(`Mystery encounter override set to ${encounterType}!`);
|
this.log(`Mystery encounter override set to ${encounterType}!`);
|
||||||
return spy;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private log(...params: any[]) {
|
private log(...params: any[]) {
|
||||||
|
|
|
@ -14,7 +14,7 @@ export default class MockContainer implements MockGameObject {
|
||||||
public frame;
|
public frame;
|
||||||
protected textureManager;
|
protected textureManager;
|
||||||
public list: MockGameObject[] = [];
|
public list: MockGameObject[] = [];
|
||||||
name: string;
|
public name: string;
|
||||||
|
|
||||||
constructor(textureManager: MockTextureManager, x, y) {
|
constructor(textureManager: MockTextureManager, x, y) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
|
@ -36,9 +36,7 @@ export default class MockContainer implements MockGameObject {
|
||||||
// same as remove or destroy
|
// same as remove or destroy
|
||||||
}
|
}
|
||||||
|
|
||||||
removeBetween(startIndex, endIndex, destroyChild) {
|
removeBetween = vi.fn((startIndex, endIndex, destroyChild) => {});
|
||||||
// Removes multiple children across an index range
|
|
||||||
}
|
|
||||||
|
|
||||||
addedToScene() {
|
addedToScene() {
|
||||||
// This callback is invoked when this Game Object is added to a Scene.
|
// This callback is invoked when this Game Object is added to a Scene.
|
||||||
|
@ -156,9 +154,7 @@ export default class MockContainer implements MockGameObject {
|
||||||
// Sends this Game Object to the back of its parent's display list.
|
// Sends this Game Object to the back of its parent's display list.
|
||||||
}
|
}
|
||||||
|
|
||||||
moveTo(obj) {
|
moveTo = vi.fn((obj) => {});
|
||||||
// Moves this Game Object to the given index in the list.
|
|
||||||
}
|
|
||||||
|
|
||||||
moveAbove(obj) {
|
moveAbove(obj) {
|
||||||
// Moves this Game Object to be above the given Game Object in the display list.
|
// Moves this Game Object to be above the given Game Object in the display list.
|
||||||
|
@ -215,9 +211,9 @@ export default class MockContainer implements MockGameObject {
|
||||||
return this.list;
|
return this.list;
|
||||||
}
|
}
|
||||||
|
|
||||||
getByName(key: string) {
|
getByName = vi.fn((key: string) => {
|
||||||
return this.list.find(v => v.name === key) ?? new MockContainer(this.textureManager, 0, 0);
|
return this.list.find(v => v.name === key) ?? new MockContainer(this.textureManager, 0, 0);
|
||||||
}
|
});
|
||||||
|
|
||||||
disableInteractive = vi.fn();
|
disableInteractive = vi.fn();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { MockGameObject } from "../mockGameObject";
|
||||||
export default class MockGraphics implements MockGameObject {
|
export default class MockGraphics implements MockGameObject {
|
||||||
private scene;
|
private scene;
|
||||||
public list: MockGameObject[] = [];
|
public list: MockGameObject[] = [];
|
||||||
name: string;
|
public name: string;
|
||||||
constructor(textureManager, config) {
|
constructor(textureManager, config) {
|
||||||
this.scene = textureManager.scene;
|
this.scene = textureManager.scene;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ export default class MockRectangle implements MockGameObject {
|
||||||
private fillColor;
|
private fillColor;
|
||||||
private scene;
|
private scene;
|
||||||
public list: MockGameObject[] = [];
|
public list: MockGameObject[] = [];
|
||||||
name: string;
|
public name: string;
|
||||||
|
|
||||||
constructor(textureManager, x, y, width, height, fillColor) {
|
constructor(textureManager, x, y, width, height, fillColor) {
|
||||||
this.fillColor = fillColor;
|
this.fillColor = fillColor;
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default class MockSprite implements MockGameObject {
|
||||||
public scene;
|
public scene;
|
||||||
public anims;
|
public anims;
|
||||||
public list: MockGameObject[] = [];
|
public list: MockGameObject[] = [];
|
||||||
name: string;
|
public name: string;
|
||||||
constructor(textureManager, x, y, texture) {
|
constructor(textureManager, x, y, texture) {
|
||||||
this.textureManager = textureManager;
|
this.textureManager = textureManager;
|
||||||
this.scene = textureManager.scene;
|
this.scene = textureManager.scene;
|
||||||
|
|
|
@ -11,7 +11,7 @@ export default class MockText implements MockGameObject {
|
||||||
public list: MockGameObject[] = [];
|
public list: MockGameObject[] = [];
|
||||||
public style;
|
public style;
|
||||||
public text = "";
|
public text = "";
|
||||||
name: string;
|
public name: string;
|
||||||
public color?: string;
|
public color?: string;
|
||||||
|
|
||||||
constructor(textureManager, x, y, content, styleOptions) {
|
constructor(textureManager, x, y, content, styleOptions) {
|
||||||
|
@ -80,19 +80,19 @@ export default class MockText implements MockGameObject {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
showText(text, delay, callback, callbackDelay, prompt, promptDelay) {
|
showText = vi.fn((text: string, delay?: integer | null, callback?: Function | null, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null) => {
|
||||||
this.scene.messageWrapper.showText(text, delay, callback, callbackDelay, prompt, promptDelay);
|
this.scene.messageWrapper.showText(text, delay, callback, callbackDelay, prompt, promptDelay);
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
showDialogue(text, name, delay, callback, callbackDelay, promptDelay) {
|
showDialogue = vi.fn((keyOrText: string, name: string | undefined, delay: integer | null = 0, callback: Function, callbackDelay?: integer, promptDelay?: integer) => {
|
||||||
this.scene.messageWrapper.showDialogue(text, name, delay, callback, callbackDelay, promptDelay);
|
this.scene.messageWrapper.showDialogue(keyOrText, name, delay, callback, callbackDelay, promptDelay);
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
setScale(scale) {
|
setScale(scale) {
|
||||||
// return this.phaserText.setScale(scale);
|
// return this.phaserText.setScale(scale);
|
||||||
|
@ -257,13 +257,9 @@ export default class MockText implements MockGameObject {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
disableInteractive() {
|
disableInteractive = vi.fn();
|
||||||
// Disables interaction with this Game Object.
|
|
||||||
}
|
|
||||||
|
|
||||||
clearTint() {
|
clearTint = vi.fn();
|
||||||
// Clears tint on this Game Object.
|
|
||||||
}
|
|
||||||
|
|
||||||
add(obj) {
|
add(obj) {
|
||||||
// Adds a child to this Game Object.
|
// Adds a child to this Game Object.
|
||||||
|
|
|
@ -12,7 +12,7 @@ export default class MockTexture implements MockGameObject {
|
||||||
public source;
|
public source;
|
||||||
public frames: object;
|
public frames: object;
|
||||||
public firstFrame: string;
|
public firstFrame: string;
|
||||||
name: string;
|
public name: string;
|
||||||
|
|
||||||
constructor(manager, key: string, source) {
|
constructor(manager, key: string, source) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
|
|
|
@ -1,129 +0,0 @@
|
||||||
import { Weather, WeatherType } from "#app/data/weather";
|
|
||||||
import { Biome } from "#app/enums/biome";
|
|
||||||
import { MockInstance, vi } from "vitest";
|
|
||||||
import GameManager from "#test/utils/gameManager";
|
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
|
||||||
import * as GameMode from "#app/game-mode";
|
|
||||||
import { GameModes, getGameMode } from "#app/game-mode";
|
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
|
||||||
import Overrides from "#app/overrides";
|
|
||||||
import { ModifierOverride } from "#app/modifier/modifier-type";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to handle overrides in tests
|
|
||||||
*/
|
|
||||||
export class OverridesHelper {
|
|
||||||
game: GameManager;
|
|
||||||
constructor(game: GameManager) {
|
|
||||||
this.game = game;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override the encounter chance for a mystery encounter.
|
|
||||||
* @param percentage the encounter chance in %
|
|
||||||
* @returns spy instance
|
|
||||||
*/
|
|
||||||
mysteryEncounterChance(percentage: number) {
|
|
||||||
const maxRate: number = 256; // 100%
|
|
||||||
const rate = maxRate * (percentage / 100);
|
|
||||||
const spy = vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_RATE_OVERRIDE", "get").mockReturnValue(rate);
|
|
||||||
this.log(`Mystery encounter chance set to ${percentage}% (=${rate})!`);
|
|
||||||
return spy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override the encounter chance for a mystery encounter.
|
|
||||||
* @returns spy instance
|
|
||||||
* @param tier
|
|
||||||
*/
|
|
||||||
mysteryEncounterTier(tier: MysteryEncounterTier): MockInstance {
|
|
||||||
const spy = vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_TIER_OVERRIDE", "get").mockReturnValue(tier);
|
|
||||||
this.log(`Mystery encounter tier set to ${tier}!`);
|
|
||||||
return spy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override the encounter that spawns for the scene
|
|
||||||
* @param encounterType
|
|
||||||
* @returns spy instance
|
|
||||||
*/
|
|
||||||
mysteryEncounter(encounterType: MysteryEncounterType) {
|
|
||||||
const spy = vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_OVERRIDE", "get").mockReturnValue(encounterType);
|
|
||||||
this.log(`Mystery encounter override set to ${encounterType}!`);
|
|
||||||
return spy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override the starting biome
|
|
||||||
* @warning Any event listeners that are attached to [NewArenaEvent](events\battle-scene.ts) may need to be handled down the line
|
|
||||||
* @param biome the biome to set
|
|
||||||
*/
|
|
||||||
startingBiome(biome: Biome) {
|
|
||||||
this.game.scene.newArena(biome);
|
|
||||||
this.log(`Starting biome set to ${Biome[biome]} (=${biome})!`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override the starting wave (index)
|
|
||||||
* @param wave the wave (index) to set. Classic: `1`-`200`
|
|
||||||
* @returns spy instance
|
|
||||||
*/
|
|
||||||
startingWave(wave: number) {
|
|
||||||
const spy = vi.spyOn(Overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(wave);
|
|
||||||
this.log(`Starting wave set to ${wave}!`);
|
|
||||||
return spy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override each wave to have or not have standard trainer battles
|
|
||||||
* @returns spy instance
|
|
||||||
* @param disable - true
|
|
||||||
*/
|
|
||||||
disableTrainerWaves(disable: boolean): MockInstance {
|
|
||||||
const realFn = getGameMode;
|
|
||||||
const spy = vi.spyOn(GameMode, "getGameMode").mockImplementation((gameMode: GameModes) => {
|
|
||||||
const mode = realFn(gameMode);
|
|
||||||
mode.hasTrainers = !disable;
|
|
||||||
return mode;
|
|
||||||
});
|
|
||||||
this.log(`Standard trainer waves are ${disable? "disabled" : "enabled"}!`);
|
|
||||||
return spy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override the weather (type)
|
|
||||||
* @param type weather type to set
|
|
||||||
* @returns spy instance
|
|
||||||
*/
|
|
||||||
weather(type: WeatherType) {
|
|
||||||
const spy = vi.spyOn(Overrides, "WEATHER_OVERRIDE", "get").mockReturnValue(type);
|
|
||||||
this.log(`Weather set to ${Weather[type]} (=${type})!`);
|
|
||||||
return spy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override the seed
|
|
||||||
* @param seed the seed to set
|
|
||||||
* @returns spy instance
|
|
||||||
*/
|
|
||||||
seed(seed: string) {
|
|
||||||
const spy = vi.spyOn(this.game.scene, "resetSeed").mockImplementation(() => {
|
|
||||||
this.game.scene.waveSeed = seed;
|
|
||||||
Phaser.Math.RND.sow([seed]);
|
|
||||||
this.game.scene.rngCounter = 0;
|
|
||||||
});
|
|
||||||
this.game.scene.resetSeed();
|
|
||||||
this.log(`Seed set to "${seed}"!`);
|
|
||||||
return spy;
|
|
||||||
}
|
|
||||||
|
|
||||||
starterHeldItems(modifiers: ModifierOverride[]) {
|
|
||||||
const spy = vi.spyOn(Overrides, "STARTING_MODIFIER_OVERRIDE", "get").mockReturnValue(modifiers);
|
|
||||||
this.log(`Starting modifiers set to ${modifiers.map(m => JSON.stringify(m)).join(", ")}!`);
|
|
||||||
return spy;
|
|
||||||
}
|
|
||||||
|
|
||||||
private log(...params: any[]) {
|
|
||||||
console.log("Overrides:", ...params);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -50,16 +50,15 @@ import {
|
||||||
MysteryEncounterRewardsPhase,
|
MysteryEncounterRewardsPhase,
|
||||||
PostMysteryEncounterPhase
|
PostMysteryEncounterPhase
|
||||||
} from "#app/phases/mystery-encounter-phases";
|
} from "#app/phases/mystery-encounter-phases";
|
||||||
import { LearnMovePhase } from "#app/phases/learn-move-phase";
|
|
||||||
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
|
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
|
||||||
import { PartyExpPhase } from "#app/phases/party-exp-phase";
|
import { PartyExpPhase } from "#app/phases/party-exp-phase";
|
||||||
|
|
||||||
export interface PromptHandler {
|
export interface PromptHandler {
|
||||||
phaseTarget?;
|
phaseTarget?: string;
|
||||||
mode?;
|
mode?: Mode;
|
||||||
callback?;
|
callback?: () => void;
|
||||||
expireFn?;
|
expireFn?: () => void;
|
||||||
awaitingActionInput?;
|
awaitingActionInput?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class PhaseInterceptor {
|
export default class PhaseInterceptor {
|
||||||
|
@ -369,7 +368,10 @@ export default class PhaseInterceptor {
|
||||||
if (expireFn) {
|
if (expireFn) {
|
||||||
this.prompts.shift();
|
this.prompts.shift();
|
||||||
} else if (currentMode === actionForNextPrompt.mode && currentPhase === actionForNextPrompt.phaseTarget && currentHandler.active && (!actionForNextPrompt.awaitingActionInput || (actionForNextPrompt.awaitingActionInput && currentHandler.awaitingActionInput))) {
|
} else if (currentMode === actionForNextPrompt.mode && currentPhase === actionForNextPrompt.phaseTarget && currentHandler.active && (!actionForNextPrompt.awaitingActionInput || (actionForNextPrompt.awaitingActionInput && currentHandler.awaitingActionInput))) {
|
||||||
this.prompts.shift()?.callback();
|
const prompt = this.prompts.shift();
|
||||||
|
if (prompt?.callback) {
|
||||||
|
prompt.callback();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,8 +13,7 @@ import { initAchievements } from "#app/system/achv";
|
||||||
import { initVouchers } from "#app/system/voucher";
|
import { initVouchers } from "#app/system/voucher";
|
||||||
import { initStatsKeys } from "#app/ui/game-stats-ui-handler";
|
import { initStatsKeys } from "#app/ui/game-stats-ui-handler";
|
||||||
import { initMysteryEncounters } from "#app/data/mystery-encounters/mystery-encounters";
|
import { initMysteryEncounters } from "#app/data/mystery-encounters/mystery-encounters";
|
||||||
import { beforeAll, beforeEach, vi } from "vitest";
|
import { beforeAll, vi } from "vitest";
|
||||||
import Overrides from "#app/overrides";
|
|
||||||
|
|
||||||
/** Mock the override import to always return default values, ignoring any custom overrides. */
|
/** Mock the override import to always return default values, ignoring any custom overrides. */
|
||||||
vi.mock("#app/overrides", async (importOriginal) => {
|
vi.mock("#app/overrides", async (importOriginal) => {
|
||||||
|
@ -49,8 +48,3 @@ beforeAll(() => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Disables Mystery Encounters on all tests (can be overridden at test level)
|
|
||||||
beforeEach( () => {
|
|
||||||
vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_RATE_OVERRIDE", "get").mockReturnValue(0);
|
|
||||||
});
|
|
||||||
|
|
|
@ -122,7 +122,8 @@ export default class FightUiHandler extends UiHandler {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Cannot back out of fight menu if skipToFightInput is enabled
|
// Cannot back out of fight menu if skipToFightInput is enabled
|
||||||
if (this.scene.currentBattle.battleType !== BattleType.MYSTERY_ENCOUNTER || !this.scene.currentBattle.mysteryEncounter?.skipToFightInput) {
|
const { battleType, mysteryEncounter } = this.scene.currentBattle;
|
||||||
|
if (battleType !== BattleType.MYSTERY_ENCOUNTER || !mysteryEncounter?.skipToFightInput) {
|
||||||
ui.setMode(Mode.COMMAND, this.fieldIndex);
|
ui.setMode(Mode.COMMAND, this.fieldIndex);
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,8 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
|
||||||
if (delay === null || delay === undefined) {
|
if (delay === null || delay === undefined) {
|
||||||
delay = 20;
|
delay = 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pattern matching regex that checks for @c{}, @f{}, @s{}, and @f{} patterns within message text and parses them to their respective behaviors.
|
||||||
const charVarMap = new Map<integer, string>();
|
const charVarMap = new Map<integer, string>();
|
||||||
const delayMap = new Map<integer, integer>();
|
const delayMap = new Map<integer, integer>();
|
||||||
const soundMap = new Map<integer, string>();
|
const soundMap = new Map<integer, string>();
|
||||||
|
|
|
@ -22,7 +22,8 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
private cursorObj?: Phaser.GameObjects.Image;
|
private cursorObj?: Phaser.GameObjects.Image;
|
||||||
|
|
||||||
private optionsContainer: Phaser.GameObjects.Container;
|
private optionsContainer: Phaser.GameObjects.Container;
|
||||||
private optionScrollTweens: (Phaser.Tweens.Tween | null)[] = [null, null, null, null];
|
// Length = max number of allowable options (4)
|
||||||
|
private optionScrollTweens: (Phaser.Tweens.Tween | null)[] = new Array(4).fill(null);
|
||||||
|
|
||||||
private tooltipWindow: Phaser.GameObjects.NineSlice;
|
private tooltipWindow: Phaser.GameObjects.NineSlice;
|
||||||
private tooltipContainer: Phaser.GameObjects.Container;
|
private tooltipContainer: Phaser.GameObjects.Container;
|
||||||
|
@ -49,7 +50,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
super(scene, Mode.MYSTERY_ENCOUNTER);
|
super(scene, Mode.MYSTERY_ENCOUNTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
setup() {
|
override setup() {
|
||||||
const ui = this.getUi();
|
const ui = this.getUi();
|
||||||
|
|
||||||
this.cursorContainer = this.scene.add.container(18, -38.7);
|
this.cursorContainer = this.scene.add.container(18, -38.7);
|
||||||
|
@ -89,7 +90,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
this.dexProgressContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, 24, 28), Phaser.Geom.Rectangle.Contains);
|
this.dexProgressContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, 24, 28), Phaser.Geom.Rectangle.Contains);
|
||||||
}
|
}
|
||||||
|
|
||||||
show(args: any[]): boolean {
|
override show(args: any[]): boolean {
|
||||||
super.show(args);
|
super.show(args);
|
||||||
|
|
||||||
this.overrideSettings = args[0] as OptionSelectSettings ?? {};
|
this.overrideSettings = args[0] as OptionSelectSettings ?? {};
|
||||||
|
@ -119,7 +120,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
processInput(button: Button): boolean {
|
override processInput(button: Button): boolean {
|
||||||
const ui = this.getUi();
|
const ui = this.getUi();
|
||||||
|
|
||||||
let success = false;
|
let success = false;
|
||||||
|
@ -179,7 +180,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTwoOptionMoveInput(button: Button): boolean {
|
private handleTwoOptionMoveInput(button: Button): boolean {
|
||||||
let success = false;
|
let success = false;
|
||||||
const cursor = this.getCursor();
|
const cursor = this.getCursor();
|
||||||
switch (button) {
|
switch (button) {
|
||||||
|
@ -208,7 +209,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleThreeOptionMoveInput(button: Button): boolean {
|
private handleThreeOptionMoveInput(button: Button): boolean {
|
||||||
let success = false;
|
let success = false;
|
||||||
const cursor = this.getCursor();
|
const cursor = this.getCursor();
|
||||||
switch (button) {
|
switch (button) {
|
||||||
|
@ -245,7 +246,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFourOptionMoveInput(button: Button): boolean {
|
private handleFourOptionMoveInput(button: Button): boolean {
|
||||||
let success = false;
|
let success = false;
|
||||||
const cursor = this.getCursor();
|
const cursor = this.getCursor();
|
||||||
switch (button) {
|
switch (button) {
|
||||||
|
@ -282,6 +283,10 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When ME UI first displays, the option buttons will be disabled temporarily to prevent player accidentally clicking through hastily
|
||||||
|
* This method is automatically called after a short delay but can also be called manually
|
||||||
|
*/
|
||||||
unblockInput() {
|
unblockInput() {
|
||||||
if (this.blockInput) {
|
if (this.blockInput) {
|
||||||
this.blockInput = false;
|
this.blockInput = false;
|
||||||
|
@ -295,11 +300,11 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getCursor(): integer {
|
override getCursor(): integer {
|
||||||
return this.cursor ? this.cursor : 0;
|
return this.cursor ? this.cursor : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCursor(cursor: integer): boolean {
|
override setCursor(cursor: integer): boolean {
|
||||||
const prevCursor = this.getCursor();
|
const prevCursor = this.getCursor();
|
||||||
const changed = prevCursor !== cursor;
|
const changed = prevCursor !== cursor;
|
||||||
if (changed) {
|
if (changed) {
|
||||||
|
@ -480,7 +485,11 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
displayOptionTooltip() {
|
/**
|
||||||
|
* Updates and displays the tooltip for a given option
|
||||||
|
* The tooltip will auto wrap and scroll if it is too long
|
||||||
|
*/
|
||||||
|
private displayOptionTooltip() {
|
||||||
const cursor = this.getCursor();
|
const cursor = this.getCursor();
|
||||||
// Clear tooltip box
|
// Clear tooltip box
|
||||||
if (this.tooltipContainer.length > 1) {
|
if (this.tooltipContainer.length > 1) {
|
||||||
|
@ -553,7 +562,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clear(): void {
|
override clear(): void {
|
||||||
super.clear();
|
super.clear();
|
||||||
this.overrideSettings = undefined;
|
this.overrideSettings = undefined;
|
||||||
this.optionsContainer.setVisible(false);
|
this.optionsContainer.setVisible(false);
|
||||||
|
@ -567,7 +576,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
this.eraseCursor();
|
this.eraseCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
eraseCursor(): void {
|
private eraseCursor(): void {
|
||||||
if (this.cursorObj) {
|
if (this.cursorObj) {
|
||||||
this.cursorObj.destroy();
|
this.cursorObj.destroy();
|
||||||
}
|
}
|
||||||
|
@ -575,10 +584,10 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Will show or hide the Dex progress icon for an option that has dex progress
|
||||||
* @param show - if true does show, if false does hide
|
* @param show - if true does show, if false does hide
|
||||||
*/
|
*/
|
||||||
showHideDexProgress(show: boolean) {
|
private showHideDexProgress(show: boolean) {
|
||||||
if (show && !this.showDexProgress) {
|
if (show && !this.showDexProgress) {
|
||||||
this.showDexProgress = true;
|
this.showDexProgress = true;
|
||||||
this.scene.tweens.killTweensOf(this.dexProgressContainer);
|
this.scene.tweens.killTweensOf(this.dexProgressContainer);
|
||||||
|
|
|
@ -531,7 +531,6 @@ export default class PartyUiHandler extends MessageUiHandler {
|
||||||
return this.processInput(Button.CANCEL);
|
return this.processInput(Button.CANCEL);
|
||||||
} else if (option === PartyOption.SELECT) {
|
} else if (option === PartyOption.SELECT) {
|
||||||
ui.playSelect();
|
ui.playSelect();
|
||||||
// ui.setModeWithoutClear(Mode.SUMMARY, pokemon).then(() => this.clearOptions());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (button === Button.CANCEL) {
|
} else if (button === Button.CANCEL) {
|
||||||
|
|
|
@ -587,6 +587,10 @@ export function isNullOrUndefined(object: any): boolean {
|
||||||
return null === object || undefined === object;
|
return null === object || undefined === object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capitalizes the first letter of a string
|
||||||
|
* @param str
|
||||||
|
*/
|
||||||
export function capitalizeFirstLetter(str: string) {
|
export function capitalizeFirstLetter(str: string) {
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue