Merge pull request #64 from AsdarDevelops/option-ui-enhancements

add option mode for UI styling consistency
This commit is contained in:
flx-sta 2024-07-12 10:40:28 -07:00 committed by GitHub
commit 5ff80cd8a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 120 additions and 334 deletions

View File

@ -7,19 +7,9 @@ import BattleScene from "../../../battle-scene";
import { AddPokeballModifierType } from "../../../modifier/modifier-type"; import { AddPokeballModifierType } from "../../../modifier/modifier-type";
import { PokeballType } from "../../pokeball"; import { PokeballType } from "../../pokeball";
import { getPokemonSpecies } from "../../pokemon-species"; import { getPokemonSpecies } from "../../pokemon-species";
import IMysteryEncounter, { import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter";
MysteryEncounterBuilder, import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
MysteryEncounterTier, import { EnemyPartyConfig, EnemyPokemonConfig, getRandomPlayerPokemon, getRandomSpeciesByStarterTier, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, } from "../mystery-encounter-utils";
} from "../mystery-encounter";
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
import {
EnemyPartyConfig,
EnemyPokemonConfig,
getRandomPlayerPokemon,
getRandomSpeciesByStarterTier,
initBattleWithEnemyConfig,
leaveEncounterWithoutBattle,
} from "../mystery-encounter-utils";
/** i18n namespace for encounter */ /** i18n namespace for encounter */
const namespace = "mysteryEncounter:dark_deal"; const namespace = "mysteryEncounter:dark_deal";
@ -27,6 +17,10 @@ const namespace = "mysteryEncounter:dark_deal";
// Exclude Ultra Beasts, Paradox, Necrozma, Eternatus, and egg-locked mythicals // Exclude Ultra Beasts, Paradox, Necrozma, Eternatus, and egg-locked mythicals
const excludedBosses = [ const excludedBosses = [
Species.NECROZMA, Species.NECROZMA,
Species.COSMOG,
Species.COSMOEM,
Species.SOLGALEO,
Species.LUNALA,
Species.ETERNATUS, Species.ETERNATUS,
Species.NIHILEGO, Species.NIHILEGO,
Species.BUZZWOLE, Species.BUZZWOLE,
@ -106,6 +100,7 @@ export const DarkDealEncounter: IMysteryEncounter =
.withQuery(`${namespace}_query`) .withQuery(`${namespace}_query`)
.withOption( .withOption(
new MysteryEncounterOptionBuilder() new MysteryEncounterOptionBuilder()
.withOptionMode(EncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}_option_1_label`, buttonLabel: `${namespace}_option_1_label`,
buttonTooltip: `${namespace}_option_1_tooltip`, buttonTooltip: `${namespace}_option_1_tooltip`,
@ -135,20 +130,12 @@ export const DarkDealEncounter: IMysteryEncounter =
removedPokemon.species.type1, removedPokemon.species.type1,
]; ];
if (removedPokemon.species.type2) { if (removedPokemon.species.type2) {
scene.currentBattle.mysteryEncounter.misc.push( scene.currentBattle.mysteryEncounter.misc.push(removedPokemon.species.type2);
removedPokemon.species.type2
);
} }
}) })
.withOptionPhase(async (scene: BattleScene) => { .withOptionPhase(async (scene: BattleScene) => {
// Give the player 5 Rogue Balls // Give the player 5 Rogue Balls
scene.unshiftPhase( scene.unshiftPhase(new ModifierRewardPhase(scene, () => new AddPokeballModifierType("rb", PokeballType.ROGUE_BALL, 5)));
new ModifierRewardPhase(
scene,
() =>
new AddPokeballModifierType("rb", PokeballType.ROGUE_BALL, 5)
)
);
// Start encounter with random legendary (7-10 starter strength) that has level additive // Start encounter with random legendary (7-10 starter strength) that has level additive
const bossTypes = scene.currentBattle.mysteryEncounter.misc as Type[]; const bossTypes = scene.currentBattle.mysteryEncounter.misc as Type[];
@ -156,21 +143,12 @@ export const DarkDealEncounter: IMysteryEncounter =
const roll = randSeedInt(100); const roll = randSeedInt(100);
const starterTier: number | [number, number] = const starterTier: number | [number, number] =
roll > 65 ? 6 : roll > 15 ? 7 : roll > 5 ? 8 : [9, 10]; roll > 65 ? 6 : roll > 15 ? 7 : roll > 5 ? 8 : [9, 10];
const bossSpecies = getPokemonSpecies( const bossSpecies = getPokemonSpecies(getRandomSpeciesByStarterTier(starterTier, excludedBosses, bossTypes));
getRandomSpeciesByStarterTier(
starterTier,
excludedBosses,
bossTypes
)
);
const pokemonConfig: EnemyPokemonConfig = { const pokemonConfig: EnemyPokemonConfig = {
species: bossSpecies, species: bossSpecies,
isBoss: true, isBoss: true,
}; };
if ( if (!isNullOrUndefined(bossSpecies.forms) && bossSpecies.forms.length > 0) {
!isNullOrUndefined(bossSpecies.forms) &&
bossSpecies.forms.length > 0
) {
pokemonConfig.formIndex = 0; pokemonConfig.formIndex = 0;
} }
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
@ -194,7 +172,6 @@ export const DarkDealEncounter: IMysteryEncounter =
}, },
async (scene: BattleScene) => { async (scene: BattleScene) => {
// Leave encounter with no rewards or exp // Leave encounter with no rewards or exp
leaveEncounterWithoutBattle(scene, true); leaveEncounterWithoutBattle(scene, true);
return true; return true;
} }

View File

@ -16,9 +16,7 @@ import IMysteryEncounter, {
const namespace = "mysteryEncounter:department_store_sale"; const namespace = "mysteryEncounter:department_store_sale";
export const DepartmentStoreSaleEncounter: IMysteryEncounter = export const DepartmentStoreSaleEncounter: IMysteryEncounter =
MysteryEncounterBuilder.withEncounterType( MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.DEPARTMENT_STORE_SALE)
MysteryEncounterType.DEPARTMENT_STORE_SALE
)
.withEncounterTier(MysteryEncounterTier.COMMON) .withEncounterTier(MysteryEncounterTier.COMMON)
.withSceneWaveRangeRequirement(10, 100) .withSceneWaveRangeRequirement(10, 100)
.withIntroSpriteConfigs([ .withIntroSpriteConfigs([
@ -45,7 +43,7 @@ export const DepartmentStoreSaleEncounter: IMysteryEncounter =
speaker: `${namespace}_speaker`, speaker: `${namespace}_speaker`,
}, },
]) ])
// .withHideIntroVisuals(false) .withHideIntroVisuals(false)
.withTitle(`${namespace}_title`) .withTitle(`${namespace}_title`)
.withDescription(`${namespace}_description`) .withDescription(`${namespace}_description`)
.withQuery(`${namespace}_query`) .withQuery(`${namespace}_query`)
@ -71,10 +69,7 @@ export const DepartmentStoreSaleEncounter: IMysteryEncounter =
i++; i++;
} }
setEncounterRewards(scene, { setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false, });
guaranteedModifierTypeFuncs: modifiers,
fillRemaining: false,
});
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} }
) )
@ -98,10 +93,7 @@ export const DepartmentStoreSaleEncounter: IMysteryEncounter =
i++; i++;
} }
setEncounterRewards(scene, { setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false, });
guaranteedModifierTypeFuncs: modifiers,
fillRemaining: false,
});
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} }
) )
@ -125,10 +117,7 @@ export const DepartmentStoreSaleEncounter: IMysteryEncounter =
i++; i++;
} }
setEncounterRewards(scene, { setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false, });
guaranteedModifierTypeFuncs: modifiers,
fillRemaining: false,
});
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} }
) )
@ -156,10 +145,7 @@ export const DepartmentStoreSaleEncounter: IMysteryEncounter =
i++; i++;
} }
setEncounterRewards(scene, { setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false, });
guaranteedModifierTypeFuncs: modifiers,
fillRemaining: false,
});
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
} }
) )

View File

@ -1,5 +1,5 @@
import { MoveCategory } from "#app/data/move"; import { MoveCategory } from "#app/data/move";
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
import { import {
generateModifierTypeOption, generateModifierTypeOption,
leaveEncounterWithoutBattle, leaveEncounterWithoutBattle,
@ -57,6 +57,7 @@ export const FieldTripEncounter: IMysteryEncounter =
.withQuery(`${namespace}_query`) .withQuery(`${namespace}_query`)
.withOption( .withOption(
new MysteryEncounterOptionBuilder() new MysteryEncounterOptionBuilder()
.withOptionMode(EncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}_option_1_label`, buttonLabel: `${namespace}_option_1_label`,
buttonTooltip: `${namespace}_option_1_tooltip`, buttonTooltip: `${namespace}_option_1_tooltip`,
@ -76,8 +77,7 @@ export const FieldTripEncounter: IMysteryEncounter =
label: move.getName(), label: move.getName(),
handler: () => { handler: () => {
// Pokemon and move selected // Pokemon and move selected
const correctMove = const correctMove = move.getMove().category === MoveCategory.PHYSICAL;
move.getMove().category === MoveCategory.PHYSICAL;
encounter.setDialogueToken("moveCategory", "Physical"); encounter.setDialogueToken("moveCategory", "Physical");
if (!correctMove) { if (!correctMove) {
encounter.options[0].dialogue.selected = [ encounter.options[0].dialogue.selected = [
@ -89,11 +89,7 @@ export const FieldTripEncounter: IMysteryEncounter =
text: `${namespace}_lesson_learned`, text: `${namespace}_lesson_learned`,
}, },
]; ];
setEncounterExp( setEncounterExp(scene, scene.getParty().map((p) => p.id), 50);
scene,
scene.getParty().map((p) => p.id),
50
);
} else { } else {
encounter.setDialogueToken("pokeName", pokemon.name); encounter.setDialogueToken("pokeName", pokemon.name);
encounter.setDialogueToken("move", move.getName()); encounter.setDialogueToken("move", move.getName());
@ -120,28 +116,13 @@ export const FieldTripEncounter: IMysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter; const encounter = scene.currentBattle.mysteryEncounter;
if (encounter.misc.correctMove) { if (encounter.misc.correctMove) {
const modifiers = [ const modifiers = [
generateModifierTypeOption( generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.ATK]),
scene, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.DEF]),
modifierTypes.TEMP_STAT_BOOSTER, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPD]),
[TempBattleStat.ATK]
),
generateModifierTypeOption(
scene,
modifierTypes.TEMP_STAT_BOOSTER,
[TempBattleStat.DEF]
),
generateModifierTypeOption(
scene,
modifierTypes.TEMP_STAT_BOOSTER,
[TempBattleStat.SPD]
),
generateModifierTypeOption(scene, modifierTypes.DIRE_HIT), generateModifierTypeOption(scene, modifierTypes.DIRE_HIT),
]; ];
setEncounterRewards(scene, { setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifiers, fillRemaining: false });
guaranteedModifierTypeOptions: modifiers,
fillRemaining: false,
});
} }
leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove); leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove);
@ -150,6 +131,7 @@ export const FieldTripEncounter: IMysteryEncounter =
) )
.withOption( .withOption(
new MysteryEncounterOptionBuilder() new MysteryEncounterOptionBuilder()
.withOptionMode(EncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}_option_2_label`, buttonLabel: `${namespace}_option_2_label`,
buttonTooltip: `${namespace}_option_2_tooltip`, buttonTooltip: `${namespace}_option_2_tooltip`,
@ -169,8 +151,7 @@ export const FieldTripEncounter: IMysteryEncounter =
label: move.getName(), label: move.getName(),
handler: () => { handler: () => {
// Pokemon and move selected // Pokemon and move selected
const correctMove = const correctMove = move.getMove().category === MoveCategory.SPECIAL;
move.getMove().category === MoveCategory.SPECIAL;
encounter.setDialogueToken("moveCategory", "Special"); encounter.setDialogueToken("moveCategory", "Special");
if (!correctMove) { if (!correctMove) {
encounter.options[1].dialogue.selected = [ encounter.options[1].dialogue.selected = [
@ -182,11 +163,7 @@ export const FieldTripEncounter: IMysteryEncounter =
text: `${namespace}_lesson_learned`, text: `${namespace}_lesson_learned`,
}, },
]; ];
setEncounterExp( setEncounterExp(scene, scene.getParty().map((p) => p.id), 50);
scene,
scene.getParty().map((p) => p.id),
50
);
} else { } else {
encounter.setDialogueToken("pokeName", pokemon.name); encounter.setDialogueToken("pokeName", pokemon.name);
encounter.setDialogueToken("move", move.getName()); encounter.setDialogueToken("move", move.getName());
@ -213,28 +190,13 @@ export const FieldTripEncounter: IMysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter; const encounter = scene.currentBattle.mysteryEncounter;
if (encounter.misc.correctMove) { if (encounter.misc.correctMove) {
const modifiers = [ const modifiers = [
generateModifierTypeOption( generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPATK]),
scene, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPDEF]),
modifierTypes.TEMP_STAT_BOOSTER, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPD]),
[TempBattleStat.SPATK]
),
generateModifierTypeOption(
scene,
modifierTypes.TEMP_STAT_BOOSTER,
[TempBattleStat.SPDEF]
),
generateModifierTypeOption(
scene,
modifierTypes.TEMP_STAT_BOOSTER,
[TempBattleStat.SPD]
),
generateModifierTypeOption(scene, modifierTypes.DIRE_HIT), generateModifierTypeOption(scene, modifierTypes.DIRE_HIT),
]; ];
setEncounterRewards(scene, { setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifiers, fillRemaining: false });
guaranteedModifierTypeOptions: modifiers,
fillRemaining: false,
});
} }
leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove); leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove);
@ -243,6 +205,7 @@ export const FieldTripEncounter: IMysteryEncounter =
) )
.withOption( .withOption(
new MysteryEncounterOptionBuilder() new MysteryEncounterOptionBuilder()
.withOptionMode(EncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}_option_3_label`, buttonLabel: `${namespace}_option_3_label`,
buttonTooltip: `${namespace}_option_3_tooltip`, buttonTooltip: `${namespace}_option_3_tooltip`,
@ -262,8 +225,7 @@ export const FieldTripEncounter: IMysteryEncounter =
label: move.getName(), label: move.getName(),
handler: () => { handler: () => {
// Pokemon and move selected // Pokemon and move selected
const correctMove = const correctMove = move.getMove().category === MoveCategory.STATUS;
move.getMove().category === MoveCategory.STATUS;
encounter.setDialogueToken("moveCategory", "Status"); encounter.setDialogueToken("moveCategory", "Status");
if (!correctMove) { if (!correctMove) {
encounter.options[2].dialogue.selected = [ encounter.options[2].dialogue.selected = [
@ -306,24 +268,13 @@ export const FieldTripEncounter: IMysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter; const encounter = scene.currentBattle.mysteryEncounter;
if (encounter.misc.correctMove) { if (encounter.misc.correctMove) {
const modifiers = [ const modifiers = [
generateModifierTypeOption( generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.ACC]),
scene, generateModifierTypeOption(scene, modifierTypes.TEMP_STAT_BOOSTER, [TempBattleStat.SPD]),
modifierTypes.TEMP_STAT_BOOSTER,
[TempBattleStat.ACC]
),
generateModifierTypeOption(
scene,
modifierTypes.TEMP_STAT_BOOSTER,
[TempBattleStat.SPD]
),
generateModifierTypeOption(scene, modifierTypes.GREAT_BALL), generateModifierTypeOption(scene, modifierTypes.GREAT_BALL),
generateModifierTypeOption(scene, modifierTypes.IV_SCANNER), generateModifierTypeOption(scene, modifierTypes.IV_SCANNER),
]; ];
setEncounterRewards(scene, { setEncounterRewards(scene, { guaranteedModifierTypeOptions: modifiers, fillRemaining: false });
guaranteedModifierTypeOptions: modifiers,
fillRemaining: false,
});
} }
leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove); leaveEncounterWithoutBattle(scene, !encounter.misc.correctMove);

View File

@ -1,5 +1,5 @@
import { BattleStat } from "#app/data/battle-stat"; import { BattleStat } from "#app/data/battle-stat";
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
import { import {
EnemyPartyConfig, EnemyPartyConfig,
initBattleWithEnemyConfig, initBattleWithEnemyConfig,
@ -50,13 +50,7 @@ export const FightOrFlightEncounter: IMysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter; const encounter = scene.currentBattle.mysteryEncounter;
// Calculate boss mon // Calculate boss mon
const bossSpecies = scene.arena.randomSpecies( const bossSpecies = scene.arena.randomSpecies(scene.currentBattle.waveIndex, scene.currentBattle.waveIndex, 0, getPartyLuckValue(scene.getParty()), true);
scene.currentBattle.waveIndex,
scene.currentBattle.waveIndex,
0,
getPartyLuckValue(scene.getParty()),
true
);
const config: EnemyPartyConfig = { const config: EnemyPartyConfig = {
levelAdditiveMultiplier: 1, levelAdditiveMultiplier: 1,
pokemonConfigs: [{ species: bossSpecies, isBoss: true }], pokemonConfigs: [{ species: bossSpecies, isBoss: true }],
@ -73,17 +67,12 @@ export const FightOrFlightEncounter: IMysteryEncounter =
: scene.currentBattle.waveIndex > 60 : scene.currentBattle.waveIndex > 60
? ModifierTier.ULTRA ? ModifierTier.ULTRA
: ModifierTier.GREAT; : ModifierTier.GREAT;
regenerateModifierPoolThresholds( regenerateModifierPoolThresholds(scene.getParty(), ModifierPoolType.PLAYER, 0);
scene.getParty(), const item = getPlayerModifierTypeOptions(1, scene.getParty(), [], { guaranteedModifierTiers: [tier] })[0];
ModifierPoolType.PLAYER,
0
); // refresh player item pool
const item = getPlayerModifierTypeOptions(1, scene.getParty(), [], {
guaranteedModifierTiers: [tier],
})[0];
encounter.setDialogueToken("itemName", item.type.name); encounter.setDialogueToken("itemName", item.type.name);
encounter.misc = item; encounter.misc = item;
const bossSpriteKey = bossSpecies.getSpriteId(false, bossSpecies.forms ? 0 : null, false, bossSpecies.hasVariants() ? 0 : null);
encounter.spriteConfigs = [ encounter.spriteConfigs = [
{ {
spriteKey: item.type.iconImage, spriteKey: item.type.iconImage,
@ -95,7 +84,7 @@ export const FightOrFlightEncounter: IMysteryEncounter =
isItem: true, isItem: true,
}, },
{ {
spriteKey: bossSpecies.speciesId.toString(), spriteKey: bossSpriteKey,
fileRoot: "pokemon", fileRoot: "pokemon",
hasShadow: true, hasShadow: true,
tint: 0.25, tint: 0.25,
@ -133,20 +122,14 @@ export const FightOrFlightEncounter: IMysteryEncounter =
// Pick battle // Pick battle
const item = scene.currentBattle.mysteryEncounter const item = scene.currentBattle.mysteryEncounter
.misc as ModifierTypeOption; .misc as ModifierTypeOption;
setEncounterRewards(scene, { setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false });
guaranteedModifierTypeOptions: [item], await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]);
fillRemaining: false,
});
await initBattleWithEnemyConfig(
scene,
scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]
);
} }
) )
.withOption( .withOption(
new MysteryEncounterOptionBuilder() new MysteryEncounterOptionBuilder()
.withOptionMode(EncounterOptionMode.DEFAULT_OR_SPECIAL)
.withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically .withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically
.withDisabledOnRequirementsNotMet(false)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}_option_2_label`, buttonLabel: `${namespace}_option_2_label`,
buttonTooltip: `${namespace}_option_2_tooltip`, buttonTooltip: `${namespace}_option_2_tooltip`,
@ -154,21 +137,14 @@ export const FightOrFlightEncounter: IMysteryEncounter =
.withOptionPhase(async (scene: BattleScene) => { .withOptionPhase(async (scene: BattleScene) => {
// Pick steal // Pick steal
const encounter = scene.currentBattle.mysteryEncounter; const encounter = scene.currentBattle.mysteryEncounter;
const item = scene.currentBattle.mysteryEncounter const item = scene.currentBattle.mysteryEncounter.misc as ModifierTypeOption;
.misc as ModifierTypeOption; setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false });
setEncounterRewards(scene, {
guaranteedModifierTypeOptions: [item],
fillRemaining: false,
});
// If player has a stealing move, they succeed automatically // If player has a stealing move, they succeed automatically
const primaryPokemon = encounter.options[1].primaryPokemon; const primaryPokemon = encounter.options[1].primaryPokemon;
if (primaryPokemon) { if (primaryPokemon) {
// Use primaryPokemon to execute the thievery // Use primaryPokemon to execute the thievery
await showEncounterText( await showEncounterText(scene, `${namespace}_option_2_steal_result`);
scene,
`${namespace}_option_2_steal_result`
);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
return; return;
} }
@ -176,34 +152,12 @@ export const FightOrFlightEncounter: IMysteryEncounter =
const roll = randSeedInt(16); const roll = randSeedInt(16);
if (roll > 6) { if (roll > 6) {
// Noticed and attacked by boss, gets +1 to all stats at start of fight (62.5%) // Noticed and attacked by boss, gets +1 to all stats at start of fight (62.5%)
const config = const config = scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0];
scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]; config.pokemonConfigs[0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON];
config.pokemonConfigs[0].tags = [ config.pokemonConfigs[0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => {
BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON, pokemon.scene.currentBattle.mysteryEncounter.setDialogueToken("enemyPokemon", pokemon.name);
];
config.pokemonConfigs[0].mysteryEncounterBattleEffects = (
pokemon: Pokemon
) => {
pokemon.scene.currentBattle.mysteryEncounter.setDialogueToken(
"enemyPokemon",
pokemon.name
);
queueEncounterMessage(pokemon.scene, `${namespace}_boss_enraged`); queueEncounterMessage(pokemon.scene, `${namespace}_boss_enraged`);
pokemon.scene.unshiftPhase( pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD], 1));
new StatChangePhase(
pokemon.scene,
pokemon.getBattlerIndex(),
true,
[
BattleStat.ATK,
BattleStat.DEF,
BattleStat.SPATK,
BattleStat.SPDEF,
BattleStat.SPD,
],
1
)
);
}; };
await showEncounterText(scene, `${namespace}_option_2_bad_result`); await showEncounterText(scene, `${namespace}_option_2_bad_result`);
await initBattleWithEnemyConfig(scene, config); await initBattleWithEnemyConfig(scene, config);

View File

@ -40,18 +40,13 @@ export const MysteriousChallengersEncounter: IMysteryEncounter =
// Calculates what trainers are available for battle in the encounter // Calculates what trainers are available for battle in the encounter
// Normal difficulty trainer is randomly pulled from biome // Normal difficulty trainer is randomly pulled from biome
const normalTrainerType = scene.arena.randomTrainerType( const normalTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex);
scene.currentBattle.waveIndex
);
const normalConfig = trainerConfigs[normalTrainerType].copy(); const normalConfig = trainerConfigs[normalTrainerType].copy();
let female = false; let female = false;
if (normalConfig.hasGenders) { if (normalConfig.hasGenders) {
female = !!Utils.randSeedInt(2); female = !!Utils.randSeedInt(2);
} }
const normalSpriteKey = normalConfig.getSpriteKey( const normalSpriteKey = normalConfig.getSpriteKey(female, normalConfig.doubleOnly);
female,
normalConfig.doubleOnly
);
encounter.enemyPartyConfigs.push({ encounter.enemyPartyConfigs.push({
trainerConfig: normalConfig, trainerConfig: normalConfig,
female: female, female: female,
@ -59,9 +54,7 @@ export const MysteriousChallengersEncounter: IMysteryEncounter =
// Hard difficulty trainer is another random trainer, but with AVERAGE_BALANCED config // Hard difficulty trainer is another random trainer, but with AVERAGE_BALANCED config
// Number of mons is based off wave: 1-20 is 2, 20-40 is 3, etc. capping at 6 after wave 100 // Number of mons is based off wave: 1-20 is 2, 20-40 is 3, etc. capping at 6 after wave 100
const hardTrainerType = scene.arena.randomTrainerType( const hardTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex);
scene.currentBattle.waveIndex
);
const hardTemplate = new TrainerPartyCompoundTemplate( const hardTemplate = new TrainerPartyCompoundTemplate(
new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER, false, true), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER, false, true),
new TrainerPartyTemplate( new TrainerPartyTemplate(
@ -77,10 +70,7 @@ export const MysteriousChallengersEncounter: IMysteryEncounter =
if (hardConfig.hasGenders) { if (hardConfig.hasGenders) {
female = !!Utils.randSeedInt(2); female = !!Utils.randSeedInt(2);
} }
const hardSpriteKey = hardConfig.getSpriteKey( const hardSpriteKey = hardConfig.getSpriteKey(female, hardConfig.doubleOnly);
female,
hardConfig.doubleOnly
);
encounter.enemyPartyConfigs.push({ encounter.enemyPartyConfigs.push({
trainerConfig: hardConfig, trainerConfig: hardConfig,
levelAdditiveMultiplier: 0.5, levelAdditiveMultiplier: 0.5,
@ -101,10 +91,7 @@ export const MysteriousChallengersEncounter: IMysteryEncounter =
if (brutalConfig.hasGenders) { if (brutalConfig.hasGenders) {
female = !!Utils.randSeedInt(2); female = !!Utils.randSeedInt(2);
} }
const brutalSpriteKey = brutalConfig.getSpriteKey( const brutalSpriteKey = brutalConfig.getSpriteKey(female, brutalConfig.doubleOnly);
female,
brutalConfig.doubleOnly
);
encounter.enemyPartyConfigs.push({ encounter.enemyPartyConfigs.push({
trainerConfig: brutalConfig, trainerConfig: brutalConfig,
levelAdditiveMultiplier: 1.1, levelAdditiveMultiplier: 1.1,
@ -152,14 +139,7 @@ export const MysteriousChallengersEncounter: IMysteryEncounter =
// Spawn standard trainer battle with memory mushroom reward // Spawn standard trainer battle with memory mushroom reward
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0]; const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
setEncounterRewards(scene, { setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM], fillRemaining: true });
guaranteedModifierTypeFuncs: [
modifierTypes.TM_COMMON,
modifierTypes.TM_GREAT,
modifierTypes.MEMORY_MUSHROOM,
],
fillRemaining: true,
});
// Seed offsets to remove possibility of different trainers having exact same teams // Seed offsets to remove possibility of different trainers having exact same teams
let ret; let ret;
@ -184,14 +164,7 @@ export const MysteriousChallengersEncounter: IMysteryEncounter =
// Spawn hard fight with ULTRA/GREAT reward (can improve with luck) // Spawn hard fight with ULTRA/GREAT reward (can improve with luck)
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1]; const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1];
setEncounterRewards(scene, { setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT], fillRemaining: true });
guaranteedModifierTiers: [
ModifierTier.ULTRA,
ModifierTier.GREAT,
ModifierTier.GREAT,
],
fillRemaining: true,
});
// Seed offsets to remove possibility of different trainers having exact same teams // Seed offsets to remove possibility of different trainers having exact same teams
let ret; let ret;
@ -219,14 +192,7 @@ export const MysteriousChallengersEncounter: IMysteryEncounter =
// To avoid player level snowballing from picking this option // To avoid player level snowballing from picking this option
encounter.expMultiplier = 0.9; encounter.expMultiplier = 0.9;
setEncounterRewards(scene, { setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT], fillRemaining: true });
guaranteedModifierTiers: [
ModifierTier.ROGUE,
ModifierTier.ULTRA,
ModifierTier.GREAT,
],
fillRemaining: true,
});
// Seed offsets to remove possibility of different trainers having exact same teams // Seed offsets to remove possibility of different trainers having exact same teams
let ret; let ret;

View File

@ -15,7 +15,7 @@ import IMysteryEncounter, {
MysteryEncounterBuilder, MysteryEncounterBuilder,
MysteryEncounterTier, MysteryEncounterTier,
} from "../mystery-encounter"; } from "../mystery-encounter";
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
export const MysteriousChestEncounter: IMysteryEncounter = export const MysteriousChestEncounter: IMysteryEncounter =
MysteryEncounterBuilder.withEncounterType( MysteryEncounterBuilder.withEncounterType(
@ -44,6 +44,7 @@ export const MysteriousChestEncounter: IMysteryEncounter =
.withQuery("mysteryEncounter:mysterious_chest_query") .withQuery("mysteryEncounter:mysterious_chest_query")
.withOption( .withOption(
new MysteryEncounterOptionBuilder() new MysteryEncounterOptionBuilder()
.withOptionMode(EncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: "mysteryEncounter:mysterious_chest_option_1_label", buttonLabel: "mysteryEncounter:mysterious_chest_option_1_label",
buttonTooltip: "mysteryEncounter:mysterious_chest_option_1_tooltip", buttonTooltip: "mysteryEncounter:mysterious_chest_option_1_tooltip",

View File

@ -1,11 +1,4 @@
import { import { generateModifierTypeOption, leaveEncounterWithoutBattle, queueEncounterMessage, selectPokemonForOption, setEncounterExp, updatePlayerMoney, } from "#app/data/mystery-encounters/mystery-encounter-utils";
generateModifierTypeOption,
leaveEncounterWithoutBattle,
queueEncounterMessage,
selectPokemonForOption,
setEncounterExp,
updatePlayerMoney,
} from "#app/data/mystery-encounters/mystery-encounter-utils";
import { StatusEffect } from "#app/data/status-effect"; import { StatusEffect } from "#app/data/status-effect";
import Pokemon, { PlayerPokemon } from "#app/field/pokemon"; import Pokemon, { PlayerPokemon } from "#app/field/pokemon";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
@ -14,11 +7,8 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import i18next from "i18next"; import i18next from "i18next";
import BattleScene from "../../../battle-scene"; import BattleScene from "../../../battle-scene";
import IMysteryEncounter, { import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter";
MysteryEncounterBuilder, import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
MysteryEncounterTier,
} from "../mystery-encounter";
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
import { MoneyRequirement } from "../mystery-encounter-requirements"; import { MoneyRequirement } from "../mystery-encounter-requirements";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
@ -63,6 +53,7 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
.withQuery(`${namespace}_query`) .withQuery(`${namespace}_query`)
.withOption( .withOption(
new MysteryEncounterOptionBuilder() new MysteryEncounterOptionBuilder()
.withOptionMode(EncounterOptionMode.DISABLED_OR_DEFAULT)
.withSceneMoneyRequirement(0, 2) // Wave scaling money multiplier of 2 .withSceneMoneyRequirement(0, 2) // Wave scaling money multiplier of 2
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}_option_1_label`, buttonLabel: `${namespace}_option_1_label`,
@ -77,17 +68,11 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter; const encounter = scene.currentBattle.mysteryEncounter;
const onPokemonSelected = (pokemon: PlayerPokemon) => { const onPokemonSelected = (pokemon: PlayerPokemon) => {
// Update money // Update money
updatePlayerMoney( updatePlayerMoney(scene, -(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney);
scene,
-(encounter.options[0].requirements[0] as MoneyRequirement)
.requiredMoney
);
// Calculate modifiers and dialogue tokens // Calculate modifiers and dialogue tokens
const modifiers = [ const modifiers = [
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER) generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type,
.type, generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type,
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER)
.type,
]; ];
encounter.setDialogueToken("boost1", modifiers[0].name); encounter.setDialogueToken("boost1", modifiers[0].name);
encounter.setDialogueToken("boost2", modifiers[1].name); encounter.setDialogueToken("boost2", modifiers[1].name);
@ -100,10 +85,7 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
// Only Pokemon that can gain benefits are above 1/3rd HP with no status // Only Pokemon that can gain benefits are above 1/3rd HP with no status
const selectableFilter = (pokemon: Pokemon) => { const selectableFilter = (pokemon: Pokemon) => {
// If pokemon meets primary pokemon reqs, it can be selected // If pokemon meets primary pokemon reqs, it can be selected
const meetsReqs = encounter.pokemonMeetsPrimaryRequirements( const meetsReqs = encounter.pokemonMeetsPrimaryRequirements(scene, pokemon);
scene,
pokemon
);
if (!meetsReqs) { if (!meetsReqs) {
return i18next.t(`${namespace}_invalid_selection`); return i18next.t(`${namespace}_invalid_selection`);
} }
@ -111,12 +93,7 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
return null; return null;
}; };
return selectPokemonForOption( return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter);
scene,
onPokemonSelected,
null,
selectableFilter
);
}) })
.withOptionPhase(async (scene: BattleScene) => { .withOptionPhase(async (scene: BattleScene) => {
// Choose Cheap Option // Choose Cheap Option
@ -162,6 +139,8 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
) )
.withOption( .withOption(
new MysteryEncounterOptionBuilder() new MysteryEncounterOptionBuilder()
.withOptionMode(EncounterOptionMode.DISABLED_OR_DEFAULT)
.withSceneMoneyRequirement(0, 5) // Wave scaling money multiplier of 5
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}_option_2_label`, buttonLabel: `${namespace}_option_2_label`,
buttonTooltip: `${namespace}_option_2_tooltip`, buttonTooltip: `${namespace}_option_2_tooltip`,
@ -171,22 +150,15 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
}, },
], ],
}) })
.withSceneMoneyRequirement(0, 5) // Wave scaling money multiplier of 5
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => { .withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
const encounter = scene.currentBattle.mysteryEncounter; const encounter = scene.currentBattle.mysteryEncounter;
const onPokemonSelected = (pokemon: PlayerPokemon) => { const onPokemonSelected = (pokemon: PlayerPokemon) => {
// Update money // Update money
updatePlayerMoney( updatePlayerMoney(scene, -(encounter.options[1].requirements[0] as MoneyRequirement).requiredMoney);
scene,
-(encounter.options[1].requirements[0] as MoneyRequirement)
.requiredMoney
);
// Calculate modifiers and dialogue tokens // Calculate modifiers and dialogue tokens
const modifiers = [ const modifiers = [
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER) generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type,
.type, generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type,
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER)
.type,
]; ];
encounter.setDialogueToken("boost1", modifiers[0].name); encounter.setDialogueToken("boost1", modifiers[0].name);
encounter.setDialogueToken("boost2", modifiers[1].name); encounter.setDialogueToken("boost2", modifiers[1].name);
@ -199,10 +171,7 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
// Only Pokemon that can gain benefits are above 1/3rd HP with no status // Only Pokemon that can gain benefits are above 1/3rd HP with no status
const selectableFilter = (pokemon: Pokemon) => { const selectableFilter = (pokemon: Pokemon) => {
// If pokemon meets primary pokemon reqs, it can be selected // If pokemon meets primary pokemon reqs, it can be selected
const meetsReqs = encounter.pokemonMeetsPrimaryRequirements( const meetsReqs = encounter.pokemonMeetsPrimaryRequirements(scene, pokemon);
scene,
pokemon
);
if (!meetsReqs) { if (!meetsReqs) {
return i18next.t(`${namespace}_invalid_selection`); return i18next.t(`${namespace}_invalid_selection`);
} }
@ -210,12 +179,7 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
return null; return null;
}; };
return selectPokemonForOption( return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter);
scene,
onPokemonSelected,
null,
selectableFilter
);
}) })
.withOptionPhase(async (scene: BattleScene) => { .withOptionPhase(async (scene: BattleScene) => {
// Choose Expensive Option // Choose Expensive Option

View File

@ -7,22 +7,10 @@ import BattleScene from "../../../battle-scene";
import * as Utils from "../../../utils"; import * as Utils from "../../../utils";
import { getPokemonSpecies } from "../../pokemon-species"; import { getPokemonSpecies } from "../../pokemon-species";
import { Status, StatusEffect } from "../../status-effect"; import { Status, StatusEffect } from "../../status-effect";
import IMysteryEncounter, { import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter";
MysteryEncounterBuilder, import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
MysteryEncounterTier,
} from "../mystery-encounter";
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
import { MoveRequirement } from "../mystery-encounter-requirements"; import { MoveRequirement } from "../mystery-encounter-requirements";
import { import { EnemyPartyConfig, EnemyPokemonConfig, generateModifierTypeOption, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, queueEncounterMessage, setEncounterExp, setEncounterRewards, } from "../mystery-encounter-utils";
EnemyPartyConfig,
EnemyPokemonConfig,
generateModifierTypeOption,
initBattleWithEnemyConfig,
leaveEncounterWithoutBattle,
queueEncounterMessage,
setEncounterExp,
setEncounterRewards,
} from "../mystery-encounter-utils";
/** i18n namespace for the encounter */ /** i18n namespace for the encounter */
const namespace = "mysteryEncounter:sleeping_snorlax"; const namespace = "mysteryEncounter:sleeping_snorlax";
@ -152,6 +140,7 @@ export const SleepingSnorlaxEncounter: IMysteryEncounter =
) )
.withOption( .withOption(
new MysteryEncounterOptionBuilder() new MysteryEncounterOptionBuilder()
.withOptionMode(EncounterOptionMode.DISABLED_OR_SPECIAL)
.withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES)) .withPrimaryPokemonRequirement(new MoveRequirement(STEALING_MOVES))
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}_option_3_label`, buttonLabel: `${namespace}_option_3_label`,

View File

@ -1,12 +1,6 @@
import { Ability, allAbilities } from "#app/data/ability"; import { Ability, allAbilities } from "#app/data/ability";
import { import { EnemyPartyConfig, getEncounterText, initBattleWithEnemyConfig, selectPokemonForOption, setEncounterRewards, } from "#app/data/mystery-encounters/mystery-encounter-utils";
EnemyPartyConfig, import { getNatureName, Nature } from "#app/data/nature";
getEncounterText,
initBattleWithEnemyConfig,
selectPokemonForOption,
setEncounterRewards,
} from "#app/data/mystery-encounters/mystery-encounter-utils";
import { Nature, getNatureName } from "#app/data/nature";
import { speciesStarters } from "#app/data/pokemon-species"; import { speciesStarters } from "#app/data/pokemon-species";
import { Stat } from "#app/data/pokemon-stat"; import { Stat } from "#app/data/pokemon-stat";
import { PlayerPokemon } from "#app/field/pokemon"; import { PlayerPokemon } from "#app/field/pokemon";
@ -20,11 +14,8 @@ import { randSeedShuffle } from "#app/utils";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import BattleScene from "../../../battle-scene"; import BattleScene from "../../../battle-scene";
import IMysteryEncounter, { import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } from "../mystery-encounter";
MysteryEncounterBuilder, import { EncounterOptionMode, MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
MysteryEncounterTier,
} from "../mystery-encounter";
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
/** The i18n namespace for the encounter */ /** The i18n namespace for the encounter */
const namespace = "mysteryEncounter:training_session"; const namespace = "mysteryEncounter:training_session";
@ -54,6 +45,7 @@ export const TrainingSessionEncounter: IMysteryEncounter =
.withQuery(`${namespace}_query`) .withQuery(`${namespace}_query`)
.withOption( .withOption(
new MysteryEncounterOptionBuilder() new MysteryEncounterOptionBuilder()
.withOptionMode(EncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}_option_1_label`, buttonLabel: `${namespace}_option_1_label`,
buttonTooltip: `${namespace}_option_1_tooltip`, buttonTooltip: `${namespace}_option_1_tooltip`,
@ -190,6 +182,7 @@ export const TrainingSessionEncounter: IMysteryEncounter =
) )
.withOption( .withOption(
new MysteryEncounterOptionBuilder() new MysteryEncounterOptionBuilder()
.withOptionMode(EncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}_option_2_label`, buttonLabel: `${namespace}_option_2_label`,
buttonTooltip: `${namespace}_option_2_tooltip`, buttonTooltip: `${namespace}_option_2_tooltip`,
@ -275,6 +268,7 @@ export const TrainingSessionEncounter: IMysteryEncounter =
) )
.withOption( .withOption(
new MysteryEncounterOptionBuilder() new MysteryEncounterOptionBuilder()
.withOptionMode(EncounterOptionMode.DEFAULT)
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}_option_3_label`, buttonLabel: `${namespace}_option_3_label`,
buttonTooltip: `${namespace}_option_3_tooltip`, buttonTooltip: `${namespace}_option_3_tooltip`,

View File

@ -3,24 +3,29 @@ import { PlayerPokemon } from "#app/field/pokemon";
import BattleScene from "../../battle-scene"; import BattleScene from "../../battle-scene";
import * as Utils from "../../utils"; import * as Utils from "../../utils";
import { EncounterPokemonRequirement, EncounterSceneRequirement, MoneyRequirement } from "./mystery-encounter-requirements"; import { EncounterPokemonRequirement, EncounterSceneRequirement, MoneyRequirement } from "./mystery-encounter-requirements";
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
}
export type OptionPhaseCallback = (scene: BattleScene) => Promise<void | boolean>; export type OptionPhaseCallback = (scene: BattleScene) => Promise<void | boolean>;
export default interface MysteryEncounterOption { export default interface MysteryEncounterOption {
optionMode: EncounterOptionMode;
requirements?: EncounterSceneRequirement[]; requirements?: EncounterSceneRequirement[];
primaryPokemonRequirements?: EncounterPokemonRequirement[]; primaryPokemonRequirements?: EncounterPokemonRequirement[];
secondaryPokemonRequirements?: EncounterPokemonRequirement[]; secondaryPokemonRequirements?: EncounterPokemonRequirement[];
primaryPokemon?: PlayerPokemon; primaryPokemon?: PlayerPokemon;
secondaryPokemon?: PlayerPokemon[]; secondaryPokemon?: PlayerPokemon[];
excludePrimaryFromSecondaryRequirements?: boolean; excludePrimaryFromSecondaryRequirements?: boolean;
/**
* There are two modes of option requirements:
* 1 (DEFAULT): Option is completely disabled if requirements are not met (unselectable and greyed out)
* 2: Option is *NOT* disabled if requirements are not met
*/
isDisabledOnRequirementsNotMet?: boolean;
/** /**
* Dialogue object containing all the dialogue, messages, tooltips, etc. for this option * Dialogue object containing all the dialogue, messages, tooltips, etc. for this option
@ -42,7 +47,6 @@ export default class MysteryEncounterOption implements MysteryEncounterOption {
this.requirements = this.requirements ? this.requirements : []; this.requirements = this.requirements ? this.requirements : [];
this.primaryPokemonRequirements = this.primaryPokemonRequirements ? this.primaryPokemonRequirements : []; this.primaryPokemonRequirements = this.primaryPokemonRequirements ? this.primaryPokemonRequirements : [];
this.secondaryPokemonRequirements = this.secondaryPokemonRequirements ? this.secondaryPokemonRequirements : []; this.secondaryPokemonRequirements = this.secondaryPokemonRequirements ? this.secondaryPokemonRequirements : [];
this.isDisabledOnRequirementsNotMet = isNullOrUndefined(this.isDisabledOnRequirementsNotMet) ? true : this.isDisabledOnRequirementsNotMet;
} }
hasRequirements?() { hasRequirements?() {
@ -134,6 +138,7 @@ export default class MysteryEncounterOption implements MysteryEncounterOption {
export class MysteryEncounterOptionBuilder implements Partial<MysteryEncounterOption> { export class MysteryEncounterOptionBuilder implements Partial<MysteryEncounterOption> {
optionMode?: EncounterOptionMode;
requirements?: EncounterSceneRequirement[] = []; requirements?: EncounterSceneRequirement[] = [];
primaryPokemonRequirements?: EncounterPokemonRequirement[] = []; primaryPokemonRequirements?: EncounterPokemonRequirement[] = [];
secondaryPokemonRequirements ?: EncounterPokemonRequirement[] = []; secondaryPokemonRequirements ?: EncounterPokemonRequirement[] = [];
@ -144,6 +149,10 @@ export class MysteryEncounterOptionBuilder implements Partial<MysteryEncounterOp
onPostOptionPhase?: OptionPhaseCallback; onPostOptionPhase?: OptionPhaseCallback;
dialogue?: OptionTextDisplay; dialogue?: OptionTextDisplay;
withOptionMode(optionMode: EncounterOptionMode): this & Pick<MysteryEncounterOption, "optionMode"> {
return Object.assign(this, { optionMode });
}
withSceneRequirement(requirement: EncounterSceneRequirement): this & Required<Pick<MysteryEncounterOption, "requirements">> { withSceneRequirement(requirement: EncounterSceneRequirement): this & Required<Pick<MysteryEncounterOption, "requirements">> {
this.requirements.push(requirement); this.requirements.push(requirement);
return Object.assign(this, { requirements: this.requirements }); return Object.assign(this, { requirements: this.requirements });
@ -180,11 +189,6 @@ export class MysteryEncounterOptionBuilder implements Partial<MysteryEncounterOp
return Object.assign(this, { secondaryPokemonRequirements: this.secondaryPokemonRequirements }); return Object.assign(this, { secondaryPokemonRequirements: this.secondaryPokemonRequirements });
} }
withDisabledOnRequirementsNotMet(disabled: boolean): this & Required<Pick<MysteryEncounterOption, "isDisabledOnRequirementsNotMet">> {
this.isDisabledOnRequirementsNotMet = disabled;
return Object.assign(this, { isDisabledOnRequirementsNotMet: this.isDisabledOnRequirementsNotMet });
}
withDialogue(dialogue: OptionTextDisplay) { withDialogue(dialogue: OptionTextDisplay) {
this.dialogue = dialogue; this.dialogue = dialogue;
return this; return this;

View File

@ -9,7 +9,7 @@ import { StatusEffect } from "../status-effect";
import MysteryEncounterDialogue, { import MysteryEncounterDialogue, {
OptionTextDisplay OptionTextDisplay
} from "./mystery-encounter-dialogue"; } from "./mystery-encounter-dialogue";
import MysteryEncounterOption, { MysteryEncounterOptionBuilder, OptionPhaseCallback } from "./mystery-encounter-option"; import MysteryEncounterOption, { EncounterOptionMode, MysteryEncounterOptionBuilder, OptionPhaseCallback } from "./mystery-encounter-option";
import { import {
EncounterPokemonRequirement, EncounterPokemonRequirement,
EncounterSceneRequirement, EncounterSceneRequirement,
@ -136,7 +136,7 @@ export default class IMysteryEncounter implements IMysteryEncounter {
Object.assign(this, encounter); Object.assign(this, encounter);
} }
this.encounterTier = this.encounterTier ? this.encounterTier : MysteryEncounterTier.COMMON; this.encounterTier = this.encounterTier ? this.encounterTier : MysteryEncounterTier.COMMON;
this.dialogue = {}; this.dialogue = this.dialogue ?? {};
this.encounterVariant = MysteryEncounterVariant.DEFAULT; this.encounterVariant = MysteryEncounterVariant.DEFAULT;
this.requirements = this.requirements ? this.requirements : []; this.requirements = this.requirements ? this.requirements : [];
this.hideBattleIntroMessage = !isNullOrUndefined(this.hideBattleIntroMessage) ? this.hideBattleIntroMessage : false; this.hideBattleIntroMessage = !isNullOrUndefined(this.hideBattleIntroMessage) ? this.hideBattleIntroMessage : false;
@ -397,7 +397,7 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
* @returns * @returns
*/ */
withSimpleOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback) { withSimpleOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback) {
return this.withOption(new MysteryEncounterOptionBuilder().withDialogue(dialogue).withOptionPhase(callback).build()); return this.withOption(new MysteryEncounterOptionBuilder().withOptionMode(EncounterOptionMode.DEFAULT).withDialogue(dialogue).withOptionPhase(callback).build());
} }
/** /**

View File

@ -6,7 +6,7 @@ import { Button } from "#enums/buttons";
import { addWindow, WindowVariant } from "./ui-theme"; import { addWindow, WindowVariant } from "./ui-theme";
import { MysteryEncounterPhase } from "../phases/mystery-encounter-phase"; import { MysteryEncounterPhase } from "../phases/mystery-encounter-phase";
import { PartyUiMode } from "./party-ui-handler"; import { PartyUiMode } from "./party-ui-handler";
import MysteryEncounterOption from "../data/mystery-encounters/mystery-encounter-option"; import MysteryEncounterOption, { EncounterOptionMode } from "../data/mystery-encounters/mystery-encounter-option";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { isNullOrUndefined } from "../utils"; import { isNullOrUndefined } from "../utils";
import { getPokeballAtlasKey } from "../data/pokeball"; import { getPokeballAtlasKey } from "../data/pokeball";
@ -100,6 +100,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
if (button === Button.CANCEL || button === Button.ACTION) { if (button === Button.CANCEL || button === Button.ACTION) {
if (button === Button.ACTION) { if (button === Button.ACTION) {
const selected = this.filteredEncounterOptions[cursor];
if (cursor === this.viewPartyIndex) { if (cursor === this.viewPartyIndex) {
// Handle view party // Handle view party
success = true; success = true;
@ -110,10 +111,9 @@ export default class MysteryEncounterUiHandler extends UiHandler {
this.unblockInput(); this.unblockInput();
}, 300); }, 300);
}); });
} else if (this.blockInput || (!this.optionsMeetsReqs[cursor] && this.filteredEncounterOptions[cursor].isDisabledOnRequirementsNotMet)) { } else if (this.blockInput || (!this.optionsMeetsReqs[cursor] && (selected.optionMode === EncounterOptionMode.DISABLED_OR_DEFAULT || selected.optionMode === EncounterOptionMode.DISABLED_OR_SPECIAL))) {
success = false; success = false;
} else { } else {
const selected = this.filteredEncounterOptions[cursor];
if ((this.scene.getCurrentPhase() as MysteryEncounterPhase).handleOptionSelect(selected, cursor)) { if ((this.scene.getCurrentPhase() as MysteryEncounterPhase).handleOptionSelect(selected, cursor)) {
success = true; success = true;
} else { } else {
@ -253,7 +253,8 @@ export default class MysteryEncounterUiHandler extends UiHandler {
if (this.blockInput) { if (this.blockInput) {
this.blockInput = false; this.blockInput = false;
for (let i = 0; i < this.optionsContainer.length - 1; i++) { for (let i = 0; i < this.optionsContainer.length - 1; i++) {
if (!this.optionsMeetsReqs[i] && this.filteredEncounterOptions[i].isDisabledOnRequirementsNotMet) { const optionMode = this.filteredEncounterOptions[i].optionMode;
if (!this.optionsMeetsReqs[i] && (optionMode === EncounterOptionMode.DISABLED_OR_DEFAULT || optionMode === EncounterOptionMode.DISABLED_OR_SPECIAL)) {
continue; continue;
} }
(this.optionsContainer.getAt(i) as Phaser.GameObjects.Text).setAlpha(1); (this.optionsContainer.getAt(i) as Phaser.GameObjects.Text).setAlpha(1);
@ -325,9 +326,8 @@ export default class MysteryEncounterUiHandler extends UiHandler {
this.optionsMeetsReqs.push(option.meetsRequirements(this.scene)); this.optionsMeetsReqs.push(option.meetsRequirements(this.scene));
const optionDialogue = option.dialogue; const optionDialogue = option.dialogue;
let text: string; let text: string;
if (option.hasRequirements() && this.optionsMeetsReqs[i]) { if (option.hasRequirements() && this.optionsMeetsReqs[i] && (option.optionMode === EncounterOptionMode.DEFAULT_OR_SPECIAL || option.optionMode === EncounterOptionMode.DISABLED_OR_SPECIAL)) {
// Options with special requirements that are met are automatically colored green // Options with special requirements that are met are automatically colored green
// In cases where isDisabledOnRequirementsNotMet = false and requirements are not met, option will not be auto-colored
text = getEncounterText(this.scene, optionDialogue.buttonLabel, TextStyle.SUMMARY_GREEN); text = getEncounterText(this.scene, optionDialogue.buttonLabel, TextStyle.SUMMARY_GREEN);
} else { } else {
text = getEncounterText(this.scene, optionDialogue.buttonLabel, optionDialogue.style ? optionDialogue.style : TextStyle.WINDOW); text = getEncounterText(this.scene, optionDialogue.buttonLabel, optionDialogue.style ? optionDialogue.style : TextStyle.WINDOW);
@ -337,7 +337,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
optionText.setText(text); optionText.setText(text);
} }
if (!this.optionsMeetsReqs[i] && option.isDisabledOnRequirementsNotMet) { if (!this.optionsMeetsReqs[i] && (option.optionMode === EncounterOptionMode.DISABLED_OR_DEFAULT || option.optionMode === EncounterOptionMode.DISABLED_OR_SPECIAL)) {
optionText.setAlpha(0.5); optionText.setAlpha(0.5);
} }
if (this.blockInput) { if (this.blockInput) {
@ -425,7 +425,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
let text: string; let text: string;
const cursorOption = this.filteredEncounterOptions[cursor]; const cursorOption = this.filteredEncounterOptions[cursor];
const optionDialogue = cursorOption.dialogue; const optionDialogue = cursorOption.dialogue;
if (!this.optionsMeetsReqs[cursor] && cursorOption.isDisabledOnRequirementsNotMet && optionDialogue.disabledTooltip) { if (!this.optionsMeetsReqs[cursor] && (cursorOption.optionMode === EncounterOptionMode.DISABLED_OR_DEFAULT || cursorOption.optionMode === EncounterOptionMode.DISABLED_OR_SPECIAL) && optionDialogue.disabledTooltip) {
text = getEncounterText(this.scene, optionDialogue.disabledTooltip, TextStyle.TOOLTIP_CONTENT); text = getEncounterText(this.scene, optionDialogue.disabledTooltip, TextStyle.TOOLTIP_CONTENT);
} else { } else {
text = getEncounterText(this.scene, optionDialogue.buttonTooltip, TextStyle.TOOLTIP_CONTENT); text = getEncounterText(this.scene, optionDialogue.buttonTooltip, TextStyle.TOOLTIP_CONTENT);