diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 49a677cd019..e252e03afaf 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -1829,17 +1829,40 @@ export class GameData { return starterCount; } - getSpeciesDefaultDexAttr(species: PokemonSpecies, forSeen: boolean = false, optimistic: boolean = false): bigint { + getSpeciesDefaultDexAttr(species: PokemonSpecies, _forSeen: boolean = false, optimistic: boolean = false): bigint { let ret = 0n; const dexEntry = this.dexData[species.speciesId]; const attr = dexEntry.caughtAttr; - ret |= optimistic - ? attr & DexAttr.SHINY ? DexAttr.SHINY : DexAttr.NON_SHINY - : attr & DexAttr.NON_SHINY || !(attr & DexAttr.SHINY) ? DexAttr.NON_SHINY : DexAttr.SHINY; + if (optimistic) { + if (attr & DexAttr.SHINY) { + ret |= DexAttr.SHINY; + + if (attr & DexAttr.VARIANT_3) { + ret |= DexAttr.VARIANT_3; + } else if (attr & DexAttr.VARIANT_2) { + ret |= DexAttr.VARIANT_2; + } else { + ret |= DexAttr.DEFAULT_VARIANT; + } + } else { + ret |= DexAttr.NON_SHINY; + ret |= DexAttr.DEFAULT_VARIANT; + } + } else { + // Default to non shiny. Fallback to shiny if it's the only thing that's unlocked + ret |= (attr & DexAttr.NON_SHINY || !(attr & DexAttr.SHINY)) ? DexAttr.NON_SHINY : DexAttr.SHINY; + + if (attr & DexAttr.DEFAULT_VARIANT) { + ret |= DexAttr.DEFAULT_VARIANT; + } else if (attr & DexAttr.VARIANT_2) { + ret |= DexAttr.VARIANT_2; + } else if (attr & DexAttr.VARIANT_3) { + ret |= DexAttr.VARIANT_3; + } else { + ret |= DexAttr.DEFAULT_VARIANT; + } + } ret |= attr & DexAttr.MALE || !(attr & DexAttr.FEMALE) ? DexAttr.MALE : DexAttr.FEMALE; - ret |= optimistic - ? attr & DexAttr.SHINY ? attr & DexAttr.VARIANT_3 ? DexAttr.VARIANT_3 : attr & DexAttr.VARIANT_2 ? DexAttr.VARIANT_2 : DexAttr.DEFAULT_VARIANT : DexAttr.DEFAULT_VARIANT - : attr & DexAttr.DEFAULT_VARIANT ? DexAttr.DEFAULT_VARIANT : attr & DexAttr.VARIANT_2 ? DexAttr.VARIANT_2 : attr & DexAttr.VARIANT_3 ? DexAttr.VARIANT_3 : DexAttr.DEFAULT_VARIANT; ret |= this.getFormAttr(this.getFormIndex(attr)); return ret; } @@ -1847,7 +1870,14 @@ export class GameData { getSpeciesDexAttrProps(species: PokemonSpecies, dexAttr: bigint): DexAttrProps { const shiny = !(dexAttr & DexAttr.NON_SHINY); const female = !(dexAttr & DexAttr.MALE); - const variant = dexAttr & DexAttr.DEFAULT_VARIANT ? 0 : dexAttr & DexAttr.VARIANT_2 ? 1 : dexAttr & DexAttr.VARIANT_3 ? 2 : 0; + let variant: Variant = 0; + if (dexAttr & DexAttr.DEFAULT_VARIANT) { + variant = 0; + } else if (dexAttr & DexAttr.VARIANT_2) { + variant = 1; + } else if (dexAttr & DexAttr.VARIANT_3) { + variant = 2; + } const formIndex = this.getFormIndex(dexAttr); return { diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/save-slot-select-ui-handler.ts index 7bfecb1f99b..b36c0af6ec8 100644 --- a/src/ui/save-slot-select-ui-handler.ts +++ b/src/ui/save-slot-select-ui-handler.ts @@ -132,7 +132,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { }, () => { ui.revertMode(); ui.showText("", 0); - }, false, 0, 19, 2000); + }, false, 0, 19, import.meta.env.DEV ? 300 : 2000); }); } else if (this.sessionSlots[cursor].hasData === false) { saveAndCallback(); diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 22408ef829f..aa0139ff7e1 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -197,6 +197,15 @@ function findClosestStarterRow(index: number, numberOfRows: number) { return closestRowIndex; } +interface SpeciesDetails { + shiny?: boolean, + formIndex?: integer + female?: boolean, + variant?: Variant, + abilityIndex?: integer, + natureIndex?: integer, + forSeen?: boolean, // default = false +} export default class StarterSelectUiHandler extends MessageUiHandler { private starterSelectContainer: Phaser.GameObjects.Container; @@ -1593,11 +1602,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (!starterAttributes) { starterAttributes = this.starterPreferences[this.lastSpecies.speciesId] = {}; } - starterAttributes.nature = n as unknown as integer; + starterAttributes.nature = n; this.clearText(); ui.setMode(Mode.STARTER_SELECT); // set nature for starter - this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined, n, undefined); + this.setSpeciesDetails(this.lastSpecies, { natureIndex: n }); this.blockInput = false; return true; } @@ -1635,7 +1644,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { handler: () => { starterData.passiveAttr |= PassiveAttr.ENABLED; ui.setMode(Mode.STARTER_SELECT); - this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined, undefined); + this.setSpeciesDetails(this.lastSpecies); return true; } }); @@ -1645,7 +1654,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { handler: () => { starterData.passiveAttr ^= PassiveAttr.ENABLED; ui.setMode(Mode.STARTER_SELECT); - this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined, undefined); + this.setSpeciesDetails(this.lastSpecies); return true; } }); @@ -1864,7 +1873,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { // Change to shiny, we need to get the proper default variant const newProps = this.scene.gameData.getSpeciesDexAttrProps(this.lastSpecies, this.getCurrentDexProps(this.lastSpecies.speciesId)); const newVariant = starterAttributes.variant ? starterAttributes.variant as Variant : newProps.variant; - this.setSpeciesDetails(this.lastSpecies, true, undefined, undefined, newVariant, undefined, undefined); + this.setSpeciesDetails(this.lastSpecies, { shiny: true, variant: newVariant }); this.scene.playSound("se/sparkle"); // Set the variant label to the shiny tint @@ -1873,12 +1882,40 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonShinyIcon.setTint(tint); this.pokemonShinyIcon.setVisible(true); } else { - this.setSpeciesDetails(this.lastSpecies, false, undefined, undefined, 0, undefined, undefined); + this.setSpeciesDetails(this.lastSpecies, { shiny: false, variant: 0 }); this.pokemonShinyIcon.setVisible(false); success = true; } } break; + case Button.V: + if (this.canCycleVariant) { + let newVariant = props.variant; + do { + newVariant = (newVariant + 1) % 3; + if (newVariant === 0) { + if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.DEFAULT_VARIANT) { // TODO: is this bang correct? + break; + } + } else if (newVariant === 1) { + if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_2) { // TODO: is this bang correct? + break; + } + } else { + if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_3) { // TODO: is this bang correct? + break; + } + } + } while (newVariant !== props.variant); + starterAttributes.variant = newVariant; // store the selected variant + this.setSpeciesDetails(this.lastSpecies, { variant: newVariant as Variant }); + // Cycle tint based on current sprite tint + const tint = getVariantTint(newVariant as Variant); + this.pokemonShinyIcon.setFrame(getVariantIcon(newVariant as Variant)); + this.pokemonShinyIcon.setTint(tint); + success = true; + } + break; case Button.CYCLE_FORM: if (this.canCycleForm) { const formCount = this.lastSpecies.forms.length; @@ -1890,14 +1927,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } } while (newFormIndex !== props.formIndex); starterAttributes.form = newFormIndex; // store the selected form - this.setSpeciesDetails(this.lastSpecies, undefined, newFormIndex, undefined, undefined, undefined, undefined); + this.setSpeciesDetails(this.lastSpecies, { formIndex: newFormIndex }); success = true; } break; case Button.CYCLE_GENDER: if (this.canCycleGender) { starterAttributes.female = !props.female; - this.setSpeciesDetails(this.lastSpecies, undefined, undefined, !props.female, undefined, undefined, undefined); + this.setSpeciesDetails(this.lastSpecies, { female: !props.female }); success = true; } break; @@ -1934,7 +1971,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.scene.ui.editTooltip(`${newAbility.name}`, `${newAbility.description}`); } - this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, newAbilityIndex, undefined); + this.setSpeciesDetails(this.lastSpecies, { abilityIndex: newAbilityIndex }); success = true; } break; @@ -1945,35 +1982,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const newNature = natures[natureIndex < natures.length - 1 ? natureIndex + 1 : 0]; // store cycled nature as default starterAttributes.nature = newNature as unknown as integer; - this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined, newNature, undefined); - success = true; - } - break; - case Button.V: - if (this.canCycleVariant) { - let newVariant = props.variant; - do { - newVariant = (newVariant + 1) % 3; - if (!newVariant) { - if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.DEFAULT_VARIANT) { // TODO: is this bang correct? - break; - } - } else if (newVariant === 1) { - if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_2) { // TODO: is this bang correct? - break; - } - } else { - if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_3) { // TODO: is this bang correct? - break; - } - } - } while (newVariant !== props.variant); - starterAttributes.variant = newVariant; // store the selected variant - this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, newVariant as Variant, undefined, undefined); - // Cycle tint based on current sprite tint - const tint = getVariantTint(newVariant as Variant); - this.pokemonShinyIcon.setFrame(getVariantIcon(newVariant as Variant)); - this.pokemonShinyIcon.setTint(tint); + this.setSpeciesDetails(this.lastSpecies, { natureIndex: newNature }); success = true; } break; @@ -2190,7 +2199,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } else { this.scene.gameData.starterData[speciesId].moveset = this.starterMoveset?.slice(0) as StarterMoveset; } - this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined, undefined, false); + this.setSpeciesDetails(this.lastSpecies, { forSeen: false }); // switch moves of starter if exists if (this.starterMovesets.length) { @@ -2875,7 +2884,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (starterIndex > -1) { props = this.scene.gameData.getSpeciesDexAttrProps(species, this.starterAttr[starterIndex]); - this.setSpeciesDetails(species, props.shiny, props.formIndex, props.female, props.variant, this.starterAbilityIndexes[starterIndex], this.starterNatures[starterIndex]); + this.setSpeciesDetails(species, { + shiny: props.shiny, + formIndex: props.formIndex, + female: props.female, + variant: props.variant, + abilityIndex: this.starterAbilityIndexes[starterIndex], + natureIndex: this.starterNatures[starterIndex] + }); } else { const defaultDexAttr = this.getCurrentDexProps(species.speciesId); const defaultAbilityIndex = starterAttributes?.ability ?? this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species); @@ -2890,7 +2906,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler { props.formIndex = starterAttributes?.form ?? props.formIndex; props.female = starterAttributes?.female ?? props.female; - this.setSpeciesDetails(species, props.shiny, props.formIndex, props.female, props.variant, defaultAbilityIndex, defaultNature); + this.setSpeciesDetails(species, { + shiny: props.shiny, + formIndex: props.formIndex, + female: props.female, + variant: props.variant, + abilityIndex: defaultAbilityIndex, + natureIndex: defaultNature + }); } const speciesForm = getPokemonSpeciesForm(species.speciesId, props.formIndex); @@ -2924,7 +2947,15 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species); const props = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr); - this.setSpeciesDetails(species, props.shiny, props.formIndex, props.female, props.variant, defaultAbilityIndex, defaultNature, true); + this.setSpeciesDetails(species, { + shiny: props.shiny, + formIndex: props.formIndex, + female: props.female, + variant: props.variant, + abilityIndex: defaultAbilityIndex, + natureIndex: defaultNature, + forSeen: true + }); this.pokemonSprite.setTint(0x808080); } } else { @@ -2948,13 +2979,21 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonCandyCountText.setVisible(false); this.pokemonFormText.setVisible(false); - this.setSpeciesDetails(species!, false, 0, false, 0, 0, 0); // TODO: is this bang correct? + this.setSpeciesDetails(species!, { // TODO: is this bang correct? + shiny: false, + formIndex: 0, + female: false, + variant: 0, + abilityIndex: 0, + natureIndex: 0 + }); this.pokemonSprite.clearTint(); } } - - setSpeciesDetails(species: PokemonSpecies, shiny?: boolean, formIndex?: integer, female?: boolean, variant?: Variant, abilityIndex?: integer, natureIndex?: integer, forSeen: boolean = false): void { + setSpeciesDetails(species: PokemonSpecies, options: SpeciesDetails = {}): void { + let { shiny, formIndex, female, variant, abilityIndex, natureIndex } = options; + const forSeen: boolean = options.forSeen ?? false; const oldProps = species ? this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor) : null; const oldAbilityIndex = this.abilityCursor > -1 ? this.abilityCursor : this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species); const oldNatureIndex = this.natureCursor > -1 ? this.natureCursor : this.scene.gameData.getSpeciesDefaultNature(species);