pokerogue/src/ui/time-of-day-widget.ts
Sirz Benjie 5854b21da0
[Refactor] Remove circular imports part 1 (#5663)
* Extract Mode enum out of UI and into its own file

Reduces circular imports from 909 to 773

* Move around utility files

Reduces cyclical dependencies from 773 to 765

* Remove starterColors and bypassLogin from battle-scene

Reduces cyclical dependencies from 765 to 623

* Fix test runner error

* Update import for bypassLogin in test

* Update mocks for utils in tests

* Fix broken tests

* Update selectWithTera override

* Update path for utils in ab-attr.ts

* Update path for utils in ability-class.ts

* Fix utils import path in healer.test.ts
2025-04-19 11:57:03 +00:00

170 lines
6.1 KiB
TypeScript

import { fixedInt } from "#app/utils/common";
import { globalScene } from "#app/global-scene";
import { BattleSceneEventType } from "../events/battle-scene";
import { EaseType } from "#enums/ease-type";
import { TimeOfDay } from "#enums/time-of-day";
/** A small self contained UI element that displays the time of day as an icon */
export default class TimeOfDayWidget extends Phaser.GameObjects.Container {
/** The {@linkcode Phaser.GameObjects.Sprite} that represents the foreground of the current time of day */
private readonly timeOfDayIconFgs: Phaser.GameObjects.Sprite[] = new Array(2);
/** The {@linkcode Phaser.GameObjects.Sprite} that represents the middle-ground of the current time of day */
private readonly timeOfDayIconMgs: Phaser.GameObjects.Sprite[] = new Array(2);
/** The {@linkcode Phaser.GameObjects.Sprite} that represents the background of the current time of day */
private readonly timeOfDayIconBgs: Phaser.GameObjects.Sprite[] = new Array(2);
/** An array containing all timeOfDayIcon objects for easier iteration */
private timeOfDayIcons: Phaser.GameObjects.Sprite[];
/** A map containing all timeOfDayIcon arrays with a matching string key for easier iteration */
private timeOfDayIconPairs: Map<string, Phaser.GameObjects.Sprite[]> = new Map([
["bg", this.timeOfDayIconBgs],
["mg", this.timeOfDayIconMgs],
["fg", this.timeOfDayIconFgs],
]);
/** The current time of day */
private currentTime: TimeOfDay = TimeOfDay.ALL;
/** The previous time of day */
private previousTime: TimeOfDay = TimeOfDay.ALL;
// Subscribes to required events available on game start
private readonly onEncounterPhaseEvent = (event: Event) => this.onEncounterPhase(event);
private _parentVisible: boolean;
/** Is the parent object visible? */
public get parentVisible(): boolean {
return this._parentVisible;
}
/** On set, resumes any paused tweens if true */
public set parentVisible(visible: boolean) {
if (visible && !this._parentVisible) {
// Only resume the tweens if parent is newly visible
this.timeOfDayIcons?.forEach(icon => globalScene.tweens.getTweensOf(icon).forEach(tween => tween.resume()));
}
this._parentVisible = visible;
}
constructor(x = 0, y = 0) {
super(globalScene, x, y);
this.setVisible(globalScene.showTimeOfDayWidget);
if (!globalScene.showTimeOfDayWidget) {
return;
}
// Initialize all sprites
this.timeOfDayIconPairs.forEach((icons, key) => {
for (let i = 0; i < icons.length; i++) {
icons[i] = globalScene.add.sprite(0, 0, "dawn_icon_" + key).setOrigin();
}
});
// Store a flat array of all icons for later
this.timeOfDayIcons = [this.timeOfDayIconBgs, this.timeOfDayIconMgs, this.timeOfDayIconFgs].flat();
this.add(this.timeOfDayIcons);
globalScene.eventTarget.addEventListener(BattleSceneEventType.ENCOUNTER_PHASE, this.onEncounterPhaseEvent);
}
/**
* Creates a tween animation based on the 'Back' ease algorithm
* @returns an array of all tweens in the animation
*/
private getBackTween(): Phaser.Types.Tweens.TweenBuilderConfig[] {
const rotate = {
targets: [this.timeOfDayIconMgs[0], this.timeOfDayIconMgs[1]],
angle: "+=90",
duration: fixedInt(1500),
ease: "Back.easeOut",
paused: !this.parentVisible,
};
const fade = {
targets: [this.timeOfDayIconBgs[1], this.timeOfDayIconMgs[1], this.timeOfDayIconFgs[1]],
alpha: 0,
duration: fixedInt(500),
ease: "Linear",
paused: !this.parentVisible,
};
return [rotate, fade];
}
/**
* Creates a tween animation based on the 'Bounce' ease algorithm
* @returns an array of all tweens in the animation
*/
private getBounceTween(): Phaser.Types.Tweens.TweenBuilderConfig[] {
const bounce = {
targets: [this.timeOfDayIconMgs[0], this.timeOfDayIconMgs[1]],
angle: "+=90",
duration: fixedInt(2000),
ease: "Bounce.easeOut",
paused: !this.parentVisible,
};
const fade = {
targets: [this.timeOfDayIconBgs[1], this.timeOfDayIconMgs[1], this.timeOfDayIconFgs[1]],
alpha: 0,
duration: fixedInt(800),
ease: "Linear",
paused: !this.parentVisible,
};
return [bounce, fade];
}
/** Resets all icons to the proper depth, texture, and alpha so they are ready to tween */
private resetIcons() {
this.moveBelow(this.timeOfDayIconBgs[0], this.timeOfDayIconBgs[1]);
this.moveBelow(this.timeOfDayIconMgs[0], this.timeOfDayIconBgs[1]);
this.moveBelow(this.timeOfDayIconFgs[0], this.timeOfDayIconFgs[1]);
this.timeOfDayIconPairs.forEach((icons, key) => {
icons[0].setTexture(TimeOfDay[this.currentTime].toLowerCase() + "_icon_" + key);
icons[1].setTexture(TimeOfDay[this.previousTime].toLowerCase() + "_icon_" + key);
});
this.timeOfDayIconMgs[0].setRotation(-90 * (3.14 / 180));
this.timeOfDayIcons.forEach(icon => icon.setAlpha(1));
}
/** Adds the proper tween for all icons */
private tweenTimeOfDayIcon() {
globalScene.tweens.killTweensOf(this.timeOfDayIcons);
this.resetIcons();
// Tween based on the player setting
(globalScene.timeOfDayAnimation === EaseType.BACK ? this.getBackTween() : this.getBounceTween()).forEach(tween =>
globalScene.tweens.add(tween),
);
// Swaps all elements of the icon arrays by shifting the first element onto the end of the array
// This ensures index[0] is always the new time of day icon and index[1] is always the current one
this.timeOfDayIconPairs.forEach(icons => {
const shifted = icons.shift();
shifted && icons.push(shifted);
});
}
/**
* Grabs the current time of day from the arena and calls {@linkcode tweenTimeOfDayIcon}
* @param _event {@linkcode Event} being sent
*/
private onEncounterPhase(_event: Event) {
const newTime = globalScene.arena.getTimeOfDay();
if (this.currentTime === newTime) {
return;
}
this.currentTime = newTime;
this.previousTime = this.currentTime - 1;
if (this.previousTime < TimeOfDay.DAWN) {
this.previousTime = TimeOfDay.NIGHT;
}
this.tweenTimeOfDayIcon();
}
}