mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-06-13 13:04:03 +00:00
Achievements accessable in main menu
This commit is contained in:
parent
9ef35a2b1c
commit
db8cd2cd77
@ -119,3 +119,19 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#state_AchievementsState {
|
||||
#ingame_HUD_Achievements {
|
||||
z-index: unset;
|
||||
overflow-y: scroll;
|
||||
position: relative;
|
||||
background-color: unset;
|
||||
max-height: 100%;
|
||||
align-items: unset;
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
grid-auto-flow: column;
|
||||
@include S(grid-gap, 15px);
|
||||
|
||||
.achievementsButton,
|
||||
.settingsButton,
|
||||
.exitAppButton,
|
||||
.languageChoose {
|
||||
@ -34,6 +35,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.achievementsButton {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/achievements.png");
|
||||
}
|
||||
|
||||
.exitAppButton {
|
||||
/* @load-async */
|
||||
background-image: uiResource("icons/main_menu_exit.png");
|
||||
|
@ -31,6 +31,7 @@ import { PreloadState } from "./states/preload";
|
||||
import { SettingsState } from "./states/settings";
|
||||
import { ShapezGameAnalytics } from "./platform/browser/game_analytics";
|
||||
import { RestrictionManager } from "./core/restriction_manager";
|
||||
import { AchievementsState } from "./states/achievements";
|
||||
|
||||
/**
|
||||
* @typedef {import("./platform/achievement_provider").AchievementProviderInterface} AchievementProviderInterface
|
||||
@ -159,6 +160,7 @@ export class Application {
|
||||
KeybindingsState,
|
||||
AboutState,
|
||||
ChangelogState,
|
||||
AchievementsState,
|
||||
];
|
||||
|
||||
for (let i = 0; i < states.length; ++i) {
|
||||
|
@ -318,6 +318,15 @@ export class AchievementProviderInterface {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks already unlocked achievements.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
unlockUnlocked() {
|
||||
abstract;
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opportunity to do additional initialization work with the GameRoot.
|
||||
* @param {GameRoot} root
|
||||
|
@ -115,6 +115,20 @@ export class BrowserAchievementProvider extends AchievementProviderInterface {
|
||||
}
|
||||
}
|
||||
|
||||
unlockUnlocked() {
|
||||
let promise = Promise.resolve();
|
||||
|
||||
//Unlock already unlocked
|
||||
for (let i = 0; i < this.storage.currentData.unlocked.length; i++) {
|
||||
promise.then(() => {
|
||||
const achievement = this.storage.currentData.unlocked[i];
|
||||
this.collection.unlock(achievement, null, true);
|
||||
});
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
/** @returns {Promise<void>} */
|
||||
initialize() {
|
||||
return Promise.resolve();
|
||||
|
@ -132,6 +132,22 @@ export class SteamAchievementProvider extends AchievementProviderInterface {
|
||||
});
|
||||
}
|
||||
|
||||
unlockUnlocked() {
|
||||
let promise = Promise.resolve();
|
||||
|
||||
//Unlock already unlocked
|
||||
for (const id in ACHIEVEMENT_IDS) {
|
||||
promise.then(() =>
|
||||
this.ipc.invoke("steam:get-achievement", ACHIEVEMENT_IDS[id]).then(is_achieved => {
|
||||
if (is_achieved) this.collection.unlock(id, null, true);
|
||||
return Promise.resolve();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {Promise<void>}
|
||||
|
180
src/js/states/achievements.js
Normal file
180
src/js/states/achievements.js
Normal file
@ -0,0 +1,180 @@
|
||||
import { TextualGameState } from "../core/textual_game_state";
|
||||
import { makeDiv } from "../core/utils";
|
||||
import {
|
||||
ACHIEVEMENTS,
|
||||
enum_achievement_mappings,
|
||||
HIDDEN_ACHIEVEMENTS,
|
||||
} from "../platform/achievement_provider";
|
||||
import { T } from "../translations";
|
||||
|
||||
export class AchievementsState extends TextualGameState {
|
||||
constructor() {
|
||||
super("AchievementsState");
|
||||
}
|
||||
|
||||
getStateHeaderTitle() {
|
||||
return T.ingame.achievements.title;
|
||||
}
|
||||
|
||||
onEnter(payload) {
|
||||
this.app.achievementProvider.unlockUnlocked();
|
||||
|
||||
this.parent = makeDiv(document.querySelector(".content.mainContent"), "ingame_HUD_Achievements", [
|
||||
"ingameDialog",
|
||||
]);
|
||||
this.contentDiv = makeDiv(this.parent, null, ["content"]);
|
||||
this.achievementToElements = {};
|
||||
|
||||
// ACHIEVEMENTS
|
||||
for (const achievementKey in ACHIEVEMENTS) {
|
||||
const handle = {};
|
||||
|
||||
// Wrapper
|
||||
handle.elem = makeDiv(this.contentDiv, null, ["achievement"]);
|
||||
|
||||
// Icon
|
||||
handle.icon = makeDiv(handle.elem, null, ["icon"]);
|
||||
handle.icon.setAttribute("data-icon", "achievements/" + achievementKey + ".png");
|
||||
|
||||
// Info
|
||||
handle.info = makeDiv(handle.elem, null, ["info"]);
|
||||
|
||||
// Title
|
||||
const title = makeDiv(handle.info, null, ["title"], T.achievements[achievementKey].title);
|
||||
|
||||
// Description
|
||||
handle.elemDescription = makeDiv(
|
||||
handle.info,
|
||||
null,
|
||||
["description"],
|
||||
T.achievements[achievementKey].description
|
||||
);
|
||||
|
||||
// Reset button
|
||||
handle.resetButton = document.createElement("button");
|
||||
handle.resetButton.classList.add("reset", "styledButton");
|
||||
handle.resetButton.innerText = T.ingame.achievements.buttonReset;
|
||||
handle.elem.appendChild(handle.resetButton);
|
||||
|
||||
this.trackClicks(handle.resetButton, () => {
|
||||
this.app.achievementProvider.collection.lock(
|
||||
achievementKey,
|
||||
enum_achievement_mappings[ACHIEVEMENTS[achievementKey]]
|
||||
);
|
||||
});
|
||||
|
||||
// Assign handle
|
||||
this.achievementToElements[achievementKey] = handle;
|
||||
}
|
||||
|
||||
this.hiddenElement = {};
|
||||
// Wrapper
|
||||
this.hiddenElement.hidden = makeDiv(this.contentDiv, null, ["achievement"]);
|
||||
|
||||
// Icon
|
||||
this.hiddenElement.icon = makeDiv(this.hiddenElement.hidden, null, ["icon"]);
|
||||
this.hiddenElement.icon.setAttribute("data-icon", "achievements/hidden.png");
|
||||
|
||||
// Info
|
||||
this.hiddenElement.info = makeDiv(this.hiddenElement.hidden, null, ["info"]);
|
||||
|
||||
// Title
|
||||
this.hiddenElement.title = makeDiv(
|
||||
this.hiddenElement.info,
|
||||
null,
|
||||
["title"],
|
||||
T.achievements.hidden.title
|
||||
);
|
||||
|
||||
// Description
|
||||
this.hiddenElement.description = makeDiv(
|
||||
this.hiddenElement.info,
|
||||
null,
|
||||
["description"],
|
||||
T.achievements.hidden.description.replace("<amountHidden>", HIDDEN_ACHIEVEMENTS.length + "")
|
||||
);
|
||||
|
||||
this.resetElement = {};
|
||||
|
||||
// Wrapper
|
||||
this.resetElement.elem = makeDiv(this.contentDiv, null, ["achievement", "reset", "unlocked"]);
|
||||
|
||||
// Icon
|
||||
this.resetElement.icon = makeDiv(this.resetElement.elem, null, ["icon"]);
|
||||
this.resetElement.icon.setAttribute("data-icon", "achievements/reset.png");
|
||||
|
||||
// Info
|
||||
this.resetElement.info = makeDiv(this.resetElement.elem, null, ["info"]);
|
||||
|
||||
// Title
|
||||
this.resetElement.title = makeDiv(
|
||||
this.resetElement.info,
|
||||
null,
|
||||
["title"],
|
||||
T.achievements.reset.title
|
||||
);
|
||||
|
||||
// Description
|
||||
this.resetElement.description = makeDiv(
|
||||
this.resetElement.info,
|
||||
null,
|
||||
["description"],
|
||||
T.achievements.reset.description
|
||||
);
|
||||
|
||||
// Reset button
|
||||
this.resetElement.resetButton = document.createElement("button");
|
||||
this.resetElement.resetButton.classList.add("reset", "styledButton");
|
||||
this.resetElement.resetButton.innerText = T.ingame.achievements.buttonReset;
|
||||
this.resetElement.elem.appendChild(this.resetElement.resetButton);
|
||||
this.trackClicks(this.resetElement.resetButton, () => {
|
||||
const signals = this.dialogs.showWarning(
|
||||
T.dialogs.resetAchievements.title,
|
||||
T.dialogs.resetAchievements.description,
|
||||
["cancel:bad:escape", "ok:good:enter"]
|
||||
);
|
||||
signals.ok.add(() => {
|
||||
for (const achievementKey in ACHIEVEMENTS) {
|
||||
if (!this.app.achievementProvider.collection.map.has(achievementKey))
|
||||
this.app.achievementProvider.collection.lock(
|
||||
achievementKey,
|
||||
enum_achievement_mappings[ACHIEVEMENTS[achievementKey]]
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onRender(dt) {
|
||||
let unlocked = 0;
|
||||
let hidden = 0;
|
||||
for (const achievementKey in this.achievementToElements) {
|
||||
const handle = this.achievementToElements[achievementKey];
|
||||
|
||||
//Check if user has achievement
|
||||
if (!this.app.achievementProvider.collection.map.get(ACHIEVEMENTS[achievementKey])) {
|
||||
if (!handle.elem.classList.contains("unlocked")) handle.elem.classList.add("unlocked");
|
||||
if (handle.elem.classList.contains("hidden")) handle.elem.classList.remove("hidden");
|
||||
unlocked++;
|
||||
} else {
|
||||
if (handle.elem.classList.contains("unlocked")) handle.elem.classList.remove("unlocked");
|
||||
|
||||
if (HIDDEN_ACHIEVEMENTS.includes(ACHIEVEMENTS[achievementKey])) {
|
||||
if (!handle.elem.classList.contains("hidden")) handle.elem.classList.add("hidden");
|
||||
hidden++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.hiddenElement.description.innerHTML = T.achievements.hidden.description.replace(
|
||||
"<amountHidden>",
|
||||
hidden + ""
|
||||
);
|
||||
|
||||
if (unlocked > 0) {
|
||||
if (!this.resetElement.elem.classList.contains("unlocked"))
|
||||
this.resetElement.elem.classList.add("unlocked");
|
||||
} else if (this.resetElement.elem.classList.contains("unlocked"))
|
||||
this.resetElement.elem.classList.remove("unlocked");
|
||||
}
|
||||
}
|
@ -48,6 +48,7 @@ export class MainMenuState extends GameState {
|
||||
: `<button class="languageChoose" data-languageicon="${this.app.settings.getLanguage()}"></button>`
|
||||
}
|
||||
|
||||
<button class="achievementsButton"></button>
|
||||
<button class="settingsButton"></button>
|
||||
${
|
||||
G_IS_STANDALONE || G_IS_DEV
|
||||
@ -232,6 +233,7 @@ export class MainMenuState extends GameState {
|
||||
});
|
||||
|
||||
this.trackClicks(qs(".settingsButton"), this.onSettingsButtonClicked);
|
||||
this.trackClicks(qs(".achievementsButton"), this.onAchievementsButtonClicked);
|
||||
|
||||
if (!G_CHINA_VERSION) {
|
||||
this.trackClicks(qs(".languageChoose"), this.onLanguageChooseClicked);
|
||||
@ -569,6 +571,10 @@ export class MainMenuState extends GameState {
|
||||
this.moveToState("SettingsState");
|
||||
}
|
||||
|
||||
onAchievementsButtonClicked() {
|
||||
this.moveToState("AchievementsState");
|
||||
}
|
||||
|
||||
onTranslationHelpLinkClicked() {
|
||||
this.app.analytics.trackUiClick("translation_help_link");
|
||||
this.app.platformWrapper.openExternalLink(
|
||||
|
Loading…
Reference in New Issue
Block a user