diff --git a/src/ui/abstact-option-select-ui-handler.ts b/src/ui/abstact-option-select-ui-handler.ts index f03523144..4168c617b 100644 --- a/src/ui/abstact-option-select-ui-handler.ts +++ b/src/ui/abstact-option-select-ui-handler.ts @@ -8,6 +8,7 @@ export interface OptionSelectConfig { xOffset?: number; yOffset?: number; options: OptionSelectItem[]; + maxOptions?: integer; } export interface OptionSelectItem { @@ -17,6 +18,9 @@ export interface OptionSelectItem { overrideSound?: boolean; } +const scrollUpLabel = '↑'; +const scrollDownLabel = '↓'; + export default abstract class AbstractOptionSelectUiHandler extends UiHandler { protected optionSelectContainer: Phaser.GameObjects.Container; protected optionSelectBg: Phaser.GameObjects.NineSlice; @@ -24,6 +28,8 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { protected config: OptionSelectConfig; + protected scrollCursor: integer = 0; + private cursorObj: Phaser.GameObjects.Image; constructor(scene: BattleScene, mode?: Mode) { @@ -33,7 +39,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { abstract getWindowWidth(): integer; getWindowHeight(): integer { - return ((this.config?.options || []).length + 1) * 16; + return (Math.min((this.config?.options || []).length, this.config?.maxOptions || 99) + 1) * 16; } setup() { @@ -62,6 +68,10 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { this.optionSelectContainer.setPosition((this.scene.game.canvas.width / 6) - 1 - (this.config?.xOffset || 0), -48 + (this.config?.yOffset || 0)); this.optionSelectBg.width = Math.max(this.optionSelectText.displayWidth + 24, this.getWindowWidth()); + + if (this.config?.options.length > this.config?.maxOptions) + this.optionSelectText.setText(this.getOptionsWithScroll().map(o => o.label).join('\n')); + this.optionSelectBg.height = this.getWindowHeight(); this.optionSelectText.setPositionRelative(this.optionSelectBg, 16, 9); @@ -79,6 +89,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { this.scene.ui.bringToTop(this.optionSelectContainer); this.optionSelectContainer.setVisible(true); + this.scrollCursor = 0; this.setCursor(0); return true; @@ -89,15 +100,20 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { let success = false; - const options = this.config?.options || []; + const options = this.getOptionsWithScroll(); let playSound = true; if (button === Button.ACTION || button === Button.CANCEL) { success = true; - if (button === Button.CANCEL) - this.setCursor(options.length - 1); - const option = options[this.cursor]; + if (button === Button.CANCEL) { + if (this.config?.maxOptions && this.config.options.length > this.config.maxOptions) { + this.scrollCursor = (this.config.options.length - this.config.maxOptions) + 1; + this.cursor = options.length - 1; + } else + this.setCursor(options.length - 1); + } + const option = this.config.options[this.cursor + (this.scrollCursor - (this.scrollCursor ? 1 : 0))]; option.handler(); if (!option.keepOpen) this.clear(); @@ -121,8 +137,68 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { return success; } + getOptionsWithScroll(): OptionSelectItem[] { + if (!this.config) + return []; + + const options = this.config.options.slice(0); + + if (!this.config.maxOptions || this.config.options.length < this.config.maxOptions) + return options; + + const optionsScrollTotal = options.length; + let optionStartIndex = this.scrollCursor; + let optionEndIndex = Math.min(optionsScrollTotal, optionStartIndex + (!optionStartIndex || this.scrollCursor + (this.config.maxOptions - 1) >= optionsScrollTotal ? this.config.maxOptions - 1 : this.config.maxOptions - 2)); + + if (this.config?.maxOptions && options.length > this.config.maxOptions) { + options.splice(optionEndIndex, optionsScrollTotal); + options.splice(0, optionStartIndex); + if (optionStartIndex) + options.unshift({ + label: scrollUpLabel, + handler: () => { } + }); + if (optionEndIndex < optionsScrollTotal) + options.push({ + label: scrollDownLabel, + handler: () => { } + }); + } + + return options; + } + setCursor(cursor: integer): boolean { - const ret = super.setCursor(cursor); + const changed = this.cursor !== cursor; + + let isScroll = false; + const options = this.getOptionsWithScroll(); + if (changed && this.config?.maxOptions && this.config.options.length > this.config.maxOptions) { + const optionsScrollTotal = options.length; + if (Math.abs(cursor - this.cursor) === options.length - 1) { + this.scrollCursor = cursor ? optionsScrollTotal - (this.config.maxOptions - 1) : 0; + this.setupOptions(); + } else { + const isDown = cursor && cursor > this.cursor; + if (isDown) { + if (options[cursor].label === scrollDownLabel) { + isScroll = true; + this.scrollCursor++; + } + } else { + if (!cursor && this.scrollCursor) { + isScroll = true; + this.scrollCursor--; + } + } + if (isScroll && this.scrollCursor === 1) + this.scrollCursor += isDown ? 1 : -1; + } + } + if (isScroll) + this.setupOptions(); + else + this.cursor = cursor; if (!this.cursorObj) { this.cursorObj = this.scene.add.image(0, 0, 'cursor'); @@ -131,7 +207,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { this.cursorObj.setPositionRelative(this.optionSelectBg, 12, 17 + this.cursor * 16); - return ret; + return changed; } clear() { diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index b1d2789a0..cd0245129 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -433,9 +433,9 @@ export default class PartyUiHandler extends MessageUiHandler { this.optionsScrollCursor += isDown ? 1 : -1; } } - if (isScroll) { + if (isScroll) this.updateOptions(); - } else + else this.optionsCursor = cursor; if (!this.optionsCursorObj) { this.optionsCursorObj = this.scene.add.image(0, 0, 'cursor'); @@ -509,8 +509,6 @@ export default class PartyUiHandler extends MessageUiHandler { } updateOptions(): void { - const wideOptions = this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER; - const pokemon = this.scene.getParty()[this.cursor]; const learnableLevelMoves = this.partyUiMode === PartyUiMode.REMEMBER_MOVE_MODIFIER diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 8abcb6418..25aff7459 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -51,9 +51,15 @@ export default class StarterSelectUiHandler extends MessageUiHandler { private pokemonNatureText: BBCodeText; private pokemonCaughtCountLabelText: Phaser.GameObjects.Text; private pokemonCaughtCountText: Phaser.GameObjects.Text; + private pokemonMovesContainer: Phaser.GameObjects.Container; private pokemonMoveContainers: Phaser.GameObjects.Container[]; private pokemonMoveBgs: Phaser.GameObjects.NineSlice[]; private pokemonMoveLabels: Phaser.GameObjects.Text[]; + private pokemonAdditionalMoveCountLabel: Phaser.GameObjects.Text; + private pokemonEggMovesContainer: Phaser.GameObjects.Container; + private pokemonEggMoveContainers: Phaser.GameObjects.Container[]; + private pokemonEggMoveBgs: Phaser.GameObjects.NineSlice[]; + private pokemonEggMoveLabels: Phaser.GameObjects.Text[]; private genOptionsText: Phaser.GameObjects.Text; private instructionsText: Phaser.GameObjects.Text; private starterSelectMessageBox: Phaser.GameObjects.NineSlice; @@ -186,6 +192,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonMoveBgs = []; this.pokemonMoveLabels = []; + this.pokemonEggMoveContainers = []; + this.pokemonEggMoveBgs = []; + this.pokemonEggMoveLabels = []; + this.genOptionsText = addTextObject(this.scene, 124, 7, '', TextStyle.WINDOW, { fontSize: 72, lineSpacing: 39, align: 'center' }); this.genOptionsText.setShadowOffset(4.5, 4.5); this.genOptionsText.setOrigin(0.5, 0); @@ -305,14 +315,16 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonSprite = this.scene.add.sprite(53, 63, `pkmn__sub`); this.starterSelectContainer.add(this.pokemonSprite); + this.pokemonMovesContainer = this.scene.add.container(102, 16); + this.pokemonMovesContainer.setScale(0.5); + for (let m = 0; m < 4; m++) { - const moveContainer = this.scene.add.container(102, 16 + 7 * m); - moveContainer.setScale(0.5); + const moveContainer = this.scene.add.container(0, 14 * m); const moveBg = this.scene.add.nineslice(0, 0, 'type_bgs', 'unknown', 92, 14, 2, 2, 2, 2); moveBg.setOrigin(1, 0); - const moveLabel = addTextObject(this.scene, -moveBg.width / 2, 0, 'Thunder Wave', TextStyle.PARTY); + const moveLabel = addTextObject(this.scene, -moveBg.width / 2, 0, '-', TextStyle.PARTY); moveLabel.setOrigin(0.5, 0); this.pokemonMoveBgs.push(moveBg); @@ -322,10 +334,47 @@ export default class StarterSelectUiHandler extends MessageUiHandler { moveContainer.add(moveLabel); this.pokemonMoveContainers.push(moveContainer); - - this.starterSelectContainer.add(moveContainer); + this.pokemonMovesContainer.add(moveContainer); } + this.pokemonAdditionalMoveCountLabel = addTextObject(this.scene, -this.pokemonMoveBgs[0].width / 2, 56, '(+0)', TextStyle.PARTY); + this.pokemonAdditionalMoveCountLabel.setOrigin(0.5, 0); + + this.pokemonMovesContainer.add(this.pokemonAdditionalMoveCountLabel); + + this.starterSelectContainer.add(this.pokemonMovesContainer); + + this.pokemonEggMovesContainer = this.scene.add.container(102, 94); + this.pokemonEggMovesContainer.setScale(0.25); + this.pokemonEggMovesContainer.setVisible(false); + + const eggMovesLabel = addTextObject(this.scene, -46, 0, 'Egg Moves', TextStyle.SUMMARY); + eggMovesLabel.setOrigin(0.5, 0); + + this.pokemonEggMovesContainer.add(eggMovesLabel); + + for (let m = 0; m < 4; m++) { + const eggMoveContainer = this.scene.add.container(0, 16 + 14 * m); + + const eggMoveBg = this.scene.add.nineslice(0, 0, 'type_bgs', 'unknown', 92, 14, 2, 2, 2, 2); + eggMoveBg.setOrigin(1, 0); + + const eggMoveLabel = addTextObject(this.scene, -eggMoveBg.width / 2, 0, '???', TextStyle.PARTY); + eggMoveLabel.setOrigin(0.5, 0); + + this.pokemonEggMoveBgs.push(eggMoveBg); + this.pokemonEggMoveLabels.push(eggMoveLabel); + + eggMoveContainer.add(eggMoveBg); + eggMoveContainer.add(eggMoveLabel); + + this.pokemonEggMoveContainers.push(eggMoveContainer); + + this.pokemonEggMovesContainer.add(eggMoveContainer); + } + + this.starterSelectContainer.add(this.pokemonEggMovesContainer); + this.instructionsText = addTextObject(this.scene, 4, 156, '', TextStyle.PARTY, { fontSize: '42px' }); this.starterSelectContainer.add(this.instructionsText); @@ -572,6 +621,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { showSwapOptions(this.starterMoveset); } }), + maxOptions: 8, yOffset: 19 }); }); @@ -585,6 +635,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { ui.setMode(Mode.STARTER_SELECT); } }), + maxOptions: 8, yOffset: 19 }); }); @@ -1083,6 +1134,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonMoveContainers[m].setVisible(!!move); } + this.pokemonAdditionalMoveCountLabel.setText(`(+${Math.max(this.speciesStarterMoves.length - 4, 0)})`); + this.pokemonAdditionalMoveCountLabel.setVisible(this.speciesStarterMoves.length > 4); + this.updateInstructions(); }