[UI][Misc] Force users to have an active challenge (#3953)

* I hope this is good enough

* renamed variable to better name

* Remove random newline

* When player is ready cool box

* Fixed cancel behavior

* standardized action/cancel behavior

* Added comments

---------

Co-authored-by: frutescens <info@laptop>
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
This commit is contained in:
Mumble 2024-09-01 21:32:22 -07:00 committed by GitHub
parent 84ef7f0683
commit 0cbdaab28e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 101 additions and 81 deletions

View File

@ -1,6 +1,7 @@
{
"title": "Challenge Modifiers",
"illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!",
"noneSelected": "None Selected",
"singleGeneration": {
"name": "Mono Gen",
"desc": "You can only use Pokémon from Generation {{gen}}.",

View File

@ -5,13 +5,13 @@ import UiHandler from "./ui-handler";
import { addWindow } from "./ui-theme";
import {Button} from "#enums/buttons";
import i18next from "i18next";
import { Challenge } from "#app/data/challenge.js";
import { Challenge } from "#app/data/challenge";
import * as Utils from "../utils";
import { Challenges } from "#app/enums/challenges.js";
import { Challenges } from "#app/enums/challenges";
import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
import { Color, ShadowColor } from "#app/enums/color.js";
import { SelectStarterPhase } from "#app/phases/select-starter-phase.js";
import { TitlePhase } from "#app/phases/title-phase.js";
import { Color, ShadowColor } from "#app/enums/color";
import { SelectStarterPhase } from "#app/phases/select-starter-phase";
import { TitlePhase } from "#app/phases/title-phase";
/**
* Handles all the UI for choosing optional challenges.
@ -33,7 +33,10 @@ export default class GameChallengesUiHandler extends UiHandler {
private cursorObj: Phaser.GameObjects.NineSlice | null;
private startBg: Phaser.GameObjects.NineSlice;
private startCursor: Phaser.GameObjects.NineSlice;
private startText: Phaser.GameObjects.Text;
private hasSelectedChallenge: boolean;
private optionsWidth: number;
@ -104,20 +107,20 @@ export default class GameChallengesUiHandler extends UiHandler {
this.descriptionText.setShadow(4, 5, ShadowColor.ORANGE);
this.descriptionText.setOrigin(0, 0);
const startBg = addWindow(this.scene, 0, 0, descriptionBg.width, 24);
startBg.setName("window-start-bg");
startBg.setOrigin(0, 0);
startBg.setPositionRelative(descriptionBg, 0, descriptionBg.height);
this.startBg = addWindow(this.scene, 0, 0, descriptionBg.width, 24);
this.startBg.setName("window-start-bg");
this.startBg.setOrigin(0, 0);
this.startBg.setPositionRelative(descriptionBg, 0, descriptionBg.height);
const startText = addTextObject(this.scene, 0, 0, i18next.t("common:start"), TextStyle.SETTINGS_LABEL);
startText.setName("text-start");
startText.setOrigin(0, 0);
startText.setPositionRelative(startBg, (startBg.width - startText.displayWidth) / 2, 4);
this.startText = addTextObject(this.scene, 0, 0, i18next.t("challenges:noneSelected"), TextStyle.SETTINGS_LABEL);
this.startText.setName("text-start");
this.startText.setOrigin(0, 0);
this.startText.setPositionRelative(this.startBg, (this.startBg.width - this.startText.displayWidth) / 2, 4);
this.startCursor = this.scene.add.nineslice(0, 0, "summary_moves_cursor", undefined, descriptionBg.width - 8, 16, 1, 1, 1, 1);
this.startCursor.setName("9s-start-cursor");
this.startCursor.setOrigin(0, 0);
this.startCursor.setPositionRelative(startBg, 4, 3);
this.startCursor.setPositionRelative(this.startBg, 4, 3);
this.startCursor.setVisible(false);
this.valuesContainer = this.scene.add.container(0, 0);
@ -157,8 +160,8 @@ export default class GameChallengesUiHandler extends UiHandler {
this.challengesContainer.add(this.optionsBg);
this.challengesContainer.add(descriptionBg);
this.challengesContainer.add(this.descriptionText);
this.challengesContainer.add(startBg);
this.challengesContainer.add(startText);
this.challengesContainer.add(this.startBg);
this.challengesContainer.add(this.startText);
this.challengesContainer.add(this.startCursor);
this.challengesContainer.add(this.valuesContainer);
@ -216,6 +219,21 @@ export default class GameChallengesUiHandler extends UiHandler {
this.monoTypeValue.setVisible(false);
}
// This checks if a challenge has been selected by the user and updates the text/its opacity accordingly.
this.hasSelectedChallenge = this.scene.gameMode.challenges.some(c => c.value !== 0);
if (this.hasSelectedChallenge) {
this.startText.setText(i18next.t("common:start"));
this.startText.setAlpha(1);
this.startText.setPositionRelative(this.startBg, (this.startBg.width - this.startText.displayWidth) / 2, 4);
} else {
this.startText.setText(i18next.t("challenges:noneSelected"));
this.startText.setAlpha(0.5);
this.startText.setPositionRelative(this.startBg, (this.startBg.width - this.startText.displayWidth) / 2, 4);
}
this.challengesContainer.update();
// const totalDifficulty = this.scene.gameMode.challenges.reduce((v, c) => v + c.getDifficulty(), 0);
// const totalMinDifficulty = this.scene.gameMode.challenges.reduce((v, c) => v + c.getMinDifficulty(), 0);
// this.difficultyText.text = `${totalDifficulty}` + (totalMinDifficulty ? `/${totalMinDifficulty}` : "");
@ -227,6 +245,8 @@ export default class GameChallengesUiHandler extends UiHandler {
this.startCursor.setVisible(false);
this.challengesContainer.setVisible(true);
// Should always be false at the start
this.hasSelectedChallenge = this.scene.gameMode.challenges.some(c => c.value !== 0);
this.setCursor(0);
this.initLabels();
@ -257,6 +277,7 @@ export default class GameChallengesUiHandler extends UiHandler {
if (button === Button.CANCEL) {
if (this.startCursor.visible) {
// If the user presses cancel when the start cursor has been activated, the game deactivates the start cursor and allows typical challenge selection behavior
this.startCursor.setVisible(false);
this.cursorObj?.setVisible(true);
} else {
@ -266,83 +287,82 @@ export default class GameChallengesUiHandler extends UiHandler {
}
success = true;
} else if (button === Button.SUBMIT || button === Button.ACTION) {
if (this.startCursor.visible) {
const totalDifficulty = this.scene.gameMode.challenges.reduce((v, c) => v + c.getDifficulty(), 0);
const totalMinDifficulty = this.scene.gameMode.challenges.reduce((v, c) => v + c.getMinDifficulty(), 0);
if (totalDifficulty >= totalMinDifficulty) {
if (this.hasSelectedChallenge) {
if (this.startCursor.visible) {
this.scene.unshiftPhase(new SelectStarterPhase(this.scene));
this.scene.getCurrentPhase()?.end();
success = true;
} else {
success = false;
this.startCursor.setVisible(true);
this.cursorObj?.setVisible(false);
}
} else {
this.startCursor.setVisible(true);
this.cursorObj?.setVisible(false);
success = true;
} else {
success = false;
}
} else {
switch (button) {
case Button.UP:
if (this.cursor === 0) {
if (this.scrollCursor === 0) {
// When at the top of the menu and pressing UP, move to the bottommost item.
if (this.scene.gameMode.challenges.length > rowsToDisplay) { // If there are more than 9 challenges, scroll to the bottom
// First, set the cursor to the last visible element, preparing for the scroll to the end.
const successA = this.setCursor(rowsToDisplay - 1);
// Then, adjust the scroll to display the bottommost elements of the menu.
const successB = this.setScrollCursor(this.scene.gameMode.challenges.length - rowsToDisplay);
success = successA && successB; // success is just there to play the little validation sound effect
} else { // If there are 9 or less challenges, just move to the bottom one
success = this.setCursor(this.scene.gameMode.challenges.length - 1);
if (this.cursorObj?.visible && !this.startCursor.visible) {
switch (button) {
case Button.UP:
if (this.cursor === 0) {
if (this.scrollCursor === 0) {
// When at the top of the menu and pressing UP, move to the bottommost item.
if (this.scene.gameMode.challenges.length > rowsToDisplay) { // If there are more than 9 challenges, scroll to the bottom
// First, set the cursor to the last visible element, preparing for the scroll to the end.
const successA = this.setCursor(rowsToDisplay - 1);
// Then, adjust the scroll to display the bottommost elements of the menu.
const successB = this.setScrollCursor(this.scene.gameMode.challenges.length - rowsToDisplay);
success = successA && successB; // success is just there to play the little validation sound effect
} else { // If there are 9 or less challenges, just move to the bottom one
success = this.setCursor(this.scene.gameMode.challenges.length - 1);
}
} else {
success = this.setScrollCursor(this.scrollCursor - 1);
}
} else {
success = this.setScrollCursor(this.scrollCursor - 1);
success = this.setCursor(this.cursor - 1);
}
} else {
success = this.setCursor(this.cursor - 1);
}
if (success) {
this.updateText();
}
break;
case Button.DOWN:
if (this.cursor === rowsToDisplay - 1) {
if (this.scrollCursor < this.scene.gameMode.challenges.length - rowsToDisplay) {
// When at the bottom and pressing DOWN, scroll if possible.
success = this.setScrollCursor(this.scrollCursor + 1);
if (success) {
this.updateText();
}
break;
case Button.DOWN:
if (this.cursor === rowsToDisplay - 1) {
if (this.scrollCursor < this.scene.gameMode.challenges.length - rowsToDisplay) {
// When at the bottom and pressing DOWN, scroll if possible.
success = this.setScrollCursor(this.scrollCursor + 1);
} else {
// When at the bottom of a scrolling menu and pressing DOWN, move to the topmost item.
// First, set the cursor to the first visible element, preparing for the scroll to the top.
const successA = this.setCursor(0);
// Then, adjust the scroll to display the topmost elements of the menu.
const successB = this.setScrollCursor(0);
success = successA && successB; // success is just there to play the little validation sound effect
}
} else if (this.scene.gameMode.challenges.length < rowsToDisplay && this.cursor === this.scene.gameMode.challenges.length - 1) {
// When at the bottom of a non-scrolling menu and pressing DOWN, move to the topmost item.
success = this.setCursor(0);
} else {
// When at the bottom of a scrolling menu and pressing DOWN, move to the topmost item.
// First, set the cursor to the first visible element, preparing for the scroll to the top.
const successA = this.setCursor(0);
// Then, adjust the scroll to display the topmost elements of the menu.
const successB = this.setScrollCursor(0);
success = successA && successB; // success is just there to play the little validation sound effect
success = this.setCursor(this.cursor + 1);
}
} else if (this.scene.gameMode.challenges.length < rowsToDisplay && this.cursor === this.scene.gameMode.challenges.length - 1) {
// When at the bottom of a non-scrolling menu and pressing DOWN, move to the topmost item.
success = this.setCursor(0);
} else {
success = this.setCursor(this.cursor + 1);
if (success) {
this.updateText();
}
break;
case Button.LEFT:
// Moves the option cursor left, if possible.
success = this.getActiveChallenge().decreaseValue();
if (success) {
this.updateText();
}
break;
case Button.RIGHT:
// Moves the option cursor right, if possible.
success = this.getActiveChallenge().increaseValue();
if (success) {
this.updateText();
}
break;
}
if (success) {
this.updateText();
}
break;
case Button.LEFT:
// Moves the option cursor left, if possible.
success = this.getActiveChallenge().decreaseValue();
if (success) {
this.updateText();
}
break;
case Button.RIGHT:
// Moves the option cursor right, if possible.
success = this.getActiveChallenge().increaseValue();
if (success) {
this.updateText();
}
break;
}
}
@ -350,7 +370,6 @@ export default class GameChallengesUiHandler extends UiHandler {
if (success) {
ui.playSelect();
}
return success;
}