mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-19 13:59:27 +02:00
Merge 967ad05b8e
into dd03887d05
This commit is contained in:
commit
81abc30fda
@ -3,9 +3,11 @@ import { getRandomTrainerFunc } from "#app/battle";
|
|||||||
import { defaultStarterSpecies } from "#app/constants";
|
import { defaultStarterSpecies } from "#app/constants";
|
||||||
import { speciesStarterCosts } from "#balance/starters";
|
import { speciesStarterCosts } from "#balance/starters";
|
||||||
import type { PokemonSpecies } from "#data/pokemon-species";
|
import type { PokemonSpecies } from "#data/pokemon-species";
|
||||||
|
import { AbilityAttr } from "#enums/ability-attr";
|
||||||
import { BattleType } from "#enums/battle-type";
|
import { BattleType } from "#enums/battle-type";
|
||||||
import { Challenges } from "#enums/challenges";
|
import { Challenges } from "#enums/challenges";
|
||||||
import { TypeColor, TypeShadow } from "#enums/color";
|
import { TypeColor, TypeShadow } from "#enums/color";
|
||||||
|
import { DexAttr } from "#enums/dex-attr";
|
||||||
import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
|
import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
|
||||||
import { ModifierTier } from "#enums/modifier-tier";
|
import { ModifierTier } from "#enums/modifier-tier";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
@ -19,8 +21,9 @@ import type { EnemyPokemon, PlayerPokemon, Pokemon } from "#field/pokemon";
|
|||||||
import { Trainer } from "#field/trainer";
|
import { Trainer } from "#field/trainer";
|
||||||
import type { ModifierTypeOption } from "#modifiers/modifier-type";
|
import type { ModifierTypeOption } from "#modifiers/modifier-type";
|
||||||
import { PokemonMove } from "#moves/pokemon-move";
|
import { PokemonMove } from "#moves/pokemon-move";
|
||||||
import type { DexAttrProps, GameData } from "#system/game-data";
|
import type { DexAttrProps, GameData, StarterDataEntry } from "#system/game-data";
|
||||||
import { RibbonData, type RibbonFlag } from "#system/ribbons/ribbon-data";
|
import { RibbonData, type RibbonFlag } from "#system/ribbons/ribbon-data";
|
||||||
|
import type { DexEntry } from "#types/dex-data";
|
||||||
import { type BooleanHolder, isBetween, type NumberHolder, randSeedItem } from "#utils/common";
|
import { type BooleanHolder, isBetween, type NumberHolder, randSeedItem } from "#utils/common";
|
||||||
import { deepCopy } from "#utils/data";
|
import { deepCopy } from "#utils/data";
|
||||||
import { getPokemonSpecies, getPokemonSpeciesForm } from "#utils/pokemon-utils";
|
import { getPokemonSpecies, getPokemonSpeciesForm } from "#utils/pokemon-utils";
|
||||||
@ -237,6 +240,15 @@ export abstract class Challenge {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An apply function for STARTER_SELECT_MODIFY challenges. Derived classes should alter this.
|
||||||
|
* @param _pokemon {@link Pokemon} The starter pokemon to modify.
|
||||||
|
* @returns {@link boolean} Whether this function did anything.
|
||||||
|
*/
|
||||||
|
applyStarterSelectModify(_speciesId: SpeciesId, _dexEntry: DexEntry, _starterDataEntry: StarterDataEntry): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An apply function for STARTER_MODIFY challenges. Derived classes should alter this.
|
* An apply function for STARTER_MODIFY challenges. Derived classes should alter this.
|
||||||
* @param _pokemon {@link Pokemon} The starter pokemon to modify.
|
* @param _pokemon {@link Pokemon} The starter pokemon to modify.
|
||||||
@ -797,10 +809,60 @@ export class FreshStartChallenge extends Challenge {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyStarterSelectModify(speciesId: SpeciesId, dexEntry: DexEntry, starterDataEntry: StarterDataEntry): boolean {
|
||||||
|
// Remove all egg moves
|
||||||
|
starterDataEntry.eggMoves = 0;
|
||||||
|
console.log("I AM APPLYING, ", starterDataEntry.eggMoves);
|
||||||
|
|
||||||
|
// Remove hidden and passive ability
|
||||||
|
const defaultAbilities = AbilityAttr.ABILITY_1 | AbilityAttr.ABILITY_2;
|
||||||
|
starterDataEntry.abilityAttr &= defaultAbilities;
|
||||||
|
starterDataEntry.passiveAttr = 0;
|
||||||
|
|
||||||
|
// Remove cost reduction
|
||||||
|
starterDataEntry.valueReduction = 0;
|
||||||
|
|
||||||
|
// Remove natures except for the default ones
|
||||||
|
const neutralNaturesAttr =
|
||||||
|
(1 << (Nature.HARDY + 1)) |
|
||||||
|
(1 << (Nature.DOCILE + 1)) |
|
||||||
|
(1 << (Nature.SERIOUS + 1)) |
|
||||||
|
(1 << (Nature.BASHFUL + 1)) |
|
||||||
|
(1 << (Nature.QUIRKY + 1));
|
||||||
|
dexEntry.natureAttr = neutralNaturesAttr;
|
||||||
|
|
||||||
|
// Set all ivs to 15
|
||||||
|
dexEntry.ivs = [15, 15, 15, 15, 15, 15];
|
||||||
|
|
||||||
|
// Removes shiny and variants
|
||||||
|
dexEntry.caughtAttr &= ~DexAttr.SHINY;
|
||||||
|
dexEntry.caughtAttr &= ~(DexAttr.VARIANT_2 | DexAttr.VARIANT_3);
|
||||||
|
|
||||||
|
// Remove unlocked forms for specific species
|
||||||
|
if (speciesId === SpeciesId.ZYGARDE) {
|
||||||
|
const formMask = (DexAttr.DEFAULT_FORM << 2n) - 1n; // Sets 10%-PC to 10%-AB and 50%-PC to 50%-AB
|
||||||
|
dexEntry.caughtAttr &= formMask;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
SpeciesId.PIKACHU,
|
||||||
|
SpeciesId.EEVEE,
|
||||||
|
SpeciesId.PICHU,
|
||||||
|
SpeciesId.ROTOM,
|
||||||
|
SpeciesId.MELOETTA,
|
||||||
|
SpeciesId.FROAKIE,
|
||||||
|
].includes(speciesId)
|
||||||
|
) {
|
||||||
|
const formMask = (DexAttr.DEFAULT_FORM << 1n) - 1n; // These mons are set to form 0 because they're meant to be unlocks or mid-run form changes
|
||||||
|
dexEntry.caughtAttr &= formMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
applyStarterModify(pokemon: Pokemon): boolean {
|
applyStarterModify(pokemon: Pokemon): boolean {
|
||||||
pokemon.abilityIndex = pokemon.abilityIndex % 2; // Always base ability, if you set it to hidden it wraps to first ability
|
pokemon.abilityIndex = pokemon.abilityIndex % 2; // Always base ability, if you set it to hidden it wraps to first ability
|
||||||
pokemon.passive = false; // Passive isn't unlocked
|
pokemon.passive = false; // Passive isn't unlocked
|
||||||
pokemon.nature = Nature.HARDY; // Neutral nature
|
|
||||||
let validMoves = pokemon.species
|
let validMoves = pokemon.species
|
||||||
.getLevelMoves()
|
.getLevelMoves()
|
||||||
.filter(m => isBetween(m[0], 1, 5))
|
.filter(m => isBetween(m[0], 1, 5))
|
||||||
@ -827,7 +889,6 @@ export class FreshStartChallenge extends Challenge {
|
|||||||
SpeciesId.ROTOM,
|
SpeciesId.ROTOM,
|
||||||
SpeciesId.MELOETTA,
|
SpeciesId.MELOETTA,
|
||||||
SpeciesId.FROAKIE,
|
SpeciesId.FROAKIE,
|
||||||
SpeciesId.ROCKRUFF,
|
|
||||||
].includes(pokemon.species.speciesId)
|
].includes(pokemon.species.speciesId)
|
||||||
) {
|
) {
|
||||||
pokemon.formIndex = 0; // These mons are set to form 0 because they're meant to be unlocks or mid-run form changes
|
pokemon.formIndex = 0; // These mons are set to form 0 because they're meant to be unlocks or mid-run form changes
|
||||||
|
@ -18,6 +18,11 @@ export enum ChallengeType {
|
|||||||
* @see {@link Challenge.applyStarterPointCost}
|
* @see {@link Challenge.applyStarterPointCost}
|
||||||
*/
|
*/
|
||||||
STARTER_COST,
|
STARTER_COST,
|
||||||
|
/**
|
||||||
|
* Challenges which modify the starter data in starter select
|
||||||
|
* @see {@link Challenge.applyStarterSelectModify}
|
||||||
|
*/
|
||||||
|
STARTER_SELECT_MODIFY,
|
||||||
/**
|
/**
|
||||||
* Challenges which modify your starters in some way
|
* Challenges which modify your starters in some way
|
||||||
* @see {@link Challenge.applyStarterModify}
|
* @see {@link Challenge.applyStarterModify}
|
||||||
|
@ -64,7 +64,7 @@ import { trainerConfigs } from "#trainers/trainer-config";
|
|||||||
import type { DexData, DexEntry } from "#types/dex-data";
|
import type { DexData, DexEntry } from "#types/dex-data";
|
||||||
import { RUN_HISTORY_LIMIT } from "#ui/run-history-ui-handler";
|
import { RUN_HISTORY_LIMIT } from "#ui/run-history-ui-handler";
|
||||||
import { applyChallenges } from "#utils/challenge-utils";
|
import { applyChallenges } from "#utils/challenge-utils";
|
||||||
import { executeIf, fixedInt, isLocal, NumberHolder, randInt, randSeedItem } from "#utils/common";
|
import { executeIf, fixedInt, isLocal, isNullOrUndefined, NumberHolder, randInt, randSeedItem } from "#utils/common";
|
||||||
import { decrypt, encrypt } from "#utils/data";
|
import { decrypt, encrypt } from "#utils/data";
|
||||||
import { getEnumKeys } from "#utils/enums";
|
import { getEnumKeys } from "#utils/enums";
|
||||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||||
@ -2103,13 +2103,17 @@ export class GameData {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getStarterSpeciesDefaultAbilityIndex(species: PokemonSpecies): number {
|
getStarterSpeciesDefaultAbilityIndex(species: PokemonSpecies, abilityAttr?: number): number {
|
||||||
const abilityAttr = this.starterData[species.speciesId].abilityAttr;
|
if (isNullOrUndefined(abilityAttr)) {
|
||||||
|
abilityAttr = this.starterData[species.speciesId].abilityAttr;
|
||||||
|
}
|
||||||
return abilityAttr & AbilityAttr.ABILITY_1 ? 0 : !species.ability2 || abilityAttr & AbilityAttr.ABILITY_2 ? 1 : 2;
|
return abilityAttr & AbilityAttr.ABILITY_1 ? 0 : !species.ability2 || abilityAttr & AbilityAttr.ABILITY_2 ? 1 : 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
getSpeciesDefaultNature(species: PokemonSpecies): Nature {
|
getSpeciesDefaultNature(species: PokemonSpecies, dexEntry?: DexEntry): Nature {
|
||||||
const dexEntry = this.dexData[species.speciesId];
|
if (isNullOrUndefined(dexEntry)) {
|
||||||
|
dexEntry = this.dexData[species.speciesId];
|
||||||
|
}
|
||||||
for (let n = 0; n < 25; n++) {
|
for (let n = 0; n < 25; n++) {
|
||||||
if (dexEntry.natureAttr & (1 << (n + 1))) {
|
if (dexEntry.natureAttr & (1 << (n + 1))) {
|
||||||
return n as Nature;
|
return n as Nature;
|
||||||
|
@ -27,6 +27,7 @@ import { AbilityAttr } from "#enums/ability-attr";
|
|||||||
import { AbilityId } from "#enums/ability-id";
|
import { AbilityId } from "#enums/ability-id";
|
||||||
import { Button } from "#enums/buttons";
|
import { Button } from "#enums/buttons";
|
||||||
import { ChallengeType } from "#enums/challenge-type";
|
import { ChallengeType } from "#enums/challenge-type";
|
||||||
|
import { Challenges } from "#enums/challenges";
|
||||||
import { Device } from "#enums/devices";
|
import { Device } from "#enums/devices";
|
||||||
import { DexAttr } from "#enums/dex-attr";
|
import { DexAttr } from "#enums/dex-attr";
|
||||||
import { DropDownColumn } from "#enums/drop-down-column";
|
import { DropDownColumn } from "#enums/drop-down-column";
|
||||||
@ -44,7 +45,7 @@ import { BattleSceneEventType } from "#events/battle-scene";
|
|||||||
import type { Variant } from "#sprites/variant";
|
import type { Variant } from "#sprites/variant";
|
||||||
import { getVariantIcon, getVariantTint } from "#sprites/variant";
|
import { getVariantIcon, getVariantTint } from "#sprites/variant";
|
||||||
import { achvs } from "#system/achv";
|
import { achvs } from "#system/achv";
|
||||||
import type { DexAttrProps, StarterAttributes, StarterMoveset } from "#system/game-data";
|
import type { DexAttrProps, StarterAttributes, StarterDataEntry, StarterMoveset } from "#system/game-data";
|
||||||
import { RibbonData } from "#system/ribbons/ribbon-data";
|
import { RibbonData } from "#system/ribbons/ribbon-data";
|
||||||
import { SettingKeyboard } from "#system/settings-keyboard";
|
import { SettingKeyboard } from "#system/settings-keyboard";
|
||||||
import type { DexEntry } from "#types/dex-data";
|
import type { DexEntry } from "#types/dex-data";
|
||||||
@ -400,8 +401,10 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
private starterSelectCallback: StarterSelectCallback | null;
|
private starterSelectCallback: StarterSelectCallback | null;
|
||||||
|
|
||||||
private starterPreferences: StarterPreferences;
|
private starterPreferences: StarterPreferences;
|
||||||
|
private originalStarterPreferences: StarterPreferences;
|
||||||
|
|
||||||
protected blockInput = false;
|
protected blockInput = false;
|
||||||
|
private allowTera: boolean;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(UiMode.STARTER_SELECT);
|
super(UiMode.STARTER_SELECT);
|
||||||
@ -1126,25 +1129,32 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
show(args: any[]): boolean {
|
show(args: any[]): boolean {
|
||||||
if (!this.starterPreferences) {
|
|
||||||
// starterPreferences haven't been loaded yet
|
|
||||||
this.starterPreferences = loadStarterPreferences();
|
|
||||||
}
|
|
||||||
this.moveInfoOverlay.clear(); // clear this when removing a menu; the cancel button doesn't seem to trigger this automatically on controllers
|
this.moveInfoOverlay.clear(); // clear this when removing a menu; the cancel button doesn't seem to trigger this automatically on controllers
|
||||||
this.pokerusSpecies = getPokerusStarters();
|
this.pokerusSpecies = getPokerusStarters();
|
||||||
|
|
||||||
|
this.allowTera = globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id);
|
||||||
|
|
||||||
if (args.length >= 1 && args[0] instanceof Function) {
|
if (args.length >= 1 && args[0] instanceof Function) {
|
||||||
super.show(args);
|
super.show(args);
|
||||||
this.starterSelectCallback = args[0] as StarterSelectCallback;
|
this.starterSelectCallback = args[0] as StarterSelectCallback;
|
||||||
|
|
||||||
this.starterSelectContainer.setVisible(true);
|
this.starterSelectContainer.setVisible(true);
|
||||||
|
|
||||||
|
this.starterPreferences = loadStarterPreferences();
|
||||||
|
this.originalStarterPreferences = loadStarterPreferences();
|
||||||
|
console.log("Loaded", this.originalStarterPreferences[1]);
|
||||||
|
|
||||||
this.allSpecies.forEach((species, s) => {
|
this.allSpecies.forEach((species, s) => {
|
||||||
const icon = this.starterContainers[s].icon;
|
const icon = this.starterContainers[s].icon;
|
||||||
const dexEntry = globalScene.gameData.dexData[species.speciesId];
|
const { dexEntry } = this.getSpeciesData(species.speciesId);
|
||||||
|
|
||||||
// Initialize the StarterAttributes for this species
|
// Initialize the StarterAttributes for this species
|
||||||
this.starterPreferences[species.speciesId] = this.initStarterPrefs(species);
|
this.starterPreferences[species.speciesId] = this.initStarterPrefs(species, this.starterPreferences);
|
||||||
|
this.originalStarterPreferences[species.speciesId] = this.initStarterPrefs(
|
||||||
|
species,
|
||||||
|
this.originalStarterPreferences,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
if (dexEntry.caughtAttr) {
|
if (dexEntry.caughtAttr) {
|
||||||
icon.clearTint();
|
icon.clearTint();
|
||||||
@ -1154,6 +1164,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
this.setUpgradeAnimation(icon, species);
|
this.setUpgradeAnimation(icon, species);
|
||||||
});
|
});
|
||||||
|
console.log("Initiated", this.originalStarterPreferences[1]);
|
||||||
|
|
||||||
this.resetFilters();
|
this.resetFilters();
|
||||||
this.updateStarters();
|
this.updateStarters();
|
||||||
@ -1179,10 +1190,14 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
* @param species The species to get Starter Preferences for
|
* @param species The species to get Starter Preferences for
|
||||||
* @returns StarterAttributes for the species
|
* @returns StarterAttributes for the species
|
||||||
*/
|
*/
|
||||||
initStarterPrefs(species: PokemonSpecies): StarterAttributes {
|
initStarterPrefs(
|
||||||
const starterAttributes = this.starterPreferences[species.speciesId];
|
species: PokemonSpecies,
|
||||||
const dexEntry = globalScene.gameData.dexData[species.speciesId];
|
preferences: StarterPreferences,
|
||||||
const starterData = globalScene.gameData.starterData[species.speciesId];
|
ignoreChallenge = false,
|
||||||
|
): StarterAttributes {
|
||||||
|
const starterAttributes = preferences[species.speciesId];
|
||||||
|
const { dexEntry, starterDataEntry } = this.getSpeciesData(species.speciesId, !ignoreChallenge);
|
||||||
|
const starterData = starterDataEntry;
|
||||||
|
|
||||||
// no preferences or Pokemon wasn't caught, return empty attribute
|
// no preferences or Pokemon wasn't caught, return empty attribute
|
||||||
if (!starterAttributes || !dexEntry.caughtAttr) {
|
if (!starterAttributes || !dexEntry.caughtAttr) {
|
||||||
@ -1262,6 +1277,17 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (starterAttributes.tera !== undefined) {
|
||||||
|
// If somehow we have an illegal tera type, it is reset here
|
||||||
|
if (!(starterAttributes.tera === species.type1 || starterAttributes.tera === species?.type2)) {
|
||||||
|
starterAttributes.tera = species.type1;
|
||||||
|
}
|
||||||
|
// In fresh start challenge, the tera type is always reset to the first one
|
||||||
|
if (globalScene.gameMode.hasChallenge(Challenges.FRESH_START) && !ignoreChallenge) {
|
||||||
|
starterAttributes.tera = species.type1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return starterAttributes;
|
return starterAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1714,7 +1740,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)),
|
globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)),
|
||||||
this.isPartyValid(),
|
this.isPartyValid(),
|
||||||
);
|
);
|
||||||
const isCaught = globalScene.gameData.dexData[species.speciesId].caughtAttr;
|
const { dexEntry } = this.getSpeciesData(species.speciesId);
|
||||||
|
const isCaught = dexEntry.caughtAttr;
|
||||||
return (
|
return (
|
||||||
!isDupe && isValidForChallenge && currentPartyValue + starterCost <= this.getValueLimit() && isCaught
|
!isDupe && isValidForChallenge && currentPartyValue + starterCost <= this.getValueLimit() && isCaught
|
||||||
);
|
);
|
||||||
@ -1781,9 +1808,11 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let starterContainer: StarterContainer;
|
let starterContainer: StarterContainer;
|
||||||
const starterData = globalScene.gameData.starterData[this.lastSpecies.speciesId];
|
const { starterDataEntry } = this.getSpeciesData(this.lastSpecies.speciesId);
|
||||||
|
const starterData = starterDataEntry;
|
||||||
// prepare persistent starter data to store changes
|
// prepare persistent starter data to store changes
|
||||||
let starterAttributes = this.starterPreferences[this.lastSpecies.speciesId];
|
let starterAttributes = this.starterPreferences[this.lastSpecies.speciesId];
|
||||||
|
const originalStarterAttributes = this.originalStarterPreferences[this.lastSpecies.speciesId];
|
||||||
|
|
||||||
// this gets the correct pokemon cursor depending on whether you're in the starter screen or the party icons
|
// this gets the correct pokemon cursor depending on whether you're in the starter screen or the party icons
|
||||||
if (!this.starterIconsCursorObj.visible) {
|
if (!this.starterIconsCursorObj.visible) {
|
||||||
@ -1999,6 +2028,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
starterAttributes = this.starterPreferences[this.lastSpecies.speciesId] = {};
|
starterAttributes = this.starterPreferences[this.lastSpecies.speciesId] = {};
|
||||||
}
|
}
|
||||||
starterAttributes.nature = n;
|
starterAttributes.nature = n;
|
||||||
|
originalStarterAttributes.nature = starterAttributes.nature;
|
||||||
this.clearText();
|
this.clearText();
|
||||||
ui.setMode(UiMode.STARTER_SELECT);
|
ui.setMode(UiMode.STARTER_SELECT);
|
||||||
// set nature for starter
|
// set nature for starter
|
||||||
@ -2067,6 +2097,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
label: i18next.t("starterSelectUiHandler:addToFavorites"),
|
label: i18next.t("starterSelectUiHandler:addToFavorites"),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
starterAttributes.favorite = true;
|
starterAttributes.favorite = true;
|
||||||
|
originalStarterAttributes.favorite = true;
|
||||||
// if the starter container not exists, it means the species is not in the filtered starters
|
// if the starter container not exists, it means the species is not in the filtered starters
|
||||||
if (starterContainer) {
|
if (starterContainer) {
|
||||||
starterContainer.favoriteIcon.setVisible(starterAttributes.favorite);
|
starterContainer.favoriteIcon.setVisible(starterAttributes.favorite);
|
||||||
@ -2080,6 +2111,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
label: i18next.t("starterSelectUiHandler:removeFromFavorites"),
|
label: i18next.t("starterSelectUiHandler:removeFromFavorites"),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
starterAttributes.favorite = false;
|
starterAttributes.favorite = false;
|
||||||
|
originalStarterAttributes.favorite = false;
|
||||||
// if the starter container not exists, it means the species is not in the filtered starters
|
// if the starter container not exists, it means the species is not in the filtered starters
|
||||||
if (starterContainer) {
|
if (starterContainer) {
|
||||||
starterContainer.favoriteIcon.setVisible(starterAttributes.favorite);
|
starterContainer.favoriteIcon.setVisible(starterAttributes.favorite);
|
||||||
@ -2102,6 +2134,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
(sanitizedName: string) => {
|
(sanitizedName: string) => {
|
||||||
ui.playSelect();
|
ui.playSelect();
|
||||||
starterAttributes.nickname = sanitizedName;
|
starterAttributes.nickname = sanitizedName;
|
||||||
|
originalStarterAttributes.nickname = sanitizedName;
|
||||||
const name = decodeURIComponent(escape(atob(starterAttributes.nickname)));
|
const name = decodeURIComponent(escape(atob(starterAttributes.nickname)));
|
||||||
if (name.length > 0) {
|
if (name.length > 0) {
|
||||||
this.pokemonNameText.setText(name);
|
this.pokemonNameText.setText(name);
|
||||||
@ -2328,6 +2361,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonShinyIcon.setFrame(getVariantIcon(newVariant)).setTint(tint).setVisible(true);
|
this.pokemonShinyIcon.setFrame(getVariantIcon(newVariant)).setTint(tint).setVisible(true);
|
||||||
|
|
||||||
starterAttributes.shiny = true;
|
starterAttributes.shiny = true;
|
||||||
|
originalStarterAttributes.shiny = true;
|
||||||
} else {
|
} else {
|
||||||
// If shiny, we update the variant
|
// If shiny, we update the variant
|
||||||
let newVariant = props.variant;
|
let newVariant = props.variant;
|
||||||
@ -2351,6 +2385,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
} while (newVariant !== props.variant);
|
} while (newVariant !== props.variant);
|
||||||
starterAttributes.variant = newVariant; // store the selected variant
|
starterAttributes.variant = newVariant; // store the selected variant
|
||||||
|
originalStarterAttributes.variant = newVariant;
|
||||||
if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.NON_SHINY && newVariant <= props.variant) {
|
if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.NON_SHINY && newVariant <= props.variant) {
|
||||||
// If we have run out of variants, go back to non shiny
|
// If we have run out of variants, go back to non shiny
|
||||||
this.setSpeciesDetails(this.lastSpecies, {
|
this.setSpeciesDetails(this.lastSpecies, {
|
||||||
@ -2360,6 +2395,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonShinyIcon.setVisible(false);
|
this.pokemonShinyIcon.setVisible(false);
|
||||||
success = true;
|
success = true;
|
||||||
starterAttributes.shiny = false;
|
starterAttributes.shiny = false;
|
||||||
|
originalStarterAttributes.shiny = false;
|
||||||
} else {
|
} else {
|
||||||
// If going to a higher variant, or only shiny forms are caught, go to next variant
|
// If going to a higher variant, or only shiny forms are caught, go to next variant
|
||||||
this.setSpeciesDetails(this.lastSpecies, {
|
this.setSpeciesDetails(this.lastSpecies, {
|
||||||
@ -2388,7 +2424,9 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
} while (newFormIndex !== props.formIndex);
|
} while (newFormIndex !== props.formIndex);
|
||||||
starterAttributes.form = newFormIndex; // store the selected form
|
starterAttributes.form = newFormIndex; // store the selected form
|
||||||
|
originalStarterAttributes.form = newFormIndex;
|
||||||
starterAttributes.tera = this.lastSpecies.forms[newFormIndex].type1;
|
starterAttributes.tera = this.lastSpecies.forms[newFormIndex].type1;
|
||||||
|
originalStarterAttributes.tera = starterAttributes.tera;
|
||||||
this.setSpeciesDetails(this.lastSpecies, {
|
this.setSpeciesDetails(this.lastSpecies, {
|
||||||
formIndex: newFormIndex,
|
formIndex: newFormIndex,
|
||||||
teraType: starterAttributes.tera,
|
teraType: starterAttributes.tera,
|
||||||
@ -2399,6 +2437,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
case Button.CYCLE_GENDER:
|
case Button.CYCLE_GENDER:
|
||||||
if (this.canCycleGender) {
|
if (this.canCycleGender) {
|
||||||
starterAttributes.female = !props.female;
|
starterAttributes.female = !props.female;
|
||||||
|
originalStarterAttributes.female = starterAttributes.female;
|
||||||
this.setSpeciesDetails(this.lastSpecies, {
|
this.setSpeciesDetails(this.lastSpecies, {
|
||||||
female: !props.female,
|
female: !props.female,
|
||||||
});
|
});
|
||||||
@ -2408,7 +2447,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
case Button.CYCLE_ABILITY:
|
case Button.CYCLE_ABILITY:
|
||||||
if (this.canCycleAbility) {
|
if (this.canCycleAbility) {
|
||||||
const abilityCount = this.lastSpecies.getAbilityCount();
|
const abilityCount = this.lastSpecies.getAbilityCount();
|
||||||
const abilityAttr = globalScene.gameData.starterData[this.lastSpecies.speciesId].abilityAttr;
|
const abilityAttr = starterDataEntry.abilityAttr;
|
||||||
const hasAbility1 = abilityAttr & AbilityAttr.ABILITY_1;
|
const hasAbility1 = abilityAttr & AbilityAttr.ABILITY_1;
|
||||||
let newAbilityIndex = this.abilityCursor;
|
let newAbilityIndex = this.abilityCursor;
|
||||||
do {
|
do {
|
||||||
@ -2430,6 +2469,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
} while (newAbilityIndex !== this.abilityCursor);
|
} while (newAbilityIndex !== this.abilityCursor);
|
||||||
starterAttributes.ability = newAbilityIndex; // store the selected ability
|
starterAttributes.ability = newAbilityIndex; // store the selected ability
|
||||||
|
originalStarterAttributes.ability = newAbilityIndex;
|
||||||
|
|
||||||
const { visible: tooltipVisible } = globalScene.ui.getTooltip();
|
const { visible: tooltipVisible } = globalScene.ui.getTooltip();
|
||||||
|
|
||||||
@ -2451,6 +2491,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
const newNature = natures[natureIndex < natures.length - 1 ? natureIndex + 1 : 0];
|
const newNature = natures[natureIndex < natures.length - 1 ? natureIndex + 1 : 0];
|
||||||
// store cycled nature as default
|
// store cycled nature as default
|
||||||
starterAttributes.nature = newNature as unknown as number;
|
starterAttributes.nature = newNature as unknown as number;
|
||||||
|
originalStarterAttributes.nature = starterAttributes.nature;
|
||||||
this.setSpeciesDetails(this.lastSpecies, {
|
this.setSpeciesDetails(this.lastSpecies, {
|
||||||
natureIndex: newNature,
|
natureIndex: newNature,
|
||||||
});
|
});
|
||||||
@ -2461,12 +2502,14 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
if (this.canCycleTera) {
|
if (this.canCycleTera) {
|
||||||
const speciesForm = getPokemonSpeciesForm(this.lastSpecies.speciesId, starterAttributes.form ?? 0);
|
const speciesForm = getPokemonSpeciesForm(this.lastSpecies.speciesId, starterAttributes.form ?? 0);
|
||||||
if (speciesForm.type1 === this.teraCursor && !isNullOrUndefined(speciesForm.type2)) {
|
if (speciesForm.type1 === this.teraCursor && !isNullOrUndefined(speciesForm.type2)) {
|
||||||
starterAttributes.tera = speciesForm.type2!;
|
starterAttributes.tera = speciesForm.type2;
|
||||||
|
originalStarterAttributes.tera = starterAttributes.tera;
|
||||||
this.setSpeciesDetails(this.lastSpecies, {
|
this.setSpeciesDetails(this.lastSpecies, {
|
||||||
teraType: speciesForm.type2!,
|
teraType: speciesForm.type2,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
starterAttributes.tera = speciesForm.type1;
|
starterAttributes.tera = speciesForm.type1;
|
||||||
|
originalStarterAttributes.tera = starterAttributes.tera;
|
||||||
this.setSpeciesDetails(this.lastSpecies, {
|
this.setSpeciesDetails(this.lastSpecies, {
|
||||||
teraType: speciesForm.type1,
|
teraType: speciesForm.type1,
|
||||||
});
|
});
|
||||||
@ -2713,16 +2756,16 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
const updatedMoveset = starterMoveset.slice() as StarterMoveset;
|
const updatedMoveset = starterMoveset.slice() as StarterMoveset;
|
||||||
const formIndex = globalScene.gameData.getSpeciesDexAttrProps(this.lastSpecies, this.dexAttrCursor).formIndex;
|
const formIndex = globalScene.gameData.getSpeciesDexAttrProps(this.lastSpecies, this.dexAttrCursor).formIndex;
|
||||||
const starterData = globalScene.gameData.starterData[speciesId];
|
const starterDataEntry = globalScene.gameData.starterData[speciesId];
|
||||||
// species has different forms
|
// species has different forms
|
||||||
if (pokemonFormLevelMoves.hasOwnProperty(speciesId)) {
|
if (pokemonFormLevelMoves.hasOwnProperty(speciesId)) {
|
||||||
// Species has forms with different movesets
|
// Species has forms with different movesets
|
||||||
if (!starterData.moveset || Array.isArray(starterData.moveset)) {
|
if (!starterDataEntry.moveset || Array.isArray(starterDataEntry.moveset)) {
|
||||||
starterData.moveset = {};
|
starterDataEntry.moveset = {};
|
||||||
}
|
}
|
||||||
starterData.moveset[formIndex] = updatedMoveset;
|
starterDataEntry.moveset[formIndex] = updatedMoveset;
|
||||||
} else {
|
} else {
|
||||||
starterData.moveset = updatedMoveset;
|
starterDataEntry.moveset = updatedMoveset;
|
||||||
}
|
}
|
||||||
this.setSpeciesDetails(this.lastSpecies, { forSeen: false });
|
this.setSpeciesDetails(this.lastSpecies, { forSeen: false });
|
||||||
|
|
||||||
@ -2994,8 +3037,9 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
container.cost = globalScene.gameData.getSpeciesStarterValue(container.species.speciesId);
|
container.cost = globalScene.gameData.getSpeciesStarterValue(container.species.speciesId);
|
||||||
|
|
||||||
// First, ensure you have the caught attributes for the species else default to bigint 0
|
// First, ensure you have the caught attributes for the species else default to bigint 0
|
||||||
const caughtAttr = globalScene.gameData.dexData[container.species.speciesId]?.caughtAttr || BigInt(0);
|
const { dexEntry, starterDataEntry } = this.getSpeciesData(container.species.speciesId);
|
||||||
const starterData = globalScene.gameData.starterData[container.species.speciesId];
|
const caughtAttr = dexEntry?.caughtAttr || BigInt(0);
|
||||||
|
const starterData = starterDataEntry;
|
||||||
const isStarterProgressable = speciesEggMoves.hasOwnProperty(container.species.speciesId);
|
const isStarterProgressable = speciesEggMoves.hasOwnProperty(container.species.speciesId);
|
||||||
|
|
||||||
// Gen filter
|
// Gen filter
|
||||||
@ -3227,12 +3271,12 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
onScreenFirstIndex + maxRows * maxColumns - 1,
|
onScreenFirstIndex + maxRows * maxColumns - 1,
|
||||||
);
|
);
|
||||||
|
|
||||||
const gameData = globalScene.gameData;
|
|
||||||
|
|
||||||
this.starterSelectScrollBar.setScrollCursor(this.scrollCursor);
|
this.starterSelectScrollBar.setScrollCursor(this.scrollCursor);
|
||||||
|
|
||||||
let pokerusCursorIndex = 0;
|
let pokerusCursorIndex = 0;
|
||||||
this.filteredStarterContainers.forEach((container, i) => {
|
this.filteredStarterContainers.forEach((container, i) => {
|
||||||
|
const { dexEntry, starterDataEntry } = this.getSpeciesData(container.species.speciesId);
|
||||||
|
|
||||||
const pos = calcStarterPosition(i, this.scrollCursor);
|
const pos = calcStarterPosition(i, this.scrollCursor);
|
||||||
container.setPosition(pos.x, pos.y);
|
container.setPosition(pos.x, pos.y);
|
||||||
if (i < onScreenFirstIndex || i > onScreenLastIndex) {
|
if (i < onScreenFirstIndex || i > onScreenLastIndex) {
|
||||||
@ -3268,10 +3312,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
container.label.setVisible(true);
|
container.label.setVisible(true);
|
||||||
const speciesVariants =
|
const speciesVariants =
|
||||||
speciesId && gameData.dexData[speciesId].caughtAttr & DexAttr.SHINY
|
speciesId && dexEntry.caughtAttr & DexAttr.SHINY
|
||||||
? [DexAttr.DEFAULT_VARIANT, DexAttr.VARIANT_2, DexAttr.VARIANT_3].filter(
|
? [DexAttr.DEFAULT_VARIANT, DexAttr.VARIANT_2, DexAttr.VARIANT_3].filter(v => !!(dexEntry.caughtAttr & v))
|
||||||
v => !!(gameData.dexData[speciesId].caughtAttr & v),
|
|
||||||
)
|
|
||||||
: [];
|
: [];
|
||||||
for (let v = 0; v < 3; v++) {
|
for (let v = 0; v < 3; v++) {
|
||||||
const hasVariant = speciesVariants.length > v;
|
const hasVariant = speciesVariants.length > v;
|
||||||
@ -3285,15 +3327,11 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
container.starterPassiveBgs.setVisible(!!gameData.starterData[speciesId].passiveAttr);
|
container.starterPassiveBgs.setVisible(!!starterDataEntry.passiveAttr);
|
||||||
container.hiddenAbilityIcon.setVisible(
|
container.hiddenAbilityIcon.setVisible(!!dexEntry.caughtAttr && !!(starterDataEntry.abilityAttr & 4));
|
||||||
!!gameData.dexData[speciesId].caughtAttr && !!(gameData.starterData[speciesId].abilityAttr & 4),
|
|
||||||
);
|
|
||||||
container.classicWinIcon
|
container.classicWinIcon
|
||||||
.setVisible(gameData.starterData[speciesId].classicWinCount > 0)
|
.setVisible(starterDataEntry.classicWinCount > 0)
|
||||||
.setTexture(
|
.setTexture(dexEntry.ribbons.has(RibbonData.NUZLOCKE) ? "champion_ribbon_emerald" : "champion_ribbon");
|
||||||
gameData.dexData[speciesId].ribbons.has(RibbonData.NUZLOCKE) ? "champion_ribbon_emerald" : "champion_ribbon",
|
|
||||||
);
|
|
||||||
container.favoriteIcon.setVisible(this.starterPreferences[speciesId]?.favorite ?? false);
|
container.favoriteIcon.setVisible(this.starterPreferences[speciesId]?.favorite ?? false);
|
||||||
|
|
||||||
// 'Candy Icon' mode
|
// 'Candy Icon' mode
|
||||||
@ -3393,11 +3431,20 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSpecies(species: PokemonSpecies | null) {
|
setSpecies(species: PokemonSpecies | null) {
|
||||||
this.speciesStarterDexEntry = species ? globalScene.gameData.dexData[species.speciesId] : null;
|
this.speciesStarterDexEntry = null;
|
||||||
this.dexAttrCursor = species ? this.getCurrentDexProps(species.speciesId) : 0n;
|
this.dexAttrCursor = 0n;
|
||||||
this.abilityCursor = species ? globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species) : 0;
|
this.abilityCursor = 0;
|
||||||
this.natureCursor = species ? globalScene.gameData.getSpeciesDefaultNature(species) : 0;
|
this.natureCursor = 0;
|
||||||
this.teraCursor = species ? species.type1 : PokemonType.UNKNOWN;
|
this.teraCursor = PokemonType.UNKNOWN;
|
||||||
|
|
||||||
|
if (species) {
|
||||||
|
const { dexEntry } = this.getSpeciesData(species.speciesId);
|
||||||
|
this.speciesStarterDexEntry = dexEntry;
|
||||||
|
this.dexAttrCursor = this.getCurrentDexProps(species.speciesId);
|
||||||
|
this.abilityCursor = globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
||||||
|
this.natureCursor = globalScene.gameData.getSpeciesDefaultNature(species, dexEntry);
|
||||||
|
this.teraCursor = species.type1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!species && globalScene.ui.getTooltip().visible) {
|
if (!species && globalScene.ui.getTooltip().visible) {
|
||||||
globalScene.ui.hideTooltip();
|
globalScene.ui.hideTooltip();
|
||||||
@ -3562,11 +3609,12 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
teraType: this.starterTeras[starterIndex],
|
teraType: this.starterTeras[starterIndex],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const defaultDexAttr = this.getCurrentDexProps(species.speciesId);
|
|
||||||
const defaultAbilityIndex =
|
const defaultAbilityIndex =
|
||||||
starterAttributes?.ability ?? globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
starterAttributes?.ability ?? globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
||||||
// load default nature from stater save data, if set
|
// load default nature from stater save data, if set
|
||||||
const defaultNature = starterAttributes?.nature || globalScene.gameData.getSpeciesDefaultNature(species);
|
const { dexEntry } = this.getSpeciesData(species.speciesId);
|
||||||
|
const defaultNature =
|
||||||
|
starterAttributes?.nature || globalScene.gameData.getSpeciesDefaultNature(species, dexEntry);
|
||||||
props = globalScene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
|
props = globalScene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
|
||||||
if (starterAttributes?.variant && !Number.isNaN(starterAttributes.variant)) {
|
if (starterAttributes?.variant && !Number.isNaN(starterAttributes.variant)) {
|
||||||
if (props.shiny) {
|
if (props.shiny) {
|
||||||
@ -3583,6 +3631,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
variant: props.variant,
|
variant: props.variant,
|
||||||
abilityIndex: defaultAbilityIndex,
|
abilityIndex: defaultAbilityIndex,
|
||||||
natureIndex: defaultNature,
|
natureIndex: defaultNature,
|
||||||
|
teraType: starterAttributes?.tera,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3663,14 +3712,34 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSpeciesData(
|
||||||
|
speciesId: SpeciesId,
|
||||||
|
applyChallenge = true,
|
||||||
|
): { dexEntry: DexEntry; starterDataEntry: StarterDataEntry } {
|
||||||
|
const dexEntry = globalScene.gameData.dexData[speciesId];
|
||||||
|
const starterDataEntry = globalScene.gameData.starterData[speciesId];
|
||||||
|
|
||||||
|
const copiedDexEntry = { ...dexEntry };
|
||||||
|
const copiedStarterDataEntry = { ...starterDataEntry };
|
||||||
|
if (applyChallenge) {
|
||||||
|
applyChallenges(ChallengeType.STARTER_SELECT_MODIFY, speciesId, copiedDexEntry, copiedStarterDataEntry);
|
||||||
|
}
|
||||||
|
return { dexEntry: { ...copiedDexEntry }, starterDataEntry: { ...copiedStarterDataEntry } };
|
||||||
|
}
|
||||||
|
|
||||||
setSpeciesDetails(species: PokemonSpecies, options: SpeciesDetails = {}): void {
|
setSpeciesDetails(species: PokemonSpecies, options: SpeciesDetails = {}): void {
|
||||||
let { shiny, formIndex, female, variant, abilityIndex, natureIndex, teraType } = options;
|
let { shiny, formIndex, female, variant, abilityIndex, natureIndex, teraType } = options;
|
||||||
const forSeen: boolean = options.forSeen ?? false;
|
const forSeen: boolean = options.forSeen ?? false;
|
||||||
const oldProps = species ? globalScene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor) : null;
|
const oldProps = species ? globalScene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor) : null;
|
||||||
const oldAbilityIndex =
|
const oldAbilityIndex =
|
||||||
this.abilityCursor > -1 ? this.abilityCursor : globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
this.abilityCursor > -1 ? this.abilityCursor : globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
||||||
const oldNatureIndex =
|
let oldNatureIndex = -1;
|
||||||
this.natureCursor > -1 ? this.natureCursor : globalScene.gameData.getSpeciesDefaultNature(species);
|
if (species) {
|
||||||
|
const { dexEntry } = this.getSpeciesData(species.speciesId);
|
||||||
|
oldNatureIndex =
|
||||||
|
this.natureCursor > -1 ? this.natureCursor : globalScene.gameData.getSpeciesDefaultNature(species, dexEntry);
|
||||||
|
}
|
||||||
|
const oldTeraType = this.teraCursor > -1 ? this.teraCursor : species ? species.type1 : PokemonType.UNKNOWN;
|
||||||
this.dexAttrCursor = 0n;
|
this.dexAttrCursor = 0n;
|
||||||
this.abilityCursor = -1;
|
this.abilityCursor = -1;
|
||||||
this.natureCursor = -1;
|
this.natureCursor = -1;
|
||||||
@ -3717,7 +3786,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
); // TODO: is this bang correct?
|
); // TODO: is this bang correct?
|
||||||
this.abilityCursor = abilityIndex !== undefined ? abilityIndex : (abilityIndex = oldAbilityIndex);
|
this.abilityCursor = abilityIndex !== undefined ? abilityIndex : (abilityIndex = oldAbilityIndex);
|
||||||
this.natureCursor = natureIndex !== undefined ? natureIndex : (natureIndex = oldNatureIndex);
|
this.natureCursor = natureIndex !== undefined ? natureIndex : (natureIndex = oldNatureIndex);
|
||||||
this.teraCursor = !isNullOrUndefined(teraType) ? teraType : (teraType = species.type1);
|
this.teraCursor = !isNullOrUndefined(teraType) ? teraType : (teraType = oldTeraType);
|
||||||
const [isInParty, partyIndex]: [boolean, number] = this.isInParty(species); // we use this to firstly check if the pokemon is in the party, and if so, to get the party index in order to update the icon image
|
const [isInParty, partyIndex]: [boolean, number] = this.isInParty(species); // we use this to firstly check if the pokemon is in the party, and if so, to get the party index in order to update the icon image
|
||||||
if (isInParty) {
|
if (isInParty) {
|
||||||
this.updatePartyIcon(species, partyIndex);
|
this.updatePartyIcon(species, partyIndex);
|
||||||
@ -3740,15 +3809,14 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.speciesStarterMoves = [];
|
this.speciesStarterMoves = [];
|
||||||
|
|
||||||
if (species) {
|
if (species) {
|
||||||
const dexEntry = globalScene.gameData.dexData[species.speciesId];
|
const { dexEntry, starterDataEntry } = this.getSpeciesData(species.speciesId);
|
||||||
const abilityAttr = globalScene.gameData.starterData[species.speciesId].abilityAttr;
|
const caughtAttr = dexEntry.caughtAttr || BigInt(0);
|
||||||
|
const abilityAttr = starterDataEntry.abilityAttr;
|
||||||
|
|
||||||
const caughtAttr = globalScene.gameData.dexData[species.speciesId]?.caughtAttr || BigInt(0);
|
if (!caughtAttr) {
|
||||||
|
|
||||||
if (!dexEntry.caughtAttr) {
|
|
||||||
const props = globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId));
|
const props = globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId));
|
||||||
const defaultAbilityIndex = globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
const defaultAbilityIndex = globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
||||||
const defaultNature = globalScene.gameData.getSpeciesDefaultNature(species);
|
const defaultNature = globalScene.gameData.getSpeciesDefaultNature(species, dexEntry);
|
||||||
|
|
||||||
if (shiny === undefined || shiny !== props.shiny) {
|
if (shiny === undefined || shiny !== props.shiny) {
|
||||||
shiny = props.shiny;
|
shiny = props.shiny;
|
||||||
@ -3858,8 +3926,9 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.canCycleNature = globalScene.gameData.getNaturesForAttr(dexEntry.natureAttr).length > 1;
|
this.canCycleNature = globalScene.gameData.getNaturesForAttr(dexEntry.natureAttr).length > 1;
|
||||||
this.canCycleTera =
|
this.canCycleTera =
|
||||||
!this.statsMode &&
|
!this.statsMode &&
|
||||||
globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) &&
|
this.allowTera &&
|
||||||
!isNullOrUndefined(getPokemonSpeciesForm(species.speciesId, formIndex ?? 0).type2);
|
!isNullOrUndefined(getPokemonSpeciesForm(species.speciesId, formIndex ?? 0).type2) &&
|
||||||
|
!globalScene.gameMode.hasChallenge(Challenges.FRESH_START);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dexEntry.caughtAttr && species.malePercent !== null) {
|
if (dexEntry.caughtAttr && species.malePercent !== null) {
|
||||||
@ -3886,7 +3955,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
.setColor(this.getTextColor(!isHidden ? TextStyle.SUMMARY_ALT : TextStyle.SUMMARY_GOLD))
|
.setColor(this.getTextColor(!isHidden ? TextStyle.SUMMARY_ALT : TextStyle.SUMMARY_GOLD))
|
||||||
.setShadowColor(this.getTextColor(!isHidden ? TextStyle.SUMMARY_ALT : TextStyle.SUMMARY_GOLD, true));
|
.setShadowColor(this.getTextColor(!isHidden ? TextStyle.SUMMARY_ALT : TextStyle.SUMMARY_GOLD, true));
|
||||||
|
|
||||||
const passiveAttr = globalScene.gameData.starterData[species.speciesId].passiveAttr;
|
const passiveAttr = starterDataEntry.passiveAttr;
|
||||||
const passiveAbility = allAbilities[this.lastSpecies.getPassiveAbility(formIndex)];
|
const passiveAbility = allAbilities[this.lastSpecies.getPassiveAbility(formIndex)];
|
||||||
|
|
||||||
if (this.pokemonAbilityText.visible) {
|
if (this.pokemonAbilityText.visible) {
|
||||||
@ -3967,13 +4036,13 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.speciesStarterMoves.push(...levelMoves.filter(lm => lm[0] > 0 && lm[0] <= 5).map(lm => lm[1]));
|
this.speciesStarterMoves.push(...levelMoves.filter(lm => lm[0] > 0 && lm[0] <= 5).map(lm => lm[1]));
|
||||||
if (speciesEggMoves.hasOwnProperty(species.speciesId)) {
|
if (speciesEggMoves.hasOwnProperty(species.speciesId)) {
|
||||||
for (let em = 0; em < 4; em++) {
|
for (let em = 0; em < 4; em++) {
|
||||||
if (globalScene.gameData.starterData[species.speciesId].eggMoves & (1 << em)) {
|
if (starterDataEntry.eggMoves & (1 << em)) {
|
||||||
this.speciesStarterMoves.push(speciesEggMoves[species.speciesId][em]);
|
this.speciesStarterMoves.push(speciesEggMoves[species.speciesId][em]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const speciesMoveData = globalScene.gameData.starterData[species.speciesId].moveset;
|
const speciesMoveData = starterDataEntry.moveset;
|
||||||
const moveData: StarterMoveset | null = speciesMoveData
|
const moveData: StarterMoveset | null = speciesMoveData
|
||||||
? Array.isArray(speciesMoveData)
|
? Array.isArray(speciesMoveData)
|
||||||
? speciesMoveData
|
? speciesMoveData
|
||||||
@ -3981,9 +4050,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
: null;
|
: null;
|
||||||
const availableStarterMoves = this.speciesStarterMoves.concat(
|
const availableStarterMoves = this.speciesStarterMoves.concat(
|
||||||
speciesEggMoves.hasOwnProperty(species.speciesId)
|
speciesEggMoves.hasOwnProperty(species.speciesId)
|
||||||
? speciesEggMoves[species.speciesId].filter(
|
? speciesEggMoves[species.speciesId].filter((_: any, em: number) => starterDataEntry.eggMoves & (1 << em))
|
||||||
(_: any, em: number) => globalScene.gameData.starterData[species.speciesId].eggMoves & (1 << em),
|
|
||||||
)
|
|
||||||
: [],
|
: [],
|
||||||
);
|
);
|
||||||
this.starterMoveset = (moveData || (this.speciesStarterMoves.slice(0, 4) as StarterMoveset)).filter(m =>
|
this.starterMoveset = (moveData || (this.speciesStarterMoves.slice(0, 4) as StarterMoveset)).filter(m =>
|
||||||
@ -4010,9 +4077,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.setTypeIcons(speciesForm.type1, speciesForm.type2);
|
this.setTypeIcons(speciesForm.type1, speciesForm.type2);
|
||||||
|
|
||||||
this.teraIcon.setFrame(PokemonType[this.teraCursor].toLowerCase());
|
this.teraIcon.setFrame(PokemonType[this.teraCursor].toLowerCase());
|
||||||
this.teraIcon.setVisible(
|
this.teraIcon.setVisible(!this.statsMode && this.allowTera);
|
||||||
!this.statsMode && globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
this.pokemonAbilityText.setText("");
|
this.pokemonAbilityText.setText("");
|
||||||
this.pokemonPassiveText.setText("");
|
this.pokemonPassiveText.setText("");
|
||||||
@ -4045,10 +4110,15 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const hasEggMoves = species && speciesEggMoves.hasOwnProperty(species.speciesId);
|
const hasEggMoves = species && speciesEggMoves.hasOwnProperty(species.speciesId);
|
||||||
|
let eggMoves = 0;
|
||||||
|
if (species) {
|
||||||
|
const { starterDataEntry } = this.getSpeciesData(this.lastSpecies.speciesId);
|
||||||
|
eggMoves = starterDataEntry.eggMoves;
|
||||||
|
}
|
||||||
|
|
||||||
for (let em = 0; em < 4; em++) {
|
for (let em = 0; em < 4; em++) {
|
||||||
const eggMove = hasEggMoves ? allMoves[speciesEggMoves[species.speciesId][em]] : null;
|
const eggMove = hasEggMoves ? allMoves[speciesEggMoves[species.speciesId][em]] : null;
|
||||||
const eggMoveUnlocked = eggMove && globalScene.gameData.starterData[species.speciesId].eggMoves & (1 << em);
|
const eggMoveUnlocked = eggMove && eggMoves & (1 << em);
|
||||||
this.pokemonEggMoveBgs[em].setFrame(
|
this.pokemonEggMoveBgs[em].setFrame(
|
||||||
PokemonType[eggMove ? eggMove.type : PokemonType.UNKNOWN].toString().toLowerCase(),
|
PokemonType[eggMove ? eggMove.type : PokemonType.UNKNOWN].toString().toLowerCase(),
|
||||||
);
|
);
|
||||||
@ -4064,6 +4134,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.tryUpdateValue();
|
this.tryUpdateValue();
|
||||||
|
|
||||||
this.updateInstructions();
|
this.updateInstructions();
|
||||||
|
|
||||||
|
saveStarterPreferences(this.originalStarterPreferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTypeIcons(type1: PokemonType | null, type2: PokemonType | null): void {
|
setTypeIcons(type1: PokemonType | null, type2: PokemonType | null): void {
|
||||||
@ -4157,9 +4229,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
textStyle = TextStyle.SUMMARY_GOLD;
|
textStyle = TextStyle.SUMMARY_GOLD;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (baseStarterValue - starterValue > 0) {
|
starter.label.setColor(this.getTextColor(textStyle)).setShadowColor(this.getTextColor(textStyle, true));
|
||||||
starter.label.setColor(this.getTextColor(textStyle)).setShadowColor(this.getTextColor(textStyle, true));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tryUpdateValue(add?: number, addingToParty?: boolean): boolean {
|
tryUpdateValue(add?: number, addingToParty?: boolean): boolean {
|
||||||
@ -4318,14 +4388,12 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
originalStarterSelectCallback?.(
|
originalStarterSelectCallback?.(
|
||||||
new Array(this.starterSpecies.length).fill(0).map((_, i) => {
|
new Array(this.starterSpecies.length).fill(0).map((_, i) => {
|
||||||
const starterSpecies = thisObj.starterSpecies[i];
|
const starterSpecies = thisObj.starterSpecies[i];
|
||||||
|
const { starterDataEntry } = this.getSpeciesData(starterSpecies.speciesId);
|
||||||
return {
|
return {
|
||||||
species: starterSpecies,
|
species: starterSpecies,
|
||||||
dexAttr: thisObj.starterAttr[i],
|
dexAttr: thisObj.starterAttr[i],
|
||||||
abilityIndex: thisObj.starterAbilityIndexes[i],
|
abilityIndex: thisObj.starterAbilityIndexes[i],
|
||||||
passive: !(
|
passive: !(starterDataEntry.passiveAttr ^ (PassiveAttr.ENABLED | PassiveAttr.UNLOCKED)),
|
||||||
globalScene.gameData.starterData[starterSpecies.speciesId].passiveAttr ^
|
|
||||||
(PassiveAttr.ENABLED | PassiveAttr.UNLOCKED)
|
|
||||||
),
|
|
||||||
nature: thisObj.starterNatures[i] as Nature,
|
nature: thisObj.starterNatures[i] as Nature,
|
||||||
teraType: thisObj.starterTeras[i] as PokemonType,
|
teraType: thisObj.starterTeras[i] as PokemonType,
|
||||||
moveset: thisObj.starterMovesets[i],
|
moveset: thisObj.starterMovesets[i],
|
||||||
@ -4382,7 +4450,8 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
*/
|
*/
|
||||||
getCurrentDexProps(speciesId: number): bigint {
|
getCurrentDexProps(speciesId: number): bigint {
|
||||||
let props = 0n;
|
let props = 0n;
|
||||||
const caughtAttr = globalScene.gameData.dexData[speciesId].caughtAttr;
|
const { dexEntry } = this.getSpeciesData(speciesId);
|
||||||
|
const caughtAttr = dexEntry.caughtAttr;
|
||||||
|
|
||||||
/* this checks the gender of the pokemon; this works by checking a) that the starter preferences for the species exist, and if so, is it female. If so, it'll add DexAttr.FEMALE to our temp props
|
/* this checks the gender of the pokemon; this works by checking a) that the starter preferences for the species exist, and if so, is it female. If so, it'll add DexAttr.FEMALE to our temp props
|
||||||
* It then checks b) if the caughtAttr for the pokemon is female and NOT male - this means that the ONLY gender we've gotten is female, and we need to add DexAttr.FEMALE to our temp props
|
* It then checks b) if the caughtAttr for the pokemon is female and NOT male - this means that the ONLY gender we've gotten is female, and we need to add DexAttr.FEMALE to our temp props
|
||||||
@ -4450,7 +4519,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonSprite.setVisible(!!this.speciesStarterDexEntry?.caughtAttr);
|
this.pokemonSprite.setVisible(!!this.speciesStarterDexEntry?.caughtAttr);
|
||||||
//@ts-expect-error
|
//@ts-expect-error
|
||||||
this.statsContainer.updateIvs(null); // TODO: resolve ts-ignore. !?!?
|
this.statsContainer.updateIvs(null); // TODO: resolve ts-ignore. !?!?
|
||||||
this.teraIcon.setVisible(globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id));
|
this.teraIcon.setVisible(this.allowTera);
|
||||||
const props = globalScene.gameData.getSpeciesDexAttrProps(
|
const props = globalScene.gameData.getSpeciesDexAttrProps(
|
||||||
this.lastSpecies,
|
this.lastSpecies,
|
||||||
this.getCurrentDexProps(this.lastSpecies.speciesId),
|
this.getCurrentDexProps(this.lastSpecies.speciesId),
|
||||||
@ -4458,8 +4527,9 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
const formIndex = props.formIndex;
|
const formIndex = props.formIndex;
|
||||||
this.canCycleTera =
|
this.canCycleTera =
|
||||||
!this.statsMode &&
|
!this.statsMode &&
|
||||||
globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) &&
|
this.allowTera &&
|
||||||
!isNullOrUndefined(getPokemonSpeciesForm(this.lastSpecies.speciesId, formIndex ?? 0).type2);
|
!isNullOrUndefined(getPokemonSpeciesForm(this.lastSpecies.speciesId, formIndex ?? 0).type2) &&
|
||||||
|
!globalScene.gameMode.hasChallenge(Challenges.FRESH_START);
|
||||||
this.updateInstructions();
|
this.updateInstructions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4501,7 +4571,7 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
clear(): void {
|
clear(): void {
|
||||||
super.clear();
|
super.clear();
|
||||||
|
|
||||||
saveStarterPreferences(this.starterPreferences);
|
this.clearStarterPreferences();
|
||||||
this.cursor = -1;
|
this.cursor = -1;
|
||||||
this.hideInstructions();
|
this.hideInstructions();
|
||||||
this.activeTooltip = undefined;
|
this.activeTooltip = undefined;
|
||||||
@ -4544,5 +4614,6 @@ export class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
*/
|
*/
|
||||||
clearStarterPreferences() {
|
clearStarterPreferences() {
|
||||||
this.starterPreferences = {};
|
this.starterPreferences = {};
|
||||||
|
this.originalStarterPreferences = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,8 @@ import type { MoveSourceType } from "#enums/move-source-type";
|
|||||||
import type { SpeciesId } from "#enums/species-id";
|
import type { SpeciesId } from "#enums/species-id";
|
||||||
import type { EnemyPokemon, PlayerPokemon, Pokemon } from "#field/pokemon";
|
import type { EnemyPokemon, PlayerPokemon, Pokemon } from "#field/pokemon";
|
||||||
import type { ModifierTypeOption } from "#modifiers/modifier-type";
|
import type { ModifierTypeOption } from "#modifiers/modifier-type";
|
||||||
import type { DexAttrProps } from "#system/game-data";
|
import type { DexAttrProps, StarterDataEntry } from "#system/game-data";
|
||||||
|
import type { DexEntry } from "#types/dex-data";
|
||||||
import { BooleanHolder, type NumberHolder } from "./common";
|
import { BooleanHolder, type NumberHolder } from "./common";
|
||||||
import { getPokemonSpecies } from "./pokemon-utils";
|
import { getPokemonSpecies } from "./pokemon-utils";
|
||||||
|
|
||||||
@ -47,6 +48,20 @@ export function applyChallenges(
|
|||||||
species: SpeciesId,
|
species: SpeciesId,
|
||||||
cost: NumberHolder,
|
cost: NumberHolder,
|
||||||
): boolean;
|
): boolean;
|
||||||
|
/**
|
||||||
|
* Apply all challenges that modify selectable starter data.
|
||||||
|
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_SELECT_MODIFY
|
||||||
|
* @param speciesId {@link SpeciesId} The speciesId of the pokemon
|
||||||
|
* @param dexEntry {@link DexEntry} The pokedex data associated to the pokemon.
|
||||||
|
* @param starterDataEntry {@link StarterDataEntry} The starter data associated to the pokemon.
|
||||||
|
* @returns True if any challenge was successfully applied.
|
||||||
|
*/
|
||||||
|
export function applyChallenges(
|
||||||
|
challengeType: ChallengeType.STARTER_SELECT_MODIFY,
|
||||||
|
speciesId: SpeciesId,
|
||||||
|
dexEntry: DexEntry,
|
||||||
|
starterDataEntry: StarterDataEntry,
|
||||||
|
): boolean;
|
||||||
/**
|
/**
|
||||||
* Apply all challenges that modify a starter after selection.
|
* Apply all challenges that modify a starter after selection.
|
||||||
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_MODIFY
|
* @param challengeType {@link ChallengeType} ChallengeType.STARTER_MODIFY
|
||||||
@ -269,6 +284,9 @@ export function applyChallenges(challengeType: ChallengeType, ...args: any[]): b
|
|||||||
case ChallengeType.STARTER_COST:
|
case ChallengeType.STARTER_COST:
|
||||||
ret ||= c.applyStarterCost(args[0], args[1]);
|
ret ||= c.applyStarterCost(args[0], args[1]);
|
||||||
break;
|
break;
|
||||||
|
case ChallengeType.STARTER_SELECT_MODIFY:
|
||||||
|
ret ||= c.applyStarterSelectModify(args[0], args[1], args[2]);
|
||||||
|
break;
|
||||||
case ChallengeType.STARTER_MODIFY:
|
case ChallengeType.STARTER_MODIFY:
|
||||||
ret ||= c.applyStarterModify(args[0]);
|
ret ||= c.applyStarterModify(args[0]);
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user