Update demo hint and lock demo to lvl 14

This commit is contained in:
tobspr 2020-09-29 16:46:29 +02:00
parent 9b7225bf44
commit 5a3807883e
29 changed files with 745 additions and 331 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,39 +1,40 @@
#ingame_HUD_BlueprintPlacer {
position: absolute;
@include S(top, 50px);
left: 50%;
transform: translateX(-50%);
color: #333;
z-index: 9999;
background: $ingameHudBg;
@include S(padding, 5px);
display: flex;
flex-direction: column;
color: #fff;
@include S(width, 120px);
align-items: center;
justify-content: center;
.label {
@include PlainText;
text-transform: uppercase;
}
.costContainer {
display: flex;
align-items: center;
@include Heading;
> canvas {
@include S(margin-left, 5px);
@include S(width, 30px);
@include S(height, 30px);
}
}
&:not(.canAfford) {
background: rgba(98, 27, 41, 0.8);
// .costContainer {
color: rgb(255, 97, 128);
// }
}
}
#ingame_HUD_BlueprintPlacer {
position: absolute;
@include S(top, 70px);
left: 50%;
transform: translateX(-50%);
color: #333;
z-index: 9999;
background: $ingameHudBg;
@include S(padding, 5px);
display: flex;
flex-direction: column;
color: #fff;
@include S(width, 120px);
align-items: center;
justify-content: center;
@include S(border-radius, $globalBorderRadius);
.label {
@include PlainText;
text-transform: uppercase;
}
.costContainer {
display: flex;
align-items: center;
@include Heading;
> canvas {
@include S(margin-left, 5px);
@include S(width, 30px);
@include S(height, 30px);
}
}
&:not(.canAfford) {
background: rgba(98, 27, 41, 0.8);
// .costContainer {
color: rgb(255, 97, 128);
// }
}
}

View File

@ -0,0 +1,171 @@
#ingame_HUD_StandaloneAdvantages {
.content {
@include S(width, 440px);
@include S(min-height, 300px);
}
p {
@include PlainText;
}
.points {
display: grid;
grid-template-columns: 1fr 1fr;
@include S(grid-column-gap, 10px);
@include S(grid-row-gap, 20px);
@include S(margin, 10px, 0, 20px);
grid-template-rows: #{D(40px)};
align-items: center;
}
.lowerBar {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
> button {
transition: opacity 0.12s ease-in-out;
&:hover {
opacity: 0.85;
}
}
.otherCloseButton {
@include SuperSmallText;
@include S(margin-right, 30px);
color: #aaa;
@include S(margin, 0);
@include IncreasedClickArea(0px);
@include S(margin-top, 15px);
@include InlineAnimation(5s ease-in-out) {
0% {
opacity: 0.05;
}
50% {
opacity: 0.05;
}
100% {
opacity: 1;
}
}
}
.steamLinkButton {
@include IncreasedClickArea(5px);
@include S(margin, 0);
@include S(width, 180px);
@include S(height, 40px);
& {
/* @load-async */
background: #171a23 uiResource("get_on_steam.png") center center / contain no-repeat;
}
@include S(border-radius, $globalBorderRadius);
}
}
.point {
display: grid;
grid-template-columns: #{D(55px)} auto;
grid-template-rows: 1fr 1fr;
> strong {
grid-column: 2 / 3;
grid-row: 1 / 2;
@include PlainText;
text-transform: uppercase;
font-weight: bold;
}
> p {
grid-column: 2 / 3;
grid-row: 2 / 3;
@include SuperSmallText;
opacity: 0.8;
}
background: transparent #{D(10px)} center / #{D(30px)} no-repeat;
&.levels {
& {
/* @load-async */
background-image: uiResource("res/ui/icons/advantage_new_levels.png");
}
> strong {
color: #f13555;
}
}
&.upgrades {
& {
/* @load-async */
background-image: uiResource("res/ui/icons/advantage_upgrades.png");
}
> strong {
color: #8a00ff;
}
}
&.buildings {
& {
/* @load-async */
background-image: uiResource("res/ui/icons/advantage_buildings.png");
}
> strong {
color: #3fce8b;
}
}
&.wires {
& {
/* @load-async */
background-image: uiResource("res/ui/icons/advantage_wires.png");
}
> strong {
color: #ef2fdb;
}
}
&.markers {
& {
/* @load-async */
background-image: uiResource("res/ui/icons/advantage_markers.png");
}
> strong {
color: #4294ff;
}
}
&.savegames {
& {
/* @load-async */
background-image: uiResource("res/ui/icons/advantage_savegames.png");
}
> strong {
color: #ff9500;
}
}
&.darkmode {
& {
/* @load-async */
background-image: uiResource("res/ui/icons/advantage_dark_mode.png");
}
> strong {
color: #292c32;
}
}
&.support {
& {
/* @load-async */
background-image: uiResource("res/ui/icons/advantage_support.png");
}
> strong {
color: #e72d2d;
}
}
}
}

View File

@ -1,22 +1,85 @@
#ingame_HUD_Watermark {
position: absolute;
& {
/* @load-async */
background: uiResource("get_on_steam.png") center center / contain no-repeat;
}
@include S(width, 110px);
@include S(height, 40px);
@include S(top, 10px);
@include S(border-radius, $globalBorderRadius);
@include S(top, 70px);
pointer-events: all;
cursor: pointer;
@include S(left, 160px);
left: 50%;
text-align: center;
background: rgba(207, 65, 65, 0.8);
color: #fff;
transform: translateX(-50%);
@include PlainText;
@include S(padding, 10px);
transition: all 0.12s ease-in;
transition-property: opacity, transform;
transform: skewX(-0.5deg);
&:hover {
transform: skewX(-1deg) scale(1.02);
opacity: 0.9;
transform: translateX(-50%) scale(1.02) !important;
}
> strong {
@include PlainText;
text-transform: uppercase;
}
> p {
@include SuperSmallText;
opacity: 0.7;
}
opacity: 0;
&.visible {
@include InlineAnimation(0.5s ease-in-out) {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
opacity: 1;
}
&:not(.visible) {
@include InlineAnimation(0.5s ease-in-out) {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
}
}
#ingame_HUD_WatermarkClicker {
@include S(top, 55px);
position: absolute;
left: 50%;
transform: translateX(-50%) !important;
@include SuperSmallText;
color: $colorBlueBright;
text-transform: uppercase;
pointer-events: all;
cursor: pointer;
display: flex;
align-items: center;
&:hover {
opacity: 0.9;
}
&::after {
@include S(margin-left, 4px);
content: "";
@include S(width, 10px);
@include S(height, 10px);
display: inline-flex;
background: center center / contain no-repeat;
& {
/* @load-async */
background-image: uiResource("res/ui/icons/demo_steam_link_indicator.png");
}
}
}

View File

@ -52,6 +52,7 @@
@import "ingame_hud/color_blind_helper";
@import "ingame_hud/shape_viewer";
@import "ingame_hud/sandbox_controller";
@import "ingame_hud/standalone_advantages";
// prettier-ignore
$elements:
@ -77,6 +78,7 @@ ingame_HUD_buildings_toolbar,
ingame_HUD_wires_toolbar,
ingame_HUD_BlueprintPlacer,
ingame_HUD_Waypoints_Hint,
ingame_HUD_WatermarkClicker,
ingame_HUD_Watermark,
ingame_HUD_ColorBlindBelowTileHelper,
ingame_HUD_SandboxController,
@ -88,6 +90,7 @@ ingame_HUD_BetaOverlay,
ingame_HUD_Shop,
ingame_HUD_Statistics,
ingame_HUD_ShapeViewer,
ingame_HUD_StandaloneAdvantages,
ingame_HUD_UnlockNotification,
ingame_HUD_SettingsMenu,
ingame_HUD_ModalDialogs;

View File

@ -1,4 +1,4 @@
import { globalConfig } from "../core/config";
import { globalConfig, IS_DEMO } from "../core/config";
import { RandomNumberGenerator } from "../core/rng";
import { clamp, findNiceIntegerValue, randomChoice, randomInt } from "../core/utils";
import { BasicSerializableObject, types } from "../savegame/serialization";
@ -29,6 +29,10 @@ export class HubGoals extends BasicSerializableObject {
return errorCode;
}
if (IS_DEMO) {
this.level = Math.min(this.level, tutorialGoals.length);
}
// Compute gained rewards
for (let i = 0; i < this.level - 1; ++i) {
if (i < tutorialGoals.length) {
@ -102,13 +106,23 @@ export class HubGoals extends BasicSerializableObject {
if (ev.key === "b") {
// root is not guaranteed to exist within ~0.5s after loading in
if (this.root && this.root.app && this.root.app.gameAnalytics) {
this.onGoalCompleted();
if (!this.isEndOfDemoReached()) {
this.onGoalCompleted();
}
}
}
});
}
}
/**
* Returns whether the end of the demo is reached
* @returns {boolean}
*/
isEndOfDemoReached() {
return IS_DEMO && this.level >= tutorialGoals.length;
}
/**
* Returns how much of the current shape is stored
* @param {ShapeDefinition} definition
@ -190,7 +204,9 @@ export class HubGoals extends BasicSerializableObject {
this.getCurrentGoalDelivered() >= this.currentGoal.required ||
(G_IS_DEV && globalConfig.debug.rewardsInstant)
) {
this.onGoalCompleted();
if (!this.isEndOfDemoReached()) {
this.onGoalCompleted();
}
}
}
@ -254,6 +270,11 @@ export class HubGoals extends BasicSerializableObject {
return false;
}
if (IS_DEMO && currentLevel >= 4) {
// DEMO
return false;
}
if (G_IS_DEV && globalConfig.debug.upgradesNoCost) {
return true;
}

View File

@ -46,6 +46,7 @@ import { HUDLayerPreview } from "./parts/layer_preview";
import { HUDMinerHighlight } from "./parts/miner_highlight";
import { HUDBetaOverlay } from "./parts/beta_overlay";
import { HUDPerformanceWarning } from "./parts/performance_warning";
import { HUDStandaloneAdvantages } from "./parts/standalone_advantages";
export class GameHUD {
/**
@ -116,6 +117,7 @@ export class GameHUD {
if (IS_DEMO) {
this.parts.watermark = new HUDWatermark(this.root);
this.parts.standaloneAdvantages = new HUDStandaloneAdvantages(this.root);
}
if (G_IS_DEV && globalConfig.debug.renderChanges) {
@ -139,9 +141,9 @@ export class GameHUD {
this.parts.sandboxController = new HUDSandboxController(this.root);
}
// if (!G_IS_RELEASE) {
this.parts.betaOverlay = new HUDBetaOverlay(this.root);
// }
if (!G_IS_RELEASE && !G_IS_DEV) {
this.parts.betaOverlay = new HUDBetaOverlay(this.root);
}
const frag = document.createDocumentFragment();
for (const key in this.parts) {

View File

@ -122,7 +122,7 @@ export class HUDModalDialogs extends BaseHUDPart {
dialog.buttonSignals.getStandalone.add(() => {
this.app.analytics.trackUiClick("demo_dialog_click");
window.open(THIRDPARTY_URLS.standaloneStorePage);
window.open(THIRDPARTY_URLS.standaloneStorePage + "?ref=ddc");
});
return dialog.buttonSignals;

View File

@ -88,13 +88,8 @@ export class HUDSettingsMenu extends BaseHUDPart {
this.close();
}
cleanup() {
document.body.classList.remove("ingameDialogOpen");
}
show() {
this.visible = true;
document.body.classList.add("ingameDialogOpen");
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
const totalMinutesPlayed = Math.ceil(this.root.time.now() / 60);
@ -120,7 +115,6 @@ export class HUDSettingsMenu extends BaseHUDPart {
close() {
this.visible = false;
document.body.classList.remove("ingameDialogOpen");
this.root.app.inputMgr.makeSureDetached(this.inputReciever);
this.update();
}

View File

@ -67,7 +67,6 @@ export class HUDShapeViewer extends BaseHUDPart {
*/
close() {
this.visible = false;
document.body.classList.remove("ingameDialogOpen");
this.root.app.inputMgr.makeSureDetached(this.inputReciever);
this.update();
}
@ -78,7 +77,6 @@ export class HUDShapeViewer extends BaseHUDPart {
*/
renderForShape(definition) {
this.visible = true;
document.body.classList.add("ingameDialogOpen");
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
removeAllChildren(this.renderArea);
@ -124,13 +122,6 @@ export class HUDShapeViewer extends BaseHUDPart {
}
}
/**
* Cleans up everything
*/
cleanup() {
document.body.classList.remove("ingameDialogOpen");
}
update() {
this.domAttach.update(this.visible);
}

View File

@ -205,8 +205,6 @@ export class HUDShop extends BaseHUDPart {
}
cleanup() {
document.body.classList.remove("ingameDialogOpen");
// Cleanup detectors
for (const upgradeId in this.upgradeToElements) {
const handle = this.upgradeToElements[upgradeId];
@ -222,15 +220,12 @@ export class HUDShop extends BaseHUDPart {
show() {
this.visible = true;
document.body.classList.add("ingameDialogOpen");
// this.background.classList.add("visible");
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
this.rerenderFull();
}
close() {
this.visible = false;
document.body.classList.remove("ingameDialogOpen");
this.root.app.inputMgr.makeSureDetached(this.inputReciever);
this.update();
}

View File

@ -0,0 +1,84 @@
import { THIRDPARTY_URLS } from "../../../core/config";
import { InputReceiver } from "../../../core/input_receiver";
import { makeDiv } from "../../../core/utils";
import { T } from "../../../translations";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
const showIntervalSeconds = 30 * 60;
export class HUDStandaloneAdvantages extends BaseHUDPart {
createElements(parent) {
this.background = makeDiv(parent, "ingame_HUD_StandaloneAdvantages", ["ingameDialog"]);
// DIALOG Inner / Wrapper
this.dialogInner = makeDiv(this.background, null, ["dialogInner"]);
this.title = makeDiv(this.dialogInner, null, ["title"], T.ingame.standaloneAdvantages.title);
this.contentDiv = makeDiv(
this.dialogInner,
null,
["content"],
`
<div class="points">
${Object.entries(T.ingame.standaloneAdvantages.points)
.map(
([key, trans]) => `
<div class="point ${key}">
<strong>${trans.title}</strong>
<p>${trans.desc}</p>
</div>`
)
.join("")}
</div>
<div class="lowerBar">
<button class="steamLinkButton">
<button class="otherCloseButton">${T.ingame.standaloneAdvantages.no_thanks}</button>
</button>
</div>
`
);
this.trackClicks(this.contentDiv.querySelector("button.steamLinkButton"), () => {
this.root.app.analytics.trackUiClick("standalone_advantage_visit_steam");
this.root.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.standaloneStorePage + "?ref=savs");
this.close();
});
this.trackClicks(this.contentDiv.querySelector("button.otherCloseButton"), () => {
this.root.app.analytics.trackUiClick("standalone_advantage_no_thanks");
this.close();
});
}
initialize() {
this.domAttach = new DynamicDomAttach(this.root, this.background, {
attachClass: "visible",
});
this.inputReciever = new InputReceiver("standalone-advantages");
this.close();
this.lastShown = this.root.gameIsFresh ? this.root.time.now() : 0;
}
show() {
this.lastShown = this.root.time.now();
this.visible = true;
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
}
close() {
this.visible = false;
this.root.app.inputMgr.makeSureDetached(this.inputReciever);
this.update();
}
update() {
if (!this.visible && this.root.time.now() - this.lastShown > showIntervalSeconds) {
this.show();
}
this.domAttach.update(this.visible);
}
}

View File

@ -151,17 +151,12 @@ export class HUDStatistics extends BaseHUDPart {
}
}
cleanup() {
document.body.classList.remove("ingameDialogOpen");
}
isBlockingOverlay() {
return this.visible;
}
show() {
this.visible = true;
document.body.classList.add("ingameDialogOpen");
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
this.rerenderFull();
this.update();
@ -169,7 +164,6 @@ export class HUDStatistics extends BaseHUDPart {
close() {
this.visible = false;
document.body.classList.remove("ingameDialogOpen");
this.root.app.inputMgr.makeSureDetached(this.inputReciever);
this.update();
}

View File

@ -1,109 +1,106 @@
import { InputReceiver } from "../../../core/input_receiver";
import { TrackedState } from "../../../core/tracked_state";
import { makeDiv } from "../../../core/utils";
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { T } from "../../../translations";
const tutorialVideos = [2, 3, 4, 5, 6, 7, 9, 10, 11];
export class HUDPartTutorialHints extends BaseHUDPart {
createElements(parent) {
this.element = makeDiv(
parent,
"ingame_HUD_TutorialHints",
[],
`
<div class="header">
<span>${T.ingame.tutorialHints.title}</span>
<button class="styledButton toggleHint">
<span class="show">${T.ingame.tutorialHints.showHint}</span>
<span class="hide">${T.ingame.tutorialHints.hideHint}</span>
</button>
</div>
<video autoplay muted loop class="fullscreenBackgroundVideo">
<source type="video/webm">
</video>
`
);
this.videoElement = this.element.querySelector("video");
}
shouldPauseGame() {
return this.enlarged;
}
initialize() {
this.trackClicks(this.element.querySelector(".toggleHint"), this.toggleHintEnlarged);
this.videoAttach = new DynamicDomAttach(this.root, this.videoElement, {
timeToKeepSeconds: 0.3,
});
this.videoAttach.update(false);
this.enlarged = false;
this.inputReciever = new InputReceiver("tutorial_hints");
this.keyActionMapper = new KeyActionMapper(this.root, this.inputReciever);
this.keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.close, this);
this.domAttach = new DynamicDomAttach(this.root, this.element);
this.currentShownLevel = new TrackedState(this.updateVideoUrl, this);
}
updateVideoUrl(level) {
if (tutorialVideos.indexOf(level) < 0) {
this.videoElement.querySelector("source").setAttribute("src", "");
this.videoElement.pause();
} else {
this.videoElement
.querySelector("source")
.setAttribute("src", "https://static.shapez.io/tutorial_videos/level_" + level + ".webm");
this.videoElement.currentTime = 0;
this.videoElement.load();
}
}
close() {
this.enlarged = false;
document.body.classList.remove("ingameDialogOpen");
this.element.classList.remove("enlarged", "noBlur");
this.root.app.inputMgr.makeSureDetached(this.inputReciever);
this.update();
}
show() {
this.root.app.analytics.trackUiClick("tutorial_hint_show");
this.root.app.analytics.trackUiClick("tutorial_hint_show_lvl_" + this.root.hubGoals.level);
document.body.classList.add("ingameDialogOpen");
this.element.classList.add("enlarged", "noBlur");
this.enlarged = true;
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
this.update();
this.videoElement.currentTime = 0;
this.videoElement.play();
}
update() {
this.videoAttach.update(this.enlarged);
this.currentShownLevel.set(this.root.hubGoals.level);
const tutorialVisible = tutorialVideos.indexOf(this.root.hubGoals.level) >= 0;
this.domAttach.update(tutorialVisible);
}
toggleHintEnlarged() {
if (this.enlarged) {
this.close();
} else {
this.show();
}
}
}
import { InputReceiver } from "../../../core/input_receiver";
import { TrackedState } from "../../../core/tracked_state";
import { makeDiv } from "../../../core/utils";
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { T } from "../../../translations";
const tutorialVideos = [2, 3, 4, 5, 6, 7, 9, 10, 11];
export class HUDPartTutorialHints extends BaseHUDPart {
createElements(parent) {
this.element = makeDiv(
parent,
"ingame_HUD_TutorialHints",
[],
`
<div class="header">
<span>${T.ingame.tutorialHints.title}</span>
<button class="styledButton toggleHint">
<span class="show">${T.ingame.tutorialHints.showHint}</span>
<span class="hide">${T.ingame.tutorialHints.hideHint}</span>
</button>
</div>
<video autoplay muted loop class="fullscreenBackgroundVideo">
<source type="video/webm">
</video>
`
);
this.videoElement = this.element.querySelector("video");
}
shouldPauseGame() {
return this.enlarged;
}
initialize() {
this.trackClicks(this.element.querySelector(".toggleHint"), this.toggleHintEnlarged);
this.videoAttach = new DynamicDomAttach(this.root, this.videoElement, {
timeToKeepSeconds: 0.3,
});
this.videoAttach.update(false);
this.enlarged = false;
this.inputReciever = new InputReceiver("tutorial_hints");
this.keyActionMapper = new KeyActionMapper(this.root, this.inputReciever);
this.keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.close, this);
this.domAttach = new DynamicDomAttach(this.root, this.element);
this.currentShownLevel = new TrackedState(this.updateVideoUrl, this);
}
updateVideoUrl(level) {
if (tutorialVideos.indexOf(level) < 0) {
this.videoElement.querySelector("source").setAttribute("src", "");
this.videoElement.pause();
} else {
this.videoElement
.querySelector("source")
.setAttribute("src", "https://static.shapez.io/tutorial_videos/level_" + level + ".webm");
this.videoElement.currentTime = 0;
this.videoElement.load();
}
}
close() {
this.enlarged = false;
this.element.classList.remove("enlarged", "noBlur");
this.root.app.inputMgr.makeSureDetached(this.inputReciever);
this.update();
}
show() {
this.root.app.analytics.trackUiClick("tutorial_hint_show");
this.root.app.analytics.trackUiClick("tutorial_hint_show_lvl_" + this.root.hubGoals.level);
this.element.classList.add("enlarged", "noBlur");
this.enlarged = true;
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
this.update();
this.videoElement.currentTime = 0;
this.videoElement.play();
}
update() {
this.videoAttach.update(this.enlarged);
this.currentShownLevel.set(this.root.hubGoals.level);
const tutorialVisible = tutorialVideos.indexOf(this.root.hubGoals.level) >= 0;
this.domAttach.update(tutorialVisible);
}
toggleHintEnlarged() {
if (this.enlarged) {
this.close();
} else {
this.show();
}
}
}

View File

@ -1,44 +1,67 @@
import { BaseHUDPart } from "../base_hud_part";
import { DrawParameters } from "../../../core/draw_parameters";
import { makeDiv } from "../../../core/utils";
import { THIRDPARTY_URLS } from "../../../core/config";
import { T } from "../../../translations";
export class HUDWatermark extends BaseHUDPart {
createElements(parent) {
this.element = makeDiv(parent, "ingame_HUD_Watermark");
}
initialize() {
this.trackClicks(this.element, this.onWatermarkClick);
}
onWatermarkClick() {
this.root.app.analytics.trackUiClick("watermark_click_2");
this.root.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.standaloneStorePage);
}
/**
*
* @param {DrawParameters} parameters
*/
drawOverlays(parameters) {
const w = this.root.gameWidth;
const x = 280 * this.root.app.getEffectiveUiScale();
parameters.context.fillStyle = "#f77";
parameters.context.font = "bold " + this.root.app.getEffectiveUiScale() * 17 + "px GameFont";
// parameters.context.textAlign = "center";
parameters.context.fillText(
T.demoBanners.title.toUpperCase(),
x,
this.root.app.getEffectiveUiScale() * 27
);
parameters.context.font = "bold " + this.root.app.getEffectiveUiScale() * 12 + "px GameFont";
// parameters.context.textAlign = "center";
parameters.context.fillText(T.demoBanners.intro, x, this.root.app.getEffectiveUiScale() * 45);
// parameters.context.textAlign = "left";
}
}
import { 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";
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",
[],
T.ingame.watermark.get_on_steam
);
this.trackClicks(this.linkElement, () => {
this.root.app.analytics.trackUiClick("watermark_click_2_direct");
this.root.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.standaloneStorePage + "?ref=wtmd");
});
}
initialize() {
this.trackClicks(this.element, this.onWatermarkClick);
this.domAttach = new DynamicDomAttach(this.root, this.element, {
attachClass: "visible",
timeToKeepSeconds: 0.5,
});
}
update() {
this.domAttach.update(this.root.time.realtimeNow() % (G_IS_DEV ? 20 : 180) < 5);
}
onWatermarkClick() {
this.root.app.analytics.trackUiClick("watermark_click_2_new");
this.root.hud.parts.standaloneAdvantages.show();
}
/**
*
* @param {import("../../../core/draw_utils").DrawParameters} parameters
*/
drawOverlays(parameters) {
const w = this.root.gameWidth;
parameters.context.fillStyle = "rgba(230, 230, 230, 0.9)";
parameters.context.font = "bold " + this.root.app.getEffectiveUiScale() * 40 + "px GameFont";
parameters.context.textAlign = "center";
parameters.context.fillText(
T.demoBanners.title.toUpperCase(),
w / 2,
this.root.app.getEffectiveUiScale() * 50
);
parameters.context.textAlign = "left";
}
}

View File

@ -1,4 +1,4 @@
import { globalConfig } from "../../core/config";
import { globalConfig, IS_DEMO } from "../../core/config";
import { smoothenDpi } from "../../core/dpi_manager";
import { DrawParameters } from "../../core/draw_parameters";
import { drawSpriteClipped } from "../../core/draw_utils";
@ -65,6 +65,17 @@ export class HubSystem extends GameSystemWithFilter {
this.hubSprite.draw(context, 0, 0, w, h);
if (this.root.hubGoals.isEndOfDemoReached()) {
// End of demo
context.font = "bold 12px GameFont";
context.fillStyle = "#fd0752";
context.textAlign = "center";
context.fillText(T.buildings.hub.endOfDemo.toUpperCase(), w / 2, h / 2 + 6);
context.textAlign = "left";
return;
}
const definition = this.root.hubGoals.currentGoal.definition;
definition.drawCentered(45, 58, parameters, 36);

View File

@ -1,3 +1,4 @@
import { IS_DEMO } from "../core/config";
import { ShapeDefinition } from "./shape_definition";
import { finalGameShape } from "./upgrades";
@ -31,6 +32,8 @@ export const enumHubGoalRewards = {
reward_virtual_processing: "reward_virtual_processing",
reward_filter: "reward_filter",
reward_demo_end: "reward_demo_end",
reward_blueprints: "reward_blueprints",
reward_freeplay: "reward_freeplay",
@ -140,107 +143,118 @@ export const tutorialGoals = [
reward: enumHubGoalRewards.reward_underground_belt_tier_2,
},
// 14
// Belt reader
{
shape: "--Cg----:--Cr----", // unused
required: 16, // Per second!
reward: enumHubGoalRewards.reward_belt_reader,
throughputOnly: true,
},
// DEMO STOPS HERE
...(IS_DEMO
? [
{
shape: "RpRpRpRp:CwCwCwCw",
required: 0,
reward: enumHubGoalRewards.reward_demo_end,
},
]
: [
// 14
// Belt reader
{
shape: "--Cg----:--Cr----", // unused
required: 16, // Per second!
reward: enumHubGoalRewards.reward_belt_reader,
throughputOnly: true,
},
// 15
// Storage
{
shape: "SrSrSrSr:CyCyCyCy", // unused
required: 10000,
reward: enumHubGoalRewards.reward_storage,
},
// 15
// Storage
{
shape: "SrSrSrSr:CyCyCyCy", // unused
required: 10000,
reward: enumHubGoalRewards.reward_storage,
},
// 16
// Quad Cutter
{
shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", // belts t4 (two variants)
required: 6000,
reward: enumHubGoalRewards.reward_cutter_quad,
},
// 16
// Quad Cutter
{
shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", // belts t4 (two variants)
required: 6000,
reward: enumHubGoalRewards.reward_cutter_quad,
},
// 17
// Double painter
{
shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
required: 20000,
reward: enumHubGoalRewards.reward_painter_double,
},
// 17
// Double painter
{
shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
required: 20000,
reward: enumHubGoalRewards.reward_painter_double,
},
// 18
// Rotater (180deg)
{
shape: "Sg----Sg:CgCgCgCg:--CyCy--", // unused
required: 20000,
reward: enumHubGoalRewards.reward_rotater_180,
},
// 18
// Rotater (180deg)
{
shape: "Sg----Sg:CgCgCgCg:--CyCy--", // unused
required: 20000,
reward: enumHubGoalRewards.reward_rotater_180,
},
// 19
// Compact splitter
{
shape: "CpRpCp--:SwSwSwSw",
required: 25000,
reward: enumHubGoalRewards.reward_splitter,
},
// 19
// Compact splitter
{
shape: "CpRpCp--:SwSwSwSw",
required: 25000,
reward: enumHubGoalRewards.reward_splitter,
},
// 20
// WIRES
{
shape: finalGameShape,
required: 25000,
reward: enumHubGoalRewards.reward_wires_painter_and_levers,
},
// 20
// WIRES
{
shape: finalGameShape,
required: 25000,
reward: enumHubGoalRewards.reward_wires_painter_and_levers,
},
// 21
// Filter
{
shape: "CrCwCrCw:CwCrCwCr:CrCwCrCw:CwCrCwCr",
required: 25000,
reward: enumHubGoalRewards.reward_filter,
},
// 21
// Filter
{
shape: "CrCwCrCw:CwCrCwCr:CrCwCrCw:CwCrCwCr",
required: 25000,
reward: enumHubGoalRewards.reward_filter,
},
// 22
// Constant signal
{
shape: "Cg----Cr:Cw----Cw:Sy------:Cy----Cy",
required: 25000,
reward: enumHubGoalRewards.reward_constant_signal,
},
// 22
// Constant signal
{
shape: "Cg----Cr:Cw----Cw:Sy------:Cy----Cy",
required: 25000,
reward: enumHubGoalRewards.reward_constant_signal,
},
// 23
// Display
{
shape: "CcSyCcSy:SyCcSyCc:CcSyCcSy",
required: 25000,
reward: enumHubGoalRewards.reward_display,
},
// 23
// Display
{
shape: "CcSyCcSy:SyCcSyCc:CcSyCcSy",
required: 25000,
reward: enumHubGoalRewards.reward_display,
},
// 24 Logic gates
{
shape: "CcRcCcRc:RwCwRwCw:Sr--Sw--:CyCyCyCy",
required: 25000,
reward: enumHubGoalRewards.reward_logic_gates,
},
// 24 Logic gates
{
shape: "CcRcCcRc:RwCwRwCw:Sr--Sw--:CyCyCyCy",
required: 25000,
reward: enumHubGoalRewards.reward_logic_gates,
},
// 25 Virtual Processing
{
shape: "Rg--Rg--:CwRwCwRw:--Rg--Rg",
required: 25000,
reward: enumHubGoalRewards.reward_virtual_processing,
},
// 25 Virtual Processing
{
shape: "Rg--Rg--:CwRwCwRw:--Rg--Rg",
required: 25000,
reward: enumHubGoalRewards.reward_virtual_processing,
},
// 26 Freeplay
{
shape: "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw",
required: 50000,
reward: enumHubGoalRewards.reward_freeplay,
},
// 26 Freeplay
{
shape: "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw",
required: 50000,
reward: enumHubGoalRewards.reward_freeplay,
},
]),
];
if (G_IS_DEV) {

View File

@ -64,6 +64,7 @@ export const enumHubGoalRewardsToContentUnlocked = {
[enumHubGoalRewards.reward_blueprints]: null,
[enumHubGoalRewards.no_reward]: null,
[enumHubGoalRewards.no_reward_freeplay]: null,
[enumHubGoalRewards.reward_demo_end]: null,
};
if (G_IS_DEV) {

View File

@ -312,7 +312,7 @@ export class MainMenuState extends GameState {
onSteamLinkClicked() {
this.app.analytics.trackUiClick("main_menu_steam_link_2");
this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.standaloneStorePage);
this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.standaloneStorePage + "?ref=mmsl2");
return false;
}
@ -537,7 +537,7 @@ export class MainMenuState extends GameState {
);
getStandalone.add(() => {
this.app.analytics.trackUiClick("visit_steampage_from_slot_limit");
this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.standaloneStorePage);
this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.standaloneStorePage + "?reF=ssll");
});
}

View File

@ -21,7 +21,7 @@ export class MobileWarningState extends GameState {
<a href="${
THIRDPARTY_URLS.standaloneStorePage
THIRDPARTY_URLS.standaloneStorePage + "?ref=mobile"
}" class="standaloneLink" target="_blank">Get the shapez.io standalone!</a>
`;
}

View File

@ -449,6 +449,49 @@ ingame:
n_miners: <amount> Miners
limited_items: Limited to <max_throughput>
# Pops up in the demo every few minutes
watermark:
title: Demo version
desc: Click here to see the Steam version advantages!
get_on_steam: Get on steam
standaloneAdvantages:
title: Get the full version!
no_thanks: No, thanks!
points:
levels:
title: 12 New Levels
desc: For a total of 26 levels!
buildings:
title: 18 New Buildings
desc: Fully automate your factory!
savegames:
title: ∞ Savegames
desc: As many as your heart desires!
upgrades:
title: 20 Upgrade Tiers
desc: This demo version has only 5!
markers:
title: ∞ Markers
desc: Never get lost in your factory!
wires:
title: Wires
desc: An entirely new dimension!
darkmode:
title: Dark Mode
desc: Stop hurting your eyes!
support:
title: Support me
desc: I develop it in my spare time!
# All shop upgrades
shopUpgrades:
belt:
@ -470,6 +513,7 @@ buildings:
deliver: Deliver
toUnlock: to unlock
levelShortcut: LVL
endOfDemo: End of Demo
belt:
default:
@ -817,6 +861,11 @@ storyRewards:
Since the hub will require a <strong>throughput</strong> from now on, I highly recommend to build a machine which automatically delivers the requested shape!<br><br>
The HUB outputs the requested shape on the wires layer, so all you have to do is to analyze it and automatically configure your factory based on that.
reward_demo_end:
title: End of Demo
desc: >-
You have reached the end of the demo version!
settings:
title: Settings
categories: