[QoL] Add red color to the quantity if the item is at it's held limit (#2221)

* Add red color to the quantity if the item is at it's held limit

* Add shadow back to option text

* Attempt to fix transfer item crash and add tests for transferring items

* remove .js file extensions from test file imports

* Fix import paths for transfer-item.test
This commit is contained in:
EmberCM 2024-07-05 12:50:19 -05:00 committed by GitHub
parent 759e4d0288
commit 10dd16fa1e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 132 additions and 15 deletions

View File

@ -0,0 +1,100 @@
import { BerryType } from "#app/enums/berry-type";
import { Moves } from "#app/enums/moves";
import { Species } from "#app/enums/species";
import { Button } from "#app/enums/buttons";
import * as overrides from "#app/overrides";
import {
BattleEndPhase,
SelectModifierPhase
} from "#app/phases";
import GameManager from "#app/test/utils/gameManager";
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
import PartyUiHandler, { PartyUiMode } from "#app/ui/party-ui-handler";
import { Mode } from "#app/ui/ui";
import Phaser from "phaser";
import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { getMovePosition } from "../utils/gameManagerUtils";
describe("UI - Transfer Items", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(async () => {
game = new GameManager(phaserGame);
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100);
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(1);
vi.spyOn(overrides, "STARTING_HELD_ITEMS_OVERRIDE", "get").mockReturnValue([
{ name: "BERRY", count: 1, type: BerryType.SITRUS },
{ name: "BERRY", count: 2, type: BerryType.APICOT },
{ name: "BERRY", count: 2, type: BerryType.LUM },
]);
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.DRAGON_CLAW]);
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGIKARP);
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH]);
await game.startBattle([Species.RAYQUAZA, Species.RAYQUAZA, Species.RAYQUAZA]);
game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_CLAW));
game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => {
expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler);
const handler = game.scene.ui.getHandler() as ModifierSelectUiHandler;
handler.setCursor(1);
handler.processInput(Button.ACTION);
game.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.MODIFIER_TRANSFER);
});
await game.phaseInterceptor.to(BattleEndPhase);
});
it("check red tint for held item limit in transfer menu", async () => {
game.onNextPrompt("SelectModifierPhase", Mode.PARTY, () => {
expect(game.scene.ui.getHandler()).toBeInstanceOf(PartyUiHandler);
const handler = game.scene.ui.getHandler() as PartyUiHandler;
handler.processInput(Button.ACTION);
expect(handler.optionsContainer.list.some((option) => (option as BBCodeText).text?.includes("Sitrus Berry"))).toBe(true);
expect(handler.optionsContainer.list.some((option) => (option as BBCodeText).text?.includes("Apicot Berry (2)"))).toBe(true);
expect(handler.optionsContainer.list.some((option) => RegExp(/Lum Berry\[color.*(2)/).exec((option as BBCodeText).text))).toBe(true);
game.phaseInterceptor.unlock();
});
await game.phaseInterceptor.to(SelectModifierPhase);
}, 20000);
it("check transfer option for pokemon to transfer to", async () => {
game.onNextPrompt("SelectModifierPhase", Mode.PARTY, () => {
expect(game.scene.ui.getHandler()).toBeInstanceOf(PartyUiHandler);
const handler = game.scene.ui.getHandler() as PartyUiHandler;
handler.processInput(Button.ACTION); // select Pokemon
handler.processInput(Button.ACTION); // select held item (Sitrus Berry)
handler.setCursor(1); // move to other Pokemon
handler.processInput(Button.ACTION); // select Pokemon
expect(handler.optionsContainer.list.some((option) => (option as BBCodeText).text?.includes("Transfer"))).toBe(true);
game.phaseInterceptor.unlock();
});
await game.phaseInterceptor.to(SelectModifierPhase);
}, 20000);
});

View File

@ -1,12 +1,12 @@
import { CommandPhase, SelectModifierPhase } from "../phases"; import { CommandPhase, SelectModifierPhase } from "../phases";
import BattleScene from "../battle-scene"; import BattleScene from "../battle-scene";
import { PlayerPokemon, PokemonMove } from "../field/pokemon"; import { PlayerPokemon, PokemonMove } from "../field/pokemon";
import { addTextObject, TextStyle } from "./text"; import { addBBCodeTextObject, addTextObject, getTextColor, TextStyle } from "./text";
import { Command } from "./command-ui-handler"; import { Command } from "./command-ui-handler";
import MessageUiHandler from "./message-ui-handler"; import MessageUiHandler from "./message-ui-handler";
import { Mode } from "./ui"; import { Mode } from "./ui";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { PokemonFormChangeItemModifier, PokemonHeldItemModifier, SwitchEffectTransferModifier } from "../modifier/modifier"; import { PokemonBaseStatModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, SwitchEffectTransferModifier } from "../modifier/modifier";
import { allMoves } from "../data/move"; import { allMoves } from "../data/move";
import { getGenderColor, getGenderSymbol } from "../data/gender"; import { getGenderColor, getGenderSymbol } from "../data/gender";
import { StatusEffect } from "../data/status-effect"; import { StatusEffect } from "../data/status-effect";
@ -19,6 +19,7 @@ import {Button} from "#enums/buttons";
import { applyChallenges, ChallengeType } from "#app/data/challenge.js"; import { applyChallenges, ChallengeType } from "#app/data/challenge.js";
import MoveInfoOverlay from "./move-info-overlay"; import MoveInfoOverlay from "./move-info-overlay";
import i18next from "i18next"; import i18next from "i18next";
import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
const defaultMessage = i18next.t("partyUiHandler:choosePokemon"); const defaultMessage = i18next.t("partyUiHandler:choosePokemon");
@ -85,7 +86,8 @@ export default class PartyUiHandler extends MessageUiHandler {
private optionsCursor: integer = 0; private optionsCursor: integer = 0;
private optionsScrollCursor: integer = 0; private optionsScrollCursor: integer = 0;
private optionsScrollTotal: integer = 0; private optionsScrollTotal: integer = 0;
private optionsContainer: Phaser.GameObjects.Container; /** This is only public for test/ui/transfer-item.test.ts */
public optionsContainer: Phaser.GameObjects.Container;
private optionsBg: Phaser.GameObjects.NineSlice; private optionsBg: Phaser.GameObjects.NineSlice;
private optionsCursorObj: Phaser.GameObjects.Image; private optionsCursorObj: Phaser.GameObjects.Image;
private options: integer[]; private options: integer[];
@ -819,7 +821,7 @@ export default class PartyUiHandler extends MessageUiHandler {
optionEndIndex = this.options.length; optionEndIndex = this.options.length;
let widestOptionWidth = 0; let widestOptionWidth = 0;
const optionTexts: Phaser.GameObjects.Text[] = []; const optionTexts: BBCodeText[] = [];
for (let o = optionStartIndex; o < optionEndIndex; o++) { for (let o = optionStartIndex; o < optionEndIndex; o++) {
const option = this.options[this.options.length - (o + 1)]; const option = this.options[this.options.length - (o + 1)];
@ -861,27 +863,42 @@ export default class PartyUiHandler extends MessageUiHandler {
const move = learnableLevelMoves[option]; const move = learnableLevelMoves[option];
optionName = allMoves[move].name; optionName = allMoves[move].name;
altText = !pokemon.getSpeciesForm().getLevelMoves().find(plm => plm[1] === move); altText = !pokemon.getSpeciesForm().getLevelMoves().find(plm => plm[1] === move);
} else if (option === PartyOption.ALL) {
optionName = i18next.t("partyUiHandler:ALL");
} else { } else {
if (option === PartyOption.ALL) { const itemModifier = itemModifiers[option];
optionName = i18next.t("partyUiHandler:ALL"); optionName = itemModifier.type.name;
} else {
const itemModifier = itemModifiers[option];
optionName = itemModifier.type.name;
/** For every item that has stack bigger than 1, display the current quantity selection */
if (this.transferQuantitiesMax[option] > 1) {
optionName += ` (${this.transferQuantities[option]})`;
}
}
} }
const yCoord = -6 - 16 * o; const yCoord = -6 - 16 * o;
const optionText = addTextObject(this.scene, 0, yCoord - 16, optionName, TextStyle.WINDOW); const optionText = addBBCodeTextObject(this.scene, 0, yCoord - 16, optionName, TextStyle.WINDOW, { maxLines: 1 });
if (altText) { if (altText) {
optionText.setColor("#40c8f8"); optionText.setColor("#40c8f8");
optionText.setShadowColor("#006090"); optionText.setShadowColor("#006090");
} }
optionText.setOrigin(0, 0); optionText.setOrigin(0, 0);
/** For every item that has stack bigger than 1, display the current quantity selection */
if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER && this.transferQuantitiesMax[option] > 1) {
const itemModifier = itemModifiers[option];
/** Not sure why getMaxHeldItemCount had an error, but it only checks the Pokemon parameter if the modifier is PokemonBaseStatModifier */
if (itemModifier === undefined || itemModifier instanceof PokemonBaseStatModifier) {
continue;
}
let amountText = ` (${this.transferQuantities[option]})`;
/** If the amount held is the maximum, display the count in red */
if (this.transferQuantitiesMax[option] === itemModifier.getMaxHeldItemCount(undefined)) {
amountText = `[color=${getTextColor(TextStyle.SUMMARY_RED)}]${amountText}[/color]`;
}
optionText.setText(optionName + amountText);
}
optionText.setText(`[shadow]${optionText.text}[/shadow]`);
optionTexts.push(optionText); optionTexts.push(optionText);
widestOptionWidth = Math.max(optionText.displayWidth, widestOptionWidth); widestOptionWidth = Math.max(optionText.displayWidth, widestOptionWidth);