From f2b66592778e6c180ae09e45264373ae64e5003f Mon Sep 17 00:00:00 2001 From: Tiago Rodrigues Date: Mon, 14 Jul 2025 14:42:21 +0100 Subject: [PATCH] [Fix] Implemented suggested cursor behavior and reworked test code --- src/ui/party-ui-handler.ts | 26 +++-- test/ui/item-manage-button.test.ts | 154 ++++++++++++++++------------- 2 files changed, 102 insertions(+), 78 deletions(-) diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 7cce8fb72fe..436dbd9eada 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -185,6 +185,8 @@ export class PartyUiHandler extends MessageUiHandler { private transferAll: boolean; private lastCursor = 0; + private lastLeftPokemonCursor = 0; + private lastRightPokemonCursor = 0; private selectCallback: PartySelectCallback | PartyModifierTransferSelectCallback | null; private selectFilter: PokemonSelectFilter | PokemonModifierTransferSelectFilter; private moveSelectFilter: PokemonMoveSelectFilter; @@ -992,11 +994,9 @@ export class PartyUiHandler extends MessageUiHandler { switch (this.partyUiMode) { case PartyUiMode.DISCARD: this.partyUiMode = PartyUiMode.MODIFIER_TRANSFER; - ui.playSelect(); break; case PartyUiMode.MODIFIER_TRANSFER: this.partyUiMode = PartyUiMode.DISCARD; - ui.playSelect(); break; default: ui.playError(); @@ -1045,6 +1045,13 @@ export class PartyUiHandler extends MessageUiHandler { const slotCount = this.partySlots.length; const battlerCount = globalScene.currentBattle.getBattlerCount(); + if (this.lastCursor < battlerCount) { + this.lastLeftPokemonCursor = this.lastCursor; + } + if (this.lastCursor >= battlerCount && this.lastCursor < 6) { + this.lastRightPokemonCursor = this.lastCursor; + } + let success = false; switch (button) { case Button.UP: @@ -1088,21 +1095,20 @@ export class PartyUiHandler extends MessageUiHandler { success = this.setCursor(this.cursor < 6 ? (this.cursor < slotCount - 1 ? this.cursor + 1 : 6) : 0); break; case Button.LEFT: - if (this.cursor >= battlerCount && this.cursor <= 6) { - success = this.setCursor(this.isItemManageMode() ? 7 : 0); + if (this.cursor === 6) { + success = this.setCursor(this.isItemManageMode() ? 7 : this.lastLeftPokemonCursor); + } + if (this.cursor >= battlerCount && this.cursor < 6) { + success = this.setCursor(this.lastLeftPokemonCursor); } break; case Button.RIGHT: - if ((this.cursor === 7 && this.isItemManageMode()) || slotCount === battlerCount) { + if (this.cursor === 7 || slotCount <= battlerCount) { success = this.setCursor(6); break; } - if (battlerCount >= 2 && slotCount > battlerCount && this.getCursor() === 0 && this.lastCursor === 1) { - success = this.setCursor(2); - break; - } if (slotCount > battlerCount && this.cursor < battlerCount) { - success = this.setCursor(this.lastCursor < 6 ? this.lastCursor || battlerCount : battlerCount); + success = this.setCursor(this.lastRightPokemonCursor || battlerCount); break; } } diff --git a/test/ui/item-manage-button.test.ts b/test/ui/item-manage-button.test.ts index 7521dea6850..fe49200cd86 100644 --- a/test/ui/item-manage-button.test.ts +++ b/test/ui/item-manage-button.test.ts @@ -3,9 +3,10 @@ import { Button } from "#enums/buttons"; import { MoveId } from "#enums/move-id"; import { SpeciesId } from "#enums/species-id"; import { UiMode } from "#enums/ui-mode"; +import type { Pokemon } from "#field/pokemon"; import { GameManager } from "#test/testUtils/gameManager"; -import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; -import { PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler"; +import type { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; +import type { PartyUiHandler } from "#ui/party-ui-handler"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -33,104 +34,121 @@ describe("UI - Transfer Items", () => { { name: "BERRY", count: 2, type: BerryType.APICOT }, { name: "BERRY", count: 2, type: BerryType.LUM }, ]) + .moveset([MoveId.DRAGON_CLAW]) .enemySpecies(SpeciesId.MAGIKARP) .enemyMoveset(MoveId.SPLASH); await game.classicMode.startBattle([SpeciesId.RAYQUAZA, SpeciesId.RAYQUAZA, SpeciesId.RAYQUAZA]); - game.move.use(MoveId.DRAGON_CLAW); + game.move.select(MoveId.DRAGON_CLAW); + + await game.phaseInterceptor.to("EggLapsePhase"); + await game.phaseInterceptor.run("SelectModifierPhase"); }); it("manage button exists in the proper screen", async () => { - game.onNextPrompt("SelectModifierPhase", UiMode.MODIFIER_SELECT, () => { - expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler); + let handlerLength: Phaser.GameObjects.GameObject[] | undefined; - const handler = game.scene.ui.getHandler() as ModifierSelectUiHandler; - handler.setCursor(1); - handler.processInput(Button.ACTION); + await new Promise(resolve => { + //select manage items menu + game.onNextPrompt("SelectModifierPhase", UiMode.MODIFIER_SELECT, () => { + const handler = game.scene.ui.getHandler() as ModifierSelectUiHandler; + handler.processInput(Button.DOWN); + handler.setCursor(1); + handler.processInput(Button.ACTION); + }); - void game.scene.ui.setModeWithoutClear(UiMode.PARTY, PartyUiMode.MODIFIER_TRANSFER); + //select manage button + game.onNextPrompt("SelectModifierPhase", UiMode.PARTY, () => { + const handler = game.scene.ui.getHandler() as PartyUiHandler; + + handler.processInput(Button.DOWN); + handler.processInput(Button.ACTION); + handlerLength = handler.optionsContainer.list; + + resolve(); + }); }); - await game.phaseInterceptor.to("BattleEndPhase"); - - game.onNextPrompt("SelectModifierPhase", UiMode.PARTY, () => { - expect(game.scene.ui.getHandler()).toBeInstanceOf(PartyUiHandler); - const handler = game.scene.ui.getHandler() as PartyUiHandler; - - handler.processInput(Button.DOWN); - handler.processInput(Button.ACTION); - expect(handler.optionsContainer.list).toHaveLength(0); // should select manage button, which has no menu - - game.phaseInterceptor.unlock(); - }); - - await game.phaseInterceptor.to("SelectModifierPhase"); + expect(handlerLength).toHaveLength(0); // should select manage button, which has no menu }); it("manage button doesn't exist in the other screens", async () => { - // Select and enter team summary menu - game.onNextPrompt("SelectModifierPhase", UiMode.MODIFIER_SELECT, () => { - expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler); + let handlerLength: Phaser.GameObjects.GameObject[] | undefined; - const handler = game.scene.ui.getHandler() as ModifierSelectUiHandler; - handler.setCursor(2); - handler.processInput(Button.ACTION); + await new Promise(resolve => { + //select check items menu + game.onNextPrompt("SelectModifierPhase", UiMode.MODIFIER_SELECT, () => { + const handler = game.scene.ui.getHandler() as ModifierSelectUiHandler; + handler.processInput(Button.DOWN); + handler.setCursor(2); + handler.processInput(Button.ACTION); + }); - void game.scene.ui.setModeWithoutClear(UiMode.PARTY, PartyUiMode.MODIFIER_TRANSFER); + //try to select manage button, select 2nd pokemon instead + game.onNextPrompt("SelectModifierPhase", UiMode.PARTY, () => { + const handler = game.scene.ui.getHandler() as PartyUiHandler; + + handler.processInput(Button.DOWN); + handler.processInput(Button.ACTION); + handlerLength = handler.optionsContainer.list; + + resolve(); + }); }); - await game.phaseInterceptor.to("BattleEndPhase"); - - game.phaseInterceptor.addToNextPrompt("SelectModifierPhase", UiMode.PARTY, () => { - expect(game.scene.ui.getHandler()).toBeInstanceOf(PartyUiHandler); - const handler = game.scene.ui.getHandler() as PartyUiHandler; - - handler.processInput(Button.DOWN); - handler.processInput(Button.ACTION); - expect(handler.optionsContainer.list.length).toBeGreaterThan(0); // should select a pokemon, which has at least the cancel option - - game.phaseInterceptor.unlock(); - }); - - await game.phaseInterceptor.to("SelectModifierPhase"); + expect(handlerLength).toHaveLength(6); // should select 2nd pokemon (length is 5 options + image) }); // Test that the manage button actually discards items, needs proofreading it("should discard items when button is selected", async () => { - game.onNextPrompt("SelectModifierPhase", UiMode.MODIFIER_SELECT, () => { - expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler); + let pokemon: Pokemon | undefined; - const handler = game.scene.ui.getHandler() as ModifierSelectUiHandler; - handler.setCursor(1); - handler.processInput(Button.ACTION); + await new Promise(resolve => { + //select manage items menu + game.onNextPrompt("SelectModifierPhase", UiMode.MODIFIER_SELECT, () => { + const handler = game.scene.ui.getHandler() as ModifierSelectUiHandler; + handler.processInput(Button.DOWN); + handler.setCursor(1); + handler.processInput(Button.ACTION); + }); - void game.scene.ui.setModeWithoutClear(UiMode.PARTY, PartyUiMode.MODIFIER_TRANSFER); + game.onNextPrompt("SelectModifierPhase", UiMode.PARTY, () => { + const handler = game.scene.ui.getHandler() as PartyUiHandler; + + // Enter discard mode and select first party member + handler.setCursor(7); + handler.processInput(Button.ACTION); + handler.setCursor(0); + handler.processInput(Button.ACTION); + pokemon = game.field.getPlayerPokemon(); + + resolve(); + }); }); - await game.phaseInterceptor.to("BattleEndPhase"); - - game.phaseInterceptor.addToNextPrompt("SelectModifierPhase", UiMode.PARTY, () => { - expect(game.scene.ui.getHandler()).toBeInstanceOf(PartyUiHandler); - const handler = game.scene.ui.getHandler() as PartyUiHandler; - - // Enter discard mode and select first party member - handler.setCursor(7); - handler.processInput(Button.ACTION); - handler.setCursor(0); - handler.processInput(Button.ACTION); - const pokemon = game.field.getPlayerPokemon(); - + expect(pokemon).toBeDefined(); + if (pokemon) { expect(pokemon.getHeldItems()).toHaveLength(3); expect(pokemon.getHeldItems().map(h => h.stackCount)).toEqual([1, 2, 2]); + } + await new Promise(resolve => { + //discard the first option + game.onNextPrompt("SelectModifierPhase", UiMode.PARTY, () => { + const handler = game.scene.ui.getHandler() as PartyUiHandler; + handler.processInput(Button.ACTION); + pokemon = game.field.getPlayerPokemon(); + + resolve(); + }); + }); + + expect(pokemon).toBeDefined(); + if (pokemon) { // Sitrus berry was discarded, leaving 2 stacks of 2 berries behind expect(pokemon.getHeldItems()).toHaveLength(2); expect(pokemon.getHeldItems().map(h => h.stackCount)).toEqual([2, 2]); - - game.phaseInterceptor.unlock(); - }); - - await game.phaseInterceptor.to("SelectModifierPhase"); + } }); });