diff --git a/artwork/gamedistribution/1280x550.jpg b/artwork/gamedistribution/1280x550.jpg
new file mode 100644
index 00000000..9f5c0f44
Binary files /dev/null and b/artwork/gamedistribution/1280x550.jpg differ
diff --git a/artwork/gamedistribution/1280x550.png b/artwork/gamedistribution/1280x550.png
new file mode 100644
index 00000000..5086af18
Binary files /dev/null and b/artwork/gamedistribution/1280x550.png differ
diff --git a/artwork/gamedistribution/1280x720.jpg b/artwork/gamedistribution/1280x720.jpg
new file mode 100644
index 00000000..ea2bb545
Binary files /dev/null and b/artwork/gamedistribution/1280x720.jpg differ
diff --git a/artwork/gamedistribution/1280x720.png b/artwork/gamedistribution/1280x720.png
new file mode 100644
index 00000000..191fe91a
Binary files /dev/null and b/artwork/gamedistribution/1280x720.png differ
diff --git a/artwork/gamedistribution/1280x720.psd b/artwork/gamedistribution/1280x720.psd
new file mode 100644
index 00000000..e1c7a047
Binary files /dev/null and b/artwork/gamedistribution/1280x720.psd differ
diff --git a/artwork/gamedistribution/512x340.jpg b/artwork/gamedistribution/512x340.jpg
new file mode 100644
index 00000000..d34f34af
Binary files /dev/null and b/artwork/gamedistribution/512x340.jpg differ
diff --git a/artwork/gamedistribution/512x340.png b/artwork/gamedistribution/512x340.png
new file mode 100644
index 00000000..33eb371c
Binary files /dev/null and b/artwork/gamedistribution/512x340.png differ
diff --git a/artwork/gamedistribution/512x384.jpg b/artwork/gamedistribution/512x384.jpg
new file mode 100644
index 00000000..77d3b3ad
Binary files /dev/null and b/artwork/gamedistribution/512x384.jpg differ
diff --git a/artwork/gamedistribution/512x384.png b/artwork/gamedistribution/512x384.png
new file mode 100644
index 00000000..65fd95c4
Binary files /dev/null and b/artwork/gamedistribution/512x384.png differ
diff --git a/artwork/gamedistribution/512x384.psd b/artwork/gamedistribution/512x384.psd
new file mode 100644
index 00000000..1bc2e2bc
Binary files /dev/null and b/artwork/gamedistribution/512x384.psd differ
diff --git a/artwork/gamedistribution/512x512.jpg b/artwork/gamedistribution/512x512.jpg
new file mode 100644
index 00000000..db293db4
Binary files /dev/null and b/artwork/gamedistribution/512x512.jpg differ
diff --git a/artwork/gamedistribution/512x512.png b/artwork/gamedistribution/512x512.png
new file mode 100644
index 00000000..81c8b737
Binary files /dev/null and b/artwork/gamedistribution/512x512.png differ
diff --git a/artwork/gamedistribution/iframe/iframe.zip b/artwork/gamedistribution/iframe/iframe.zip
new file mode 100644
index 00000000..133206b0
Binary files /dev/null and b/artwork/gamedistribution/iframe/iframe.zip differ
diff --git a/artwork/gamedistribution/iframe/index.html b/artwork/gamedistribution/iframe/index.html
new file mode 100644
index 00000000..801b3c20
--- /dev/null
+++ b/artwork/gamedistribution/iframe/index.html
@@ -0,0 +1,85 @@
+
+
+
+ shapez.io
+
+
+
+
+
+
+
+
+
diff --git a/artwork/gamedistribution/iframe/manifest.json b/artwork/gamedistribution/iframe/manifest.json
new file mode 100644
index 00000000..539af604
--- /dev/null
+++ b/artwork/gamedistribution/iframe/manifest.json
@@ -0,0 +1,8 @@
+{
+ "name": "shapez.io",
+ "short_name": "shapez.io",
+ "start_url": "index.html",
+ "display": "standalone",
+ "background_color": "#222428",
+ "description": "shapez.io"
+}
diff --git a/src/css/common.scss b/src/css/common.scss
index 34d6f5b5..242bb9c7 100644
--- a/src/css/common.scss
+++ b/src/css/common.scss
@@ -72,6 +72,33 @@ body {
overflow: hidden;
@include Text;
+ &.externalAdOpen {
+ &::before {
+ text-transform: uppercase;
+ @include SuperSmallText;
+ content: "Loading Advertisement...";
+ color: #333;
+ position: fixed;
+ top: 0;
+ pointer-events: all;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(50, 60, 70, 0.8);
+ z-index: 9999;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ color: #fff;
+
+ @include InlineAnimation(1s ease-in-out infinite) {
+ 50% {
+ transform: scale(1.05);
+ }
+ }
+ }
+ }
+
// For recording the bg video
// filter: blur(5px);
diff --git a/src/css/main.scss b/src/css/main.scss
index 2d3f6857..7a3c6df3 100644
--- a/src/css/main.scss
+++ b/src/css/main.scss
@@ -96,6 +96,7 @@ body.uiHidden {
}
body.modalDialogActive,
+body.externalAdOpen,
body.ingameDialogOpen {
> *:not(.ingameDialog):not(.modalDialogParent):not(.loadingDialog):not(.gameLoadingOverlay):not(#ingame_HUD_ModalDialogs) {
filter: blur(5px) !important;
diff --git a/src/js/core/click_detector.js b/src/js/core/click_detector.js
index fe0b5690..a4aece50 100644
--- a/src/js/core/click_detector.js
+++ b/src/js/core/click_detector.js
@@ -38,6 +38,7 @@ export let clickDetectorGlobals = {
* targetOnly?: boolean,
* maxDistance?: number,
* clickSound?: string,
+ * preventClick?: boolean,
* }} ClickDetectorConstructorArgs
*/
@@ -55,6 +56,7 @@ export class ClickDetector {
* @param {boolean=} param1.targetOnly Whether to also accept clicks on child elements (e.target !== element)
* @param {number=} param1.maxDistance The maximum distance in pixels to accept clicks
* @param {string=} param1.clickSound Sound key to play on touchdown
+ * @param {boolean=} param1.preventClick Whether to prevent click events
*/
constructor(
element,
@@ -66,6 +68,7 @@ export class ClickDetector {
targetOnly = false,
maxDistance = MAX_MOVE_DISTANCE_PX,
clickSound = SOUNDS.uiClick,
+ preventClick = false,
}
) {
assert(element, "No element given!");
@@ -78,6 +81,7 @@ export class ClickDetector {
this.targetOnly = targetOnly;
this.clickSound = clickSound;
this.maxDistance = maxDistance;
+ this.preventClick = preventClick;
// Signals
this.click = new Signal();
@@ -128,6 +132,10 @@ export class ClickDetector {
this.element.removeEventListener("mousemove", this.handlerTouchMove, options);
}
+ if (this.preventClick) {
+ this.element.removeEventListener("click", this.handlerPreventClick, options);
+ }
+
this.click.removeAll();
this.touchstart.removeAll();
this.touchmove.removeAll();
@@ -142,6 +150,14 @@ export class ClickDetector {
// INTERNAL METHODS
+ /**
+ *
+ * @param {Event} event
+ */
+ internalPreventClick(event) {
+ event.preventDefault();
+ }
+
/**
* Internal method to get the options to pass to an event listener
*/
@@ -164,6 +180,11 @@ export class ClickDetector {
this.handlerTouchMove = this.internalOnPointerMove.bind(this);
this.handlerTouchCancel = this.internalOnTouchCancel.bind(this);
+ if (this.preventClick) {
+ this.handlerPreventClick = this.internalPreventClick.bind(this);
+ element.addEventListener("click", this.handlerPreventClick, options);
+ }
+
element.addEventListener("touchstart", this.handlerTouchStart, options);
element.addEventListener("touchend", this.handlerTouchEnd, options);
element.addEventListener("touchcancel", this.handlerTouchCancel, options);
diff --git a/src/js/core/config.js b/src/js/core/config.js
index 74436202..67277dba 100644
--- a/src/js/core/config.js
+++ b/src/js/core/config.js
@@ -101,6 +101,7 @@ export const globalConfig = {
// framePausesBetweenTicks: 40,
// testTranslations: true,
// enableEntityInspector: true,
+ testAds: true,
/* dev:end */
},
diff --git a/src/js/game/hud/parts/unlock_notification.js b/src/js/game/hud/parts/unlock_notification.js
index 13c0cd76..44fa7deb 100644
--- a/src/js/game/hud/parts/unlock_notification.js
+++ b/src/js/game/hud/parts/unlock_notification.js
@@ -47,7 +47,7 @@ export class HUDUnlockNotification extends BaseHUDPart {
this.btnClose.innerText = "Next level";
dialog.appendChild(this.btnClose);
- this.trackClicks(this.btnClose, this.close);
+ this.trackClicks(this.btnClose, this.requestClose);
}
/**
@@ -119,6 +119,12 @@ export class HUDUnlockNotification extends BaseHUDPart {
this.root.soundProxy.playUi(SOUNDS.levelComplete);
}
+ requestClose() {
+ this.root.app.adProvider.showVideoAd().then(() => {
+ this.close();
+ });
+ }
+
close() {
this.visible = false;
}
diff --git a/src/js/platform/ad_providers/gamedistribution.js b/src/js/platform/ad_providers/gamedistribution.js
new file mode 100644
index 00000000..431d6096
--- /dev/null
+++ b/src/js/platform/ad_providers/gamedistribution.js
@@ -0,0 +1,125 @@
+/* typehints:start */
+import { Application } from "../../application";
+/* typehints:end */
+
+import { AdProviderInterface } from "../ad_provider";
+import { performanceNow } from "../../core/builtins";
+import { createLogger } from "../../core/logging";
+
+const minimumTimeBetweenVideoAdsMs = G_IS_DEV ? 1 : 5 * 60 * 1000;
+
+const logger = createLogger("gamedistribution");
+
+export class GamedistributionAdProvider extends AdProviderInterface {
+ /**
+ *
+ * @param {Application} app
+ */
+ constructor(app) {
+ super(app);
+
+ /**
+ * The resolve function to finish the current video ad. Null if none is currently running
+ * @type {Function}
+ */
+ this.videoAdResolveFunction = null;
+
+ /**
+ * The current timer which will timeout the resolve
+ */
+ this.videoAdResolveTimer = null;
+
+ /**
+ * When we showed the last video ad
+ */
+ this.lastVideoAdShowTime = -1e20;
+
+ console.error("X");
+ }
+
+ getHasAds() {
+ return true;
+ }
+
+ getCanShowVideoAd() {
+ return (
+ this.getHasAds() &&
+ !this.videoAdResolveFunction &&
+ performanceNow() - this.lastVideoAdShowTime > minimumTimeBetweenVideoAdsMs
+ );
+ }
+
+ initialize() {
+ // No point to initialize everything if ads are not supported
+ if (!this.getHasAds()) {
+ return Promise.resolve();
+ }
+
+ logger.log("🎬 Initializing gamedistribution ads");
+
+ try {
+ parent.postMessage("shapezio://gd.game_loaded", "*");
+ } catch (ex) {
+ return Promise.reject("Frame communication not allowed");
+ }
+
+ window.addEventListener(
+ "message",
+ event => {
+ if (event.data === "shapezio://gd.ad_started") {
+ console.log("🎬 Got ad started callback");
+ } else if (event.data === "shapezio://gd.ad_finished") {
+ console.log("🎬 Got ad finished callback");
+ if (this.videoAdResolveFunction) {
+ this.videoAdResolveFunction();
+ }
+ }
+ },
+ false
+ );
+
+ return Promise.resolve();
+ }
+
+ showVideoAd() {
+ assert(this.getHasAds(), "Called showVideoAd but ads are not supported!");
+ assert(!this.videoAdResolveFunction, "Video ad still running, can not show again!");
+ this.lastVideoAdShowTime = performanceNow();
+
+ console.log("🎬 Gamedistribution: Start ad");
+ try {
+ parent.postMessage("shapezio://gd.show_ad", "*");
+ } catch (ex) {
+ logger.warn("🎬 Failed to send message for gd ad:", ex);
+ return Promise.resolve();
+ }
+
+ document.body.classList.add("externalAdOpen");
+
+ return new Promise(resolve => {
+ // So, wait for the remove call but also remove after N seconds
+ this.videoAdResolveFunction = () => {
+ this.videoAdResolveFunction = null;
+ clearTimeout(this.videoAdResolveTimer);
+ this.videoAdResolveTimer = null;
+
+ // When the ad closed, also set the time
+ this.lastVideoAdShowTime = performanceNow();
+ resolve();
+ };
+
+ this.videoAdResolveTimer = setTimeout(() => {
+ logger.warn("Automatically closing ad after not receiving callback");
+ if (this.videoAdResolveFunction) {
+ this.videoAdResolveFunction();
+ }
+ }, 35000);
+ })
+ .catch(err => {
+ logger.error(this, "Error while resolving video ad:", err);
+ })
+ .then(() => {
+ document.body.classList.remove("externalAdOpen");
+ });
+ }
+}
diff --git a/src/js/platform/browser/embed_provider.js b/src/js/platform/browser/embed_provider.js
deleted file mode 100644
index 8703ec27..00000000
--- a/src/js/platform/browser/embed_provider.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import { AdProviderInterface } from "../ad_provider";
-
-/**
- * Stores information about where we are iframed
- */
-export class EmbedProvider {
- /**
- * @returns {string}
- */
- getId() {
- abstract;
- return "";
- }
-
- /**
- * Whether this provider supports ads
- * @returns {boolean}
- */
- getSupportsAds() {
- return false;
- }
-
- /**
- * Returns the ad provider
- * @returns {typeof AdProviderInterface}
- */
- getAdProvider() {
- abstract;
- return null;
- }
-
- /**
- * Whetherexternal links are supported
- * @returns {boolean}
- */
- getSupportsExternalLinks() {
- return true;
- }
-
- /**
- * Returns whether this provider is iframed
- * @returns {boolean}
- */
- getIsIframed() {
- return true;
- }
-}
diff --git a/src/js/platform/browser/embed_providers/armorgames.js b/src/js/platform/browser/embed_providers/armorgames.js
deleted file mode 100644
index 867e0a71..00000000
--- a/src/js/platform/browser/embed_providers/armorgames.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import { AdinplayAdProvider } from "../../ad_providers/adinplay";
-import { ShapezioWebsiteEmbedProvider } from "./shapezio_website";
-
-export class ArmorgamesEmbedProvider extends ShapezioWebsiteEmbedProvider {
- getId() {
- return "armorgames";
- }
-
- getAdProvider() {
- return AdinplayAdProvider;
- }
-
- getIsIframed() {
- return true;
- }
-}
diff --git a/src/js/platform/browser/embed_providers/crazygames.js b/src/js/platform/browser/embed_providers/crazygames.js
deleted file mode 100644
index dc0b09dc..00000000
--- a/src/js/platform/browser/embed_providers/crazygames.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { ShapezioWebsiteEmbedProvider } from "./shapezio_website";
-
-export class CrazygamesEmbedProvider extends ShapezioWebsiteEmbedProvider {
- getId() {
- return "crazygames";
- }
-
- getIsIframed() {
- return true;
- }
-}
diff --git a/src/js/platform/browser/embed_providers/gamedistribution.js b/src/js/platform/browser/embed_providers/gamedistribution.js
deleted file mode 100644
index 49dda339..00000000
--- a/src/js/platform/browser/embed_providers/gamedistribution.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import { AdinplayAdProvider } from "../../ad_providers/adinplay";
-import { ShapezioWebsiteEmbedProvider } from "./shapezio_website";
-
-export class GamedistributionEmbedProvider extends ShapezioWebsiteEmbedProvider {
- getId() {
- return "gamedistribution";
- }
-
- getAdProvider() {
- return AdinplayAdProvider;
- }
-
- getSupportsExternalLinks() {
- return false;
- }
-
- getIsIframed() {
- return true;
- }
-}
diff --git a/src/js/platform/browser/embed_providers/iogames_space.js b/src/js/platform/browser/embed_providers/iogames_space.js
deleted file mode 100644
index 5f7d317d..00000000
--- a/src/js/platform/browser/embed_providers/iogames_space.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { ShapezioWebsiteEmbedProvider } from "./shapezio_website";
-
-export class IogamesSpaceEmbedProvider extends ShapezioWebsiteEmbedProvider {
- getId() {
- return "iogames.space";
- }
-
- getShowUpvoteHints() {
- return true;
- }
-
- getIsIframed() {
- return true;
- }
-}
diff --git a/src/js/platform/browser/embed_providers/kongregate.js b/src/js/platform/browser/embed_providers/kongregate.js
deleted file mode 100644
index b0ed4d8b..00000000
--- a/src/js/platform/browser/embed_providers/kongregate.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { NoAdProvider } from "../../ad_providers/no_ad_provider";
-import { EmbedProvider } from "../embed_provider";
-
-export class KongregateEmbedProvider extends EmbedProvider {
- getId() {
- return "kongregate";
- }
-
- getSupportsAds() {
- return false;
- }
-
- getAdProvider() {
- return NoAdProvider;
- }
-
- getSupportsExternalLinks() {
- return true;
- }
-
- getIsIframed() {
- return true;
- }
-}
diff --git a/src/js/platform/browser/embed_providers/miniclip.js b/src/js/platform/browser/embed_providers/miniclip.js
deleted file mode 100644
index e0612978..00000000
--- a/src/js/platform/browser/embed_providers/miniclip.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { ShapezioWebsiteEmbedProvider } from "./shapezio_website";
-
-export class MiniclipEmbedProvider extends ShapezioWebsiteEmbedProvider {
- getId() {
- return "miniclip";
- }
-
- getIsIframed() {
- return true;
- }
-}
diff --git a/src/js/platform/browser/embed_providers/shapezio_website.js b/src/js/platform/browser/embed_providers/shapezio_website.js
deleted file mode 100644
index 2a5359ed..00000000
--- a/src/js/platform/browser/embed_providers/shapezio_website.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { EmbedProvider } from "../embed_provider";
-import { AdinplayAdProvider } from "../../ad_providers/adinplay";
-
-export class ShapezioWebsiteEmbedProvider extends EmbedProvider {
- getId() {
- return "shapezio";
- }
-
- getSupportsAds() {
- return true;
- }
-
- getAdProvider() {
- return AdinplayAdProvider;
- }
-
- getIsIframed() {
- return false;
- }
-
- getSupportsExternalLinks() {
- return true;
- }
-}
diff --git a/src/js/platform/browser/wrapper.js b/src/js/platform/browser/wrapper.js
index 93565342..32c0e5f3 100644
--- a/src/js/platform/browser/wrapper.js
+++ b/src/js/platform/browser/wrapper.js
@@ -1,18 +1,11 @@
import { Math_min } from "../../core/builtins";
+import { globalConfig, IS_MOBILE } from "../../core/config";
import { createLogger } from "../../core/logging";
import { queryParamOptions } from "../../core/query_parameters";
import { clamp } from "../../core/utils";
-import { globalConfig, IS_MOBILE } from "../../core/config";
import { NoAdProvider } from "../ad_providers/no_ad_provider";
import { PlatformWrapperInterface } from "../wrapper";
-import { ShapezioWebsiteEmbedProvider } from "./embed_providers/shapezio_website";
-import { ArmorgamesEmbedProvider } from "./embed_providers/armorgames";
-import { IogamesSpaceEmbedProvider } from "./embed_providers/iogames_space";
-import { MiniclipEmbedProvider } from "./embed_providers/miniclip";
-import { GamedistributionEmbedProvider } from "./embed_providers/gamedistribution";
-import { KongregateEmbedProvider } from "./embed_providers/kongregate";
-import { CrazygamesEmbedProvider } from "./embed_providers/crazygames";
-import { EmbedProvider } from "./embed_provider";
+import { GamedistributionAdProvider } from "../ad_providers/gamedistribution";
const logger = createLogger("platform/browser");
@@ -20,39 +13,50 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
initialize() {
this.recaptchaTokenCallback = null;
- this.embedProvider = new ShapezioWebsiteEmbedProvider();
+ this.embedProvider = {
+ id: "shapezio-website",
+ adProvider: NoAdProvider,
+ iframed: false,
+ externalLinks: true,
+ iogLink: true,
+ };
if (!G_IS_STANDALONE && queryParamOptions.embedProvider) {
const providerId = queryParamOptions.embedProvider;
+ this.embedProvider.iframed = true;
+ this.embedProvider.iogLink = false;
switch (providerId) {
case "armorgames": {
- this.embedProvider = new ArmorgamesEmbedProvider();
+ this.embedProvider.id = "armorgames";
break;
}
case "iogames.space": {
- this.embedProvider = new IogamesSpaceEmbedProvider();
+ this.embedProvider.id = "iogames.space";
+ this.embedProvider.iogLink = true;
break;
}
case "miniclip": {
- this.embedProvider = new MiniclipEmbedProvider();
+ this.embedProvider.id = "miniclip";
break;
}
case "gamedistribution": {
- this.embedProvider = new GamedistributionEmbedProvider();
+ this.embedProvider.id = "gamedistribution";
+ this.embedProvider.externalLinks = false;
+ this.embedProvider.adProvider = GamedistributionAdProvider;
break;
}
case "kongregate": {
- this.embedProvider = new KongregateEmbedProvider();
+ this.embedProvider.id = "kongregate";
break;
}
case "crazygames": {
- this.embedProvider = new CrazygamesEmbedProvider();
+ this.embedProvider.id = "crazygames";
break;
}
@@ -62,27 +66,9 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
}
}
- logger.log("Embed provider:", this.embedProvider.getId());
+ logger.log("Embed provider:", this.embedProvider.id);
- return super.initialize().then(() => {
- // SENTRY
- if (!G_IS_DEV && false) {
- logger.log(this, "Loading sentry");
- const sentryTag = document.createElement("script");
- sentryTag.src = "https://browser.sentry-cdn.com/5.7.1/bundle.min.js";
- sentryTag.setAttribute("integrity", "TODO_SENTRY");
- sentryTag.setAttribute("crossorigin", "anonymous");
- sentryTag.addEventListener("load", this.onSentryLoaded.bind(this));
- document.head.appendChild(sentryTag);
- }
- });
- }
-
- /**
- * @returns {EmbedProvider}
- */
- getEmbedProvider() {
- return this.embedProvider;
+ return super.initialize().then(() => this.initializeAdProvider());
}
onSentryLoaded() {
@@ -151,7 +137,7 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
}
getId() {
- return "browser@" + this.embedProvider.getId();
+ return "browser@" + this.embedProvider.id;
}
getUiScale() {
@@ -173,16 +159,15 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
openExternalLink(url, force = false) {
logger.log("Opening external:", url);
- // if (force || this.embedProvider.getSupportsExternalLinks()) {
- window.open(url);
- // } else {
- // // Do nothing
- // alert("This platform does not allow opening external links. You can play on the website directly to open them.");
- // }
- }
-
- getSupportsAds() {
- return this.embedProvider.getSupportsAds();
+ if (force || this.embedProvider.externalLinks) {
+ window.open(url);
+ } else {
+ // Do nothing
+ alert(
+ "This platform does not allow opening external links. You can play on https://shapez.io directly to open them.\n\nClicked Link: " +
+ url
+ );
+ }
}
performRestart() {
@@ -218,16 +203,18 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
initializeAdProvider() {
if (G_IS_DEV && !globalConfig.debug.testAds) {
+ logger.log("Ads disabled in local environment");
return Promise.resolve();
}
// First, detect adblocker
return this.detectAdblock().then(hasAdblocker => {
if (hasAdblocker) {
+ logger.log("Adblock detected");
return;
}
- const adProvider = this.embedProvider.getAdProvider();
+ const adProvider = this.embedProvider.adProvider;
this.app.adProvider = new adProvider(this.app);
return this.app.adProvider.initialize().catch(err => {
logger.error("Failed to initialize ad provider, disabling ads:", err);
diff --git a/src/js/states/about.js b/src/js/states/about.js
index 81d556e0..e527b737 100644
--- a/src/js/states/about.js
+++ b/src/js/states/about.js
@@ -28,7 +28,16 @@ export class AboutState extends TextualGameState {
`;
}
- onEnter() {}
+ onEnter() {
+ const links = this.htmlElement.querySelectorAll("a[href]");
+ links.forEach(link => {
+ this.trackClicks(
+ link,
+ () => this.app.platformWrapper.openExternalLink(link.getAttribute("href")),
+ { preventClick: true }
+ );
+ });
+ }
getDefaultPreviousState() {
return "SettingsState";
diff --git a/src/js/states/main_menu.js b/src/js/states/main_menu.js
index 5665bb0b..0f4481ce 100644
--- a/src/js/states/main_menu.js
+++ b/src/js/states/main_menu.js
@@ -11,6 +11,7 @@ import {
import { ReadWriteProxy } from "../core/read_write_proxy";
import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
import { T } from "../translations";
+import { PlatformWrapperImplBrowser } from "../platform/browser/wrapper";
export class MainMenuState extends GameState {
constructor() {
@@ -76,23 +77,25 @@ export class MainMenuState extends GameState {
`;
@@ -100,6 +103,7 @@ export class MainMenuState extends GameState {
requestImportSavegame() {
if (IS_DEMO && this.app.savegameMgr.getSavegamesMetaData().length > 0) {
+ this.app.analytics.trackUiClick("importgame_slot_limit_show");
this.dialogs.showWarning(T.dialogs.oneSavegameLimit.title, T.dialogs.oneSavegameLimit.desc);
return;
}
@@ -210,16 +214,36 @@ export class MainMenuState extends GameState {
this.renderSavegames();
- const steamLinks = this.htmlElement.querySelectorAll(".steamLink");
- steamLinks.forEach(steamLink => {
- steamLink.addEventListener("click", this.onSteamLinkClicked.bind(this));
- });
+ const steamLink = this.htmlElement.querySelector(".steamLink");
+ if (steamLink) {
+ this.trackClicks(steamLink, () => this.onSteamLinkClicked(), { preventClick: true });
+ }
+
+ const discordLink = this.htmlElement.querySelector(".discordLink");
+ this.trackClicks(
+ discordLink,
+ () => this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.discord),
+ { preventClick: true }
+ );
+
+ const githubLink = this.htmlElement.querySelector(".githubLink");
+ this.trackClicks(
+ githubLink,
+ () => this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.github),
+ { preventClick: true }
+ );
+
+ const producerLink = this.htmlElement.querySelector(".producerLink");
+ this.trackClicks(
+ producerLink,
+ () => this.app.platformWrapper.openExternalLink("https://tobspr.com"),
+ { preventClick: true }
+ );
}
- onSteamLinkClicked(event) {
+ onSteamLinkClicked() {
this.app.analytics.trackUiClick("main_menu_steam_link");
- window.open(THIRDPARTY_URLS.standaloneStorePage);
- event.preventDefault();
+ this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.standaloneStorePage);
return false;
}
@@ -272,15 +296,13 @@ export class MainMenuState extends GameState {
resumeGame(game) {
this.app.analytics.trackUiClick("resume_game");
- // if (IS_DEMO) {
- // this.dialogs.showFeatureRestrictionInfo(T.demo.features.restoringGames);
- // return;
- // }
-
- const savegame = this.app.savegameMgr.getSavegameById(game.internalId);
- savegame.readAsync().then(() => {
- this.moveToState("InGameState", {
- savegame,
+ this.app.adProvider.showVideoAd().then(() => {
+ this.app.analytics.trackUiClick("resume_game_adcomplete");
+ const savegame = this.app.savegameMgr.getSavegameById(game.internalId);
+ savegame.readAsync().then(() => {
+ this.moveToState("InGameState", {
+ savegame,
+ });
});
});
}
@@ -289,6 +311,8 @@ export class MainMenuState extends GameState {
* @param {object} game
*/
deleteGame(game) {
+ this.app.analytics.trackUiClick("delete_game");
+
const signals = this.dialogs.showWarning(
T.dialogs.confirmSavegameDelete.title,
T.dialogs.confirmSavegameDelete.text,
@@ -329,20 +353,26 @@ export class MainMenuState extends GameState {
doStartNewGame() {
this.app.analytics.trackUiClick("startgame");
- const savegame = this.app.savegameMgr.createNewSavegame();
- this.moveToState("InGameState", {
- savegame,
+ this.app.adProvider.showVideoAd().then(() => {
+ const savegame = this.app.savegameMgr.createNewSavegame();
+
+ this.moveToState("InGameState", {
+ savegame,
+ });
+ this.app.analytics.trackUiClick("startgame_adcomplete");
});
}
onPlayButtonClicked() {
if (IS_DEMO && this.app.savegameMgr.getSavegamesMetaData().length > 0) {
+ this.app.analytics.trackUiClick("startgame_slot_limit_show");
this.dialogs.showWarning(T.dialogs.oneSavegameLimit.title, T.dialogs.oneSavegameLimit.desc);
return;
}
if (IS_DEMO) {
+ this.app.analytics.trackUiClick("startgame_pre_show");
const { ok } = this.dialogs.showWarning(
T.dialogs.demoExplanation.title,
T.dialogs.demoExplanation.desc