Compare commits

...

14 Commits

Author SHA1 Message Date
Frederico Santos
31a11e08bb
Merge pull request #3743 from pagefaultgames/main
Main to Beta sync
2024-08-25 02:36:41 +01:00
Frederico Santos
2c4f02098f chore: Fix import formatting in ui.ts file 2024-08-25 02:35:16 +01:00
Frederico Santos
f6fd091d9b
Doc update (#3742)
* Update feature_request.yml

Fix auto labels

* add CODEOWNERS file

* Update CODEOWNERS

* Update pull_request_template.md

---------

Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>
2024-08-25 02:09:29 +01:00
Mumble
c7184558c2
[Enhancement][UI] Merging Achievements and Vouchers into a single Page (#3424)
* Merging Achievements/Vouchers

* Fixed bug

* Fixed bug

* Removed vouchers-ui-handler.ts

* fixed update bug

* sample localization change

* Fixing imports

* Organized localizations

* Not a Cat commit unless something's forgotten

* Made Action button/text position responsive to language.

* typedocs

* idk why phaser

* ugh

* Fixed cursors

* why

* Removing stray file

* Merge conflicts yay

---------

Co-authored-by: Frutescens <info@laptop>
2024-08-25 00:36:18 +01:00
Mumble
f6551efc36
[Bug] Run History Day 1 patch (#3715)
* Money Display Fix + Partially localized import data

* Fixed Japanese text.

---------

Co-authored-by: frutescens <info@laptop>
2024-08-25 00:03:28 +01:00
Dakurei
9bcbc66db0
Change background-color to black if display-mode is fullscreen (#1605)
+ fullscreen which is the mode defined in manifest.webmanifest
2024-08-24 23:56:50 +01:00
MokaStitcher
1e4b3a45dd
[QoL] Add arrows in the Stats screen to show it is scrollable (#3489)
* [qol] add animated arrows in the Stats screen to show that the list is scrollable

* make legacy theme checks more explicit

* add some documentation + code cleanup
2024-08-24 23:56:35 +01:00
雪霁
872f05d2a7
centralize module typing overrides (#1786)
* optimize typings with declaration file
2024-08-24 12:46:16 -07:00
Madmadness65
d15c01378d Minor filename correction
Misspelled "forme".
2024-08-24 13:15:41 -05:00
Madmadness65
208aaf11cd
Add battle music for Legendary Pokémon forms (#3723) 2024-08-24 13:07:11 -05:00
Frederico Santos
0df40893b2 Add modeChain to gameInfo for debug purposes 2024-08-24 17:59:41 +01:00
Frederico Santos
2d0cf54a7f revert modechain debug info 2024-08-24 17:47:21 +01:00
Frederico Santos
38d4a594a0 revert fix 2024-08-24 17:44:36 +01:00
Frederico Santos
0f6170b3f7 GetModeChain in window.gameInfo for prod debugging 2024-08-24 17:42:20 +01:00
31 changed files with 393 additions and 460 deletions

45
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,45 @@
# Order is important; the last matching pattern takes the most precedence.
# everything (whole code-base) - Junior Devs
* @pagefaultgames/junior-dev-team
# github actions/templates etc. - Dev Leads
/.github @pagefaultgames/dev-leads
# --- Translations ---
# all translations - Translation Leads
/src/locales @pagefaultgames/translation-leads
# Catalan (Spain/Spanish)
/src/locales/ca_ES @pagefaultgames/catalan-translation-team
# German
/src/locales/de @pagefaultgames/german-translation-team
# English
/src/locales/en @pagefaultgames/english-translation-team
# Spanish
/src/locales/es @pagefaultgames/spanish-translation-team
# French
/src/locales/fr @pagefaultgames/french-translation-team
# Italian
/src/locales/it @pagefaultgames/italian-translation-team
# Japenese
/src/locales/ja @pagefaultgames/japanese-translation-team
# Korean
/src/locales/ko @pagefaultgames/korean-translation-team
# Brasilian (Brasil/Portuguese)
/src/locales/pt_BR @pagefaultgames/portuguese_br-translation-team
# Chinese (simplified)
/src/locales/zh_CN @pagefaultgames/chinese_simplified-translation-team
# Chinese (traditional)
/src/locales/zh_TW @pagefaultgames/chinese_traditional-translation-team

View File

@ -1,7 +1,7 @@
name: Feature Request
description: Suggest an idea for this project
title: "[Feature] "
labels: ["enhancement"]
labels: ["Enhancement"]
body:
- type: markdown
attributes:

View File

@ -30,7 +30,7 @@
- [ ] The PR is self-contained and cannot be split into smaller PRs?
- [ ] Have I provided a clear explanation of the changes?
- [ ] Have I considered writing automated tests for the issue?
- [ ] If I have text, did I add placeholders for them in locales?
- [ ] If I have text, did I add make it translatable and added a key in the English language?
- [ ] Have I tested the changes (manually)?
- [ ] Are all unit tests still passing? (`npm run test`)
- [ ] Are the changes visual?

View File

@ -53,6 +53,7 @@ Check out [Github Issues](https://github.com/pagefaultgames/pokerogue/issues) to
- Pokémon Sun/Moon
- Pokémon Ultra Sun/Ultra Moon
- Pokémon Sword/Shield
- Pokémon Legends: Arceus
- Pokémon Scarlet/Violet
- Firel (Custom Laboratory, Metropolis, Seabed, and Space biome music)
- Lmz (Custom Jungle biome music)

View File

@ -17,6 +17,12 @@ body {
background: #484050;
}
@media (display-mode: fullscreen) {
body {
background: #000000;
}
}
#links {
width: 90%;
text-align: center;

Binary file not shown.

Binary file not shown.

View File

@ -49,8 +49,8 @@ import CandyBar from "./ui/candy-bar";
import { Variant, variantData } from "./data/variant";
import { Localizable } from "#app/interfaces/locales";
import Overrides from "#app/overrides";
import {InputsController} from "./inputs-controller";
import {UiInputs} from "./ui-inputs";
import { InputsController } from "./inputs-controller";
import { UiInputs } from "./ui-inputs";
import { NewArenaEvent } from "./events/battle-scene";
import { ArenaFlyout } from "./ui/arena-flyout";
import { EaseType } from "#enums/ease-type";
@ -65,7 +65,7 @@ import { Species } from "#enums/species";
import { UiTheme } from "#enums/ui-theme";
import { TimedEventManager } from "#app/timed-event-manager.js";
import i18next from "i18next";
import {TrainerType} from "#enums/trainer-type";
import { TrainerType } from "#enums/trainer-type";
import { battleSpecDialogue } from "./data/dialogue";
import { LoadingScene } from "./loading-scene";
import { LevelCapPhase } from "./phases/level-cap-phase";
@ -1897,6 +1897,8 @@ export default class BattleScene extends SceneBase {
return 22.770;
case "battle_legendary_dia_pal": //ORAS Dialga & Palkia Battle
return 16.009;
case "battle_legendary_origin_forme": //LA Origin Dialga & Palkia Battle
return 18.961;
case "battle_legendary_giratina": //ORAS Giratina Battle
return 10.451;
case "battle_legendary_arceus": //HGSS Arceus Battle
@ -1925,6 +1927,8 @@ export default class BattleScene extends SceneBase {
return 12.503;
case "battle_legendary_calyrex": //SWSH Calyrex Battle
return 50.641;
case "battle_legendary_riders": //SWSH Ice & Shadow Rider Calyrex Battle
return 18.155;
case "battle_legendary_birds_galar": //SWSH Galarian Legendary Birds Battle
return 0.175;
case "battle_legendary_ruinous": //SV Treasures of Ruin Battle
@ -2668,7 +2672,8 @@ export default class BattleScene extends SceneBase {
wave: this.currentBattle?.waveIndex || 0,
party: this.party ? this.party.map(p => {
return { name: p.name, level: p.level };
}) : []
}) : [],
modeChain: this.ui?.getModeChain() ?? [],
};
(window as any).gameInfo = gameInfo;
}

View File

@ -275,7 +275,12 @@ export default class Battle {
return "battle_legendary_sinnoh";
}
if (pokemon.species.speciesId === Species.DIALGA || pokemon.species.speciesId === Species.PALKIA) {
return "battle_legendary_dia_pal";
if (pokemon.getFormKey() === "") {
return "battle_legendary_dia_pal";
}
if (pokemon.getFormKey() === "origin") {
return "battle_legendary_origin_forme";
}
}
if (pokemon.species.speciesId === Species.GIRATINA) {
return "battle_legendary_giratina";
@ -319,7 +324,12 @@ export default class Battle {
return "battle_legendary_glas_spec";
}
if (pokemon.species.speciesId === Species.CALYREX) {
return "battle_legendary_calyrex";
if (pokemon.getFormKey() === "") {
return "battle_legendary_calyrex";
}
if (pokemon.getFormKey() === "ice" || pokemon.getFormKey() === "shadow") {
return "battle_legendary_riders";
}
}
if (pokemon.species.speciesId === Species.GALAR_ARTICUNO || pokemon.species.speciesId === Species.GALAR_ZAPDOS || pokemon.species.speciesId === Species.GALAR_MOLTRES) {
return "battle_legendary_birds_galar";
@ -504,7 +514,7 @@ export const classicFixedBattles: FixedBattleConfigs = {
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_1, TrainerType.MAXIE, TrainerType.ARCHIE, TrainerType.CYRUS, TrainerType.GHETSIS, TrainerType.LYSANDRE ])),
[145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_5, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
[165]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
[165]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_2, TrainerType.MAXIE_2, TrainerType.ARCHIE_2, TrainerType.CYRUS_2, TrainerType.GHETSIS_2, TrainerType.LYSANDRE_2 ])),
[182]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LORELEI, TrainerType.WILL, TrainerType.SIDNEY, TrainerType.AARON, TrainerType.SHAUNTAL, TrainerType.MALVA, [ TrainerType.HALA, TrainerType.MOLAYNE ], TrainerType.MARNIE_ELITE, TrainerType.RIKA, TrainerType.CRISPIN ])),

View File

@ -51,21 +51,6 @@ export interface InterfaceConfig {
const repeatInputDelayMillis = 250;
// Phaser.Input.Gamepad.GamepadPlugin#refreshPads
declare module "phaser" {
namespace Input {
namespace Gamepad {
interface GamepadPlugin {
/**
* Refreshes the list of connected Gamepads.
* This is called automatically when a gamepad is connected or disconnected, and during the update loop.
*/
refreshPads(): void;
}
}
}
}
/**
* Manages and handles all input controls for the game, including keyboard and gamepad interactions.
*

View File

@ -3,7 +3,6 @@
"ACHIEVEMENTS": "Erfolge",
"STATS": "Statistiken",
"RUN_HISTORY": "Laufhistorie",
"VOUCHERS": "Gutscheine",
"EGG_LIST": "Eierliste",
"EGG_GACHA": "Eier-Gacha",
"MANAGE_DATA": "Daten verwalten",

View File

@ -45,6 +45,7 @@
"battle_legendary_lake_trio": "ORAS Lake Guardians Battle",
"battle_legendary_sinnoh": "ORAS Sinnoh Legendary Battle",
"battle_legendary_dia_pal": "ORAS Dialga & Palkia Battle",
"battle_legendary_origin_forme": "LA Origin Dialga & Palkia Battle",
"battle_legendary_giratina": "ORAS Giratina Battle",
"battle_legendary_arceus": "HGSS Arceus Battle",
"battle_legendary_unova": "BW Unova Legendary Battle",
@ -59,6 +60,7 @@
"battle_legendary_zac_zam": "SWSH Zacian & Zamazenta Battle",
"battle_legendary_glas_spec": "SWSH Glastrier & Spectrier Battle",
"battle_legendary_calyrex": "SWSH Calyrex Battle",
"battle_legendary_riders": "SWSH Ice & Shadow Rider Calyrex Battle",
"battle_legendary_birds_galar": "SWSH Galarian Legendary Birds Battle",
"battle_legendary_ruinous": "SV Treasures of Ruin Battle",
"battle_legendary_kor_mir": "SV Depths of Area Zero Battle",

View File

@ -3,7 +3,6 @@
"ACHIEVEMENTS": "Achievements",
"STATS": "Stats",
"RUN_HISTORY": "Run History",
"VOUCHERS": "Vouchers",
"EGG_LIST": "Egg List",
"EGG_GACHA": "Egg Gacha",
"MANAGE_DATA": "Manage Data",

View File

@ -3,7 +3,6 @@
"ACHIEVEMENTS": "Logros",
"STATS": "Estadísticas",
"RUN_HISTORY": "Historial de partida",
"VOUCHERS": "Vales",
"EGG_LIST": "Lista de Huevos",
"EGG_GACHA": "Gacha de Huevos",
"MANAGE_DATA": "Gestionar Datos",

View File

@ -3,7 +3,6 @@
"ACHIEVEMENTS": "Succès",
"STATS": "Statistiques",
"RUN_HISTORY": "Historique",
"VOUCHERS": "Coupons",
"EGG_LIST": "Liste des Œufs",
"EGG_GACHA": "Gacha-Œufs",
"MANAGE_DATA": "Mes données",

View File

@ -3,7 +3,6 @@
"ACHIEVEMENTS": "Obiettivi",
"STATS": "Statistiche",
"RUN_HISTORY": "Run precedenti",
"VOUCHERS": "Biglietti",
"EGG_LIST": "Lista uova",
"EGG_GACHA": "Macchine uova",
"MANAGE_DATA": "Gestisci dati",

View File

@ -3,7 +3,6 @@
"ACHIEVEMENTS": "じっせき",
"STATS": "とうけい",
"RUN_HISTORY":"ラン履歴",
"VOUCHERS": "クーポン",
"EGG_LIST": "タマゴリスト",
"EGG_GACHA": "タマゴガチャ",
"MANAGE_DATA": "データかんり",

View File

@ -3,7 +3,6 @@
"ACHIEVEMENTS": "업적",
"STATS": "통계",
"RUN_HISTORY": "플레이 이력",
"VOUCHERS": "바우처",
"EGG_LIST": "알 목록",
"EGG_GACHA": "알 뽑기",
"MANAGE_DATA": "데이터 관리",

View File

@ -3,7 +3,6 @@
"ACHIEVEMENTS": "Conquistas",
"STATS": "Estatísticas",
"RUN_HISTORY": "Histórico de Jogos",
"VOUCHERS": "Vouchers",
"EGG_LIST": "Incubadora",
"EGG_GACHA": "Gacha de ovos",
"MANAGE_DATA": "Gerenciar dados",

View File

@ -3,7 +3,6 @@
"ACHIEVEMENTS": "成就",
"STATS": "数据统计",
"RUN_HISTORY": "历史记录",
"VOUCHERS": "兑换券",
"EGG_LIST": "蛋列表",
"EGG_GACHA": "扭蛋机",
"MANAGE_DATA": "管理数据",

View File

@ -3,7 +3,6 @@
"ACHIEVEMENTS": "成就",
"STATS": "數據",
"RUN_HISTORY": "歷史記錄",
"VOUCHERS": "兌換劵",
"EGG_LIST": "蛋列表",
"EGG_GACHA": "扭蛋機",
"MANAGE_DATA": "管理數據",

View File

@ -73,75 +73,13 @@ const config: Phaser.Types.Core.GameConfig = {
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
* @param x The relative x position
* @param y The relative y position
*/
const setPositionRelative = function (guideObject: any, x: number, y: number) {
const setPositionRelative = function (guideObject: Phaser.GameObjects.GameObject, x: number, y: number) {
const offsetX = guideObject.width * (-0.5 + (0.5 - guideObject.originX));
const offsetY = guideObject.height * (-0.5 + (0.5 - guideObject.originY));
this.setPosition(guideObject.x + offsetX + x, guideObject.y + offsetY + y);
};
declare module "phaser" {
namespace GameObjects {
interface Container {
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
* @param x The relative x position
* @param y The relative y position
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface Sprite {
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
* @param x The relative x position
* @param y The relative y position
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface Image {
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
* @param x The relative x position
* @param y The relative y position
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface NineSlice {
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
* @param x The relative x position
* @param y The relative y position
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface Text {
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
* @param x The relative x position
* @param y The relative y position
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface Rectangle {
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
* @param x The relative x position
* @param y The relative y position
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
}
}
Phaser.GameObjects.Container.prototype.setPositionRelative = setPositionRelative;
Phaser.GameObjects.Sprite.prototype.setPositionRelative = setPositionRelative;
Phaser.GameObjects.Image.prototype.setPositionRelative = setPositionRelative;

View File

@ -1411,6 +1411,7 @@ export class GameData {
case GameDataType.RUN_HISTORY:
const data = JSON.parse(dataStr);
const keys = Object.keys(data);
dataName = i18next.t("menuUiHandler:RUN_HISTORY").toLowerCase();
keys.forEach((key) => {
const entryKeys = Object.keys(data[key]);
valid = ["isFavorite", "isVictory", "entry"].every(v => entryKeys.includes(v)) && entryKeys.length === 3;

68
src/typings/phaser/index.d.ts vendored Normal file
View File

@ -0,0 +1,68 @@
import "phaser";
declare module "phaser" {
namespace GameObjects {
interface GameObject {
width: number;
height: number;
originX: number;
originY: number;
x: number;
y: number;
}
interface Container {
/**
* Sets this object's position relative to another object with a given offset
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface Sprite {
/**
* Sets this object's position relative to another object with a given offset
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface Image {
/**
* Sets this object's position relative to another object with a given offset
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface NineSlice {
/**
* Sets this object's position relative to another object with a given offset
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface Text {
/**
* Sets this object's position relative to another object with a given offset
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface Rectangle {
/**
* Sets this object's position relative to another object with a given offset
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
}
namespace Input {
namespace Gamepad {
interface GamepadPlugin {
/**
* Refreshes the list of connected Gamepads.
* This is called automatically when a gamepad is connected or disconnected, and during the update loop.
*/
refreshPads(): void;
}
}
}
}

View File

@ -2,6 +2,7 @@ import BattleScene from "../battle-scene";
import { Button } from "#enums/buttons";
import i18next from "i18next";
import { Achv, achvs, getAchievementDescription } from "../system/achv";
import { Voucher, getVoucherTypeIcon, getVoucherTypeName, vouchers } from "../system/voucher";
import MessageUiHandler from "./message-ui-handler";
import { addTextObject, TextStyle } from "./text";
import { Mode } from "./ui";
@ -9,40 +10,67 @@ import { addWindow } from "./ui-theme";
import { ParseKeys } from "i18next";
import { PlayerGender } from "#enums/player-gender";
enum Page {
ACHIEVEMENTS,
VOUCHERS
}
export default class AchvsUiHandler extends MessageUiHandler {
private readonly ACHV_ROWS = 4;
private readonly ACHV_COLS = 17;
private readonly ROWS = 4;
private readonly COLS = 17;
private achvsContainer: Phaser.GameObjects.Container;
private achvIconsContainer: Phaser.GameObjects.Container;
private mainContainer: Phaser.GameObjects.Container;
private iconsContainer: Phaser.GameObjects.Container;
private headerBg: Phaser.GameObjects.NineSlice;
private headerText: Phaser.GameObjects.Text;
private headerActionText: Phaser.GameObjects.Text;
private headerActionButton: Phaser.GameObjects.Sprite;
private headerBgX: number;
private iconsBg: Phaser.GameObjects.NineSlice;
private icons: Phaser.GameObjects.Sprite[];
private achvIconsBg: Phaser.GameObjects.NineSlice;
private achvIcons: Phaser.GameObjects.Sprite[];
private titleText: Phaser.GameObjects.Text;
private scoreText: Phaser.GameObjects.Text;
private unlockText: Phaser.GameObjects.Text;
private achvsName: string;
private achvsTotal: number;
private scrollCursor: number;
private vouchersName: string;
private vouchersTotal: number;
private currentTotal: number;
private scrollCursor: number;
private cursorObj: Phaser.GameObjects.NineSlice | null;
private currentPage: Page;
constructor(scene: BattleScene, mode: Mode | null = null) {
super(scene, mode);
this.achvsTotal = Object.keys(achvs).length;
this.vouchersTotal = Object.keys(vouchers).length;
this.scrollCursor = 0;
}
setup() {
const ui = this.getUi();
this.achvsContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
this.mainContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
this.achvsContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6), Phaser.Geom.Rectangle.Contains);
this.mainContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6), Phaser.Geom.Rectangle.Contains);
const headerBg = addWindow(this.scene, 0, 0, (this.scene.game.canvas.width / 6) - 2, 24);
headerBg.setOrigin(0, 0);
this.headerBg = addWindow(this.scene, 0, 0, (this.scene.game.canvas.width / 6) - 2, 24);
this.headerBg.setOrigin(0, 0);
this.headerText = addTextObject(this.scene, 0, 0, "", TextStyle.SETTINGS_LABEL);
this.headerText.setOrigin(0, 0);
this.headerText.setPositionRelative(this.headerBg, 8, 4);
this.headerActionButton = new Phaser.GameObjects.Sprite(this.scene, 0, 0, "keyboard", "SPACE.png");
this.headerActionButton.setOrigin(0, 0);
this.headerActionButton.setPositionRelative(this.headerBg, 236, 6);
this.headerActionText = addTextObject(this.scene, 0, 0, "", TextStyle.WINDOW, {fontSize:"60px"});
this.headerActionText.setOrigin(0, 0);
this.headerActionText.setPositionRelative(this.headerBg, 264, 8);
// We need to get the player gender from the game data to add the correct prefix to the achievement name
const playerGender = this.scene.gameData.gender;
@ -51,30 +79,29 @@ export default class AchvsUiHandler extends MessageUiHandler {
genderPrefix = "PGF";
}
const headerText = addTextObject(this.scene, 0, 0, i18next.t(`${genderPrefix}achv:Achievements.name` as ParseKeys), TextStyle.SETTINGS_LABEL);
headerText.setOrigin(0, 0);
headerText.setPositionRelative(headerBg, 8, 4);
this.achvsName = i18next.t(`${genderPrefix}achv:Achievements.name` as ParseKeys);
this.vouchersName = i18next.t("voucher:vouchers");
this.achvIconsBg = addWindow(this.scene, 0, headerBg.height, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - headerBg.height - 68);
this.achvIconsBg.setOrigin(0, 0);
this.iconsBg = addWindow(this.scene, 0, this.headerBg.height, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - this.headerBg.height - 68);
this.iconsBg.setOrigin(0, 0);
this.achvIconsContainer = this.scene.add.container(6, headerBg.height + 6);
this.iconsContainer = this.scene.add.container(6, this.headerBg.height + 6);
this.achvIcons = [];
this.icons = [];
for (let a = 0; a < this.ACHV_ROWS * this.ACHV_COLS; a++) {
const x = (a % this.ACHV_COLS) * 18;
const y = Math.floor(a / this.ACHV_COLS) * 18;
for (let a = 0; a < this.ROWS * this.COLS; a++) {
const x = (a % this.COLS) * 18;
const y = Math.floor(a / this.COLS) * 18;
const icon = this.scene.add.sprite(x, y, "items", "unknown");
icon.setOrigin(0, 0);
icon.setScale(0.5);
this.achvIcons.push(icon);
this.achvIconsContainer.add(icon);
this.icons.push(icon);
this.iconsContainer.add(icon);
}
const titleBg = addWindow(this.scene, 0, headerBg.height + this.achvIconsBg.height, 174, 24);
const titleBg = addWindow(this.scene, 0, this.headerBg.height + this.iconsBg.height, 174, 24);
titleBg.setOrigin(0, 0);
this.titleText = addTextObject(this.scene, 0, 0, "", TextStyle.WINDOW);
@ -105,36 +132,40 @@ export default class AchvsUiHandler extends MessageUiHandler {
this.message = descriptionText;
this.achvsContainer.add(headerBg);
this.achvsContainer.add(headerText);
this.achvsContainer.add(this.achvIconsBg);
this.achvsContainer.add(this.achvIconsContainer);
this.achvsContainer.add(titleBg);
this.achvsContainer.add(this.titleText);
this.achvsContainer.add(scoreBg);
this.achvsContainer.add(this.scoreText);
this.achvsContainer.add(unlockBg);
this.achvsContainer.add(this.unlockText);
this.achvsContainer.add(descriptionBg);
this.achvsContainer.add(descriptionText);
this.mainContainer.add(this.headerBg);
this.mainContainer.add(this.headerActionButton);
this.mainContainer.add(this.headerText);
this.mainContainer.add(this.headerActionText);
this.mainContainer.add(this.iconsBg);
this.mainContainer.add(this.iconsContainer);
this.mainContainer.add(titleBg);
this.mainContainer.add(this.titleText);
this.mainContainer.add(scoreBg);
this.mainContainer.add(this.scoreText);
this.mainContainer.add(unlockBg);
this.mainContainer.add(this.unlockText);
this.mainContainer.add(descriptionBg);
this.mainContainer.add(descriptionText);
ui.add(this.achvsContainer);
ui.add(this.mainContainer);
this.currentPage = Page.ACHIEVEMENTS;
this.setCursor(0);
this.achvsContainer.setVisible(false);
this.mainContainer.setVisible(false);
}
show(args: any[]): boolean {
super.show(args);
this.headerBgX = this.headerBg.getTopRight().x;
this.updateAchvIcons();
this.achvsContainer.setVisible(true);
this.mainContainer.setVisible(true);
this.setCursor(0);
this.setScrollCursor(0);
this.getUi().moveTo(this.achvsContainer, this.getUi().length - 1);
this.getUi().moveTo(this.mainContainer, this.getUi().length - 1);
this.getUi().hideTooltip();
@ -160,48 +191,71 @@ export default class AchvsUiHandler extends MessageUiHandler {
this.unlockText.setText(unlocked ? new Date(achvUnlocks[achv.id]).toLocaleDateString() : i18next.t(`${genderPrefix}achv:Locked.name` as ParseKeys));
}
protected showVoucher(voucher: Voucher) {
const voucherUnlocks = this.scene.gameData.voucherUnlocks;
const unlocked = voucherUnlocks.hasOwnProperty(voucher.id);
this.titleText.setText(getVoucherTypeName(voucher.voucherType));
this.showText(voucher.description);
this.unlockText.setText(unlocked ? new Date(voucherUnlocks[voucher.id]).toLocaleDateString() : i18next.t("voucher:locked"));
}
processInput(button: Button): boolean {
const ui = this.getUi();
let success = false;
if (button === Button.ACTION) {
success = true;
this.setScrollCursor(0);
if (this.currentPage === Page.ACHIEVEMENTS) {
this.currentPage = Page.VOUCHERS;
this.updateVoucherIcons();
this.setCursor(0);
} else if (this.currentPage === Page.VOUCHERS) {
this.currentPage = Page.ACHIEVEMENTS;
this.updateAchvIcons();
this.setCursor(0);
}
this.mainContainer.update();
}
if (button === Button.CANCEL) {
success = true;
this.scene.ui.revertMode();
} else {
const rowIndex = Math.floor(this.cursor / this.ACHV_COLS);
const itemOffset = (this.scrollCursor * this.ACHV_COLS);
const rowIndex = Math.floor(this.cursor / this.COLS);
const itemOffset = (this.scrollCursor * this.COLS);
switch (button) {
case Button.UP:
if (this.cursor < this.ACHV_COLS) {
if (this.cursor < this.COLS) {
if (this.scrollCursor) {
success = this.setScrollCursor(this.scrollCursor - 1);
}
} else {
success = this.setCursor(this.cursor - this.ACHV_COLS);
success = this.setCursor(this.cursor - this.COLS);
}
break;
case Button.DOWN:
const canMoveDown = (this.cursor + itemOffset) + this.ACHV_COLS < this.achvsTotal;
if (rowIndex >= this.ACHV_ROWS - 1) {
if (this.scrollCursor < Math.ceil(this.achvsTotal / this.ACHV_COLS) - this.ACHV_ROWS && canMoveDown) {
const canMoveDown = (this.cursor + itemOffset) + this.COLS < this.currentTotal;
if (rowIndex >= this.ROWS - 1) {
if (this.scrollCursor < Math.ceil(this.currentTotal / this.COLS) - this.ROWS && canMoveDown) {
success = this.setScrollCursor(this.scrollCursor + 1);
}
} else if (canMoveDown) {
success = this.setCursor(this.cursor + this.ACHV_COLS);
success = this.setCursor(this.cursor + this.COLS);
}
break;
case Button.LEFT:
if (!this.cursor && this.scrollCursor) {
success = this.setScrollCursor(this.scrollCursor - 1) && this.setCursor(this.cursor + (this.ACHV_COLS - 1));
success = this.setScrollCursor(this.scrollCursor - 1) && this.setCursor(this.cursor + (this.COLS - 1));
} else if (this.cursor) {
success = this.setCursor(this.cursor - 1);
}
break;
case Button.RIGHT:
if (this.cursor + 1 === this.ACHV_ROWS * this.ACHV_COLS && this.scrollCursor < Math.ceil(this.achvsTotal / this.ACHV_COLS) - this.ACHV_ROWS) {
success = this.setScrollCursor(this.scrollCursor + 1) && this.setCursor(this.cursor - (this.ACHV_COLS - 1));
} else if (this.cursor + itemOffset < this.achvsTotal - 1) {
if (this.cursor + 1 === this.ROWS * this.COLS && this.scrollCursor < Math.ceil(this.currentTotal / this.COLS) - this.ROWS) {
success = this.setScrollCursor(this.scrollCursor + 1) && this.setCursor(this.cursor - (this.COLS - 1));
} else if (this.cursor + itemOffset < this.currentTotal - 1) {
success = this.setCursor(this.cursor + 1);
}
break;
@ -215,24 +269,30 @@ export default class AchvsUiHandler extends MessageUiHandler {
return success;
}
setCursor(cursor: integer): boolean {
setCursor(cursor: integer, pageChange?: boolean): boolean {
const ret = super.setCursor(cursor);
let updateAchv = ret;
let update = ret;
if (!this.cursorObj) {
this.cursorObj = this.scene.add.nineslice(0, 0, "select_cursor_highlight", undefined, 16, 16, 1, 1, 1, 1);
this.cursorObj.setOrigin(0, 0);
this.achvIconsContainer.add(this.cursorObj);
updateAchv = true;
this.iconsContainer.add(this.cursorObj);
update = true;
}
this.cursorObj.setPositionRelative(this.achvIcons[this.cursor], 0, 0);
this.cursorObj.setPositionRelative(this.icons[this.cursor], 0, 0);
if (updateAchv) {
this.showAchv(achvs[Object.keys(achvs)[cursor + this.scrollCursor * this.ACHV_COLS]]);
if (update || pageChange) {
switch (this.currentPage) {
case Page.ACHIEVEMENTS:
this.showAchv(achvs[Object.keys(achvs)[cursor + this.scrollCursor * this.COLS]]);
break;
case Page.VOUCHERS:
this.showVoucher(vouchers[Object.keys(vouchers)[cursor + this.scrollCursor * this.COLS]]);
break;
}
}
return ret;
}
@ -249,10 +309,16 @@ export default class AchvsUiHandler extends MessageUiHandler {
this.scrollCursor = scrollCursor;
this.updateAchvIcons();
this.showAchv(achvs[Object.keys(achvs)[Math.min(this.cursor + this.scrollCursor * this.ACHV_COLS, Object.values(achvs).length - 1)]]);
switch (this.currentPage) {
case Page.ACHIEVEMENTS:
this.updateAchvIcons();
this.showAchv(achvs[Object.keys(achvs)[Math.min(this.cursor + this.scrollCursor * this.COLS, Object.values(achvs).length - 1)]]);
break;
case Page.VOUCHERS:
this.updateVoucherIcons();
this.showVoucher(vouchers[Object.keys(vouchers)[Math.min(this.cursor + this.scrollCursor * this.COLS, Object.values(vouchers).length - 1)]]);
break;
}
return true;
}
@ -262,15 +328,21 @@ export default class AchvsUiHandler extends MessageUiHandler {
* Determines what data is to be displayed on the UI and updates it accordingly based on the current value of this.scrollCursor
*/
updateAchvIcons(): void {
this.headerText.text = this.achvsName;
this.headerActionText.text = this.vouchersName;
const textPosition = this.headerBgX - this.headerActionText.displayWidth - 8;
this.headerActionText.setX(textPosition);
this.headerActionButton.setX(textPosition - this.headerActionButton.displayWidth - 4);
const achvUnlocks = this.scene.gameData.achvUnlocks;
const itemOffset = this.scrollCursor * this.ACHV_COLS;
const itemLimit = this.ACHV_ROWS * this.ACHV_COLS;
const itemOffset = this.scrollCursor * this.COLS;
const itemLimit = this.ROWS * this.COLS;
const achvRange = Object.values(achvs).slice(itemOffset, itemLimit + itemOffset);
achvRange.forEach((achv: Achv, i: integer) => {
const icon = this.achvIcons[i];
const icon = this.icons[i];
const unlocked = achvUnlocks.hasOwnProperty(achv.id);
const hidden = !unlocked && achv.secret && (!achv.parentId || !achvUnlocks.hasOwnProperty(achv.parentId));
const tinted = !hidden && !unlocked;
@ -284,14 +356,54 @@ export default class AchvsUiHandler extends MessageUiHandler {
}
});
if (achvRange.length < this.achvIcons.length) {
this.achvIcons.slice(achvRange.length).map(i => i.setVisible(false));
if (achvRange.length < this.icons.length) {
this.icons.slice(achvRange.length).map(i => i.setVisible(false));
}
this.currentTotal = this.achvsTotal;
}
/**
* updateVoucherIcons(): void
* Determines what data is to be displayed on the UI and updates it accordingly based on the current value of this.scrollCursor
*/
updateVoucherIcons(): void {
this.headerText.text = this.vouchersName;
this.headerActionText.text = this.achvsName;
const textPosition = this.headerBgX - this.headerActionText.displayWidth - 8;
this.headerActionText.setX(textPosition);
this.headerActionButton.setX(textPosition - this.headerActionButton.displayWidth - 4);
const voucherUnlocks = this.scene.gameData.voucherUnlocks;
const itemOffset = this.scrollCursor * this.COLS;
const itemLimit = this.ROWS * this.COLS;
const voucherRange = Object.values(vouchers).slice(itemOffset, itemLimit + itemOffset);
voucherRange.forEach((voucher: Voucher, i: integer) => {
const icon = this.icons[i];
const unlocked = voucherUnlocks.hasOwnProperty(voucher.id);
icon.setFrame(getVoucherTypeIcon(voucher.voucherType));
icon.setVisible(true);
if (!unlocked) {
icon.setTintFill(0);
} else {
icon.clearTint();
}
});
if (voucherRange.length < this.icons.length) {
this.icons.slice(voucherRange.length).map(i => i.setVisible(false));
}
this.currentTotal = this.vouchersTotal;
}
clear() {
super.clear();
this.achvsContainer.setVisible(false);
this.currentPage = Page.ACHIEVEMENTS;
this.mainContainer.setVisible(false);
this.eraseCursor();
}

View File

@ -9,6 +9,7 @@ import { DexAttr, GameData } from "../system/game-data";
import { speciesStarters } from "../data/pokemon-species";
import {Button} from "#enums/buttons";
import i18next from "i18next";
import { UiTheme } from "#app/enums/ui-theme";
interface DisplayStat {
label_key?: string;
@ -218,6 +219,9 @@ export default class GameStatsUiHandler extends UiHandler {
private statLabels: Phaser.GameObjects.Text[];
private statValues: Phaser.GameObjects.Text[];
private arrowUp: Phaser.GameObjects.Sprite;
private arrowDown: Phaser.GameObjects.Sprite;
constructor(scene: BattleScene, mode: Mode | null = null) {
super(scene, mode);
@ -241,11 +245,9 @@ export default class GameStatsUiHandler extends UiHandler {
const statsBgWidth = ((this.scene.game.canvas.width / 6) - 2) / 2;
const [ statsBgLeft, statsBgRight ] = new Array(2).fill(null).map((_, i) => {
let width = statsBgWidth;
if (!i) {
width += 5;
}
const statsBg = addWindow(this.scene, statsBgWidth * i, headerBg.height, width, (this.scene.game.canvas.height / 6) - headerBg.height - 2, false, !!i, 2);
const width = statsBgWidth + 2;
const height = Math.floor((this.scene.game.canvas.height / 6) - headerBg.height - 2);
const statsBg = addWindow(this.scene, (statsBgWidth - 2) * i, headerBg.height, width, height, false, false, i>0?-3:0, 1);
statsBg.setOrigin(0, 0);
return statsBg;
});
@ -272,6 +274,14 @@ export default class GameStatsUiHandler extends UiHandler {
this.gameStatsContainer.add(statsBgRight);
this.gameStatsContainer.add(this.statsContainer);
// arrows to show that we can scroll through the stats
const isLegacyTheme = this.scene.uiTheme === UiTheme.LEGACY;
this.arrowDown = this.scene.add.sprite(statsBgWidth, this.scene.game.canvas.height / 6 - (isLegacyTheme? 9 : 5), "prompt");
this.gameStatsContainer.add(this.arrowDown);
this.arrowUp = this.scene.add.sprite(statsBgWidth, headerBg.height + (isLegacyTheme? 7 : 3), "prompt");
this.arrowUp.flipY = true;
this.gameStatsContainer.add(this.arrowUp);
ui.add(this.gameStatsContainer);
this.setCursor(0);
@ -286,6 +296,15 @@ export default class GameStatsUiHandler extends UiHandler {
this.updateStats();
this.arrowUp.play("prompt");
this.arrowDown.play("prompt");
if (this.scene.uiTheme === UiTheme.LEGACY) {
this.arrowUp.setTint(0x484848);
this.arrowDown.setTint(0x484848);
}
this.updateArrows();
this.gameStatsContainer.setVisible(true);
this.getUi().moveTo(this.gameStatsContainer, this.getUi().length - 1);
@ -311,6 +330,17 @@ export default class GameStatsUiHandler extends UiHandler {
}
}
/**
* Show arrows at the top / bottom of the page if it's possible to scroll in that direction
*/
updateArrows(): void {
const showUpArrow = this.cursor > 0;
this.arrowUp.setVisible(showUpArrow);
const showDownArrow = this.cursor < Math.ceil((Object.keys(displayStats).length - 18) / 2);
this.arrowDown.setVisible(showDownArrow);
}
processInput(button: Button): boolean {
const ui = this.getUi();
@ -346,6 +376,7 @@ export default class GameStatsUiHandler extends UiHandler {
if (ret) {
this.updateStats();
this.updateArrows();
}
return ret;

View File

@ -8,7 +8,7 @@ import { OptionSelectConfig, OptionSelectItem } from "./abstact-option-select-ui
import { Tutorial, handleTutorial } from "../tutorial";
import { loggedInUser, updateUserInfo } from "../account";
import i18next from "i18next";
import {Button} from "#enums/buttons";
import { Button } from "#enums/buttons";
import { GameDataType } from "#enums/game-data-type";
import BgmBar from "#app/ui/bgm-bar";
@ -17,7 +17,6 @@ enum MenuOptions {
ACHIEVEMENTS,
STATS,
RUN_HISTORY,
VOUCHERS,
EGG_LIST,
EGG_GACHA,
MANAGE_DATA,
@ -98,7 +97,6 @@ export default class MenuUiHandler extends MessageUiHandler {
render() {
const ui = this.getUi();
console.log(ui.getModeChain());
this.excludedMenus = () => [
{ condition: ![Mode.COMMAND, Mode.TITLE].includes(ui.getModeChain()[0]), options: [ MenuOptions.EGG_GACHA, MenuOptions.EGG_LIST] },
{ condition: bypassLogin, options: [ MenuOptions.LOG_OUT ] }
@ -388,10 +386,6 @@ export default class MenuUiHandler extends MessageUiHandler {
ui.setOverlayMode(Mode.RUN_HISTORY);
success = true;
break;
case MenuOptions.VOUCHERS:
ui.setOverlayMode(Mode.VOUCHERS);
success = true;
break;
case MenuOptions.EGG_LIST:
if (this.scene.gameData.eggs.length) {
ui.revertMode();

View File

@ -409,10 +409,12 @@ export default class RunInfoUiHandler extends UiHandler {
// Duration + Money
const runInfoTextContainer = this.scene.add.container(0, 0);
const runInfoText = addBBCodeTextObject(this.scene, 7, 0, "", TextStyle.WINDOW, {fontSize : "50px", lineSpacing:3});
// Japanese is set to a greater line spacing of 35px in addBBCodeTextObject() if lineSpacing < 12.
const lineSpacing = (i18next.resolvedLanguage === "ja") ? 12 : 3;
const runInfoText = addBBCodeTextObject(this.scene, 7, 0, "", TextStyle.WINDOW, {fontSize: "50px", lineSpacing: lineSpacing});
const runTime = Utils.getPlayTimeString(this.runInfo.playTime);
runInfoText.appendText(`${i18next.t("runHistory:runLength")}: ${runTime}`, false);
const runMoney = Utils.formatMoney(this.runInfo.money, 1000);
const runMoney = Utils.formatMoney(this.scene.moneyFormat, this.runInfo.money);
runInfoText.appendText(`[color=${getTextColor(TextStyle.MONEY)}]${i18next.t("battleScene:moneyOwned", {formattedMoney : runMoney})}[/color]`);
runInfoText.setPosition(7, 70);
runInfoTextContainer.add(runInfoText);
@ -513,7 +515,9 @@ export default class RunInfoUiHandler extends UiHandler {
}
const pPassiveInfo = pokemon.passive ? passiveLabel+": "+pokemon.getPassiveAbility().name : "";
const pAbilityInfo = abilityLabel + ": " + pokemon.getAbility().name;
const pokeInfoText = addBBCodeTextObject(this.scene, 0, 0, pName, TextStyle.SUMMARY, {fontSize: textContainerFontSize, lineSpacing:3});
// Japanese is set to a greater line spacing of 35px in addBBCodeTextObject() if lineSpacing < 12.
const lineSpacing = (i18next.resolvedLanguage === "ja") ? 12 : 3;
const pokeInfoText = addBBCodeTextObject(this.scene, 0, 0, pName, TextStyle.SUMMARY, {fontSize: textContainerFontSize, lineSpacing: lineSpacing});
pokeInfoText.appendText(`${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatFancyLargeNumber(pokemon.level, 1)} - ${pNature}`);
pokeInfoText.appendText(pAbilityInfo);
pokeInfoText.appendText(pPassiveInfo);
@ -537,12 +541,12 @@ export default class RunInfoUiHandler extends UiHandler {
const speedLabel = (currentLanguage==="es"||currentLanguage==="pt_BR") ? i18next.t("runHistory:SPDshortened") : i18next.t("pokemonInfo:Stat.SPDshortened");
const speed = speedLabel+": "+pStats[5];
// Column 1: HP Atk Def
const pokeStatText1 = addBBCodeTextObject(this.scene, -5, 0, hp, TextStyle.SUMMARY, {fontSize: textContainerFontSize, lineSpacing:3});
const pokeStatText1 = addBBCodeTextObject(this.scene, -5, 0, hp, TextStyle.SUMMARY, {fontSize: textContainerFontSize, lineSpacing: lineSpacing});
pokeStatText1.appendText(atk);
pokeStatText1.appendText(def);
pokeStatTextContainer.add(pokeStatText1);
// Column 2: SpAtk SpDef Speed
const pokeStatText2 = addBBCodeTextObject(this.scene, 25, 0, spatk, TextStyle.SUMMARY, {fontSize: textContainerFontSize, lineSpacing:3});
const pokeStatText2 = addBBCodeTextObject(this.scene, 25, 0, spatk, TextStyle.SUMMARY, {fontSize: textContainerFontSize, lineSpacing: lineSpacing});
pokeStatText2.appendText(spdef);
pokeStatText2.appendText(speed);
pokeStatTextContainer.add(pokeStatText2);

View File

@ -5,7 +5,7 @@ import BBCodeText from "phaser3-rex-plugins/plugins/gameobjects/tagtext/bbcodete
import InputText from "phaser3-rex-plugins/plugins/inputtext";
import BattleScene from "../battle-scene";
import { ModifierTier } from "../modifier/modifier-tier";
import i18next from "#app/plugins/i18n.js";
import i18next from "#app/plugins/i18n";
export enum TextStyle {
MESSAGE,
@ -227,6 +227,7 @@ export function getBBCodeFrag(content: string, textStyle: TextStyle, uiTheme: Ui
}
export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: UiTheme = UiTheme.DEFAULT): string {
const isLegacyTheme = uiTheme === UiTheme.LEGACY;
switch (textStyle) {
case TextStyle.MESSAGE:
return !shadow ? "#f8f8f8" : "#6b5a73";
@ -235,29 +236,29 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui
case TextStyle.MOVE_PP_FULL:
case TextStyle.TOOLTIP_CONTENT:
case TextStyle.SETTINGS_VALUE:
if (uiTheme) {
if (isLegacyTheme) {
return !shadow ? "#484848" : "#d0d0c8";
}
return !shadow ? "#f8f8f8" : "#6b5a73";
case TextStyle.MOVE_PP_HALF_FULL:
if (uiTheme) {
if (isLegacyTheme) {
return !shadow ? "#a68e17" : "#ebd773";
}
return !shadow ? "#ccbe00" : "#6e672c";
case TextStyle.MOVE_PP_NEAR_EMPTY:
if (uiTheme) {
if (isLegacyTheme) {
return !shadow ? "#d64b00" : "#f7b18b";
}
return !shadow ? "#d64b00" : "#69402a";
case TextStyle.MOVE_PP_EMPTY:
if (uiTheme) {
if (isLegacyTheme) {
return !shadow ? "#e13d3d" : "#fca2a2";
}
return !shadow ? "#e13d3d" : "#632929";
case TextStyle.WINDOW_ALT:
return !shadow ? "#484848" : "#d0d0c8";
case TextStyle.BATTLE_INFO:
if (uiTheme) {
if (isLegacyTheme) {
return !shadow ? "#404040" : "#ded6b5";
}
return !shadow ? "#f8f8f8" : "#6b5a73";
@ -268,7 +269,7 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui
case TextStyle.SUMMARY:
return !shadow ? "#f8f8f8" : "#636363";
case TextStyle.SUMMARY_ALT:
if (uiTheme) {
if (isLegacyTheme) {
return !shadow ? "#f8f8f8" : "#636363";
}
return !shadow ? "#484848" : "#d0d0c8";
@ -288,6 +289,9 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui
case TextStyle.STATS_LABEL:
return !shadow ? "#f8b050" : "#c07800";
case TextStyle.STATS_VALUE:
if (isLegacyTheme) {
return !shadow ? "#484848" : "#d0d0c8";
}
return !shadow ? "#f8f8f8" : "#6b5a73";
case TextStyle.SUMMARY_GREEN:
return !shadow ? "#78c850" : "#306850";

View File

@ -1,4 +1,4 @@
import {default as BattleScene} from "../battle-scene";
import { default as BattleScene } from "../battle-scene";
import UiHandler from "./ui-handler";
import BattleMessageUiHandler from "./battle-message-ui-handler";
import CommandUiHandler from "./command-ui-handler";
@ -23,7 +23,6 @@ import OptionSelectUiHandler from "./settings/option-select-ui-handler";
import EggHatchSceneHandler from "./egg-hatch-scene-handler";
import EggListUiHandler from "./egg-list-ui-handler";
import EggGachaUiHandler from "./egg-gacha-ui-handler";
import VouchersUiHandler from "./vouchers-ui-handler";
import {addWindow} from "./ui-theme";
import LoginFormUiHandler from "./login-form-ui-handler";
import RegistrationFormUiHandler from "./registration-form-ui-handler";
@ -37,8 +36,8 @@ import SavingIconHandler from "./saving-icon-handler";
import UnavailableModalUiHandler from "./unavailable-modal-ui-handler";
import OutdatedModalUiHandler from "./outdated-modal-ui-handler";
import SessionReloadModalUiHandler from "./session-reload-modal-ui-handler";
import {Button} from "#enums/buttons";
import i18next, {ParseKeys} from "i18next";
import { Button } from "#enums/buttons";
import i18next, { ParseKeys } from "i18next";
import GamepadBindingUiHandler from "./settings/gamepad-binding-ui-handler";
import SettingsKeyboardUiHandler from "#app/ui/settings/settings-keyboard-ui-handler";
import KeyboardBindingUiHandler from "#app/ui/settings/keyboard-binding-ui-handler";
@ -77,7 +76,6 @@ export enum Mode {
KEYBOARD_BINDING,
ACHIEVEMENTS,
GAME_STATS,
VOUCHERS,
EGG_LIST,
EGG_GACHA,
LOGIN_FORM,
@ -120,7 +118,6 @@ const noTransitionModes = [
Mode.SETTINGS_KEYBOARD,
Mode.ACHIEVEMENTS,
Mode.GAME_STATS,
Mode.VOUCHERS,
Mode.LOGIN_FORM,
Mode.REGISTRATION_FORM,
Mode.LOADING,
@ -179,7 +176,6 @@ export default class UI extends Phaser.GameObjects.Container {
new KeyboardBindingUiHandler(scene),
new AchvsUiHandler(scene),
new GameStatsUiHandler(scene),
new VouchersUiHandler(scene),
new EggListUiHandler(scene),
new EggGachaUiHandler(scene),
new LoginFormUiHandler(scene),
@ -460,6 +456,7 @@ export default class UI extends Phaser.GameObjects.Container {
}
if (chainMode && this.mode && !clear) {
this.modeChain.push(this.mode);
(this.scene as BattleScene).updateGameInfo();
}
this.mode = mode;
const touchControls = document?.getElementById("touchControls");
@ -507,6 +504,7 @@ export default class UI extends Phaser.GameObjects.Container {
resetModeChain(): void {
this.modeChain = [];
(this.scene as BattleScene).updateGameInfo();
}
revertMode(): Promise<boolean> {
@ -520,6 +518,7 @@ export default class UI extends Phaser.GameObjects.Container {
const doRevertMode = () => {
this.getHandler().clear();
this.mode = this.modeChain.pop()!; // TODO: is this bang correct?
(this.scene as BattleScene).updateGameInfo();
const touchControls = document.getElementById("touchControls");
if (touchControls) {
touchControls.dataset.uiMode = Mode[this.mode];

View File

@ -1,262 +0,0 @@
import BattleScene from "../battle-scene";
import { Button } from "#enums/buttons";
import i18next from "i18next";
import { Voucher, getVoucherTypeIcon, getVoucherTypeName, vouchers } from "../system/voucher";
import MessageUiHandler from "./message-ui-handler";
import { TextStyle, addTextObject } from "./text";
import { Mode } from "./ui";
import { addWindow } from "./ui-theme";
const itemRows = 4;
const itemCols = 17;
export default class VouchersUiHandler extends MessageUiHandler {
private vouchersContainer: Phaser.GameObjects.Container;
private voucherIconsContainer: Phaser.GameObjects.Container;
private voucherIconsBg: Phaser.GameObjects.NineSlice;
private voucherIcons: Phaser.GameObjects.Sprite[];
private titleText: Phaser.GameObjects.Text;
private unlockText: Phaser.GameObjects.Text;
private itemsTotal: integer;
private scrollCursor: integer;
private cursorObj: Phaser.GameObjects.NineSlice | null;
constructor(scene: BattleScene, mode: Mode | null = null) {
super(scene, mode);
this.itemsTotal = Object.keys(vouchers).length;
this.scrollCursor = 0;
}
setup() {
const ui = this.getUi();
this.vouchersContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
this.vouchersContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6), Phaser.Geom.Rectangle.Contains);
const headerBg = addWindow(this.scene, 0, 0, (this.scene.game.canvas.width / 6) - 2, 24);
headerBg.setOrigin(0, 0);
const headerText = addTextObject(this.scene, 0, 0, i18next.t("voucher:vouchers"), TextStyle.SETTINGS_LABEL);
headerText.setOrigin(0, 0);
headerText.setPositionRelative(headerBg, 8, 4);
this.voucherIconsBg = addWindow(this.scene, 0, headerBg.height, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - headerBg.height - 68);
this.voucherIconsBg.setOrigin(0, 0);
this.voucherIconsContainer = this.scene.add.container(6, headerBg.height + 6);
this.voucherIcons = [];
for (let a = 0; a < itemRows * itemCols; a++) {
const x = (a % itemCols) * 18;
const y = Math.floor(a / itemCols) * 18;
const icon = this.scene.add.sprite(x, y, "items", "unknown");
icon.setOrigin(0, 0);
icon.setScale(0.5);
this.voucherIcons.push(icon);
this.voucherIconsContainer.add(icon);
}
const titleBg = addWindow(this.scene, 0, headerBg.height + this.voucherIconsBg.height, 220, 24);
titleBg.setOrigin(0, 0);
this.titleText = addTextObject(this.scene, 0, 0, "", TextStyle.WINDOW);
this.titleText.setOrigin(0, 0);
this.titleText.setPositionRelative(titleBg, 8, 4);
const unlockBg = addWindow(this.scene, titleBg.x + titleBg.width, titleBg.y, 98, 24);
unlockBg.setOrigin(0, 0);
this.unlockText = addTextObject(this.scene, 0, 0, "", TextStyle.WINDOW);
this.unlockText.setOrigin(0, 0);
this.unlockText.setPositionRelative(unlockBg, 8, 4);
const descriptionBg = addWindow(this.scene, 0, titleBg.y + titleBg.height, (this.scene.game.canvas.width / 6) - 2, 42);
descriptionBg.setOrigin(0, 0);
const descriptionText = addTextObject(this.scene, 0, 0, "", TextStyle.WINDOW, { maxLines: 2 });
descriptionText.setWordWrapWidth(1870);
descriptionText.setOrigin(0, 0);
descriptionText.setPositionRelative(descriptionBg, 8, 4);
this.message = descriptionText;
this.vouchersContainer.add(headerBg);
this.vouchersContainer.add(headerText);
this.vouchersContainer.add(this.voucherIconsBg);
this.vouchersContainer.add(this.voucherIconsContainer);
this.vouchersContainer.add(titleBg);
this.vouchersContainer.add(this.titleText);
this.vouchersContainer.add(unlockBg);
this.vouchersContainer.add(this.unlockText);
this.vouchersContainer.add(descriptionBg);
this.vouchersContainer.add(descriptionText);
ui.add(this.vouchersContainer);
this.setCursor(0);
this.vouchersContainer.setVisible(false);
}
show(args: any[]): boolean {
super.show(args);
this.vouchersContainer.setVisible(true);
this.setCursor(0);
this.setScrollCursor(0);
this.updateVoucherIcons();
this.getUi().moveTo(this.vouchersContainer, this.getUi().length - 1);
this.getUi().hideTooltip();
return true;
}
protected showVoucher(voucher: Voucher) {
const voucherUnlocks = this.scene.gameData.voucherUnlocks;
const unlocked = voucherUnlocks.hasOwnProperty(voucher.id);
this.titleText.setText(getVoucherTypeName(voucher.voucherType));
this.showText(voucher.description);
this.unlockText.setText(unlocked ? new Date(voucherUnlocks[voucher.id]).toLocaleDateString() : i18next.t("voucher:locked"));
}
processInput(button: Button): boolean {
const ui = this.getUi();
let success = false;
if (button === Button.CANCEL) {
success = true;
this.scene.ui.revertMode();
} else {
const rowIndex = Math.floor(this.cursor / itemCols);
const itemOffset = (this.scrollCursor * itemCols);
switch (button) {
case Button.UP:
if (this.cursor < itemCols) {
if (this.scrollCursor) {
success = this.setScrollCursor(this.scrollCursor - 1);
}
} else {
success = this.setCursor(this.cursor - itemCols);
}
break;
case Button.DOWN:
const canMoveDown = (this.cursor + itemOffset) + itemCols < this.itemsTotal;
if (rowIndex >= itemRows - 1) {
if (this.scrollCursor < Math.ceil(this.itemsTotal / itemCols) - itemRows && canMoveDown) {
success = this.setScrollCursor(this.scrollCursor + 1);
}
} else if (canMoveDown) {
success = this.setCursor(this.cursor + itemCols);
}
break;
case Button.LEFT:
if (!this.cursor && this.scrollCursor) {
success = this.setScrollCursor(this.scrollCursor - 1) && this.setCursor(this.cursor + (itemCols - 1));
} else if (this.cursor) {
success = this.setCursor(this.cursor - 1);
}
break;
case Button.RIGHT:
if (this.cursor + 1 === itemRows * itemCols && this.scrollCursor < Math.ceil(this.itemsTotal / itemCols) - itemRows) {
success = this.setScrollCursor(this.scrollCursor + 1) && this.setCursor(this.cursor - (itemCols - 1));
} else if (this.cursor + itemOffset < Object.keys(vouchers).length - 1) {
success = this.setCursor(this.cursor + 1);
}
break;
}
}
if (success) {
ui.playSelect();
}
return success;
}
setCursor(cursor: integer): boolean {
const ret = super.setCursor(cursor);
let updateVoucher = ret;
if (!this.cursorObj) {
this.cursorObj = this.scene.add.nineslice(0, 0, "select_cursor_highlight", undefined, 16, 16, 1, 1, 1, 1);
this.cursorObj.setOrigin(0, 0);
this.voucherIconsContainer.add(this.cursorObj);
updateVoucher = true;
}
this.cursorObj.setPositionRelative(this.voucherIcons[this.cursor], 0, 0);
if (updateVoucher) {
this.showVoucher(vouchers[Object.keys(vouchers)[cursor + this.scrollCursor * itemCols]]);
}
return ret;
}
setScrollCursor(scrollCursor: integer): boolean {
if (scrollCursor === this.scrollCursor) {
return false;
}
this.scrollCursor = scrollCursor;
this.updateVoucherIcons();
this.showVoucher(vouchers[Object.keys(vouchers)[Math.min(this.cursor + this.scrollCursor * itemCols, Object.values(vouchers).length - 1)]]);
return true;
}
updateVoucherIcons(): void {
const voucherUnlocks = this.scene.gameData.voucherUnlocks;
const itemOffset = this.scrollCursor * itemCols;
const itemLimit = itemRows * itemCols;
const voucherRange = Object.values(vouchers).slice(itemOffset, itemLimit + itemOffset);
voucherRange.forEach((voucher: Voucher, i: integer) => {
const icon = this.voucherIcons[i];
const unlocked = voucherUnlocks.hasOwnProperty(voucher.id);
icon.setFrame(getVoucherTypeIcon(voucher.voucherType));
icon.setVisible(true);
if (!unlocked) {
icon.setTintFill(0);
} else {
icon.clearTint();
}
});
if (voucherRange.length < this.voucherIcons.length) {
this.voucherIcons.slice(voucherRange.length).map(i => i.setVisible(false));
}
}
clear() {
super.clear();
this.vouchersContainer.setVisible(false);
this.eraseCursor();
}
eraseCursor() {
if (this.cursorObj) {
this.cursorObj.destroy();
}
this.cursorObj = null;
}
}