add unit tests for offer you can't refuse encounter
This commit is contained in:
parent
065ac0e779
commit
c2e5a58f59
|
@ -66,10 +66,12 @@ import { Species } from "#enums/species";
|
|||
import { UiTheme } from "#enums/ui-theme";
|
||||
import { TimedEventManager } from "#app/timed-event-manager.js";
|
||||
import i18next from "i18next";
|
||||
import IMysteryEncounter, { MysteryEncounterTier, MysteryEncounterVariant } from "./data/mystery-encounters/mystery-encounter";
|
||||
import IMysteryEncounter from "./data/mystery-encounters/mystery-encounter";
|
||||
import { allMysteryEncounters, AVERAGE_ENCOUNTERS_PER_RUN_TARGET, BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT, mysteryEncountersByBiome, WEIGHT_INCREMENT_ON_SPAWN_MISS } from "./data/mystery-encounters/mystery-encounters";
|
||||
import { MysteryEncounterData } from "#app/data/mystery-encounters/mystery-encounter-data";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
|
||||
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
|
||||
|
||||
|
@ -1184,7 +1186,7 @@ export default class BattleScene extends SceneBase {
|
|||
this.arena.removeAllTags();
|
||||
|
||||
// If last battle was mystery encounter and no battle occurred, skip return phases
|
||||
if (lastBattle?.mysteryEncounter?.encounterVariant !== MysteryEncounterVariant.NO_BATTLE) {
|
||||
if (lastBattle?.mysteryEncounter?.encounterMode !== MysteryEncounterMode.NO_BATTLE) {
|
||||
playerField.forEach((_, p) => this.unshiftPhase(new ReturnPhase(this, p)));
|
||||
|
||||
for (const pokemon of this.getParty()) {
|
||||
|
|
|
@ -14,7 +14,8 @@ import { PlayerGender } from "#enums/player-gender";
|
|||
import { Species } from "#enums/species";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import i18next from "#app/plugins/i18n";
|
||||
import IMysteryEncounter, { MysteryEncounterVariant } from "./data/mystery-encounters/mystery-encounter";
|
||||
import IMysteryEncounter from "./data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
|
||||
export enum BattleType {
|
||||
WILD,
|
||||
|
@ -205,7 +206,7 @@ export default class Battle {
|
|||
|
||||
getBgmOverride(scene: BattleScene): string {
|
||||
const battlers = this.enemyParty.slice(0, this.getBattlerCount());
|
||||
if (this.battleType === BattleType.TRAINER || this.mysteryEncounter?.encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE) {
|
||||
if (this.battleType === BattleType.TRAINER || this.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
|
||||
if (!this.started && this.trainer.config.encounterBgm && this.trainer.getEncounterMessages().length) {
|
||||
return `encounter_${this.trainer.getEncounterBgm()}`;
|
||||
}
|
||||
|
|
|
@ -3,13 +3,15 @@ import { ModifierRewardPhase } from "#app/phases";
|
|||
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { getPokemonSpecies } from "../../pokemon-species";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter";
|
||||
import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { EnemyPartyConfig, EnemyPokemonConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, } from "../utils/encounter-phase-utils";
|
||||
import { getRandomPlayerPokemon, getRandomSpeciesByStarterTier } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
/** i18n namespace for encounter */
|
||||
const namespace = "mysteryEncounter:darkDeal";
|
||||
|
@ -105,7 +107,7 @@ export const DarkDealEncounter: IMysteryEncounter =
|
|||
.withQuery(`${namespace}:query`)
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:1:label`,
|
||||
buttonTooltip: `${namespace}:option:1:tooltip`,
|
||||
|
|
|
@ -6,11 +6,11 @@ import { modifierTypes } from "#app/modifier/modifier-type";
|
|||
import { randSeedInt } from "#app/utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, {
|
||||
MysteryEncounterBuilder,
|
||||
MysteryEncounterTier,
|
||||
} from "../mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
|
||||
/** i18n namespace for encounter */
|
||||
const namespace = "mysteryEncounter:departmentStoreSale";
|
||||
|
|
|
@ -1,22 +1,15 @@
|
|||
import { MoveCategory } from "#app/data/move";
|
||||
import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import {
|
||||
generateModifierTypeOption,
|
||||
leaveEncounterWithoutBattle,
|
||||
selectPokemonForOption,
|
||||
setEncounterExp,
|
||||
setEncounterRewards,
|
||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { generateModifierTypeOption, leaveEncounterWithoutBattle, selectPokemonForOption, setEncounterExp, setEncounterRewards } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { TempBattleStat } from "#app/data/temp-battle-stat";
|
||||
import { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import IMysteryEncounter, {
|
||||
MysteryEncounterBuilder,
|
||||
MysteryEncounterTier,
|
||||
} from "../mystery-encounter";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
/** i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounter:fieldTrip";
|
||||
|
@ -62,7 +55,7 @@ export const FieldTripEncounter: IMysteryEncounter =
|
|||
.withQuery(`${namespace}:query`)
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:1:label`,
|
||||
buttonTooltip: `${namespace}:option:1:tooltip`,
|
||||
|
@ -88,7 +81,7 @@ export const FieldTripEncounter: IMysteryEncounter =
|
|||
encounter.options[0].dialogue.selected = [
|
||||
{
|
||||
text: `${namespace}:option:incorrect`,
|
||||
speaker: `${namespace}:option:speaker`,
|
||||
speaker: `${namespace}:speaker`,
|
||||
},
|
||||
{
|
||||
text: `${namespace}:option:lesson_learned`,
|
||||
|
@ -148,7 +141,7 @@ export const FieldTripEncounter: IMysteryEncounter =
|
|||
)
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:2:label`,
|
||||
buttonTooltip: `${namespace}:option:2:tooltip`,
|
||||
|
@ -174,7 +167,7 @@ export const FieldTripEncounter: IMysteryEncounter =
|
|||
encounter.options[1].dialogue.selected = [
|
||||
{
|
||||
text: `${namespace}:option:incorrect`,
|
||||
speaker: `${namespace}:option:speaker`,
|
||||
speaker: `${namespace}:speaker`,
|
||||
},
|
||||
{
|
||||
text: `${namespace}:option:lesson_learned`,
|
||||
|
@ -240,7 +233,7 @@ export const FieldTripEncounter: IMysteryEncounter =
|
|||
)
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:3:label`,
|
||||
buttonTooltip: `${namespace}:option:3:tooltip`,
|
||||
|
@ -266,7 +259,7 @@ export const FieldTripEncounter: IMysteryEncounter =
|
|||
encounter.options[2].dialogue.selected = [
|
||||
{
|
||||
text: `${namespace}:option:incorrect`,
|
||||
speaker: `${namespace}:option:speaker`,
|
||||
speaker: `${namespace}:speaker`,
|
||||
},
|
||||
{
|
||||
text: `${namespace}:option:lesson_learned`,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig, initCustomMovesForEncounter, leaveEncounterWithoutBattle, setEncounterExp, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { modifierTypes, } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { TypeRequirement } from "../mystery-encounter-requirements";
|
||||
import { Species } from "#enums/species";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
|
@ -18,6 +18,8 @@ import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
|||
import { StatusEffect } from "#app/data/status-effect";
|
||||
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { applyDamageToPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounter:fieryFallout";
|
||||
|
@ -202,7 +204,7 @@ export const FieryFalloutEncounter: IMysteryEncounter =
|
|||
)
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DISABLED_OR_SPECIAL)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
|
||||
.withPrimaryPokemonRequirement(new TypeRequirement(Type.FIRE, true, 1)) // Will set option3PrimaryName dialogue token automatically
|
||||
.withSecondaryPokemonRequirement(new TypeRequirement(Type.FIRE, true, 1)) // Will set option3SecondaryName dialogue token automatically
|
||||
.withDialogue({
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BattleStat } from "#app/data/battle-stat";
|
||||
import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import {
|
||||
EnemyPartyConfig,
|
||||
initBattleWithEnemyConfig,
|
||||
|
@ -20,14 +20,13 @@ import { StatChangePhase } from "#app/phases";
|
|||
import { randSeedInt } from "#app/utils";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import IMysteryEncounter, {
|
||||
MysteryEncounterBuilder,
|
||||
MysteryEncounterTier,
|
||||
} from "../mystery-encounter";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MoveRequirement } from "../mystery-encounter-requirements";
|
||||
import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounter:fightOrFlight";
|
||||
|
@ -132,7 +131,7 @@ export const FightOrFlightEncounter: IMysteryEncounter =
|
|||
)
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT_OR_SPECIAL)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT_OR_SPECIAL)
|
||||
.withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:2:label`,
|
||||
|
|
|
@ -2,11 +2,13 @@ import { getPokemonSpecies } from "#app/data/pokemon-species.js";
|
|||
import { Moves } from "#app/enums/moves";
|
||||
import { Species } from "#app/enums/species.js";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier } from "../mystery-encounter";
|
||||
import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { leaveEncounterWithoutBattle, setEncounterExp } from "../utils/encounter-phase-utils";
|
||||
import { applyDamageToPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
const OPTION_1_REQUIRED_MOVE = Moves.SURF;
|
||||
const OPTION_2_REQUIRED_MOVE = Moves.FLY;
|
||||
|
@ -53,7 +55,7 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||
// Option 1: Use a (non fainted) pokemon that can learn Surf to guide you back/
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withPokemonCanLearnMoveRequirement(OPTION_1_REQUIRED_MOVE)
|
||||
.withOptionMode(EncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:1:label`,
|
||||
disabledButtonLabel: `${namespace}:option:1:label_disabled`,
|
||||
|
@ -72,7 +74,7 @@ export const LostAtSeaEncounter: MysteryEncounter = MysteryEncounterBuilder.with
|
|||
//Option 2: Use a (non fainted) pokemon that can learn fly to guide you back.
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withPokemonCanLearnMoveRequirement(OPTION_2_REQUIRED_MOVE)
|
||||
.withOptionMode(EncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:2:label`,
|
||||
disabledButtonLabel: `${namespace}:option:2:label_disabled`,
|
||||
|
|
|
@ -13,12 +13,10 @@ import { ModifierTier } from "#app/modifier/modifier-tier";
|
|||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import * as Utils from "../../../utils";
|
||||
import IMysteryEncounter, {
|
||||
MysteryEncounterBuilder,
|
||||
MysteryEncounterTier,
|
||||
} from "../mystery-encounter";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import * as Utils from "#app/utils";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounter:mysteriousChallengers";
|
||||
|
|
|
@ -4,9 +4,11 @@ import { getHighestLevelPlayerPokemon, koPlayerPokemon } from "#app/data/mystery
|
|||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||
import { randSeedInt } from "#app/utils.js";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter";
|
||||
import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
/** i18n namespace for encounter */
|
||||
const namespace = "mysteryEncounter:mysteriousChest";
|
||||
|
@ -42,7 +44,7 @@ export const MysteriousChestEncounter: IMysteryEncounter =
|
|||
.withQuery(`${namespace}:query`)
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:1:label`,
|
||||
buttonTooltip: `${namespace}:option:1:tooltip`,
|
||||
|
|
|
@ -2,14 +2,16 @@ import { leaveEncounterWithoutBattle, setEncounterExp, updatePlayerMoney, } from
|
|||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter";
|
||||
import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { MoveRequirement } from "../mystery-encounter-requirements";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { AbilityRequirement, CombinationPokemonRequirement, MoveRequirement } from "../mystery-encounter-requirements";
|
||||
import { getHighestStatTotalPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { ModifierRewardPhase } from "#app/phases";
|
||||
import { EXTORTION_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
||||
import { EXTORTION_ABILITIES, EXTORTION_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
/** the i18n namespace for this encounter */
|
||||
const namespace = "mysteryEncounter:offerYouCantRefuse";
|
||||
|
@ -56,22 +58,36 @@ export const OfferYouCantRefuseEncounter: IMysteryEncounter =
|
|||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
.withOnInit((scene: BattleScene) => {
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
const pokemon = getHighestStatTotalPlayerPokemon(scene, false);
|
||||
const price = scene.getWaveMoneyAmount(10);
|
||||
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("strongestPokemon", pokemon.name);
|
||||
scene.currentBattle.mysteryEncounter.setDialogueToken("price", price.toString());
|
||||
encounter.setDialogueToken("strongestPokemon", pokemon.name);
|
||||
encounter.setDialogueToken("price", price.toString());
|
||||
|
||||
// Store pokemon and price
|
||||
scene.currentBattle.mysteryEncounter.misc = {
|
||||
encounter.misc = {
|
||||
pokemon: pokemon,
|
||||
price: price
|
||||
};
|
||||
|
||||
// If player meets the combo OR requirements for option 2, populate the token
|
||||
const opt2Req = encounter.options[1].primaryPokemonRequirements[0];
|
||||
if (opt2Req.meetsRequirement(scene)) {
|
||||
const abilityToken = encounter.dialogueTokens["option2PrimaryAbility"];
|
||||
const moveToken = encounter.dialogueTokens["option2PrimaryMove"];
|
||||
if (abilityToken) {
|
||||
encounter.setDialogueToken("moveOrAbility", abilityToken);
|
||||
} else if (moveToken) {
|
||||
encounter.setDialogueToken("moveOrAbility", moveToken);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:1:label`,
|
||||
buttonTooltip: `${namespace}:option:1:tooltip`,
|
||||
|
@ -98,14 +114,18 @@ export const OfferYouCantRefuseEncounter: IMysteryEncounter =
|
|||
)
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withPrimaryPokemonRequirement(new MoveRequirement(EXTORTION_MOVES))
|
||||
.withOptionMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
|
||||
.withPrimaryPokemonRequirement(new CombinationPokemonRequirement(
|
||||
new MoveRequirement(EXTORTION_MOVES),
|
||||
new AbilityRequirement(EXTORTION_ABILITIES))
|
||||
)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:2:label`,
|
||||
buttonTooltip: `${namespace}:option:2:tooltip`,
|
||||
disabledButtonTooltip: `${namespace}:option:2:tooltip_disabled`,
|
||||
selected: [
|
||||
{
|
||||
speaker: `${namespace}:speaker`,
|
||||
text: `${namespace}:option:2:selected`,
|
||||
},
|
||||
],
|
||||
|
@ -129,7 +149,7 @@ export const OfferYouCantRefuseEncounter: IMysteryEncounter =
|
|||
selected: [
|
||||
{
|
||||
speaker: `${namespace}:speaker`,
|
||||
text: `${namespace}:option:2:selected`,
|
||||
text: `${namespace}:option:3:selected`,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
import { leaveEncounterWithoutBattle, transitionMysteryEncounterIntroVisuals, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MoneyRequirement } from "../mystery-encounter-requirements";
|
||||
import { catchPokemon, getRandomSpeciesByStarterTier } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { getPokemonSpecies, speciesStarters } from "#app/data/pokemon-species";
|
||||
import { Species } from "#enums/species";
|
||||
import { PokeballType } from "#app/data/pokeball";
|
||||
import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon";
|
||||
import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { showEncounterDialogue } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import PokemonData from "#app/system/pokemon-data";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
/** the i18n namespace for this encounter */
|
||||
const namespace = "mysteryEncounter:pokemonSalesman";
|
||||
|
@ -104,7 +106,7 @@ export const PokemonSalesmanEncounter: IMysteryEncounter =
|
|||
})
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT_OR_SPECIAL)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT_OR_SPECIAL)
|
||||
.withHasDexProgress(true)
|
||||
.withSceneMoneyRequirement(null, MAX_POKEMON_PRICE_MULTIPLIER) // Wave scaling money multiplier of 2
|
||||
.withDialogue({
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { initSubsequentOptionSelect, leaveEncounterWithoutBattle, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, MysteryEncounterVariant } from "../mystery-encounter";
|
||||
import MysteryEncounterOption, { EncounterOptionMode, MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import MysteryEncounterOption, { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { TrainerSlot } from "#app/data/trainer-config";
|
||||
import { ScanIvsPhase, SummonPhase, VictoryPhase } from "#app/phases";
|
||||
import { HiddenAbilityRateBoosterModifier, IvScannerModifier } from "#app/modifier/modifier";
|
||||
|
@ -15,6 +15,9 @@ import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter
|
|||
import { doPlayerFlee, doPokemonFlee, getRandomSpeciesByStarterTier, trainerThrowPokeball } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { getEncounterText, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounter:safariZone";
|
||||
|
@ -50,7 +53,7 @@ export const SafariZoneEncounter: IMysteryEncounter =
|
|||
.withDescription(`${namespace}:description`)
|
||||
.withQuery(`${namespace}:query`)
|
||||
.withOption(new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withSceneRequirement(new MoneyRequirement(0, 2.75)) // Cost equal to 1 Max Revive
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:1:label`,
|
||||
|
@ -64,7 +67,7 @@ export const SafariZoneEncounter: IMysteryEncounter =
|
|||
.withOptionPhase(async (scene: BattleScene) => {
|
||||
// Start safari encounter
|
||||
const encounter = scene.currentBattle.mysteryEncounter;
|
||||
encounter.encounterVariant = MysteryEncounterVariant.CONTINUOUS_ENCOUNTER;
|
||||
encounter.encounterMode = MysteryEncounterMode.CONTINUOUS_ENCOUNTER;
|
||||
encounter.misc = {
|
||||
safariPokemonRemaining: 3
|
||||
};
|
||||
|
@ -116,7 +119,7 @@ export const SafariZoneEncounter: IMysteryEncounter =
|
|||
*/
|
||||
const safariZoneGameOptions: MysteryEncounterOption[] = [
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:safari:1:label`,
|
||||
buttonTooltip: `${namespace}:safari:1:tooltip`,
|
||||
|
@ -150,7 +153,7 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
|
|||
})
|
||||
.build(),
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:safari:2:label`,
|
||||
buttonTooltip: `${namespace}:safari:2:tooltip`,
|
||||
|
@ -180,7 +183,7 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
|
|||
})
|
||||
.build(),
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:safari:3:label`,
|
||||
buttonTooltip: `${namespace}:safari:3:tooltip`,
|
||||
|
@ -209,7 +212,7 @@ const safariZoneGameOptions: MysteryEncounterOption[] = [
|
|||
})
|
||||
.build(),
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:safari:4:label`,
|
||||
buttonTooltip: `${namespace}:safari:4:tooltip`,
|
||||
|
|
|
@ -5,12 +5,14 @@ import { modifierTypes } from "#app/modifier/modifier-type";
|
|||
import { randSeedInt } from "#app/utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { Species } from "#enums/species";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter";
|
||||
import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { MoneyRequirement } from "../mystery-encounter-requirements";
|
||||
import { getEncounterText, queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { applyDamageToPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
/** the i18n namespace for this encounter */
|
||||
const namespace = "mysteryEncounter:shadyVitaminDealer";
|
||||
|
@ -59,7 +61,7 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
|
|||
.withQuery(`${namespace}:query`)
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withSceneMoneyRequirement(0, 2) // Wave scaling money multiplier of 2
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:1:label`,
|
||||
|
@ -144,7 +146,7 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
|
|||
)
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT)
|
||||
.withSceneMoneyRequirement(0, 5) // Wave scaling money multiplier of 5
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:2:label`,
|
||||
|
|
|
@ -4,8 +4,8 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
|||
import { Species } from "#enums/species";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { StatusEffect } from "#app/data/status-effect";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter";
|
||||
import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { MoveRequirement } from "../mystery-encounter-requirements";
|
||||
import { EnemyPartyConfig, EnemyPokemonConfig, initBattleWithEnemyConfig, initCustomMovesForEncounter, leaveEncounterWithoutBattle, setEncounterExp, setEncounterRewards, } from "../utils/encounter-phase-utils";
|
||||
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
|
@ -14,6 +14,8 @@ import { BattlerIndex } from "#app/battle";
|
|||
import { PokemonMove } from "#app/field/pokemon";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { PartyHealPhase } from "#app/phases";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
/** i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounter:slumberingSnorlax";
|
||||
|
@ -121,7 +123,7 @@ export const SlumberingSnorlaxEncounter: IMysteryEncounter =
|
|||
)
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DISABLED_OR_SPECIAL)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
|
||||
.withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES))
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:3:label`,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig, initCustomMovesForEncounter, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { modifierTypes, PokemonHeldItemModifierType, } from "#app/modifier/modifier-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { Species } from "#enums/species";
|
||||
import { Nature } from "#app/data/nature";
|
||||
|
@ -15,6 +15,7 @@ import { StatChangePhase } from "#app/phases";
|
|||
import { BattleStat } from "#app/data/battle-stat";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { BerryType } from "#enums/berry-type";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounter:theStrongStuff";
|
||||
|
|
|
@ -13,10 +13,12 @@ import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
|||
import { randSeedShuffle } from "#app/utils";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter";
|
||||
import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||
import { getEncounterText, queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
/** The i18n namespace for the encounter */
|
||||
const namespace = "mysteryEncounter:trainingSession";
|
||||
|
@ -52,7 +54,7 @@ export const TrainingSessionEncounter: IMysteryEncounter =
|
|||
.withQuery(`${namespace}:query`)
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withHasDexProgress(true)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:1:label`,
|
||||
|
@ -196,7 +198,7 @@ export const TrainingSessionEncounter: IMysteryEncounter =
|
|||
)
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withHasDexProgress(true)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:2:label`,
|
||||
|
@ -289,7 +291,7 @@ export const TrainingSessionEncounter: IMysteryEncounter =
|
|||
)
|
||||
.withOption(
|
||||
new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withHasDexProgress(true)
|
||||
.withDialogue({
|
||||
buttonLabel: `${namespace}:option:3:label`,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { MysteryEncounterTier } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT } from "#app/data/mystery-encounters/mystery-encounters";
|
||||
import { isNullOrUndefined } from "#app/utils";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
|
||||
export class MysteryEncounterData {
|
||||
encounteredEvents: [MysteryEncounterType, MysteryEncounterTier][] = [];
|
||||
|
|
|
@ -1,29 +1,19 @@
|
|||
import { OptionTextDisplay } from "#app/data/mystery-encounters/mystery-encounter-dialogue";
|
||||
import { Moves } from "#app/enums/moves";
|
||||
import { PlayerPokemon } from "#app/field/pokemon";
|
||||
import BattleScene from "../../battle-scene";
|
||||
import * as Utils from "../../utils";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import * as Utils from "#app/utils";
|
||||
import { Type } from "../type";
|
||||
import { EncounterPokemonRequirement, EncounterSceneRequirement, MoneyRequirement, TypeRequirement } from "./mystery-encounter-requirements";
|
||||
import { CanLearnMoveRequirement, CanLearnMoveRequirementOptions } from "./requirements/can-learn-move-requirement";
|
||||
import { isNullOrUndefined } from "../../utils";
|
||||
|
||||
export enum EncounterOptionMode {
|
||||
/** Default style */
|
||||
DEFAULT,
|
||||
/** Disabled on requirements not met, default style on requirements met */
|
||||
DISABLED_OR_DEFAULT,
|
||||
/** Default style on requirements not met, special style on requirements met */
|
||||
DEFAULT_OR_SPECIAL,
|
||||
/** Disabled on requirements not met, special style on requirements met */
|
||||
DISABLED_OR_SPECIAL
|
||||
}
|
||||
import { isNullOrUndefined } from "#app/utils";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
|
||||
export type OptionPhaseCallback = (scene: BattleScene) => Promise<void | boolean>;
|
||||
|
||||
export default interface MysteryEncounterOption {
|
||||
optionMode: EncounterOptionMode;
|
||||
optionMode: MysteryEncounterOptionMode;
|
||||
|
||||
hasDexProgress?: boolean;
|
||||
|
||||
|
@ -114,8 +104,8 @@ export default class MysteryEncounterOption implements MysteryEncounterOption {
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
// this means we CAN have the same pokemon be a primary and secondary pokemon, so just choose any qualifying one randomly.
|
||||
this.primaryPokemon = qualified[Utils.randSeedInt(qualified.length, 0)];
|
||||
// Just pick the first qualifying Pokemon
|
||||
this.primaryPokemon = qualified[0];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -145,7 +135,7 @@ export default class MysteryEncounterOption implements MysteryEncounterOption {
|
|||
|
||||
|
||||
export class MysteryEncounterOptionBuilder implements Partial<MysteryEncounterOption> {
|
||||
optionMode?: EncounterOptionMode;
|
||||
optionMode?: MysteryEncounterOptionMode;
|
||||
requirements?: EncounterSceneRequirement[] = [];
|
||||
primaryPokemonRequirements?: EncounterPokemonRequirement[] = [];
|
||||
secondaryPokemonRequirements ?: EncounterPokemonRequirement[] = [];
|
||||
|
@ -156,7 +146,7 @@ export class MysteryEncounterOptionBuilder implements Partial<MysteryEncounterOp
|
|||
onPostOptionPhase?: OptionPhaseCallback;
|
||||
dialogue?: OptionTextDisplay;
|
||||
|
||||
withOptionMode(optionMode: EncounterOptionMode): this & Pick<MysteryEncounterOption, "optionMode"> {
|
||||
withOptionMode(optionMode: MysteryEncounterOptionMode): this & Pick<MysteryEncounterOption, "optionMode"> {
|
||||
return Object.assign(this, { optionMode });
|
||||
}
|
||||
|
||||
|
@ -165,6 +155,10 @@ export class MysteryEncounterOptionBuilder implements Partial<MysteryEncounterOp
|
|||
}
|
||||
|
||||
withSceneRequirement(requirement: EncounterSceneRequirement): this & Required<Pick<MysteryEncounterOption, "requirements">> {
|
||||
if (requirement instanceof EncounterPokemonRequirement) {
|
||||
Error("Incorrectly added pokemon requirement as scene requirement.");
|
||||
}
|
||||
|
||||
this.requirements.push(requirement);
|
||||
return Object.assign(this, { requirements: this.requirements });
|
||||
}
|
||||
|
@ -190,6 +184,10 @@ export class MysteryEncounterOptionBuilder implements Partial<MysteryEncounterOp
|
|||
}
|
||||
|
||||
withPrimaryPokemonRequirement(requirement: EncounterPokemonRequirement): this & Required<Pick<MysteryEncounterOption, "primaryPokemonRequirements">> {
|
||||
if (requirement instanceof EncounterSceneRequirement) {
|
||||
Error("Incorrectly added scene requirement as pokemon requirement.");
|
||||
}
|
||||
|
||||
this.primaryPokemonRequirements.push(requirement);
|
||||
return Object.assign(this, { primaryPokemonRequirements: this.primaryPokemonRequirements });
|
||||
}
|
||||
|
@ -218,7 +216,11 @@ export class MysteryEncounterOptionBuilder implements Partial<MysteryEncounterOp
|
|||
return this.withPrimaryPokemonRequirement(new CanLearnMoveRequirement(move, options));
|
||||
}
|
||||
|
||||
withSecondaryPokemonRequirement(requirement: EncounterPokemonRequirement, excludePrimaryFromSecondaryRequirements?: boolean): this & Required<Pick<MysteryEncounterOption, "secondaryPokemonRequirements">> {
|
||||
withSecondaryPokemonRequirement(requirement: EncounterPokemonRequirement, excludePrimaryFromSecondaryRequirements: boolean = true): this & Required<Pick<MysteryEncounterOption, "secondaryPokemonRequirements">> {
|
||||
if (requirement instanceof EncounterSceneRequirement) {
|
||||
Error("Incorrectly added scene requirement as pokemon requirement.");
|
||||
}
|
||||
|
||||
this.secondaryPokemonRequirements.push(requirement);
|
||||
this.excludePrimaryFromSecondaryRequirements = excludePrimaryFromSecondaryRequirements;
|
||||
return Object.assign(this, { secondaryPokemonRequirements: this.secondaryPokemonRequirements });
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { PlayerPokemon } from "#app/field/pokemon";
|
||||
import { ModifierType, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||
import BattleScene from "../../battle-scene";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { isNullOrUndefined } from "#app/utils";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
|
@ -21,12 +21,35 @@ export interface EncounterRequirement {
|
|||
}
|
||||
|
||||
export abstract class EncounterSceneRequirement implements EncounterRequirement {
|
||||
abstract meetsRequirement(scene: BattleScene): boolean;
|
||||
abstract getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string];
|
||||
}
|
||||
|
||||
export class CombinationSceneRequirement extends EncounterSceneRequirement {
|
||||
orRequirements: EncounterSceneRequirement[];
|
||||
|
||||
constructor(... orRequirements: EncounterSceneRequirement[]) {
|
||||
super();
|
||||
this.orRequirements = orRequirements;
|
||||
}
|
||||
|
||||
meetsRequirement(scene: BattleScene): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
for (const req of this.orRequirements) {
|
||||
if (req.meetsRequirement(scene)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
|
||||
return ["", ""];
|
||||
for (const req of this.orRequirements) {
|
||||
if (req.meetsRequirement(scene)) {
|
||||
return req.getDialogueToken(scene, pokemon);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,12 +63,49 @@ export abstract class EncounterPokemonRequirement implements EncounterRequiremen
|
|||
* Returns all party members that are compatible with this requirement. For non pokemon related requirements, the entire party is returned.
|
||||
* @param partyPokemon
|
||||
*/
|
||||
abstract queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[];
|
||||
|
||||
abstract getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string];
|
||||
}
|
||||
|
||||
export class CombinationPokemonRequirement extends EncounterPokemonRequirement {
|
||||
orRequirements: EncounterPokemonRequirement[];
|
||||
|
||||
constructor(...orRequirements: EncounterPokemonRequirement[]) {
|
||||
super();
|
||||
this.invertQuery = false;
|
||||
this.minNumberOfPokemon = 1;
|
||||
this.orRequirements = orRequirements;
|
||||
}
|
||||
|
||||
meetsRequirement(scene: BattleScene): boolean {
|
||||
for (const req of this.orRequirements) {
|
||||
if (req.meetsRequirement(scene)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
|
||||
for (const req of this.orRequirements) {
|
||||
const result = req.queryParty(partyPokemon);
|
||||
if (result?.length > 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
|
||||
return ["", ""];
|
||||
for (const req of this.orRequirements) {
|
||||
if (req.meetsRequirement(scene)) {
|
||||
return req.getDialogueToken(scene, pokemon);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +116,7 @@ export class PreviousEncounterRequirement extends EncounterSceneRequirement {
|
|||
* Used for specifying an encounter that must be seen before this encounter can spawn
|
||||
* @param previousEncounterRequirement
|
||||
*/
|
||||
constructor(previousEncounterRequirement) {
|
||||
constructor(previousEncounterRequirement: MysteryEncounterType) {
|
||||
super();
|
||||
this.previousEncounterRequirement = previousEncounterRequirement;
|
||||
}
|
||||
|
@ -497,19 +557,16 @@ export class AbilityRequirement extends EncounterPokemonRequirement {
|
|||
|
||||
queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
|
||||
if (!this.invertQuery) {
|
||||
return partyPokemon.filter((pokemon) => this.requiredAbilities.filter((abilities) => pokemon.hasAbility(abilities)).length > 0);
|
||||
return partyPokemon.filter((pokemon) => this.requiredAbilities.some((ability) => pokemon.getAbility().id === ability));
|
||||
} else {
|
||||
// for an inverted query, we only want to get the pokemon that don't have ANY of the listed abilitiess
|
||||
return partyPokemon.filter((pokemon) => this.requiredAbilities.filter((abilities) => pokemon.hasAbility(abilities)).length === 0);
|
||||
return partyPokemon.filter((pokemon) => this.requiredAbilities.filter((ability) => pokemon.getAbility().id === ability).length === 0);
|
||||
}
|
||||
}
|
||||
|
||||
getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
|
||||
const reqAbilities = this.requiredAbilities.filter((a) => {
|
||||
pokemon.hasAbility(a);
|
||||
});
|
||||
if (reqAbilities.length > 0) {
|
||||
return ["ability", Abilities[reqAbilities[0]]];
|
||||
if (this.requiredAbilities.some(a => pokemon.getAbility().id === a)) {
|
||||
return ["ability", pokemon.getAbility().name];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -2,14 +2,14 @@ import { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-p
|
|||
import Pokemon, { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import { isNullOrUndefined } from "#app/utils";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import BattleScene from "../../battle-scene";
|
||||
import MysteryEncounterIntroVisuals, { MysteryEncounterSpriteConfig } from "../../field/mystery-encounter-intro";
|
||||
import * as Utils from "../../utils";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import MysteryEncounterIntroVisuals, { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro";
|
||||
import * as Utils from "#app/utils";
|
||||
import { StatusEffect } from "../status-effect";
|
||||
import MysteryEncounterDialogue, {
|
||||
OptionTextDisplay
|
||||
} from "./mystery-encounter-dialogue";
|
||||
import MysteryEncounterOption, { EncounterOptionMode, MysteryEncounterOptionBuilder, OptionPhaseCallback } from "./mystery-encounter-option";
|
||||
import MysteryEncounterOption, { MysteryEncounterOptionBuilder, OptionPhaseCallback } from "./mystery-encounter-option";
|
||||
import {
|
||||
EncounterPokemonRequirement,
|
||||
EncounterSceneRequirement,
|
||||
|
@ -20,27 +20,9 @@ import {
|
|||
} from "./mystery-encounter-requirements";
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
import { EncounterAnim } from "#app/data/battle-anims";
|
||||
|
||||
export enum MysteryEncounterVariant {
|
||||
DEFAULT,
|
||||
TRAINER_BATTLE,
|
||||
WILD_BATTLE,
|
||||
BOSS_BATTLE,
|
||||
NO_BATTLE,
|
||||
/** For spawning new encounter queries instead of continuing to next wave */
|
||||
CONTINUOUS_ENCOUNTER
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum values are base spawn weights of each tier
|
||||
*/
|
||||
export enum MysteryEncounterTier {
|
||||
COMMON = 64,
|
||||
GREAT = 40,
|
||||
ULTRA = 21,
|
||||
ROGUE = 3,
|
||||
MASTER = 0 // Not currently used
|
||||
}
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
|
||||
export interface StartOfBattleEffect {
|
||||
sourcePokemon?: Pokemon;
|
||||
|
@ -130,7 +112,7 @@ export default interface IMysteryEncounter {
|
|||
* For example, if there is no battle as part of the encounter/selected option, should be set to NO_BATTLE
|
||||
* Defaults to DEFAULT
|
||||
*/
|
||||
encounterVariant?: MysteryEncounterVariant;
|
||||
encounterMode?: MysteryEncounterMode;
|
||||
/**
|
||||
* Flag for checking if it's the first time a shop is being shown for an encounter.
|
||||
* Defaults to true so that the first shop does not override the specified rewards.
|
||||
|
@ -181,7 +163,7 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
|||
this.dialogue = this.dialogue ?? {};
|
||||
// Default max is 1 for ROGUE encounters, 3 for others
|
||||
this.maxAllowedEncounters = this.maxAllowedEncounters ?? this.encounterTier === MysteryEncounterTier.ROGUE ? 1 : 3;
|
||||
this.encounterVariant = MysteryEncounterVariant.DEFAULT;
|
||||
this.encounterMode = MysteryEncounterMode.DEFAULT;
|
||||
this.requirements = this.requirements ? this.requirements : [];
|
||||
this.hideBattleIntroMessage = !isNullOrUndefined(this.hideBattleIntroMessage) ? this.hideBattleIntroMessage : false;
|
||||
this.autoHideIntroVisuals = !isNullOrUndefined(this.autoHideIntroVisuals) ? this.autoHideIntroVisuals : true;
|
||||
|
@ -314,7 +296,9 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
|||
if (this.requirements?.length > 0) {
|
||||
for (const req of this.requirements) {
|
||||
const dialogueToken = req.getDialogueToken(scene);
|
||||
this.setDialogueToken(...dialogueToken);
|
||||
if (dialogueToken?.length === 2) {
|
||||
this.setDialogueToken(...dialogueToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.primaryPokemon?.length > 0) {
|
||||
|
@ -322,7 +306,9 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
|||
for (const req of this.primaryPokemonRequirements) {
|
||||
if (!req.invertQuery) {
|
||||
const value = req.getDialogueToken(scene, this.primaryPokemon);
|
||||
this.setDialogueToken("primary" + this.capitalizeFirstLetter(value[0]), value[1]);
|
||||
if (value?.length === 2) {
|
||||
this.setDialogueToken("primary" + this.capitalizeFirstLetter(value[0]), value[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -331,6 +317,9 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
|||
for (const req of this.secondaryPokemonRequirements) {
|
||||
if (!req.invertQuery) {
|
||||
const value = req.getDialogueToken(scene, this.secondaryPokemon[0]);
|
||||
if (value?.length === 2) {
|
||||
this.setDialogueToken("primary" + this.capitalizeFirstLetter(value[0]), value[1]);
|
||||
}
|
||||
this.setDialogueToken("secondary" + this.capitalizeFirstLetter(value[0]), value[1]);
|
||||
}
|
||||
}
|
||||
|
@ -344,7 +333,9 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
|||
if (opt.requirements?.length > 0) {
|
||||
for (const req of opt.requirements) {
|
||||
const dialogueToken = req.getDialogueToken(scene);
|
||||
this.setDialogueToken("option" + j + this.capitalizeFirstLetter(dialogueToken[0]), dialogueToken[1]);
|
||||
if (dialogueToken?.length === 2) {
|
||||
this.setDialogueToken("option" + j + this.capitalizeFirstLetter(dialogueToken[0]), dialogueToken[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opt.primaryPokemonRequirements?.length > 0 && opt.primaryPokemon?.length > 0) {
|
||||
|
@ -352,7 +343,9 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
|||
for (const req of opt.primaryPokemonRequirements) {
|
||||
if (!req.invertQuery) {
|
||||
const value = req.getDialogueToken(scene, opt.primaryPokemon);
|
||||
this.setDialogueToken("option" + j + "Primary" + this.capitalizeFirstLetter(value[0]), value[1]);
|
||||
if (value?.length === 2) {
|
||||
this.setDialogueToken("option" + j + "Primary" + this.capitalizeFirstLetter(value[0]), value[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -361,7 +354,9 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
|||
for (const req of opt.secondaryPokemonRequirements) {
|
||||
if (!req.invertQuery) {
|
||||
const value = req.getDialogueToken(scene, opt.secondaryPokemon[0]);
|
||||
this.setDialogueToken("option" + j + "Secondary" + this.capitalizeFirstLetter(value[0]), value[1]);
|
||||
if (value?.length === 2) {
|
||||
this.setDialogueToken("option" + j + "Secondary" + this.capitalizeFirstLetter(value[0]), value[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -373,7 +368,7 @@ export default class IMysteryEncounter implements IMysteryEncounter {
|
|||
}
|
||||
|
||||
/**
|
||||
* If an encounter uses {@link MysteryEncounterVariant.CONTINUOUS_ENCOUNTER},
|
||||
* If an encounter uses {@link MysteryEncounterMode.CONTINUOUS_ENCOUNTER},
|
||||
* should rely on this value for seed offset instead of wave index.
|
||||
*
|
||||
* This offset is incremented for each new {@link MysteryEncounterPhase} that occurs,
|
||||
|
@ -466,7 +461,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||
* @returns
|
||||
*/
|
||||
withSimpleOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback): this & Pick<IMysteryEncounter, "options"> {
|
||||
return this.withOption(new MysteryEncounterOptionBuilder().withOptionMode(EncounterOptionMode.DEFAULT).withDialogue(dialogue).withOptionPhase(callback).build());
|
||||
return this.withOption(new MysteryEncounterOptionBuilder().withOptionMode(MysteryEncounterOptionMode.DEFAULT).withDialogue(dialogue).withOptionPhase(callback).build());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -481,7 +476,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||
*/
|
||||
withSimpleDexProgressOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback): this & Pick<IMysteryEncounter, "options"> {
|
||||
return this.withOption(new MysteryEncounterOptionBuilder()
|
||||
.withOptionMode(EncounterOptionMode.DEFAULT)
|
||||
.withOptionMode(MysteryEncounterOptionMode.DEFAULT)
|
||||
.withHasDexProgress(true)
|
||||
.withDialogue(dialogue)
|
||||
.withOptionPhase(callback).build());
|
||||
|
@ -592,6 +587,10 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||
* @returns
|
||||
*/
|
||||
withPrimaryPokemonRequirement(requirement: EncounterPokemonRequirement): this & Required<Pick<IMysteryEncounter, "primaryPokemonRequirements">> {
|
||||
if (requirement instanceof EncounterSceneRequirement) {
|
||||
Error("Incorrectly added scene requirement as pokemon requirement.");
|
||||
}
|
||||
|
||||
this.primaryPokemonRequirements.push(requirement);
|
||||
return Object.assign(this, { primaryPokemonRequirements: this.primaryPokemonRequirements });
|
||||
}
|
||||
|
@ -624,6 +623,10 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
|
|||
// ex. if your only grass type pokemon, a snivy, is chosen as primary, if the support pokemon requires a grass type, the event won't trigger because
|
||||
// it's already been
|
||||
withSecondaryPokemonRequirement(requirement: EncounterPokemonRequirement, excludePrimaryFromSecondaryRequirements: boolean = false): this & Required<Pick<IMysteryEncounter, "secondaryPokemonRequirements">> {
|
||||
if (requirement instanceof EncounterSceneRequirement) {
|
||||
Error("Incorrectly added scene requirement as pokemon requirement.");
|
||||
}
|
||||
|
||||
this.secondaryPokemonRequirements.push(requirement);
|
||||
this.excludePrimaryFromSupportRequirements = excludePrimaryFromSecondaryRequirements;
|
||||
return Object.assign(this, { excludePrimaryFromSecondaryRequirements: this.excludePrimaryFromSupportRequirements, secondaryPokemonRequirements: this.secondaryPokemonRequirements });
|
||||
|
|
|
@ -61,7 +61,7 @@ export const EXTORTION_MOVES = [
|
|||
Moves.BEAT_UP,
|
||||
Moves.COIL,
|
||||
Moves.WRING_OUT,
|
||||
Moves.STRING_SHOT
|
||||
Moves.STRING_SHOT,
|
||||
];
|
||||
|
||||
export const EXTORTION_ABILITIES = [
|
||||
|
@ -69,5 +69,5 @@ export const EXTORTION_ABILITIES = [
|
|||
Abilities.ARENA_TRAP,
|
||||
Abilities.SHADOW_TAG,
|
||||
Abilities.SUCTION_CUPS,
|
||||
Abilities.STICKY_HOLD,
|
||||
Abilities.STICKY_HOLD
|
||||
];
|
||||
|
|
|
@ -18,17 +18,17 @@ import { BattlerTagType } from "#enums/battler-tag-type";
|
|||
import { Biome } from "#enums/biome";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import i18next from "i18next";
|
||||
import BattleScene from "../../../battle-scene";
|
||||
import Trainer, { TrainerVariant } from "../../../field/trainer";
|
||||
import * as Utils from "../../../utils";
|
||||
import PokemonSpecies from "../../pokemon-species";
|
||||
import { Status, StatusEffect } from "../../status-effect";
|
||||
import { TrainerConfig, trainerConfigs, TrainerSlot } from "../../trainer-config";
|
||||
import { MysteryEncounterVariant } from "../mystery-encounter";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import Trainer, { TrainerVariant } from "#app/field/trainer";
|
||||
import * as Utils from "#app/utils";
|
||||
import { Gender } from "#app/data/gender";
|
||||
import { Nature } from "#app/data/nature";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
import { Status, StatusEffect } from "#app/data/status-effect";
|
||||
import { TrainerConfig, trainerConfigs, TrainerSlot } from "#app/data/trainer-config";
|
||||
import PokemonSpecies from "#app/data/pokemon-species";
|
||||
|
||||
/**
|
||||
* Animates exclamation sprite over trainer's head at start of encounter
|
||||
|
@ -107,7 +107,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
|||
const trainerType = partyConfig?.trainerType;
|
||||
let trainerConfig = partyConfig?.trainerConfig;
|
||||
if (trainerType || trainerConfig) {
|
||||
scene.currentBattle.mysteryEncounter.encounterVariant = MysteryEncounterVariant.TRAINER_BATTLE;
|
||||
scene.currentBattle.mysteryEncounter.encounterMode = MysteryEncounterMode.TRAINER_BATTLE;
|
||||
if (scene.currentBattle.trainer) {
|
||||
scene.currentBattle.trainer.setVisible(false);
|
||||
scene.currentBattle.trainer.destroy();
|
||||
|
@ -128,7 +128,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
|||
battle.enemyLevels = scene.currentBattle.trainer.getPartyLevels(scene.currentBattle.waveIndex);
|
||||
} else {
|
||||
// Wild
|
||||
scene.currentBattle.mysteryEncounter.encounterVariant = MysteryEncounterVariant.WILD_BATTLE;
|
||||
scene.currentBattle.mysteryEncounter.encounterMode = MysteryEncounterMode.WILD_BATTLE;
|
||||
battle.enemyLevels = new Array(partyConfig?.pokemonConfigs?.length > 0 ? partyConfig?.pokemonConfigs?.length : doubleBattle ? 2 : 1).fill(null).map(() => scene.currentBattle.getLevelForWave());
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
|||
enemySpecies = config.species;
|
||||
isBoss = config.isBoss;
|
||||
if (isBoss) {
|
||||
scene.currentBattle.mysteryEncounter.encounterVariant = MysteryEncounterVariant.BOSS_BATTLE;
|
||||
scene.currentBattle.mysteryEncounter.encounterMode = MysteryEncounterMode.BOSS_BATTLE;
|
||||
}
|
||||
} else {
|
||||
enemySpecies = scene.randomSpecies(battle.waveIndex, level, true);
|
||||
|
@ -508,7 +508,7 @@ export function setEncounterExp(scene: BattleScene, participantId: integer | int
|
|||
let expValue = Math.floor(baseExpValue * (useWaveIndex ? scene.currentBattle.waveIndex : 1) / 5 + 1);
|
||||
|
||||
if (participantIds?.length > 0) {
|
||||
if (scene.currentBattle.mysteryEncounter.encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE) {
|
||||
if (scene.currentBattle.mysteryEncounter.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
|
||||
expValue = Math.floor(expValue * 1.5);
|
||||
}
|
||||
for (const partyMember of nonFaintedPartyMembers) {
|
||||
|
@ -609,7 +609,7 @@ export function initSubsequentOptionSelect(scene: BattleScene, optionSelectSetti
|
|||
* @param addHealPhase - when true, will add a shop phase to end of encounter with 0 rewards but healing items are available
|
||||
*/
|
||||
export function leaveEncounterWithoutBattle(scene: BattleScene, addHealPhase: boolean = false) {
|
||||
scene.currentBattle.mysteryEncounter.encounterVariant = MysteryEncounterVariant.NO_BATTLE;
|
||||
scene.currentBattle.mysteryEncounter.encounterMode = MysteryEncounterMode.NO_BATTLE;
|
||||
scene.clearPhaseQueue();
|
||||
scene.clearPhaseQueueSplice();
|
||||
handleMysteryEncounterVictory(scene, addHealPhase);
|
||||
|
@ -626,14 +626,14 @@ export function handleMysteryEncounterVictory(scene: BattleScene, addHealPhase:
|
|||
|
||||
// If in repeated encounter variant, do nothing
|
||||
// Variant must eventually be swapped in order to handle "true" end of the encounter
|
||||
if (scene.currentBattle.mysteryEncounter.encounterVariant === MysteryEncounterVariant.CONTINUOUS_ENCOUNTER) {
|
||||
if (scene.currentBattle.mysteryEncounter.encounterMode === MysteryEncounterMode.CONTINUOUS_ENCOUNTER) {
|
||||
return;
|
||||
} else if (scene.currentBattle.mysteryEncounter.encounterVariant === MysteryEncounterVariant.NO_BATTLE) {
|
||||
} else if (scene.currentBattle.mysteryEncounter.encounterMode === MysteryEncounterMode.NO_BATTLE) {
|
||||
scene.pushPhase(new EggLapsePhase(scene));
|
||||
scene.pushPhase(new MysteryEncounterRewardsPhase(scene, addHealPhase));
|
||||
} else if (!scene.getEnemyParty().find(p => scene.currentBattle.mysteryEncounter.encounterVariant !== MysteryEncounterVariant.TRAINER_BATTLE ? p.isOnField() : !p?.isFainted(true))) {
|
||||
} else if (!scene.getEnemyParty().find(p => scene.currentBattle.mysteryEncounter.encounterMode !== MysteryEncounterMode.TRAINER_BATTLE ? p.isOnField() : !p?.isFainted(true))) {
|
||||
scene.pushPhase(new BattleEndPhase(scene));
|
||||
if (scene.currentBattle.mysteryEncounter.encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE) {
|
||||
if (scene.currentBattle.mysteryEncounter.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
|
||||
scene.pushPhase(new TrainerVictoryPhase(scene));
|
||||
}
|
||||
if (scene.gameMode.isEndless || !scene.gameMode.isWaveFinal(scene.currentBattle.waveIndex)) {
|
||||
|
@ -693,7 +693,7 @@ export function transitionMysteryEncounterIntroVisuals(scene: BattleScene, hide:
|
|||
*/
|
||||
export function handleMysteryEncounterBattleStartEffects(scene: BattleScene) {
|
||||
const encounter = scene.currentBattle?.mysteryEncounter;
|
||||
if (scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && encounter.encounterVariant !== MysteryEncounterVariant.NO_BATTLE && !encounter.startOfBattleEffectsComplete) {
|
||||
if (scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && encounter.encounterMode !== MysteryEncounterMode.NO_BATTLE && !encounter.startOfBattleEffectsComplete) {
|
||||
const effects = encounter.startOfBattleEffects;
|
||||
effects.forEach(effect => {
|
||||
let source;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
export enum MysteryEncounterMode {
|
||||
DEFAULT,
|
||||
TRAINER_BATTLE,
|
||||
WILD_BATTLE,
|
||||
BOSS_BATTLE,
|
||||
NO_BATTLE,
|
||||
/** For spawning new encounter queries instead of continuing to next wave */
|
||||
CONTINUOUS_ENCOUNTER
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
export enum MysteryEncounterOptionMode {
|
||||
/** Default style */
|
||||
DEFAULT,
|
||||
/** Disabled on requirements not met, default style on requirements met */
|
||||
DISABLED_OR_DEFAULT,
|
||||
/** Default style on requirements not met, special style on requirements met */
|
||||
DEFAULT_OR_SPECIAL,
|
||||
/** Disabled on requirements not met, special style on requirements met */
|
||||
DISABLED_OR_SPECIAL
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Enum values are base spawn weights of each tier
|
||||
*/
|
||||
export enum MysteryEncounterTier {
|
||||
COMMON = 64,
|
||||
GREAT = 40,
|
||||
ULTRA = 21,
|
||||
ROGUE = 3,
|
||||
MASTER = 0 // Not currently used
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
export const offerYouCantRefuseDialogue = {
|
||||
intro: "You're stopped by a rich looking boy.",
|
||||
speaker: "Rich Kid",
|
||||
speaker: "Rich Boy",
|
||||
intro_dialogue: `Good day to you.
|
||||
$I can't help but notice that your\n{{strongestPokemon}} looks positively divine!
|
||||
$I've always wanted to have a pet like that!
|
||||
$I'd pay you handsomely, and\nI'll even give you this old bauble!`,
|
||||
$I'd pay you handsomely,\nand also give you this old bauble!`,
|
||||
title: "An Offer You Can't Refuse",
|
||||
description: "You're being offered a @[TOOLTIP_TITLE]{Shiny Charm} and {{price, money}} for your {{strongestPokemon}}!\n\nIt's is an extremely good deal, but can you really bear to part with such a strong team member?",
|
||||
query: "What will you do?",
|
||||
|
@ -18,11 +18,10 @@ export const offerYouCantRefuseDialogue = {
|
|||
},
|
||||
2: {
|
||||
label: "Extort the Kid",
|
||||
tooltip: "(+) Gain {{price, money}}",
|
||||
tooltip: "(+) {{option2PrimaryName}} uses {{moveOrAbility}}\n(+) Gain {{price, money}}",
|
||||
tooltip_disabled: "Your Pokémon need to have certain moves or abilities to choose this",
|
||||
selected: `My word, we're being robbed, Liepard!
|
||||
$How wonderful!
|
||||
$Now I'll have an amazing\nstory for the yacht club!`,
|
||||
$You'll be hearing from my lawyers for this!`,
|
||||
},
|
||||
3: {
|
||||
label: "Leave",
|
||||
|
|
|
@ -9,7 +9,7 @@ import { PokeballType } from "./data/pokeball";
|
|||
import { Gender } from "./data/gender";
|
||||
import { StatusEffect } from "./data/status-effect";
|
||||
import { modifierTypes, SpeciesStatBoosterItem } from "./modifier/modifier-type";
|
||||
import { VariantTier } from "./enums/variant-tiers";
|
||||
import { VariantTier } from "#enums/variant-tiers";
|
||||
import { EggTier } from "#enums/egg-type";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { BerryType } from "#enums/berry-type";
|
||||
|
@ -18,7 +18,7 @@ import { Moves } from "#enums/moves";
|
|||
import { Species } from "#enums/species";
|
||||
import { TimeOfDay } from "#enums/time-of-day";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
import { MysteryEncounterTier } from "#app/data/mystery-encounters/mystery-encounter"; // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
|
||||
/**
|
||||
* Overrides for testing different in game situations
|
||||
|
@ -117,9 +117,9 @@ export const EGG_GACHA_PULL_COUNT_OVERRIDE: number = 0;
|
|||
*/
|
||||
|
||||
// 1 to 256, set to null to ignore
|
||||
export const MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = 256;
|
||||
export const MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = null;
|
||||
export const MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier = null;
|
||||
export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = MysteryEncounterType.OFFER_YOU_CANT_REFUSE;
|
||||
export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = null;
|
||||
|
||||
/**
|
||||
* MODIFIER / ITEM OVERRIDES
|
||||
|
|
|
@ -65,11 +65,11 @@ import { Moves } from "#enums/moves";
|
|||
import { PlayerGender } from "#enums/player-gender";
|
||||
import { Species } from "#enums/species";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import { MysteryEncounterVariant } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases";
|
||||
import { doTrainerExclamation, handleMysteryEncounterBattleStartEffects, handleMysteryEncounterVictory } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "#app/ui/modifier-select-ui-handler";
|
||||
import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
|
||||
const { t } = i18next;
|
||||
|
||||
|
@ -866,7 +866,7 @@ export class EncounterPhase extends BattlePhase {
|
|||
}
|
||||
|
||||
if (!this.loaded) {
|
||||
this.scene.gameData.setPokemonSeen(enemyPokemon, true, battle.battleType === BattleType.TRAINER || battle?.mysteryEncounter?.encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE);
|
||||
this.scene.gameData.setPokemonSeen(enemyPokemon, true, battle.battleType === BattleType.TRAINER || battle?.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE);
|
||||
}
|
||||
|
||||
if (enemyPokemon.species.speciesId === Species.ETERNATUS) {
|
||||
|
@ -1550,7 +1550,7 @@ export class SummonPhase extends PartyMemberPokemonPhase {
|
|||
onComplete: () => this.scene.trainer.setVisible(false)
|
||||
});
|
||||
this.scene.time.delayedCall(750, () => this.summon());
|
||||
} else if (this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene?.currentBattle?.mysteryEncounter?.encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE) {
|
||||
} else if (this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene?.currentBattle?.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
|
||||
const trainerName = this.scene.currentBattle.trainer.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER);
|
||||
const pokemonName = this.getPokemon().name;
|
||||
const message = i18next.t("battle:trainerSendOut", { trainerName, pokemonName });
|
||||
|
|
|
@ -5,7 +5,6 @@ import { Mode } from "../ui/ui";
|
|||
import { transitionMysteryEncounterIntroVisuals, OptionSelectSettings } from "../data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { CheckSwitchPhase, NewBattlePhase, ReturnPhase, ScanIvsPhase, SelectModifierPhase, SummonPhase, ToggleDoublePositionPhase } from "../phases";
|
||||
import MysteryEncounterOption, { OptionPhaseCallback } from "../data/mystery-encounters/mystery-encounter-option";
|
||||
import { MysteryEncounterVariant } from "../data/mystery-encounters/mystery-encounter";
|
||||
import { getCharVariantFromDialogue } from "../data/dialogue";
|
||||
import { TrainerSlot } from "../data/trainer-config";
|
||||
import { BattleSpec } from "#enums/battle-spec";
|
||||
|
@ -15,6 +14,7 @@ import * as Utils from "../utils";
|
|||
import { isNullOrUndefined } from "../utils";
|
||||
import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { BattlerTagLapseType } from "#app/data/battler-tags";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
|
||||
/**
|
||||
* Will handle (in order):
|
||||
|
@ -210,13 +210,13 @@ export class MysteryEncounterBattlePhase extends Phase {
|
|||
|
||||
getBattleMessage(scene: BattleScene): string {
|
||||
const enemyField = scene.getEnemyField();
|
||||
const encounterVariant = scene.currentBattle.mysteryEncounter.encounterVariant;
|
||||
const encounterMode = scene.currentBattle.mysteryEncounter.encounterMode;
|
||||
|
||||
if (scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
|
||||
return i18next.t("battle:bossAppeared", { bossName: enemyField[0].name });
|
||||
}
|
||||
|
||||
if (encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE) {
|
||||
if (encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
|
||||
if (scene.currentBattle.double) {
|
||||
return i18next.t("battle:trainerAppearedDouble", { trainerName: scene.currentBattle.trainer.getName(TrainerSlot.NONE, true) });
|
||||
|
||||
|
@ -231,10 +231,10 @@ export class MysteryEncounterBattlePhase extends Phase {
|
|||
}
|
||||
|
||||
doMysteryEncounterBattle(scene: BattleScene) {
|
||||
const encounterVariant = scene.currentBattle.mysteryEncounter.encounterVariant;
|
||||
if (encounterVariant === MysteryEncounterVariant.WILD_BATTLE || encounterVariant === MysteryEncounterVariant.BOSS_BATTLE) {
|
||||
const encounterMode = scene.currentBattle.mysteryEncounter.encounterMode;
|
||||
if (encounterMode === MysteryEncounterMode.WILD_BATTLE || encounterMode === MysteryEncounterMode.BOSS_BATTLE) {
|
||||
// Summons the wild/boss Pokemon
|
||||
if (encounterVariant === MysteryEncounterVariant.BOSS_BATTLE) {
|
||||
if (encounterMode === MysteryEncounterMode.BOSS_BATTLE) {
|
||||
scene.playBgm(undefined);
|
||||
}
|
||||
const availablePartyMembers = scene.getEnemyParty().filter(p => !p.isFainted()).length;
|
||||
|
@ -248,7 +248,7 @@ export class MysteryEncounterBattlePhase extends Phase {
|
|||
} else {
|
||||
this.endBattleSetup(scene);
|
||||
}
|
||||
} else if (encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE) {
|
||||
} else if (encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
|
||||
this.showEnemyTrainer();
|
||||
const doSummon = () => {
|
||||
scene.currentBattle.started = true;
|
||||
|
@ -296,11 +296,11 @@ export class MysteryEncounterBattlePhase extends Phase {
|
|||
|
||||
endBattleSetup(scene: BattleScene) {
|
||||
const enemyField = scene.getEnemyField();
|
||||
const encounterVariant = scene.currentBattle.mysteryEncounter.encounterVariant;
|
||||
const encounterMode = scene.currentBattle.mysteryEncounter.encounterMode;
|
||||
|
||||
// PostSummon and ShinySparkle phases are handled by SummonPhase
|
||||
|
||||
if (encounterVariant !== MysteryEncounterVariant.TRAINER_BATTLE) {
|
||||
if (encounterMode !== MysteryEncounterMode.TRAINER_BATTLE) {
|
||||
const ivScannerModifier = this.scene.findModifier(m => m instanceof IvScannerModifier);
|
||||
if (ivScannerModifier) {
|
||||
enemyField.map(p => this.scene.pushPhase(new ScanIvsPhase(this.scene, p.getBattlerIndex(), Math.min(ivScannerModifier.getStackCount() * 2, 6))));
|
||||
|
@ -327,7 +327,7 @@ export class MysteryEncounterBattlePhase extends Phase {
|
|||
scene.pushPhase(new ToggleDoublePositionPhase(scene, false));
|
||||
}
|
||||
|
||||
if (encounterVariant !== MysteryEncounterVariant.TRAINER_BATTLE && !this.disableSwitch) {
|
||||
if (encounterMode !== MysteryEncounterMode.TRAINER_BATTLE && !this.disableSwitch) {
|
||||
const minPartySize = scene.currentBattle.double ? 2 : 1;
|
||||
if (availablePartyMembers.length > minPartySize) {
|
||||
scene.pushPhase(new CheckSwitchPhase(scene, 0, scene.currentBattle.double));
|
||||
|
|
|
@ -13,6 +13,53 @@ import { Status, StatusEffect } from "#app/data/status-effect";
|
|||
* @param optionNo - human number, not index
|
||||
* @param isBattle - if selecting option should lead to battle, set to true
|
||||
*/
|
||||
export async function runMysteryEncounterToEnd(game: GameManager, optionNo: number, isBattle: boolean = false) {
|
||||
await runSelectMysteryEncounterOption(game, optionNo, isBattle);
|
||||
|
||||
// run the selected options phase
|
||||
game.onNextPrompt("MysteryEncounterOptionSelectedPhase", Mode.MESSAGE, () => {
|
||||
const uiHandler = game.scene.ui.getHandler<MysteryEncounterUiHandler>();
|
||||
uiHandler.processInput(Button.ACTION);
|
||||
});
|
||||
|
||||
// If a battle is started, fast forward to end of the battle
|
||||
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
game.scene.clearPhaseQueue();
|
||||
game.scene.clearPhaseQueueSplice();
|
||||
game.scene.unshiftPhase(new VictoryPhase(game.scene, 0));
|
||||
game.endPhase();
|
||||
});
|
||||
|
||||
// Handle end of battle trainer messages
|
||||
game.onNextPrompt("TrainerVictoryPhase", Mode.MESSAGE, () => {
|
||||
const uiHandler = game.scene.ui.getHandler<MessageUiHandler>();
|
||||
uiHandler.processInput(Button.ACTION);
|
||||
});
|
||||
|
||||
// Handle egg hatch dialogue
|
||||
game.onNextPrompt("EggLapsePhase", Mode.MESSAGE, () => {
|
||||
const uiHandler = game.scene.ui.getHandler<MessageUiHandler>();
|
||||
uiHandler.processInput(Button.ACTION);
|
||||
});
|
||||
|
||||
// Handle modifier reward dialogue
|
||||
game.onNextPrompt("ModifierRewardPhase", Mode.MESSAGE, () => {
|
||||
const uiHandler = game.scene.ui.getHandler<MessageUiHandler>();
|
||||
uiHandler.processInput(Button.ACTION);
|
||||
});
|
||||
|
||||
game.onNextPrompt("SelectModifier", Mode.MODIFIER_SELECT, () => {
|
||||
const uiHandler = game.scene.ui.getHandler<MessageUiHandler>();
|
||||
uiHandler.processInput(Button.ACTION);
|
||||
});
|
||||
|
||||
if (isBattle) {
|
||||
await game.phaseInterceptor.to(CommandPhase);
|
||||
} else {
|
||||
await game.phaseInterceptor.to(MysteryEncounterRewardsPhase);
|
||||
}
|
||||
}
|
||||
|
||||
export async function runSelectMysteryEncounterOption(game: GameManager, optionNo: number, isBattle: boolean = false) {
|
||||
// Handle any eventual queued messages (e.g. weather phase, etc.)
|
||||
game.onNextPrompt("MessagePhase", Mode.MESSAGE, () => {
|
||||
|
@ -53,38 +100,6 @@ export async function runSelectMysteryEncounterOption(game: GameManager, optionN
|
|||
}
|
||||
|
||||
uiHandler.processInput(Button.ACTION);
|
||||
|
||||
// run the selected options phase
|
||||
game.onNextPrompt("MysteryEncounterOptionSelectedPhase", Mode.MESSAGE, () => {
|
||||
const uiHandler = game.scene.ui.getHandler<MysteryEncounterUiHandler>();
|
||||
uiHandler.processInput(Button.ACTION);
|
||||
});
|
||||
|
||||
// If a battle is started, fast forward to end of the battle
|
||||
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
game.scene.clearPhaseQueue();
|
||||
game.scene.clearPhaseQueueSplice();
|
||||
game.scene.unshiftPhase(new VictoryPhase(game.scene, 0));
|
||||
game.endPhase();
|
||||
});
|
||||
|
||||
// Handle end of battle trainer messages
|
||||
game.onNextPrompt("TrainerVictoryPhase", Mode.MESSAGE, () => {
|
||||
const uiHandler = game.scene.ui.getHandler<MessageUiHandler>();
|
||||
uiHandler.processInput(Button.ACTION);
|
||||
});
|
||||
|
||||
// Handle egg hatch dialogue
|
||||
game.onNextPrompt("EggLapsePhase", Mode.MESSAGE, () => {
|
||||
const uiHandler = game.scene.ui.getHandler<MessageUiHandler>();
|
||||
uiHandler.processInput(Button.ACTION);
|
||||
});
|
||||
|
||||
if (isBattle) {
|
||||
await game.phaseInterceptor.to(CommandPhase);
|
||||
} else {
|
||||
await game.phaseInterceptor.to(MysteryEncounterRewardsPhase);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,15 +5,15 @@ import { Species } from "#app/enums/species";
|
|||
import GameManager from "#app/test/utils/gameManager";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { EncounterOptionMode } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { runSelectMysteryEncounterOption } from "#test/mystery-encounter/encounterTestUtils";
|
||||
import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounterTestUtils";
|
||||
import { SelectModifierPhase } from "#app/phases";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { MysteryEncounterTier } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { Mode } from "#app/ui/ui";
|
||||
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
|
||||
import { DepartmentStoreSaleEncounter } from "#app/data/mystery-encounters/encounters/department-store-sale-encounter";
|
||||
import { CIVILIZATION_ENCOUNTER_BIOMES } from "#app/data/mystery-encounters/mystery-encounters";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
|
||||
const namespace = "mysteryEncounter:departmentStoreSale";
|
||||
const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA];
|
||||
|
@ -98,7 +98,7 @@ describe("Department Store Sale - Mystery Encounter", () => {
|
|||
describe("Option 1 - TM Shop", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option = DepartmentStoreSaleEncounter.options[0];
|
||||
expect(option.optionMode).toBe(EncounterOptionMode.DEFAULT);
|
||||
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
|
||||
expect(option.dialogue).toBeDefined();
|
||||
expect(option.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:1:label`,
|
||||
|
@ -108,7 +108,7 @@ describe("Department Store Sale - Mystery Encounter", () => {
|
|||
|
||||
it("should have shop with only TMs", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.DEPARTMENT_STORE_SALE, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 1);
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name);
|
||||
await game.phaseInterceptor.run(SelectModifierPhase);
|
||||
|
||||
|
@ -124,7 +124,7 @@ describe("Department Store Sale - Mystery Encounter", () => {
|
|||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.DEPARTMENT_STORE_SALE, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 1);
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
|
@ -133,7 +133,7 @@ describe("Department Store Sale - Mystery Encounter", () => {
|
|||
describe("Option 2 - Vitamin Shop", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option = DepartmentStoreSaleEncounter.options[1];
|
||||
expect(option.optionMode).toBe(EncounterOptionMode.DEFAULT);
|
||||
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
|
||||
expect(option.dialogue).toBeDefined();
|
||||
expect(option.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:2:label`,
|
||||
|
@ -143,7 +143,7 @@ describe("Department Store Sale - Mystery Encounter", () => {
|
|||
|
||||
it("should have shop with only Vitamins", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.DEPARTMENT_STORE_SALE, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 2);
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name);
|
||||
await game.phaseInterceptor.run(SelectModifierPhase);
|
||||
|
||||
|
@ -160,7 +160,7 @@ describe("Department Store Sale - Mystery Encounter", () => {
|
|||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.DEPARTMENT_STORE_SALE, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 2);
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
|
@ -169,7 +169,7 @@ describe("Department Store Sale - Mystery Encounter", () => {
|
|||
describe("Option 3 - X Item Shop", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option = DepartmentStoreSaleEncounter.options[2];
|
||||
expect(option.optionMode).toBe(EncounterOptionMode.DEFAULT);
|
||||
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
|
||||
expect(option.dialogue).toBeDefined();
|
||||
expect(option.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:3:label`,
|
||||
|
@ -179,7 +179,7 @@ describe("Department Store Sale - Mystery Encounter", () => {
|
|||
|
||||
it("should have shop with only X Items", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.DEPARTMENT_STORE_SALE, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 3);
|
||||
await runMysteryEncounterToEnd(game, 3);
|
||||
expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name);
|
||||
await game.phaseInterceptor.run(SelectModifierPhase);
|
||||
|
||||
|
@ -196,7 +196,7 @@ describe("Department Store Sale - Mystery Encounter", () => {
|
|||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.DEPARTMENT_STORE_SALE, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 3);
|
||||
await runMysteryEncounterToEnd(game, 3);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
|
@ -205,7 +205,7 @@ describe("Department Store Sale - Mystery Encounter", () => {
|
|||
describe("Option 4 - Pokeball Shop", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option = DepartmentStoreSaleEncounter.options[3];
|
||||
expect(option.optionMode).toBe(EncounterOptionMode.DEFAULT);
|
||||
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
|
||||
expect(option.dialogue).toBeDefined();
|
||||
expect(option.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:4:label`,
|
||||
|
@ -215,7 +215,7 @@ describe("Department Store Sale - Mystery Encounter", () => {
|
|||
|
||||
it("should have shop with only Pokeballs", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.DEPARTMENT_STORE_SALE, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 4);
|
||||
await runMysteryEncounterToEnd(game, 4);
|
||||
expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name);
|
||||
await game.phaseInterceptor.run(SelectModifierPhase);
|
||||
|
||||
|
@ -231,7 +231,7 @@ describe("Department Store Sale - Mystery Encounter", () => {
|
|||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.DEPARTMENT_STORE_SALE, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 4);
|
||||
await runMysteryEncounterToEnd(game, 4);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
|
|
|
@ -5,20 +5,21 @@ import { Species } from "#app/enums/species";
|
|||
import GameManager from "#app/test/utils/gameManager";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { FieryFalloutEncounter } from "#app/data/mystery-encounters/encounters/fiery-fallout-encounter";
|
||||
import Battle from "#app/battle";
|
||||
import { Gender } from "#app/data/gender";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import * as BattleAnims from "#app/data/battle-anims";
|
||||
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { EncounterOptionMode } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { runSelectMysteryEncounterOption, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
|
||||
import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
|
||||
import { CommandPhase, MovePhase, SelectModifierPhase } from "#app/phases";
|
||||
import { Moves } from "#enums/moves";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
||||
import { Type } from "#app/data/type";
|
||||
import { Status, StatusEffect } from "#app/data/status-effect";
|
||||
import { MysteryEncounterTier } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils";
|
||||
|
||||
const namespace = "mysteryEncounter:fieryFallout";
|
||||
/** Arcanine and Ninetails for 2 Fire types. Lapras, Gengar, Abra for burnable mon. */
|
||||
|
@ -94,7 +95,8 @@ describe("Fiery Fallout - Mystery Encounter", () => {
|
|||
});
|
||||
|
||||
it("should initialize fully ", async () => {
|
||||
vi.spyOn(scene, "currentBattle", "get").mockReturnValue({ mysteryEncounter: FieryFalloutEncounter } as Battle);
|
||||
initSceneWithoutEncounterPhase(scene, defaultParty);
|
||||
scene.currentBattle.mysteryEncounter = FieryFalloutEncounter;
|
||||
const weatherSpy = vi.spyOn(scene.arena, "trySetWeather").mockReturnValue(true);
|
||||
const moveInitSpy = vi.spyOn(BattleAnims, "initMoveAnim");
|
||||
const moveLoadSpy = vi.spyOn(BattleAnims, "loadMoveAnimAssets");
|
||||
|
@ -103,6 +105,7 @@ describe("Fiery Fallout - Mystery Encounter", () => {
|
|||
|
||||
expect(FieryFalloutEncounter.onInit).toBeDefined();
|
||||
|
||||
FieryFalloutEncounter.populateDialogueTokensFromRequirements(scene);
|
||||
const onInitResult = onInit(scene);
|
||||
|
||||
expect(FieryFalloutEncounter.enemyPartyConfigs).toEqual([
|
||||
|
@ -132,7 +135,7 @@ describe("Fiery Fallout - Mystery Encounter", () => {
|
|||
describe("Option 1 - Fight 2 Volcarona", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option1 = FieryFalloutEncounter.options[0];
|
||||
expect(option1.optionMode).toBe(EncounterOptionMode.DEFAULT);
|
||||
expect(option1.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
|
||||
expect(option1.dialogue).toBeDefined();
|
||||
expect(option1.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:1:label`,
|
||||
|
@ -149,7 +152,7 @@ describe("Fiery Fallout - Mystery Encounter", () => {
|
|||
const phaseSpy = vi.spyOn(scene, "pushPhase");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 1, true);
|
||||
await runMysteryEncounterToEnd(game, 1, true);
|
||||
|
||||
const enemyField = scene.getEnemyField();
|
||||
expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
|
||||
|
@ -166,7 +169,7 @@ describe("Fiery Fallout - Mystery Encounter", () => {
|
|||
|
||||
it("should give charcoal to lead pokemon", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 1, true);
|
||||
await runMysteryEncounterToEnd(game, 1, true);
|
||||
await skipBattleRunMysteryEncounterRewardsPhase(game);
|
||||
await game.phaseInterceptor.to(SelectModifierPhase, false);
|
||||
expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name);
|
||||
|
@ -182,7 +185,7 @@ describe("Fiery Fallout - Mystery Encounter", () => {
|
|||
describe("Option 2 - Suffer the weather", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option1 = FieryFalloutEncounter.options[1];
|
||||
expect(option1.optionMode).toBe(EncounterOptionMode.DEFAULT);
|
||||
expect(option1.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
|
||||
expect(option1.dialogue).toBeDefined();
|
||||
expect(option1.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:2:label`,
|
||||
|
@ -204,7 +207,7 @@ describe("Fiery Fallout - Mystery Encounter", () => {
|
|||
const abra = party.find((pkm) => pkm.species.speciesId === Species.ABRA);
|
||||
vi.spyOn(abra, "isAllowedInBattle").mockReturnValue(false);
|
||||
|
||||
await runSelectMysteryEncounterOption(game, 2);
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
||||
const burnablePokemon = party.filter((pkm) => pkm.isAllowedInBattle() && !pkm.getTypes().includes(Type.FIRE));
|
||||
const notBurnablePokemon = party.filter((pkm) => !pkm.isAllowedInBattle() || pkm.getTypes().includes(Type.FIRE));
|
||||
|
@ -220,7 +223,7 @@ describe("Fiery Fallout - Mystery Encounter", () => {
|
|||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 2);
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
|
@ -229,7 +232,7 @@ describe("Fiery Fallout - Mystery Encounter", () => {
|
|||
describe("Option 3 - use FIRE types", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option1 = FieryFalloutEncounter.options[2];
|
||||
expect(option1.optionMode).toBe(EncounterOptionMode.DISABLED_OR_SPECIAL);
|
||||
expect(option1.optionMode).toBe(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL);
|
||||
expect(option1.dialogue).toBeDefined();
|
||||
expect(option1.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:3:label`,
|
||||
|
@ -245,7 +248,7 @@ describe("Fiery Fallout - Mystery Encounter", () => {
|
|||
|
||||
it("should give charcoal to lead pokemon", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 3);
|
||||
await runMysteryEncounterToEnd(game, 3);
|
||||
// await skipBattleRunMysteryEncounterRewardsPhase(game);
|
||||
await game.phaseInterceptor.to(SelectModifierPhase, false);
|
||||
expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name);
|
||||
|
@ -261,9 +264,23 @@ describe("Fiery Fallout - Mystery Encounter", () => {
|
|||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 3);
|
||||
await runMysteryEncounterToEnd(game, 3);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
|
||||
it("should be disabled if not enough FIRE types are in party", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, [Species.MAGIKARP, Species.ARCANINE]);
|
||||
await game.phaseInterceptor.to(MysteryEncounterPhase, false);
|
||||
|
||||
const encounterPhase = scene.getCurrentPhase();
|
||||
expect(encounterPhase.constructor.name).toBe(MysteryEncounterPhase.name);
|
||||
const continueEncounterSpy = vi.spyOn((encounterPhase as MysteryEncounterPhase), "continueEncounter");
|
||||
|
||||
await runSelectMysteryEncounterOption(game, 3);
|
||||
|
||||
expect(scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name);
|
||||
expect(continueEncounterSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import Battle from "#app/battle";
|
||||
import { LostAtSeaEncounter } from "#app/data/mystery-encounters/encounters/lost-at-sea-encounter";
|
||||
import { EncounterOptionMode } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters";
|
||||
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species.js";
|
||||
|
@ -10,8 +8,11 @@ import { MysteryEncounterType } from "#app/enums/mystery-encounter-type";
|
|||
import { Species } from "#app/enums/species";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { runSelectMysteryEncounterOption } from "../encounterTestUtils";
|
||||
import { MysteryEncounterTier } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { runMysteryEncounterToEnd } from "../encounterTestUtils";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
|
||||
const namespace = "mysteryEncounter:lostAtSea";
|
||||
/** Blastoise for surf. Pidgeot for fly. Abra for none. */
|
||||
|
@ -22,6 +23,7 @@ const defaultWave = 33;
|
|||
describe("Lost at Sea - Mystery Encounter", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
let scene: BattleScene;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({ type: Phaser.HEADLESS });
|
||||
|
@ -29,6 +31,7 @@ describe("Lost at Sea - Mystery Encounter", () => {
|
|||
|
||||
beforeEach(async () => {
|
||||
game = new GameManager(phaserGame);
|
||||
scene = game.scene;
|
||||
game.override.mysteryEncounterChance(100);
|
||||
game.override.startingWave(defaultWave);
|
||||
game.override.startingBiome(defaultBiome);
|
||||
|
@ -83,14 +86,16 @@ describe("Lost at Sea - Mystery Encounter", () => {
|
|||
expect(game.scene.currentBattle.mysteryEncounter).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should set the correct dialog tokens during initialization", () => {
|
||||
vi.spyOn(game.scene, "currentBattle", "get").mockReturnValue({ mysteryEncounter: LostAtSeaEncounter } as Battle);
|
||||
it("should initialize fully", () => {
|
||||
initSceneWithoutEncounterPhase(scene, defaultParty);
|
||||
scene.currentBattle.mysteryEncounter = LostAtSeaEncounter;
|
||||
|
||||
const { onInit } = LostAtSeaEncounter;
|
||||
|
||||
expect(LostAtSeaEncounter.onInit).toBeDefined();
|
||||
|
||||
const onInitResult = onInit(game.scene);
|
||||
LostAtSeaEncounter.populateDialogueTokensFromRequirements(scene);
|
||||
const onInitResult = onInit(scene);
|
||||
|
||||
expect(LostAtSeaEncounter.dialogueTokens?.damagePercentage).toBe("25");
|
||||
expect(LostAtSeaEncounter.dialogueTokens?.option1RequiredMove).toBe(Moves[Moves.SURF]);
|
||||
|
@ -101,7 +106,7 @@ describe("Lost at Sea - Mystery Encounter", () => {
|
|||
describe("Option 1 - Surf", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option1 = LostAtSeaEncounter.options[0];
|
||||
expect(option1.optionMode).toBe(EncounterOptionMode.DISABLED_OR_DEFAULT);
|
||||
expect(option1.optionMode).toBe(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT);
|
||||
expect(option1.dialogue).toBeDefined();
|
||||
expect(option1.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:1:label`,
|
||||
|
@ -124,7 +129,7 @@ describe("Lost at Sea - Mystery Encounter", () => {
|
|||
const blastoise = party.find((pkm) => pkm.species.speciesId === Species.PIDGEOT);
|
||||
const expBefore = blastoise.exp;
|
||||
|
||||
await runSelectMysteryEncounterOption(game, 2);
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
||||
expect(blastoise.exp).toBe(expBefore + Math.floor(laprasSpecies.baseExp * defaultWave / 5 + 1));
|
||||
});
|
||||
|
@ -134,7 +139,7 @@ describe("Lost at Sea - Mystery Encounter", () => {
|
|||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.LOST_AT_SEA, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 1);
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
|
@ -148,7 +153,7 @@ describe("Lost at Sea - Mystery Encounter", () => {
|
|||
it("should have the correct properties", () => {
|
||||
const option2 = LostAtSeaEncounter.options[1];
|
||||
|
||||
expect(option2.optionMode).toBe(EncounterOptionMode.DISABLED_OR_DEFAULT);
|
||||
expect(option2.optionMode).toBe(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT);
|
||||
expect(option2.dialogue).toBeDefined();
|
||||
expect(option2.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:2:label`,
|
||||
|
@ -173,7 +178,7 @@ describe("Lost at Sea - Mystery Encounter", () => {
|
|||
const pidgeot = party.find((pkm) => pkm.species.speciesId === Species.PIDGEOT);
|
||||
const expBefore = pidgeot.exp;
|
||||
|
||||
await runSelectMysteryEncounterOption(game, 2);
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
||||
expect(pidgeot.exp).toBe(expBefore + Math.floor(laprasBaseExp * defaultWave / 5 + 1));
|
||||
});
|
||||
|
@ -183,7 +188,7 @@ describe("Lost at Sea - Mystery Encounter", () => {
|
|||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.LOST_AT_SEA, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 2);
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
|
@ -197,7 +202,7 @@ describe("Lost at Sea - Mystery Encounter", () => {
|
|||
it("should have the correct properties", () => {
|
||||
const option3 = LostAtSeaEncounter.options[2];
|
||||
|
||||
expect(option3.optionMode).toBe(EncounterOptionMode.DEFAULT);
|
||||
expect(option3.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
|
||||
expect(option3.dialogue).toBeDefined();
|
||||
expect(option3.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:3:label`,
|
||||
|
@ -219,7 +224,7 @@ describe("Lost at Sea - Mystery Encounter", () => {
|
|||
const abra = party.find((pkm) => pkm.species.speciesId === Species.ABRA);
|
||||
vi.spyOn(abra, "isAllowedInBattle").mockReturnValue(false);
|
||||
|
||||
await runSelectMysteryEncounterOption(game, 3);
|
||||
await runMysteryEncounterToEnd(game, 3);
|
||||
|
||||
const allowedPkm = party.filter((pkm) => pkm.isAllowedInBattle());
|
||||
const notAllowedPkm = party.filter((pkm) => !pkm.isAllowedInBattle());
|
||||
|
@ -235,7 +240,7 @@ describe("Lost at Sea - Mystery Encounter", () => {
|
|||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.LOST_AT_SEA, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 3);
|
||||
await runMysteryEncounterToEnd(game, 3);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters";
|
||||
import { HUMAN_TRANSITABLE_BIOMES } from "#app/data/mystery-encounters/mystery-encounters";
|
||||
import { Biome } from "#app/enums/biome";
|
||||
import { MysteryEncounterType } from "#app/enums/mystery-encounter-type";
|
||||
import { Species } from "#app/enums/species";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounterTestUtils";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import { OfferYouCantRefuseEncounter } from "#app/data/mystery-encounters/encounters/offer-you-cant-refuse-encounter";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { Moves } from "#enums/moves";
|
||||
|
||||
const namespace = "mysteryEncounter:offerYouCantRefuse";
|
||||
/** Gyarados for Indimidate */
|
||||
const defaultParty = [Species.GYARADOS, Species.GENGAR, Species.ABRA];
|
||||
const defaultBiome = Biome.CAVE;
|
||||
const defaultWave = 45;
|
||||
|
||||
describe("An Offer You Can't Refuse - Mystery Encounter", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
let scene: BattleScene;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({ type: Phaser.HEADLESS });
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
game = new GameManager(phaserGame);
|
||||
scene = game.scene;
|
||||
game.override.mysteryEncounterChance(100);
|
||||
game.override.mysteryEncounterTier(MysteryEncounterTier.COMMON);
|
||||
game.override.startingWave(defaultWave);
|
||||
game.override.startingBiome(defaultBiome);
|
||||
|
||||
const biomeMap = new Map<Biome, MysteryEncounterType[]>([
|
||||
[Biome.VOLCANO, [MysteryEncounterType.MYSTERIOUS_CHALLENGERS]],
|
||||
]);
|
||||
HUMAN_TRANSITABLE_BIOMES.forEach(biome => {
|
||||
biomeMap.set(biome, [MysteryEncounterType.OFFER_YOU_CANT_REFUSE]);
|
||||
});
|
||||
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(biomeMap);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
vi.clearAllMocks();
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it("should have the correct properties", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.OFFER_YOU_CANT_REFUSE, defaultParty);
|
||||
|
||||
expect(OfferYouCantRefuseEncounter.encounterType).toBe(MysteryEncounterType.OFFER_YOU_CANT_REFUSE);
|
||||
expect(OfferYouCantRefuseEncounter.encounterTier).toBe(MysteryEncounterTier.GREAT);
|
||||
expect(OfferYouCantRefuseEncounter.dialogue).toBeDefined();
|
||||
expect(OfferYouCantRefuseEncounter.dialogue.intro).toStrictEqual([
|
||||
{ text: `${namespace}:intro` },
|
||||
{ speaker: `${namespace}:speaker`, text: `${namespace}:intro_dialogue` }
|
||||
]);
|
||||
expect(OfferYouCantRefuseEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}:title`);
|
||||
expect(OfferYouCantRefuseEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}:description`);
|
||||
expect(OfferYouCantRefuseEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}:query`);
|
||||
expect(OfferYouCantRefuseEncounter.options.length).toBe(3);
|
||||
});
|
||||
|
||||
it("should not spawn outside of HUMAN_TRANSITABLE_BIOMES", async () => {
|
||||
game.override.startingBiome(Biome.VOLCANO);
|
||||
await game.runToMysteryEncounter();
|
||||
|
||||
expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.OFFER_YOU_CANT_REFUSE);
|
||||
});
|
||||
|
||||
it("should not run below wave 10", async () => {
|
||||
game.override.startingWave(9);
|
||||
|
||||
await game.runToMysteryEncounter();
|
||||
|
||||
expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.OFFER_YOU_CANT_REFUSE);
|
||||
});
|
||||
|
||||
it("should not run above wave 179", async () => {
|
||||
game.override.startingWave(181);
|
||||
|
||||
await game.runToMysteryEncounter();
|
||||
|
||||
expect(scene.currentBattle.mysteryEncounter).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should initialize fully ", async () => {
|
||||
initSceneWithoutEncounterPhase(scene, defaultParty);
|
||||
scene.currentBattle.mysteryEncounter = OfferYouCantRefuseEncounter;
|
||||
|
||||
const { onInit } = OfferYouCantRefuseEncounter;
|
||||
|
||||
expect(OfferYouCantRefuseEncounter.onInit).toBeDefined();
|
||||
|
||||
OfferYouCantRefuseEncounter.populateDialogueTokensFromRequirements(scene);
|
||||
const onInitResult = onInit(scene);
|
||||
|
||||
expect(OfferYouCantRefuseEncounter.dialogueTokens?.strongestPokemon).toBeDefined();
|
||||
expect(OfferYouCantRefuseEncounter.dialogueTokens?.price).toBeDefined();
|
||||
expect(OfferYouCantRefuseEncounter.dialogueTokens?.option2PrimaryAbility).toBe("Intimidate");
|
||||
expect(OfferYouCantRefuseEncounter.dialogueTokens?.moveOrAbility).toBe("Intimidate");
|
||||
expect(OfferYouCantRefuseEncounter.misc.pokemon instanceof PlayerPokemon).toBeTruthy();
|
||||
expect(OfferYouCantRefuseEncounter.misc?.price?.toString()).toBe(OfferYouCantRefuseEncounter.dialogueTokens?.price);
|
||||
expect(onInitResult).toBe(true);
|
||||
});
|
||||
|
||||
describe("Option 1 - Sell your Pokemon for money and a Shiny Charm", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option = OfferYouCantRefuseEncounter.options[0];
|
||||
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
|
||||
expect(option.dialogue).toBeDefined();
|
||||
expect(option.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:1:label`,
|
||||
buttonTooltip: `${namespace}:option:1:tooltip`,
|
||||
selected: [
|
||||
{
|
||||
speaker: `${namespace}:speaker`,
|
||||
text: `${namespace}:option:1:selected`,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("Should update the player's money properly", async () => {
|
||||
const initialMoney = 20000;
|
||||
scene.money = initialMoney;
|
||||
const updateMoneySpy = vi.spyOn(EncounterPhaseUtils, "updatePlayerMoney");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.OFFER_YOU_CANT_REFUSE, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
const price = scene.currentBattle.mysteryEncounter.misc.price;
|
||||
|
||||
expect(updateMoneySpy).toHaveBeenCalledWith(scene, price);
|
||||
expect(scene.money).toBe(initialMoney + price);
|
||||
});
|
||||
|
||||
it("Should remove the Pokemon from the party", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.OFFER_YOU_CANT_REFUSE, defaultParty);
|
||||
|
||||
const initialPartySize = scene.getParty().length;
|
||||
const pokemonName = scene.currentBattle.mysteryEncounter.misc.pokemon.name;
|
||||
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
expect(scene.getParty().length).toBe(initialPartySize - 1);
|
||||
expect(scene.getParty().find(p => p.name === pokemonName)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should leave encounter without battle", async () => {
|
||||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.OFFER_YOU_CANT_REFUSE, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Option 2 - Extort the Kid", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option = OfferYouCantRefuseEncounter.options[1];
|
||||
expect(option.optionMode).toBe(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL);
|
||||
expect(option.dialogue).toBeDefined();
|
||||
expect(option.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:2:label`,
|
||||
buttonTooltip: `${namespace}:option:2:tooltip`,
|
||||
disabledButtonTooltip: `${namespace}:option:2:tooltip_disabled`,
|
||||
selected: [
|
||||
{
|
||||
speaker: `${namespace}:speaker`,
|
||||
text: `${namespace}:option:2:selected`,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should award EXP to a pokemon with an ability in EXTORTION_ABILITIES", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.OFFER_YOU_CANT_REFUSE, defaultParty);
|
||||
const party = scene.getParty();
|
||||
const gyarados = party.find((pkm) => pkm.species.speciesId === Species.GYARADOS);
|
||||
const expBefore = gyarados.exp;
|
||||
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
||||
expect(gyarados.exp).toBe(expBefore + Math.floor(getPokemonSpecies(Species.LIEPARD).baseExp * defaultWave / 5 + 1));
|
||||
});
|
||||
|
||||
it("should award EXP to a pokemon with a move in EXTORTION_MOVES", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.OFFER_YOU_CANT_REFUSE, [Species.ABRA]);
|
||||
const party = scene.getParty();
|
||||
const abra = party.find((pkm) => pkm.species.speciesId === Species.ABRA);
|
||||
abra.moveset = [new PokemonMove(Moves.BEAT_UP)];
|
||||
const expBefore = abra.exp;
|
||||
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
||||
expect(abra.exp).toBe(expBefore + Math.floor(getPokemonSpecies(Species.LIEPARD).baseExp * defaultWave / 5 + 1));
|
||||
});
|
||||
|
||||
it("Should update the player's money properly", async () => {
|
||||
const initialMoney = 20000;
|
||||
scene.money = initialMoney;
|
||||
const updateMoneySpy = vi.spyOn(EncounterPhaseUtils, "updatePlayerMoney");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.OFFER_YOU_CANT_REFUSE, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
||||
const price = scene.currentBattle.mysteryEncounter.misc.price;
|
||||
|
||||
expect(updateMoneySpy).toHaveBeenCalledWith(scene, price);
|
||||
expect(scene.money).toBe(initialMoney + price);
|
||||
});
|
||||
|
||||
it("should leave encounter without battle", async () => {
|
||||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.OFFER_YOU_CANT_REFUSE, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Option 3 - Leave", () => {
|
||||
it("should leave encounter without battle", async () => {
|
||||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.OFFER_YOU_CANT_REFUSE, defaultParty);
|
||||
await runMysteryEncounterToEnd(game, 3);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -4,15 +4,15 @@ import { MysteryEncounterType } from "#app/enums/mystery-encounter-type";
|
|||
import { Species } from "#app/enums/species";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import Battle from "#app/battle";
|
||||
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { EncounterOptionMode } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { runSelectMysteryEncounterOption } from "#test/mystery-encounter/encounterTestUtils";
|
||||
import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounterTestUtils";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import { MysteryEncounterTier } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { PlayerPokemon } from "#app/field/pokemon";
|
||||
import { HUMAN_TRANSITABLE_BIOMES } from "#app/data/mystery-encounters/mystery-encounters";
|
||||
import { PokemonSalesmanEncounter } from "#app/data/mystery-encounters/encounters/pokemon-salesman-encounter";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils";
|
||||
|
||||
const namespace = "mysteryEncounter:pokemonSalesman";
|
||||
const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA];
|
||||
|
@ -59,7 +59,7 @@ describe("The Pokemon Salesman - Mystery Encounter", () => {
|
|||
expect(PokemonSalesmanEncounter.dialogue).toBeDefined();
|
||||
expect(PokemonSalesmanEncounter.dialogue.intro).toStrictEqual([
|
||||
{ text: `${namespace}:intro` },
|
||||
{ speaker: "mysteryEncounter:pokemonSalesman:speaker", text: "mysteryEncounter:pokemonSalesman:intro_dialogue" }
|
||||
{ speaker: `${namespace}:speaker`, text: `${namespace}:intro_dialogue` }
|
||||
]);
|
||||
expect(PokemonSalesmanEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}:title`);
|
||||
expect(PokemonSalesmanEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}:description`);
|
||||
|
@ -91,12 +91,14 @@ describe("The Pokemon Salesman - Mystery Encounter", () => {
|
|||
});
|
||||
|
||||
it("should initialize fully ", async () => {
|
||||
vi.spyOn(scene, "currentBattle", "get").mockReturnValue({ mysteryEncounter: PokemonSalesmanEncounter } as Battle);
|
||||
initSceneWithoutEncounterPhase(scene, defaultParty);
|
||||
scene.currentBattle.mysteryEncounter = PokemonSalesmanEncounter;
|
||||
|
||||
const { onInit } = PokemonSalesmanEncounter;
|
||||
|
||||
expect(PokemonSalesmanEncounter.onInit).toBeDefined();
|
||||
|
||||
PokemonSalesmanEncounter.populateDialogueTokensFromRequirements(scene);
|
||||
const onInitResult = onInit(scene);
|
||||
|
||||
expect(PokemonSalesmanEncounter.dialogueTokens?.purchasePokemon).toBeDefined();
|
||||
|
@ -109,7 +111,7 @@ describe("The Pokemon Salesman - Mystery Encounter", () => {
|
|||
describe("Option 1 - Purchase the pokemon", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option1 = PokemonSalesmanEncounter.options[0];
|
||||
expect(option1.optionMode).toBe(EncounterOptionMode.DEFAULT_OR_SPECIAL);
|
||||
expect(option1.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT_OR_SPECIAL);
|
||||
expect(option1.dialogue).toBeDefined();
|
||||
expect(option1.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:1:label`,
|
||||
|
@ -128,7 +130,7 @@ describe("The Pokemon Salesman - Mystery Encounter", () => {
|
|||
const updateMoneySpy = vi.spyOn(EncounterPhaseUtils, "updatePlayerMoney");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.POKEMON_SALESMAN, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 1);
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
const price = scene.currentBattle.mysteryEncounter.misc.price;
|
||||
|
||||
|
@ -142,7 +144,7 @@ describe("The Pokemon Salesman - Mystery Encounter", () => {
|
|||
const initialPartySize = scene.getParty().length;
|
||||
const pokemonName = scene.currentBattle.mysteryEncounter.misc.pokemon.name;
|
||||
|
||||
await runSelectMysteryEncounterOption(game, 1);
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
expect(scene.getParty().length).toBe(initialPartySize + 1);
|
||||
expect(scene.getParty().find(p => p.name === pokemonName) instanceof PlayerPokemon).toBeTruthy();
|
||||
|
@ -152,7 +154,7 @@ describe("The Pokemon Salesman - Mystery Encounter", () => {
|
|||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.POKEMON_SALESMAN, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 1);
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
|
@ -163,7 +165,7 @@ describe("The Pokemon Salesman - Mystery Encounter", () => {
|
|||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.POKEMON_SALESMAN, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 2);
|
||||
await runMysteryEncounterToEnd(game, 2);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
|
|
|
@ -4,17 +4,14 @@ import { MysteryEncounterType } from "#app/enums/mystery-encounter-type";
|
|||
import { Species } from "#app/enums/species";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import Battle from "#app/battle";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import * as BattleAnims from "#app/data/battle-anims";
|
||||
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { EncounterOptionMode } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { runSelectMysteryEncounterOption, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
|
||||
import { runMysteryEncounterToEnd, skipBattleRunMysteryEncounterRewardsPhase } from "#test/mystery-encounter/encounterTestUtils";
|
||||
import { CommandPhase, MovePhase, SelectModifierPhase } from "#app/phases";
|
||||
import { Moves } from "#enums/moves";
|
||||
import BattleScene from "#app/battle-scene";
|
||||
import * as Modifiers from "#app/modifier/modifier";
|
||||
import { MysteryEncounterTier } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import { TheStrongStuffEncounter } from "#app/data/mystery-encounters/encounters/the-strong-stuff-encounter";
|
||||
import { Nature } from "#app/data/nature";
|
||||
import { BerryType } from "#enums/berry-type";
|
||||
|
@ -23,6 +20,9 @@ import { PokemonMove } from "#app/field/pokemon";
|
|||
import { Mode } from "#app/ui/ui";
|
||||
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
|
||||
import { PokemonBaseStatTotalModifier } from "#app/modifier/modifier";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils";
|
||||
|
||||
const namespace = "mysteryEncounter:theStrongStuff";
|
||||
const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA];
|
||||
|
@ -97,7 +97,8 @@ describe("The Strong Stuff - Mystery Encounter", () => {
|
|||
});
|
||||
|
||||
it("should initialize fully ", async () => {
|
||||
vi.spyOn(scene, "currentBattle", "get").mockReturnValue({ mysteryEncounter: TheStrongStuffEncounter } as Battle);
|
||||
initSceneWithoutEncounterPhase(scene, defaultParty);
|
||||
scene.currentBattle.mysteryEncounter = TheStrongStuffEncounter;
|
||||
const moveInitSpy = vi.spyOn(BattleAnims, "loadMoveAnimAssets");
|
||||
const moveLoadSpy = vi.spyOn(BattleAnims, "loadMoveAnimAssets");
|
||||
|
||||
|
@ -105,6 +106,7 @@ describe("The Strong Stuff - Mystery Encounter", () => {
|
|||
|
||||
expect(TheStrongStuffEncounter.onInit).toBeDefined();
|
||||
|
||||
TheStrongStuffEncounter.populateDialogueTokensFromRequirements(scene);
|
||||
const onInitResult = onInit(scene);
|
||||
|
||||
expect(TheStrongStuffEncounter.enemyPartyConfigs).toEqual([
|
||||
|
@ -134,7 +136,7 @@ describe("The Strong Stuff - Mystery Encounter", () => {
|
|||
describe("Option 1 - Power Swap BSTs", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option1 = TheStrongStuffEncounter.options[0];
|
||||
expect(option1.optionMode).toBe(EncounterOptionMode.DEFAULT);
|
||||
expect(option1.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
|
||||
expect(option1.dialogue).toBeDefined();
|
||||
expect(option1.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:1:label`,
|
||||
|
@ -151,7 +153,7 @@ describe("The Strong Stuff - Mystery Encounter", () => {
|
|||
await game.runToMysteryEncounter(MysteryEncounterType.THE_STRONG_STUFF, defaultParty);
|
||||
|
||||
const bstsPrior = scene.getParty().map(p => p.getSpeciesForm().getBaseStatTotal());
|
||||
await runSelectMysteryEncounterOption(game, 1);
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
const bstsAfter = scene.getParty().map(p => {
|
||||
const baseStats = p.getSpeciesForm().baseStats.slice(0);
|
||||
|
@ -168,7 +170,7 @@ describe("The Strong Stuff - Mystery Encounter", () => {
|
|||
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.THE_STRONG_STUFF, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 1);
|
||||
await runMysteryEncounterToEnd(game, 1);
|
||||
|
||||
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||
});
|
||||
|
@ -177,7 +179,7 @@ describe("The Strong Stuff - Mystery Encounter", () => {
|
|||
describe("Option 2 - battle the Shuckle", () => {
|
||||
it("should have the correct properties", () => {
|
||||
const option1 = TheStrongStuffEncounter.options[1];
|
||||
expect(option1.optionMode).toBe(EncounterOptionMode.DEFAULT);
|
||||
expect(option1.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT);
|
||||
expect(option1.dialogue).toBeDefined();
|
||||
expect(option1.dialogue).toStrictEqual({
|
||||
buttonLabel: `${namespace}:option:2:label`,
|
||||
|
@ -194,7 +196,7 @@ describe("The Strong Stuff - Mystery Encounter", () => {
|
|||
const phaseSpy = vi.spyOn(scene, "pushPhase");
|
||||
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.THE_STRONG_STUFF, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 2, true);
|
||||
await runMysteryEncounterToEnd(game, 2, true);
|
||||
|
||||
const enemyField = scene.getEnemyField();
|
||||
expect(scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
|
||||
|
@ -218,7 +220,7 @@ describe("The Strong Stuff - Mystery Encounter", () => {
|
|||
|
||||
it("should have Soul Dew in rewards", async () => {
|
||||
await game.runToMysteryEncounter(MysteryEncounterType.THE_STRONG_STUFF, defaultParty);
|
||||
await runSelectMysteryEncounterOption(game, 2, true);
|
||||
await runMysteryEncounterToEnd(game, 2, true);
|
||||
await skipBattleRunMysteryEncounterRewardsPhase(game);
|
||||
await game.phaseInterceptor.to(SelectModifierPhase, false);
|
||||
expect(scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name);
|
||||
|
|
|
@ -7,8 +7,8 @@ import {Mode} from "#app/ui/ui";
|
|||
import {Button} from "#enums/buttons";
|
||||
import MysteryEncounterUiHandler from "#app/ui/mystery-encounter-ui-handler";
|
||||
import {MysteryEncounterType} from "#enums/mystery-encounter-type";
|
||||
import {MysteryEncounterTier} from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import MessageUiHandler from "#app/ui/message-ui-handler";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
|
||||
describe("Mystery Encounter Phases", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
|
|
|
@ -5,9 +5,9 @@ import { MockInstance, vi } from "vitest";
|
|||
import GameManager from "#test/utils/gameManager";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import * as overrides from "#app/overrides";
|
||||
import { MysteryEncounterTier } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import * as GameMode from "#app/game-mode";
|
||||
import { GameModes, getGameMode } from "#app/game-mode";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
|
||||
/**
|
||||
* Helper to handle overrides in tests
|
||||
|
|
|
@ -11,13 +11,15 @@ import {
|
|||
LearnMovePhase,
|
||||
LoginPhase,
|
||||
MessagePhase,
|
||||
ModifierRewardPhase,
|
||||
MoveEffectPhase,
|
||||
MoveEndPhase,
|
||||
MovePhase,
|
||||
NewBattlePhase,
|
||||
NextEncounterPhase,
|
||||
PostSummonPhase,
|
||||
SelectGenderPhase, SelectModifierPhase,
|
||||
SelectGenderPhase,
|
||||
SelectModifierPhase,
|
||||
SelectStarterPhase,
|
||||
SelectTargetPhase,
|
||||
ShinySparklePhase,
|
||||
|
@ -105,6 +107,7 @@ export default class PhaseInterceptor {
|
|||
[MysteryEncounterRewardsPhase, this.startPhase],
|
||||
[PostMysteryEncounterPhase, this.startPhase],
|
||||
[LearnMovePhase, this.startPhase],
|
||||
[ModifierRewardPhase, this.startPhase],
|
||||
// [CommonAnimPhase, this.startPhase]
|
||||
];
|
||||
|
||||
|
|
|
@ -6,14 +6,15 @@ import { Button } from "#enums/buttons";
|
|||
import { addWindow, WindowVariant } from "./ui-theme";
|
||||
import { MysteryEncounterPhase } from "../phases/mystery-encounter-phases";
|
||||
import { PartyUiMode } from "./party-ui-handler";
|
||||
import MysteryEncounterOption, { EncounterOptionMode } from "../data/mystery-encounters/mystery-encounter-option";
|
||||
import MysteryEncounterOption from "../data/mystery-encounters/mystery-encounter-option";
|
||||
import * as Utils from "../utils";
|
||||
import { isNullOrUndefined } from "../utils";
|
||||
import { getPokeballAtlasKey } from "../data/pokeball";
|
||||
import { OptionSelectSettings } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||
import { MysteryEncounterTier } from "#app/data/mystery-encounters/mystery-encounter";
|
||||
import i18next from "i18next";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||
|
||||
export default class MysteryEncounterUiHandler extends UiHandler {
|
||||
private cursorContainer: Phaser.GameObjects.Container;
|
||||
|
@ -146,7 +147,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
|||
this.unblockInput();
|
||||
}, 300);
|
||||
});
|
||||
} else if (this.blockInput || (!this.optionsMeetsReqs[cursor] && (selected.optionMode === EncounterOptionMode.DISABLED_OR_DEFAULT || selected.optionMode === EncounterOptionMode.DISABLED_OR_SPECIAL))) {
|
||||
} else if (this.blockInput || (!this.optionsMeetsReqs[cursor] && (selected.optionMode === MysteryEncounterOptionMode.DISABLED_OR_DEFAULT || selected.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL))) {
|
||||
success = false;
|
||||
} else {
|
||||
if ((this.scene.getCurrentPhase() as MysteryEncounterPhase).handleOptionSelect(selected, cursor)) {
|
||||
|
@ -290,7 +291,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
|||
this.blockInput = false;
|
||||
for (let i = 0; i < this.optionsContainer.length - 1; i++) {
|
||||
const optionMode = this.encounterOptions[i].optionMode;
|
||||
if (!this.optionsMeetsReqs[i] && (optionMode === EncounterOptionMode.DISABLED_OR_DEFAULT || optionMode === EncounterOptionMode.DISABLED_OR_SPECIAL)) {
|
||||
if (!this.optionsMeetsReqs[i] && (optionMode === MysteryEncounterOptionMode.DISABLED_OR_DEFAULT || optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)) {
|
||||
continue;
|
||||
}
|
||||
(this.optionsContainer.getAt(i) as Phaser.GameObjects.Text).setAlpha(1);
|
||||
|
@ -363,7 +364,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
|||
const optionDialogue = option.dialogue;
|
||||
const label = !this.optionsMeetsReqs[i] && optionDialogue.disabledButtonLabel ? optionDialogue.disabledButtonLabel : optionDialogue.buttonLabel;
|
||||
let text: string;
|
||||
if (option.hasRequirements() && this.optionsMeetsReqs[i] && (option.optionMode === EncounterOptionMode.DEFAULT_OR_SPECIAL || option.optionMode === EncounterOptionMode.DISABLED_OR_SPECIAL)) {
|
||||
if (option.hasRequirements() && this.optionsMeetsReqs[i] && (option.optionMode === MysteryEncounterOptionMode.DEFAULT_OR_SPECIAL || option.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)) {
|
||||
// Options with special requirements that are met are automatically colored green
|
||||
text = getEncounterText(this.scene, label, TextStyle.SUMMARY_GREEN);
|
||||
} else {
|
||||
|
@ -374,7 +375,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
|||
optionText.setText(text);
|
||||
}
|
||||
|
||||
if (!this.optionsMeetsReqs[i] && (option.optionMode === EncounterOptionMode.DISABLED_OR_DEFAULT || option.optionMode === EncounterOptionMode.DISABLED_OR_SPECIAL)) {
|
||||
if (!this.optionsMeetsReqs[i] && (option.optionMode === MysteryEncounterOptionMode.DISABLED_OR_DEFAULT || option.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)) {
|
||||
optionText.setAlpha(0.5);
|
||||
}
|
||||
if (this.blockInput) {
|
||||
|
@ -468,7 +469,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
|||
let text: string;
|
||||
const cursorOption = this.encounterOptions[cursor];
|
||||
const optionDialogue = cursorOption.dialogue;
|
||||
if (!this.optionsMeetsReqs[cursor] && (cursorOption.optionMode === EncounterOptionMode.DISABLED_OR_DEFAULT || cursorOption.optionMode === EncounterOptionMode.DISABLED_OR_SPECIAL) && optionDialogue.disabledButtonTooltip) {
|
||||
if (!this.optionsMeetsReqs[cursor] && (cursorOption.optionMode === MysteryEncounterOptionMode.DISABLED_OR_DEFAULT || cursorOption.optionMode === MysteryEncounterOptionMode.DISABLED_OR_SPECIAL) && optionDialogue.disabledButtonTooltip) {
|
||||
text = getEncounterText(this.scene, optionDialogue.disabledButtonTooltip, TextStyle.TOOLTIP_CONTENT);
|
||||
} else {
|
||||
text = getEncounterText(this.scene, optionDialogue.buttonTooltip, TextStyle.TOOLTIP_CONTENT);
|
||||
|
|
Loading…
Reference in New Issue