pokerogue/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts
Moka a13550ec44
[Balance][ME] Various ME Balance changes (#4700)
* balance changes and updates to various MEs

* fix import to new item

* fix import to new item

* Update src/data/mystery-encounters/utils/encounter-pokemon-utils.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* Update src/phases/select-modifier-phase.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* Update src/modifier/modifier.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* Update src/modifier/modifier.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* revert item atlas changes

* eslint

* revert 'revert item atlas'

* update locale repo to latest commit

* Fix fiery fallout missing argument

* [balance] Training session ME does not update Seen/Defeated GameStats

* [balance] update Weird Dream ME maximum spawn wave

* [ME] update CombinationRequirements to allow AND or OR combinations

* refactor: CombinationPokemonRequirement `.Some()` and `Every()`

* chore: rename `orRequirements` to `requirements`

* fix: returns of `Some()` and `Any()`

* apply `Some()` / `Any()` pattern to `CombinationSceneRequirement` too

* revert 'offer you can't refuse' giving Silver Pokeball'

* Apply code review suggestions

* [me] Weird Dream: apply same old gateau logic to team in options 1 and 2

---------

Co-authored-by: ImperialSympathizer <imperialsympathizer@gmail.com>
Co-authored-by: ImperialSympathizer <110984302+ben-lear@users.noreply.github.com>
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>
Co-authored-by: innerthunder <brandonerickson98@gmail.com>
2024-10-23 21:46:57 +02:00

222 lines
8.4 KiB
TypeScript

import {
EnemyPartyConfig,
initBattleWithEnemyConfig,
setEncounterRewards,
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import {
trainerConfigs,
TrainerPartyCompoundTemplate,
TrainerPartyTemplate,
trainerPartyTemplates,
} from "#app/data/trainer-config";
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 "#app/battle-scene";
import * as Utils from "#app/utils";
import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
/** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/mysteriousChallengers";
/**
* Mysterious Challengers encounter.
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3801 | GitHub Issue #3801}
* @see For biome requirements check {@linkcode mysteryEncountersByBiome}
*/
export const MysteriousChallengersEncounter: MysteryEncounter =
MysteryEncounterBuilder.withEncounterType(MysteryEncounterType.MYSTERIOUS_CHALLENGERS)
.withEncounterTier(MysteryEncounterTier.GREAT)
.withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES)
.withIntroSpriteConfigs([]) // These are set in onInit()
.withIntroDialogue([
{
text: `${namespace}:intro`,
},
])
.withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!;
// Calculates what trainers are available for battle in the encounter
// Normal difficulty trainer is randomly pulled from biome
const normalTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex);
const normalConfig = trainerConfigs[normalTrainerType].clone();
let female = false;
if (normalConfig.hasGenders) {
female = !!Utils.randSeedInt(2);
}
const normalSpriteKey = normalConfig.getSpriteKey(female, normalConfig.doubleOnly);
encounter.enemyPartyConfigs.push({
trainerConfig: normalConfig,
female: female,
});
// 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
let retries = 0;
let hardTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex);
while (retries < 5 && hardTrainerType === normalTrainerType) {
// Will try to use a different trainer from the normal trainer type
hardTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex);
retries++;
}
const hardTemplate = new TrainerPartyCompoundTemplate(
new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER, false, true),
new TrainerPartyTemplate(
Math.min(Math.ceil(scene.currentBattle.waveIndex / 20), 5),
PartyMemberStrength.AVERAGE,
false,
true
)
);
const hardConfig = trainerConfigs[hardTrainerType].clone();
hardConfig.setPartyTemplates(hardTemplate);
female = false;
if (hardConfig.hasGenders) {
female = !!Utils.randSeedInt(2);
}
const hardSpriteKey = hardConfig.getSpriteKey(female, hardConfig.doubleOnly);
encounter.enemyPartyConfigs.push({
trainerConfig: hardConfig,
levelAdditiveModifier: 1,
female: female,
});
// Brutal trainer is pulled from pool of boss trainers (gym leaders) for the biome
// They are given an E4 template team, so will be stronger than usual boss encounter and always have 6 mons
const brutalTrainerType = scene.arena.randomTrainerType(
scene.currentBattle.waveIndex,
true
);
const e4Template = trainerPartyTemplates.ELITE_FOUR;
const brutalConfig = trainerConfigs[brutalTrainerType].clone();
brutalConfig.title = trainerConfigs[brutalTrainerType].title;
brutalConfig.setPartyTemplates(e4Template);
// @ts-ignore
brutalConfig.partyTemplateFunc = null; // Overrides gym leader party template func
female = false;
if (brutalConfig.hasGenders) {
female = !!Utils.randSeedInt(2);
}
const brutalSpriteKey = brutalConfig.getSpriteKey(female, brutalConfig.doubleOnly);
encounter.enemyPartyConfigs.push({
trainerConfig: brutalConfig,
levelAdditiveModifier: 1.5,
female: female,
});
encounter.spriteConfigs = [
{
spriteKey: normalSpriteKey,
fileRoot: "trainer",
hasShadow: true,
tint: 1,
},
{
spriteKey: hardSpriteKey,
fileRoot: "trainer",
hasShadow: true,
tint: 1,
},
{
spriteKey: brutalSpriteKey,
fileRoot: "trainer",
hasShadow: true,
tint: 1,
},
];
return true;
})
.setLocalizationKey(`${namespace}`)
.withTitle(`${namespace}:title`)
.withDescription(`${namespace}:description`)
.withQuery(`${namespace}:query`)
.withSimpleOption(
{
buttonLabel: `${namespace}:option.1.label`,
buttonTooltip: `${namespace}:option.1.tooltip`,
selected: [
{
text: `${namespace}:option.selected`,
},
],
},
async (scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!;
// Spawn standard trainer battle with memory mushroom reward
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [ modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM ], fillRemaining: true });
// Seed offsets to remove possibility of different trainers having exact same teams
let initBattlePromise: Promise<void>;
scene.executeWithSeedOffset(() => {
initBattlePromise = initBattleWithEnemyConfig(scene, config);
}, scene.currentBattle.waveIndex * 10);
await initBattlePromise!;
}
)
.withSimpleOption(
{
buttonLabel: `${namespace}:option.2.label`,
buttonTooltip: `${namespace}:option.2.tooltip`,
selected: [
{
text: `${namespace}:option.selected`,
},
],
},
async (scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!;
// Spawn hard fight
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1];
setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT ], fillRemaining: true });
// Seed offsets to remove possibility of different trainers having exact same teams
let initBattlePromise: Promise<void>;
scene.executeWithSeedOffset(() => {
initBattlePromise = initBattleWithEnemyConfig(scene, config);
}, scene.currentBattle.waveIndex * 100);
await initBattlePromise!;
}
)
.withSimpleOption(
{
buttonLabel: `${namespace}:option.3.label`,
buttonTooltip: `${namespace}:option.3.tooltip`,
selected: [
{
text: `${namespace}:option.selected`,
},
],
},
async (scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter!;
// Spawn brutal fight
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[2];
// To avoid player level snowballing from picking this option
encounter.expMultiplier = 0.9;
setEncounterRewards(scene, { guaranteedModifierTiers: [ ModifierTier.ROGUE, ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT ], fillRemaining: true });
// Seed offsets to remove possibility of different trainers having exact same teams
let initBattlePromise: Promise<void>;
scene.executeWithSeedOffset(() => {
initBattlePromise = initBattleWithEnemyConfig(scene, config);
}, scene.currentBattle.waveIndex * 1000);
await initBattlePromise!;
}
)
.withOutroDialogue([
{
text: `${namespace}:outro`,
},
])
.build();