wordRotator/src/client/js/Sites/LevelSite.ts
2021-05-17 18:41:48 +02:00

544 lines
20 KiB
TypeScript

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<any>;
private continueButtonScaler: () => Promise<unknown>;
private wonTextScaler: () => Promise<unknown>;
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<void>((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 = <HTMLElement>this.coinTemplate.cloneNode(true);
this.coinContainer.appendChild(coinElem);
this.coinPromise = this.coinPromise.then(() => {
return new Promise<void>(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");
}
}
}
}
}