pokerogue/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts
NightKev 9dcb904649
[Misc] Improve enum naming (#5933)
* Rename `Abilities` to `AbilityId`

* Rename `abilities.ts` to `ability-id.ts`

* Rename `Moves` to `MoveId`

* Rename `moves.ts` to `move-id.ts`

* Rename `Species` to `SpeciesId`

* Rename `species.ts` to `species-id.ts`

* Rename `Biome` to `BiomeId`

* Rename `biome.ts` to `biome-id.ts`

* Replace `Abilities` with `AbilityId` in comments

* Replace `Biome` with `BiomeId` in comments

* Replace `Moves` with `MoveId` in comments

* Replace `Species` with `SpeciesId` in comments
2025-06-04 14:54:27 -07:00

194 lines
7.1 KiB
TypeScript

import {
generateModifierType,
leaveEncounterWithoutBattle,
setEncounterExp,
updatePlayerMoney,
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { modifierTypes } from "#app/modifier/modifier-type";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { SpeciesId } from "#enums/species-id";
import { globalScene } from "#app/global-scene";
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
import {
AbilityRequirement,
CombinationPokemonRequirement,
MoveRequirement,
} from "#app/data/mystery-encounters/mystery-encounter-requirements";
import { getHighestStatTotalPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import { EXTORTION_ABILITIES, EXTORTION_MOVES } from "#app/data/mystery-encounters/requirements/requirement-groups";
import { getPokemonSpecies } from "#app/data/pokemon-species";
import { speciesStarterCosts } from "#app/data/balance/starters";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import i18next from "i18next";
/** the i18n namespace for this encounter */
const namespace = "mysteryEncounters/anOfferYouCantRefuse";
/**
* Money offered starts at base value of Relic Gold, increasing linearly up to 3x Relic Gold based on the starter tier of the Pokemon being purchased
* Starter value 1-3 -> Relic Gold
* Starter value 10 -> 3 * Relic Gold
*/
const MONEY_MINIMUM_MULTIPLIER = 10;
const MONEY_MAXIMUM_MULTIPLIER = 30;
/**
* An Offer You Can't Refuse encounter.
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3808 | GitHub Issue #3808}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const AnOfferYouCantRefuseEncounter: MysteryEncounter = MysteryEncounterBuilder.withEncounterType(
MysteryEncounterType.AN_OFFER_YOU_CANT_REFUSE,
)
.withEncounterTier(MysteryEncounterTier.GREAT)
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
.withScenePartySizeRequirement(2, 6, true) // Must have at least 2 pokemon in party
.withIntroSpriteConfigs([
{
spriteKey: SpeciesId.LIEPARD.toString(),
fileRoot: "pokemon",
hasShadow: true,
repeat: true,
x: 0,
y: -4,
yShadow: -4,
},
{
spriteKey: "rich_kid_m",
fileRoot: "trainer",
hasShadow: true,
x: 2,
y: 5,
yShadow: 5,
},
])
.withIntroDialogue([
{
text: `${namespace}:intro`,
},
{
text: `${namespace}:intro_dialogue`,
speaker: `${namespace}:speaker`,
},
])
.setLocalizationKey(`${namespace}`)
.withTitle(`${namespace}:title`)
.withDescription(`${namespace}:description`)
.withQuery(`${namespace}:query`)
.withOnInit(() => {
const encounter = globalScene.currentBattle.mysteryEncounter!;
const pokemon = getHighestStatTotalPlayerPokemon(true, true);
const baseSpecies = pokemon.getSpeciesForm().getRootSpeciesId();
const starterValue: number = speciesStarterCosts[baseSpecies] ?? 1;
const multiplier = Math.max((MONEY_MAXIMUM_MULTIPLIER / 10) * starterValue, MONEY_MINIMUM_MULTIPLIER);
const price = globalScene.getWaveMoneyAmount(multiplier);
encounter.setDialogueToken("strongestPokemon", pokemon.getNameToRender());
encounter.setDialogueToken("price", price.toString());
// Store pokemon and price
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()) {
const abilityToken = encounter.dialogueTokens["option2PrimaryAbility"];
const moveToken = encounter.dialogueTokens["option2PrimaryMove"];
if (abilityToken) {
encounter.setDialogueToken("moveOrAbility", abilityToken);
} else if (moveToken) {
encounter.setDialogueToken("moveOrAbility", moveToken);
}
}
const shinyCharm = generateModifierType(modifierTypes.SHINY_CHARM);
encounter.setDialogueToken("itemName", shinyCharm?.name ?? i18next.t("modifierType:ModifierType.SHINY_CHARM.name"));
encounter.setDialogueToken("liepardName", getPokemonSpecies(SpeciesId.LIEPARD).getName());
return true;
})
.withOption(
MysteryEncounterOptionBuilder.newOptionWithMode(MysteryEncounterOptionMode.DEFAULT)
.withDialogue({
buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [
{
text: `${namespace}:option.1.selected`,
speaker: `${namespace}:speaker`,
},
],
})
.withPreOptionPhase(async (): Promise<boolean> => {
const encounter = globalScene.currentBattle.mysteryEncounter!;
// Update money and remove pokemon from party
updatePlayerMoney(encounter.misc.price);
globalScene.removePokemonFromPlayerParty(encounter.misc.pokemon);
return true;
})
.withOptionPhase(async () => {
// Give the player a Shiny Charm
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.SHINY_CHARM));
leaveEncounterWithoutBattle(true);
})
.build(),
)
.withOption(
MysteryEncounterOptionBuilder.newOptionWithMode(MysteryEncounterOptionMode.DISABLED_OR_SPECIAL)
.withPrimaryPokemonRequirement(
CombinationPokemonRequirement.Some(
new MoveRequirement(EXTORTION_MOVES, true),
new AbilityRequirement(EXTORTION_ABILITIES, true),
),
)
.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`,
},
],
})
.withOptionPhase(async () => {
// Extort the rich kid for money
const encounter = globalScene.currentBattle.mysteryEncounter!;
// Update money and remove pokemon from party
updatePlayerMoney(encounter.misc.price);
setEncounterExp(encounter.options[1].primaryPokemon!.id, getPokemonSpecies(SpeciesId.LIEPARD).baseExp, true);
leaveEncounterWithoutBattle(true);
})
.build(),
)
.withSimpleOption(
{
buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}:option.3.tooltip`,
selected: [
{
speaker: `${namespace}:speaker`,
text: `${namespace}:option.3.selected`,
},
],
},
async () => {
// Leave encounter with no rewards or exp
leaveEncounterWithoutBattle(true);
return true;
},
)
.build();