import {Level} from "../wordrotator/Level/Level"; const helpIcon = require("../../img/help.png").default; const view = require("../../html/sites/level.html"); const coinSound = require("../../sound/single_coin_fall_on_concrete_.mp3").default; import {TemplateContainer} from "../wordrotator/Segment/TemplateContainer"; import {LevelHelper} from "../wordrotator/Level/LevelHelper"; import {EndSite} from "./EndSite"; import { MenuAction, Toast, ScaleHelper, Matomo, NativeStoragePromise, } from "cordova-sites/dist/client"; import {Helper} from "js-helper/dist/shared/Helper"; import {LevelData} from "../../../shared/model/LevelData"; import {LevelPlayed} from "../model/LevelPlayed"; import {ViewHelper} from "js-helper/dist/client/ViewHelper"; import {SoundManager} from "cordova-sites/dist/client/js/Sound/SoundManager"; import {MenuSite} from "cordova-sites/dist/client/js/Context/MenuSite"; export class LevelSite extends MenuSite { public static readonly RENDERER_TYPES = [20, 40, 60, 80, 81, 82, 83, 100, 110, 111, 112, 120, 140, 160]; public static readonly TUTORIAL = { FIRST_LEVEL: 67, SECOND_LEVEL: 15, BIG_SEGMENT_LEVEL: 1921 }; private coinAction: MenuAction; private levelCounterAction: MenuAction; private levelCounter: number; private levelScaler: () => void; private wonParams: { aborted: boolean; coinCounterTimer: any }; private coinPromise: Promise; private continueButtonScaler: () => Promise; private wonTextScaler: () => Promise; private wonText: HTMLElement; private templateContainer: TemplateContainer; private coinTemplate: HTMLElement; private coinContainer: HTMLElement; private level: Level; constructor(siteManager) { super(siteManager, view); // this.getNavbarFragment().setBackgroundImage(null); } async onCreateMenu(navbar) { super.onCreateMenu(navbar); let coinAction = new MenuAction(Helper.nonNull(await NativeStoragePromise.getItem("coins"), "0"), () => { }, MenuAction.SHOW_ALWAYS, 900); coinAction._shouldTranslate = false; coinAction.setLiClass("coin-counter img"); navbar.addAction(coinAction); this.coinAction = coinAction; let levelCounterAction = new MenuAction(Helper.nonNull(this.levelCounter, "1"), () => { }, MenuAction.SHOW_ALWAYS, 900); levelCounterAction._shouldTranslate = false; levelCounterAction.setLiClass("level-counter"); navbar.addAction(levelCounterAction); this.levelCounterAction = levelCounterAction; let helpAction = new MenuAction("", () => { this.help(); }, MenuAction.SHOW_ALWAYS, 900); helpAction._shouldTranslate = false; helpAction._icon = helpIcon; helpAction.setLiClass("help-action show-while-playing"); navbar.addAction(helpAction); return navbar; } async onConstruct(args) { this.levelCounter = Helper.nonNull(await NativeStoragePromise.getItem("levelCounter"), 1); // this.levelCounter = 9999; this.levelScaler = () => { }; this.wonParams = { aborted: false, coinCounterTimer: null, }; this.coinPromise = Promise.resolve(); let soundManager = SoundManager.getInstance(); soundManager.set({ audio: coinSound, muted: ((await NativeStoragePromise.getItem("play-sound", "1")) !== "1"), volume: 0.7 }, SoundManager.CHANNELS.SOUND); soundManager.resume(SoundManager.CHANNELS.MUSIC); return super.onConstruct(args); } async onViewLoaded() { let res = super.onViewLoaded(); let leafSegmentTemplate = this.findBy("#segment-leaf-template"); let parentSegmentTemplate = this.findBy("#segment-parent-template"); let rowSegmentTemplate = this.findBy("#segment-row-template"); let triangleTemplate = this.findBy("#segment-triangle-template"); let columnTemplate = this.findBy("#segment-column-template"); leafSegmentTemplate.removeAttribute("id"); parentSegmentTemplate.removeAttribute("id"); rowSegmentTemplate.removeAttribute("id"); triangleTemplate.removeAttribute("id"); columnTemplate.removeAttribute("id"); leafSegmentTemplate.remove(); parentSegmentTemplate.remove(); rowSegmentTemplate.remove(); triangleTemplate.remove(); columnTemplate.remove(); let continueButton = this.findBy("#continue-button"); continueButton.addEventListener("click", () => { continueButton.style.opacity = 0; this.nextLevel(); }); let wonText = this.findBy("#won-text"); let scaleHelper = new ScaleHelper(); this.continueButtonScaler = await scaleHelper.scaleToFull(continueButton, continueButton.parentElement, false, true, 2); this.wonTextScaler = await scaleHelper.scaleToFull(wonText, wonText.parentElement, false, false, 2, null, 5); this.wonText = wonText; this.wonText.style.fontSize = "0"; this.templateContainer = new TemplateContainer(leafSegmentTemplate, parentSegmentTemplate, rowSegmentTemplate, triangleTemplate, columnTemplate); this.coinTemplate = this.findBy("#coin-template"); this.coinContainer = this.findBy("#coin-container"); this.coinTemplate.id = null; ViewHelper.removeAllChildren(this.coinContainer); // this.findBy("#help-button").addEventListener("click", () => { // this.help(); // }); await this.loadLastLevel(); return res; } async loadLastLevel() { try { let currentLevelInfo = await NativeStoragePromise.getItem("currentLevel"); if (Helper.isNotNull(currentLevelInfo)) { currentLevelInfo = JSON.parse(currentLevelInfo); let levelData = await LevelData.findById(currentLevelInfo["id"]); if (Helper.isNull(levelData)) { return this.nextLevel(); } let level = LevelHelper.inflateLevel(levelData, this.templateContainer); level.setStartRotations(currentLevelInfo["rotations"]); level.getWonPromise().then(() => { this.levelWon(level); }); level.createSegments(); level.setLocks(currentLevelInfo["locks"]); level.getRootSegment()._updateElement(); level.saveAsCurrentLevel(); let levelSegment = this.findBy("#level"); ViewHelper.removeAllChildren(levelSegment).appendChild(level.getRootSegment().getElement()); let scaleHelper = new ScaleHelper(); this.levelScaler = await scaleHelper.scaleTo(1, levelSegment, levelSegment.parentElement, false, false, 1, level.words[0].length * 1.5, null, 0); this.level = level; Matomo.push(["trackEvent", "LevelSite", "LoadLastLevel"]); this.level.checkHasWon(); return; } } catch (e) { console.error(e); } return this.nextLevel(); } startEndSite() { this.startSite(EndSite); this.finish(); } updateLevelCounter() { this.levelCounterAction.setName(this.levelCounter); if (this.levelCounter >= 10 && this.levelCounter <= 99) { this.levelCounterAction.setLiClass("num-10 level-counter"); } else if (this.levelCounter >= 100 && this.levelCounter <= 999) { this.levelCounterAction.setLiClass("num-100 level-counter"); } else if (this.levelCounter >= 1000) { this.levelCounterAction.setLiClass("num-1000 level-counter"); } else { this.levelCounterAction.setLiClass("level-counter"); } } async nextLevel() { this.showLoadingSymbol(); try { let levelData = await LevelPlayed.getNextLevelData(LevelSite.RENDERER_TYPES); if (Helper.isNull(levelData)) { this.startEndSite(); return; } const level = LevelHelper.inflateLevel(levelData, this.templateContainer); //Waiting for Level to be done if (this.level && level.id === this.level.id) { console.log("Level is the same as before! reload!"); await new Promise((resolve) => setTimeout(resolve, 50)); // return; debugger; return this.nextLevel(); } level.getWonPromise().then(async () => { await this.levelWon(level); }); level.createSegments(); level.getRootSegment()._updateElement(); level.saveAsCurrentLevel(); let levelSegment = this.findBy("#level"); ViewHelper.removeAllChildren(levelSegment).appendChild(level.getRootSegment().getElement()); this._view.classList.remove('won'); this.wonText.style.fontSize = "0"; this.removeLoadingSymbol(); let scaleHelper = new ScaleHelper(); this.levelScaler = await scaleHelper.scaleToFull(levelSegment, levelSegment.parentElement, false, false, 1, level.words[0].length * 1.5, null, 0); this.level = level; this.updateLevelCounter(); this.coinAction.setName(Helper.nonNull(await NativeStoragePromise.getItem("coins"), "0")); // this.coinAction.redraw(); this.wonParams.aborted = true; clearTimeout(this.wonParams.coinCounterTimer); Matomo.push(["trackEvent", "LevelSite", "NextLevel", "Level Number Normal", this.levelCounter]); this.level.checkHasWon(); return this.tutorial(); } catch (e) { console.log("Fehler!"); console.error(e); this.startEndSite(); } } async onStart(args) { this.setTitle("WR"); Matomo.update("Level Sites"); let res = super.onStart(args); if (this.levelCounterAction) { this.updateLevelCounter(); } this.levelScaler(); //TODO Sound let soundManager = SoundManager.getInstance(); soundManager.set({ audio: coinSound, muted: (await NativeStoragePromise.getItem("play-sound", "1") !== "1"), volume: 0.7 }, SoundManager.CHANNELS.SOUND); await this.tutorial(); return res; } async levelWon(level) { try { const savePromise = LevelPlayed.setPlayed(level.getLevelData()); // savePromise.then((r) => console.log("levelSaved!", r)); this.levelCounter++; await NativeStoragePromise.setItem("levelCounter", this.levelCounter); await NativeStoragePromise.remove("currentLevel"); let continueButton = this.findBy("#continue-button"); continueButton.style.transition = "none"; continueButton.style.opacity = 0; //Todo richtiges Element aufrufen? this._view.classList.add('won'); ViewHelper.removeAllChildren(this.coinContainer); let coinsPerLevel = await NativeStoragePromise.getItem("coinsPerLevel", 5); let coinsBefore = 0; let soundManager = SoundManager.getInstance(); let audioOptions = soundManager.get(SoundManager.CHANNELS.SOUND); this.coinPromise = this.coinPromise.then(async () => { coinsBefore = parseInt(Helper.nonNull(await NativeStoragePromise.getItem("coins"), "0")); await NativeStoragePromise.setItem("coins", coinsBefore + parseInt(coinsPerLevel)); }).then(async () => { return Promise.all([new Promise((r) => { setTimeout(() => { //TODO animationen einbauen continueButton.style.opacity = 1; r(); }, 500) }), audioOptions.loadedPromise.catch(e => { console.error(e) }) ]); }); this.wonParams.aborted = false; for (let i = 0; i < coinsPerLevel; i++) { let coinElem = this.coinTemplate.cloneNode(true); this.coinContainer.appendChild(coinElem); this.coinPromise = this.coinPromise.then(() => { return new Promise(r => { let timeout = 350; if (!this.wonParams.aborted) { //TODO animationen einbauen coinElem.style.opacity = "1"; soundManager.play(SoundManager.CHANNELS.SOUND); this.wonParams.coinCounterTimer = setTimeout(() => { if (!this.wonParams.aborted) { this.coinAction.setName(++coinsBefore); } }, timeout / 2); } else { r(); } //Always do the next promise for garbage collection setTimeout(r, timeout); }) }); } this.coinPromise = this.coinPromise.catch((e) => { console.error(e) }); this.wonTextScaler(); this.continueButtonScaler(); this.levelScaler(); Matomo.push(["trackEvent", "LevelSite", "LevelWon", "Coins", parseInt(Helper.nonNull(await NativeStoragePromise.getItem("coins"), "0"))]); let leafs = level.getLeafSegments(); leafs.forEach((leaf, i) => { let elem = leaf.getElement(); elem.style.animationDelay = i * 50 + "ms"; elem.classList.add("jump-animation"); }) await savePromise; } catch (e) { console.error(e); } } async help() { let cost = await NativeStoragePromise.getItem("costForHelp", 25); let currentCoins = parseInt(Helper.nonNull(await NativeStoragePromise.getItem("coins"), 0)); if (currentCoins >= cost) { currentCoins -= cost; await NativeStoragePromise.setItem("coins", currentCoins); this.coinAction.setName(currentCoins); let rotatables = this.level.getRotatableSegments(); rotatables = rotatables.filter((segment) => { return (!segment.isSolved(false)); }); let index = Math.floor(Math.random() * rotatables.length); let segmentToHelp = rotatables[index]; while (segmentToHelp.rotation !== 0) { segmentToHelp.rotate(); } segmentToHelp.setIsRotatable(false); this.level.saveAsCurrentLevel(); // Matomo.push(["trackEvent", "LevelSite", "Help", "Coins", parseInt(Helper.nonNull(localStorage.getItem("coins"), "0"))]); } else { new Toast("not-enough-coins").show(); // Matomo.push(["trackEvent", "LevelSite", "Help", "Not enough Coins", parseInt(Helper.nonNull(localStorage.getItem("coins"), "0"))]); } } async tutorial() { const tutorialScale = 0.01; if (this.level.id === LevelSite.TUTORIAL.FIRST_LEVEL) { let currentStep = Helper.nonNull(await NativeStoragePromise.getItem("tutorial-step"), "1"); let scaleHelper = new ScaleHelper(); this._view.classList.add("tutorial"); this._view.classList.add("step-" + currentStep); switch (currentStep) { case "1": { this.level.setSegmentClickedListener(async () => { this._view.classList.remove("step-1"); await NativeStoragePromise.setItem("tutorial-step", "2"); this.tutorial(); }); // let textElem = this.findBy(".tutorial-text .step-1"); await this.levelScaler(); // scaleHelper.scaleTo(tutorialScale, textElem, textElem.parentElement, null, true, 2, 2); break; } case "2": { this.level.setSegmentClickedListener(() => { }); this.level.getWonPromise().then(async () => { this._view.classList.remove("tutorial"); this._view.classList.remove("step-2"); await NativeStoragePromise.remove("tutorial-step"); this.coinPromise = this.coinPromise.then(async () => { new Toast("extra-coins-after-first-level").show(); await NativeStoragePromise.setItem("coins", parseInt(Helper.nonNull(await NativeStoragePromise.getItem("coins"), "0")) + 50); this.coinAction.setName(Helper.nonNull(await NativeStoragePromise.getItem("coins"), "0")); // this.coinAction.redraw(); }); }); // let textElem = this.findBy(".tutorial-text .step-2"); await this.levelScaler(); // scaleHelper.scaleTo(tutorialScale, textElem, textElem.parentElement, null, true, 1, 2); break; } default: { this._view.classList.remove("tutorial"); } } } else if (this.level.id === LevelSite.TUTORIAL.SECOND_LEVEL) { let currentStep = Helper.nonNull(await NativeStoragePromise.getItem("tutorial-step"), "3"); switch (currentStep) { case "3": { let scaleHelper = new ScaleHelper(); this._view.classList.add("tutorial"); this._view.classList.add("step-" + currentStep); let eventListener = async () => { this._view.classList.remove("tutorial"); this._view.classList.remove("step-3"); await NativeStoragePromise.setItem("tutorial-step", "4"); // this.findBy("#help-button").removeEventListener("click", eventListener); this.levelScaler(); }; this.findBy(".help-action").addEventListener("click", eventListener); // let textElem = this.findBy(".tutorial-text .step-3"); await this.levelScaler(); // scaleHelper.scaleTo(tutorialScale, textElem, textElem.parentElement, null, true, 1, 2); break; } default: { this._view.classList.remove("tutorial"); } } } else if (this.level.id === LevelSite.TUTORIAL.BIG_SEGMENT_LEVEL) { let currentStep = Helper.nonNull(await NativeStoragePromise.getItem("tutorial-step"), "4"); switch (currentStep) { case "4": { let scaleHelper = new ScaleHelper(); this._view.classList.add("tutorial"); this._view.classList.add("step-" + currentStep); let rotatableSegments = this.level.getRotatableSegments(); let firstSegment = rotatableSegments[2]; let pointer = this.findBy("#tutorial-pointer"); pointer.remove(); firstSegment.element.appendChild(pointer); this.level.setSegmentClickedListener(async (segment) => { if (firstSegment === segment) { this._view.classList.remove("tutorial"); this._view.classList.remove("step-4"); await NativeStoragePromise.setItem("tutorial-step", "5"); this.levelScaler(); } }); // let textElem = this.findBy(".tutorial-text .step-4"); await this.levelScaler(); // debugger; // scaleHelper.scaleTo(tutorialScale, textElem, textElem.parentElement, null, true, 1, 2); break; } default: { this._view.classList.remove("tutorial"); } } } } }