[ui] add background overlay during tutorials

This commit is contained in:
MokaStitcher 2024-09-15 23:07:01 +02:00
parent f7b8cf7256
commit 256cc56daf
7 changed files with 110 additions and 25 deletions

View File

@ -70,6 +70,8 @@ class DefaultOverrides {
[PokeballType.MASTER_BALL]: 0,
},
};
/** Set to true to show all tutorials */
readonly BYPASS_TUTORIAL_SKIP: boolean = false;
// ----------------
// PLAYER OVERRIDES

View File

@ -1,7 +1,9 @@
import BattleScene from "./battle-scene";
import AwaitableUiHandler from "./ui/awaitable-ui-handler";
import UiHandler from "./ui/ui-handler";
import { Mode } from "./ui/ui";
import i18next from "i18next";
import Overrides from "#app/overrides";
export enum Tutorial {
Intro = "INTRO",
@ -39,7 +41,7 @@ const tutorialHandlers = {
scene.ui.showText(i18next.t("tutorial:starterSelect"), null, () => scene.ui.showText("", null, () => resolve()), null, true);
});
},
[Tutorial.Pokerus]: (scene: BattleScene) => {
[Tutorial.Pokerus]: (scene: BattleScene) => {
return new Promise<void>(resolve => {
scene.ui.showText(i18next.t("tutorial:pokerus"), null, () => scene.ui.showText("", null, () => resolve()), null, true);
});
@ -63,26 +65,79 @@ const tutorialHandlers = {
},
};
export function handleTutorial(scene: BattleScene, tutorial: Tutorial): Promise<boolean> {
return new Promise<boolean>(resolve => {
if (!scene.enableTutorials) {
return resolve(false);
}
export async function handleTutorial(scene: BattleScene, tutorial: Tutorial): Promise<boolean> {
if (!scene.enableTutorials && !Overrides.BYPASS_TUTORIAL_SKIP) {
return false;
}
if (scene.gameData.getTutorialFlags()[tutorial]) {
return resolve(false);
}
if (scene.gameData.getTutorialFlags()[tutorial] && !Overrides.BYPASS_TUTORIAL_SKIP) {
return false;
}
const handler = scene.ui.getHandler();
if (handler instanceof AwaitableUiHandler) {
handler.tutorialActive = true;
}
tutorialHandlers[tutorial](scene).then(() => {
scene.gameData.saveTutorialFlag(tutorial, true);
if (handler instanceof AwaitableUiHandler) {
handler.tutorialActive = false;
}
resolve(true);
});
});
const handler = scene.ui.getHandler();
const isMenuDisabled = scene.disableMenu;
// starting tutorial, disable menu
scene.disableMenu = true;
if (handler instanceof AwaitableUiHandler) {
handler.tutorialActive = true;
}
await showTutorialOverlay(scene, handler);
await tutorialHandlers[tutorial](scene);
await hideTutorialOverlay(scene, handler);
// tutorial finished and overlay gone, re-enable menu, save tutorial as seen
scene.disableMenu = isMenuDisabled;
scene.gameData.saveTutorialFlag(tutorial, true);
if (handler instanceof AwaitableUiHandler) {
handler.tutorialActive = false;
}
return true;
}
/**
* Show the tutorial overlay if there is one
* @param scene the current BattleScene
* @param handler the current UiHandler
* @returns true once the overlay has finished appearing, or if there is no overlay
*/
async function showTutorialOverlay(scene: BattleScene, handler: UiHandler) {
if (handler instanceof AwaitableUiHandler && handler.tutorialOverlay) {
scene.tweens.add({
targets: handler.tutorialOverlay,
alpha: 0.5,
duration: 750,
ease: "Sine.easeOut",
onComplete: () => {
return true;
}
});
} else {
return true;
}
}
/**
* Hide the tutorial overlay if there is one
* @param scene the current BattleScene
* @param handler the current UiHandler
* @returns true once the overlay has finished disappearing, or if there is no overlay
*/
async function hideTutorialOverlay(scene: BattleScene, handler: UiHandler) {
if (handler instanceof AwaitableUiHandler && handler.tutorialOverlay) {
scene.tweens.add({
targets: handler.tutorialOverlay,
alpha: 0,
duration: 500,
ease: "Sine.easeOut",
onComplete: () => {
return true;
}
});
} else {
return true;
}
}

View File

@ -7,6 +7,7 @@ export default abstract class AwaitableUiHandler extends UiHandler {
protected awaitingActionInput: boolean;
protected onActionInput: Function | null;
public tutorialActive: boolean = false;
public tutorialOverlay: Phaser.GameObjects.Rectangle;
constructor(scene: BattleScene, mode: Mode | null = null) {
super(scene, mode);
@ -24,4 +25,21 @@ export default abstract class AwaitableUiHandler extends UiHandler {
return false;
}
/**
* Create a semi transparent overlay that will get shown during tutorials
* @param container the container to add the overlay to
*/
initTutorialOverlay(container: Phaser.GameObjects.Container) {
if (!this.tutorialOverlay) {
this.tutorialOverlay = new Phaser.GameObjects.Rectangle(this.scene, -1, -1, this.scene.scaledCanvas.width, this.scene.scaledCanvas.height, 0x070707);
this.tutorialOverlay.setName("tutorial-overlay");
this.tutorialOverlay.setOrigin(0, 0);
this.tutorialOverlay.setAlpha(0);
}
if (container) {
container.add(this.tutorialOverlay);
}
}
}

View File

@ -287,7 +287,6 @@ export default class EggGachaUiHandler extends MessageUiHandler {
this.eggGachaContainer.add(this.eggGachaSummaryContainer);
const gachaMessageBoxContainer = this.scene.add.container(0, 148);
this.eggGachaContainer.add(gachaMessageBoxContainer);
const gachaMessageBox = addWindow(this.scene, 0, 0, 320, 32);
gachaMessageBox.setOrigin(0, 0);
@ -301,6 +300,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
this.message = gachaMessageText;
this.initTutorialOverlay(this.eggGachaContainer);
this.eggGachaContainer.add(gachaMessageBoxContainer);
this.initPromptSprite(gachaMessageBoxContainer);

View File

@ -157,6 +157,7 @@ export default class MenuUiHandler extends MessageUiHandler {
menuMessageText.setOrigin(0, 0);
this.menuMessageBoxContainer.add(menuMessageText);
this.initTutorialOverlay(this.menuContainer);
this.initPromptSprite(this.menuMessageBoxContainer);
this.message = menuMessageText;
@ -435,6 +436,9 @@ export default class MenuUiHandler extends MessageUiHandler {
this.scene.playSound("ui/menu_open");
// Make sure the tutorial overlay sits above everything, but below the message box
this.menuContainer.bringToTop(this.tutorialOverlay);
this.menuContainer.bringToTop(this.menuMessageBoxContainer);
handleTutorial(this.scene, Tutorial.Menu);
this.bgmBar.toggleBgmBar(true);

View File

@ -22,14 +22,16 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
* @param container the container to add the sprite to
*/
initPromptSprite(container: Phaser.GameObjects.Container) {
if (container && !this.prompt) {
if (!this.prompt) {
const promptSprite = this.scene.add.sprite(0, 0, "prompt");
promptSprite.setVisible(false);
promptSprite.setOrigin(0, 0);
container.add(promptSprite);
this.prompt = promptSprite;
}
if (container) {
container.add(this.prompt);
}
}
showText(text: string, delay?: integer | null, callback?: Function | null, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null) {

View File

@ -914,7 +914,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
y: this.scene.game.canvas.height / 6 - MoveInfoOverlay.getHeight(overlayScale) - 29,
});
this.starterSelectContainer.add(this.moveInfoOverlay);
// Filter bar sits above everything, except the tutorial overlay and message box
this.starterSelectContainer.bringToTop(this.filterBarContainer);
this.initTutorialOverlay(this.starterSelectContainer);
this.starterSelectContainer.bringToTop(this.starterSelectMessageBoxContainer);
this.scene.eventTarget.addEventListener(BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED, (e) => this.onCandyUpgradeDisplayChanged(e));