Added "Skip Seen Dialogues" option (#1431)
* Added "Skip Dialogues" option (if at least 1 classic win) * Removed error sound and hide option instead when classic wins = 0 * Add skip dialogues option to Unlockables and show unlocked message on first classic win * Only skips seen dialogues, removed dialogue option from unlockables, seen dialogues get saved to local storage * oops * dont show charSprite when skipping a dialogue, small fixes --------- Co-authored-by: Frederik Hobein <frederik.hobein@nterra.com>
This commit is contained in:
parent
50c1f8aee4
commit
12bd22f2ca
|
@ -114,6 +114,8 @@ export default class BattleScene extends SceneBase {
|
|||
public experimentalSprites: boolean = false;
|
||||
public moveAnimations: boolean = true;
|
||||
public expGainsSpeed: integer = 0;
|
||||
public skipSeenDialogues: boolean = false;
|
||||
|
||||
/**
|
||||
* Defines the experience gain display mode.
|
||||
*
|
||||
|
|
|
@ -959,14 +959,15 @@ export class EncounterPhase extends BattlePhase {
|
|||
if (!encounterMessages?.length) {
|
||||
doSummon();
|
||||
} else {
|
||||
let message: string;
|
||||
this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(encounterMessages), this.scene.currentBattle.waveIndex);
|
||||
|
||||
const showDialogueAndSummon = () => {
|
||||
let message: string;
|
||||
this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(encounterMessages), this.scene.currentBattle.waveIndex);
|
||||
this.scene.ui.showDialogue(message, trainer.getName(TrainerSlot.NONE,true), null, () => {
|
||||
this.scene.charSprite.hide().then(() => this.scene.hideFieldOverlay(250).then(() => doSummon()));
|
||||
});
|
||||
};
|
||||
if (this.scene.currentBattle.trainer.config.hasCharSprite) {
|
||||
if (this.scene.currentBattle.trainer.config.hasCharSprite && !this.scene.ui.shouldSkipDialogue(message)) {
|
||||
this.scene.showFieldOverlay(500).then(() => this.scene.charSprite.showCharacter(trainer.getKey(), getCharVariantFromDialogue(encounterMessages[0])).then(() => showDialogueAndSummon()));
|
||||
} else {
|
||||
showDialogueAndSummon();
|
||||
|
@ -3789,21 +3790,18 @@ export class TrainerVictoryPhase extends BattlePhase {
|
|||
|
||||
this.scene.ui.showText(i18next.t("battle:trainerDefeated", { trainerName: this.scene.currentBattle.trainer.getName(TrainerSlot.NONE, true) }), null, () => {
|
||||
const victoryMessages = this.scene.currentBattle.trainer.getVictoryMessages();
|
||||
const showMessage = () => {
|
||||
let message: string;
|
||||
this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(victoryMessages), this.scene.currentBattle.waveIndex);
|
||||
const messagePages = message.split(/\$/g).map(m => m.trim());
|
||||
let message: string;
|
||||
this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(victoryMessages), this.scene.currentBattle.waveIndex);
|
||||
|
||||
for (let p = messagePages.length - 1; p >= 0; p--) {
|
||||
const originalFunc = showMessageOrEnd;
|
||||
showMessageOrEnd = () => this.scene.ui.showDialogue(messagePages[p], this.scene.currentBattle.trainer.getName(), null, originalFunc);
|
||||
}
|
||||
const showMessage = () => {
|
||||
const originalFunc = showMessageOrEnd;
|
||||
showMessageOrEnd = () => this.scene.ui.showDialogue(message, this.scene.currentBattle.trainer.getName(), null, originalFunc);
|
||||
|
||||
showMessageOrEnd();
|
||||
};
|
||||
let showMessageOrEnd = () => this.end();
|
||||
if (victoryMessages?.length) {
|
||||
if (this.scene.currentBattle.trainer.config.hasCharSprite) {
|
||||
if (this.scene.currentBattle.trainer.config.hasCharSprite && !this.scene.ui.shouldSkipDialogue(message)) {
|
||||
const originalFunc = showMessageOrEnd;
|
||||
showMessageOrEnd = () => this.scene.charSprite.hide().then(() => this.scene.hideFieldOverlay(250).then(() => originalFunc()));
|
||||
this.scene.showFieldOverlay(500).then(() => this.scene.charSprite.showCharacter(this.scene.currentBattle.trainer.getKey(), getCharVariantFromDialogue(victoryMessages[0])).then(() => showMessage()));
|
||||
|
@ -4014,19 +4012,27 @@ export class GameOverPhase extends BattlePhase {
|
|||
};
|
||||
|
||||
if (this.victory && this.scene.gameMode.isClassic) {
|
||||
this.scene.ui.fadeIn(500).then(() => {
|
||||
this.scene.charSprite.showCharacter(`rival_${this.scene.gameData.gender === PlayerGender.FEMALE ? "m" : "f"}`, getCharVariantFromDialogue(miscDialogue.ending[this.scene.gameData.gender === PlayerGender.FEMALE ? 0 : 1])).then(() => {
|
||||
this.scene.ui.showDialogue(miscDialogue.ending[this.scene.gameData.gender === PlayerGender.FEMALE ? 0 : 1], this.scene.gameData.gender === PlayerGender.FEMALE ? trainerConfigs[TrainerType.RIVAL].name : trainerConfigs[TrainerType.RIVAL].nameFemale, null, () => {
|
||||
this.scene.ui.fadeOut(500).then(() => {
|
||||
this.scene.charSprite.hide().then(() => {
|
||||
const endCardPhase = new EndCardPhase(this.scene);
|
||||
this.scene.unshiftPhase(endCardPhase);
|
||||
clear(endCardPhase);
|
||||
const message = miscDialogue.ending[this.scene.gameData.gender === PlayerGender.FEMALE ? 0 : 1];
|
||||
|
||||
if (!this.scene.ui.shouldSkipDialogue(message)) {
|
||||
this.scene.ui.fadeIn(500).then(() => {
|
||||
this.scene.charSprite.showCharacter(`rival_${this.scene.gameData.gender === PlayerGender.FEMALE ? "m" : "f"}`, getCharVariantFromDialogue(miscDialogue.ending[this.scene.gameData.gender === PlayerGender.FEMALE ? 0 : 1])).then(() => {
|
||||
this.scene.ui.showDialogue(message, this.scene.gameData.gender === PlayerGender.FEMALE ? trainerConfigs[TrainerType.RIVAL].name : trainerConfigs[TrainerType.RIVAL].nameFemale, null, () => {
|
||||
this.scene.ui.fadeOut(500).then(() => {
|
||||
this.scene.charSprite.hide().then(() => {
|
||||
const endCardPhase = new EndCardPhase(this.scene);
|
||||
this.scene.unshiftPhase(endCardPhase);
|
||||
clear(endCardPhase);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
const endCardPhase = new EndCardPhase(this.scene);
|
||||
this.scene.unshiftPhase(endCardPhase);
|
||||
clear(endCardPhase);
|
||||
}
|
||||
} else {
|
||||
clear();
|
||||
}
|
||||
|
|
|
@ -40,7 +40,8 @@ export enum GameDataType {
|
|||
SYSTEM,
|
||||
SESSION,
|
||||
SETTINGS,
|
||||
TUTORIALS
|
||||
TUTORIALS,
|
||||
SEEN_DIALOGUES
|
||||
}
|
||||
|
||||
export enum PlayerGender {
|
||||
|
@ -68,6 +69,8 @@ export function getDataTypeKey(dataType: GameDataType, slotId: integer = 0): str
|
|||
return "settings";
|
||||
case GameDataType.TUTORIALS:
|
||||
return "tutorials";
|
||||
case GameDataType.SEEN_DIALOGUES:
|
||||
return "seenDialogues";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,6 +204,10 @@ export interface TutorialFlags {
|
|||
[key: string]: boolean
|
||||
}
|
||||
|
||||
export interface SeenDialogues {
|
||||
[key: string]: boolean;
|
||||
}
|
||||
|
||||
const systemShortKeys = {
|
||||
seenAttr: "$sa",
|
||||
caughtAttr: "$ca",
|
||||
|
@ -716,9 +723,10 @@ export class GameData {
|
|||
}
|
||||
|
||||
public saveTutorialFlag(tutorial: Tutorial, flag: boolean): boolean {
|
||||
const key = getDataTypeKey(GameDataType.TUTORIALS);
|
||||
let tutorials: object = {};
|
||||
if (localStorage.hasOwnProperty("tutorials")) {
|
||||
tutorials = JSON.parse(localStorage.getItem("tutorials"));
|
||||
if (localStorage.hasOwnProperty(key)) {
|
||||
tutorials = JSON.parse(localStorage.getItem(key));
|
||||
}
|
||||
|
||||
Object.keys(Tutorial).map(t => t as Tutorial).forEach(t => {
|
||||
|
@ -730,20 +738,21 @@ export class GameData {
|
|||
}
|
||||
});
|
||||
|
||||
localStorage.setItem("tutorials", JSON.stringify(tutorials));
|
||||
localStorage.setItem(key, JSON.stringify(tutorials));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public getTutorialFlags(): TutorialFlags {
|
||||
const key = getDataTypeKey(GameDataType.TUTORIALS);
|
||||
const ret: TutorialFlags = {};
|
||||
Object.values(Tutorial).map(tutorial => tutorial as Tutorial).forEach(tutorial => ret[Tutorial[tutorial]] = false);
|
||||
|
||||
if (!localStorage.hasOwnProperty("tutorials")) {
|
||||
if (!localStorage.hasOwnProperty(key)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const tutorials = JSON.parse(localStorage.getItem("tutorials"));
|
||||
const tutorials = JSON.parse(localStorage.getItem(key));
|
||||
|
||||
for (const tutorial of Object.keys(tutorials)) {
|
||||
ret[tutorial] = tutorials[tutorial];
|
||||
|
@ -752,6 +761,34 @@ export class GameData {
|
|||
return ret;
|
||||
}
|
||||
|
||||
public saveSeenDialogue(dialogue: string): boolean {
|
||||
const key = getDataTypeKey(GameDataType.SEEN_DIALOGUES);
|
||||
const dialogues: object = this.getSeenDialogues();
|
||||
|
||||
dialogues[dialogue] = true;
|
||||
localStorage.setItem(key, JSON.stringify(dialogues));
|
||||
console.log("Dialogue saved as seen:", dialogue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public getSeenDialogues(): SeenDialogues {
|
||||
const key = getDataTypeKey(GameDataType.SEEN_DIALOGUES);
|
||||
const ret: SeenDialogues = {};
|
||||
|
||||
if (!localStorage.hasOwnProperty(key)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const dialogues = JSON.parse(localStorage.getItem(key));
|
||||
|
||||
for (const dialogue of Object.keys(dialogues)) {
|
||||
ret[dialogue] = dialogues[dialogue];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private getSessionSaveData(scene: BattleScene): SessionSaveData {
|
||||
return {
|
||||
seed: scene.seed,
|
||||
|
|
|
@ -19,6 +19,7 @@ export enum Setting {
|
|||
Window_Type = "WINDOW_TYPE",
|
||||
Tutorials = "TUTORIALS",
|
||||
Enable_Retries = "ENABLE_RETRIES",
|
||||
Skip_Seen_Dialogues = "SKIP_SEEN_DIALOGUES",
|
||||
Candy_Upgrade_Notification = "CANDY_UPGRADE_NOTIFICATION",
|
||||
Candy_Upgrade_Display = "CANDY_UPGRADE_DISPLAY",
|
||||
Money_Format = "MONEY_FORMAT",
|
||||
|
@ -54,6 +55,7 @@ export const settingOptions: SettingOptions = {
|
|||
[Setting.Window_Type]: new Array(5).fill(null).map((_, i) => (i + 1).toString()),
|
||||
[Setting.Tutorials]: ["Off", "On"],
|
||||
[Setting.Enable_Retries]: ["Off", "On"],
|
||||
[Setting.Skip_Seen_Dialogues]: ["Off", "On"],
|
||||
[Setting.Candy_Upgrade_Notification]: ["Off", "Passives Only", "On"],
|
||||
[Setting.Candy_Upgrade_Display]: ["Icon", "Animation"],
|
||||
[Setting.Money_Format]: ["Normal", "Abbreviated"],
|
||||
|
@ -81,6 +83,7 @@ export const settingDefaults: SettingDefaults = {
|
|||
[Setting.Window_Type]: 0,
|
||||
[Setting.Tutorials]: 1,
|
||||
[Setting.Enable_Retries]: 0,
|
||||
[Setting.Skip_Seen_Dialogues]: 0,
|
||||
[Setting.Candy_Upgrade_Notification]: 0,
|
||||
[Setting.Candy_Upgrade_Display]: 0,
|
||||
[Setting.Money_Format]: 0,
|
||||
|
@ -198,6 +201,9 @@ export function setSetting(scene: BattleScene, setting: Setting, value: integer)
|
|||
case Setting.Vibration:
|
||||
scene.enableVibration = settingOptions[setting][value] !== "Disabled" && hasTouchscreen();
|
||||
break;
|
||||
case Setting.Skip_Seen_Dialogues:
|
||||
scene.skipSeenDialogues = settingOptions[setting][value] === "On";
|
||||
break;
|
||||
case Setting.Language:
|
||||
if (value) {
|
||||
if (scene.ui) {
|
||||
|
|
37
src/ui/ui.ts
37
src/ui/ui.ts
|
@ -259,15 +259,26 @@ export default class UI extends Phaser.GameObjects.Container {
|
|||
}
|
||||
// Add the prefix to the text
|
||||
const localizationKey = playerGenderPrefix + text;
|
||||
|
||||
// Get localized dialogue (if available)
|
||||
let hasi18n = false;
|
||||
if (i18next.exists(localizationKey as ParseKeys) ) {
|
||||
|
||||
|
||||
text = i18next.t(localizationKey as ParseKeys);
|
||||
hasi18n = true;
|
||||
|
||||
// Skip dialogue if the player has enabled the option and the dialogue has been already seen
|
||||
if ((this.scene as BattleScene).skipSeenDialogues && (this.scene as BattleScene).gameData.getSeenDialogues()[localizationKey] === true) {
|
||||
console.log(`Dialogue ${localizationKey} skipped`);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
let showMessageAndCallback = () => {
|
||||
hasi18n && (this.scene as BattleScene).gameData.saveSeenDialogue(localizationKey);
|
||||
callback();
|
||||
};
|
||||
if (text.indexOf("$") > -1) {
|
||||
const messagePages = text.split(/\$/g).map(m => m.trim());
|
||||
let showMessageAndCallback = () => callback();
|
||||
for (let p = messagePages.length - 1; p >= 0; p--) {
|
||||
const originalFunc = showMessageAndCallback;
|
||||
showMessageAndCallback = () => this.showDialogue(messagePages[p], name, null, originalFunc);
|
||||
|
@ -276,13 +287,29 @@ export default class UI extends Phaser.GameObjects.Container {
|
|||
} else {
|
||||
const handler = this.getHandler();
|
||||
if (handler instanceof MessageUiHandler) {
|
||||
(handler as MessageUiHandler).showDialogue(text, name, delay, callback, callbackDelay, true, promptDelay);
|
||||
(handler as MessageUiHandler).showDialogue(text, name, delay, showMessageAndCallback, callbackDelay, true, promptDelay);
|
||||
} else {
|
||||
this.getMessageHandler().showDialogue(text, name, delay, callback, callbackDelay, true, promptDelay);
|
||||
this.getMessageHandler().showDialogue(text, name, delay, showMessageAndCallback, callbackDelay, true, promptDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shouldSkipDialogue(text): boolean {
|
||||
let playerGenderPrefix = "PGM";
|
||||
if ((this.scene as BattleScene).gameData.gender === PlayerGender.FEMALE) {
|
||||
playerGenderPrefix = "PGF";
|
||||
}
|
||||
|
||||
const key = playerGenderPrefix + text;
|
||||
|
||||
if (i18next.exists(key as ParseKeys) ) {
|
||||
if ((this.scene as BattleScene).skipSeenDialogues && (this.scene as BattleScene).gameData.getSeenDialogues()[key] === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
showTooltip(title: string, content: string, overlap?: boolean): void {
|
||||
this.tooltipContainer.setVisible(true);
|
||||
this.tooltipTitle.setText(title || "");
|
||||
|
|
Loading…
Reference in New Issue