1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2024-10-27 20:34:29 +00:00

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 { #ingame_HUD_BlueprintPlacer {
position: absolute; position: absolute;
@include S(top, 50px); @include S(top, 70px);
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
color: #333; color: #333;
z-index: 9999; z-index: 9999;
background: $ingameHudBg; background: $ingameHudBg;
@include S(padding, 5px); @include S(padding, 5px);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
color: #fff; color: #fff;
@include S(width, 120px); @include S(width, 120px);
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@include S(border-radius, $globalBorderRadius);
.label {
@include PlainText; .label {
text-transform: uppercase; @include PlainText;
} text-transform: uppercase;
.costContainer { }
display: flex; .costContainer {
align-items: center; display: flex;
@include Heading; align-items: center;
@include Heading;
> canvas {
@include S(margin-left, 5px); > canvas {
@include S(width, 30px); @include S(margin-left, 5px);
@include S(height, 30px); @include S(width, 30px);
} @include S(height, 30px);
} }
}
&:not(.canAfford) {
background: rgba(98, 27, 41, 0.8); &:not(.canAfford) {
// .costContainer { background: rgba(98, 27, 41, 0.8);
color: rgb(255, 97, 128); // .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 { #ingame_HUD_Watermark {
position: absolute; position: absolute;
& {
/* @load-async */
background: uiResource("get_on_steam.png") center center / contain no-repeat;
}
@include S(width, 110px); @include S(border-radius, $globalBorderRadius);
@include S(height, 40px); @include S(top, 70px);
@include S(top, 10px);
pointer-events: all; pointer-events: all;
cursor: pointer; 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 { &:hover {
transform: skewX(-1deg) scale(1.02); transform: translateX(-50%) scale(1.02) !important;
opacity: 0.9; }
> 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/color_blind_helper";
@import "ingame_hud/shape_viewer"; @import "ingame_hud/shape_viewer";
@import "ingame_hud/sandbox_controller"; @import "ingame_hud/sandbox_controller";
@import "ingame_hud/standalone_advantages";
// prettier-ignore // prettier-ignore
$elements: $elements:
@ -77,6 +78,7 @@ ingame_HUD_buildings_toolbar,
ingame_HUD_wires_toolbar, ingame_HUD_wires_toolbar,
ingame_HUD_BlueprintPlacer, ingame_HUD_BlueprintPlacer,
ingame_HUD_Waypoints_Hint, ingame_HUD_Waypoints_Hint,
ingame_HUD_WatermarkClicker,
ingame_HUD_Watermark, ingame_HUD_Watermark,
ingame_HUD_ColorBlindBelowTileHelper, ingame_HUD_ColorBlindBelowTileHelper,
ingame_HUD_SandboxController, ingame_HUD_SandboxController,
@ -88,6 +90,7 @@ ingame_HUD_BetaOverlay,
ingame_HUD_Shop, ingame_HUD_Shop,
ingame_HUD_Statistics, ingame_HUD_Statistics,
ingame_HUD_ShapeViewer, ingame_HUD_ShapeViewer,
ingame_HUD_StandaloneAdvantages,
ingame_HUD_UnlockNotification, ingame_HUD_UnlockNotification,
ingame_HUD_SettingsMenu, ingame_HUD_SettingsMenu,
ingame_HUD_ModalDialogs; 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 { RandomNumberGenerator } from "../core/rng";
import { clamp, findNiceIntegerValue, randomChoice, randomInt } from "../core/utils"; import { clamp, findNiceIntegerValue, randomChoice, randomInt } from "../core/utils";
import { BasicSerializableObject, types } from "../savegame/serialization"; import { BasicSerializableObject, types } from "../savegame/serialization";
@ -29,6 +29,10 @@ export class HubGoals extends BasicSerializableObject {
return errorCode; return errorCode;
} }
if (IS_DEMO) {
this.level = Math.min(this.level, tutorialGoals.length);
}
// Compute gained rewards // Compute gained rewards
for (let i = 0; i < this.level - 1; ++i) { for (let i = 0; i < this.level - 1; ++i) {
if (i < tutorialGoals.length) { if (i < tutorialGoals.length) {
@ -102,13 +106,23 @@ export class HubGoals extends BasicSerializableObject {
if (ev.key === "b") { if (ev.key === "b") {
// root is not guaranteed to exist within ~0.5s after loading in // root is not guaranteed to exist within ~0.5s after loading in
if (this.root && this.root.app && this.root.app.gameAnalytics) { 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 * Returns how much of the current shape is stored
* @param {ShapeDefinition} definition * @param {ShapeDefinition} definition
@ -190,7 +204,9 @@ export class HubGoals extends BasicSerializableObject {
this.getCurrentGoalDelivered() >= this.currentGoal.required || this.getCurrentGoalDelivered() >= this.currentGoal.required ||
(G_IS_DEV && globalConfig.debug.rewardsInstant) (G_IS_DEV && globalConfig.debug.rewardsInstant)
) { ) {
this.onGoalCompleted(); if (!this.isEndOfDemoReached()) {
this.onGoalCompleted();
}
} }
} }
@ -254,6 +270,11 @@ export class HubGoals extends BasicSerializableObject {
return false; return false;
} }
if (IS_DEMO && currentLevel >= 4) {
// DEMO
return false;
}
if (G_IS_DEV && globalConfig.debug.upgradesNoCost) { if (G_IS_DEV && globalConfig.debug.upgradesNoCost) {
return true; return true;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,44 +1,67 @@
import { BaseHUDPart } from "../base_hud_part"; import { THIRDPARTY_URLS } from "../../../core/config";
import { DrawParameters } from "../../../core/draw_parameters"; import { makeDiv } from "../../../core/utils";
import { makeDiv } from "../../../core/utils"; import { T } from "../../../translations";
import { THIRDPARTY_URLS } from "../../../core/config"; import { BaseHUDPart } from "../base_hud_part";
import { T } from "../../../translations"; import { DynamicDomAttach } from "../dynamic_dom_attach";
export class HUDWatermark extends BaseHUDPart { export class HUDWatermark extends BaseHUDPart {
createElements(parent) { createElements(parent) {
this.element = makeDiv(parent, "ingame_HUD_Watermark"); this.element = makeDiv(
} parent,
"ingame_HUD_Watermark",
initialize() { [],
this.trackClicks(this.element, this.onWatermarkClick); `
} <strong>${T.ingame.watermark.title}</strong>
<p>${T.ingame.watermark.desc}</p>
onWatermarkClick() { `
this.root.app.analytics.trackUiClick("watermark_click_2"); );
this.root.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.standaloneStorePage);
} this.linkElement = makeDiv(
parent,
/** "ingame_HUD_WatermarkClicker",
* [],
* @param {DrawParameters} parameters T.ingame.watermark.get_on_steam
*/ );
drawOverlays(parameters) { this.trackClicks(this.linkElement, () => {
const w = this.root.gameWidth; this.root.app.analytics.trackUiClick("watermark_click_2_direct");
const x = 280 * this.root.app.getEffectiveUiScale(); this.root.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.standaloneStorePage + "?ref=wtmd");
});
parameters.context.fillStyle = "#f77"; }
parameters.context.font = "bold " + this.root.app.getEffectiveUiScale() * 17 + "px GameFont";
// parameters.context.textAlign = "center"; initialize() {
parameters.context.fillText( this.trackClicks(this.element, this.onWatermarkClick);
T.demoBanners.title.toUpperCase(),
x, this.domAttach = new DynamicDomAttach(this.root, this.element, {
this.root.app.getEffectiveUiScale() * 27 attachClass: "visible",
); timeToKeepSeconds: 0.5,
});
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); update() {
this.domAttach.update(this.root.time.realtimeNow() % (G_IS_DEV ? 20 : 180) < 5);
// parameters.context.textAlign = "left"; }
}
} 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 { smoothenDpi } from "../../core/dpi_manager";
import { DrawParameters } from "../../core/draw_parameters"; import { DrawParameters } from "../../core/draw_parameters";
import { drawSpriteClipped } from "../../core/draw_utils"; import { drawSpriteClipped } from "../../core/draw_utils";
@ -65,6 +65,17 @@ export class HubSystem extends GameSystemWithFilter {
this.hubSprite.draw(context, 0, 0, w, h); 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; const definition = this.root.hubGoals.currentGoal.definition;
definition.drawCentered(45, 58, parameters, 36); definition.drawCentered(45, 58, parameters, 36);

View File

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

View File

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

View File

@ -312,7 +312,7 @@ export class MainMenuState extends GameState {
onSteamLinkClicked() { onSteamLinkClicked() {
this.app.analytics.trackUiClick("main_menu_steam_link_2"); 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; return false;
} }
@ -537,7 +537,7 @@ export class MainMenuState extends GameState {
); );
getStandalone.add(() => { getStandalone.add(() => {
this.app.analytics.trackUiClick("visit_steampage_from_slot_limit"); 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="${ <a href="${
THIRDPARTY_URLS.standaloneStorePage THIRDPARTY_URLS.standaloneStorePage + "?ref=mobile"
}" class="standaloneLink" target="_blank">Get the shapez.io standalone!</a> }" class="standaloneLink" target="_blank">Get the shapez.io standalone!</a>
`; `;
} }

View File

@ -449,6 +449,49 @@ ingame:
n_miners: <amount> Miners n_miners: <amount> Miners
limited_items: Limited to <max_throughput> 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 # All shop upgrades
shopUpgrades: shopUpgrades:
belt: belt:
@ -470,6 +513,7 @@ buildings:
deliver: Deliver deliver: Deliver
toUnlock: to unlock toUnlock: to unlock
levelShortcut: LVL levelShortcut: LVL
endOfDemo: End of Demo
belt: belt:
default: 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> 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. 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: settings:
title: Settings title: Settings
categories: categories: