mirror of
https://github.com/tobspr/shapez.io.git
synced 2026-03-02 03:39:21 +00:00
Merge steam-demo branch
This commit is contained in:
@@ -52,6 +52,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.playtimeDisclaimer {
|
||||
@include S(margin-bottom, 10px);
|
||||
@include PlainText;
|
||||
}
|
||||
|
||||
.steamLinkButton {
|
||||
@include IncreasedClickArea(5px);
|
||||
@include S(margin, 0);
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
#ingame_HUD_CatMemes {
|
||||
#ingame_HUD_SteamCapsule {
|
||||
position: absolute;
|
||||
@include S(width, 150px);
|
||||
@include S(height, 150px);
|
||||
background: transparent center center / contain no-repeat;
|
||||
@include S(height, 119px);
|
||||
background: transparent center center / cover no-repeat;
|
||||
|
||||
right: 0;
|
||||
pointer-events: all;
|
||||
overflow: hidden;
|
||||
@include S(right, 10px);
|
||||
|
||||
border: D(2px) solid #000;
|
||||
@include S(border-radius, $globalBorderRadius);
|
||||
cursor: pointer;
|
||||
@include S(bottom, 150px);
|
||||
|
||||
& {
|
||||
@@ -12,6 +18,10 @@
|
||||
background-image: uiResource("res/ui/memes/cat1.png") !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
@include InlineAnimation(0.5s ease-in-out) {
|
||||
0% {
|
||||
transform: translateX(100%);
|
||||
@@ -57,7 +57,7 @@
|
||||
@import "ingame_hud/shape_viewer";
|
||||
@import "ingame_hud/sandbox_controller";
|
||||
@import "ingame_hud/standalone_advantages";
|
||||
@import "ingame_hud/cat_memes";
|
||||
@import "ingame_hud/steam_capsule";
|
||||
@import "ingame_hud/puzzle_back_to_menu";
|
||||
@import "ingame_hud/puzzle_editor_review";
|
||||
@import "ingame_hud/puzzle_dlc_logo";
|
||||
@@ -105,6 +105,7 @@ ingame_HUD_Waypoints_Hint,
|
||||
ingame_HUD_WatermarkClicker,
|
||||
ingame_HUD_Watermark,
|
||||
ingame_HUD_ColorBlindBelowTileHelper,
|
||||
ingame_HUD_SteamCapsule,
|
||||
ingame_HUD_SandboxController,
|
||||
|
||||
// Overlays
|
||||
@@ -118,8 +119,7 @@ ingame_HUD_StandaloneAdvantages,
|
||||
ingame_HUD_UnlockNotification,
|
||||
ingame_HUD_PuzzleCompleteNotification,
|
||||
ingame_HUD_SettingsMenu,
|
||||
ingame_HUD_ModalDialogs,
|
||||
ingame_HUD_CatMemes;
|
||||
ingame_HUD_ModalDialogs;
|
||||
|
||||
$zindex: 100;
|
||||
|
||||
@@ -132,7 +132,7 @@ $zindex: 100;
|
||||
}
|
||||
|
||||
body.uiHidden {
|
||||
> div {
|
||||
> div:not(.ingameDialog):not(#ingame_HUD_SettingsMenu):not(#ingame_HUD_ModalDialogs):not(#ingame_HUD_UnlockNotification):not(#ingame_HUD_PuzzleCompleteNotification) {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
}
|
||||
|
||||
.standaloneBanner {
|
||||
background: rgb(216, 79, 76);
|
||||
background: rgba(12, 168, 93, 0.957);
|
||||
@include S(border-radius, $globalBorderRadius);
|
||||
box-sizing: border-box;
|
||||
@include S(padding, 15px);
|
||||
@@ -129,8 +129,18 @@
|
||||
@include S(padding-left, 20px);
|
||||
li {
|
||||
@include Text;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
strong {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.playtimeDisclaimer {
|
||||
color: #fff;
|
||||
@include S(margin-top, 15px);
|
||||
@include SuperSmallText;
|
||||
}
|
||||
|
||||
.steamLink {
|
||||
align-self: center;
|
||||
@@ -153,6 +163,12 @@
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
@include InlineAnimation(1s ease-in-out infinite) {
|
||||
50% {
|
||||
transform: scale(1.02, 1.03);
|
||||
}
|
||||
}
|
||||
|
||||
> .discount {
|
||||
position: absolute;
|
||||
@include S(top, -7px);
|
||||
@@ -186,9 +202,8 @@
|
||||
img {
|
||||
@include S(width, 300px);
|
||||
}
|
||||
|
||||
position: relative;
|
||||
@include S(left, -22px);
|
||||
@include S(left, -8px);
|
||||
|
||||
.updateLabel {
|
||||
position: absolute;
|
||||
@@ -677,25 +692,19 @@
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: grid;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
justify-content: center;
|
||||
align-items: flex-end;
|
||||
width: 100%;
|
||||
grid-template-columns: auto auto auto 1fr;
|
||||
@include S(padding, 10px);
|
||||
box-sizing: border-box;
|
||||
@include S(grid-gap, 4px);
|
||||
|
||||
&.noLinks {
|
||||
grid-template-columns: auto 1fr;
|
||||
}
|
||||
|
||||
&.wegameDisclaimer {
|
||||
@include SuperSmallText;
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
text-align: center;
|
||||
|
||||
> .disclaimer {
|
||||
|
||||
@@ -47,6 +47,10 @@
|
||||
align-self: end;
|
||||
margin-top: auto;
|
||||
|
||||
&.noabout {
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
@include StyleBelowWidth($layoutBreak) {
|
||||
margin-top: 0;
|
||||
display: grid;
|
||||
|
||||
@@ -41,7 +41,6 @@ import { ModsState } from "./states/mods";
|
||||
|
||||
/**
|
||||
* @typedef {import("./platform/achievement_provider").AchievementProviderInterface} AchievementProviderInterface
|
||||
* @typedef {import("./platform/game_analytics").GameAnalyticsInterface} GameAnalyticsInterface
|
||||
* @typedef {import("./platform/sound").SoundInterface} SoundInterface
|
||||
* @typedef {import("./platform/storage").StorageInterface} StorageInterface
|
||||
*/
|
||||
@@ -118,7 +117,7 @@ export class Application {
|
||||
/** @type {AnalyticsInterface} */
|
||||
this.analytics = null;
|
||||
|
||||
/** @type {GameAnalyticsInterface} */
|
||||
/** @type {ShapezGameAnalytics} */
|
||||
this.gameAnalytics = null;
|
||||
|
||||
this.initPlatformDependentInstances();
|
||||
@@ -227,12 +226,10 @@ export class Application {
|
||||
window.addEventListener("resize", () => this.checkResize(), true);
|
||||
window.addEventListener("orientationchange", () => this.checkResize(), true);
|
||||
|
||||
if (!G_IS_MOBILE_APP && !IS_MOBILE) {
|
||||
window.addEventListener("mousemove", this.handleMousemove.bind(this));
|
||||
window.addEventListener("mouseout", this.handleMousemove.bind(this));
|
||||
window.addEventListener("mouseover", this.handleMousemove.bind(this));
|
||||
window.addEventListener("mouseleave", this.handleMousemove.bind(this));
|
||||
}
|
||||
window.addEventListener("mousemove", this.handleMousemove.bind(this));
|
||||
window.addEventListener("mouseout", this.handleMousemove.bind(this));
|
||||
window.addEventListener("mouseover", this.handleMousemove.bind(this));
|
||||
window.addEventListener("mouseleave", this.handleMousemove.bind(this));
|
||||
|
||||
// Unload events
|
||||
window.addEventListener("beforeunload", this.onBeforeUnload.bind(this), true);
|
||||
|
||||
@@ -17,6 +17,10 @@ export function getLogoSprite() {
|
||||
return "logo_wegame.png";
|
||||
}
|
||||
|
||||
if (G_IS_STEAM_DEMO) {
|
||||
return "logo_demo.png";
|
||||
}
|
||||
|
||||
if (G_CHINA_VERSION) {
|
||||
return "logo_cn.png";
|
||||
}
|
||||
|
||||
@@ -117,13 +117,7 @@ export const globalConfig = {
|
||||
rendering: {},
|
||||
debug: require("./config.local").default,
|
||||
|
||||
currentDiscount: {
|
||||
amount: 50,
|
||||
from: Date.parse("May 23 2022 17:00 +2:00"),
|
||||
until: Date.parse("May 30 2022 23:59 +2:00"),
|
||||
|
||||
active: false, // computed later
|
||||
},
|
||||
currentDiscount: 0,
|
||||
|
||||
// Secret vars
|
||||
info: {
|
||||
@@ -169,8 +163,3 @@ if (G_IS_DEV && globalConfig.debug.noArtificialDelays) {
|
||||
globalConfig.warmupTimeSecondsFast = 0;
|
||||
globalConfig.warmupTimeSecondsRegular = 0;
|
||||
}
|
||||
|
||||
globalConfig.currentDiscount.active =
|
||||
!G_IS_STANDALONE &&
|
||||
new Date().getTime() < globalConfig.currentDiscount.until &&
|
||||
new Date().getTime() > globalConfig.currentDiscount.from;
|
||||
|
||||
@@ -19,12 +19,10 @@ export function setGlobalApp(app) {
|
||||
export const BUILD_OPTIONS = {
|
||||
HAVE_ASSERT: G_HAVE_ASSERT,
|
||||
APP_ENVIRONMENT: G_APP_ENVIRONMENT,
|
||||
TRACKING_ENDPOINT: G_TRACKING_ENDPOINT,
|
||||
CHINA_VERSION: G_CHINA_VERSION,
|
||||
WEGAME_VERSION: G_WEGAME_VERSION,
|
||||
IS_DEV: G_IS_DEV,
|
||||
IS_RELEASE: G_IS_RELEASE,
|
||||
IS_MOBILE_APP: G_IS_MOBILE_APP,
|
||||
IS_BROWSER: G_IS_BROWSER,
|
||||
IS_STANDALONE: G_IS_STANDALONE,
|
||||
BUILD_TIME: G_BUILD_TIME,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { Application } from "../application";
|
||||
/* typehints:end */
|
||||
import { ExplainedResult } from "./explained_result";
|
||||
import { queryParamOptions } from "./query_parameters";
|
||||
import { ReadWriteProxy } from "./read_write_proxy";
|
||||
|
||||
export class RestrictionManager extends ReadWriteProxy {
|
||||
@@ -56,13 +55,12 @@ export class RestrictionManager extends ReadWriteProxy {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isLimitedVersion() {
|
||||
if (G_IS_STANDALONE) {
|
||||
// Standalone is never limited
|
||||
return false;
|
||||
if (G_IS_STEAM_DEMO) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (queryParamOptions.embedProvider === "gamedistribution") {
|
||||
// also full version on gamedistribution
|
||||
if (G_IS_STANDALONE) {
|
||||
// Standalone is never limited
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,29 +2,6 @@ import { T } from "../translations";
|
||||
|
||||
const bigNumberSuffixTranslationKeys = ["thousands", "millions", "billions", "trillions"];
|
||||
|
||||
/**
|
||||
* Returns if this platform is android
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isAndroid() {
|
||||
if (!G_IS_MOBILE_APP) {
|
||||
return false;
|
||||
}
|
||||
const platform = window.device.platform;
|
||||
return platform === "Android" || platform === "amazon-fireos";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this platform is iOs
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isIos() {
|
||||
if (!G_IS_MOBILE_APP) {
|
||||
return false;
|
||||
}
|
||||
return window.device.platform === "iOS";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a platform name
|
||||
* @returns {"android" | "browser" | "ios" | "standalone" | "unknown"}
|
||||
@@ -34,10 +11,6 @@ export function getPlatformName() {
|
||||
return "standalone";
|
||||
} else if (G_IS_BROWSER) {
|
||||
return "browser";
|
||||
} else if (G_IS_MOBILE_APP && isAndroid()) {
|
||||
return "android";
|
||||
} else if (G_IS_MOBILE_APP && isIos()) {
|
||||
return "ios";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
@@ -456,7 +429,7 @@ export function isSupportedBrowser() {
|
||||
// and if not iOS Chrome check
|
||||
// so use the below updated condition
|
||||
|
||||
if (G_IS_MOBILE_APP || G_IS_STANDALONE) {
|
||||
if (G_IS_STANDALONE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
|
||||
const memeShowIntervalSeconds = 70 * 60;
|
||||
const memeShowDuration = 5;
|
||||
|
||||
export class HUDCatMemes extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
this.element = makeDiv(parent, "ingame_HUD_CatMemes");
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.domAttach = new DynamicDomAttach(this.root, this.element);
|
||||
}
|
||||
|
||||
update() {
|
||||
const now = this.root.time.realtimeNow();
|
||||
this.domAttach.update(now % memeShowIntervalSeconds > memeShowIntervalSeconds - memeShowDuration);
|
||||
}
|
||||
}
|
||||
@@ -125,7 +125,11 @@ export class HUDModalDialogs extends BaseHUDPart {
|
||||
|
||||
dialog.buttonSignals.getStandalone.add(() => {
|
||||
this.app.analytics.trackUiClick("demo_dialog_click");
|
||||
window.open(THIRDPARTY_URLS.stanaloneCampaignLink + "/shapez_demo_dialog");
|
||||
window.open(
|
||||
THIRDPARTY_URLS.stanaloneCampaignLink +
|
||||
"/shapez_demo_dialog" +
|
||||
(G_IS_STEAM_DEMO ? "_steamdemo" : "")
|
||||
);
|
||||
});
|
||||
|
||||
return dialog.buttonSignals;
|
||||
|
||||
@@ -5,8 +5,6 @@ import { T } from "../../../translations";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
|
||||
const showIntervalSeconds = 9 * 60;
|
||||
|
||||
export class HUDStandaloneAdvantages extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
this.background = makeDiv(parent, "ingame_HUD_StandaloneAdvantages", ["ingameDialog"]);
|
||||
@@ -33,10 +31,11 @@ export class HUDStandaloneAdvantages extends BaseHUDPart {
|
||||
</div>
|
||||
|
||||
<div class="lowerBar">
|
||||
<div class="playtimeDisclaimer">${T.demoBanners.playtimeDisclaimer}</div>
|
||||
<button class="steamLinkButton ${A_B_TESTING_LINK_TYPE}">
|
||||
${
|
||||
globalConfig.currentDiscount.active
|
||||
? `<span class='discount'>${globalConfig.currentDiscount.amount}% off!</span>`
|
||||
globalConfig.currentDiscount > 0
|
||||
? `<span class='discount'>${globalConfig.currentDiscount}% off!</span>`
|
||||
: ""
|
||||
}
|
||||
</button>
|
||||
@@ -46,13 +45,15 @@ export class HUDStandaloneAdvantages extends BaseHUDPart {
|
||||
);
|
||||
|
||||
this.trackClicks(this.contentDiv.querySelector("button.steamLinkButton"), () => {
|
||||
const discount = globalConfig.currentDiscount.active
|
||||
? "_discount" + globalConfig.currentDiscount.amount
|
||||
: "";
|
||||
const discount =
|
||||
globalConfig.currentDiscount > 0 ? "_discount" + globalConfig.currentDiscount : "";
|
||||
|
||||
this.root.app.analytics.trackUiClick("standalone_advantage_visit_steam");
|
||||
this.root.app.platformWrapper.openExternalLink(
|
||||
THIRDPARTY_URLS.stanaloneCampaignLink + "/shapez_std_advg" + discount
|
||||
THIRDPARTY_URLS.stanaloneCampaignLink +
|
||||
"/shapez_std_advg" +
|
||||
discount +
|
||||
(G_IS_STEAM_DEMO ? "_steamdemo" : "")
|
||||
);
|
||||
this.close();
|
||||
});
|
||||
@@ -62,6 +63,22 @@ export class HUDStandaloneAdvantages extends BaseHUDPart {
|
||||
});
|
||||
}
|
||||
|
||||
get showIntervalSeconds() {
|
||||
switch (this.root.app.gameAnalytics.abtVariant) {
|
||||
case "0":
|
||||
return 5 * 60;
|
||||
case "1":
|
||||
return 10 * 60;
|
||||
case "2":
|
||||
default:
|
||||
return 15 * 60;
|
||||
case "3":
|
||||
return 20 * 60;
|
||||
case "4":
|
||||
return 1e14;
|
||||
}
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.domAttach = new DynamicDomAttach(this.root, this.background, {
|
||||
attachClass: "visible",
|
||||
@@ -86,7 +103,7 @@ export class HUDStandaloneAdvantages extends BaseHUDPart {
|
||||
}
|
||||
|
||||
update() {
|
||||
if (!this.visible && this.root.time.now() - this.lastShown > showIntervalSeconds) {
|
||||
if (!this.visible && this.root.time.now() - this.lastShown > this.showIntervalSeconds) {
|
||||
this.show();
|
||||
}
|
||||
|
||||
|
||||
31
src/js/game/hud/parts/steam_capsule.js
Normal file
31
src/js/game/hud/parts/steam_capsule.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { globalConfig, THIRDPARTY_URLS } from "../../../core/config";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
|
||||
const showCapsuleAfter = 30 * 60;
|
||||
|
||||
export class HUDSteamCapsule extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
this.element = makeDiv(parent, "ingame_HUD_SteamCapsule");
|
||||
}
|
||||
|
||||
initialize() {
|
||||
const discount = globalConfig.currentDiscount > 0 ? "_discount" + globalConfig.currentDiscount : "";
|
||||
|
||||
this.domAttach = new DynamicDomAttach(this.root, this.element);
|
||||
|
||||
this.trackClicks(this.element, () => {
|
||||
this.root.app.platformWrapper.openExternalLink(
|
||||
THIRDPARTY_URLS.stanaloneCampaignLink +
|
||||
"/shapez_steamcapsule" +
|
||||
discount +
|
||||
(G_IS_STEAM_DEMO ? "_steamdemo" : "")
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
update() {
|
||||
this.domAttach.update(this.root.time.now() > showCapsuleAfter);
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
||||
<div class="rewardName">
|
||||
${T.ingame.levelCompleteNotification.unlockText.replace("<reward>", rewardName)}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="rewardDesc">
|
||||
${T.storyRewards[reward].desc}
|
||||
</div>
|
||||
@@ -131,6 +131,13 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
||||
|
||||
this.root.hud.signals.unlockNotificationFinished.dispatch();
|
||||
|
||||
if (
|
||||
this.root.hubGoals.level === 7 &&
|
||||
this.root.app.restrictionMgr.getIsStandaloneMarketingActive()
|
||||
) {
|
||||
this.root.hud.parts.standaloneAdvantages.show();
|
||||
}
|
||||
|
||||
if (!this.root.app.settings.getAllSettings().offerHints) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,66 +2,35 @@ import { globalConfig, THIRDPARTY_URLS } from "../../../core/config";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { T } from "../../../translations";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
|
||||
const watermarkShowIntervalSeconds = G_IS_DEV ? 120 : 7 * 60;
|
||||
const watermarkShowDuration = 5;
|
||||
|
||||
export class HUDWatermark extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
this.element = makeDiv(
|
||||
parent,
|
||||
"ingame_HUD_Watermark",
|
||||
[],
|
||||
`
|
||||
<strong>${T.ingame.watermark.title}</strong>
|
||||
<p>${T.ingame.watermark.desc}
|
||||
</p>
|
||||
|
||||
|
||||
`
|
||||
);
|
||||
|
||||
this.linkElement = makeDiv(
|
||||
parent,
|
||||
"ingame_HUD_WatermarkClicker",
|
||||
globalConfig.currentDiscount.active ? ["withDiscount"] : [],
|
||||
globalConfig.currentDiscount > 0 ? ["withDiscount"] : [],
|
||||
T.ingame.watermark.get_on_steam +
|
||||
(globalConfig.currentDiscount.active
|
||||
? `<span class='discount'>${globalConfig.currentDiscount.amount}% off!</span>`
|
||||
(globalConfig.currentDiscount > 0
|
||||
? `<span class='discount'>${globalConfig.currentDiscount}% off!</span>`
|
||||
: "")
|
||||
);
|
||||
this.trackClicks(this.linkElement, () => {
|
||||
this.root.app.analytics.trackUiClick("watermark_click_2_direct");
|
||||
const discount = globalConfig.currentDiscount.active
|
||||
? "_discount" + globalConfig.currentDiscount.amount
|
||||
: "";
|
||||
const discount =
|
||||
globalConfig.currentDiscount > 0 ? "_discount" + globalConfig.currentDiscount : "";
|
||||
|
||||
this.root.app.platformWrapper.openExternalLink(
|
||||
THIRDPARTY_URLS.stanaloneCampaignLink + "/shapez_watermark" + discount
|
||||
THIRDPARTY_URLS.stanaloneCampaignLink +
|
||||
"/shapez_watermark" +
|
||||
discount +
|
||||
(G_IS_STEAM_DEMO ? "_steamdemo" : "")
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.trackClicks(this.element, this.onWatermarkClick);
|
||||
initialize() {}
|
||||
|
||||
this.domAttach = new DynamicDomAttach(this.root, this.element, {
|
||||
attachClass: "visible",
|
||||
timeToKeepSeconds: 0.5,
|
||||
});
|
||||
}
|
||||
|
||||
update() {
|
||||
this.domAttach.update(
|
||||
this.root.time.realtimeNow() % watermarkShowIntervalSeconds < watermarkShowDuration
|
||||
);
|
||||
}
|
||||
|
||||
onWatermarkClick() {
|
||||
this.root.app.analytics.trackUiClick("watermark_click_2_new");
|
||||
this.root.hud.parts.standaloneAdvantages.show();
|
||||
}
|
||||
update() {}
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -70,7 +39,7 @@ export class HUDWatermark extends BaseHUDPart {
|
||||
drawOverlays(parameters) {
|
||||
const w = this.root.gameWidth;
|
||||
|
||||
parameters.context.fillStyle = "rgba(230, 230, 230, 0.9)";
|
||||
parameters.context.fillStyle = "rgba(20, 30, 40, 0.25)";
|
||||
parameters.context.font = "bold " + this.root.app.getEffectiveUiScale() * 40 + "px GameFont";
|
||||
parameters.context.textAlign = "center";
|
||||
parameters.context.fillText(
|
||||
|
||||
@@ -31,11 +31,9 @@ import { IS_MOBILE } from "../../core/config";
|
||||
import { HUDKeybindingOverlay } from "../hud/parts/keybinding_overlay";
|
||||
import { HUDWatermark } from "../hud/parts/watermark";
|
||||
import { HUDStandaloneAdvantages } from "../hud/parts/standalone_advantages";
|
||||
import { HUDCatMemes } from "../hud/parts/cat_memes";
|
||||
import { HUDSteamCapsule } from "../hud/parts/steam_capsule";
|
||||
import { HUDPartTutorialHints } from "../hud/parts/tutorial_hints";
|
||||
import { HUDInteractiveTutorial } from "../hud/parts/interactive_tutorial";
|
||||
import { HUDSandboxController } from "../hud/parts/sandbox_controller";
|
||||
import { queryParamOptions } from "../../core/query_parameters";
|
||||
import { MetaBlockBuilding } from "../buildings/block";
|
||||
import { MetaItemProducerBuilding } from "../buildings/item_producer";
|
||||
import { MOD_SIGNALS } from "../../mods/mod_signals";
|
||||
@@ -584,7 +582,7 @@ export class RegularGameMode extends GameMode {
|
||||
if (this.root.app.restrictionMgr.getIsStandaloneMarketingActive()) {
|
||||
this.additionalHudParts.watermark = HUDWatermark;
|
||||
this.additionalHudParts.standaloneAdvantages = HUDStandaloneAdvantages;
|
||||
this.additionalHudParts.catMemes = HUDCatMemes;
|
||||
this.additionalHudParts.catMemes = HUDSteamCapsule;
|
||||
}
|
||||
|
||||
if (this.root.app.settings.getAllSettings().offerHints) {
|
||||
|
||||
3
src/js/globals.d.ts
vendored
3
src/js/globals.d.ts
vendored
@@ -10,11 +10,10 @@ declare const G_APP_ENVIRONMENT: string;
|
||||
declare const G_HAVE_ASSERT: boolean;
|
||||
declare const G_BUILD_TIME: number;
|
||||
declare const G_IS_STANDALONE: boolean;
|
||||
declare const G_IS_STEAM_DEMO: boolean;
|
||||
declare const G_IS_BROWSER: boolean;
|
||||
declare const G_IS_MOBILE_APP: boolean;
|
||||
|
||||
declare const G_BUILD_COMMIT_HASH: string;
|
||||
declare const G_TRACKING_ENDPOINT: string;
|
||||
declare const G_BUILD_VERSION: string;
|
||||
declare const G_ALL_UI_IMAGES: Array<string>;
|
||||
declare const G_IS_RELEASE: boolean;
|
||||
|
||||
@@ -105,6 +105,10 @@ export class ModLoader {
|
||||
}
|
||||
|
||||
exposeExports() {
|
||||
if (G_IS_STEAM_DEMO) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (G_IS_DEV || G_IS_STANDALONE) {
|
||||
let exports = {};
|
||||
const modules = require.context("../", true, /\.js$/);
|
||||
@@ -136,6 +140,11 @@ export class ModLoader {
|
||||
}
|
||||
|
||||
async initMods() {
|
||||
if (G_IS_STEAM_DEMO) {
|
||||
this.initialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!G_IS_STANDALONE && !G_IS_DEV) {
|
||||
this.initialized = true;
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { createLogger } from "../../core/logging";
|
||||
import { randomInt } from "../../core/utils";
|
||||
import { BeltComponent } from "../../game/components/belt";
|
||||
import { StaticMapEntityComponent } from "../../game/components/static_map_entity";
|
||||
import { RegularGameMode } from "../../game/modes/regular";
|
||||
@@ -13,16 +14,26 @@ const logger = createLogger("game_analytics");
|
||||
|
||||
const analyticsUrl = G_IS_DEV ? "http://localhost:8001" : "https://analytics.shapez.io";
|
||||
|
||||
// Be sure to increment the ID whenever it changes to make sure all
|
||||
// users are tracked
|
||||
const analyticsLocalFile = "shapez_token_123.bin";
|
||||
// Be sure to increment the ID whenever it changes
|
||||
const analyticsLocalFile = G_IS_STEAM_DEMO ? "shapez_token_steamdemo.bin" : "shapez_token_123.bin";
|
||||
|
||||
const currentABT = "abt_sa_si";
|
||||
|
||||
export class ShapezGameAnalytics extends GameAnalyticsInterface {
|
||||
constructor(app) {
|
||||
super(app);
|
||||
this.abtVariant = "0";
|
||||
}
|
||||
|
||||
get environment() {
|
||||
if (G_IS_DEV) {
|
||||
return "dev";
|
||||
}
|
||||
|
||||
if (G_IS_STEAM_DEMO) {
|
||||
return "steam-demo";
|
||||
}
|
||||
|
||||
if (G_IS_STANDALONE) {
|
||||
return "steam";
|
||||
}
|
||||
@@ -38,6 +49,22 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
|
||||
}
|
||||
}
|
||||
|
||||
fetchABVariant() {
|
||||
return this.app.storage.readFileAsync("shapez_" + currentABT + ".bin").then(
|
||||
abt => {
|
||||
this.abtVariant = abt;
|
||||
logger.log("Got abtVariant:", abt);
|
||||
},
|
||||
err => {
|
||||
if (err === FILE_NOT_FOUND) {
|
||||
this.abtVariant = String(randomInt(0, 4));
|
||||
logger.log("Determing abt variant to", this.abtVariant);
|
||||
this.app.storage.writeFileAsync("shapez_" + currentABT + ".bin", this.abtVariant);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
@@ -48,46 +75,68 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
|
||||
return;
|
||||
}
|
||||
|
||||
setInterval(() => this.sendTimePoints(), 60 * 1000);
|
||||
|
||||
// Retrieve sync key from player
|
||||
return this.app.storage.readFileAsync(analyticsLocalFile).then(
|
||||
syncKey => {
|
||||
this.syncKey = syncKey;
|
||||
logger.log("Player sync key read:", this.syncKey);
|
||||
},
|
||||
error => {
|
||||
// File was not found, retrieve new key
|
||||
if (error === FILE_NOT_FOUND) {
|
||||
logger.log("Retrieving new player key");
|
||||
return this.fetchABVariant().then(() => {
|
||||
setInterval(() => this.sendTimePoints(), 60 * 1000);
|
||||
|
||||
// Perform call to get a new key from the API
|
||||
this.sendToApi("/v1/register", {
|
||||
environment: this.environment,
|
||||
standalone:
|
||||
G_IS_STANDALONE &&
|
||||
this.app.achievementProvider instanceof SteamAchievementProvider,
|
||||
commit: G_BUILD_COMMIT_HASH,
|
||||
})
|
||||
.then(res => {
|
||||
// Try to read and parse the key from the api
|
||||
if (res.key && typeof res.key === "string" && res.key.length === 40) {
|
||||
this.syncKey = res.key;
|
||||
logger.log("Key retrieved:", this.syncKey);
|
||||
this.app.storage.writeFileAsync(analyticsLocalFile, res.key);
|
||||
} else {
|
||||
throw new Error("Bad response from analytics server: " + res);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error("Failed to register on analytics api:", err);
|
||||
});
|
||||
} else {
|
||||
logger.error("Failed to read ga key:", error);
|
||||
}
|
||||
return;
|
||||
if (this.app.restrictionMgr.isLimitedVersion()) {
|
||||
fetch(
|
||||
analyticsUrl +
|
||||
"/track/shapez_launch_" +
|
||||
this.environment +
|
||||
"_" +
|
||||
currentABT +
|
||||
"_" +
|
||||
this.abtVariant,
|
||||
{
|
||||
method: "GET",
|
||||
mode: "no-cors",
|
||||
cache: "no-cache",
|
||||
referrer: "no-referrer",
|
||||
credentials: "omit",
|
||||
}
|
||||
).catch(err => {});
|
||||
}
|
||||
);
|
||||
|
||||
return this.app.storage.readFileAsync(analyticsLocalFile).then(
|
||||
syncKey => {
|
||||
this.syncKey = syncKey;
|
||||
logger.log("Player sync key read:", this.syncKey);
|
||||
},
|
||||
error => {
|
||||
// File was not found, retrieve new key
|
||||
if (error === FILE_NOT_FOUND) {
|
||||
logger.log("Retrieving new player key");
|
||||
|
||||
// Perform call to get a new key from the API
|
||||
this.sendToApi("/v1/register", {
|
||||
environment: this.environment,
|
||||
standalone:
|
||||
G_IS_STANDALONE &&
|
||||
!G_IS_STEAM_DEMO &&
|
||||
this.app.achievementProvider instanceof SteamAchievementProvider,
|
||||
commit: G_BUILD_COMMIT_HASH,
|
||||
})
|
||||
.then(res => {
|
||||
// Try to read and parse the key from the api
|
||||
if (res.key && typeof res.key === "string" && res.key.length === 40) {
|
||||
this.syncKey = res.key;
|
||||
logger.log("Key retrieved:", this.syncKey);
|
||||
this.app.storage.writeFileAsync(analyticsLocalFile, res.key);
|
||||
} else {
|
||||
throw new Error("Bad response from analytics server: " + res);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error("Failed to register on analytics api:", err);
|
||||
});
|
||||
} else {
|
||||
logger.error("Failed to read ga key:", error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import { GameAnalyticsInterface } from "../game_analytics";
|
||||
|
||||
export class NoGameAnalytics extends GameAnalyticsInterface {
|
||||
initialize() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
@@ -189,7 +189,7 @@ function initializeSettings() {
|
||||
},
|
||||
/**
|
||||
* @param {Application} app
|
||||
*/ app => app.restrictionMgr.getHasExtendedSettings()
|
||||
*/ app => G_IS_STANDALONE
|
||||
),
|
||||
|
||||
new BoolSetting(
|
||||
@@ -514,7 +514,7 @@ export class ApplicationSettings extends ReadWriteProxy {
|
||||
const settings = data.settings;
|
||||
|
||||
// MODS
|
||||
if (!THEMES[settings.theme]) {
|
||||
if (!THEMES[settings.theme] || !this.app.restrictionMgr.getHasExtendedSettings()) {
|
||||
console.warn("Resetting theme because its no longer available: " + settings.theme);
|
||||
settings.theme = "light";
|
||||
}
|
||||
@@ -700,7 +700,7 @@ export class ApplicationSettings extends ReadWriteProxy {
|
||||
}
|
||||
|
||||
// MODS
|
||||
if (!THEMES[data.settings.theme]) {
|
||||
if (!THEMES[data.settings.theme] || !this.app.restrictionMgr.getHasExtendedSettings()) {
|
||||
console.warn("Resetting theme because its no longer available: " + data.settings.theme);
|
||||
data.settings.theme = "light";
|
||||
}
|
||||
|
||||
@@ -38,9 +38,8 @@ export class MainMenuState extends GameState {
|
||||
getInnerHTML() {
|
||||
const showLanguageIcon = !G_CHINA_VERSION && !G_WEGAME_VERSION;
|
||||
const showExitAppButton = G_IS_STANDALONE;
|
||||
const showUpdateLabel = !G_WEGAME_VERSION;
|
||||
const showBrowserWarning = !G_IS_STANDALONE && !isSupportedBrowser();
|
||||
const showPuzzleDLC = !G_WEGAME_VERSION && G_IS_STANDALONE;
|
||||
const showPuzzleDLC = !G_WEGAME_VERSION && G_IS_STANDALONE && !G_IS_STEAM_DEMO;
|
||||
const showWegameFooter = G_WEGAME_VERSION;
|
||||
const hasMods = MODS.anyModsActive();
|
||||
|
||||
@@ -69,15 +68,17 @@ export class MainMenuState extends GameState {
|
||||
const ownsPuzzleDLC =
|
||||
G_IS_DEV ||
|
||||
(G_IS_STANDALONE &&
|
||||
!G_IS_STEAM_DEMO &&
|
||||
/** @type { PlatformWrapperImplElectron}*/ (this.app.platformWrapper).dlcs.puzzle);
|
||||
|
||||
const bannerHtml = `
|
||||
<h3>${T.demoBanners.title}</h3>
|
||||
<p>${T.demoBanners.intro}</p>
|
||||
<span class="playtimeDisclaimer">${T.demoBanners.playtimeDisclaimer}</span>
|
||||
<a href="#" class="steamLink ${A_B_TESTING_LINK_TYPE}" target="_blank">
|
||||
${
|
||||
globalConfig.currentDiscount.active
|
||||
? `<span class='discount'>${globalConfig.currentDiscount.amount}% off!</span>`
|
||||
globalConfig.currentDiscount > 0
|
||||
? `<span class='discount'>${globalConfig.currentDiscount}% off!</span>`
|
||||
: ""
|
||||
}
|
||||
|
||||
@@ -201,7 +202,7 @@ export class MainMenuState extends GameState {
|
||||
|
||||
<div class="footer ${showExternalLinks ? "" : "noLinks"} ">
|
||||
${
|
||||
showExternalLinks
|
||||
showExternalLinks && !G_IS_STEAM_DEMO
|
||||
? `
|
||||
<a class="githubLink boxLink" target="_blank">
|
||||
${T.mainMenu.openSourceHint}
|
||||
@@ -453,11 +454,12 @@ export class MainMenuState extends GameState {
|
||||
|
||||
onSteamLinkClicked() {
|
||||
this.app.analytics.trackUiClick("main_menu_steam_link_" + A_B_TESTING_LINK_TYPE);
|
||||
const discount = globalConfig.currentDiscount.active
|
||||
? "_discount" + globalConfig.currentDiscount.amount
|
||||
: "";
|
||||
const discount = globalConfig.currentDiscount > 0 ? "_discount" + globalConfig.currentDiscount : "";
|
||||
this.app.platformWrapper.openExternalLink(
|
||||
THIRDPARTY_URLS.stanaloneCampaignLink + "/shapez_mainmenu" + discount
|
||||
THIRDPARTY_URLS.stanaloneCampaignLink +
|
||||
"/shapez_mainmenu" +
|
||||
discount +
|
||||
(G_IS_STEAM_DEMO ? "_steamdemo" : "")
|
||||
);
|
||||
|
||||
return false;
|
||||
@@ -743,7 +745,9 @@ export class MainMenuState extends GameState {
|
||||
getStandalone.add(() => {
|
||||
this.app.analytics.trackUiClick("visit_steampage_from_slot_limit");
|
||||
this.app.platformWrapper.openExternalLink(
|
||||
THIRDPARTY_URLS.stanaloneCampaignLink + "/shapez_slotlimit"
|
||||
THIRDPARTY_URLS.stanaloneCampaignLink +
|
||||
"/shapez_slotlimit" +
|
||||
(G_IS_STEAM_DEMO ? "_steamdemo" : "")
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ import { TextualGameState } from "../core/textual_game_state";
|
||||
import { MODS } from "../mods/modloader";
|
||||
import { T } from "../translations";
|
||||
|
||||
const MODS_SUPPORTED = !G_IS_STEAM_DEMO && (G_IS_STANDALONE || G_IS_DEV);
|
||||
|
||||
export class ModsState extends TextualGameState {
|
||||
constructor() {
|
||||
super("ModsState");
|
||||
@@ -19,12 +21,12 @@ export class ModsState extends TextualGameState {
|
||||
|
||||
<div class="actions">
|
||||
${
|
||||
(G_IS_STANDALONE || G_IS_DEV) && MODS.mods.length > 0
|
||||
MODS_SUPPORTED && MODS.mods.length > 0
|
||||
? `<button class="styledButton browseMods">${T.mods.browseMods}</button>`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
G_IS_STANDALONE || G_IS_DEV
|
||||
MODS_SUPPORTED
|
||||
? `<button class="styledButton openModsFolder">${T.mods.openFolder}</button>`
|
||||
: ""
|
||||
}
|
||||
@@ -41,7 +43,7 @@ export class ModsState extends TextualGameState {
|
||||
}
|
||||
|
||||
getMainContentHTML() {
|
||||
if (!G_IS_STANDALONE && !G_IS_DEV) {
|
||||
if (!MODS_SUPPORTED) {
|
||||
return `
|
||||
<div class="noModSupport">
|
||||
|
||||
@@ -137,7 +139,9 @@ export class ModsState extends TextualGameState {
|
||||
onSteamLinkClicked() {
|
||||
this.app.analytics.trackUiClick("mods_steam_link");
|
||||
this.app.platformWrapper.openExternalLink(
|
||||
THIRDPARTY_URLS.stanaloneCampaignLink + "/shapez_modsettings"
|
||||
THIRDPARTY_URLS.stanaloneCampaignLink +
|
||||
"/shapez_modsettings" +
|
||||
(G_IS_STEAM_DEMO ? "_steamdemo" : "")
|
||||
);
|
||||
|
||||
return false;
|
||||
|
||||
@@ -61,6 +61,26 @@ export class PreloadState extends GameState {
|
||||
this.startLoading();
|
||||
}
|
||||
|
||||
async fetchDiscounts() {
|
||||
await Promise.race([
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
reject("Failed to resolve steam discounts within timeout");
|
||||
}, 2000);
|
||||
}),
|
||||
fetch("https://analytics.shapez.io/v1/discounts")
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
globalConfig.currentDiscount = Number(
|
||||
data["1318690"].data.price_overview.discount_percent
|
||||
);
|
||||
logger.log("Fetched current discount:", globalConfig.currentDiscount);
|
||||
}),
|
||||
]).catch(err => {
|
||||
logger.warn("Failed to fetch current discount:", err);
|
||||
});
|
||||
}
|
||||
|
||||
onLeave() {
|
||||
// this.dialogs.cleanup();
|
||||
}
|
||||
@@ -101,6 +121,9 @@ export class PreloadState extends GameState {
|
||||
.then(() => this.app.analytics.initialize())
|
||||
.then(() => this.app.gameAnalytics.initialize())
|
||||
|
||||
.then(() => this.setStatus("Connecting to api"))
|
||||
.then(() => this.fetchDiscounts())
|
||||
|
||||
.then(() => this.setStatus("Initializing settings"))
|
||||
.then(() => {
|
||||
return this.app.settings.initialize();
|
||||
|
||||
@@ -36,13 +36,11 @@ export class SettingsState extends TextualGameState {
|
||||
: `
|
||||
<button class="styledButton categoryButton manageMods">${T.mods.title}
|
||||
<span class="newBadge">${T.settings.newBadge}</span>
|
||||
</button>
|
||||
|
||||
`
|
||||
</button>`
|
||||
}
|
||||
|
||||
|
||||
<div class="other">
|
||||
<div class="other ${G_CHINA_VERSION || G_WEGAME_VERSION ? "noabout" : ""}">
|
||||
|
||||
${
|
||||
G_CHINA_VERSION || G_WEGAME_VERSION
|
||||
|
||||
Reference in New Issue
Block a user