migrate shady-vitamin-dealer encounter

This commit is contained in:
Felix Staud 2024-07-11 14:39:18 -07:00
parent 71a047a1f6
commit 19d96ed381
4 changed files with 273 additions and 221 deletions

View File

@ -2646,7 +2646,7 @@ export default class BattleScene extends SceneBase {
if (encounter) { if (encounter) {
encounter = new MysteryEncounter(encounter); encounter = new MysteryEncounter(encounter);
encounter.meetsRequirements(this); encounter.populateDialogueTokensFromRequirements(this);
return encounter; return encounter;
} }
@ -2674,7 +2674,7 @@ export default class BattleScene extends SceneBase {
tier = Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE; tier = Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE;
} }
let availableEncounters = []; let availableEncounters: MysteryEncounter[] = [];
// New encounter will never be the same as the most recent encounter // New encounter will never be the same as the most recent encounter
const previousEncounter = this.mysteryEncounterData.encounteredEvents?.length > 0 ? this.mysteryEncounterData.encounteredEvents[this.mysteryEncounterData.encounteredEvents.length - 1][0] : null; const previousEncounter = this.mysteryEncounterData.encounteredEvents?.length > 0 ? this.mysteryEncounterData.encounteredEvents[this.mysteryEncounterData.encounteredEvents.length - 1][0] : null;
const biomeMysteryEncounters = mysteryEncountersByBiome.get(this.arena.biomeType); const biomeMysteryEncounters = mysteryEncountersByBiome.get(this.arena.biomeType);

View File

@ -1,42 +0,0 @@
import MysteryEncounterDialogue from "#app/data/mystery-encounters/mystery-encounter-dialogue";
export const ShadyVitaminDealerDialogue: MysteryEncounterDialogue = {
intro: [
{
text: "mysteryEncounter:shady_vitamin_dealer_intro_message"
},
{
text: "mysteryEncounter:shady_vitamin_dealer_intro_dialogue",
speaker: "mysteryEncounter:shady_vitamin_dealer_speaker"
}
],
encounterOptionsDialogue: {
title: "mysteryEncounter:shady_vitamin_dealer_title",
description: "mysteryEncounter:shady_vitamin_dealer_description",
query: "mysteryEncounter:shady_vitamin_dealer_query",
options: [
{
buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_1_label",
buttonTooltip: "mysteryEncounter:shady_vitamin_dealer_option_1_tooltip",
selected: [
{
text: "mysteryEncounter:shady_vitamin_dealer_option_selected"
}
]
},
{
buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_2_label",
buttonTooltip: "mysteryEncounter:shady_vitamin_dealer_option_2_tooltip",
selected: [
{
text: "mysteryEncounter:shady_vitamin_dealer_option_selected"
}
]
},
{
buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_3_label",
buttonTooltip: "mysteryEncounter:shady_vitamin_dealer_option_3_tooltip"
}
]
}
};

View File

@ -2,7 +2,8 @@ import {
generateModifierTypeOption, generateModifierTypeOption,
leaveEncounterWithoutBattle, leaveEncounterWithoutBattle,
queueEncounterMessage, queueEncounterMessage,
selectPokemonForOption, setEncounterExp, selectPokemonForOption,
setEncounterExp,
updatePlayerMoney, updatePlayerMoney,
} from "#app/data/mystery-encounters/mystery-encounter-utils"; } from "#app/data/mystery-encounters/mystery-encounter-utils";
import { StatusEffect } from "#app/data/status-effect"; import { StatusEffect } from "#app/data/status-effect";
@ -11,184 +12,279 @@ import { modifierTypes } from "#app/modifier/modifier-type";
import { randSeedInt } from "#app/utils"; import { randSeedInt } from "#app/utils";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import BattleScene from "../../../battle-scene";
import MysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier } from "../mystery-encounter";
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
import {
MoneyRequirement
} from "../mystery-encounter-requirements";
import i18next from "i18next"; import i18next from "i18next";
import BattleScene from "../../../battle-scene";
import MysteryEncounter, {
MysteryEncounterBuilder,
MysteryEncounterTier,
} from "../mystery-encounter";
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
import { MoneyRequirement } from "../mystery-encounter-requirements";
export const ShadyVitaminDealerEncounter: MysteryEncounter = MysteryEncounterBuilder export const ShadyVitaminDealerEncounter: MysteryEncounter =
.withEncounterType(MysteryEncounterType.SHADY_VITAMIN_DEALER) MysteryEncounterBuilder.withEncounterType(
.withEncounterTier(MysteryEncounterTier.COMMON) MysteryEncounterType.SHADY_VITAMIN_DEALER
.withIntroSpriteConfigs([ )
{ .withEncounterTier(MysteryEncounterTier.COMMON)
spriteKey: Species.KROOKODILE.toString(), .withSceneWaveRangeRequirement(10, 180)
fileRoot: "pokemon", .withPrimaryPokemonStatusEffectRequirement([StatusEffect.NONE]) // Pokemon must not have status
hasShadow: true, .withPrimaryPokemonHealthRatioRequirement([0.34, 1]) // Pokemon must have above 1/3rd HP
repeat: true, .withIntroSpriteConfigs([
x: 10, {
y: -1 spriteKey: Species.KROOKODILE.toString(),
}, fileRoot: "pokemon",
{ hasShadow: true,
spriteKey: "b2w2_veteran_m", repeat: true,
fileRoot: "mystery-encounters", x: 10,
hasShadow: true, y: -1,
x: -10, },
y: 2 {
} spriteKey: "b2w2_veteran_m",
]) fileRoot: "mystery-encounters",
.withSceneWaveRangeRequirement(10, 180) hasShadow: true,
.withPrimaryPokemonStatusEffectRequirement([StatusEffect.NONE]) // Pokemon must not have status x: -10,
.withPrimaryPokemonHealthRatioRequirement([0.34, 1]) // Pokemon must have above 1/3rd HP y: 2,
.withOption(new MysteryEncounterOptionBuilder() },
.withSceneMoneyRequirement(0, 2) // Wave scaling money multiplier of 2 ])
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => { .withIntroDialogue([
const encounter = scene.currentBattle.mysteryEncounter; {
const onPokemonSelected = (pokemon: PlayerPokemon) => { text: "mysteryEncounter:shady_vitamin_dealer_intro_message",
// Update money },
updatePlayerMoney(scene, -(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney); {
// Calculate modifiers and dialogue tokens text: "mysteryEncounter:shady_vitamin_dealer_intro_dialogue",
const modifiers = [ speaker: "mysteryEncounter:shady_vitamin_dealer_speaker",
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type, },
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type ])
]; .withTitle("mysteryEncounter:shady_vitamin_dealer_title")
encounter.setDialogueToken("boost1", modifiers[0].name); .withDescription("mysteryEncounter:shady_vitamin_dealer_description")
encounter.setDialogueToken("boost2", modifiers[1].name); .withQuery("mysteryEncounter:shady_vitamin_dealer_query")
encounter.misc = { .withOption(
chosenPokemon: pokemon, new MysteryEncounterOptionBuilder()
modifiers: modifiers .withSceneMoneyRequirement(0, 2) // Wave scaling money multiplier of 2
}; .withDialogue({
}; buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_1_label",
buttonTooltip:
"mysteryEncounter:shady_vitamin_dealer_option_1_tooltip",
selected: [
{
text: "mysteryEncounter:shady_vitamin_dealer_option_selected",
},
],
})
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
const encounter = scene.currentBattle.mysteryEncounter;
const onPokemonSelected = (pokemon: PlayerPokemon) => {
// Update money
updatePlayerMoney(
scene,
-(encounter.options[0].requirements[0] as MoneyRequirement)
.requiredMoney
);
// Calculate modifiers and dialogue tokens
const modifiers = [
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER)
.type,
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER)
.type,
];
encounter.setDialogueToken("boost1", modifiers[0].name);
encounter.setDialogueToken("boost2", modifiers[1].name);
encounter.misc = {
chosenPokemon: pokemon,
modifiers: modifiers,
};
};
// 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(scene, pokemon); const meetsReqs = encounter.pokemonMeetsPrimaryRequirements(
if (!meetsReqs) { scene,
return i18next.t("mysteryEncounter:shady_vitamin_dealer_invalid_selection"); pokemon
} );
if (!meetsReqs) {
return i18next.t(
"mysteryEncounter:shady_vitamin_dealer_invalid_selection"
);
}
return null; return null;
}; };
return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter); return selectPokemonForOption(
}) scene,
.withOptionPhase(async (scene: BattleScene) => { onPokemonSelected,
// Choose Cheap Option null,
const encounter = scene.currentBattle.mysteryEncounter; selectableFilter
const chosenPokemon = encounter.misc.chosenPokemon; );
const modifiers = encounter.misc.modifiers; })
.withOptionPhase(async (scene: BattleScene) => {
// Choose Cheap Option
const encounter = scene.currentBattle.mysteryEncounter;
const chosenPokemon = encounter.misc.chosenPokemon;
const modifiers = encounter.misc.modifiers;
for (const modType of modifiers) { for (const modType of modifiers) {
const modifier = modType.newModifier(chosenPokemon); const modifier = modType.newModifier(chosenPokemon);
await scene.addModifier(modifier, true, false, false, true); await scene.addModifier(modifier, true, false, false, true);
}
scene.updateModifiers(true);
leaveEncounterWithoutBattle(scene);
})
.withPostOptionPhase(async (scene: BattleScene) => {
// Damage and status applied after dealer leaves (to make thematic sense)
const encounter = scene.currentBattle.mysteryEncounter;
const chosenPokemon = encounter.misc.chosenPokemon;
// Pokemon takes 1/3 max HP damage
const damage = Math.round(chosenPokemon.getMaxHp() / 3);
chosenPokemon.hp = Math.max(chosenPokemon.hp - damage, 0);
// Roll for poison (80%)
if (randSeedInt(10) < 8) {
if (chosenPokemon.trySetStatus(StatusEffect.TOXIC)) {
// Toxic applied
queueEncounterMessage(
scene,
"mysteryEncounter:shady_vitamin_dealer_bad_poison"
);
} else {
// Pokemon immune or something else prevents status
queueEncounterMessage(
scene,
"mysteryEncounter:shady_vitamin_dealer_damage_only"
);
}
} else {
queueEncounterMessage(
scene,
"mysteryEncounter:shady_vitamin_dealer_damage_only"
);
}
setEncounterExp(scene, [chosenPokemon.id], 100);
chosenPokemon.updateInfo();
})
.build()
)
.withOption(
new MysteryEncounterOptionBuilder()
.withDialogue({
buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_2_label",
buttonTooltip:
"mysteryEncounter:shady_vitamin_dealer_option_2_tooltip",
selected: [
{
text: "mysteryEncounter:shady_vitamin_dealer_option_selected",
},
],
})
.withSceneMoneyRequirement(0, 5) // Wave scaling money multiplier of 5
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
const encounter = scene.currentBattle.mysteryEncounter;
const onPokemonSelected = (pokemon: PlayerPokemon) => {
// Update money
updatePlayerMoney(
scene,
-(encounter.options[1].requirements[0] as MoneyRequirement)
.requiredMoney
);
// Calculate modifiers and dialogue tokens
const modifiers = [
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER)
.type,
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER)
.type,
];
encounter.setDialogueToken("boost1", modifiers[0].name);
encounter.setDialogueToken("boost2", modifiers[1].name);
encounter.misc = {
chosenPokemon: pokemon,
modifiers: modifiers,
};
};
// Only Pokemon that can gain benefits are above 1/3rd HP with no status
const selectableFilter = (pokemon: Pokemon) => {
// If pokemon meets primary pokemon reqs, it can be selected
const meetsReqs = encounter.pokemonMeetsPrimaryRequirements(
scene,
pokemon
);
if (!meetsReqs) {
return i18next.t(
"mysteryEncounter:shady_vitamin_dealer_invalid_selection"
);
}
return null;
};
return selectPokemonForOption(
scene,
onPokemonSelected,
null,
selectableFilter
);
})
.withOptionPhase(async (scene: BattleScene) => {
// Choose Expensive Option
const encounter = scene.currentBattle.mysteryEncounter;
const chosenPokemon = encounter.misc.chosenPokemon;
const modifiers = encounter.misc.modifiers;
for (const modType of modifiers) {
const modifier = modType.newModifier(chosenPokemon);
await scene.addModifier(modifier, true, false, false, true);
}
scene.updateModifiers(true);
leaveEncounterWithoutBattle(scene);
})
.withPostOptionPhase(async (scene: BattleScene) => {
// Status applied after dealer leaves (to make thematic sense)
const encounter = scene.currentBattle.mysteryEncounter;
const chosenPokemon = encounter.misc.chosenPokemon;
// Roll for poison (20%)
if (randSeedInt(10) < 2) {
if (chosenPokemon.trySetStatus(StatusEffect.POISON)) {
// Poison applied
queueEncounterMessage(
scene,
"mysteryEncounter:shady_vitamin_dealer_poison"
);
} else {
// Pokemon immune or something else prevents status
queueEncounterMessage(
scene,
"mysteryEncounter:shady_vitamin_dealer_no_bad_effects"
);
}
} else {
queueEncounterMessage(
scene,
"mysteryEncounter:shady_vitamin_dealer_no_bad_effects"
);
}
setEncounterExp(scene, [chosenPokemon.id], 100);
chosenPokemon.updateInfo();
})
.build()
)
.withSimpleOption(
{
buttonLabel: "mysteryEncounter:shady_vitamin_dealer_option_3_label",
buttonTooltip: "mysteryEncounter:shady_vitamin_dealer_option_3_tooltip",
},
async (scene: BattleScene) => {
// Leave encounter with no rewards or exp
leaveEncounterWithoutBattle(scene, true);
return true;
} }
scene.updateModifiers(true); )
.build();
leaveEncounterWithoutBattle(scene);
})
.withPostOptionPhase(async (scene: BattleScene) => {
// Damage and status applied after dealer leaves (to make thematic sense)
const encounter = scene.currentBattle.mysteryEncounter;
const chosenPokemon = encounter.misc.chosenPokemon;
// Pokemon takes 1/3 max HP damage
const damage = Math.round(chosenPokemon.getMaxHp() / 3);
chosenPokemon.hp = Math.max(chosenPokemon.hp - damage, 0);
// Roll for poison (80%)
if (randSeedInt(10) < 8) {
if (chosenPokemon.trySetStatus(StatusEffect.TOXIC)) {
// Toxic applied
queueEncounterMessage(scene, "mysteryEncounter:shady_vitamin_dealer_bad_poison");
} else {
// Pokemon immune or something else prevents status
queueEncounterMessage(scene, "mysteryEncounter:shady_vitamin_dealer_damage_only");
}
} else {
queueEncounterMessage(scene, "mysteryEncounter:shady_vitamin_dealer_damage_only");
}
setEncounterExp(scene, [chosenPokemon.id], 100);
chosenPokemon.updateInfo();
})
.build())
.withOption(new MysteryEncounterOptionBuilder()
.withSceneMoneyRequirement(0, 5) // Wave scaling money multiplier of 5
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
const encounter = scene.currentBattle.mysteryEncounter;
const onPokemonSelected = (pokemon: PlayerPokemon) => {
// Update money
updatePlayerMoney(scene, -(encounter.options[1].requirements[0] as MoneyRequirement).requiredMoney);
// Calculate modifiers and dialogue tokens
const modifiers = [
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type,
generateModifierTypeOption(scene, modifierTypes.BASE_STAT_BOOSTER).type
];
encounter.setDialogueToken("boost1", modifiers[0].name);
encounter.setDialogueToken("boost2", modifiers[1].name);
encounter.misc = {
chosenPokemon: pokemon,
modifiers: modifiers
};
};
// Only Pokemon that can gain benefits are above 1/3rd HP with no status
const selectableFilter = (pokemon: Pokemon) => {
// If pokemon meets primary pokemon reqs, it can be selected
const meetsReqs = encounter.pokemonMeetsPrimaryRequirements(scene, pokemon);
if (!meetsReqs) {
return i18next.t("mysteryEncounter:shady_vitamin_dealer_invalid_selection");
}
return null;
};
return selectPokemonForOption(scene, onPokemonSelected, null, selectableFilter);
})
.withOptionPhase(async (scene: BattleScene) => {
// Choose Expensive Option
const encounter = scene.currentBattle.mysteryEncounter;
const chosenPokemon = encounter.misc.chosenPokemon;
const modifiers = encounter.misc.modifiers;
for (const modType of modifiers) {
const modifier = modType.newModifier(chosenPokemon);
await scene.addModifier(modifier, true, false, false, true);
}
scene.updateModifiers(true);
leaveEncounterWithoutBattle(scene);
})
.withPostOptionPhase(async (scene: BattleScene) => {
// Status applied after dealer leaves (to make thematic sense)
const encounter = scene.currentBattle.mysteryEncounter;
const chosenPokemon = encounter.misc.chosenPokemon;
// Roll for poison (20%)
if (randSeedInt(10) < 2) {
if (chosenPokemon.trySetStatus(StatusEffect.POISON)) {
// Poison applied
queueEncounterMessage(scene, "mysteryEncounter:shady_vitamin_dealer_poison");
} else {
// Pokemon immune or something else prevents status
queueEncounterMessage(scene, "mysteryEncounter:shady_vitamin_dealer_no_bad_effects");
}
} else {
queueEncounterMessage(scene, "mysteryEncounter:shady_vitamin_dealer_no_bad_effects");
}
setEncounterExp(scene, [chosenPokemon.id], 100);
chosenPokemon.updateInfo();
})
.build())
.withSimpleOption(async (scene: BattleScene) => {
// Leave encounter with no rewards or exp
leaveEncounterWithoutBattle(scene, true);
return true;
})
.build();

View File

@ -1,7 +1,6 @@
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { TrainingSessionDialogue } from "#app/data/mystery-encounters/dialogue/training-session-dialogue"; import { TrainingSessionDialogue } from "#app/data/mystery-encounters/dialogue/training-session-dialogue";
import { SleepingSnorlaxDialogue } from "./dialogue/sleeping-snorlax-dialogue"; import { SleepingSnorlaxDialogue } from "./dialogue/sleeping-snorlax-dialogue";
import { ShadyVitaminDealerDialogue } from "#app/data/mystery-encounters/dialogue/shady-vitamin-dealer";
import { TextStyle } from "#app/ui/text"; import { TextStyle } from "#app/ui/text";
export class TextDisplay { export class TextDisplay {
@ -81,5 +80,4 @@ export const allMysteryEncounterDialogue: { [encounterType: number]: MysteryEnco
export function initMysteryEncounterDialogue() { export function initMysteryEncounterDialogue() {
allMysteryEncounterDialogue[MysteryEncounterType.TRAINING_SESSION] = TrainingSessionDialogue; allMysteryEncounterDialogue[MysteryEncounterType.TRAINING_SESSION] = TrainingSessionDialogue;
allMysteryEncounterDialogue[MysteryEncounterType.SLEEPING_SNORLAX] = SleepingSnorlaxDialogue; allMysteryEncounterDialogue[MysteryEncounterType.SLEEPING_SNORLAX] = SleepingSnorlaxDialogue;
allMysteryEncounterDialogue[MysteryEncounterType.SHADY_VITAMIN_DEALER] = ShadyVitaminDealerDialogue;
} }