pokerogue/src/phases/select-starter-phase.ts
Amani H. 94650670fd
[Challenge] Add Nuzlocke-related Challenges (#6186)
* [Challenge] Add Nuzlocke-related Challenges

Co-authored-by: Matilde Simões <matilde.simoes@tecnico.ulisboa.pt>
Co-authored-by: Fuad Ali <fuad.ali@tecnico.ulisboa.pt>
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
Co-authored-by: Sirzento <sirzento@gmx.de>

* Add Sacred Ash to `revive` Group

* Separate Challenge Utility Functions

* Misc. Changes

* Transition to `BooleanHolder`

* Add "Nuzlocke" Achievement

* Change Challenge Order

* Adjust Nuzlocke Achievement to Include Fresh Start

* Fix Infinite Reward Reroll Bug

* Fix Party Heal

* Minor Change

* Adjust TODOs

* Add Unit Tests

* Tweak Faint Cry in Permanent Faint

* Resolve rebase issue

* Apply Matthew's Suggestions

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>

* Apply Matthew's Suggestions Pt. 2

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>

* Fix and Lint Suggestions

* Revert Accidental Overrides

* Fix and Lint Suggestions Pt. 2

* Rename Challenges

* Prevent `RandomMoveAttr` from Using Banned Moves

* Update Locales

---------

Co-authored-by: Matilde Simões <matilde.simoes@tecnico.ulisboa.pt>
Co-authored-by: Fuad Ali <fuad.ali@tecnico.ulisboa.pt>
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
Co-authored-by: Sirzento <sirzento@gmx.de>
Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>
2025-08-07 18:47:28 -06:00

132 lines
5.2 KiB
TypeScript

import { globalScene } from "#app/global-scene";
import Overrides from "#app/overrides";
import { Phase } from "#app/phase";
import { SpeciesFormChangeMoveLearnedTrigger } from "#data/form-change-triggers";
import { Gender } from "#data/gender";
import { ChallengeType } from "#enums/challenge-type";
import type { SpeciesId } from "#enums/species-id";
import { UiMode } from "#enums/ui-mode";
import { overrideHeldItems, overrideModifiers } from "#modifiers/modifier";
import { SaveSlotUiMode } from "#ui/save-slot-select-ui-handler";
import type { Starter } from "#ui/starter-select-ui-handler";
import { applyChallenges } from "#utils/challenge-utils";
import { isNullOrUndefined } from "#utils/common";
import { getPokemonSpecies } from "#utils/pokemon-utils";
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
export class SelectStarterPhase extends Phase {
public readonly phaseName = "SelectStarterPhase";
start() {
super.start();
globalScene.playBgm("menu");
globalScene.ui.setMode(UiMode.STARTER_SELECT, (starters: Starter[]) => {
globalScene.ui.clearText();
globalScene.ui.setMode(UiMode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: number) => {
// If clicking cancel, back out to title screen
if (slotId === -1) {
globalScene.phaseManager.toTitleScreen();
this.end();
return;
}
globalScene.sessionSlotId = slotId;
this.initBattle(starters);
});
});
}
/**
* Initialize starters before starting the first battle
* @param starters - Array of {@linkcode Starter}s with which to start the battle
*/
initBattle(starters: Starter[]) {
const party = globalScene.getPlayerParty();
const loadPokemonAssets: Promise<void>[] = [];
starters.forEach((starter: Starter, i: number) => {
if (!i && Overrides.STARTER_SPECIES_OVERRIDE) {
starter.species = getPokemonSpecies(Overrides.STARTER_SPECIES_OVERRIDE as SpeciesId);
}
const starterProps = globalScene.gameData.getSpeciesDexAttrProps(starter.species, starter.dexAttr);
let starterFormIndex = Math.min(starterProps.formIndex, Math.max(starter.species.forms.length - 1, 0));
if (
starter.species.speciesId in Overrides.STARTER_FORM_OVERRIDES &&
!isNullOrUndefined(Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]) &&
starter.species.forms[Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!]
) {
starterFormIndex = Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!;
}
let starterGender =
starter.species.malePercent !== null ? (!starterProps.female ? Gender.MALE : Gender.FEMALE) : Gender.GENDERLESS;
if (Overrides.GENDER_OVERRIDE !== null) {
starterGender = Overrides.GENDER_OVERRIDE;
}
const starterIvs = globalScene.gameData.dexData[starter.species.speciesId].ivs.slice(0);
const starterPokemon = globalScene.addPlayerPokemon(
starter.species,
globalScene.gameMode.getStartingLevel(),
starter.abilityIndex,
starterFormIndex,
starterGender,
starterProps.shiny,
starterProps.variant,
starterIvs,
starter.nature,
);
starter.moveset && starterPokemon.tryPopulateMoveset(starter.moveset);
if (starter.passive) {
starterPokemon.passive = true;
}
starterPokemon.luck = globalScene.gameData.getDexAttrLuck(
globalScene.gameData.dexData[starter.species.speciesId].caughtAttr,
);
if (starter.pokerus) {
starterPokemon.pokerus = true;
}
if (starter.nickname) {
starterPokemon.nickname = starter.nickname;
}
if (!isNullOrUndefined(starter.teraType)) {
starterPokemon.teraType = starter.teraType;
} else {
starterPokemon.teraType = starterPokemon.species.type1;
}
if (globalScene.gameMode.isSplicedOnly || Overrides.STARTER_FUSION_OVERRIDE) {
starterPokemon.generateFusionSpecies(true);
}
starterPokemon.setVisible(false);
const chalApplied = applyChallenges(ChallengeType.STARTER_MODIFY, starterPokemon);
party.push(starterPokemon);
if (chalApplied) {
// If any challenges modified the starter, it should update
loadPokemonAssets.push(starterPokemon.updateInfo());
}
loadPokemonAssets.push(starterPokemon.loadAssets());
});
overrideModifiers();
overrideHeldItems(party[0]);
Promise.all(loadPokemonAssets).then(() => {
SoundFade.fadeOut(globalScene, globalScene.sound.get("menu"), 500, true);
globalScene.time.delayedCall(500, () => globalScene.playBgm());
if (globalScene.gameMode.isClassic) {
globalScene.gameData.gameStats.classicSessionsPlayed++;
} else {
globalScene.gameData.gameStats.endlessSessionsPlayed++;
}
globalScene.newBattle();
globalScene.arena.init();
globalScene.sessionPlayTime = 0;
globalScene.lastSavePlayTime = 0;
// Ensures Keldeo (or any future Pokemon that have this type of form change) starts in the correct form
globalScene.getPlayerParty().forEach(p => {
globalScene.triggerPokemonFormChange(p, SpeciesFormChangeMoveLearnedTrigger);
});
this.end();
});
}
}