From 8093b3117b3edd2509f9619d747070a3b29ccbb5 Mon Sep 17 00:00:00 2001 From: OriShalhon Date: Mon, 23 Dec 2024 17:37:04 +0100 Subject: [PATCH] feat: add random selection option during starter select --- src/configs/inputs/cfg_keyboard_qwerty.ts | 4 +- src/enums/buttons.ts | 3 +- src/system/settings/settings-keyboard.ts | 8 ++ src/ui-inputs.ts | 2 + src/ui/starter-select-ui-handler.ts | 93 ++++++++++++++++++++++- 5 files changed, 105 insertions(+), 5 deletions(-) diff --git a/src/configs/inputs/cfg_keyboard_qwerty.ts b/src/configs/inputs/cfg_keyboard_qwerty.ts index 5ddc12e8784..e14923c59f1 100644 --- a/src/configs/inputs/cfg_keyboard_qwerty.ts +++ b/src/configs/inputs/cfg_keyboard_qwerty.ts @@ -183,6 +183,7 @@ const cfg_keyboard_qwerty = { [SettingKeyboard.Button_Cycle_Variant]: Button.V, [SettingKeyboard.Button_Speed_Up]: Button.SPEED_UP, [SettingKeyboard.Button_Slow_Down]: Button.SLOW_DOWN, + [SettingKeyboard.Button_Randomize]: Button.RANDOMIZE, [SettingKeyboard.Alt_Button_Up]: Button.UP, [SettingKeyboard.Alt_Button_Down]: Button.DOWN, [SettingKeyboard.Alt_Button_Left]: Button.LEFT, @@ -200,6 +201,7 @@ const cfg_keyboard_qwerty = { [SettingKeyboard.Alt_Button_Cycle_Variant]: Button.V, [SettingKeyboard.Alt_Button_Speed_Up]: Button.SPEED_UP, [SettingKeyboard.Alt_Button_Slow_Down]: Button.SLOW_DOWN, + [SettingKeyboard.Alt_Button_Randomize]: Button.RANDOMIZE }, default: { KEY_ARROW_UP: SettingKeyboard.Button_Up, @@ -230,7 +232,7 @@ const cfg_keyboard_qwerty = { KEY_M: SettingKeyboard.Alt_Button_Menu, KEY_O: -1, KEY_P: -1, - KEY_Q: -1, + KEY_Q: SettingKeyboard.Button_Randomize, KEY_S: SettingKeyboard.Alt_Button_Down, KEY_T: SettingKeyboard.Alt_Button_Cycle_Form, KEY_U: -1, diff --git a/src/enums/buttons.ts b/src/enums/buttons.ts index fe26023f8e7..28287ec156e 100644 --- a/src/enums/buttons.ts +++ b/src/enums/buttons.ts @@ -15,5 +15,6 @@ export enum Button { CYCLE_NATURE, V, SPEED_UP, - SLOW_DOWN + SLOW_DOWN, + RANDOMIZE, } diff --git a/src/system/settings/settings-keyboard.ts b/src/system/settings/settings-keyboard.ts index 97990f61c86..172132cf856 100644 --- a/src/system/settings/settings-keyboard.ts +++ b/src/system/settings/settings-keyboard.ts @@ -34,6 +34,8 @@ export enum SettingKeyboard { Alt_Button_Cycle_Nature = "ALT_BUTTON_CYCLE_NATURE", Button_Cycle_Variant = "BUTTON_CYCLE_VARIANT", Alt_Button_Cycle_Variant = "ALT_BUTTON_CYCLE_VARIANT", + Button_Randomize = "BUTTON_RANDOMIZE", + Alt_Button_Randomize = "ALT_BUTTON_RANDOMIZE", Button_Speed_Up = "BUTTON_SPEED_UP", Alt_Button_Speed_Up = "ALT_BUTTON_SPEED_UP", Button_Slow_Down = "BUTTON_SLOW_DOWN", @@ -75,6 +77,8 @@ export const settingKeyboardOptions = { [SettingKeyboard.Alt_Button_Cycle_Nature]: [ `KEY ${Button.CYCLE_NATURE.toString()}`, pressAction ], [SettingKeyboard.Button_Cycle_Variant]: [ `KEY ${Button.V.toString()}`, pressAction ], [SettingKeyboard.Alt_Button_Cycle_Variant]: [ `KEY ${Button.V.toString()}`, pressAction ], + [SettingKeyboard.Button_Randomize]: [ `KEY ${Button.RANDOMIZE.toString()}`, pressAction ], + [SettingKeyboard.Alt_Button_Randomize]: [ `KEY ${Button.RANDOMIZE.toString()}`, pressAction ], [SettingKeyboard.Button_Speed_Up]: [ `KEY ${Button.SPEED_UP.toString()}`, pressAction ], [SettingKeyboard.Alt_Button_Speed_Up]: [ `KEY ${Button.SPEED_UP.toString()}`, pressAction ], [SettingKeyboard.Button_Slow_Down]: [ `KEY ${Button.SLOW_DOWN.toString()}`, pressAction ], @@ -114,6 +118,8 @@ export const settingKeyboardDefaults = { [SettingKeyboard.Alt_Button_Cycle_Nature]: 0, [SettingKeyboard.Button_Cycle_Variant]: 0, [SettingKeyboard.Alt_Button_Cycle_Variant]: 0, + [SettingKeyboard.Button_Randomize]: 0, + [SettingKeyboard.Alt_Button_Randomize]: 0, [SettingKeyboard.Button_Speed_Up]: 0, [SettingKeyboard.Alt_Button_Speed_Up]: 0, [SettingKeyboard.Button_Slow_Down]: 0, @@ -149,6 +155,7 @@ export function setSettingKeyboard(scene: BattleScene, setting: SettingKeyboard, case SettingKeyboard.Button_Cycle_Ability: case SettingKeyboard.Button_Cycle_Nature: case SettingKeyboard.Button_Cycle_Variant: + case SettingKeyboard.Button_Randomize: case SettingKeyboard.Button_Speed_Up: case SettingKeyboard.Button_Slow_Down: case SettingKeyboard.Alt_Button_Up: @@ -165,6 +172,7 @@ export function setSettingKeyboard(scene: BattleScene, setting: SettingKeyboard, case SettingKeyboard.Alt_Button_Cycle_Ability: case SettingKeyboard.Alt_Button_Cycle_Nature: case SettingKeyboard.Alt_Button_Cycle_Variant: + case SettingKeyboard.Alt_Button_Randomize: case SettingKeyboard.Alt_Button_Speed_Up: case SettingKeyboard.Alt_Button_Slow_Down: case SettingKeyboard.Alt_Button_Submit: diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts index 92b1653df3d..3c6ca780715 100644 --- a/src/ui-inputs.ts +++ b/src/ui-inputs.ts @@ -79,6 +79,7 @@ export class UiInputs { [Button.SUBMIT]: () => this.buttonTouch(), [Button.ACTION]: () => this.buttonAb(Button.ACTION), [Button.CANCEL]: () => this.buttonAb(Button.CANCEL), + [Button.RANDOMIZE]: () => this.buttonAb(Button.RANDOMIZE), [Button.MENU]: () => this.buttonMenu(), [Button.STATS]: () => this.buttonGoToFilter(Button.STATS), [Button.CYCLE_SHINY]: () => this.buttonCycleOption(Button.CYCLE_SHINY), @@ -110,6 +111,7 @@ export class UiInputs { [Button.CYCLE_ABILITY]: () => undefined, [Button.CYCLE_NATURE]: () => undefined, [Button.V]: () => this.buttonInfo(false), + [Button.RANDOMIZE]: () => undefined, [Button.SPEED_UP]: () => undefined, [Button.SLOW_DOWN]: () => undefined, }; diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 691e339eafc..1da8c635e5e 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -267,6 +267,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { private natureIconElement: Phaser.GameObjects.Sprite; private variantIconElement: Phaser.GameObjects.Sprite; private goFilterIconElement: Phaser.GameObjects.Sprite; + private randomSelectIconElement: Phaser.GameObjects.Sprite; private shinyLabel: Phaser.GameObjects.Text; private formLabel: Phaser.GameObjects.Text; private genderLabel: Phaser.GameObjects.Text; @@ -274,6 +275,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { private natureLabel: Phaser.GameObjects.Text; private variantLabel: Phaser.GameObjects.Text; private goFilterLabel: Phaser.GameObjects.Text; + private randomSelectLabel: Phaser.GameObjects.Text; private starterSelectMessageBox: Phaser.GameObjects.NineSlice; private starterSelectMessageBoxContainer: Phaser.GameObjects.Container; @@ -863,6 +865,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.goFilterLabel = addTextObject(this.scene, this.filterInstructionRowX + this.instructionRowTextOffset, this.filterInstructionRowY, i18next.t("starterSelectUiHandler:goFilter"), TextStyle.PARTY, { fontSize: instructionTextSize }); this.goFilterLabel.setName("text-goFilter-label"); + this.randomSelectIconElement = new Phaser.GameObjects.Sprite(this.scene, this.instructionRowX, this.instructionRowY, "keyboard", "Q.png"); + this.randomSelectIconElement.setName("sprite-random-icon-element"); + this.randomSelectIconElement.setScale(0.675); + this.randomSelectIconElement.setOrigin(0.0, 0.0); + this.randomSelectLabel = addTextObject(this.scene, this.instructionRowX + this.instructionRowTextOffset, this.instructionRowY, i18next.t("starterSelectUiHandler:randomize"), TextStyle.PARTY, { fontSize: instructionTextSize }); + this.randomSelectLabel.setName("text-random-label"); + this.hideInstructions(); this.filterInstructionsContainer = this.scene.add.container(50, 5); @@ -1437,8 +1446,79 @@ export default class StarterSelectUiHandler extends MessageUiHandler { success = true; break; } - } else { + } else if (button === Button.RANDOMIZE) { + console.log("Attempting random selection from visible starters"); + if (this.starterSpecies.length < 6) { + // Get current party value + const currentPartyValue = this.starterSpecies + .map(s => s.generation) + .reduce((total: number, gen: number, i: number) => + total += this.scene.gameData.getSpeciesStarterValue(this.starterSpecies[i].speciesId), 0); + // Filter valid starters first + const validStarters = this.filteredStarterContainers.filter(starter => { + const species = starter.species; + const [ isDupe ] = this.isInParty(species); + const starterCost = this.scene.gameData.getSpeciesStarterValue(species.speciesId); + const isValidForChallenge = new BooleanHolder(true); + Challenge.applyChallenges( + this.scene.gameMode, + Challenge.ChallengeType.STARTER_CHOICE, + species, + isValidForChallenge, + this.scene.gameData.getSpeciesDexAttrProps( + species, + this.getCurrentDexProps(species.speciesId) + ), + this.isPartyValid() + ); + const isCaught = this.scene.gameData.dexData[species.speciesId].caughtAttr; + return !isDupe && + isValidForChallenge.value && + (currentPartyValue + starterCost <= this.getValueLimit()) && + isCaught; + }); + if (validStarters.length > 0) { + // Select random starter from valid options + const randomIndex = Math.floor(Math.random() * validStarters.length); + const randomStarter = validStarters[randomIndex]; + const randomSpecies = randomStarter.species; + + // First set the species to load saved preferences and initialize default values + // This triggers the same flow as if the player had moved their cursor to this Pokemon + this.setSpecies(randomSpecies); + + // Get the dex attributes after setSpecies has potentially loaded saved preferences + const dexAttr = this.getCurrentDexProps(randomSpecies.speciesId); + const props = this.scene.gameData.getSpeciesDexAttrProps(randomSpecies, dexAttr); + + // Use the current cursor values which now reflect any saved preferences + // these are the same values the player would see in the UI + const abilityIndex = this.abilityCursor; + const nature = this.natureCursor as unknown as Nature; + const moveset = this.starterMoveset?.slice(0) as StarterMoveset; + + const starterCost = this.scene.gameData.getSpeciesStarterValue(randomSpecies.speciesId); + + const speciesForm = getPokemonSpeciesForm(randomSpecies.speciesId, props.formIndex); + speciesForm.loadAssets(this.scene, props.female, props.formIndex, props.shiny, props.variant, true) + .then(() => { + if (this.tryUpdateValue(starterCost, true)) { + // Use addToParty with the same parameters that would be used in manual selection + this.addToParty(randomSpecies, dexAttr, abilityIndex, nature, moveset, true); + console.log("Random starter added to party:", randomSpecies.name, "with cost:", starterCost); + success = true; + } + }); + } else { + // No valid starters available + error = true; + } + } else { + // Party is full + error = true; + } + } else { let starterContainer; const starterData = this.scene.gameData.starterData[this.lastSpecies.speciesId]; // prepare persistent starter data to store changes @@ -2159,7 +2239,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { return [ isDupe, removeIndex ]; } - addToParty(species: PokemonSpecies, dexAttr: bigint, abilityIndex: integer, nature: Nature, moveset: StarterMoveset) { + addToParty(species: PokemonSpecies, dexAttr: bigint, abilityIndex: integer, nature: Nature, moveset: StarterMoveset, randomSelection: boolean = false) { const props = this.scene.gameData.getSpeciesDexAttrProps(species, dexAttr); this.starterIcons[this.starterSpecies.length].setTexture(species.getIconAtlasKey(props.formIndex, props.shiny, props.variant)); this.starterIcons[this.starterSpecies.length].setFrame(species.getIconId(props.female, props.formIndex, props.shiny, props.variant)); @@ -2170,7 +2250,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.starterAbilityIndexes.push(abilityIndex); this.starterNatures.push(nature); this.starterMovesets.push(moveset); - if (this.speciesLoaded.get(species.speciesId)) { + if (this.speciesLoaded.get(species.speciesId) || randomSelection ) { getPokemonSpeciesForm(species.speciesId, props.formIndex).cry(this.scene); } this.updateInstructions(); @@ -2255,6 +2335,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler { case SettingKeyboard.Button_Stats: iconPath = "C.png"; break; + case SettingKeyboard.Button_Randomize: + iconPath = "Q.png"; + break; default: break; } @@ -2340,8 +2423,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler { // if filter mode is inactivated and gamepadType is not undefined, update the button icons if (!this.filterMode) { this.updateFilterButtonIcon(SettingKeyboard.Button_Stats, gamepadType, this.goFilterIconElement, this.goFilterLabel); + this.updateButtonIcon(SettingKeyboard.Button_Randomize, gamepadType, this.randomSelectIconElement, this.randomSelectLabel); // random icon only appears not in filter mode } + } getValueLimit(): number { @@ -3694,6 +3779,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.variantLabel.setVisible(false); this.goFilterIconElement.setVisible(false); this.goFilterLabel.setVisible(false); + this.randomSelectIconElement.setVisible(false); + this.randomSelectLabel.setVisible(false); } clear(): void {