var Input = { STATE_CHANGE_LIMIT: 500, x: 0, y: 0, pressed: !1, currentScreen: !1, inPopup: !1, currentTouchId: !1, isTouchDevice: !1, init: function() { var self = this; document.body.addEventListener("mousedown", function(e) { self.isTouchDevice || self.onMouseDown(e) }), document.body.addEventListener("mouseup", function(e) { self.isTouchDevice || self.onMouseUp(e) }), document.body.addEventListener("mousemove", function(e) { self.isTouchDevice || self.onMouseMove(e) }), document.body.addEventListener("touchmove", function(e) { for (var i = 0; i < e.changedTouches.length; i++) e.changedTouches[i].identifier == self.currentTouchId && self.onTouchMove(e.changedTouches[i]) }), document.body.addEventListener("touchstart", function(e) { self.isTouchDevice = !0, 1 == e.touches.length && (self.currentTouchId = e.touches[0].identifier, self.onTouchStart(e.touches[0])) }), document.body.addEventListener("touchend", function(e) { for (var i = 0; i < e.changedTouches.length; i++) if (e.changedTouches[i].identifier == self.currentTouchId) { self.currentTouchId = !1, self.onTouchEnd(e.changedTouches[i]); break } }), document.body.addEventListener("keydown", function(e) { e = e || window.event; var key = e.keyCode || e.charCode; key >= 37 && 40 >= key && e.preventDefault() }), this.colliderList = {} }, setCanvasMousePos: function(x, y) { var density = app.getDevicePixelRatio(); this.x = x * density, this.y = y * density }, isIn: function(collider) { return this.x >= collider.x && this.x <= collider.x2 && this.y >= collider.y && this.y <= collider.y2 }, applyMouseDown: function() { app.onMouseDown(this.x, this.y); var list = this.colliderList[this.currentScreen]; if (list) for (var i in list) { var c = list[i]; c.ignore || !this.isIn(c) || c.visibilityHandler && !c.visibilityHandler() || (c.listener && c.listener.mousedown && c.listener.mousedown(), c.active || (c.listener && c.listener.on && c.listener.on(), c.active = !0, c.needRefresh = !0, c.changeListener && c.changeListener()), c.waitingForReturn = !0) } }, applyMouseUp: function() { app.onMouseUp(this.x, this.y); var list = this.colliderList[this.currentScreen]; if (list) for (var i in list) { var c = list[i]; c.waitingForReturn && c.listener && c.listener.mouseup && c.listener.mouseup(), c.active && (c.listener && ("function" == typeof c.listener ? c.listener() : c.listener.off && c.listener.off()), c.active = !1, c.needRefresh = !0, c.changeListener && c.changeListener()), c.waitingForReturn = !1 } }, applyMouseMove: function() { app.onMouseMove(this.x, this.y); var list = this.colliderList[this.currentScreen]; if (list) for (var i in list) { var c = list[i]; c.ignore || this.isIn(c) ? !c.ignore && c.waitingForReturn && (c.active || (c.listener && c.listener.on && c.listener.on(), c.active = !0, c.needRefresh = !0, c.changeListener && c.changeListener())) : c.active && (c.listener && c.listener.off && c.listener.off(), c.active = !1, c.needRefresh = !0, c.changeListener && c.changeListener()) } }, onMouseDown: function(e) { this.pressed = !0, this.setCanvasMousePos(e.clientX, e.clientY), this.applyMouseDown() }, onTouchStart: function(e) { e.preventDefault && e.preventDefault(), this.pressed = !0, this.setCanvasMousePos(e.clientX, e.clientY), this.applyMouseDown() }, onMouseUp: function(e) { e.preventDefault && e.preventDefault(), this.pressed = !1, this.setCanvasMousePos(e.clientX, e.clientY), this.applyMouseUp() }, onTouchEnd: function(e) { e.preventDefault && e.preventDefault(), this.pressed = !1, this.setCanvasMousePos(e.clientX, e.clientY), this.applyMouseUp() }, onMouseMove: function(e) { e.preventDefault && e.preventDefault(), this.setCanvasMousePos(e.clientX, e.clientY), this.applyMouseMove() }, onTouchMove: function(e) { e.preventDefault && e.preventDefault(), this.setCanvasMousePos(e.clientX, e.clientY), this.applyMouseMove() }, onResize: function() { this.colliderList = {} }, isActive: function(id) { return this.colliderList[this.currentScreen] && this.colliderList[this.currentScreen][id] && this.colliderList[this.currentScreen][id].active }, needRefresh: function(id) { if (id) return this.colliderList && this.colliderList[this.currentScreen] && this.colliderList[this.currentScreen][id] && this.colliderList[this.currentScreen][id].needRefresh; for (var i in this.colliderList[this.currentScreen]) if (this.needRefresh(i)) return !0; return !1 }, setRefreshed: function(id) { id && this.colliderList && this.colliderList[this.currentScreen] && this.colliderList[this.currentScreen][id] && (this.colliderList[this.currentScreen][id].needRefresh = !1) }, setCurrentScreen: function(id) { this.currentScreen = id, this.removeAllCollider() }, removeAllCollider: function() { delete this.colliderList[this.currentScreen] }, removeCollider: function(id) { delete this.colliderList[this.currentScreen][id] }, addCollider: function(id, x, y, width, height, listener, changeListener, visibilityHandler) { if (this.colliderList[this.currentScreen] || (this.colliderList[this.currentScreen] = {}), this.colliderList[this.currentScreen][id] || (this.colliderList[this.currentScreen][id] = { x: x, y: y, width: width, height: height, x2: x + width, y2: y + height, listener: listener, changeListener: changeListener, visibilityHandler: visibilityHandler, active: !1 }), this.colliderList[this.currentScreen][id].ignore = !1, Debug.COLLIDER) { var g = app.graphics; g.save(), g.setTransform(1, 0, 0, 1, 0, 0), g.fillStyle = "rgba(255, 0, 0, 0.75)", g.fillRect(x, y, width, height), g.restore() } }, startPopup: function() { for (var i in this.colliderList[this.currentScreen]) this.colliderList[this.currentScreen][i].ignore = !0; this.inPopup = !0 }, endPopup: function() { this.inPopup = !1 } }, Operator = { SUP: 1, INF: 2, EQUAL: 3 }, SGUtils = { assetManager: null, logoPosX: 0, logoPosY: 0, moreGamesPosX: 0, moreGamesPosY: 0, init: function(assetManager) { var self = this; assetManager ? (this.parentAssetManager = assetManager, this.assetManager = new AssetManager(assetManager)) : this.assetManager = new AssetManager; var SpilData = { id: "576742227280295693" }; GameAPI.loadAPI(function(apiInstance) { self.loadLogo(apiInstance), self.loadMoreGames(apiInstance), self.assetManager.addLoadingListener(function() { self.refreshInputMenu(!0) }), self.assetManager.startLoading() }, SpilData), Config.GENERAL.SPILGAMES_DEBUG && (document.onkeypress = function(e) { e = e || window.event; var key = e.keyCode || e.charCode; 49 == key ? Achievement.achievementDone(DataStore.achievementList[1].achievement_type, DataStore.achievementList[1].id) : 50 == key ? Achievement.achievementDone(DataStore.achievementList[2].achievement_type, DataStore.achievementList[2].id) : 51 == key ? Achievement.achievementDone(DataStore.achievementList[3].achievement_type, DataStore.achievementList[3].id) : 52 == key ? Achievement.achievementDone(DataStore.achievementList[4].achievement_type, DataStore.achievementList[4].id) : 53 == key && Achievement.achievementDone(DataStore.achievementList[5].achievement_type, DataStore.achievementList[5].id) }) }, loadLogo: function(apiInstance) { var self = this, logoData = apiInstance.Branding.getLogo(); logoData.image && (self.logoId = logoData.image, self.logoAction = logoData.action, self.assetManager.addImage(logoData.image, logoData.image)) }, loadMoreGames: function(apiInstance) { var buttonProperties = apiInstance.Branding.getLink("more_games"); this.moreGamesAction = buttonProperties.action }, getLogo: function() { return this.assetManager.getImage(this.logoId) }, getMoreGamesLink: function() { return this.parentAssetManager.getImage("gui.start.more_games") }, drawMenu: function(renderer) { SGUtils.getLogo() && (this.logoPosX = app.width / 2 - this.getLogo().width * app.scale / 2, renderer.drawImage(this.getLogo(), 0, 0, this.getLogo().width, this.getLogo().height, this.logoPosX, this.logoPosY, this.getLogo().width * app.scale, this.getLogo().height * app.scale)), SGUtils.getMoreGamesLink() && (this.moreGamesPosX = Math.round(renderer.width / 2 - this.getMoreGamesLink().width * app.scale - 20 * app.scale), this.moreGamesPosY = Math.round(renderer.height - this.getMoreGamesLink().height * app.scale - 20 * app.scale), renderer.drawImage(this.getMoreGamesLink(), 0, 0, this.getMoreGamesLink().width, this.getMoreGamesLink().height, this.moreGamesPosX, this.moreGamesPosY, this.getMoreGamesLink().width * app.scale, this.getMoreGamesLink().height * app.scale)) }, refreshInputMenu: function(force) { var self = this; (Input.needRefresh("spilLogo") || force) && this.getLogo() && (Input.addCollider("spilLogo", this.logoPosX, this.logoPosY, this.getLogo().width * app.scale, this.getLogo().height * app.scale, self.logoAction, null, function() { return !0 }), Input.setRefreshed("spilLogo")), (Input.needRefresh("moreGames") || force) && this.getMoreGamesLink() && (Input.addCollider("moreGames", this.moreGamesPosX, this.moreGamesPosY, this.getMoreGamesLink().width * app.scale, this.getMoreGamesLink().height * app.scale, self.moreGamesAction, null, function() { return !0 }), Input.setRefreshed("moreGames")) }, showInterstitial: function(closeListener) { GameAPI.GameBreak.request(function() { app.assetManager.muteSound(!0) }, function() { app.assetManager.muteSound(!1), closeListener() }) } }, Analytics = { initialized: !1, init: function() { DataSync.isConnected() && "undefined" != typeof FlurryAgent && (FlurryAgent.startSession("N2F5WRNC4NFK6JBC3WN4"), DataSync.getUserId() && FlurryAgent.setUserId(DataSync.getUserId()), this.initialized = !0) }, log: function(type, parameters, timed) { this.initialized || this.init(), this.initialized && FlurryAgent.logEvent(type, parameters, timed) }, endLog: function(type, parameters) { this.initialized || this.init(), this.initialized && FlurryAgent.endTimedEvent(type, parameters) } }; Array.shuffle = function(a) { var j, temp, i = a.length; if (0 == i) return a; for (; --i;) j = Math.floor(Math.random() * (i + 1)), temp = a[i], a[i] = a[j], a[j] = temp; return a }, window.requestAnimFrame = function() { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1e3 / 60) } }(), CanvasRenderingContext2D.prototype.roundRect = function(sx, sy, w, h, r) { var optim = !1, ex = sx + w, ey = sy + h; if (optim) this.beginPath(), this.rect(sx, sy, ex, ey), this.closePath(); else { var r2d = Math.PI / 180; 0 > ex - sx - 2 * r && (r = (ex - sx) / 2), 0 > ey - sy - 2 * r && (r = (ey - sy) / 2), this.beginPath(), this.moveTo(sx + r, sy), this.lineTo(ex - r, sy), this.arc(ex - r, sy + r, r, 270 * r2d, 360 * r2d, !1), this.lineTo(ex, ey - r), this.arc(ex - r, ey - r, r, 0 * r2d, 90 * r2d, !1), this.lineTo(sx + r, ey), this.arc(sx + r, ey - r, r, 90 * r2d, 180 * r2d, !1), this.lineTo(sx, sy + r), this.arc(sx + r, sy + r, r, 180 * r2d, 270 * r2d, !1), this.closePath() } }, CanvasRenderingContext2D.prototype.fillRoundRect = function(sx, sy, ex, ey, r) { this.roundRect(sx, sy, ex, ey, r), this.fill() }, CanvasRenderingContext2D.prototype.strokeRoundRect = function(sx, sy, ex, ey, r) { this.roundRect(sx, sy, ex, ey, r), this.stroke() }, CanvasRenderingContext2D.prototype.circle = function(sx, sy, r) { this.beginPath(), this.arc(sx, sy, r, 0, 2 * Math.PI), this.closePath() }, CanvasRenderingContext2D.prototype.fillCircle = function(sx, sy, r) { this.circle(sx, sy, r), this.fill() }, CanvasRenderingContext2D.prototype.strokeCircle = function(sx, sy, r) { this.circle(sx, sy, r), this.stroke() }, CanvasRenderingContext2D.prototype.resetTransform = function() { this.setTransform(1, 0, 0, 1, 0, 0) }, function() { Cocoon.Audio = function() { return this }, Cocoon.Audio.prototype = { audio: null, setAudio: function(audio) { return this.audio = audio, this.audio.load(), this }, loop: function() { return this }, play: function() { return this.audio.play(), this }, pause: function() { return this.audio.pause(), this } } }(); var DataSync = { lastWorld: 0, lastLevel: 0, lastLevelId: 0, init: function(app) { this.app = app }, isConnected: function() { return !testLevel && navigator.onLine && !PUBLISHER_NO_NET }, getUserId: function() { return getStoredInt("userId") }, logPayment: function(pack) { var self = this; this.getUserId() ? UDBT.insert("bill", { user: this.getUserId(), money_pack: pack.id, cost: pack.cost, amount: pack.total, last_world: this.lastWorld, last_level: this.lastLevel }) : this.sync(function() { self.logPayment(pack) }) }, sync: function() { var self = this; if (this.isConnected()) { if (getStoredInt("userId")) { !getStoredInt("fbid") && FBUtils.userData && UDBT.update("user", { id: getStoredInt("userId"), fbid: FBUtils.userData.id }); var searchLastLevel = !0; for (var i in DataStore.worldList) { var w = DataStore.worldList[i]; for (var j in w.levelList) { var level = w.levelList[j].id; if (getStoredInt("try-" + level)) { if (searchLastLevel && (this.lastWorld = w.index + 1, this.lastLevel = w.levelList[j].index + 1, this.lastLevelId = level), !getStoredBool("saved-" + level)) return console.log("Saving level " + level), UDBT.replace("score", { user: getStoredInt("userId"), level: level, best_score: getStoredInt("score-" + level), best_star_count: getStoredInt("stars-" + level), best_time: getStoredInt("time-" + level), defeat_count: getStoredInt("defeat-" + level), victory_count: getStoredInt("victory-" + level), try_count: getStoredInt("try-" + level) }, function() { setStoredBool("saved-" + level, !0), console.log("Level " + level + " saved !"), self.sync() }), void 0 } else searchLastLevel = !1 } } getStoredInt("lastLevelId") != this.lastLevelId && (setStoredInt("lastLevelId", this.lastLevelId), UDBT.update("user", { id: this.getUserId(), last_world: this.lastWorld, last_level: this.lastLevel, last_level_id: this.lastLevelId })) } else UDBT.insert("user", { fbid: FBUtils.userData ? FBUtils.userData.id : 0, device_model: "undefined" != typeof device ? device.model : "?", device_platform: "undefined" != typeof device ? device.platform : "?", device_uuid: "undefined" != typeof device ? device.uuid : "?", device_version: "undefined" != typeof device ? device.version : "?", device_locale: this.app.systemLocale, "creation_date:timestamp": !0 }, function(response) { FBUtils.userData && setStoredString("fbid", FBUtils.userData.id); var userId = parseInt(response); userId > 0 && 0 / 0 != userId && setStoredInt("userId", userId), self.sync() }); if (Cocoon.Social.GameCenter && Cocoon.Social.GameCenter.nativeAvailable) { var p = Cocoon.Social.GameCenter.getLocalPlayer(); if (p && p.isAuthenticated) { var worldTotal = 0; for (var i in DataStore.worldList) { var w = DataStore.worldList[i], total = 0; for (var j in w.levelList) { var level = w.levelList[j].id; total += getStoredInt("score-" + level) } worldTotal += total } Cocoon.Social.GameCenter.getSocialInterface().submitScore(worldTotal, function(e) { console.log("Score submitted ? " + e) }) } } } }, getFriendLevelData: function(level, friendList, handler) { if (0 == friendList.length) handler([]); else if (this.isConnected()) { var returnList = {}, fbidList = []; for (var i in friendList) returnList["f" + friendList[i].id] = { id: friendList[i].id, first_name: friendList[i].first_name, best_score: 0, best_star_count: 0 }, fbidList.push(friendList[i].id); UDBT.list(function(result) { for (var i in result) { var r = result[i]; returnList["f" + r.fbid] ? (returnList["f" + r.fbid].best_score = r.best_score, returnList["f" + r.fbid].best_star_count = r.best_star_count) : (console.log(returnList), console.log("[ERROR:DataSyn:getFriendLevelData] Missing returnList[f" + r.fbid + "]")) } handler(returnList) }, "user", { request: { table: "user", select: ["fbid", "best_score", "best_star_count"], where: ['fbid IN("' + fbidList.join('","') + '")', "level=" + level], join: [{ table: "score", on: "user", to: "id" }] } }) } } }; Math.tweenBack = function(t, backAt) { return backAt || (backAt = .5), backAt >= t ? t / backAt : 1 - (t - backAt) / (1 - backAt) }, Math.linearTween = function(t) { return t }, Math.easeInQuad = function(t) { return t * t }, Math.easeOutQuad = function(t) { return -t * (t - 2) }, Math.easeInOutQuad = function(t) { return t *= 2, 1 > t ? .5 * t * t : (t--, -.5 * (t * (t - 2) - 1)) }, Math.easeInCubic = function(t) { return t * t * t }, Math.easeOutCubic = function(t) { return t--, t * t * t + 1 }, Math.easeInOutCubic = function(t) { return t *= 2, 1 > t ? .5 * t * t * t : (t -= 2, .5 * (t * t * t + 2)) }, Math.easeInQuart = function(t) { return t * t * t * t }, Math.easeOutQuart = function(t) { return t--, -(t * t * t * t - 1) }, Math.easeInOutQuart = function(t) { return t *= 2, 1 > t ? .5 * t * t * t * t : (t -= 2, -.5 * (t * t * t * t - 2)) }, Math.easeInQuint = function(t) { return t * t * t * t * t }, Math.easeOutQuint = function(t) { return t--, t * t * t * t * t + 1 }, Math.easeInOutQuint = function(t) { return t *= 2, 1 > t ? .5 * t * t * t * t * t : (t -= 2, .5 * (t * t * t * t * t + 2)) }, Math.easeInSine = function(t) { return -Math.cos(t * (Math.PI / 2)) }, Math.easeOutSine = function(t) { return Math.sin(t * (Math.PI / 2)) }, Math.easeInOutSine = function(t) { return -.5 * (Math.cos(Math.PI * t) - 1) }, Math.easeInExpo = function(t) { return Math.pow(2, 10 * (t - 1)) }, Math.easeOutExpo = function(t) { return -Math.pow(2, -10 * t) + 1 }, Math.easeInOutExpo = function(t) { return t *= 2, 1 > t ? .5 * Math.pow(2, 10 * (t - 1)) : (t--, .5 * (-Math.pow(2, -10 * t) + 2)) }, Math.easeInCirc = function(t) { return -(Math.sqrt(1 - t * t) - 1) }, Math.easeOutCirc = function(t) { return t--, Math.sqrt(1 - t * t) }, Math.easeInBack = function(t) { var s = 1.70158; return t * t * ((s + 1) * t - s) }, Math.easeOutBack = function(t, s) { return s || (s = 1.70158), --t * t * ((s + 1) * t + s) + 1 }, Math.easeInOutCirc = function(t) { return t *= 2, 1 > t ? -.5 * (Math.sqrt(1 - t * t) - 1) : (t -= 2, .5 * (Math.sqrt(1 - t * t) + 1)) }, Math.easeOutElastic = function(t, f) { var ts = t * t, tc = ts * t; return f || (f = 1), f * (33 * tc * ts + -106 * ts * ts + 126 * tc + -67 * ts + 15 * t - 1) + 1 }, Math.easeInElastic = function(t) { var ts = t * t, tc = ts * t; return 33 * tc * ts + -59 * ts * ts + 32 * tc + -5 * ts }, Math.easeOutBounce = function(t) { return 1 / 2.75 > t ? 7.5625 * t * t : 2 / 2.75 > t ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : 2.5 / 2.75 > t ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375 }, Math.cycleSin = function(t, duration) { return .5 * Math.sin(2 * t * Math.PI / duration) + .5 }; var FBUtils = { init: function(appId) { this.fb = Cocoon.Social.Facebook, this.fb.init({ appId: appId, channelUrl: "//connect.facebook.net/en_US/all.js" }), this.fbInterface = this.fb.getSocialInterface() }, isLoggedIn: function() { return this.fbInterface ? this.fbInterface.isLoggedIn() : !1 }, login: function(handler) { var self = this; !this.isLoggedIn() && this.fbInterface && this.fbInterface.login(function(loggedIn, error) { error ? console.log("[FBUtils] Unable to connect : " + JSON.stringify(error)) : loggedIn ? self.fbInterface.requestUser(function(user, error) { error ? console.log("[FBUtils] Unable to retrieve user data : " + JSON.stringify(error)) : (console.log("[FBUtils] " + user.userName + " successfully logged in."), console.log(JSON.stringify(user)), self.logged = !0, self.userData = user, handler()) }) : console.log("[FBUtils] Login cancelled") }) }, logout: function() { this.isLoggedIn() && (this.fbInterface.logout(function(error) { error && console.log("[FBUtils] Unable to logout : " + JSON.stringify(error)) }), this.userData = !1, this.logged = !1) }, getFriendList: function(handler) { var self = this; "undefined" != typeof this.friendList ? handler(this.friendList) : this.logged ? this.fbInterface.requestFriends(function(friends, error) { if (error) console.log("[FBUtils] Unable to get friend list : " + JSON.stringify(error)); else { self.friendList = friends; for (var i in friends) console.log("friend " + i + " : " + JSON.stringify(friends[i])); self.getFriendList(handler) } }) : this.login(function() { self.getFriendList(handler) }) } }; window.Modernizr = function(a, b, c) { function t(a) { i.cssText = a } function v(a, b) { return typeof a === b } var j, q, s, d = "2.8.3", e = {}, f = b.documentElement, g = "modernizr", h = b.createElement(g), i = h.style, l = ({}.toString, {}), o = [], p = o.slice, r = {}.hasOwnProperty; s = v(r, "undefined") || v(r.call, "undefined") ? function(a, b) { return b in a && v(a.constructor.prototype[b], "undefined") } : function(a, b) { return r.call(a, b) }, Function.prototype.bind || (Function.prototype.bind = function(b) { var c = this; if ("function" != typeof c) throw new TypeError; var d = p.call(arguments, 1), e = function() { if (this instanceof e) { var a = function() {}; a.prototype = c.prototype; var f = new a, g = c.apply(f, d.concat(p.call(arguments))); return Object(g) === g ? g : f } return c.apply(b, d.concat(p.call(arguments))) }; return e }), l.audio = function() { var a = b.createElement("audio"), c = !1; try { (c = !!a.canPlayType) && (c = new Boolean(c), c.ogg = a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""), c.mp3 = a.canPlayType("audio/mpeg;").replace(/^no$/, ""), c.wav = a.canPlayType('audio/wav; codecs="1"').replace(/^no$/, ""), c.m4a = (a.canPlayType("audio/x-m4a;") || a.canPlayType("audio/aac;")).replace(/^no$/, "")) } catch (d) {} return c }; for (var y in l) s(l, y) && (q = y.toLowerCase(), e[q] = l[y](), o.push((e[q] ? "" : "no-") + q)); return e.addTest = function(a, b) { if ("object" == typeof a) for (var d in a) s(a, d) && e.addTest(d, a[d]); else { if (a = a.toLowerCase(), e[a] !== c) return e; b = "function" == typeof b ? b() : b, "undefined" != typeof enableClasses && enableClasses && (f.className += " " + (b ? "" : "no-") + a), e[a] = b } return e }, t(""), h = j = null, e._version = d, e }(this, this.document), getStoredInt = function(id, defaultValue) { return "undefined" == typeof defaultValue && (defaultValue = 0), null == localStorage.getItem(id) ? defaultValue : parseInt(localStorage.getItem(id)) }, setStoredInt = function(id, value) { localStorage[id] = value }, getStoredFloat = function(id, defaultValue) { return "undefined" == typeof defaultValue && (defaultValue = 0), null == localStorage.getItem(id) ? defaultValue : parseFloat(localStorage.getItem(id)) }, setStoredFloat = function(id, value) { localStorage[id] = value }, getStoredString = function(id, defaultValue) { return "undefined" == typeof defaultValue && (defaultValue = ""), null == localStorage.getItem(id) ? defaultValue : localStorage.getItem(id) }, setStoredString = function(id, value) { localStorage[id] = value }, getStoredBool = function(id, defaultValue) { if ("undefined" == typeof defaultValue && (defaultValue = !1), null == localStorage.getItem(id)) return defaultValue; var v = localStorage.getItem(id); return "false" == v.toLowerCase() || "0" == v ? !1 : !0 }, setStoredBool = function(id, value) { localStorage[id] = value ? !0 : !1 }, cleanStorage = function() { clearStoredData("start-money-received"), clearStoredData("money"), clearStoredData("money-tuto"), clearStoredData("stock-tuto"), clearStoredData("fbid"), clearStoredData("userId"), clearStoredData("locale"), clearStoredData("soundEnabled"); for (var i = 0; i < DataStore.worldList.length; i++) { clearStoredData("world-unlocked-" + DataStore.worldList[i].id); for (var j = 0; j < DataStore.worldList[i].levelList.length; j++) clearLevelData(DataStore.worldList[i].levelList[j].id) } for (var i in DataStore.bonusList) clearStoredData("bonus-" + i); for (var i in DataStore.dodoTypeList) clearStoredData("stock-" + i), clearStoredData("next-life-time-" + i); for (var i in DataStore.achievementTypeList) clearStoredData("achievement-value-" + i); for (var i in DataStore.achievementList) clearStoredData("achievement-" + i), clearStoredData("achievement-date-" + i) }, clearStoredData = function(id) { localStorage.removeItem(id) }, clearLevelData = function(levelId) { clearStoredData("stars-" + levelId), clearStoredData("score-" + levelId), clearStoredData("time-" + levelId), clearStoredData("saved-" + levelId), clearStoredData("defeat-" + levelId), clearStoredData("victory-" + levelId), clearStoredData("try-" + levelId), clearStoredData("level-unlock-" + levelId) }, clearLevelDataAfter = function(world, level) { for (var i = 0; i < DataStore.worldList.length; i++) for (var j = 0; j < DataStore.worldList[i].levelList.length; j++)(i > world || i == world && j > level) && clearLevelData(DataStore.worldList[i].levelList[j].id) }; var UDBT = { apiLow: function(handler, data) { data || (data = {}), data.project = "savethedodos", data.hash_time = Date.now(), data.hash = CryptoJS.MD5(DataStore.k + data.hash_time).toString(); var req = new XMLHttpRequest, params = []; for (var i in data) params.push(i + "=" + encodeURIComponent(data[i])); req.open("GET", "https://apps.3dduo.com/unity-db-tools/?" + params.join("&"), !0), req.onreadystatechange = function() { 4 == req.readyState && (200 == req.status ? handler(req.responseText) : console.log("[ERROR:UDBT] Unable to reach api")) }, req.send(null) }, api: function(handler, action, table, params) { var data = { action: action, table: table }; if (params) for (var i in params) data[i] = "object" == typeof params[i] ? JSON.stringify(params[i]) : params[i]; this.apiLow(function(response) { if (response) try { response = JSON.parse(response) } catch (e) { console.log("[ERROR:UDBT:api] Unable to parse response : " + e), console.log("response : " + response) } handler && handler(response) }, data) }, list: function(handler, table, params) { this.api(handler, "list", table, params) }, load: function(handler, table, params) { this.api(handler, "load", table, params) }, insert: function(table, params, handler) { this.api(handler, "insert", table, params) }, replace: function(table, params, handler) { this.api(handler, "saveUser", table, params) }, update: function(table, params, handler) { this.api(handler, "update", table, params) }, deleteUser: function(table, params, handler) { this.api(handler, "deleteUser", table, params) } }; Utils = { formatTime: function(t) { var cs = Math.floor(t % 1e3 / 10) + "", s = Math.floor(t / 1e3) % 60 + "", m = Math.floor(t / 6e4) + ""; return cs.length < 2 && (cs = "0" + cs), s.length < 2 && (s = "0" + s), m.length < 2 && (m = "0" + m), m + ":" + s + ":" + cs }, formatTimeHour: function(t) { var s = t % 60 + "", m = Math.floor(t / 60 % 60) + "", h = Math.floor(t / 3600); return s.length < 2 && (s = "0" + s), m.length < 2 && (m = "0" + m), (h ? h + ":" : "") + m + ":" + s }, splitText: function(s) { for (var r = s.split("
"), i = 0; i < r.length; i++) r[i] = r[i].trim(); return r }, ease: function(from, to, func, options) { var isObject = !0; "object" != typeof from && (from = { v: from }, to = { v: to }, isObject = !1); var o = {}; if (options) for (i in options) o[i] = options[i]; o.duration || (o.duration = 500); var fromDate = Date.now(), easeFunction = !1; o.easing && (easeFunction = Math[o.easing]); var stop = !1, step = function() { var f = (Date.now() - fromDate) / o.duration; if (f > 1 ? f = 1 : easeFunction && (f = easeFunction(f)), isObject) { var res = {}; for (i in from) res[i] = f * (to[i] - from[i]) + from[i]; func(res) } else func(f * (to.v - from.v) + from.v); 1 > f && !stop ? requestAnimFrame(step) : o.complete && o.complete() }; return requestAnimFrame(step), { stop: function() { stop = !0 } } }, canvasCount: 0, createCanvas: function(width, height) { var self = this, c = document.createElement("canvas"); return this.canvasCount++, c.dispose || (c.dispose = function() { self.canvasCount-- }), width && height && (c.width = width, c.height = height), c } }, Math.sameSign = function(a, b) { return a >= 0 && b >= 0 || 0 >= a && 0 >= b }, Math.distance = function(x1, y1, x2, y2, yFactor) { return yFactor || (yFactor = 1), Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * yFactor * (y2 - y1) * yFactor) }; var App = function() { var self = this; App.instance = this, this.canvas = document.getElementById("game"), this.canvas.style.width = "100%", this.canvas.style.height = "100%", this.graphics = this.canvas.getContext("2d"), this.graphics.lineJoin = "round", this.onResize(), this.graphics.fillStyle = "black", this.graphics.fillRect(0, 0, this.canvas.width, this.canvas.height), this.nextInterstitialMinTime = 0, this.timeData = { local: 0, appLocal: 0, global: Date.now(), localDelta: 0, globalDelta: 0 }, navigator.globalization ? navigator.globalization.getLocaleName(function(o) { self.systemLocale = o.value, console.log("System locale fetch : " + self.systemLocale) }) : navigator.language ? (self.systemLocale = navigator.language, console.log("Navigator locale fetch : " + self.systemLocale)) : "undefined" != typeof LOCALE ? (this.systemLocale = LOCALE, console.log("Manual locale set : " + self.systemLocale)) : (this.systemLocale = App.DEFAULT_LOCALE, console.log("Default locale set : " + self.systemLocale)), getStoredString("locale", !1) ? this.setLocale(getStoredString("locale")) : this.setLocale(this.systemLocale) || this.setLocale(App.DEFAULT_LOCALE), DataSync.init(this), DataSync.sync(), this.assetManager = new AssetManager, console.log("Sound format: " + this.assetManager.getSoundFileFormat()), this.assetManager.addLoadingListener(function() { self.onAppPreloaded() }), this.assetManager.startLoading(LoadingScreen.getLoadingList(imageList)), this.assetManager.initAtlases(), this.loadingScreen = new LoadingScreen(this), Analytics.log("app-loading", !1, !0) }; App.MAX_RATIO = 16 / 9, App.BASE_HEIGHT = 768, App.BASE_MAX_WIDTH = Math.round(App.MAX_RATIO * App.BASE_HEIGHT), App.DEFAULT_LOCALE = "en", App.STROKE_STYLE = "#2E180A", App.FILL_STYLE = "#FEFDF9", App.SHADOW_STYLE = "rgba(0, 0, 0, 0.6)", App.RED_STYLE = "#EB131E", App.BROWN_STROKE_STYLE = "#FFE681", App.BROWN_FILL_STYLE = "#6C430F", App.prototype.onAppPreloaded = function() { var self = this; console.log("preloading done"), this.assetManager.resetLoading(); for (var i in DataStore.soundList) this.assetManager.addSound(i, WEB_DATA_URI + "sound/common/sound-" + DataStore.soundList[i].id + AssetManager.SOUND_FILE_FORMAT); this.assetManager.addLoadingListener(function() { self.onAppLoaded() }), this.assetManager.startLoading(imageList), this.music = this.assetManager.getSound("menu-music"), console.log("start loading"), window.addEventListener("resize", function() { self.onResize() }), this.onResize(), testLevel || (this.startScreen = new StartScreen(this), this.levelSelectScreen = new LevelSelectScreen(this), this.achievementScreen = new AchievementScreen(this)), this.gameScreen = new GameScreen(this), this.loadingScreen && this.loadingScreen.show(), Input.init(), requestAnimFrame(function loop() { self.mainLoop(), requestAnimFrame(loop) }) }, App.prototype.mainLoop = function() { var now = Date.now(); this.timeData.globalDelta = now - this.timeData.global, this.timeData.global = now, this.timeData.localDelta = Math.min(50, this.timeData.globalDelta) * GameScreen.speedFactor * (this.gameScreen && this.gameScreen.world && this.gameScreen.world.dragging && Config.MOVE.PAUSE_DURING_DRAG ? 0 : 1), this.timeData.local += this.timeData.localDelta, this.timeData.appLocal += this.timeData.localDelta, this.update(), this.render() }, App.prototype.update = function() { this.appLoaded && !this.appInitialized && this.tryLaunchApp(), this.currentScreen && (StockManager.update(this.timeData), this.currentScreen.update(this.timeData), Achievement.hasIndic() && (this.currentScreen.needRefresh = !0)) }, App.prototype.render = function() { var g = this.graphics; if (this.shakeS && (this.currentScreen && (this.currentScreen.needRefresh = !0), g.save(), g.translate(Math.round(g.width / 2), Math.round(g.height / 2)), g.scale(this.shakeS, this.shakeS), g.translate(-Math.round(g.width / 2), -Math.round(g.height / 2)), g.translate(this.shakeX, this.shakeY)), StockManager.visible && this.currentScreen && (this.currentScreen.needRefresh = StockManager.needRefresh), this.currentScreen && !Money.visible && this.currentScreen.render(g), StockManager.visible && StockManager.renderPopup(g), Money.visible && Money.renderPopup(g), Achievement.renderIndic(g), this.shakeS && g.restore(), this.interstitialCheckTimer) { g.save(), g.resetTransform(), g.fillStyle = "rgba(0, 0, 0, 0.66)", g.fillRect(0, 0, g.width, g.height), g.translate(Math.round(g.width / 2), Math.round(g.height / 2)), g.scale(app.scale, app.scale), g.rotate(2 * Math.PI * (g.timeData.global % 1e3) / 1e3); var icon = this.assetManager.getAtlasImage("gui.loading.icon"); icon.render(g, -Math.round(icon.width / 2) + 1, -Math.round(icon.height / 2) + 1), g.restore() } }, App.prototype.onAppLoaded = function() { Analytics.endLog("app-loading", !1), Analytics.log("platform", this.getPlatform()), console.log("GAME LOADED"), this.appLoaded = !0, this.tryLaunchApp() }, App.prototype.tryLaunchApp = function() { var self = this; this.timeData.appLocal < this.loadingScreen.getSplashEndTime() || (this.appInitialized = !0, this.initAds(), this.refreshTrainingCanvas(), Achievement.init(), StockManager.init(), this.startScreen && this.startScreen.init(), this.gameScreen.init(), Money.init(), testLevel || this.music.playLoop(), this.startScreen ? getStoredInt("score-" + DataStore.worldList[0].levelList[0].id, 0) ? this.startScreen.show() : this.levelSelectScreen.init(function() { self.levelSelectScreen.loadWorld(0), self.levelSelectScreen.loadLevel(0) }) : this.gameScreen.loadLevel(DataStore.worldList[0], DataStore.worldList[0].levelList[0]), this.loadingScreen && this.loadingScreen.hide()) }, App.prototype.getDevicePixelRatio = function() { return this.devicePixelRatio ? this.devicePixelRatio : "undefined" != typeof devicePixelRatio ? (this.devicePixelRatio = devicePixelRatio, this.devicePixelRatio) : 1 }, App.prototype.onResize = function() { Input.onResize(), StockManager.onResize(), Money.onResize(), this.screenWidth = document.body.clientWidth, this.screenHeight = document.body.clientHeight, this.screenRatio = this.screenWidth / this.screenHeight; var density = this.getDevicePixelRatio(); this.width = this.screenWidth * density, this.height = this.screenHeight * density, this.canvas.width = this.width, this.canvas.height = this.height, this.graphics.width = this.width, this.graphics.height = this.height, this.graphics.timeData = this.timeData, this.scale = this.height / App.BASE_HEIGHT, this.currentScreen && this.currentScreen.onResize() }, App.prototype.setLocale = function(locale) { return console.log("Set locale " + locale), Gettext.setLocale(locale) ? (this.localeLanguage = Gettext.locale.split("_")[0].toLowerCase(), setStoredString("locale", locale), Achievement.needRefresh = !0, this.trainingCanvas && this.refreshTrainingCanvas(), this.levelSelectScreen && this.levelSelectScreen.refreshData(), !0) : !1 }, App.prototype.refreshTrainingCanvas = function() { this.trainingCanvas && this.trainingCanvas.dispose(), this.trainingCanvas = Utils.createCanvas(128, 128); var g2 = this.trainingCanvas.getContext("2d"); this.setSecondaryFont(g2, 20), g2.textAlign = "center", g2.strokeStyle = App.BROWN_FILL_STYLE; var training = this.assetManager.getAtlasImage("gui.common.training"); training.render(g2, this.trainingCanvas.width / 2 - training.width / 2, 0), app.fillOutlineText(g2, _2("training"), this.trainingCanvas.width / 2, 90) }, App.prototype.toggleLocale = function() { var firstLocale = Gettext.localeList[0].id, found = !1; for (var i in Gettext.localeList) { var loc = Gettext.localeList[i].id; if (found) return this.setLocale(loc), void 0; loc == Gettext.locale && (found = !0) } this.setLocale(firstLocale), Analytics.log("locale", firstLocale) }, App.prototype.getPlatform = function() { if (!this.platform) { var info = Cocoon.Device.getDeviceInfo(); this.platform = info ? info.os : "web" } return this.platform }, App.prototype.setBaseFont = function(g, size, bold) { this.fontSize = size; var font = size + "px brlnsr"; bold && (font = "bold " + font), g.font = font, g.strokeStyle = App.STROKE_STYLE, g.fillStyle = App.FILL_STYLE, g.lineWidth = Math.ceil(Math.pow(size, .45) + ("ios" == this.getPlatform() ? 2 : 0)) }, App.prototype.setSecondaryFont = function(g, size) { this.fontSize = size, g.font = size + "px edson_comics", g.strokeStyle = App.STROKE_STYLE, g.fillStyle = App.FILL_STYLE, g.lineWidth = Math.ceil(Math.pow(size, .45) + ("ios" == this.getPlatform() ? 2 : 0)) }, App.prototype.setThirdFont = function(g, size) { this.fontSize = size, g.font = size + "px brlnsdb", g.strokeStyle = App.STROKE_STYLE, g.fillStyle = App.FILL_STYLE, g.lineWidth = Math.ceil(Math.pow(size, .45) + ("ios" == this.getPlatform() ? 2 : 0)) }, App.prototype.fillOutlineText = function(g, text, x, y) { x || (x = 0), y || (y = 0), g.lineJoin = "round", "left" == g.textAlign ? (g.strokeText(" " + text + " ", x, y), g.fillText(" " + text + " ", x, y)) : "right" == g.textAlign ? (g.strokeText(" " + text + " ", x, y), g.fillText(" " + text + " ", x, y)) : (g.strokeText(" " + text + " ", x, y), g.fillText(text, x, y)) }, App.prototype.fillShadowedOutlineText = function(g, text, x, y, fillStyle) { x || (x = 0), y || (y = 0), g.fillStyle = App.SHADOW_STYLE, "left" == g.textAlign ? g.fillText(" " + text, x - Math.round(this.fontSize / 12), y + Math.round(this.fontSize / 12)) : "right" == g.textAlign ? g.fillText(text + " ", x - Math.round(this.fontSize / 12), y + Math.round(this.fontSize / 12)) : g.fillText(text, x - Math.round(this.fontSize / 12), y + Math.round(this.fontSize / 12)), g.fillStyle = fillStyle ? fillStyle : App.FILL_STYLE, this.fillOutlineText(g, text, x, y) }, App.prototype.onMouseDown = function(x, y) { this.currentScreen && !this.interstitialCheckTimer && this.currentScreen.onMouseDown(x, y) }, App.prototype.onMouseUp = function(x, y) { this.currentScreen && !this.interstitialCheckTimer && this.currentScreen.onMouseUp(x, y) }, App.prototype.onMouseMove = function(x, y) { this.currentScreen && !this.interstitialCheckTimer && this.currentScreen.onMouseMove(x, y) }, App.prototype.shake = function() { var self = this, amplitude = 10; Utils.ease(1, 0, function(f) { var x = Math.round(2 * f * (Math.random() - .5) * amplitude), y = Math.round(2 * f * (Math.random() - .5) * amplitude), s = 1 + .05 * f; self.shakeS = s, self.shakeX = x, self.shakeY = y }, { duration: 300, complete: function() { self.shakeS = !1, self.shakeX = 0, self.shakeY = 0 } }) }, App.prototype.createFxSprite = function(id, frameRate) { var sprite = new Sprite(this.assetManager.getAtlasImage("data.fx-opti." + DataStore.fxList[id].id), DataStore.fxList[id].col_count, DataStore.fxList[id].row_count, DataStore.fxList[id].loop); return sprite.frame_count = DataStore.fxList[id].frame_count, frameRate && sprite.setFrameRate(frameRate), sprite }, App.prototype.initAds = function() { var self = this; if (!getStoredBool("no-ads") && !PUBLISHER_NO_ADS) { var loadBannerAccel = null; this.loadInterstitialAccel = null, Cocoon.Ad.banner.on("ready", function() { self.bannerReady = !0, loadBannerAccel && (clearInterval(loadBannerAccel), loadBannerAccel = null), Cocoon.Ad.setBannerLayout(Cocoon.Ad.BannerLayout.BOTTOM_CENTER) }), Cocoon.Ad.interstitial.on("shown", function() { self.interstitialCheckTimer && (clearTimeout(self.interstitialCheckTimer), self.interstitialCheckTimer = !1) }), Cocoon.Ad.interstitial.on("ready", function() { self.interstitialReady = !0, self.loadInterstitialAccel && (clearInterval(self.loadInterstitialAccel), self.loadInterstitialAccel = null) }), Cocoon.Ad.banner.on("shown", function() { self.bannerReady = !1, Cocoon.Ad.loadBanner() }), Cocoon.Ad.interstitial.on("hidden", function() { self.onInterstitialEnd() }), loadBannerAccel = setInterval(function() { Cocoon.Ad.loadBanner() }, 5e3), Cocoon.Ad.loadBanner(), this.loadInterstitial() } }, App.prototype.loadInterstitial = function() { this.loadInterstitialAccel || (this.loadInterstitialAccel = setInterval(function() { Cocoon.Ad.loadInterstitial() }, 5e3), Cocoon.Ad.loadInterstitial()) }, App.prototype.onInterstitialEnd = function() { this.interstitialCloseListener && (this.interstitialCloseListener(), this.interstitialCloseListener = !1), self.interstitialCheckTimer && clearTimeout(self.interstitialCheckTimer), this.interstitialCheckTimer = !1, this.interstitialReady = !1, this.loadInterstitial() }, App.prototype.showInterstitial = function(closeListener) { var self = this; !PUBLISHER_NO_ADS && !getStoredBool("no-ads") && this.interstitialReady && this.timeData.global > this.nextInterstitialMinTime ? (this.interstitialCheckTimer = setTimeout(function() { self.nextInterstitialMinTime = 0, self.onInterstitialEnd() }, 2e3), this.interstitialCloseListener = closeListener, setTimeout(function() { Cocoon.Ad.showInterstitial() }, 100), this.nextInterstitialMinTime = this.timeData.global + 1e3 * Config.AD.MIN_DELAY) : !PUBLISHER_NO_ADS && closeListener && closeListener(), "spilgames" == PUBLISHER && SGUtils.showInterstitial(closeListener) }, App.prototype.showBanner = function() { this.bannerReady && !getStoredBool("no-ads") && Cocoon.Ad.showBanner() }, App.prototype.hideBanner = function() { Cocoon.Ad.hideBanner() }, App.prototype.autoMute = function() { function onchange(evt) { var v = !0, h = !1, evtMap = { focus: v, focusin: v, pageshow: v, blur: h, focusout: h, pagehide: h }; evt = evt || window.event, is_visible = !0, is_visible = evt.type in evtMap ? evtMap[evt.type] : this[hidden] ? !1 : !0, 0 == is_visible ? this && self.pauseMusic && self.pauseMusic() : self && self.playMusic && self.playMusic() } var self = this, hidden = "hidden"; hidden in document ? document.addEventListener("visibilitychange", onchange) : (hidden = "mozHidden") in document ? document.addEventListener("mozvisibilitychange", onchange) : (hidden = "webkitHidden") in document ? document.addEventListener("webkitvisibilitychange", onchange) : (hidden = "msHidden") in document ? document.addEventListener("msvisibilitychange", onchange) : "onfocusin" in document ? document.onfocusin = document.onfocusout = onchange : window.onpageshow = window.onpagehide = window.onfocus = window.onblur = onchange, void 0 !== document[hidden] && onchange({ type: document[hidden] ? "blur" : "focus" }) }, App.prototype.pauseMusic = function() { this.assetManager.muteSound(!0) }, App.prototype.playMusic = function() { this.assetManager.muteSound(!1) }; var AssetManager = function(parentManager) { this.parentManager = parentManager, this.soundEnabled = !0, this.parentManager && (this.parentManager.setChildManager(this), this.soundEnabled = this.parentManager.soundEnabled), this.images = {}, this.desaturatedImages = {}, this.sounds = {}, this.imagesError = {}, this.imagesToLoad = {}, this.soundsToLoad = {}, this.loadingListenerList = [], this.imageLoadingList = [], this.soundLoadingList = [], this.loadingEndTime = !1, this.childManager = !1, this.atlasImages = {} }; AssetManager.SOUND_FILE_FORMAT = Modernizr && Modernizr.audio && Modernizr.audio.ogg ? ".ogg" : ".mp3", AssetManager.prototype.getSoundFileFormat = function() { return Modernizr && Modernizr.audio && (Modernizr.audio.ogg || Modernizr.audio.mp3) ? AssetManager.SOUND_FILE_FORMAT : "None!" }, AssetManager.prototype.setChildManager = function(m) { this.childManager = m }, AssetManager.prototype.initAtlases = function() { for (var i = 0; ATLAS_COUNT > i; i++) this.loadAtlas(i) }, AssetManager.prototype.loadAtlas = function(id) { var data = window["atlas" + id]; for (var i in data.frames) this.atlasImages[i.replace(/[/]/g, ".")] = new AtlasImage(this.images["atlas" + id], data.frames[i]) }, AssetManager.prototype.dispose = function() { this.parentManager && this.parentManager.setChildManager(!1); for (var i in this.sounds) this.sounds[i].dispose(); for (var i in this.images) this.images[i].dispose && this.images[i].dispose() }, AssetManager.prototype.loadImage = function(url, id) { var self = this; id || (id = url); var img = this.images[id]; return img ? self.assetLoaded() : (this.imagesToLoad[id] = url, img = new Image, img.addEventListener("load", function() { delete self.imagesToLoad[id], img.complete ? self.assetLoaded() : setTimeout(function() { self.assetLoaded() }, 500) }), img.addEventListener("error", function() { !img.complete && self.imagesToLoad[id] && (delete self.imagesToLoad[id], self.imagesError[id] = id, self.assetLoaded()) }), img.src = url, this.images[id] = img), img }, AssetManager.prototype.loadSound = function(url, id) { return id || (id = url), this.sounds[id] || (this.soundsToLoad[id] = url, this.sounds[id] = new Sound(url), this.soundEnabled || this.sounds[id].setMuted(!0), this.assetLoaded()), this.sounds[id] }, AssetManager.soundEnablingLoaded = !1, AssetManager.prototype.assetLoaded = function() { var allDone = !1; if (this.totalAssetLoaded++, !this.loadingEndTime && (this.loadingTime = Date.now() - this.loadingStartTime, this.isDoneLoading())) { allDone = !0, this.loadingEndTime = Date.now(), AssetManager.soundEnablingLoaded || getStoredBool("soundEnabled", !0) || (AssetManager.soundEnablingLoaded = !0, this.toggleSound()); for (var i in this.loadingListenerList) this.loadingListenerList[i]() } return allDone }, AssetManager.prototype.resetLoading = function() { this.loadingListenerList = [], this.imageLoadingList = [], this.loadingEndTime = !1, this.totalAssetLoaded = 0, this.totalAssetCount = 0, this.loadingStartTime = 0 }, AssetManager.prototype.addLoadingListener = function(listener) { this.loadingListenerList.push(listener), this.isDoneLoading() && listener() }, AssetManager.prototype.isDoneLoading = function() { return this.loadingStartTime > 0 && this.totalAssetCount == this.totalAssetLoaded }, AssetManager.prototype.addImage = function(id, path) { "undefined" == typeof this.imageLoadingList[id] && (this.imageLoadingList[id] = path + (EMBED ? "" : "?r=" + Math.random())) }, AssetManager.prototype.addSound = function(id, path) { "undefined" == typeof this.soundLoadingList[id] && (this.soundLoadingList[id] = path + (EMBED ? "" : "?r=" + Math.random())) }, AssetManager.prototype.startLoading = function(imageLoadingList, soundLoadingList) { var self = this; if (this.loadingStartTime = Date.now(), this.loadingEndTime = !1, this.totalAssetLoaded = 0, this.totalAssetCount = 0, imageLoadingList) for (var i in imageLoadingList) this.addImage(i, imageLoadingList[i]); if (soundLoadingList) for (var i in soundLoadingList) this.addSound(i, soundLoadingList[i]); for (var i in this.imageLoadingList) this.totalAssetCount++; for (var i in this.soundLoadingList) this.totalAssetCount++; for (var i in this.soundLoadingList) this.loadSound(this.soundLoadingList[i], i); for (var i in this.imageLoadingList) this.loadImage(this.imageLoadingList[i], i); var checkTimeout = 30, inter = setInterval(function() { if (self.isDoneLoading()) clearInterval(inter); else { console.log("Loading check"); for (var j in self.imagesToLoad) self.images[j].complete && (delete self.imagesToLoad[j], self.assetLoaded() && clearInterval(inter)) } }, 1e3); setTimeout(function() { if (clearInterval(inter), !self.isDoneLoading()) { console.log("Loading flush"); for (var j in self.imagesToLoad) delete self.imagesToLoad[j], self.assetLoaded() } }, 1e3 * checkTimeout) }, AssetManager.prototype.getLoadingProgress = function() { return 0 == this.totalAssetCount ? 0 : this.totalAssetLoaded / this.totalAssetCount }, AssetManager.prototype.getImage = function(id) { return this.images[id] }, AssetManager.prototype.getAtlasImage = function(id) { return this.atlasImages[id] }, AssetManager.prototype.getDesaturatedImage = function(id) { if (!this.desaturatedImages[id] && this.images[id]) { var img = this.images[id]; if (img.width > 0) { var canvas = Utils.createCanvas(); canvas.width = img.width, canvas.height = img.height; var g = canvas.getContext("2d"); g.drawImage(img, 0, 0); for (var imageData = g.getImageData(0, 0, canvas.width, canvas.height), imageDataContent = imageData.data, i = 0; i < imageDataContent.length; i += 4) { var brightness = .34 * imageDataContent[i] + .5 * imageDataContent[i + 1] + .16 * imageDataContent[i + 2]; imageDataContent[i] = brightness, imageDataContent[i + 1] = brightness, imageDataContent[i + 2] = brightness } g.putImageData(imageData, 0, 0), canvas.complete = !0, this.desaturatedImages[id] = canvas } else this.desaturatedImages[id] = img } return this.desaturatedImages[id] }, AssetManager.prototype.getSound = function(id) { return this.sounds[id] }, AssetManager.prototype.setSoundEnabled = function(b) { this.soundEnabled = b, setStoredBool("soundEnabled", this.soundEnabled); for (var i in this.sounds) this.sounds[i].setMuted(!this.soundEnabled); this.childManager && this.childManager.setSoundEnabled(this.soundEnabled) }, AssetManager.prototype.toggleSound = function() { this.setSoundEnabled(!this.soundEnabled) }, AssetManager.prototype.muteSound = function(b) { if (this.soundEnabled) { for (var i in this.sounds) this.sounds[i].setMuted(b); this.childManager && this.childManager.muteSound(b) } }; var AtlasImage = function(atlas, config) { this.atlas = atlas, this.complete = !0, this.x = config.frame.x - config.spriteSourceSize.x, this.y = config.frame.y - config.spriteSourceSize.y, this.width = config.frame.w, this.height = config.frame.h }; AtlasImage.prototype.render = function(g, sx, sy, sw, sh, dx, dy, dw, dh) { sw || (dx = sx, dy = sy, sw = this.width, sh = this.height, dw = sw, dh = sh, sx = 0, sy = 0), g.drawImage(this.atlas, this.x + sx, this.y + sy, sw, sh, dx, dy, dw, dh) }; var Sprite = function(image, colCount, rowCount, loop) { return image.complete && 0 != image.width ? (this.fromAtlas = image instanceof AtlasImage, this.loop = loop, this.rowCount = rowCount, this.colCount = colCount, this.frameCount = this.rowCount * this.colCount, this.currentFrame = 0, this.lastFrameUpdate = 0, this.setFrameRate(12), this.invert = !1, this.invertAnim = !1, this.scale = 1, this.lastUpdateTime = 0, this.img = image, this.imgWidth = this.img.width, this.imgHeight = this.img.height, this.centerX = 0, this.centerY = 0, this.x = 0, this.y = 0, this.animDelay = 0, this.onAnimationComplete = !1, this.width = Math.round(this.imgWidth / this.colCount), this.height = Math.round(this.imgHeight / this.rowCount), this.img.blackFrames && (this.blackFrames = this.img.blackFrames), this.flip = !1, void 0) : (console.log("[ERROR] Image " + image.src + " should be loaded before being used in sprite"), void 0) }; Sprite.prototype.setPosition = function(x, y) { this.x = x, this.y = y }, Sprite.prototype.renderBlack = function(g, renderWidth, renderHeight, speedFactor, useGlobalTime) { this.render(g, renderWidth, renderHeight, speedFactor, useGlobalTime, !0) }, Sprite.prototype.render = function(g, renderWidth, renderHeight, speedFactor, useGlobalTime, black) { g.save(); var time = useGlobalTime ? g.timeData.global : g.timeData.local + this.animDelay; useGlobalTime ? g.timeData.globalDelta : g.timeData.localDelta, ("undefined" == typeof speedFactor || speedFactor === !1) && (speedFactor = 1); var scaleX = 1, scaleY = 1; if (renderWidth && (scaleX = renderWidth / this.width), renderHeight && (scaleY = renderHeight / this.height), !this.lastFrameUpdate || this.lastFrameUpdate > time) this.lastFrameUpdate = time; else { var timePassed = time - this.lastFrameUpdate, framePassed = Math.floor(timePassed * speedFactor / this.frameDuration); this.stopAnim || 0 == framePassed || (this.lastFrameUpdate = time, this.currentFrame += framePassed), this.currentFrame < 0 && console.log("[ERROR:Sprite] Current frame at " + this.currentFrame + " (timePassed:" + timePassed + ", framePassed:" + framePassed + ")") } if (this.currentFrame >= this.frameCount) if (this.loop) this.currentFrame = this.currentFrame % this.frameCount; else if (this.currentFrame = this.frameCount - 1, this.animComplete = !0, this.onAnimationComplete) { var handler = this.onAnimationComplete; this.onAnimationComplete = !1, handler(this) } var frame = this.currentFrame; this.invertAnim && (frame = this.frameCount - this.currentFrame - 1); var col = frame % this.colCount, row = Math.floor(frame / this.colCount); (1 != scaleX || 1 != scaleY) && g.scale(scaleX, scaleY), black ? (this.blackFrames || this.createBlackFrames(), g.drawImage(this.blackFrames, col * this.width, row * this.height, this.width, this.height, 0, 0, this.width, this.height)) : this.fromAtlas ? this.img.render(g, col * this.width, row * this.height, this.width, this.height, 0, 0, this.width, this.height) : g.drawImage(this.img, col * this.width, row * this.height, this.width, this.height, 0, 0, this.width, this.height), g.restore() }, Sprite.prototype.setCenter = function(x, y) { this.centerX = x, this.centerY = y }, Sprite.prototype.show = function() { this.loop && (this.currentFrame = 0, this.play()) }, Sprite.prototype.hide = function() { this.stop() }, Sprite.prototype.play = function(timeData) { this.stopAnim = !1, this.lastFrameUpdate = timeData.local }, Sprite.prototype.resetAnim = function() { this.stop(), this.currentFrame = 0, this.animComplete = !1 }, Sprite.prototype.isPlaying = function() { return !this.stopAnim && (this.loop || this.currentFrame < this.frameCount - 1) }, Sprite.prototype.stop = function() { this.stopAnim = !0 }, Sprite.prototype.setFrameRate = function(frameRate) { this.frameRate = frameRate, this.frameDuration = Math.round(1e3 / this.frameRate) }, Sprite.prototype.setScale = function(scale) { this.scale != scale && (this.scale = scale) }, Sprite.prototype.createBlackFrames = function() { if (!this.img.blackFrames) { var c = Utils.createCanvas(); c.width = this.img.width, c.height = this.img.height; var g = c.getContext("2d"); this.fromAtlas ? this.img.render(g, 0, 0) : g.drawImage(this.img, 0, 0), g.globalCompositeOperation = "source-atop", g.fillStyle = "black", g.fillRect(0, 0, c.width, c.height), this.img.blackFrames = c } this.blackFrames = this.img.blackFrames }; var Screen = function(app, id) { "undefined" != typeof app && (this.visible = !1, this.needRefresh = !1, this.app = app, this.id = id, this.canvas = this.app.canvas, this.graphics = this.app.graphics, this.assetManager = this.app.assetManager, this.timeData = this.app.timeData) }; Screen.prototype.show = function() { this.app.hideBanner(), Input.setCurrentScreen(this.id), this.app.currentScreen && (this.app.lastScreen = this.app.currentScreen, this.app.currentScreen.hide()), this.visible = !0, this.needRefresh = !0, this.app.currentScreen = this, this.onResize(), Analytics.log("display-screen", this.id, !0) }, Screen.prototype.hide = function() { this.visible = !1, Analytics.endLog("display-screen", this.id) }, Screen.prototype.update = function() {}, Screen.prototype.render = function() {}, Screen.prototype.onResize = function() { this.needRefresh = !0 }, Screen.prototype.onMouseMove = function() {}, Screen.prototype.onMouseUp = function() {}, Screen.prototype.onMouseDown = function() {}; var Achievement = { CONTAINER_SIZE: 483, ENTRY_SIZE: 108, SCROLL_SPEED: 36, SCROLLBAR_SIZE: 457, SCROLLER_SIZE: 53, INDIC_DURATION: 3e3, INDIC_FADE_DURATION: 1e3, init: function() { this.indicList = [], this.achievementByType = {}; for (var i in DataStore.achievementType) this.achievementByType[DataStore.achievementType[i]] = []; for (var i in DataStore.achievementList) { var a = DataStore.achievementList[i]; this.isAchievementDone(a.id) || this.achievementByType[a.achievement_type].push(a) } this.scrollMax = this.achievementCount * this.ENTRY_SIZE - this.CONTAINER_SIZE, this.scrollTop = 0, this.progressBackground = app.assetManager.getAtlasImage("gui.achievement.progress-background"), this.progressIndicator = app.assetManager.getAtlasImage("gui.achievement.progress-indicator"), this.entryBackground = app.assetManager.getAtlasImage("gui.achievement.entry-background"), this.doneEntryBackground = app.assetManager.getAtlasImage("gui.achievement.done-entry-background"), this.guess = app.assetManager.getAtlasImage("gui.achievement.guess"), this.money = app.assetManager.getAtlasImage("gui.common.money"), this.tick = app.assetManager.getAtlasImage("gui.common.tick"), this.needRefresh = !0, this.achievementList = []; var index = 0; for (var i in DataStore.achievementList) DataStore.achievementList[i].index = index, this.achievementList[index] = Utils.createCanvas(), this.achievementList[index].width = this.entryBackground.width, this.achievementList[index].height = this.entryBackground.height, this.achievementList[index].g = this.achievementList[index].getContext("2d"), index++; Cocoon.Social.GameCenter && Cocoon.Social.GameCenter.nativeAvailable && Cocoon.Social.GameCenter.login() }, getCount: function() { return this.achievementCount }, getDoneCount: function() { return this.doneCount }, refresh: function() { if (this.needRefresh) { this.doneCount = 0, this.achievementCount = 0; for (var i in DataStore.achievementList) this.refreshAchievement(i), this.achievementCount++, this.isAchievementDone(i) && this.doneCount++; this.needRefresh = !1 } }, refreshAchievement: function(id) { var p = DataStore.achievementList[id], currentValue = Math.min(getStoredInt("achievement-value-" + p.achievement_type), p.value), g = this.achievementList[p.index].g; g.clearRect(0, 0, this.progressBackground.width, this.progressBackground.height), this.isAchievementDone(p.id) ? this.doneEntryBackground.render(g, 0, 0) : this.entryBackground.render(g, 0, 0), app.setBaseFont(g, 28), g.textAlign = "left"; var label = Utils.splitText(getDBText("achievement", "name", p.id)); app.fillOutlineText(g, label[0], 10, 36), label.length > 1 && app.fillOutlineText(g, label[1], 10, 63), app.setBaseFont(g, 20), g.fillStyle = "black"; var description = "???"; if ((this.isAchievementDone(p.id) || !p.no_progress) && (description = getDBText("achievement_type", "description", p.achievement_type).replace("%1", p.value)), label.length > 1 ? g.fillText(description, 10, 90) : g.fillText(description, 10, 65), this.isAchievementDone(p.id)) this.tick.render(g, 365, 15); else if (p.no_progress) this.guess.render(g, 385, 15); else { var progress = currentValue / p.value, text = currentValue + "/" + p.value; app.setBaseFont(g, text.length > 6 ? 22 : 35), g.textAlign = "center", app.fillOutlineText(g, text, 414, text.length > 6 ? 38 : 42), this.progressBackground.render(g, 333, 50), progress > 0 && this.progressIndicator.render(g, 0, 0, Math.round(this.progressIndicator.width * progress), this.progressIndicator.height, 333, 50, Math.round(this.progressIndicator.width * progress), this.progressIndicator.height) } this.money.render(g, 520, 12), g.textAlign = "left", app.setThirdFont(g, 35), app.fillOutlineText(g, "x", 580, 80), app.setThirdFont(g, 60), app.fillOutlineText(g, p.reward, 600, 80) }, clearAchievementList: function() { for (var i in DataStore.achievementType) clearStoredData("achievement-value-" + DataStore.achievementType[i]); for (var i in DataStore.achievementList) clearStoredData("achievement-" + DataStore.achievementList[i].id) }, record: function(type, value) { if (!testLevel) { if ("undefined" == typeof value && (value = getStoredInt("achievement-value-" + type) + 1, setStoredInt("achievement-value-" + type, value)), this.achievementByType[type]) { var operator = DataStore.achievementTypeList[type].operator, list = this.achievementByType[type]; setStoredInt("achievement-value-" + type, value); for (var i = 0; i < list.length; i++) { var a = list[i]; (!operator || value >= a.value && operator == Operator.SUP || value <= a.value && operator == Operator.INF) && this.achievementDone(type, a.id) } } this.needRefresh = !0 } }, achievementDone: function(type, id) { var now = Math.floor(Date.now() / 1e3); if (Cocoon.Social.GameCenter && Cocoon.Social.GameCenter.nativeAvailable) { var a = new Cocoon.Social.GameCenter.Achievement; a.identifier = "com.3dduo.std.a" + id, a.percentComplete = 100, a.lastReportedDate = now, Cocoon.Social.GameCenter.submitAchievements([a]) } if ("spilgames" == PUBLISHER) { var award = { award: "award" + id }; GameAPI.Award.submit(award) } app.assetManager.getSound("game.achievement").reset().play(), setStoredBool("achievement-" + id, !0), setStoredInt("achievement-date-" + id, now); for (var list = [], i = 0; i < this.achievementByType[type].length; i++) this.achievementByType[type][i].id != id && list.push(this.achievementByType[type][i]); this.achievementByType[type] = list.length > 0 ? list : !1, Money.add(DataStore.achievementList[id].reward), this.addNewIndic(id); var doneCount = 0; for (var i in DataStore.achievementList) this.isAchievementDone(i) && doneCount++; Achievement.record(DataStore.achievementType.ACHIEVEMENT_COUNT, doneCount) }, addNewIndic: function(id) { this.indicList.push(id), 1 == this.indicList.length && this.showNextIndic() }, hasIndic: function() { return this.currentIndic ? !0 : !1 }, renderIndic: function(g) { if (this.currentIndic) { if (g.save(), g.resetTransform(), g.timeData.global > this.currentIndicShowTime + this.INDIC_DURATION) { var f = Math.min(1, Math.max(0, Math.easeOutSine((g.timeData.global - this.currentIndicShowTime - this.INDIC_DURATION) / this.INDIC_FADE_DURATION))); g.globalAlpha = 1 - f } g.translate(Math.round(g.width / 2), 0), g.scale(app.scale, app.scale), g.drawImage(this.currentIndic, -Math.round(this.currentIndic.width / 2), 10), g.restore() } }, showNextIndic: function() { var self = this, a = DataStore.achievementList[this.indicList[0]]; this.refreshAchievement(a.id), this.currentIndic = this.achievementList[a.index], this.currentIndicShowTime = app.timeData.global, setTimeout(function() { self.indicList.shift(), self.indicList.length > 0 ? self.showNextIndic() : self.currentIndic = !1 }, this.INDIC_DURATION + this.INDIC_FADE_DURATION) }, isAchievementDone: function(id) { return getStoredBool("achievement-" + id) } }, AchievementScreen = function(app) { Screen.call(this, app, "achievement"), this.needRefresh = !0, this.scrollTop = 0, this.scrollPercent = 0, this.background = this.assetManager.getImage("gui.level-select.background"), this.popupBackground = this.assetManager.getAtlasImage("gui.achievement.background"), this.scroller = this.assetManager.getAtlasImage("gui.achievement.scroller"), this.backButton = this.assetManager.getAtlasImage("gui.common.back"), this.gameCenterButton = this.assetManager.getAtlasImage("gui.achievement.game-center") }; AchievementScreen.ENTRY_HEIGHT = 108, AchievementScreen.CONTAINER_SIZE = 450, AchievementScreen.SCROLLBAR_SIZE = 408, AchievementScreen.SCROLLER_SIZE = 20, AchievementScreen.prototype = new Screen, AchievementScreen.prototype.onResize = function() { var self = this; Screen.prototype.onResize.call(this), Input.addCollider("panel", app.width / 2 - 450 * app.scale, 110 * app.scale, 740 * app.scale, 550 * app.scale, { mousedown: function() { self.startMovePanel() }, mouseup: function() { self.stopMove() } }), Input.addCollider("scroller", app.width / 2 + 295 * app.scale, 110 * app.scale, 120 * app.scale, 550 * app.scale, { mousedown: function() { self.startMoveScroller() }, mouseup: function() { self.stopMove() } }), this.scrollMax = Achievement.getCount() * AchievementScreen.ENTRY_HEIGHT - AchievementScreen.CONTAINER_SIZE }, AchievementScreen.prototype.show = function() { if (Achievement.refresh(), Cocoon.Social.GameCenter && Cocoon.Social.GameCenter.nativeAvailable) { var list = []; for (var i in DataStore.achievementList) if (Achievement.isAchievementDone(i)) { var a = new Cocoon.Social.GameCenter.Achievement; a.identifier = "com.3dduo.std.a" + i, a.percentComplete = 100, a.lastReportedDate = getStoredInt("achivement-date-" + i), list.push(a) } list.length > 0 && Cocoon.Social.GameCenter.submitAchievements(list) } Screen.prototype.show.call(this) }, AchievementScreen.prototype.render = function(g) { var self = this; if (this.needRefresh) { g.save(), g.translate(Math.round(g.width / 2), 0), g.scale(app.scale, app.scale), g.drawImage(this.background, 0, 0, this.background.width, this.background.height, -Math.round(App.BASE_MAX_WIDTH / 2), 0, App.BASE_MAX_WIDTH, App.BASE_HEIGHT), g.translate(40, 0), this.popupBackground.render(g, -Math.round(this.popupBackground.width / 2), 30), app.setSecondaryFont(g, 80), g.textAlign = "right", app.fillShadowedOutlineText(g, _2("achievement-popup-title"), 360, 115), app.setBaseFont(g, 45), g.textAlign = "center", app.fillOutlineText(g, Achievement.getDoneCount() + "/" + Achievement.getCount(), -240, 105), this.scroller.render(g, 310, 165 + AchievementScreen.SCROLLBAR_SIZE * this.scrollPercent), g.translate(-400, 170), g.beginPath(), g.rect(0, -23, Achievement.entryBackground.width, 486), g.clip(); for (var i = 0; i < Achievement.achievementList.length; i++) { var y = i * AchievementScreen.ENTRY_HEIGHT - this.scrollTop; y + 1.2 * AchievementScreen.ENTRY_HEIGHT > 0 && y < 1.1 * AchievementScreen.CONTAINER_SIZE && g.drawImage(Achievement.achievementList[i], 0, y) } g.restore() } ButtonUtils.render({ g: g, img: this.backButton, id: "back", x: 90 * app.scale, y: g.height - Math.round(10 * app.scale), align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { app.lastScreen.show() }, changeListener: function() { self.needRefresh = !0 }, needRefresh: this.needRefresh }), Cocoon.Social.GameCenter && Cocoon.Social.GameCenter.nativeAvailable && ButtonUtils.render({ g: g, img: this.gameCenterButton, id: "game-center", x: g.width - 90 * app.scale, y: g.height - Math.round(20 * app.scale), align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, scale: 1.2, listener: function() { Cocoon.Social.GameCenter && Cocoon.Social.GameCenter.nativeAvailable ? Cocoon.Social.GameCenter.showAchievements() : console.log("Should display Game Center") }, changeListener: function() { self.needRefresh = !0 }, needRefresh: this.needRefresh }), this.needRefresh = !1 }, AchievementScreen.prototype.wheelScroll = function(amount) { this.scrollTop = Math.max(0, Math.min(this.scrollMax, this.scrollTop + Math.round(amount * this.SCROLL_SPEED))), this.scrollPercent = this.scrollTop / this.scrollMax, this.refreshScroll() }, AchievementScreen.prototype.scrollerMove = function(y) { this.scrollPercent = Math.max(0, Math.min(1, this.scrollPercentStart + y / AchievementScreen.SCROLLBAR_SIZE)), this.scrollTop = Math.round(this.scrollPercent * this.scrollMax), this.needRefresh = !0 }, AchievementScreen.prototype.panelMove = function(y) { this.scrollTop = Math.max(0, Math.min(this.scrollMax, this.scrollTopStart - y)), this.scrollPercent = this.scrollTop / this.scrollMax, this.needRefresh = !0 }, AchievementScreen.prototype.startMovePanel = function() { this.scrolling = !0, this.scrollingPanel = !0, this.scrollTopStart = this.scrollTop, this.scrollStartY = Input.y }, AchievementScreen.prototype.startMoveScroller = function() { this.scrolling = !0, this.scrollingPanel = !1, this.scrollPercentStart = this.scrollPercent, this.scrollStartY = Input.y }, AchievementScreen.prototype.stopMove = function() { this.scrolling = !1 }, AchievementScreen.prototype.onMouseMove = function(x, y) { Input.pressed && this.scrolling && (this.scrollingPanel ? this.panelMove((y - this.scrollStartY) / app.scale) : this.scrollerMove((y - this.scrollStartY) / app.scale)) }; var ButtonUtils = { ACTIVE_SCALE: 1.1, ALIGN_LEFT: 1, ALIGN_CENTER: 2, ALIGN_RIGHT: 3, VALIGN_TOP: 1, VALIGN_CENTER: 2, VALIGN_BOTTOM: 3, render: function(o) { if (Input.needRefresh(o.id) || o.needRefresh) { var g = o.g; o.width = o.img.width / 2, o.height = o.img.height, g.save(), g.resetTransform(), app.shakeS && (g.translate(Math.round(g.width / 2), Math.round(g.height / 2)), g.scale(app.shakeS, app.shakeS), g.translate(-Math.round(g.width / 2), -Math.round(g.height / 2)), g.translate(app.shakeX, app.shakeY)); var x = o.x; switch (o.align) { case this.ALIGN_LEFT: x += Math.round(o.img.width * app.scale / 4); break; case this.ALIGN_RIGHT: x -= Math.round(o.img.width * app.scale / 4) } var y = o.y; switch (o.valign) { case this.VALIGN_TOP: y += Math.round(o.img.height * app.scale / 2); break; case this.VALIGN_BOTTOM: y -= Math.round(o.img.height * app.scale / 2) } o.background && this.renderBackground(o, x, y), g.translate(x, y), g.scale(app.scale, app.scale); var listener = o.listener; "function" == typeof o.listener && (listener = function() { o.sound ? app.assetManager.getSound(o.sound).reset().play() : app.assetManager.getSound("tap").reset().play(), o.listener() }), Input.addCollider(o.id, x - Math.round(o.img.width * app.scale / 4), y - Math.round(o.img.height * app.scale / 2), Math.round(o.img.width / 2 * app.scale), Math.round(o.img.height * app.scale), listener, o.changeListener, o.visibilityHandler), o.scale && g.scale(o.scale, o.scale), Input.isActive(o.id) && g.scale(this.ACTIVE_SCALE, this.ACTIVE_SCALE), o.img.render(g, Input.isActive(o.id) ? o.img.width / 2 : 0, 0, o.img.width / 2, o.img.height, -o.img.width / 4, -Math.round(o.img.height / 2), o.img.width / 2, o.img.height), o.extraRender && o.extraRender(g), g.restore(), Input.setRefreshed(o.id) } }, renderBackground: function(o, x, y) { var g = o.g; o.bgActiveScale || (o.bgActiveScale = this.ACTIVE_SCALE), g.save(), g.resetTransform(); var sx = 1, sy = 1; o.backgroundWidth && o.backgroundWidth != o.background.width && (sx = o.background.width / o.backgroundWidth), o.backgroundHeight && o.backgroundHeight != o.background.height && (sy = o.background.height / o.backgroundHeight); var bgx = o.backgroundX, bgy = o.backgroundY, bx = x - o.width * o.bgActiveScale * app.scale / 2, by = y - o.height * o.bgActiveScale * app.scale / 2, bw = o.width * app.scale * o.bgActiveScale, bh = o.height * app.scale * o.bgActiveScale, bgw = bw * sx / app.scale, bgh = bh * sy / app.scale; bgx = (-bgx + bx) * sx / app.scale, bgy = (-bgy + by) * sy / app.scale, 0 > bgx && (bx -= Math.round(bgx * bw / bgw), bgx = 0), 0 > bgy && (by -= Math.round(bgy * bh / bgy), bgy = 0), bgx >= 0 && bgy >= 0 && bgx + bgw <= o.background.width && bgy + bgh <= o.background.height && g.drawImage(o.background, Math.round(bgx), Math.round(bgy), Math.round(bgw), Math.round(bgh), Math.round(bx), Math.round(by), Math.round(bw), Math.round(bh)), g.restore() } }, Carousel = function(assetManager, config) { this.assetManager = assetManager, this.canvas = app.canvas, this.graphics = app.graphics, this.paintHandler = config.paintHandler, this.itemPaintHandler = config.itemPaintHandler, this.selectionHandler = config.selectionHandler, this.dataList = config.dataList, this.callback = config.callback, this.elmSize = config.elmSize, this.enabled = !1, this.needRefresh = !0, this.currentIndex = 0, this.elmPos = 0; for (var i = 0; i < this.dataList.length; i++) { var elm = this.dataList[i]; elm.pos = !1, elm.posFound = !1, elm.minF = !1 } }; Carousel.MIN_DRAG_DISTANCE = 10, Carousel.OTHER_SCALE_REDUCTION = .6, Carousel.OTHER_DISTANCE = 2, Carousel.prototype = new Screen, Carousel.prototype.onMouseDown = function(x) { this.startMove = x, this.startPos = this.elmPos, this.mouseDownTime = Date.now(), this.mouseDown = !0, this.dragDistance = 0, this.lastPosX = x }, Carousel.prototype.getNearestIndex = function() { if (this.dragging) { for (var nearest = 0, min = !1, nearest = 0, i = 0; i < this.dataList.length; i++) { var x = Math.abs(this.dataList[i].x - this.graphics.width / 2); (min === !1 || min > x) && (nearest = i, min = x) } return nearest } return this.currentIndex }, Carousel.prototype.onMouseUp = function(x, y) { if (this.mouseDown = !1, this.dragDistance < 50) for (var i = 0; i < this.dataList.length; i++) { var w = this.dataList[i]; if (Math.abs(y / app.height - .5) < .25 * w.iconScale && x > w.minX && x < w.maxX && (w.minX || w.maxX)) return this.selectElm(i, !1, !0), this.dragging = !1, void 0 } if (this.dragging) { this.dragging = !1; for (var nearest = 0, fast = Date.now() - this.mouseDownTime < 300, toNext = Input.x - this.startMove < 0, min = !1, nearest = 0, i = 0; i < this.dataList.length; i++) { var x = Math.abs(this.dataList[i].x - this.graphics.width / 2); (min === !1 || min > x) && (nearest = i, min = x) } fast && (nearest == this.currentIndex ? (nearest = this.currentIndex, toNext && nearest < this.dataList.length - 1 ? nearest++ : !toNext && nearest > 0 && nearest--) : nearest = nearest > this.currentIndex ? Math.min(nearest + 1, this.dataList.length - 1) : Math.max(nearest - 1, 0)), this.selectElm(nearest, !0, !0) } }, Carousel.prototype.onMouseMove = function(x) { this.mouseDown && (this.dragDistance += Math.abs(x - this.lastPosX), this.dragging ? (this.elmPos = this.startPos + x - this.startMove, this.lastPosX = x, this.refreshElmList()) : this.dragging = !0) }, Carousel.prototype.onResize = function() { this.refreshElmList() }, Carousel.prototype.refreshElmList = function() { this.needRefresh = !0 }, Carousel.prototype.render = function(g) { if (this.needRefresh) { var elmPos = 10 * this.elmPos, x = this.elmPos; g.save(), g.translate(Math.round(g.width / 2), Math.round(g.height / 2)), g.scale(app.scale, app.scale); for (var i = 0; i < this.dataList.length; i++) { x = elmPos + this.elmSize * i; var f = x / (this.elmSize * Carousel.OTHER_DISTANCE), invert = 0 > f; f = Math.abs(f), f > 1 && (f = 1), f = Math.easeInOutQuad(f); var scale = 1 - Carousel.OTHER_SCALE_REDUCTION * f; this.dataList[i].iconScale = scale, x = Math.round(Math.pow(Math.abs(elmPos + this.elmSize * i), .75) * (invert ? -1 : 1)), x > .7 * -g.width && x < .7 * g.width ? (g.save(), g.translate(x, -30), g.scale(scale, scale), this.itemPaintHandler(g, i), g.restore(), this.dataList[i].x = Math.round(x * app.scale + g.width / 2), this.dataList[i].minX = this.dataList[i].x - Math.round(300 * scale / 2), this.dataList[i].maxX = this.dataList[i].x + Math.round(300 * scale / 2)) : (this.dataList[i].minX = 0, this.dataList[i].maxX = 0) } this.paintHandler && this.paintHandler(g), g.restore(), this.needRefresh = !1 } }, Carousel.prototype.refreshData = function() { this.onResize() }, Carousel.prototype.next = function() { this.currentIndex < this.dataList.length - 1 && this.selectElm(this.currentIndex + 1) }, Carousel.prototype.selectElm = function(index, refreshPos, playSound) { var self = this; if (this.lastIndex = this.currentIndex, this.lastSelectionTime = Date.now(), "undefined" == typeof this.dataList[index]) console.log("[ERROR] Undefined elm " + index); else if (this.currentIndex != index || refreshPos) { this.selectionHandler && this.selectionHandler(index), playSound && App.instance.assetManager.getSound("swipe").reset().play(), this.easeListener && this.easeListener.stop(), this.currentIndex = index; var newPos = -(this.elmSize * index) / 10; this.easeListener = Utils.ease(this.elmPos, newPos, function(v) { self.elmPos = Math.round(v), self.refreshElmList() }, { easing: "easeOutCubic", duration: refreshPos ? 250 : 500 }) } else this.dataList[index].isLocked || this.callback(index); this.refreshElmList() }, Carousel.prototype.setEnabled = function(b) { this.enabled = b, this.enabled && (this.refreshData(), this.selectionHandler && this.selectionHandler(this.currentIndex)) }; var DodoStock = function(stockManager, id) { this.stockManager = stockManager, this.id = id, this.recoverTime = DataStore.dodoTypeList[this.id].recover_time, this.refreshMaxStock(), this.levelAmount = this.getAmount() }; DodoStock.prototype.recover = function() { this.getAmount() < this.getMaxAmount() && Money.spend(this.getCost()) && this.add(this.getMaxAmount() - this.getAmount()) }, DodoStock.prototype.resetLevelAmount = function() { this.levelAmount = this.getAmount() }, DodoStock.prototype.levelConsume = function() { 0 == this.levelAmount ? console.log("Level amount error for stock " + this.id) : this.levelAmount-- }, DodoStock.prototype.getLevelAmount = function() { return this.levelAmount }, DodoStock.prototype.getAmount = function() { return Math.min(this.maxStock, getStoredInt("stock-" + this.id, this.maxStock)) }, DodoStock.prototype.getCost = function() { return (this.getMaxAmount() - this.getAmount()) * DataStore.dodoTypeList[this.id].cost }, DodoStock.prototype.addMaxStock = function(amount, listener) { this.refreshMaxStock(), this.getAmount() < this.getMaxAmount() ? (StockManager.stockUpdateListener = listener, this.add(amount)) : listener(), Achievement.record(DataStore.achievementType.COLONY_SIZE, this.stockManager.getMaxAmount()), Achievement.record(DataStore.achievementType.SPECIAL_DODO_COUNT, this.stockManager.getMaxAmount() - this.stockManager.stockList[Config.GENERAL.DEFAULT_DODO_TYPE].getMaxAmount()) }, DodoStock.prototype.refreshMaxStock = function() { this.maxStock = DataStore.dodoTypeList[this.id].start_stock; for (var i in DataStore.worldList) { var world = DataStore.worldList[i]; for (var j in world.levelList) { var level = world.levelList[j]; level.unlockedDodoType == this.id && App.instance.gameScreen.isLevelDone(level.id, !0) && level.goalType == GoalType.CAGE && (this.maxStock += level.unlockedDodoCount) } } }, DodoStock.prototype.getMaxAmount = function() { return this.maxStock }, DodoStock.prototype.getNextLifeTime = function() { return getStoredInt("next-life-time-" + this.id) }, DodoStock.prototype.renderEmpty = function(g) { if (!app.gameScreen.stockTuto) { var icon = app.assetManager.getAtlasImage("data.dodos." + this.id + "-disabled-icon"), guess = app.assetManager.getAtlasImage("gui.achievement.guess"); g.save(), g.scale(.85, .85), icon.render(g, 0, 0), guess.render(g, 190, 8), g.restore() } }, DodoStock.prototype.render = function(g, index) { var self = this, icon = app.assetManager.getAtlasImage("data.dodos." + this.id + "-icon"); g.save(), g.save(), g.scale(.85, .85), icon.render(g, 0, 0), g.restore(), this.getAmount(); var now = Math.floor(g.timeData.global / 1e3), nextLifeTime = this.getNextLifeTime(); if (g.translate(180, 40), this.stockManager.isInfinite()) app.setBaseFont(g, 30), app.fillOutlineText(g, _2("infinite"), 0, 0), g.translate(165, 0), this.stockManager.infinite.render(g, -Math.round(this.stockManager.infinite.width / 2), -Math.round(this.stockManager.infinite.height / 2)); else { if (nextLifeTime) { var remainingTime = nextLifeTime - now; app.setBaseFont(g, 22), app.fillOutlineText(g, _2("next-in"), 0, -20), app.setBaseFont(g, 45), app.fillOutlineText(g, Utils.formatTimeHour(remainingTime), 0, 12) } else app.setBaseFont(g, 30), app.fillOutlineText(g, _2("life-full"), 0, 0); g.translate(160, 0), app.setBaseFont(g, 30), g.textAlign = "left", app.fillOutlineText(g, "/ " + this.getMaxAmount(), 0, 10), app.setBaseFont(g, 50), g.textAlign = "right", nextLifeTime && (g.fillStyle = App.RED_STYLE), app.fillOutlineText(g, this.getAmount(), 12, 3), nextLifeTime && (Config.GENERAL.MONETIZATION || self.getCost() <= Money.getAmount()) && ButtonUtils.render({ g: g, img: app.assetManager.getAtlasImage("gui.stock.restore-button"), id: "restore-dodo-" + this.id, x: Math.round(g.width / 2) + 55 * app.scale, y: (180 + StockManager.ENTRY_HEIGHT * index) * app.scale, align: ButtonUtils.ALIGN_LEFT, valign: ButtonUtils.VALIGN_CENTER, listener: function() { self.recover(), app.gameScreen.stockTuto && !StockManager.isTutoDone() && StockManager.setTutoDone() }, sound: "stock.recover", needRefresh: !0, scale: StockManager.isTutoDone() || !app.gameScreen.stockTuto ? 1 : .05 * Math.cycleSin(g.timeData.global, 1e3) + 1, changeListener: function() { self.stockManager.needRefresh = !0 }, extraRender: function(g) { app.setBaseFont(g, 25), g.textAlign = "center"; var text = Utils.splitText(_2("stock-recover")); app.fillOutlineText(g, text[0].toUpperCase(), -65, -13), app.fillOutlineText(g, text[1].toUpperCase(), -65, 13), app.setBaseFont(g, 45), g.textAlign = "right", app.fillOutlineText(g, self.getCost(), 85, 0), g.save(), g.scale(.6, .6), self.stockManager.money.render(g, 160, -40), g.restore() }, visibilityHandler: function() { return self.stockManager.visible } }) }(!nextLifeTime || this.stockManager.isInfinite()) && (g.save(), g.scale(.8, .8), this.stockManager.tick.render(g, 230, -Math.round(this.stockManager.tick.height / 2)), g.restore()), g.restore() }, DodoStock.prototype.update = function(timeData) { var amount = this.getAmount(), now = Math.floor(timeData.global / 1e3), lastLifeTime = this.getNextLifeTime(), nextLifeTime = 0; if (amount < this.maxStock) if (nextLifeTime = lastLifeTime) { if (now >= nextLifeTime) { var elapsedTime = now - nextLifeTime, lifeGained = Math.floor(elapsedTime / this.recoverTime + 1); amount = Math.min(this.maxStock, amount + lifeGained), setStoredInt("stock-" + this.id, amount), app.startScreen && app.startScreen.refreshStock(), nextLifeTime = amount < this.maxStock ? now + this.recoverTime - elapsedTime % this.recoverTime : 0 } } else nextLifeTime = now + this.recoverTime; lastLifeTime != nextLifeTime && setStoredInt("next-life-time-" + this.id, nextLifeTime) }, DodoStock.prototype.lost = function() { if (!this.stockManager.isInfinite()) { var newValue = this.getAmount() - 1; return 0 > newValue ? (console.log("Not more life !"), !1) : (this.stockManager.lastUpdateTime = 0, setStoredInt("stock-" + this.id, newValue), app.startScreen.refreshStock(), !0) } }, DodoStock.prototype.add = function(value) { if ("undefined" == typeof value && (value = 1), this.getAmount() >= this.maxStock) console.log("Already at maximum"); else { var newValue = this.getAmount() + value; newValue > this.maxStock && (console.log("Cannot get more than " + this.maxStock + "."), newValue = this.maxStock), setStoredInt("stock-" + this.id, newValue), app.startScreen.refreshStock(), this.stockManager.lastUpdateTime = 0 } }, DodoStock.prototype.checkAvailable = function() { return this.getAmount() > 0 ? !0 : (alert("Vous n'avez plus de vie !"), !1) }; var GameScreen = function(app) { Screen.call(this, app, "game"), this.app = app, this.friendLevelData = {}, this.paused = !1, this.unlockableDodoCount = 0; for (var id in DataStore.dodoTypeList) { var t = DataStore.dodoTypeList[id]; t.unlockable && this.unlockableDodoCount++ } this.endScreenCache = {} }; GameScreen.prototype = new Screen, GameScreen.EPSILON = 1e-5, GameScreen.speedFactor = 1, GameScreen.BAR_CONTENT_RATIO = .164, GameScreen.prototype.cageEndNext = function() { this.world.cageEndNext() }, GameScreen.prototype.enableSpeed = function() { this.paused || (this.speedStartTime = this.timeData.global, GameScreen.speedFactor = 3, this.world.music.setPlaybackRate(1.5)) }, GameScreen.prototype.disableSpeed = function() { this.paused || (this.speedStartTime = !1, GameScreen.speedFactor && (GameScreen.speedFactor = 1), this.world.music.setPlaybackRate(1)) }, GameScreen.prototype.setBonusEnabled = function(type) { var id; for (var i in DataStore.bonusList) DataStore.bonusList[i].identifier == type && (id = i) }, GameScreen.prototype.displayFriendList = function() {}, GameScreen.prototype.activateBonus = function(id) { var count = getStoredInt("bonus-" + id, 0), bonus = DataStore.bonusList[id]; if (count > 0 || testLevel || bonus.cost <= Money.getAmount() || bonus.tuto_level == this.currentLevel.id) switch (bonus.isFree || testLevel || (count > 0 ? (count--, setStoredInt("bonus-" + id, count)) : Money.spend(bonus.cost)), this.refreshBonusCount(id, !0), bonus.identifier) { case "portal": this.world.activatePortal(); break; case "freeze": this.world.setEnnemyFreeze(bonus.duration); break; case "immune": this.world.setImmunity(bonus.duration); break; case "dodo": this.showDodoWheel() } else alert("Tu n'as pas assez d'oeufs !") }, GameScreen.prototype.refreshBonusCount = function() {}, GameScreen.prototype.onMouseDown = function(x, y) { x -= this.screenDecal, this.world && !this.paused && GameScreen.speedFactor > 0 && this.world.onMouseDown(x, y), this.gameOverTime && (this.skipEndScreen += 1e4) }, GameScreen.prototype.onMouseUp = function(x, y) { x -= this.screenDecal, this.world && !this.paused && GameScreen.speedFactor > 0 && this.world.onMouseUp(x, y) }, GameScreen.prototype.onMouseMove = function(x, y) { x -= this.screenDecal, this.world && !this.paused && GameScreen.speedFactor > 0 && this.world.onMouseMove(x, y) }, GameScreen.prototype.onResize = function() { Screen.prototype.onResize.call(this), this.screenRatio = this.app.screenRatio, this.screenDecal = Math.round((this.canvas.width - this.canvas.height) / 2), this.backgroundImage && (this.backgroundScale = this.canvas.height / this.backgroundImage.height), this.world && this.world.onResize(this.graphics.height, this.graphics.height), this.tutoEntity && (this.tutoEntity.world.onResize(this.graphics.height, this.graphics.height), this.tutoEntity.onResize()), this.tutoEnnemy && (this.tutoEnnemy.world.onResize(this.graphics.height, this.graphics.height), this.tutoEnnemy.onResize()), this.tutoItem && (this.tutoItem.world.onResize(this.graphics.height, this.graphics.height), this.tutoItem.onResize()), this.menuBackground && (this.menuCount = Math.ceil(this.screenDecal / (this.menuBackground.width * this.app.scale)) + 1) }, GameScreen.prototype.update = function() { this.gameOverTime && !Money.isTutoDone() ? (this.canRestart = StockManager.getAmount() >= StockManager.getLevelDodoCount(this.currentWorld.index, this.currentLevel.index), this.canNext = this.currentLevel.index >= this.currentWorld.levelList.length - 1 || StockManager.getAmount() >= StockManager.getLevelDodoCount(this.currentWorld.index, this.currentLevel.index + 1), this.notEnoughDodoTuto = !(this.canNext && (this.canRestart || this.isLevelDone(this.currentLevel.id)) || Money.isTutoDone() || this.gameOverTuto || testLevel)) : this.notEnoughDodoTuto = !1, this.world && (this.world.update(this.timeData), this.speedStartTime && this.world.tutoForward && this.timeData.global - this.speedStartTime > 2e3 && (this.world.tutoForward = !1)) }, GameScreen.prototype.onWorldLoaded = function() { console.log("WORLD LOADED"); var self = this; if (this.world.onResize(this.canvas.height, this.canvas.height), Debug.TUTO || this.hasLevelGoalTypeTuto(this.currentLevel) && !testLevel) { if (this.displayTuto = !0, !this.tutoEntity) { var w = new World(this); w.goalType = this.world.goalType, this.tutoEntity = new Entity(w, 1, 1, !1, !1, DataStore.dodoTypeList[Config.GENERAL.DEFAULT_DODO_TYPE], !1), this.tutoEntity.setSprite("WALK"), this.world.goalType == GoalType.COLLECT && (this.tutoItem = new Item(new World(this), { x: 0, y: 0 }), this.tutoItem.init()) } this.tutoEnnemy || this.currentLevel.goalType != GoalType.SURVIVE || (this.tutoEnnemy = new Entity(this.world, 1, 1, !0, !1, this.currentWorld.ennemyData, !1), this.tutoEnnemy.setSprite("WALK")), this.tutoCageSprite || this.currentLevel.goalType != GoalType.CAGE || (this.tutoCageSprite = this.app.createFxSprite("CAGE_1", 18)) } else this.displayTuto = !1, this.tutoEntity = !1, setTimeout(function() { self.startLevel() }, 1e3); this.show() }, GameScreen.prototype.onWorldReady = function() { if (this.timeData.local = 0, !testLevel) { var tryCount = getStoredInt("try-" + this.currentLevel.id); Achievement.record(DataStore.achievementType.LEVEL_RESTART, tryCount), setStoredInt("try-" + this.currentLevel.id, tryCount + 1), setStoredBool("saved-" + this.currentLevel.id, !1), DataSync.sync() } }, GameScreen.prototype.loadLevel = function(worldConfig, level) { this.currentWorld = worldConfig, this.currentLevel = level, this.app.music.pause(), this.createWorld(this.currentWorld, this.currentLevel) }, GameScreen.prototype.resetLevel = function() { this.world.destroy(), this.createWorld(this.currentWorld, this.currentLevel) }, GameScreen.prototype.createWorld = function(worldConfig, config) { var self = this; StockManager.onLevelStart(), this.destroyWorld(), this.showRetryTutoTime = !1, this.lostCount = 0, this.tutoHandTextCanvas && (this.tutoHandTextCanvas.dispose(), this.tutoHandTextCanvas = !1), this.gameOverTime = !1, this.skipEndScreen = 0, this.levelCreationTime = this.timeData.global, this.displayLevelTitle = !0, this.levelDisplayEndTime = !1, this.hsDisplayEndTime = !1; for (var i = 0; i < this.endStarFx.length; i++) this.endStarFx[i].resetAnim(); StockManager.getLevelDodoCount(worldConfig.index, config.index), "undefined" == typeof this.currentWorld.levelList[this.currentLevel.order], this.showForwardButton = this.isLevelDone(Config.TUTO.FORWARD_LEVEL) || config.id == Config.TUTO.FORWARD_LEVEL || testLevel, setTimeout(function() { self.restarting = !1, self.app.assetManager.getSound("start.level-board").reset().play(), self.hasLevelGoalTypeTuto(config) && !testLevel && setTimeout(function() { self.app.assetManager.getSound("start.tuto-roll").reset().play() }, 750) }, 500), this.paused && this.togglePause(), this.showTreasure = config.bonus && 3 != getStoredInt("stars-" + config.id), this.world && this.world.dispose(), this.world = new World(self, worldConfig, config), this.world.onResize(this.graphics.height, this.graphics.height), this.goalType = this.world.goalType, this.tutoDisplayEndTime = !1, this.displayLevelTitle = !0 }, GameScreen.prototype.getLevelGoalType = function(level) { return level ? !testLevel && level.goalType == GoalType.CAGE && this.isLevelDone(level.id, !0) ? GoalType.SAVE : level.goalType : !1 }, GameScreen.prototype.hasLevelGoalTypeTuto = function(level) { return level.goalType == GoalType.CAGE && this.isLevelDone(level.id) ? !1 : level.goalTypeTuto }, GameScreen.prototype.cleanLevel = function() { this.world.tutoForward && (this.world.tutoForward = !1) }, GameScreen.prototype.registerLevelScore = function() { if (this.score = this.world.score, this.starCount = this.progressBar.starCount, this.lostCount = this.world.lost, this.gameDuration = this.timeData.local, this.highScore = Debug.HIGHSCORE, !testLevel) { var needUpdate = !1; this.score > getStoredInt("score-" + this.currentLevel.id, 0) && (getStoredInt("score-" + this.currentLevel.id, 0) && (this.highScore = !0), setStoredInt("score-" + this.currentLevel.id, this.score), needUpdate = !0), this.starCount > getStoredInt("stars-" + this.currentLevel.id, 0) && (setStoredInt("stars-" + this.currentLevel.id, this.starCount), needUpdate = !0), this.gameDuration < getStoredInt("time-" + this.currentLevel.id, 999999999) && (setStoredInt("time-" + this.currentLevel.id, this.gameDuration), needUpdate = !0), 0 == this.starCount ? (setStoredInt("defeat-" + this.currentLevel.id, getStoredInt("defeat-" + this.currentLevel.id) + 1), Achievement.record(DataStore.achievementType.DEFEAT), Achievement.record(DataStore.achievementType.QUICK_LOST, Math.floor(this.gameDuration / 1e3))) : (setStoredInt("victory-" + this.currentLevel.id, getStoredInt("victory-" + this.currentLevel.id) + 1), Achievement.record(DataStore.achievementType.VICTORY), Achievement.record(DataStore.achievementType.QUICK_WIN, Math.floor(this.gameDuration / 1e3)), 0 == this.lostCount && Achievement.record(DataStore.achievementType.PERFECT)), setStoredBool("saved-" + this.currentLevel.id, !1), needUpdate && this.app.levelSelectScreen.refreshData(), Achievement.record(DataStore.achievementType.LEVEL_SCORE, this.score); for (var globalScore = 0, globalStarCount = 0, i = 0; i < DataStore.worldList.length; i++) for (var world = DataStore.worldList[i], j = 0; j < world.levelList.length; j++) { var levelId = world.levelList[j].id; globalScore += getStoredInt("score-" + levelId, 0), globalStarCount += getStoredInt("stars-" + levelId, 0) } Achievement.record(DataStore.achievementType.GLOBAL_SCORE, globalScore),DOTscore(globalScore, "SaveTheDodosH5DOT", 1, 1), Achievement.record(DataStore.achievementType.STARS, globalStarCount), DataSync.sync() } }, GameScreen.prototype.gameOver = function() { this.registerLevelScore(), this.currentLevel.isTuto && 0 == this.starCount ? this.showRetryTutoTime = this.timeData.global : this.displayEndScreen() }, GameScreen.prototype.displayEndScreen = function() { var self = this; this.currentLevel.id, this.cleanLevel(), this.gameOverTime = this.timeData.global, this.scoreDisplayTime = !1, this.starShake = [!1, !1, !1], this.hsShaked = !1, this.gameOverTuto = StockManager.hasWarning() && !StockManager.isTutoDone() && !testLevel, this.world.music.pause(), this.starCount > 0 ? this.app.assetManager.getSound("end.victory").reset().play(function() { self.app.music.reset().playLoop() }) : this.app.assetManager.getSound("end.defeat").reset().play(function() { self.app.music.reset().playLoop() }), this.friendsDisplayed = !1, FBUtils.userData && this.displayFriendList(), setTimeout(function() { self.app.assetManager.getSound("end.screen").reset().play(), self.shake() }, 500) }, GameScreen.prototype.backToLevelList = function() { var self = this; this.cleanLevel(), Analytics.log("quit-level", self.currentWorld.index + 1 + "-" + (self.currentLevel.index + 1)), this.app.showInterstitial(function() { self.world && !self.world.finished && self.app.music.reset().playLoop(), self.destroyWorld(), GameScreen.speedFactor = 1, self.app.levelSelectScreen.levelCarousel.currentIndex != self.currentLevel.index && self.app.levelSelectScreen.levelCarousel.selectElm(self.currentLevel.index), self.app.levelSelectScreen.show() }) }, GameScreen.prototype.restartLevel = function() { var self = this; !this.restarting && this.currentLevel.isTuto && StockManager.stockList[Config.GENERAL.DEFAULT_DODO_TYPE].add(this.lostCount), Analytics.log("restart-level", self.currentWorld.index + 1 + "-" + (self.currentLevel.index + 1)), !this.restarting && StockManager.checkAvailable(self.currentWorld.index, self.currentLevel.index, function() { self.restartLevel() }) && (this.restarting = !0, this.app.showInterstitial(function() { setTimeout(function() { self.destroyWorld(), self.loadLevel(self.currentWorld, self.currentLevel) }, 500) })) }, GameScreen.prototype.startLevel = function() { var self = this; this.tutoDisplayEndTime = this.timeData.global, this.levelDisplayEndTime = this.timeData.global + 2e3, Analytics.log("start-level", self.currentWorld.index + 1 + "-" + (self.currentLevel.index + 1)), setTimeout(function() { self.world.init(), self.app.assetManager.getSound("start.tile").reset().play() }, 500), setTimeout(function() { self.world.config.id == Config.TUTO.FORWARD_LEVEL && (self.world.tutoForward = !0) }, 2500) }, GameScreen.prototype.getNextLevelDodoMissingAmount = function() { var missingAmount = 0; return this.currentLevel.index < this.currentWorld.levelList.length - 1 && (missingAmount = Math.max(0, StockManager.getLevelDodoCount(this.currentWorld.index, this.currentLevel.index + 1) - StockManager.getAmount())), missingAmount }, GameScreen.prototype.getUnlockCost = function() { return Config.GENERAL.UNLOCK_LEVEL_COST + StockManager.getMissingDodoCost(this.getNextLevelDodoMissingAmount()) }, GameScreen.prototype.nextLevel = function() { var self = this; if (console.log("go next level"), this.isLevelDone(this.currentLevel.id)) { var worldComplete = "undefined" == typeof this.currentWorld.levelList[this.currentLevel.order]; (worldComplete || StockManager.checkAvailable(this.currentWorld.index, this.currentLevel.index + 1, function() { self.nextLevel() })) && (console.log("world will be destroyed"), this.restarting = !0, this.destroyWorld(), worldComplete ? (this.backToLevelList(), this.app.levelSelectScreen.back(), this.app.levelSelectScreen.worldCarousel.next()) : (console.log("show showInterstitial"), this.app.showInterstitial(function() { console.log("ok load level"), self.loadLevel(self.currentWorld, self.currentWorld.levelList[self.currentLevel.order]) }))) } else Money.spend(this.getUnlockCost(), function() { StockManager.stockList[Config.GENERAL.DEFAULT_DODO_TYPE].add(self.getNextLevelDodoMissingAmount()), setStoredBool("level-unlock-" + self.currentLevel.id, !0), self.nextLevel() }) }, GameScreen.prototype.destroyWorld = function() { this.world && (this.world.dispose(), delete this.world, this.world = !1) }, GameScreen.prototype.togglePause = function() { this.paused = !this.paused, GameScreen.speedFactor = this.paused ? 0 : 1, this.needRefresh = !0 }, GameScreen.prototype.isLevelDone = function(level, withoutUnlock) { return getStoredInt("stars-" + level) > 0 || !withoutUnlock && getStoredBool("level-unlock-" + level) }, GameScreen.prototype.shake = function() { this.app.shake() }, GameScreen.prototype.init = function() { this.goalTypeCount = 4, this.goalTypeImg = this.app.assetManager.getAtlasImage("gui.common.goal-type"), this.goalTypeWidth = Math.round(this.goalTypeImg.width / this.goalTypeCount), this.goalTypeHeight = this.goalTypeImg.height, this.progressBar = new ProgressBar(this, this.app.assetManager), this.tutoHand = this.assetManager.getAtlasImage("gui.game.tuto-finger"), this.tutoBackground = this.assetManager.getAtlasImage("gui.game.tuto-background"), this.tutoForeground = this.assetManager.getAtlasImage("gui.game.tuto-foreground"), this.tutoStartArrow = this.assetManager.getAtlasImage("gui.game.tuto-start-arrow"), this.tutoBottom = this.assetManager.getAtlasImage("gui.game.tuto-bottom"), this.tutoTop = this.assetManager.getAtlasImage("gui.game.tuto-top"), this.trainingTutoBackground = this.assetManager.getAtlasImage("gui.game.training-tuto"), this.nest = this.assetManager.getAtlasImage("gui.game.nest"), this.captionWood = this.assetManager.getAtlasImage("gui.common.caption-wood"), this.captionLight = this.app.assetManager.getAtlasImage("gui.common.caption-light"), this.captionDark = this.app.assetManager.getAtlasImage("gui.common.caption-dark"), this.skull = this.app.assetManager.getAtlasImage("gui.game.skull"), this.starCenter = this.assetManager.getAtlasImage("gui.game.end-star-center"), this.starSide = this.assetManager.getAtlasImage("gui.game.end-star-side"), this.money = app.assetManager.getAtlasImage("gui.common.money"), this.menuBackground = this.app.assetManager.getImage("gui.game.background"), this.menuBackgroundHeight = App.BASE_HEIGHT, this.menuBackgroundWidth = this.menuBackground.width * App.BASE_HEIGHT / this.menuBackground.height, this.goalTypeIndexById = {}; var i = 0; for (var id in GoalType) this.goalTypeIndexById[GoalType[id]] = i++; this.endStarFx = [this.app.createFxSprite("END_STAR", 18), this.app.createFxSprite("END_STAR", 18), this.app.createFxSprite("END_STAR", 18)] }, GameScreen.prototype.renderGoalType = function(g, type, x, y) { this.goalTypeImg.render(g, this.goalTypeIndexById[type] * this.goalTypeWidth, 0, this.goalTypeWidth, this.goalTypeHeight, x, y, this.goalTypeWidth, this.goalTypeHeight) }, GameScreen.prototype.render = function() { var self = this, g = this.graphics; g.timeData = this.timeData; var tutoHand = !this.paused && (this.world.tutoForward || this.stockTuto && !StockManager.visible); if (this.needRefresh || (this.needRefresh = tutoHand), this.needRefresh) { StockManager.visible && (StockManager.needRefresh = !0); var g = this.graphics; g.save(), g.translate(Math.round(this.screenDecal / 2), 0), g.scale(app.scale, app.scale); for (var i = 0; i < this.menuCount; i++) { var decal = (this.menuBackgroundWidth - 1) * Math.ceil(i / 2); i % 2 && (decal = -decal), g.drawImage(this.menuBackground, 0, 0, this.menuBackground.width, this.menuBackground.height, decal - Math.round(this.menuBackgroundWidth / 2), 0, this.menuBackgroundWidth, this.menuBackgroundHeight) } g.restore(), g.save(), g.translate(g.width - Math.round(this.screenDecal / 2), 0), g.scale(app.scale, app.scale); for (var i = 0; i < this.menuCount; i++) { var decal = (this.menuBackgroundWidth - 1) * Math.ceil(i / 2); i % 2 && (decal = -decal), g.drawImage(this.menuBackground, 0, 0, this.menuBackground.width, this.menuBackground.height, decal - Math.round(this.menuBackgroundWidth / 2), 0, this.menuBackgroundWidth, this.menuBackgroundHeight) } g.restore() } if (g.save(), g.translate(Math.round(this.screenDecal / 2), 0), g.scale(app.scale, app.scale), this.renderMoney(g), this.renderLevelCaption(g), this.renderScoreCaption(g), this.renderPauseMenu(g), this.renderFriendList(g), g.restore(), g.save(), g.translate(g.width - Math.round(this.screenDecal / 2), 0), g.scale(app.scale, app.scale), this.renderStock(g), this.progressBar.render(g, this.needRefresh), this.renderLostCount(g), g.restore(), this.needRefresh || !StockManager.visible) { if (g.save(), g.globalAlpha = 1, g.translate(this.screenDecal, 0), g.beginPath(), g.rect(0, 0, g.height, g.height), g.clip(), this.backgroundImage ? (g.save(), this.backgroundScale || (this.backgroundScale = g.height / this.backgroundImage.height), g.scale(this.backgroundScale, this.backgroundScale), g.drawImage(this.backgroundImage, 0, 0), g.restore()) : g.clearRect(0, 0, g.width, g.height), this.world && this.world.ready && this.world.render(g), this.paused && (g.fillStyle = "black", g.globalAlpha = .5, g.fillRect(0, 0, g.width, g.height)), g.scale(app.scale, app.scale), this.displayLevelTitle && this.renderLevelTitle(g), this.displayTuto && this.renderTuto(g), g.restore(), this.currentLevel.isTuto && !this.showRetryTutoTime && (g.save(), g.globalAlpha = .7 + .2 * Math.cycleSin(g.timeData.global, 2e3), g.translate(this.screenDecal, 0), g.scale(app.scale, app.scale), g.scale(.8, .8), g.drawImage(app.trainingCanvas, 10, 10), g.restore()), !this.gameOverTime || this.paused && !this.needRefresh) { if (this.showRetryTutoTime) { if (!this.tutoRetryTextCanvas) { this.tutoRetryTextCanvas = Utils.createCanvas(512, 256); var g2 = this.tutoRetryTextCanvas.getContext("2d"); g2.textAlign = "center", this.app.setSecondaryFont(g2, 64), this.app.fillOutlineText(g2, _2("tuto-retry-title"), Math.round(this.tutoRetryTextCanvas.width / 2), 75), text = Utils.splitText(_2("tuto-retry-text")), this.app.setBaseFont(g2, 28); for (var i = 0; i < text.length; i++) this.app.fillOutlineText(g2, text[i], Math.round(this.tutoRetryTextCanvas.width / 2), 35 * i + 120) } g.save(), g.translate(Math.round(g.width / 2), Math.round(g.height / 2)), g.scale(this.app.scale, this.app.scale), g.save(), this.trainingTutoBackground.render(g, -Math.round(this.trainingTutoBackground.width / 2), 15 - Math.round(this.trainingTutoBackground.height / 2)), g.restore(), g.drawImage(this.tutoRetryTextCanvas, -Math.round(this.tutoRetryTextCanvas.width / 2), -Math.round(this.tutoRetryTextCanvas.height / 2)), g.scale(1.2, 1.2), g.drawImage(app.trainingCanvas, 105, -165), g.restore(), ButtonUtils.render({ g: g, img: this.app.assetManager.getAtlasImage("gui.common.restart"), id: "tuto-restart", x: Math.round(g.width / 2), y: Math.round(g.height / 2) + 120 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_TOP, scale: .1 * Math.cycleSin(this.timeData.global, 1e3) + 1, listener: function() { self.restartLevel() }, needRefresh: !0 }) } } else this.renderEndScreen(g); var borderWidth = 3; if (g.fillStyle = "#38250C", g.fillRect(this.screenDecal - Math.round(borderWidth / 2), 0, borderWidth, g.height), g.fillRect(this.screenDecal + g.height - Math.round(borderWidth / 2), 0, borderWidth, g.height), tutoHand) { g.save(), this.stockTuto ? g.translate(g.width - Math.round(this.screenDecal / 2), 0) : g.translate(Math.round(this.screenDecal / 2), g.height), g.scale(app.scale, app.scale); var f = Math.cycleSin(g.timeData.local, 1e3); if (g.translate(-25 * f, 19 * f), this.stockTuto ? (g.translate(-70, 80), g.save(), g.rotate(.45 * Math.PI), this.tutoHand.render(g, 0, 0), g.restore(), g.translate(-140, 140)) : (g.translate(80, -130), g.save(), g.rotate(.15 * Math.PI), g.scale(1, -1), this.tutoHand.render(g, 0, 0), g.restore(), g.translate(200, -80)), !this.tutoHandTextCanvas) { this.tutoHandTextCanvas = Utils.createCanvas(), this.tutoHandTextCanvas.width = this.stockTuto ? 512 : 256, this.tutoHandTextCanvas.height = 64; var g2 = this.tutoHandTextCanvas.getContext("2d"), text = Utils.splitText(this.stockTuto ? _2("stock-tuto-label") : _2("forward-tuto-label")); app.setBaseFont(g2, 30), g2.translate(0, 26), this.stockTuto ? (g2.textAlign = "right", g2.translate(this.tutoHandTextCanvas.width, 0)) : g2.textAlign = "left"; for (var i = 0; i < text.length; i++) app.fillOutlineText(g2, text[i], 0, 30 * i) } g.drawImage(this.tutoHandTextCanvas, this.stockTuto ? -this.tutoHandTextCanvas.width : 0, -26), g.restore() } else this.needRefresh = this.gameOverTuto || this.notEnoughDodoTuto } else this.needRefresh = !1 }, GameScreen.prototype.renderLevelTitle = function(g) { var t = g.timeData.global - this.levelCreationTime; g.translate(Math.round(g.height / app.scale / 2), 0), g.save(); var dropDelay = 500, dropDuration = 2e3, undropDuration = 1e3, dropF = 0; (this.levelDisplayEndTime && g.timeData.global > this.levelDisplayEndTime || dropDelay + dropDuration > t) && (dropF = this.tutoDisplayEndTime ? 1 : 0, this.levelDisplayEndTime && g.timeData.global > this.levelDisplayEndTime ? (dropF = 1 - Math.easeOutExpo((g.timeData.global - this.levelDisplayEndTime) / undropDuration), g.globalAlpha = Math.max(0, dropF), 0 == g.globalAlpha && (this.displayLevelTitle = !1)) : !this.levelDisplayEndTime && t > dropDelay && (dropF = Math.easeOutElastic((t - dropDelay) / dropDuration, 2), dropF > 1 && (dropF = 2 - dropF)), g.scale(1, .95 * dropF + .05)), this.captionWood.render(g, Math.round(-this.captionWood.width / 2), 0), g.save(), g.scale(.7, .7), this.renderGoalType(g, this.getLevelGoalType(this.currentLevel), Math.round(-this.captionWood.width / 2) - 50, 30), g.restore(), g.translate(0, 50); var levelTitle = _2("level").toUpperCase() + " " + this.currentLevel.order; this.app.setThirdFont(g, 32), g.textAlign = "center", g.strokeText(levelTitle, 0, 0), g.fillText(levelTitle, 0, 0), g.translate(0, 33); var levelType = getDBText("goal_type", "name", this.getLevelGoalType(this.currentLevel)); this.app.setBaseFont(g, 26), g.strokeText(levelType, 0, 0), g.fillText(levelType, 0, 0), g.restore() }, GameScreen.prototype.renderTuto = function(g) { var self = this; g.translate(-Math.round(this.tutoBackground.width / 2), 170); var dropDelay = 1e3, dropDuration = 500, undropDuration = 1e3, buttonDuration = 500, t = g.timeData.global - this.levelCreationTime, dropF = 1; g.save(), (this.tutoDisplayEndTime && g.timeData.global > this.tutoDisplayEndTime || dropDelay + dropDuration > t) && (dropF = 1, this.tutoDisplayEndTime && g.timeData.global > this.tutoDisplayEndTime ? (dropF = Math.easeOutExpo((g.timeData.global - this.tutoDisplayEndTime) / undropDuration), g.globalAlpha = Math.max(0, 1 - dropF), 0 == g.globalAlpha && (this.displayTuto = !1)) : !this.tutoDisplayEndTime && t > dropDelay && (dropF = 1 - Math.easeOutExpo((t - dropDelay) / dropDuration)), g.beginPath(), g.rect(-10, 0, this.tutoBackground.width + 20, this.tutoBackground.height + 10), g.clip(), g.translate(0, -410 * dropF)), this.tutoBackground.render(g, 0, 0); var tile = this.world.assetManager.getImage("tile-" + Config.TUTO.BASE_TILE); g.save(), g.beginPath(), g.rect(10, 10, this.tutoForeground.width - 20, this.tutoForeground.height - 20), g.clip(), this.currentLevel.goalType == GoalType.SAVE ? g.drawImage(this.world.assetManager.getImage("exit"), 330, 140) : this.currentLevel.goalType == GoalType.COLLECT && this.nest.render(g, 375, 170), g.save(), g.translate(240, 90); var description = Utils.splitText(getDBText("goal_type", "tuto", this.getLevelGoalType(this.currentLevel))); this.app.setBaseFont(g, 28), g.textAlign = "center", g.fillStyle = "black"; for (var i = 0; i < description.length; i++) g.fillText(description[i].toUpperCase(), 0, 30 * i); g.restore(), g.translate(-150, -35), g.drawImage(tile, 0, 0), g.drawImage(tile, 370, 0), this.currentLevel.goalType == GoalType.CAGE && (g.save(), g.translate(560, 230), g.scale(1.2, 1.2), this.tutoCageSprite.render(g), g.restore()), g.save(); var duration = this.currentLevel.goalType == GoalType.SURVIVE || this.currentLevel.goalType == GoalType.COLLECT ? 9e3 : 7e3, part = .85, f = g.timeData.local % duration / duration, xMax = this.currentLevel.goalType == GoalType.SURVIVE || this.currentLevel.goalType == GoalType.COLLECT ? 800 : 480, x = xMax, y = 0, scale = 1.2 / app.scale; if (part > f || this.currentLevel.goalType == GoalType.SURVIVE || this.currentLevel.goalType == GoalType.COLLECT ? ("WALK" != this.tutoEntity.currentSpriteId && this.tutoEntity.setSprite("WALK"), x = this.currentLevel.goalType == GoalType.SURVIVE || this.currentLevel.goalType == GoalType.COLLECT ? Math.round(f * xMax) : Math.round(f / part * xMax)) : (f = (f - part) / (1 - part), y = Math.round(-35 * f), f = Math.easeInExpo(f), g.globalAlpha = 1 - f, scale -= f * scale, this.currentLevel.goalType == GoalType.CAGE ? "DEATH_CAGE" != this.tutoEntity.currentSpriteId && (this.assetManager.getSound("game.death").reset().play(), this.tutoEntity.setSprite("DEATH_CAGE")) : "SAVED" != this.tutoEntity.currentSpriteId && this.tutoEntity.setSprite("SAVED")), this.world.goalType == GoalType.COLLECT && .15 >= f && (g.save(), g.translate(280, 390), g.scale(scale, scale), this.tutoItem.renderAtOrigin(g), g.restore()), g.save(), this.tutoEntity.item = this.world.goalType == GoalType.COLLECT && f > .15 && .6 > f, g.translate(120 + x, 340 + y), g.scale(scale, scale), this.tutoEntity.renderAtOrigin(g), g.restore(), this.currentLevel.goalType == GoalType.SURVIVE && f > .3 && (g.translate(1.08 * xMax * (f - .3) / .7, 355 + y), g.scale(scale, scale), this.tutoEnnemy.renderAtOrigin(g)), g.restore(), this.currentLevel.goalType != GoalType.SURVIVE) { var fc = Math.cycleSin(g.timeData.local, 1e3); g.save(), this.currentLevel.goalType == GoalType.CAGE ? g.translate(40, -30 * fc) : g.translate(0, -30 * fc), this.tutoStartArrow.render(g, 550, 90), g.restore() } if (g.restore(), this.tutoForeground.render(g, 0, 0), this.tutoBottom.render(g, 0, 410), g.restore(), this.tutoDisplayEndTime && (g.globalAlpha = 1 - dropF), this.tutoTop.render(g, 0, -25), t > dropDelay + dropDuration) { g.save(); var t = g.timeData.local - dropDuration - dropDelay, scale = !1; buttonDuration > t && (scale = Math.easeOutBack(t / buttonDuration)), ButtonUtils.render({ g: g, img: this.assetManager.getAtlasImage("gui.common.play"), id: "tuto-play", x: Math.round(g.width / 2 + 300 * app.scale), y: 560 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_TOP, scale: scale, listener: function() { self.startLevel() }, visibilityHandler: function() { return !self.tutoDisplayEndTime }, needRefresh: !0 }), g.restore() } }, GameScreen.prototype.renderStock = function(g) { var self = this; !this.paused && this.world && this.world.ready && !this.world.finished && this.showForwardButton && this.renderForwardButton(g), (this.needRefresh || !StockManager.visible) && (this.stockTuto || ButtonUtils.renderBackground({ g: g, bgActiveScale: 1, background: this.menuBackground, backgroundX: Math.round(g.width - this.screenDecal / 2 - this.menuBackgroundWidth * app.scale / 2), backgroundY: 0, backgroundWidth: this.menuBackgroundWidth, backgroundHeight: this.menuBackgroundHeight, width: 180, height: 130 }, Math.round(g.width - this.screenDecal / 2), 75 * app.scale), StockManager.renderForGame(g), Input.addCollider("stock-game", Math.round(g.width - this.screenDecal / 2 - 50 * app.scale), 12 * app.scale, 100 * app.scale, 130 * app.scale, function() { self.gameOverTuto = !1; var closeListener = !1; self.paused || (closeListener = function() { self.paused && self.togglePause() }, self.togglePause()), StockManager.openPopup(closeListener) }, !1, function() { return !self.notEnoughDodoTuto && (!self.gameOverTuto || self.stockTuto) })) }, GameScreen.prototype.renderMoney = function(g) { var self = this; (this.needRefresh || Input.needRefresh("money-game")) && (g.save(), g.scale(.52, .52), Config.GENERAL.MONETIZATION ? (g.translate(-Math.round(Money.background.width / 2), 20), Input.addCollider("money-game", Math.round((this.screenDecal - .6 * Money.background.width * app.scale) / 2), 12 * app.scale, .6 * Money.background.width * app.scale, .6 * Money.background.height * app.scale, function() { var closeListener = !1; self.paused || (closeListener = function() { self.paused && self.togglePause() }, self.togglePause()), Money.openPopup(closeListener) }, !1, function() { return !self.gameOverTuto && !self.notEnoughDodoTuto && !self.stockTuto })) : g.translate(-Math.round(.85 * Money.background.width), 20), ButtonUtils.renderBackground({ g: g, background: this.menuBackground, backgroundX: Math.round((this.screenDecal - this.menuBackgroundWidth * app.scale) / 2), backgroundY: 0, backgroundWidth: this.menuBackgroundWidth, backgroundHeight: this.menuBackgroundHeight, width: .52 * Money.background.width, height: .52 * Money.background.height }, (20 + .52 * (Money.background.width / 2)) * app.scale, (20 + .52 * (Money.background.height / 2)) * app.scale), Money.render(g, Input.isActive("money-game")), Input.setRefreshed("money-game"), g.restore()) }, GameScreen.prototype.renderPauseMenu = function(g) { var self = this; this.world && this.world.gameStarted && !this.world.finished && (ButtonUtils.render({ g: g, img: this.app.assetManager.getAtlasImage(this.paused ? "gui.common.play" : "gui.common.pause"), id: "pause", x: Math.round(this.screenDecal / 2), y: 215 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_TOP, listener: function() { self.togglePause() }, visibilityHandler: function() { return self.world && self.world.gameStarted && !self.world.finished }, changeListener: function() { self.needRefresh = !0 }, needRefresh: this.needRefresh, background: this.menuBackground, backgroundWidth: this.menuBackgroundWidth, backgroundHeight: this.menuBackgroundHeight, backgroundX: Math.round((this.screenDecal - this.menuBackgroundWidth * app.scale) / 2), backgroundY: 0 }), this.paused && (ButtonUtils.render({ g: g, img: this.app.assetManager.getAtlasImage("gui.common.menu"), id: "pause-menu", x: Math.round(this.screenDecal / 2), y: 455 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_TOP, listener: function() { self.backToLevelList() }, visibilityHandler: function() { return self.paused }, needRefresh: this.needRefresh, background: this.menuBackground, backgroundWidth: this.menuBackgroundWidth, backgroundHeight: this.menuBackgroundHeight, backgroundX: Math.round((this.screenDecal - this.menuBackgroundWidth * app.scale) / 2), backgroundY: 0 }), ButtonUtils.render({ g: g, img: this.app.assetManager.getAtlasImage("gui.common.restart"), id: "pause-restart", x: Math.round(this.screenDecal / 2), y: 335 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_TOP, listener: function() { self.restartLevel() }, changeListener: function() { self.needRefresh = !0 }, extraRender: function(g) { self.currentLevel.isTuto || StockManager.renderCountTag(g, self.currentWorld.index, self.currentLevel.index) }, visibilityHandler: function() { return self.paused }, bgActiveScale: 1.6, needRefresh: this.needRefresh }), ButtonUtils.render({ g: g, img: this.app.assetManager.getAtlasImage(app.assetManager.soundEnabled ? "gui.common.sound-on" : "gui.common.sound-off"), id: "pause-sound", scale: .9, x: Math.round(this.screenDecal / 2), y: g.height - 10 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { app.assetManager.toggleSound() }, visibilityHandler: function() { return self.paused }, needRefresh: this.needRefresh, background: this.menuBackground, backgroundWidth: this.menuBackgroundWidth, backgroundHeight: this.menuBackgroundHeight, backgroundX: Math.round((this.screenDecal - this.menuBackgroundWidth * app.scale) / 2), backgroundY: 0 }))) }, GameScreen.prototype.renderForwardButton = function(g) { var self = this; ButtonUtils.render({ g: g, img: this.app.assetManager.getAtlasImage("gui.common.forward"), id: "forward", x: Math.round(this.screenDecal / 2), y: g.height - 20 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, listener: { on: function() { self.enableSpeed() }, off: function() { self.disableSpeed() } }, needRefresh: this.needRefresh, background: this.menuBackground, backgroundWidth: this.menuBackgroundWidth, backgroundHeight: this.menuBackgroundHeight, backgroundX: Math.round((this.screenDecal - this.menuBackgroundWidth * app.scale) / 2), backgroundY: 0 }) }, GameScreen.prototype.renderLevelCaption = function(g) { this.needRefresh && (g.save(), g.translate(0, 70), this.captionLight.render(g, -Math.round(this.captionLight.width / 2), 0), g.save(), g.scale(.42, .42), this.renderGoalType(g, this.getLevelGoalType(this.currentLevel), -132, 8), g.restore(), app.setBaseFont(g, 30), g.translate(20, 35), g.textAlign = "center", g.strokeText(this.currentWorld.order + "-" + this.currentLevel.order, 0, 0), g.fillText(this.currentWorld.order + "-" + this.currentLevel.order, 0, 0), g.restore()) }, GameScreen.prototype.renderScoreCaption = function(g) { var duration = 500; if (this.needRefresh || this.world && g.timeData.global <= this.world.scoreRefreshTime + duration) { g.save(); var f = Math.min(1, Math.max(0, (g.timeData.global - this.world.scoreRefreshTime) / duration)), score = Math.round(f * (this.world.score - this.world.lastScore)) + this.world.lastScore; g.translate(0, 150), g.scale(.9, .9), this.captionDark.render(g, -Math.round(this.captionDark.width / 2), 0), app.setSecondaryFont(g, 28), g.save(), g.translate(-Math.round(this.captionDark.width / 2) + 5, 5), g.textAlign = "left", g.textBaseline = "bottom", g.strokeText(_2("score"), 0, 0), g.fillText(_2("score"), 0, 0), g.restore(), app.setBaseFont(g, 30), g.translate(0, 32), g.textAlign = "center", g.strokeText(score, 0, 0), g.fillText(score, 0, 0), g.restore() } }, GameScreen.prototype.renderLostCount = function(g) { var duration = 500; if (this.needRefresh || this.world && g.timeData.global <= this.world.lostRefreshTime + duration) { g.save(), ButtonUtils.renderBackground({ g: g, bgActiveScale: 1, background: this.menuBackground, backgroundX: Math.round(g.width - this.screenDecal / 2 - this.menuBackgroundWidth * app.scale / 2), backgroundY: 0, backgroundWidth: this.menuBackgroundWidth, backgroundHeight: this.menuBackgroundHeight, width: this.captionDark.width + 50, height: this.captionDark.height + 10 }, Math.round(g.width - this.screenDecal / 2), Math.round(g.height - (60 - this.captionDark.height / 2) * app.scale)), g.translate(0, App.BASE_HEIGHT - 60), g.scale(.85, .85), this.captionDark.render(g, -Math.round(this.captionDark.width / 2), 0), g.save(), g.translate(50, 20); var scaleEffect = .75, f = 1; this.world && g.timeData.global <= this.world.lostRefreshTime + duration && (f = Math.easeOutElastic((g.timeData.global - this.world.lostRefreshTime) / duration)), g.scale(1 + (1 - f) * scaleEffect, 1 + (1 - f) * scaleEffect), g.translate(0, -20), this.app.setBaseFont(g, 40), g.textAlign = "right", g.strokeText(this.world.lost, 0, 35), g.fillText(this.world.lost, 0, 35); var decal = g.measureText(this.world.lost); this.app.setBaseFont(g, 25), g.strokeText("x", -5 - decal.width, 35), g.fillText("x", -5 - decal.width, 35), g.restore(), g.scale(1.2, 1.2), this.skull.render(g, -60, 0), g.restore() } }, GameScreen.END_SCREEN_FADE_DURATION = 500, GameScreen.END_SCREEN_STAR_DELAY = 1e3, GameScreen.END_SCREEN_STAR_DURATION = 500, GameScreen.END_SCREEN_NEXT_STAR_DELAY = 400, GameScreen.prototype.renderEndScreen = function(g) { var self = this; g.save(); var globalTime = g.timeData.global; if (this.skipEndScreen && (globalTime += this.skipEndScreen), globalTime < this.gameOverTime + GameScreen.END_SCREEN_FADE_DURATION) { var f = Math.easeInExpo((globalTime - this.gameOverTime) / GameScreen.END_SCREEN_FADE_DURATION); g.translate(0, (1 - f) * -g.height) } g.translate(this.screenDecal, 0), g.scale(this.app.scale, this.app.scale); var won = this.starCount > 0, background = this.assetManager.getImage("gui.game.end-background-" + (won ? "victory" : "defeat")); if (g.drawImage(background, 0, 0, background.width, background.height, 0, 0, App.BASE_HEIGHT, App.BASE_HEIGHT), g.translate(Math.round(g.height / app.scale / 2), 0), g.save(), g.translate(0, 130), this.drawCachedText(g, "title", won ? _2("victory-title") : _2("defeat-title"), 90, 1024, 128, -4, !0), g.restore(), won) { var displayStarOff = [!0, !0, !0], displayStarOn = [!1, !1, !1], displayStarF = [0, 0, 0]; if (globalTime > this.gameOverTime + GameScreen.END_SCREEN_STAR_DELAY) for (var i = 0; i < displayStarOn.length; i++) this.starCount > i && globalTime > this.gameOverTime + GameScreen.END_SCREEN_STAR_DELAY + GameScreen.END_SCREEN_NEXT_STAR_DELAY * i && (displayStarOn[i] = !0, displayStarF[i] = Math.easeInExpo((globalTime - (this.gameOverTime + GameScreen.END_SCREEN_STAR_DELAY + GameScreen.END_SCREEN_NEXT_STAR_DELAY * i)) / GameScreen.END_SCREEN_STAR_DURATION), displayStarF[i] > 1 ? (displayStarF[i] = 1, displayStarOff[i] = !1, this.starShake[i] || (this.app.shake(), this.starShake[i] = !0, this.starCount == i + 1 && (this.scoreDisplayTime = globalTime + 250))) : displayStarF[i] > .5 && this.endStarFx[i].stopAnim && (this.assetManager.getSound("end.star").reset().play(), this.endStarFx[i].play(g.timeData))); globalTime > GameScreen.END_SCREEN_STAR_DELAY && (g.save(), g.translate(-205, 258), displayStarOff[0] && this.starSide.render(g, 0, 0, this.starSide.width / 2, this.starSide.height, -Math.round(this.starSide.width / 4), -Math.round(this.starSide.height / 2), this.starSide.width / 2, this.starSide.height), displayStarOn[0] && (g.scale(displayStarF[0], displayStarF[0]), this.starSide.render(g, this.starSide.width / 2, 0, this.starSide.width / 2, this.starSide.height, -Math.round(this.starSide.width / 4), -Math.round(this.starSide.height / 2), this.starSide.width / 2, this.starSide.height), this.endStarFx[0].stopAnim || this.endStarFx[0].animComplete || (g.save(), g.scale(1.5, 1.5), g.translate(-Math.round(this.endStarFx[0].width / 2), -Math.round(this.endStarFx[0].height / 2)), this.endStarFx[0].render(g), g.restore())), g.restore(), g.save(), g.translate(205, 258), g.scale(-1, 1), displayStarOff[2] && this.starSide.render(g, 0, 0, this.starSide.width / 2, this.starSide.height, -Math.round(this.starSide.width / 4), -Math.round(this.starSide.height / 2), this.starSide.width / 2, this.starSide.height), displayStarOn[2] && (g.scale(displayStarF[2], displayStarF[2]), this.starSide.render(g, this.starSide.width / 2, 0, this.starSide.width / 2, this.starSide.height, -Math.round(this.starSide.width / 4), -Math.round(this.starSide.height / 2), this.starSide.width / 2, this.starSide.height), this.endStarFx[2].stopAnim || this.endStarFx[2].animComplete || (g.save(), g.scale(1.5, 1.5), g.translate(-Math.round(this.endStarFx[2].width / 2), -Math.round(this.endStarFx[2].height / 2)), this.endStarFx[2].render(g), g.restore())), g.restore(), g.save(), g.translate(0, 262), displayStarOff[1] && this.starCenter.render(g, 0, 0, this.starCenter.width / 2, this.starCenter.height, -Math.round(this.starCenter.width / 4), -Math.round(this.starCenter.height / 2), this.starCenter.width / 2, this.starCenter.height), displayStarOn[1] && (g.scale(displayStarF[1], displayStarF[1]), this.starCenter.render(g, this.starCenter.width / 2, 0, this.starCenter.width / 2, this.starCenter.height, -Math.round(this.starCenter.width / 4), -Math.round(this.starCenter.height / 2), this.starCenter.width / 2, this.starCenter.height), this.endStarFx[1].stopAnim || this.endStarFx[1].animComplete || (g.save(), g.scale(1.5, 1.5), g.translate(-Math.round(this.endStarFx[1].width / 2), -Math.round(this.endStarFx[1].height / 2)), this.endStarFx[1].render(g), g.restore())), g.restore()) } else g.save(), g.scale(1.2, 1.2), g.translate(-Math.round(this.defeatSprite.width / 2), 100), this.defeatSprite.render(g), g.restore(), this.scoreDisplayTime || (this.scoreDisplayTime = globalTime + 2e3); if (this.scoreDisplayTime) { var btimeDisplayTime = !1; if (won) { var scoreDuration = 1e3; if (globalTime > this.scoreDisplayTime) { this.world && !this.world.scoreSoundPlayed && (this.assetManager.getSound("end.score").reset().play(), this.world.scoreSoundPlayed = !0), g.translate(0, 465); var f = (globalTime - this.scoreDisplayTime) / scoreDuration, score = this.score; if (1 > f && (score = Math.round(score * f)), this.drawCachedText(g, "end-score", score, 86, 256, 64, 2), this.app.setBaseFont(g, 30), f >= 1) if (this.highScore) { this.world && !this.world.highscoreSoundPlayed && (this.assetManager.getSound("end.highscore").reset().play(), this.world.highscoreSoundPlayed = !0), g.save(), g.translate(130, -35), g.rotate(Math.PI / 12), f -= 1, 1 > f ? g.globalAlpha = f : this.hsDisplayEndTime || (this.hsDisplayEndTime = globalTime); var text = Utils.splitText(_2("new-highscore")); if (g.textAlign = "center", g.save(), 1 > f) { f = Math.easeInExpo(f); var s = .8 * f + .2; g.scale(s, s) } if (g.fillStyle = "rgba(0, 0, 0, 0.75)", g.translate(-5, 5), g.fillText(text[0], 0, -15), g.fillText(text[1], 0, 15), g.restore(), 1 > f) { var s = 2 * (1 - f) + 1; g.scale(s, s) } else this.hsShaked || (this.app.shake(), this.hsShaked = !0); g.fillStyle = "gold", this.app.fillOutlineText(g, text[0], 0, -15), this.app.fillOutlineText(g, text[1], 0, 15), g.restore() } else this.hsDisplayEndTime || (this.hsDisplayEndTime = globalTime) } if (this.hsDisplayEndTime) { var timeDisplayTime = this.hsDisplayEndTime + 150, timeDuration = 200; if (globalTime > timeDisplayTime) { this.world && !this.world.timeSoundPlayed && (this.assetManager.getSound("end.other").reset().play(), this.world.timeSoundPlayed = !0); var f = (globalTime - timeDisplayTime) / timeDuration; 1 > f && (g.globalAlpha = f), g.translate(0, 60), this.drawCachedText(g, "time", _2("time").replace("%1", Utils.formatTime(this.gameDuration)), 40, 512, 64, 3) } var hsDisplayTime = timeDisplayTime + timeDuration + 150, hsDuration = 200; if (globalTime > hsDisplayTime) { this.world && !this.world.hsSoundPlayed && (this.assetManager.getSound("end.other").reset().play(), this.world.hsSoundPlayed = !0); var f = (globalTime - hsDisplayTime) / hsDuration; 1 > f && (g.globalAlpha = f), g.translate(0, 50), this.drawCachedText(g, "highscore", _2("highscore").replace("%1", getStoredInt("score-" + this.currentLevel.id)), 30, 512, 32, 3) } btimeDisplayTime = hsDisplayTime + hsDuration + 150; var btimeDuration = 200; if (globalTime > btimeDisplayTime) { this.world && !this.world.btimeSoundPlayed && (this.assetManager.getSound("end.other").reset().play(), this.world.btimeSoundPlayed = !0); var f = (globalTime - btimeDisplayTime) / btimeDuration; 1 > f && (g.globalAlpha = f), g.translate(0, 35), this.drawCachedText(g, "best-time", _2("best-time").replace("%1", Utils.formatTime(getStoredInt("time-" + this.currentLevel.id))), 26, 512, 32, 3) } } } var buttonsDisplayTime = won ? btimeDisplayTime + btimeDuration + 250 : this.scoreDisplayTime, buttonsDuration = 200; if (globalTime > buttonsDisplayTime) { var f = (globalTime - buttonsDisplayTime) / buttonsDuration; if (1 > f && (g.globalAlpha = f), ButtonUtils.render({ g: g, img: this.assetManager.getAtlasImage("gui.common.menu"), id: "end-menu", x: Math.round(g.width / 2) - 80 * app.scale, y: g.height - 20 * app.scale, align: ButtonUtils.ALIGN_RIGHT, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { self.backToLevelList() }, visibilityHandler: function() { return self.gameOverTime && self.timeData.global > self.gameOverTime + 2e3 && !self.gameOverTuto && !self.notEnoughDodoTuto }, needRefresh: !0 }), ButtonUtils.render({ g: g, img: this.assetManager.getAtlasImage("gui.common.restart"), id: "end-restart", x: Math.round(g.width / 2), y: g.height - 20 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { self.restartLevel() }, visibilityHandler: function() { return self.gameOverTime && self.timeData.global > self.gameOverTime + 2e3 && !self.gameOverTuto && (!self.notEnoughDodoTuto || self.moneyTuto && !self.canRestart) }, extraRender: function(g) { StockManager.renderCountTag(g, self.currentWorld.index, self.currentLevel.index) }, needRefresh: !0 }), this.isLevelDone(this.currentLevel.id) ? ButtonUtils.render({ g: g, img: this.assetManager.getAtlasImage("gui.common.play"), id: "end-next", x: Math.round(g.width / 2) + 80 * app.scale, y: g.height - 20 * app.scale, align: ButtonUtils.ALIGN_LEFT, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { self.nextLevel() }, visibilityHandler: function() { return self.gameOverTime && self.timeData.global > self.gameOverTime + 2e3 && !self.gameOverTuto && (!self.notEnoughDodoTuto || self.moneyTuto && !self.canNext) }, extraRender: function(g) { self.currentLevel.index < self.currentWorld.levelList.length - 1 && StockManager.renderCountTag(g, self.currentWorld.index, self.currentLevel.index + 1) }, needRefresh: !0 }) : Money.isTutoDone() && Config.GENERAL.MONETIZATION && ButtonUtils.render({ g: g, img: this.assetManager.getAtlasImage("gui.game.unlock-level"), id: "end-unlock-next", x: Math.round(g.width / 2) + 80 * app.scale, y: g.height - 20 * app.scale, align: ButtonUtils.ALIGN_LEFT, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { self.nextLevel() }, visibilityHandler: function() { return self.gameOverTime && self.timeData.global > self.gameOverTime + 2e3 && !self.gameOverTuto && !self.notEnoughDodoTuto }, extraRender: function(g) { g.save(); var text = Utils.splitText(_2("unlock-level")); app.setBaseFont(g, 25, !0), g.fillStyle = App.BROWN_FILL_STYLE, g.strokeStyle = App.BROWN_STROKE_STYLE, g.translate(-25, 0), g.textAlign = "center", app.fillOutlineText(g, text[0].toUpperCase(), 0, -9), app.fillOutlineText(g, text[1].toUpperCase(), 0, 15), g.restore(), app.setBaseFont(g, 35), g.textAlign = "right", app.fillOutlineText(g, self.getUnlockCost(), -20, 60), g.save(), g.scale(.5, .5), self.money.render(g, -15, 55), g.restore(), self.currentLevel.index < self.currentWorld.levelList.length - 1 && (g.translate(40, 0), StockManager.renderCountTag(g, self.currentWorld.index, self.currentLevel.index + 1)) }, needRefresh: !0 }), !StockManager.visible && (this.gameOverTuto || this.notEnoughDodoTuto)) { if (g.fillStyle = "rgba(0, 0, 0, 0.75)", g.save(), g.resetTransform(), g.fillRect(0, 0, g.width, g.height), g.restore(), self.stockTuto) g.save(), g.resetTransform(), g.translate(g.width - Math.round(this.screenDecal / 2), 0), g.scale(app.scale, app.scale), this.renderStock(g), g.restore(); else if (!self.moneyTuto) { g.save(), won ? g.translate(0, -150) : g.translate(0, 450); var text = Utils.splitText(this.gameOverTuto ? _2("gameover-tuto") : _2("not-enough-dodo-tuto")); g.lineWidth = 2, g.fillRoundRect(-280, -40, 560, 35 * text.length + 30, 10), g.strokeStyle = "black", g.stroke(), app.setBaseFont(g, 35), g.textAlign = "center"; for (var i = 0; i < text.length; i++) app.fillOutlineText(g, text[i], 0, 35 * i); g.restore(), (this.gameOverTuto || !this.canRestart) && (g.save(), g.resetTransform(), g.translate(Math.round(g.width / 2), g.height - 20 * app.scale), g.scale(app.scale, app.scale), g.translate(0, -55), StockManager.renderCountTag(g, this.currentWorld.index, this.currentLevel.index), g.restore()), this.isLevelDone(this.currentLevel.id) && !this.canNext && this.currentLevel.index < this.currentWorld.levelList.length - 1 && (g.save(), g.resetTransform(), g.translate(Math.round(g.width / 2) + 80 * app.scale, g.height - 20 * app.scale), g.scale(app.scale, app.scale), g.translate(55, -55), StockManager.renderCountTag(g, this.currentWorld.index, this.currentLevel.index + 1), g.restore()) }!this.stockTuto && !this.moneyTuto && g.timeData.global > this.gameOverTime + 5e3 ? ButtonUtils.render({ g: g, img: this.assetManager.getAtlasImage("gui.common.ok"), id: "end-tuto-ok", x: Math.round(g.width / 2) + 270 * app.scale, y: g.height - 180 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_CENTER, scale: .8, listener: function() { self.gameOverTuto ? self.stockTuto = !0 : self.moneyTuto = !0 }, visibilityHandler: function() { return self.gameOverTime && (self.gameOverTuto || self.notEnoughDodoTuto) && !self.stockTuto }, needRefresh: !0 }) : this.moneyTuto && (this.canRestart || ButtonUtils.render({ g: g, img: this.assetManager.getAtlasImage("gui.common.restart"), id: "end-restart", x: Math.round(g.width / 2), y: g.height - 20 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, scale: .1 * Math.cycleSin(globalTime, 1e3) + 1, listener: function() { self.restartLevel() }, visibilityHandler: function() { return self.gameOverTime && self.timeData.global > self.gameOverTime + 2e3 && !self.gameOverTuto && (!self.notEnoughDodoTuto || self.moneyTuto && !self.canRestart) }, extraRender: function(g) { StockManager.renderCountTag(g, self.currentWorld.index, self.currentLevel.index) }, needRefresh: !0 }), this.isLevelDone(this.currentLevel.id) && !this.canNext && ButtonUtils.render({ g: g, img: this.assetManager.getAtlasImage("gui.common.play"), id: "end-next", x: Math.round(g.width / 2) + 80 * app.scale, y: g.height - 20 * app.scale, align: ButtonUtils.ALIGN_LEFT, valign: ButtonUtils.VALIGN_BOTTOM, scale: .1 * Math.cycleSin(globalTime, 1e3) + 1, listener: function() { self.nextLevel() }, visibilityHandler: function() { return self.gameOverTime && self.timeData.global > self.gameOverTime + 2e3 && !self.gameOverTuto && (!self.notEnoughDodoTuto || self.moneyTuto && !self.canNext) }, extraRender: function(g) { self.currentLevel.index < self.currentWorld.levelList.length - 1 && StockManager.renderCountTag(g, self.currentWorld.index, self.currentLevel.index + 1) }, needRefresh: !0 })) } } } g.restore() }, GameScreen.prototype.drawCachedText = function(graphics, id, text, fontSize, width, height, yDecal, otherFont) { var g; yDecal || (yDecal = 0), this.endScreenCache[id] ? text != this.endScreenCache[id].lastText && (g = this.endScreenCache[id].getContext("2d"), g.clearRect(-this.endScreenCache[id].width / 2, -this.endScreenCache[id].height + Math.floor(height / 9) + yDecal, this.endScreenCache[id].width, this.endScreenCache[id].height)) : (this.endScreenCache[id] = Utils.createCanvas(width, height), this.endScreenCache[id].lastText = !1, g = this.endScreenCache[id].getContext("2d"), otherFont ? this.app.setSecondaryFont(g, fontSize) : this.app.setBaseFont(g, fontSize), g.textAlign = "center", g.translate(this.endScreenCache[id].width / 2, this.endScreenCache[id].height - Math.floor(height / 9) - yDecal)), text != this.endScreenCache[id].lastText && (this.endScreenCache[id].lastText = text, this.app.fillShadowedOutlineText(g, text, 0, 0)), graphics.drawImage(this.endScreenCache[id], -this.endScreenCache[id].width / 2, -this.endScreenCache[id].height) }, GameScreen.prototype.renderFriendList = function(g) { return }; var LevelSelectScreen = function(app) { Screen.call(this, app, "level-select"), this.needRefresh = !0, this.hasLoaded = !1, this.hasInit = !1, this.assetManager = new AssetManager(app.assetManager), this.background = this.app.assetManager.getImage("gui.level-select.background"), this.spin = this.app.assetManager.getImage("gui.level-select.spin"), this.captionTransparent = this.app.assetManager.getAtlasImage("gui.common.caption-transparent"), this.backButton = this.app.assetManager.getAtlasImage("gui.common.back"), this.achievementButton = this.app.assetManager.getAtlasImage("gui.common.achievement"), this.starBig = this.app.assetManager.getAtlasImage("gui.common.star-big"), this.star = this.app.assetManager.getAtlasImage("gui.common.star"), this.dodoCountIcon = this.app.assetManager.getAtlasImage("gui.common.dodo-count"), this.dodoCountIconWidth = Math.round(this.dodoCountIcon.width / 2), this.dodoCountIconHeight = this.dodoCountIcon.height, this.treasureIcon = this.app.assetManager.getAtlasImage("gui.common.treasure-icon"), this.treasureIconWidth = Math.round(this.treasureIcon.width / 2), this.treasureIconHeight = this.treasureIcon.height, this.infinite = this.app.assetManager.getAtlasImage("gui.stock.infinite"), this.darkCaption = this.app.assetManager.getAtlasImage("gui.common.caption-dark"), this.locker = this.app.assetManager.getAtlasImage("gui.common.locker"), this.money = this.app.assetManager.getAtlasImage("gui.common.money"), this.levelTitle = [], this.levelDecoration = {} }; LevelSelectScreen.prototype = new Screen, LevelSelectScreen.prototype.createCarousel = function() { var self = this; this.worldCarousel = new Carousel(this.app.assetManager, { dataList: DataStore.worldList, callback: function(index) { self.loadWorld(index) }, itemPaintHandler: function(g, index) { self.paintWorld(g, index) }, elmSize: 2700 }), this.currentCarousel = this.worldCarousel, this.loadedWorldIndex = 0, this.levelCarousel = new Carousel(this.app.assetManager, { dataList: DataStore.worldList[0].levelList, callback: function(index) { self.loadLevel(index) }, itemPaintHandler: function(g, index) { self.paintLevel(g, index) }, paintHandler: function(g) { self.paintLevelDecoration(g) }, elmSize: 1600 }), this.refreshData() }, LevelSelectScreen.prototype.back = function() { this.loadedWorld ? (this.loadedWorld = !1, this.levelCarousel.setEnabled(!1), this.worldCarousel.setEnabled(!0), this.currentCarousel = this.worldCarousel) : (this.worldCarousel.setEnabled(!1), this.currentCarousel = !1, this.app.startScreen.show()) }, LevelSelectScreen.prototype.loadWorld = function(index) { var self = this, world = DataStore.worldList[index]; if (world.locked) world.index > 0 && !DataStore.worldList[world.index - 1].locked && Config.GENERAL.MONETIZATION && Money.spend(world.cost) && (setStoredBool("world-unlocked-" + world.id, !0), this.refreshData()); else { this.loadedWorld = world, this.worldCarousel.setEnabled(!1), this.loadedWorldIndex = index, this.levelCarousel.dataList = this.loadedWorld.levelList, this.enabledLevelIndex = 0; for (var enabledIndexFound = !1, i = 0; i < DataStore.worldList[this.loadedWorldIndex].levelList.length; i++) { var level = DataStore.worldList[this.loadedWorldIndex].levelList[i]; enabledIndexFound || (self.app.gameScreen.isLevelDone(level.id) ? this.enabledLevelIndex = i + 1 : enabledIndexFound = !0) } var selectLevel = this.enabledLevelIndex; if (selectLevel == DataStore.worldList[this.loadedWorldIndex].levelList.length) for (var i = 0; i < DataStore.worldList[this.loadedWorldIndex].levelList.length; i++) { var level = DataStore.worldList[this.loadedWorldIndex].levelList[i]; if (getStoredInt("stars-" + level.id) < 3) { selectLevel = i; break } } this.levelCarousel.setEnabled(!0), this.currentCarousel = this.levelCarousel, this.assetManager.getSound("world-tap-" + DataStore.worldList[this.loadedWorldIndex].graphic_template).reset().play(), this.levelCarousel.currentIndex != selectLevel && this.levelCarousel.selectElm(selectLevel) } }, LevelSelectScreen.prototype.loadLevel = function(index) { var self = this; (0 == index || index <= this.enabledLevelIndex) && StockManager.checkAvailable(this.loadedWorldIndex, index, function() { self.loadLevel(index) }) && (this.levelCarousel.setEnabled(!1), this.app.music.pause(), this.app.gameScreen.startSoundPlaying = !0, this.app.assetManager.getSound("start").play(function() { self.app.gameScreen.startSoundPlaying = !1 }), this.app.gameScreen.loadLevel(this.loadedWorld, this.loadedWorld.levelList[index])) }, LevelSelectScreen.prototype.show = function() { var self = this; this.hasInit ? this._show() : this.init(function() { self._show() }) }, LevelSelectScreen.prototype._show = function() { if (this.needRefresh && this.refreshData(!0), Screen.prototype.show.call(this), this.loadedWorld) this.levelCarousel.setEnabled(!0), this.currentCarousel = this.levelCarousel; else { this.worldCarousel.setEnabled(!0), this.currentCarousel = this.worldCarousel; for (var i = DataStore.worldList.length - 1; i >= 0; i--) if (!DataStore.worldList[i].locked) { this.worldCarousel.currentIndex != i && this.worldCarousel.selectElm(i); break } } this.app.showBanner() }, LevelSelectScreen.prototype.refreshData = function(force) { if (this.worldCarousel && (force || this.visible)) { this.totalStarCount = 0; for (var i = 0; i < DataStore.worldList.length; i++) for (var world = DataStore.worldList[i], j = 0; j < world.levelList.length; j++) this.totalStarCount += getStoredInt("stars-" + world.levelList[j].id, 0); for (var i in DataStore.worldList) { var world = DataStore.worldList[i]; world.locked = this.totalStarCount < world.required_stars && !getStoredBool("world-unlocked-" + world.id, !1), this.refreshWorldIcon(i) } this.enabledLevelIndex = 0; for (var enabledIndexFound = !1, i = 0; i < DataStore.worldList[this.loadedWorldIndex].levelList.length; i++) { var level = DataStore.worldList[this.loadedWorldIndex].levelList[i]; enabledIndexFound || (this.app.gameScreen.isLevelDone(level.id) ? this.enabledLevelIndex = i + 1 : enabledIndexFound = !0) } this.worldCarousel.refreshData(), this.levelCarousel.refreshData(), this.needRefresh = !1 } else this.needRefresh = !0 }, LevelSelectScreen.MIN_LEVEL_COUNT = 25, LevelSelectScreen.prototype.init = function(cb) { var self = this; if (this.hasLoaded) self._init(); else { for (var i in DataStore.graphicTemplateList) { var w = DataStore.graphicTemplateList[i]; this.assetManager.addImage("world-icon-" + w.id, WEB_DATA_URI + "img/world/icon-" + w.id + ".png"), this.assetManager.addImage("world-level-icon-" + w.id, WEB_DATA_URI + "img/world/level-icon-" + w.id + ".png"), this.assetManager.addSound("world-tap-" + w.id, WEB_DATA_URI + "sound/world/tap-" + w.id + AssetManager.SOUND_FILE_FORMAT) } this.assetManager.addLoadingListener(function() { self.hasLoaded = !0, self._init(), cb && cb() }), this.assetManager.startLoading() } }, LevelSelectScreen.prototype._init = function() { this.levelIconWidth = 310, this.levelIconHeight = 450, this.levelIconCenterX = -Math.round(this.levelIconWidth / 2), this.levelIconCenterY = -Math.round(this.levelIconHeight / 2); for (var i in DataStore.worldList) for (var world = DataStore.worldList[i], j = 0; 4 >= j; j++) { var canvas = Utils.createCanvas(); canvas.width = this.levelIconWidth, canvas.height = this.levelIconHeight; var g = canvas.getContext("2d"); g.width = canvas.width, g.height = canvas.height, g.translate(Math.round(g.width / 2), Math.round(g.height / 2)); var img = this.assetManager.getImage("world-level-icon-" + world.graphic_template); g.drawImage(img, -Math.round(img.width / 2), -Math.round(img.height / 2)), 4 == j ? (this.locker.render(g, -Math.round(this.locker.width / 2), -Math.round(this.locker.height / 2)), world.levelIconLocked = canvas) : (this.starBig.render(g, j > 1 ? Math.round(this.starBig.width / 2) : 0, 0, Math.round(this.starBig.width / 2), this.starBig.height, -Math.round(this.starBig.width / 4), 80, Math.round(this.starBig.width / 2), this.starBig.height), g.save(), g.scale(.7, .7), this.starBig.render(g, j > 0 ? Math.round(this.starBig.width / 2) : 0, 0, Math.round(this.starBig.width / 2), this.starBig.height, -60 - Math.round(this.starBig.width / 2), 150, Math.round(this.starBig.width / 2), this.starBig.height), this.starBig.render(g, j > 2 ? Math.round(this.starBig.width / 2) : 0, 0, Math.round(this.starBig.width / 2), this.starBig.height, 60, 150, Math.round(this.starBig.width / 2), this.starBig.height), g.restore(), world["levelIcon" + j] = canvas) } for (var i = 0; i < LevelSelectScreen.MIN_LEVEL_COUNT; i++) { var c = Utils.createCanvas(); .1 > i + 1 ? (c.width = 128, c.height = 128) : (c.width = 256, c.height = 128); var g = c.getContext("2d"), title = parseInt(i) + 1; g.lineJoin = "round", g.font = "175px brlnsr", g.lineWidth = 6, g.textAlign = "center", g.translate(c.width / 2, c.height - 19), g.fillStyle = "rgba(0, 0, 0, 0.6)", g.fillText(title, -7, 7), g.fillStyle = "#FEFDF9", g.strokeStyle = "#361C05", g.strokeText(" " + title + " ", 0, 0), g.fillText(title, 0, 0), this.levelTitle[i] = c } this.hasInit = !0, this.createCarousel(), this.onResize(), this.refreshData(!0) }, LevelSelectScreen.prototype.renderDodoCountIcon = function(g, id, x, y) { this.dodoCountIcon.render(g, this.dodoCountIconWidth * id, 0, this.dodoCountIconWidth, this.dodoCountIconHeight, x, y, this.dodoCountIconWidth, this.dodoCountIconHeight) }, LevelSelectScreen.prototype.renderTreasureIcon = function(g, id, x, y) { this.treasureIcon.render(g, this.treasureIconWidth * id, 0, this.treasureIconWidth, this.treasureIconHeight, x, y, this.treasureIconWidth, this.treasureIconHeight) }, LevelSelectScreen.prototype.paintLevelDecoration = function(g) { if (g.save(), g.translate(-256, -290), this.loadedWorld) { var levelIndex = this.levelCarousel.getNearestIndex(), level = this.loadedWorld.levelList[levelIndex], levelGoalType = this.app.gameScreen.getLevelGoalType(level), goalType = this.app.gameScreen.getLevelGoalType(level); if (!this.levelDecoration[goalType]) { var c = Utils.createCanvas(); c.width = 512, c.height = 128; var g2 = c.getContext("2d"); g2.translate(c.width / 2, c.height / 2), g2.scale(.8, .8), this.captionTransparent.render(g2, -Math.round(this.captionTransparent.width) / 2, -Math.round(this.captionTransparent.height / 2)), app.setBaseFont(g2, 32), g2.textAlign = "center"; var text = Utils.splitText(getDBText("goal_type", "description", goalType)); text.length > 1 ? (app.fillOutlineText(g2, text[0], 0, -5), app.fillOutlineText(g2, text[1], 0, 25)) : app.fillOutlineText(g2, text[0], 0, 10); var pos = 0; this.app.gameScreen.renderGoalType(g2, levelGoalType, -260, -Math.round(this.app.gameScreen.goalTypeHeight / 2)), this.levelDecoration[goalType] = c } g.drawImage(this.levelDecoration[goalType], 0, 0), g.translate(this.levelDecoration[goalType].width / 2, this.levelDecoration[goalType].height / 2), g.save(), g.scale(1.1, 1.1), pos = 0; var dodoCount = StockManager.getLevelDodoCount(this.loadedWorldIndex, levelIndex), dodoCountId = 0; if ((StockManager.getAmount() >= dodoCount || StockManager.isInfinite()) && (dodoCountId = 1), this.renderDodoCountIcon(g, dodoCountId, 135, -Math.round(this.dodoCountIconHeight / 2)), StockManager.isInfinite() ? (g.save(), g.scale(.6, .6), this.infinite.render(g, 246, -Math.round(this.infinite.height / 2)), g.restore()) : (g.font = "55px brlnsr", g.strokeStyle = "#361C05", g.lineWidth = 7, g.textAlign = "center", g.fillStyle = "rgba(0, 0, 0, 0.5)", g.fillText(dodoCount, 173, 19), g.fillStyle = "#FEFDF9", g.strokeText(" " + dodoCount + " ", 178, 14), g.fillText(dodoCount, 178, 14)), level.bonus) { (Date.now() - this.levelCarousel.lastSelectionTime) / 250, g.save(); var bonusId = 0; 3 == getStoredInt("stars-" + level.id) && (bonusId = 1), this.renderTreasureIcon(g, bonusId, 230, -55), g.restore() } if (g.restore(), levelIndex <= this.enabledLevelIndex) { g.translate(0, 75), g.lineJoin = "round", app.setSecondaryFont(g, 36), g.textAlign = "center", app.fillShadowedOutlineText(g, _2("score"), 0, 0); var score = getStoredInt("score-" + level.id); g.translate(0, 50), app.setBaseFont(g, 64), app.fillShadowedOutlineText(g, score, 0, 0, "#FFC946") } } g.restore() }, LevelSelectScreen.prototype.paintLevel = function(g, index) { var world = DataStore.worldList[this.loadedWorldIndex], locked = index > this.enabledLevelIndex, level = world.levelList[index], levelGoalType = this.app.gameScreen.getLevelGoalType(level); if (g.translate(0, 40), locked) g.drawImage(world.levelIconLocked, this.levelIconCenterX, this.levelIconCenterY); else { if (g.drawImage(world["levelIcon" + getStoredInt("stars-" + level.id, 0)], this.levelIconCenterX, this.levelIconCenterY), level.isTuto) { if (g.save(), !this.trainingCanvas) { this.trainingCanvas = Utils.createCanvas(256, 32); var g2 = this.trainingCanvas.getContext("2d"); app.setSecondaryFont(g2, 26), g2.textAlign = "center", g2.strokeStyle = App.BROWN_FILL_STYLE, app.fillOutlineText(g2, _2("training"), this.trainingCanvas.width / 2, this.trainingCanvas.height - 5) } g.drawImage(this.trainingCanvas, -this.trainingCanvas.width / 2, 45), g.restore() } g.drawImage(this.levelTitle[index], -this.levelTitle[index].width / 2, -75) } var goalTypeId = !1; for (var i in GoalType) if (GoalType[i] == levelGoalType && "SAVE" != i) { goalTypeId = levelGoalType; break } if (goalTypeId !== !1 || level.bonus) { var f = (Date.now() - this.levelCarousel.lastSelectionTime) / 250; if (index != this.levelCarousel.currentIndex || 1 > f && this.levelCarousel.lastIndex != index) { if (g.save(), 1 > f && (index == this.levelCarousel.lastIndex || index == this.levelCarousel.currentIndex) && (index == this.levelCarousel.currentIndex && (f = 1 - f), g.globalAlpha = Math.easeOutQuad(f)), level.bonus) { var bonusId = 0; 3 == getStoredInt("stars-" + level.id) && (bonusId = 1), this.renderTreasureIcon(g, bonusId, 45, -180) } goalTypeId !== !1 && this.app.gameScreen.renderGoalType(g, levelGoalType, -Math.round(this.app.gameScreen.goalTypeWidth / 2), -200), g.restore() } } }, LevelSelectScreen.prototype.paintWorld = function(g, index) { var img = DataStore.worldList[index].iconCanvas; g.drawImage(img, -Math.round(img.width / 2), Math.round(-img.height / 2)) }, LevelSelectScreen.prototype.refreshWorldIcon = function(index) { var canvas, g, world = DataStore.worldList[index]; DataStore.worldList[index].iconCanvas ? (canvas = DataStore.worldList[index].iconCanvas, g = canvas.getContext("2d"), g.width = canvas.width, g.height = canvas.height, g.clearRect(0, 0, g.width, g.height)) : (canvas = Utils.createCanvas(), canvas.width = 512, canvas.height = 512, g = canvas.getContext("2d"), g.width = canvas.width, g.height = canvas.height), g.save(), g.translate(Math.round(g.width / 2), Math.round(g.height / 2) + 5); var img = this.assetManager.getImage("world-icon-" + world.graphic_template); if (g.drawImage(img, -Math.round(img.width / 2), -Math.round(img.height / 2)), world.locked) { if (this.locker.render(g, -Math.round(this.locker.width / 2), -Math.round(this.locker.height / 2)), world.index > 0 && !DataStore.worldList[world.index - 1].locked) { g.fillStyle = "rgba(0, 0, 0, 0.6)", g.fillRoundRect(-190, 100, 380, 130, 20); var text = Utils.splitText(_2("remaining-stars-label")); g.font = "28px brlnsr", g.fillStyle = "#FEFDF9", g.strokeStyle = "#361C05", g.lineWidth = 4, g.textAlign = "center"; for (var i = 0; i < text.length; i++) { g.font = "28px brlnsr", g.textAlign = "center"; var pos = !1, stars = !1, money = !1, textX = 0, textY = 140 + 37 * i; if (text[i].search(":stars") >= 0 ? (text[i] = text[i].replace(":stars", ""), pos = Math.round(g.measureText(text[i]).width / 2), textX = -30, stars = !0) : text[i].search(":money") >= 0 && (text[i] = text[i].replace(":money", ""), pos = Math.round(g.measureText(text[i]).width / 2), textX = -30, money = !0), g.strokeText(text[i], textX, textY), g.fillText(text[i], textX, textY), stars || money) { g.font = "40px brlnsr", g.textAlign = "left"; var value = ""; stars ? (value = world.required_stars - this.totalStarCount, this.star.render(g, Math.round(this.star.width / 2), 0, Math.round(this.star.width / 2), this.star.height, pos + g.measureText(value).width - 21, textY - this.star.height + 3, Math.round(this.star.width / 2), this.star.height)) : (value = world.cost, g.save(), g.translate(pos + g.measureText(value).width - 20, textY - this.money.height + 17), g.scale(.42, .42), this.money.render(g, 0, this.money.height), g.restore()), g.strokeText(value, pos - 25, textY), g.fillText(value, pos - 25, textY) } } } } else { g.save(), g.translate(0, -10), g.scale(1.1, 1.1), this.darkCaption.render(g, -187, 165), this.darkCaption.render(g, 45, 165), g.save(), g.scale(.7, .7), this.starBig.render(g, Math.round(this.starBig.width / 2), 0, Math.round(this.starBig.width / 2), this.starBig.height, 20, 225, Math.round(this.starBig.width / 2), this.starBig.height), g.restore(), g.font = "26px edson_comics", g.fillStyle = "#FEFDF9", g.strokeStyle = "#361C05", g.lineWidth = 4, g.strokeText(_2("score"), -180, 165), g.fillText(_2("score"), -180, 165); for (var score = 0, starCount = 0, j = 0; j < world.levelList.length; j++) { var levelId = world.levelList[j].id; score += getStoredInt("score-" + levelId, 0), starCount += getStoredInt("stars-" + levelId, 0) } g.font = "30px brlnsr", g.fillStyle = "#FDBC2C", g.textAlign = "center", g.strokeText(score, -120, 197), g.fillText(score, -120, 197), g.strokeText(starCount + "/" + 3 * world.levelList.length, 120, 197), g.fillText(starCount + "/" + 3 * world.levelList.length, 120, 197), g.restore() } g.translate(0, -205); var title = world.order + ". " + getDBText("world", "name", world.id); app.setSecondaryFont(g, 70), g.textAlign = "center", app.fillShadowedOutlineText(g, title), g.restore(), DataStore.worldList[index].iconCanvas = canvas }, LevelSelectScreen.prototype.onMouseDown = function(x, y) { !this.currentCarousel || StockManager.visible || Money.visible || this.currentCarousel.onMouseDown(x, y) }, LevelSelectScreen.prototype.onMouseUp = function(x, y) { !this.currentCarousel || StockManager.visible || Money.visible || this.currentCarousel.onMouseUp(x, y) }, LevelSelectScreen.prototype.onMouseMove = function(x, y) { !this.currentCarousel || StockManager.visible || Money.visible || this.currentCarousel.onMouseMove(x, y) }, LevelSelectScreen.prototype.onResize = function() { Screen.prototype.onResize.call(this), this.worldCarousel.onResize(), this.levelCarousel.onResize() }, LevelSelectScreen.prototype.render = function(g) { var self = this; if (StockManager.visible || Money.visible || (this.needRefresh = !0), this.needRefresh) { this.currentCarousel.needRefresh = !0, g.save(), g.translate(Math.round(g.width / 2), 0), g.scale(app.scale, app.scale), g.drawImage(this.background, 0, 0, this.background.width, this.background.height, -Math.round(App.BASE_MAX_WIDTH / 2), 0, App.BASE_MAX_WIDTH, App.BASE_HEIGHT), g.save(), g.translate(0, Math.round(App.BASE_HEIGHT / 2)); var f = Math.cycleSin(g.timeData.global, 3e3), s = 1 + .3 * f; g.globalAlpha = 1 - .5 * f, g.scale(s, s), g.rotate(2 * Math.PI * (g.timeData.global % 2e3) / 2e3), g.drawImage(this.spin, -this.spin.width / 2, -this.spin.height / 2), g.restore(), this.currentCarousel == this.levelCarousel && (app.setSecondaryFont(g, 80), g.textAlign = "center", app.fillShadowedOutlineText(g, this.loadedWorld.order + ". " + getDBText("world", "name", this.loadedWorld.id), 0, 90)), g.restore(), this.currentCarousel.render(g) } this.renderMoney(g), this.renderStock(g), ButtonUtils.render({ g: g, img: this.backButton, id: "back", x: 90 * app.scale, y: g.height - Math.round(10 * app.scale), align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { self.back() }, needRefresh: this.needRefresh }), ButtonUtils.render({ g: g, img: this.achievementButton, id: "achievement", x: g.width - 90 * app.scale, y: g.height - Math.round(10 * app.scale), align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { app.achievementScreen.show() }, needRefresh: this.needRefresh }), this.needRefresh = !1 }, LevelSelectScreen.prototype.renderMoney = function(g) { !Money.visible && (this.needRefresh || this.currentCarousel.needRefresh || Input.needRefresh("money")) && (g.save(), g.scale(app.scale, app.scale), g.translate(20, 20), Config.GENERAL.MONETIZATION && Input.addCollider("money", 20 * app.scale, 20 * app.scale, Money.background.width * app.scale, Money.background.height * app.scale, function() { Money.openPopup() }), Money.render(g, Input.isActive("money")), Input.setRefreshed("money"), g.restore()) }, LevelSelectScreen.prototype.renderStock = function(g) { (this.needRefresh || this.currentCarousel.needRefresh || Input.needRefresh("stock") || StockManager.hasWarning()) && (g.save(), g.translate(g.width, 0), g.scale(app.scale, app.scale), g.translate(-StockManager.background.width - 20, 20), Input.addCollider("stock", g.width - (StockManager.background.width + 20) * app.scale, 20 * app.scale, StockManager.background.width * app.scale, StockManager.background.height * app.scale, function() { StockManager.openPopup() }), StockManager.render(g, Input.isActive("stock")), Input.setRefreshed("stock"), g.restore()) }; var LoadingScreen = function(app) { Screen.call(this, app, "loading"), this.splash = this.assetManager.getImage("gui.loading.splash"), this.background = this.assetManager.getImage("gui.loading.background"), this.progressBackground = this.assetManager.getAtlasImage("gui.achievement.progress-background"), this.progressIndicator = this.assetManager.getAtlasImage("gui.achievement.progress-indicator") }; LoadingScreen.prototype = new Screen, LoadingScreen.SPLASH_FADE_DURATION = 500, LoadingScreen.getLoadingList = function(imageList) { var list = {}; list["gui.loading.splash"] = imageList["gui.loading.splash"], list["gui.loading.background"] = imageList["gui.loading.background"]; for (var i = 0; ATLAS_COUNT > i; i++) list["atlas" + i] = imageList["atlas" + i]; return list }, LoadingScreen.prototype.getSplashEndTime = function() { return this.endSplashTime ? this.endSplashTime + 2.5 * LoadingScreen.SPLASH_FADE_DURATION : Config.GENERAL.SPLASH_DURATION + 2.5 * LoadingScreen.SPLASH_FADE_DURATION }, LoadingScreen.prototype.onMouseDown = function() { console.log("oki"), this.endSplashTime || (this.endSplashTime = this.app.timeData.appLocal) }, LoadingScreen.prototype.render = function(g) { if (g.save(), g.fillStyle = "black", g.textAlign = "left", app.setBaseFont(g, 20), app.fillOutlineText(g, "test", 0, 10), app.setThirdFont(g, 20), app.fillOutlineText(g, "test", 0, 20), g.fillStyle = "black", g.fillRect(0, 0, g.width, g.height), g.translate(Math.round(g.width / 2), 0), g.scale(app.scale, app.scale), !this.endSplashTime && g.timeData.appLocal > Config.GENERAL.SPLASH_DURATION && (this.endSplashTime = g.timeData.appLocal), !this.endSplashTime || g.timeData.appLocal < this.endSplashTime + LoadingScreen.SPLASH_FADE_DURATION) this.endSplashTime && (g.globalAlpha = Math.easeOutSine(1 - (g.timeData.appLocal - this.endSplashTime) / LoadingScreen.SPLASH_FADE_DURATION)), g.drawImage(this.splash, 0, 0, this.splash.width, this.splash.height, -Math.round(App.BASE_MAX_WIDTH / 2), 0, App.BASE_MAX_WIDTH, App.BASE_HEIGHT), g.globalAlpha = 1; else { g.timeData.appLocal < this.endSplashTime + 2 * LoadingScreen.SPLASH_FADE_DURATION && (g.globalAlpha = Math.easeOutSine((g.timeData.appLocal - this.endSplashTime - LoadingScreen.SPLASH_FADE_DURATION) / LoadingScreen.SPLASH_FADE_DURATION)), g.drawImage(this.background, 0, 0, this.background.width, this.background.height, -Math.round(App.BASE_MAX_WIDTH / 2), 0, App.BASE_MAX_WIDTH, App.BASE_HEIGHT), app.setSecondaryFont(g, 45), g.textAlign = "center", app.fillOutlineText(g, _2("loading", "Chargement..."), 0, Math.round(g.height / app.scale) - 60), this.progressBackground.render(g, -Math.round(this.progressBackground.width / 2), Math.round(g.height / app.scale) - 45); var w = Math.round(app.assetManager.getLoadingProgress() * this.progressIndicator.width); this.progressIndicator.render(g, 0, 0, w, this.progressIndicator.height, -Math.round(this.progressIndicator.width / 2), Math.round(g.height / app.scale) - 45, w, this.progressIndicator.height), g.globalAlpha = 1 } g.restore() }; var Money = { ENTRY_HEIGHT: 86, NO_ADS_STORE_ID: "com.3dduo.savethedodos.removeads", storeLoaded: !1, init: function() { this.popupBackground = app.assetManager.getImage("gui.money.background"), this.background = Config.GENERAL.MONETIZATION ? app.assetManager.getAtlasImage("gui.common.money-life-background") : app.assetManager.getAtlasImage("gui.common.caption-light"), this.icon = app.assetManager.getAtlasImage("gui.common.money"), this.plus = app.assetManager.getAtlasImage("gui.common.money-plus"), getStoredBool("start-money-received") || (this.add(Config.GENERAL.START_MONEY), setStoredBool("start-money-received", !0)), this.isLoading = !1, this.firstOpen = !0, this.loadStoreData(), this.refresh() }, onResize: function() { this.needRefresh = !0 }, openPopup: function(closeHandler) { app.hideBanner(), this.isTuto = !1, this.closeHandler = closeHandler, app.assetManager.getSound("menu.money").reset().play(), this.visible = !0, this.needRefresh = !0, this.firstOpen && (this.firstOpen = !1, Cocoon.Store.restore()) }, buy: function(packIndex) { var pack = DataStore.moneyPackList[packIndex]; Cocoon.Store.nativeAvailable ? navigator.onLine ? Cocoon.Store.getStoreType() == Cocoon.Store.StoreType.APP_STORE && (this.isLoading = !0, Cocoon.Store.purchase(pack.appstore_id)) : alert(_2("game-offline-error")) : this.applyBuy(pack, !1) }, applyBuy: function(pack, fromStore) { fromStore && DataSync.logPayment(pack), this.add(pack.total); var buyHandler = this.buyHandler; this.closePopup(), buyHandler && this.spend(this.buyValue, buyHandler) }, closePopup: function() { this.visible = !1, app.currentScreen.needRefresh = !0, StockManager.visible ? StockManager.needRefresh = !0 : app.currentScreen == app.levelSelectScreen && app.showBanner(), this.closeHandler && (this.closeHandler(), this.closeHandler = !1), this.buyHandler = !1 }, refresh: function() { this.needRefresh = !0 }, getAmount: function() { return getStoredInt("money") }, spend: function(value, handler) { var amount = this.getAmount() - value; return 0 > amount ? (this.buyValue = value, this.buyHandler = handler, this.openPopup(), app.assetManager.getSound("menu.money").play(), !1) : (setStoredInt("money", amount), this.refresh(), handler && handler(), !0) }, startTuto: function(value, handler) { this.buyValue = value, this.buyHandler = handler, this.openPopup(), this.isTuto = !0, app.assetManager.getSound("menu.money").play() }, resetTuto: function() { setStoredBool("money-tuto", !1) }, setTutoDone: function() { setStoredBool("money-tuto", !0) }, endTuto: function() { var buyHandler = this.buyHandler; this.closePopup(), buyHandler(), this.setTutoDone() }, add: function(value) { setStoredInt("money", this.getAmount() + value), this.refresh() }, render: function(g, isActive) { Config.GENERAL.MONETIZATION ? this.background.render(g, 0, 0) : (g.save(), g.scale(1.3, 1.3), this.background.render(g, 30, 17), g.restore()), this.icon.render(g, 0, 15), Config.GENERAL.MONETIZATION && this.plus.render(g, isActive ? this.plus.width / 2 : 0, 0, this.plus.width / 2, this.plus.height, 175, 8, this.plus.width / 2, this.plus.height), app.setBaseFont(g, 45), g.translate(125, 70), g.textAlign = "center", app.fillOutlineText(g, this.getAmount(), 0, 0) }, renderPopup: function(g) { var self = this; g.save(), this.needRefresh && (Input.startPopup(), g.translate(Math.round(g.width / 2), 0), g.scale(app.scale, app.scale), this.cache && this.cacheLocale == Gettext.locale || this.createCache(), g.drawImage(this.cache, -Math.round(this.cache.width / 2), 0)), app.setBaseFont(g, 39), g.textAlign = "center", g.textBaseline = "middle", g.save(); for (var i = 0; i < DataStore.moneyPackList.length; i++) { var p = DataStore.moneyPackList[i]; p.index = i, ButtonUtils.render({ g: g, img: app.assetManager.getAtlasImage("gui.money.buy-button"), id: "money-buy-" + p.id, x: Math.round(g.width / 2 + 290 * app.scale), y: 170 * app.scale + this.ENTRY_HEIGHT * i * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_MIDDLE, listener: function(index) { return function() { self.buy(index) } }(i), changeListener: function() { self.needRefresh = !0 }, visibilityHandler: function() { return !self.isTuto && self.visible && !self.isLoading }, scale: .8, extraRender: function(g) { g.save(), g.translate(-4, -2), app.fillOutlineText(g, p.localizedCost ? p.localizedCost : p.cost + "€", 0, 0), g.restore() }, needRefresh: this.needRefresh }) } if (g.restore(), this.isTuto && this.needRefresh) { g.fillStyle = "rgba(0, 0, 0, 0.75)", g.fillRect(-368, 122, 740, 433); var x = 410, y = 570, w = 130, h = 60, sx = this.popupBackground.width / App.BASE_MAX_WIDTH, sy = this.popupBackground.height / App.BASE_HEIGHT; g.drawImage(this.popupBackground, x * sx, y * sy, w * sx, h * sy, x - Math.round(App.BASE_MAX_WIDTH / 2), y, w, h), app.setBaseFont(g, 45), g.save(), g.translate(0, 170 + this.ENTRY_HEIGHT * (DataStore.moneyPackList.length - 1)), app.fillOutlineText(g, this.buyValue, -200, 0), g.restore(), app.setBaseFont(g, 30), ButtonUtils.render({ g: g, img: app.assetManager.getAtlasImage("gui.money.buy-button"), id: "money-buy-fake", x: Math.round(g.width / 2 + 290 * app.scale), y: 170 * app.scale + this.ENTRY_HEIGHT * (DataStore.moneyPackList.length - 1) * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_MIDDLE, scale: .1 * Math.cycleSin(g.timeData.global, 1e3) + .8, listener: function() { self.endTuto() }, changeListener: function() { self.needRefresh = !0 }, visibilityHandler: function() { return self.isTuto && self.visible && !self.isLoading }, extraRender: function(g) { app.fillOutlineText(g, _2("free"), 0, 0) }, needRefresh: !0 }) } if (this.isTuto || ButtonUtils.render({ g: g, img: app.assetManager.getAtlasImage("gui.common.back"), id: "money-back", x: Math.round(g.width / 2 - 450 * app.scale), y: g.height, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { self.closePopup() }, visibilityHandler: function() { return !self.isTuto && self.visible && !self.isLoading }, background: this.popupBackground, backgroundX: g.width / 2 - Math.round(App.BASE_MAX_WIDTH * app.scale / 2), backgroundY: 0, backgroundWidth: App.BASE_MAX_WIDTH, backgroundHeight: App.BASE_HEIGHT, needRefresh: this.needRefresh, scale: .8 }), g.restore(), this.isLoading) { g.save(), g.resetTransform(), g.fillStyle = "rgba(0, 0, 0, 0.66)", g.fillRect(0, 0, g.width, g.height), g.translate(Math.round(g.width / 2), Math.round(g.height / 2)), g.scale(app.scale, app.scale), g.rotate(2 * Math.PI * (g.timeData.global % 1e3) / 1e3); var icon = app.assetManager.getAtlasImage("gui.loading.icon"); icon.render(g, -Math.round(icon.width / 2) + 1, -Math.round(icon.height / 2) + 1), g.restore() } this.needRefresh && (this.needRefresh = this.isTuto || this.isLoading, Input.endPopup()) }, isTutoDone: function() { return getStoredBool("money-tuto") }, createCache: function() { var canvas = Utils.createCanvas(); canvas.width = App.BASE_MAX_WIDTH, canvas.height = App.BASE_HEIGHT; var g = canvas.getContext("2d"); g.width = canvas.width, g.height = canvas.height, g.drawImage(this.popupBackground, 0, 0, this.popupBackground.width, this.popupBackground.height, 0, 0, g.width, g.height), g.translate(Math.round(canvas.width / 2), 0), g.save(), app.setSecondaryFont(g, 60), g.textAlign = "center", g.textBaseline = "middle", app.fillOutlineText(g, _2("money-popup-title"), 0, 58), g.translate(0, 170); for (var i = 0; i < DataStore.moneyPackList.length; i++) { var p = DataStore.moneyPackList[i], icon = app.assetManager.getAtlasImage("gui.money.pack-" + i); if (icon.render(g, -310 - Math.round(icon.width / 2), 0 - Math.round(icon.height / 2)), app.setBaseFont(g, 45), app.fillOutlineText(g, p.total, -200, 0), p.popular) { var arrow = app.assetManager.getAtlasImage("gui.money.purple-arrow"); arrow.render(g, -495, -Math.round(arrow.height / 2)), app.setBaseFont(g, 18); var text = Utils.splitText(_2("popular")); app.fillOutlineText(g, text[0].toUpperCase(), -440, -14), text.length > 1 && app.fillOutlineText(g, text[1].toUpperCase(), -440, 8) } if (p.bestOffer) { var arrow = app.assetManager.getAtlasImage("gui.money.yellow-arrow"); arrow.render(g, -495, -Math.round(arrow.height / 2)), app.setBaseFont(g, 18); var text = Utils.splitText(_2("best-offer")); app.fillOutlineText(g, text[0].toUpperCase(), -440, -14), text.length > 1 && app.fillOutlineText(g, text[1].toUpperCase(), -440, 8) } 0 == i ? (app.setThirdFont(g, 50), g.fillStyle = "#fee74c", g.strokeStyle = "#984a00") : 3 > i ? app.setThirdFont(g, 45) : (app.setThirdFont(g, 40), g.fillStyle = "#ffd28e"), g.save(), g.rotate(.15 * (Math.random() - .5)), app.fillOutlineText(g, p.bonus ? _2("money-pack-bonus").replace("%bonus%", p.bonus) : _2("money-pack-no-bonus"), 45, 0), g.restore(), g.translate(0, this.ENTRY_HEIGHT) } g.restore(), g.save(), app.setBaseFont(g, 25), g.textAlign = "center", g.textBaseline = "middle"; var text = Utils.splitText(_2("secured-payment")); app.fillOutlineText(g, text[0].toUpperCase(), 425, g.height - 58), text.length > 1 && app.fillOutlineText(g, text[1].toUpperCase(), 425, g.height - 30), g.restore(), this.cache && this.cache.dispose(), this.cache = canvas, this.cacheLocale = Gettext.locale }, checkNoAds: function() { getStoredBool("no-ads") || !Cocoon.Store.nativeAvailable || navigator.onLine || Cocoon.Store.getStoreType() != Cocoon.Store.StoreType.APP_STORE || Cocoon.Store.isProductPurchased(self.NO_ADS_STORE_ID) && (setStoredBool("no-ads", !0), app.startScreen.needRefresh = !0) }, loadStoreData: function() { var self = this; if (!Cocoon.Store.nativeAvailable) return this.storeProductList = [], void 0; Cocoon.Store.on("load", { started: function() { console.log("Fetching products...") }, success: function(products) { console.log("received products", products.length); for (var i = 0; i < products.length; i++) { var productInfo = products[i]; Cocoon.Store.addProduct(productInfo), console.log("Adding product to the local database", JSON.stringify(products[i])); for (var j = 0; j < DataStore.moneyPackList.length; j++) { var p = DataStore.moneyPackList[j]; Cocoon.Store.getStoreType() == Cocoon.Store.StoreType.APP_STORE && productInfo.productId == p.appstore_id && (p.cost = Math.round(100 * productInfo.price) / 100, p.localizedCost = productInfo.localizedPrice.replace(" ", ""), p.loaded = !0) } } self.storeLoaded = !0, self.checkNoAds() }, error: function(errorMessage) { console.log("load store error", errorMessage) } }), Cocoon.Store.on("consume", { started: function(transactionId) { console.log("start consuming " + transactionId) }, success: function(transactionId) { console.log("consuming " + transactionId + " ok") }, error: function(transactionId, err) { console.log("unable to consume " + transactionId, JSON.stringify(err)) } }), Cocoon.Store.on("purchase", { started: function(productId) { console.log("initialize purchase on", productId) }, verification: function(productId, data) { self.isLoading = !1, console.log("verification", productId); try { var jsonData = JSON.parse(data.replace(/\\/g, "")); jsonData = atob(jsonData.receipt).replace(/" *= *"/g, '":"').replace(/;/g, ",").replace(/}/g, '"debugTime": "' + (new Date).toString() + '"}'), jsonData = JSON.parse(jsonData); var purchaseInfo = atob(jsonData["purchase-info"]).replace(/" *= *"/g, '":"').replace(/;/g, ",").replace(/}/g, '"debugTime": "' + (new Date).toString() + '"}'); purchaseInfo = JSON.parse(purchaseInfo); var orderId = purchaseInfo["transaction-id"]; if (console.log("complete orderId", orderId), Cocoon.Store.consume(orderId, productId), Cocoon.Store.finish(orderId), productId == self.NO_ADS_STORE_ID) setStoredBool("no-ads", !0), app.startScreen.needRefresh = !0; else for (var i = 0; i < DataStore.moneyPackList.length; i++) { var pack = DataStore.moneyPackList[i]; if (Cocoon.Store.getStoreType() == Cocoon.Store.StoreType.APP_STORE && pack.appstore_id == productId) { console.log("pack found"), self.applyBuy(pack, !0); break } } } catch (e) { console.log("error : " + e) } }, success: function(purchaseInfo) { if (self.isLoading = !1, console.log("purchase complete", JSON.stringify(purchaseInfo)), Cocoon.Store.consume(purchaseInfo.transactionId, purchaseInfo.productId), Cocoon.Store.finish(purchaseInfo.transactionId), purchaseInfo.productId == self.NO_ADS_STORE_ID) setStoredBool("no-ads", !0), app.startScreen.needRefresh = !0; else for (var i = 0; i < DataStore.moneyPackList.length; i++) { var pack = DataStore.moneyPackList[i]; if (Cocoon.Store.getStoreType() == Cocoon.Store.StoreType.APP_STORE && pack.appstore_id == purchaseInfo.productId) { console.log("pack found"), self.applyBuy(pack, !0); break } } }, error: function(productId, error) { self.isLoading = !1, console.log("purchase error ", productId, JSON.stringify(error)), alert(_2("transaction-cancelled")) } }), Cocoon.Store.on("restore", { started: function(a) { console.log("restore init", a) }, success: function(a) { console.log("restore termine", a), self.checkNoAds() }, error: function(errorMessage) { console.log("error", errorMessage), self.checkNoAds() } }); var managed = Cocoon.Store.getStoreType() != Cocoon.Store.StoreType.APP_STORE; console.log("managed ? ", managed), Cocoon.Store.initialize({ sandbox: Config.GENERAL.SANDBOX, managed: !1 }), this.storeProductList = []; for (var i = 0; i < DataStore.moneyPackList.length; i++) Cocoon.Store.getStoreType() == Cocoon.Store.StoreType.APP_STORE && this.storeProductList.push(DataStore.moneyPackList[i].appstore_id); console.log("product list : ", JSON.stringify(this.storeProductList)), Cocoon.Store.loadProducts(this.storeProductList); var purchaseList = Cocoon.Store.getPurchases(); console.log(JSON.stringify(purchaseList)) } }, Sound = function(src) { this.src = src, this.muted = !1, this.paused = !1, this.playing = !1, this.loop = !1, this.elm = new Audio, this.elm.preload = !1, this.elm.src = src, this.elm.load() }; Sound.prototype.dispose = function() { this.elm.pause(), this.elm.dispose && this.elm.dispose() }, Sound.prototype.play = function(callback) { var self = this; return this.callback = callback, this.playing || (this.muted ? callback && (callback(), this.callback = !1) : (this.playing = !0, this.elm.addEventListener("ended", function() { self.playing = !1, self.callback && (callback(), self.callback = !1) }), this.reset(), this.elm.play())), this }, Sound.prototype.reset = function() { try { this.playing = !1, this.elm.pause(), this.elm.currentTime = 0 } catch (e) {} return this }, Sound.prototype.playLoop = function() { return this.loop = !0, this.elm.loop = !0, this.playing = !0, this.muted || this.elm.play(), this }, Sound.prototype.pause = function() { return this.playing = !1, this.elm.pause(), this }, Sound.prototype.setMuted = function(b) { if (this.muted = b, this.muted) { if (this.elm.pause(), this.playing && !this.loop && this.callback) { var callback = this.callback; this.callback = !1, callback() } } else this.playing && this.loop && this.elm.play(); return this }, Sound.prototype.setPlaybackRate = function(rate) { this.elm.playbackRate = rate }; var StartScreen = function(app) { Screen.call(this, app, "start"), this.background = this.assetManager.getImage("gui.start.background"), this.logo = this.assetManager.getAtlasImage("gui.start.logo"), this.play = this.assetManager.getAtlasImage("gui.start.play"), this.creditBackground = this.assetManager.getAtlasImage("gui.credits.background"), this.achievementButton = this.app.assetManager.getAtlasImage("gui.common.achievement"), this.cncLogo = this.assetManager.getAtlasImage("gui.credits.cnc"), "spilgames" == PUBLISHER && SGUtils.init(this.assetManager), this.creditsEnabled = !1, this.entityList = [] }; StartScreen.prototype = new Screen, StartScreen.prototype.onResize = function() { Screen.prototype.onResize.call(this), this.fakeWorld.onResize(this.graphics.height, this.graphics.height), this.worldWidth = 2 * (app.width / app.height); for (var i = 0; i < this.entityList.length; i++) this.entityList[i].onResize() }, StartScreen.prototype.render = function(g) { var self = this; if (!this.needRefresh && (Input.needRefresh("f4f") || Input.needRefresh("facebook") || Input.needRefresh("settings")) && (this.needRefresh = !0), this.needRefresh ? (g.save(), g.translate(Math.round(g.width / 2), 0), g.scale(app.scale, app.scale), g.drawImage(this.background, 0, 0, this.background.width, this.background.height, -Math.round(App.BASE_MAX_WIDTH / 2), 0, App.BASE_MAX_WIDTH, App.BASE_HEIGHT), this.logo.render(g, -Math.round(this.logo.width / 2), 50), g.restore()) : this.creditsEnabled || StockManager.visible || Money.visible || ButtonUtils.renderBackground({ g: g, background: this.background, backgroundX: (g.width - App.BASE_MAX_WIDTH * app.scale) / 2, backgroundY: 0, backgroundWidth: App.BASE_MAX_WIDTH, backgroundHeight: App.BASE_HEIGHT, width: App.BASE_MAX_WIDTH, height: 320, bgActiveScale: 1 }, g.width / 2, g.height - 280 * app.scale), !this.creditsEnabled && !StockManager.visible && !Money.visible || this.needRefresh) { g.save(), g.translate(0, Math.round(.68 * g.height)); for (var i = 0; i < this.entityList.length; i++) this.entityList[i].render(g, !0, !1); g.restore() }(this.needRefresh || !StockManager.visible && !Money.visible) && (ButtonUtils.render({ g: g, img: this.play, id: "play", x: Math.round(g.width / 2), y: 320 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_TOP, listener: function() { app.levelSelectScreen.show() }, visibilityHandler: function() { return !0 }, sound: "tap-kwak", needRefresh: !this.creditsEnabled }), PUBLISHER_NO_BRANDING || ButtonUtils.render({ g: g, img: app.assetManager.getAtlasImage("gui.start.f4f"), id: "f4f", x: Math.round(g.width / 2 - 20 * app.scale), y: Math.round(g.height - 20 * app.scale), align: ButtonUtils.ALIGN_RIGHT, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { Cocoon.App.openURL("http://www.appstore.com/3dduo") }, visibilityHandler: function() { return !self.creditsEnabled }, needRefresh: !this.creditsEnabled }), ButtonUtils.render({ g: g, img: app.assetManager.getAtlasImage("gui.start.facebook"), id: "facebook", x: Math.round(g.width / 2 + 20 * app.scale), y: Math.round(g.height - 20 * app.scale), align: ButtonUtils.ALIGN_LEFT, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { Cocoon.App.openURL("https://facebook.com/fun4family") }, visibilityHandler: function() { return !self.creditsEnabled }, needRefresh: !this.creditsEnabled }), ButtonUtils.render({ g: g, img: this.achievementButton, id: "achievement", x: g.width - 90 * app.scale, y: g.height - Math.round(10 * app.scale), align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { app.achievementScreen.show() }, changeListener: function() { self.needRefresh = !0 }, visibilityHandler: function() { return !self.creditsEnabled && !StockManager.visible && !Money.visible }, needRefresh: !this.creditsEnabled }), this.renderMoney(g), this.renderStock(g), Config.GENERAL.MONETIZATION && this.renderNoAds(g), this.renderSettings(g), this.renderCredits(g), "spilgames" != PUBLISHER || self.creditsEnabled || StockManager.visible || Money.visible || (SGUtils.drawMenu(g), SGUtils.refreshInputMenu(!0))), this.needRefresh = !1 }, StartScreen.prototype.renderNoAds = function(g) { var self = this; getStoredBool("no-ads") || (ButtonUtils.render({ g: g, img: this.assetManager.getAtlasImage("gui.start.no-ads-" + ("fr" == this.app.localeLanguage ? "fr" : "en")), id: "no-ads", x: Math.round(g.width - 20 * app.scale), y: Math.round(150 * app.scale), align: ButtonUtils.ALIGN_RIGHT, valign: ButtonUtils.VALIGN_TOP, listener: function() { Cocoon.Store.nativeAvailable ? navigator.onLine ? Cocoon.Store.getStoreType() == Cocoon.Store.StoreType.APP_STORE && Cocoon.Store.purchase(Money.NO_ADS_STORE_ID) : alert(_2("game-offline-error")) : (setStoredBool("no-ads", !0), self.needRefresh = !0) }, changeListener: function() { self.needRefresh = !0 }, visibilityHandler: function() { return !self.creditsEnabled && !StockManager.visible && !Money.visible }, needRefresh: !this.creditsEnabled }), ButtonUtils.render({ g: g, img: this.assetManager.getAtlasImage("gui.start.restore-" + ("fr" == this.app.localeLanguage ? "fr" : "en")), id: "restore", x: Math.round(g.width - 20 * app.scale), y: Math.round(240 * app.scale), align: ButtonUtils.ALIGN_RIGHT, valign: ButtonUtils.VALIGN_TOP, listener: function() { Cocoon.Store.restore() }, changeListener: function() { self.needRefresh = !0 }, visibilityHandler: function() { return !self.creditsEnabled && !StockManager.visible && !Money.visible }, needRefresh: !this.creditsEnabled })) }, StartScreen.prototype.toggleSettings = function() { this.settingsEnabled = !this.settingsEnabled, this.settingsSwitchTime = this.app.timeData.global }, StartScreen.prototype.closeCredits = function() { this.creditsEnabled = !1 }, StartScreen.prototype.openCredits = function() { this.creditsEnabled = !0 }, StartScreen.prototype.renderCredits = function(g) { var self = this; if (this.needRefresh && this.creditsEnabled) { g.save(), g.fillStyle = "rgba(0, 0, 0, 0.5)", g.fillRect(0, 0, g.width, g.height), g.translate(Math.round(g.width / 2), Math.round(g.height / 2)), g.scale(app.scale, app.scale), this.creditBackground.render(g, -Math.round(this.creditBackground.width / 2), -Math.round(this.creditBackground.height / 2)), g.save(), g.scale(.55, .55), this.logo.render(g, -Math.round(this.logo.width / 2), -470), g.restore(); var credits = Utils.splitText(_2("credits-text")); app.setBaseFont(g, 18), g.translate(0, -90), g.fillStyle = "black"; for (var i = 0; i < credits.length; i++) { var t = credits[i].split("/"); t.length > 1 ? (g.textAlign = "right", g.fillText(t[0], -60, 32 * i), g.textAlign = "left", g.fillText(t[1], -60, 32 * i)) : (g.textAlign = "center", g.fillText(credits[i], 0, 32 * i)) } var smallText = Utils.splitText(_2("credits-small-text")); app.setBaseFont(g, 14), g.translate(-200, 320), g.fillStyle = "black"; for (var i = 0; i < smallText.length; i++) g.textAlign = "left", g.fillText(smallText[i], 0, 17 * i); this.cncLogo.render(g, -120, -11), g.restore(), ButtonUtils.render({ g: g, img: app.assetManager.getAtlasImage("gui.common.close"), id: "credits-close", x: Math.round(g.width / 2 + 300 * app.scale), y: Math.round(g.height / 2 - 220 * app.scale), align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_CENTER, listener: function() { self.closeCredits() }, changeListener: function() { self.needRefresh = !0 }, visibilityHandler: function() { return self.creditsEnabled && !StockManager.visible && !Money.visible }, needRefresh: this.needRefresh }), ButtonUtils.render({ g: g, img: app.assetManager.getAtlasImage("gui.credits.3dduo"), id: "credits-3dduo", x: Math.round(g.width / 2 - 290 * app.scale), y: Math.round(g.height / 2 - 210 * app.scale), align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_CENTER, listener: function() { Cocoon.App.openURL(PUBLISHER_3DD_URL) }, changeListener: function() { self.needRefresh = !0 }, visibilityHandler: function() { return self.creditsEnabled && !StockManager.visible && !Money.visible }, needRefresh: this.needRefresh }), ButtonUtils.render({ g: g, img: app.assetManager.getAtlasImage("gui.start.f4f"), id: "credits-f4f", x: Math.round(g.width / 2 - 285 * app.scale), y: Math.round(g.height / 2 - 95 * app.scale), align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_CENTER, scale: .82, listener: function() { Cocoon.App.openURL(PUBLISHER_F4F_URL) }, changeListener: function() { self.needRefresh = !0 }, visibilityHandler: function() { return self.creditsEnabled && !StockManager.visible && !Money.visible }, needRefresh: this.needRefresh }) } }, StartScreen.prototype.renderSettings = function(g) { var self = this; this.settingsEnabled && !this.creditsEnabled && (g.fillStyle = "rgba(0, 0, 0, 0.5)", g.fillRect(40 * app.scale, g.height - 470 * app.scale, 100 * app.scale, 400 * app.scale)), ButtonUtils.render({ g: g, img: this.app.assetManager.getAtlasImage("gui.common.settings"), id: "settings", x: 90 * app.scale, y: g.height - 10 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { self.toggleSettings() }, changeListener: function() { self.needRefresh = !0 }, visibilityHandler: function() { return !self.creditsEnabled && !StockManager.visible && !Money.visible }, needRefresh: !this.creditsEnabled }), this.settingsEnabled && (ButtonUtils.render({ g: g, img: this.app.assetManager.getAtlasImage("gui.locale." + this.app.localeLanguage), id: "locale", x: 90 * app.scale, y: g.height - 170 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { self.app.toggleLocale() }, changeListener: function() { self.needRefresh = !0 }, visibilityHandler: function() { return !self.creditsEnabled && self.settingsEnabled && !StockManager.visible && !Money.visible }, needRefresh: !this.creditsEnabled }), ButtonUtils.render({ g: g, img: this.app.assetManager.getAtlasImage(app.assetManager.soundEnabled ? "gui.common.sound-on" : "gui.common.sound-off"), id: "sound", x: 90 * app.scale, y: g.height - 300 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { app.assetManager.toggleSound() }, changeListener: function() { self.needRefresh = !0 }, visibilityHandler: function() { return !self.creditsEnabled && self.settingsEnabled && !StockManager.visible && !Money.visible }, needRefresh: !this.creditsEnabled }), ButtonUtils.render({ g: g, img: this.app.assetManager.getAtlasImage("gui.common.info"), id: "info", x: 90 * app.scale, y: g.height - 430 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { self.openCredits() }, changeListener: function() { self.needRefresh = !0 }, visibilityHandler: function() { return !self.creditsEnabled && self.settingsEnabled && !StockManager.visible && !Money.visible }, needRefresh: !this.creditsEnabled })) }, StartScreen.prototype.renderMoney = function(g) { var self = this; (this.needRefresh || Input.needRefresh("money") || StockManager.needRefresh && StockManager.visible) && (g.save(), g.scale(app.scale, app.scale), g.translate(20, 20), Config.GENERAL.MONETIZATION && Input.addCollider("money", 20 * app.scale, 20 * app.scale, Money.background.width * app.scale, Money.background.height * app.scale, function() { Money.openPopup() }, !1, function() { return !app.gameScreen.stockTuto && !self.creditsEnabled }), StockManager.visible || ButtonUtils.renderBackground({ g: g, background: this.background, backgroundX: (g.width - App.BASE_MAX_WIDTH * app.scale) / 2, backgroundY: 0, backgroundWidth: App.BASE_MAX_WIDTH, backgroundHeight: App.BASE_HEIGHT, width: Money.background.width, height: Money.background.height }, 20 * app.scale + Money.background.width * app.scale / 2, 20 * app.scale + Money.background.height * app.scale / 2), Money.render(g, Input.isActive("money")), Input.setRefreshed("money"), g.restore()) }, StartScreen.prototype.renderStock = function(g) { var self = this; Money.visible || !this.needRefresh && this.creditsEnabled || StockManager.visible && !this.needRefresh && !StockManager.hasWarning() || (g.save(), g.translate(g.width, 0), g.scale(app.scale, app.scale), g.translate(-StockManager.background.width - 20, 20), Input.addCollider("stock", g.width - (StockManager.background.width + 20) * app.scale, 20 * app.scale, StockManager.background.width * app.scale, StockManager.background.height * app.scale, function() { StockManager.openPopup() }, !1, function() { return !self.creditsEnabled }), ButtonUtils.renderBackground({ g: g, background: this.background, backgroundX: (g.width - App.BASE_MAX_WIDTH * app.scale) / 2, backgroundY: 0, backgroundWidth: App.BASE_MAX_WIDTH, backgroundHeight: App.BASE_HEIGHT, width: 1.1 * StockManager.background.width, height: 1.5 * StockManager.background.height }, g.width - (1.1 * StockManager.background.width / 2 + 20) * app.scale, 20 * app.scale + 1.5 * StockManager.background.height * app.scale / 2), StockManager.render(g, Input.isActive("stock")), g.restore()) }, StartScreen.prototype.init = function() { this.fakeWorld = new World(this.app.gameScreen), this.fakeWorld.isFake = !0, this.onResize(), this.refreshStock() }, StartScreen.prototype.refreshStock = function() { this.entityList = []; for (var dt in DataStore.dodoTypeList) if (StockManager.stockList[dt]) for (var i = 0; i < StockManager.stockList[dt].getAmount(); i++) { var e = new Entity(this.fakeWorld, 1, 1, !1, !1, DataStore.dodoTypeList[dt], !1); if (e.setPosition(Math.random() * this.worldWidth, .1 * Math.random()), e.setSprite("WALK", !1, !0), e.scale = 1.2, this.entityList.push(e), DataStore.dodoTypeList[dt].spawn_count > 0 && DataStore.dodoTypeList[dt].spawn_dodo_type) for (var j = 0; j < DataStore.dodoTypeList[dt].spawn_count; j++) e = new Entity(this.fakeWorld, 1, 1, !1, !1, DataStore.dodoTypeList[DataStore.dodoTypeList[dt].spawn_dodo_type], !1), e.setPosition(Math.random() * this.worldWidth, .1 * Math.random()), e.setSprite("WALK", !1, !0), e.scale = 1.2, this.entityList.push(e) } this.sortEntities(), this.onResize() }, StartScreen.prototype.sortEntities = function() { this.entityList.sort(function(a, b) { return a.y - b.y }) }, StartScreen.prototype.update = function(timeData) { if (this.worldWidth && (!this.creditsEnabled && !StockManager.visible && !Money.visible || this.needRefresh)) { for (var needSort = !1, i = 0; i < this.entityList.length; i++) { var e = this.entityList[i], offset = timeData.localDelta * e.getSpeed() / 1e3; e.setPosition(e.x + offset, e.y), e.x > this.worldWidth && (e.setPosition(-.1, .1 * Math.random()), needSort = !0), e.update(timeData, !0) } needSort && this.sortEntities() } }; var StockManager = { ENTRY_HEIGHT: 88, init: function() { this.stockList = {}, this.visible = !1; for (var i in DataStore.dodoTypeList) { var dodoType = DataStore.dodoTypeList[i]; dodoType.recover_time && (this.stockList[i] = new DodoStock(this, i)) } this.background = app.assetManager.getAtlasImage("gui.common.money-life-background"), this.stockBackground = app.assetManager.getAtlasImage("gui.stock.background"), this.plus = app.assetManager.getAtlasImage("gui.common.money-plus"), this.dodoCount = app.assetManager.getAtlasImage("gui.common.dodo-count"), this.captionWood = app.assetManager.getAtlasImage("gui.common.caption-wood"), this.infinite = app.assetManager.getAtlasImage("gui.stock.infinite"), this.money = app.assetManager.getAtlasImage("gui.common.money"), this.tick = app.assetManager.getAtlasImage("gui.common.tick"), this.lastRenderTime = 0, this.lastUpdateTime = 0 }, onResize: function() { this.needRefresh = !0 }, getLevelDodoCount: function(worldIndex, levelIndex) { var count = 0, startPoints = DataStore.worldList[worldIndex].levelList[levelIndex].startPoints; for (var i in startPoints) { var p = startPoints[i]; p.ennemy || (count += p.popCount) } return count }, openPopup: function(closeListener) { app.hideBanner(), this.visible = !0, this.needRefresh = !0, this.closeListener = closeListener, this.isMissingPopup = !1, this.openTime = app.timeData.global, Input.removeAllCollider(), app.assetManager.getSound("menu.stock").reset().play() }, closePopup: function() { this.visible = !1, app.gameScreen.stockTuto && (app.gameScreen.stockTuto = !1), this.closeListener && this.closeListener(), app.currentScreen == app.levelSelectScreen && app.showBanner(), app.currentScreen.needRefresh = !0 }, getMissingDodoCost: function(missingAmount) { return Math.round(missingAmount * DataStore.dodoTypeList[Config.GENERAL.DEFAULT_DODO_TYPE].cost * Config.GENERAL.MISSING_DODO_COST_FACTOR) }, openMissingPopup: function(missingAmount, handler) { this.visible = !0, this.needRefresh = !0, this.isMissingPopup = !0, this.missingHandler = handler, this.missingAmount = missingAmount, this.missingCost = this.getMissingDodoCost(missingAmount), Money.setTutoDone() }, isInfinite: function() { return getStoredInt("infinite-stock-time") > Math.floor(app.timeData.global / 1e3) }, getInfiniteTime: function() { return getStoredInt("infinite-stock-time") }, startInfinite: function() { this.isInfinite() || Money.spend(Config.GENERAL.INFINITE_COST) && setStoredInt("infinite-stock-time", Math.floor(app.timeData.global / 1e3) + Config.GENERAL.INFINITE_DURATION) }, stopInfinite: function() { this.isInfinite() && clearStoredData("infinite-stock-time") }, getAmount: function() { var amount = 0; for (var i in this.stockList) amount += this.stockList[i].getAmount(); return amount }, getLevelAmount: function() { var amount = 0; for (var i in this.stockList) amount += this.stockList[i].getLevelAmount(); return amount }, getMaxAmount: function() { var max = 0; for (var i in this.stockList) max += this.stockList[i].getMaxAmount(); return max }, update: function(timeData) { var self = this, amount = this.getAmount(), max = this.getMaxAmount(), now = Math.floor(timeData.global / 1e3); if (now != this.lastUpdateTime) { this.visible && (this.needRefresh = !0), this.lastUpdateTime = now; var nextLifeTime = 0; if (this.currentDodoType = Config.GENERAL.DEFAULT_DODO_TYPE, this.isInfinite()) { nextLifeTime = this.getInfiniteTime(); for (var i in this.stockList) this.stockList[i].update(timeData) } else for (var i in this.stockList) { this.stockList[i].update(timeData); var lifeTime = this.stockList[i].getNextLifeTime(); lifeTime && (nextLifeTime > lifeTime || !nextLifeTime) && (nextLifeTime = lifeTime, this.currentDodoType = i), this.nextLifeTime = nextLifeTime } this.currentMax && (0 != amount - this.currentAmount || max != this.currentMax) && this.stockUpdateListener ? this.lifeUpdateInterval || (this.lifeUpdateInterval = setInterval(function() { amount != self.currentAmount && (self.lastUpdateTime = app.timeData.global, amount > self.currentAmount ? (app.assetManager.getSound("game.new-egg").reset().play(), self.currentAmount++) : amount < self.currentAmount && self.currentAmount--, max > self.currentMax ? self.currentMax++ : max < self.currentMax && self.currentMax--), amount == self.currentAmount && max == self.currentMax && (clearInterval(self.lifeUpdateInterval), self.lifeUpdateInterval = !1, self.stockUpdateListener && (self.stockUpdateListener(), self.stockUpdateListener = !1)) }, 500)) : (this.lifeUpdateInterval && (clearInterval(this.lifeUpdateInterval), this.lifeUpdateInterval = !1), this.currentMax = max, this.currentAmount = amount) } }, onLevelStart: function() { for (var i in this.stockList) this.stockList[i].resetLevelAmount() }, getAvailableDodoType: function() { var levelAmount = this.getLevelAmount(), index = Math.floor(Math.random() * levelAmount); for (var i in this.stockList) { var amount = this.stockList[i].getLevelAmount(); if (amount > index) return this.stockList[i].levelConsume(), i; index -= amount } return console.log("No dodo found for index " + index + " (on " + levelAmount + ")"), !1 }, checkAvailable: function(world, level, handler) { var needs = this.getLevelDodoCount(world, level) - this.getAmount(); return this.isInfinite() || 0 >= needs || testLevel ? !0 : (this.openMissingPopup(needs, handler), !1) }, renderForGame: function(g) { g.save(); var icon = app.assetManager.getAtlasImage("data.dodos." + this.currentDodoType + "-icon"); if (icon.render(g, -Math.round(icon.width / 2), 20), this.isInfinite()) g.scale(.6, .6), this.infinite.render(g, -Math.round(this.infinite.width / 2), 160); else { g.translate(0, icon.height + 35), app.setBaseFont(g, 45); var duration = 250; if (this.lastUpdateTime && g.timeData.global - this.lastUpdateTime < duration) { var scaleEffect = .33, f = (g.timeData.global - this.lastUpdateTime) / duration, scale = 1 + Math.easeOutQuad(Math.tweenBack(Math.min(1, 1.5 * f), .5)) * scaleEffect; g.scale(scale, scale) } g.textAlign = "right", g.fillStyle = this.hasWarning() ? App.RED_STYLE : App.FILL_STYLE, app.fillOutlineText(g, this.currentAmount, 0, 0), g.textAlign = "left", app.setBaseFont(g, 25), app.fillOutlineText(g, "/ " + this.currentMax, -10, 0) } g.restore() }, hasWarning: function() { return this.getAmount() <= Config.GENERAL.STOCK_WARNING_LEVEL }, refreshAmountCache: function() { var g; this.amountCache ? g = this.amountCache.getContext("2d") : (this.amountCache = Utils.createCanvas(128, 32), g = this.amountCache.getContext("2d"), app.setBaseFont(g, 42), g.textAlign = "center"), g.save(), g.clearRect(0, 0, this.amountCache.width, this.amountCache.height), g.translate(this.amountCache.width / 2, this.amountCache.height - 4), g.fillStyle = this.hasWarning() ? App.RED_STYLE : App.FILL_STYLE, app.fillOutlineText(g, this.getAmount()), g.restore(), this.cacheValue = this.getAmount() }, getDisplayedTime: function(timeData) { var time = 0; return time = this.isInfinite() ? this.getInfiniteTime() : this.nextLifeTime, Math.ceil(time - timeData.global / 1e3) }, refreshTimeCache: function(timeData) { var g; this.timeCache ? g = this.timeCache.getContext("2d") : (this.timeCache = Utils.createCanvas(256, 32), g = this.timeCache.getContext("2d")), g.save(), g.clearRect(0, 0, this.timeCache.width, this.timeCache.height), g.translate(this.timeCache.width / 2, this.timeCache.height - 5); var time = this.getDisplayedTime(timeData); app.setBaseFont(g, 20), g.textAlign = "right", this.isInfinite() ? app.fillOutlineText(g, _2("infinite-remaining"), 5, 0) : app.fillOutlineText(g, _2("next-in"), 5, 0), app.setBaseFont(g, 27), g.textAlign = "left", app.fillOutlineText(g, Utils.formatTimeHour(time), 0, 0), this.cacheTimeValue = time, g.restore() }, render: function(g, isActive) { this.background.render(g, 0, 0); var icon = app.assetManager.getAtlasImage("data.dodos." + this.currentDodoType + "-icon"); if (icon.render(g, -20, 5), this.plus.render(g, isActive ? this.plus.width / 2 : 0, 0, this.plus.width / 2, this.plus.height, 175, 8, this.plus.width / 2, this.plus.height), g.save(), this.isInfinite()) g.scale(.8, .8), this.infinite.render(g, 108, 43); else { if (g.translate(128, 57), this.getAmount() <= Config.GENERAL.STOCK_WARNING_LEVEL) { var s = .2 * Math.cycleSin(g.timeData.global, 400) + .9; g.scale(s, s) } this.amountCache && this.cacheValue == this.getAmount() || this.refreshAmountCache(g.timeData), g.drawImage(this.amountCache, -this.amountCache.width / 2, -this.amountCache.height / 2) } g.restore(), (this.getAmount() < this.getMaxAmount() || this.isInfinite()) && (this.timeCache && this.cacheTimeValue == this.getDisplayedTime(g.timeData) || this.refreshTimeCache(g.timeData), g.drawImage(this.timeCache, 10, 92)) }, renderPopup: function(g) { var self = this; if (!Money.visible) { if (g.save(), this.needRefresh) if (this.lastRenderTime = g.timeData.global, Input.startPopup(), g.fillStyle = "rgba(0, 0, 0, 0.75)", g.fillRect(0, 0, g.width, g.height), g.translate(Math.round(g.width / 2), 0), g.scale(app.scale, app.scale), this.isMissingPopup) { var bg = app.assetManager.getAtlasImage("gui.stock.complete-background"); g.save(), g.translate(0, Math.round(g.height / 2 / app.scale)), bg.render(g, -Math.round(bg.width / 2), -Math.round(bg.height / 2)), g.translate(120, -80), g.rotate(.08), app.setBaseFont(g, 70), g.textAlign = "center", app.fillOutlineText(g, _2("missing-dodo-title"), 0, 0), app.setBaseFont(g, 50); for (var text = Utils.splitText(_2("missing-dodo-description").replace("%1", self.missingAmount)), i = 0; i < text.length; i++) app.fillOutlineText(g, text[i], 0, 45 * (i + 1)); g.restore() } else { this.captionWood.render(g, -Math.round(this.captionWood.width / 2), 0), app.setBaseFont(g, 45), g.textAlign = "center", g.textBaseline = "middle", app.fillOutlineText(g, _2("stock-popup-title"), 0, 55), this.stockBackground.render(g, -Math.round(this.stockBackground.width / 2), 100), g.save(), g.translate(-360, 52); var index = 0; for (var i in this.stockList) g.translate(0, this.ENTRY_HEIGHT), this.stockList[i].getMaxAmount() > 0 ? this.stockList[i].render(g, index++) : this.stockList[i].renderEmpty(g, index++); if (g.restore(), app.gameScreen.stockTuto) { g.save(), g.translate(0, 280); var text; text = this.isTutoDone() ? Utils.splitText(_2("stock-tuto-text-ok")) : Utils.splitText(_2("stock-tuto-text")), g.lineWidth = 2, g.fillStyle = "rgba(0, 0, 0, 0.5)", g.fillRoundRect(-350, -30, 700, 35 * text.length + 30, 10), g.strokeStyle = "black", g.stroke(), app.setBaseFont(g, 35), g.textAlign = "center"; for (var i = 0; i < text.length; i++) app.fillOutlineText(g, text[i], 0, 35 * i); g.restore() } } this.isMissingPopup ? (ButtonUtils.render({ g: g, img: app.assetManager.getAtlasImage("gui.money.buy-button"), id: "stock-manage", x: Math.round(g.width / 2) - 120 * app.scale, y: Math.round(g.height / 2 + 160 * app.scale), align: ButtonUtils.ALIGN_RIGHT, valign: ButtonUtils.VALIGN_CENTER, scale: 1.35, listener: function() { self.isMissingPopup = !1 }, changeListener: function() { app.currentScreen.needRefresh = !0, self.needRefresh = !0 }, extraRender: function(g) { g.save(), g.textAlign = "center", g.translate(0, -5), app.setBaseFont(g, 22); for (var text = Utils.splitText(_2("missing-dodo-manage-stock")), i = 0; i < text.length; i++) app.fillOutlineText(g, text[i], 0, 25 * i); g.restore() }, visibilityHandler: function() { return self.visible }, needRefresh: this.needRefresh }), (Config.GENERAL.MONETIZATION || self.missingCost <= Money.getAmount()) && ButtonUtils.render({ g: g, img: app.assetManager.getAtlasImage("gui.stock.complete"), id: "stock-complete", x: Math.round(g.width / 2) - 90 * app.scale, y: Math.round(g.height / 2 + 160 * app.scale), align: ButtonUtils.ALIGN_LEFT, valign: ButtonUtils.VALIGN_CENTER, listener: function() { Money.spend(self.missingCost) && (self.stockList[Config.GENERAL.DEFAULT_DODO_TYPE].add(self.missingAmount), self.closePopup(), self.missingHandler && self.missingHandler()) }, changeListener: function() { app.currentScreen.needRefresh = !0, self.needRefresh = !0 }, extraRender: function(g) { g.save(), g.textAlign = "center", g.translate(-60, 0), app.setBaseFont(g, 27), app.fillOutlineText(g, _2("missing-dodo-complete-label").toUpperCase(), 0, -15), app.setBaseFont(g, 40), app.fillOutlineText(g, _2("missing-dodo-complete-amount").toUpperCase().replace("%1", self.missingAmount), 0, 20), g.restore(), app.setBaseFont(g, 45), g.textAlign = "right", app.fillOutlineText(g, self.missingCost, 120, 14), g.save(), g.scale(.6, .6), self.money.render(g, 210, -Math.round(self.money.height / 2)), g.restore() }, visibilityHandler: function() { return self.visible }, needRefresh: this.needRefresh }), ButtonUtils.render({ g: g, img: app.assetManager.getAtlasImage("gui.common.close"), id: "stock-close", x: Math.round(g.width / 2 + 300 * app.scale), y: Math.round(g.height / 2 - 160 * app.scale), align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_CENTER, listener: function() { self.closePopup() }, changeListener: function() { app.currentScreen.needRefresh = !0, self.needRefresh = !0 }, visibilityHandler: function() { return self.visible }, needRefresh: this.needRefresh })) : (StockManager.isTutoDone() && Config.GENERAL.MONETIZATION && ButtonUtils.render({ g: g, img: app.assetManager.getAtlasImage("gui.stock.infinite-button"), id: "stock-infinite", x: Math.round(g.width / 2), y: g.height - 30 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { self.startInfinite() }, changeListener: function() { app.currentScreen.needRefresh = !0, self.needRefresh = !0 }, extraRender: function(g) { app.setBaseFont(g, 28, !0), g.fillStyle = App.BROWN_FILL_STYLE, g.strokeStyle = App.BROWN_STROKE_STYLE, g.textAlign = "left"; var infiniteDuration = _2("infinite-duration").replace("%1", Config.GENERAL.INFINITE_DURATION / 3600); if (self.isInfinite()) { var remainingTime = self.getInfiniteTime() - Math.floor(g.timeData.global / 1e3); infiniteDuration = _2("infinite-remaining") + " " + Utils.formatTimeHour(remainingTime) } app.fillOutlineText(g, infiniteDuration, -50, 30), self.isInfinite() ? (app.setBaseFont(g, 25), g.textAlign = "right", app.fillOutlineText(g, _2("in-progress"), 190, 55)) : (app.setBaseFont(g, 35), g.textAlign = "right", app.fillOutlineText(g, Config.GENERAL.INFINITE_COST, 150, 60), g.save(), g.scale(.5, .5), self.money.render(g, 310, 80), g.restore()), app.setBaseFont(g, 34), g.textAlign = "center", g.translate(120, 0), g.rotate(.08), app.fillOutlineText(g, _2("infinite-label"), -65, -13) }, visibilityHandler: function() { return !self.isInfinite() && self.visible && StockManager.isTutoDone() }, needRefresh: this.needRefresh }), (this.isTutoDone() || !app.gameScreen.stockTuto) && ButtonUtils.render({ g: g, img: app.assetManager.getAtlasImage("gui.common.ok"), id: "stock-ok", x: Math.round(g.width / 2 + 350 * app.scale), y: g.height - 100 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, scale: app.gameScreen.stockTuto ? .05 * Math.cycleSin(g.timeData.global, 1e3) + 1 : 1, listener: function() { self.closePopup() }, changeListener: function() { app.currentScreen.needRefresh = !0, self.needRefresh = !0 }, visibilityHandler: function() { return self.visible }, needRefresh: this.needRefresh })), g.restore(), app.startScreen && this.isTutoDone() && app.startScreen.renderMoney(g, !0), this.needRefresh && (this.needRefresh = this.hasWarning() || app.gameScreen.stockTuto, Input.endPopup()) } }, renderCountTag: function(g, world, level) { var count = this.getLevelDodoCount(world, level); this.dodoCount.render(g, this.getAmount() >= count || this.isInfinite() ? this.dodoCount.width / 2 : 0, 0, this.dodoCount.width / 2, this.dodoCount.height, 10, 10 - this.dodoCount.height, Math.round(.6 * (this.dodoCount.width / 2)), Math.round(.6 * this.dodoCount.height)), this.isInfinite() ? (g.scale(.4, .4), this.infinite.render(g, 39, -147)) : (app.setBaseFont(g, 32), g.textAlign = "center", app.fillOutlineText(g, count, 35, -40)) }, isTutoDone: function() { return getStoredBool("stock-tuto") }, setTutoDone: function() { setStoredBool("stock-tuto", !0) } }, app, launch = function() { "undefined" == typeof WEB_DATA_URI && (WEB_DATA_URI = WEB_STATIC_URI), app = new App, PUBLISHER_AUTO_MUTE && app.autoMute() }; Animation = { WALK: 1, FALL: 2, SAVE: 3, POWER: 4, STUN: 5, DEATH: 6, SAVED: 7 }; var EndPoint = function(world, config, index) { this.world = world, this.config = config, this.index = index, this.x = this.config.x, this.y = this.config.y, this.isBonus = this.config.is_bonus, this.score = Config.SCORE.START_VALUE, this.lastScoreUpdate = 0, this.popScoreList = [] }; EndPoint.GLOW_ANIM_DURATION = 3e3, EndPoint.prototype.init = function() { this.isBonus && (this.chainSprite = this.world.createFxSprite("CHAINS")), this.world.goalType == GoalType.CAGE ? (this.currentFrame = 0, this.isSprite = !0, this.cageSpriteList = [this.world.createFxSprite("CAGE_1", 18), this.world.createFxSprite("CAGE_2", 18), this.world.createFxSprite("CAGE_3", 18), this.world.createFxSprite("CAGE_BREAK", 18)], this.ratio = this.cageSpriteList[0].width / this.cageSpriteList[0].height) : (this.isSprite = !1, this.image = this.world.goalType == GoalType.COLLECT ? this.world.game.assetManager.getAtlasImage("gui.game.nest") : this.world.assetManager.getImage("exit"), this.ratio = this.image.width / this.image.height), this.onResize(), this.apparitionTime = this.index * Config.END_POINT.FADE_IN_DELAY_FACTOR + Config.GRAPHICS.TILE_FADE_IN_DELAY_FACTOR * this.world.mainSquare.length * this.world.mainSquare[0].length + Config.GRAPHICS.TILE_FADE_IN_DURATION, this.apparitionCompleteTime = this.apparitionTime + Config.END_POINT.FADE_IN_DURATION }, EndPoint.prototype.activate = function() { this.isBonus && (this.isBonus = !1, this.image = this.world.assetManager.getImage("exit")) }, EndPoint.prototype.onResize = function() { (this.image || this.isSprite) && (this.renderHeight = (this.isSprite ? Config.END_POINT.CAGE_SIZE : Config.END_POINT.SIZE) * this.world.squareSize, this.world.goalType == GoalType.COLLECT && (this.renderHeight *= .8), this.scale = this.renderHeight / (this.isSprite ? this.cageSpriteList[0].height : this.image.height), this.renderDecalY = Math.round((this.isSprite ? Config.END_POINT.CAGE_Y_DECAL : Config.END_POINT.Y_DECAL) * this.world.squareSize), this.renderX = Math.round(this.x * this.world.squareSize), this.renderY = Math.round(this.y * this.world.squareSize) + this.renderDecalY) }, EndPoint.prototype.update = function(timeData) { this.score > Config.SCORE.MIN_VALUE && timeData.local > this.lastScoreUpdate + Config.SCORE.STEP_DURATION && (this.lastScoreUpdate = timeData.local, this.score -= Config.SCORE.STEP_VALUE, this.score < Config.SCORE.MIN_VALUE && (this.score = Config.SCORE.MIN_VALUE)) }, EndPoint.prototype.render = function(g) { if (!(g.timeData.local < this.apparitionTime)) { if (this.soundPlayed || (app.assetManager.getSound("start.portal").reset().play(), this.soundPlayed = !0), g.save(), g.translate(this.renderX, this.renderY), g.scale(this.scale, this.scale), g.timeData.local < this.apparitionCompleteTime) { var f = Math.easeOutBack((g.timeData.local - this.apparitionTime) / Config.END_POINT.FADE_IN_DURATION); g.globalAlpha = Math.min(1, f), g.scale(f, f) } g.save(), this.isSprite ? this.currentFrame >= 0 && (g.translate(-Math.round(this.cageSpriteList[this.currentFrame].width / 2), -Math.round(this.cageSpriteList[this.currentFrame].height / 2)), this.cageSpriteList[this.currentFrame].render(g), this.cageSpriteList[this.currentFrame].loop || this.cageSpriteList[this.currentFrame].currentFrame != this.cageSpriteList[this.currentFrame].frameCount - 1 || (this.currentFrame = -1)) : (g.translate(-Math.round(this.image.width / 2), -Math.round(this.image.height / 2)), this.world.goalType == GoalType.COLLECT ? this.image.render(g, 0, -20) : g.drawImage(this.image, 0, 0)), this.isBonus && this.chainSprite.render(g), g.restore(); Debug.ENTITY && (g.font = "40px brlnsr", g.textAlign = "center", g.fillStyle = "black", g.translate(0, -this.renderDecalY), g.globalAlpha = 1, g.fillStyle = "rgba(0, 0, 255, 0.5)", g.fillCircle(this.x, this.y, Config.END_POINT.COLLIDE_SIZE * this.world.squareSize), g.fillText(this.score, 0, -140)), g.restore() } }, EndPoint.prototype.renderScore = function(g) { if (this.popScoreList.length > 0) { g.save(), g.translate(this.renderX, this.renderY), g.scale(this.scale, this.scale), 0 == this.popScoreList[0].alpha && this.popScoreList.shift(0).dispose(); for (var i in this.popScoreList) this.popScoreList[i].render(g); g.restore() } }, EndPoint.prototype.checkReached = function(x, y, timeData, noScore) { if (this.isBonus) return !1; var res = Math.abs((x - this.x) * (x - this.x) + (y - this.y) * (y - this.y)) <= Math.pow(Config.END_POINT.COLLIDE_SIZE, 2); return res && (noScore || this.popScoreList.push(new PopScore(this.score, timeData))), res }, EndPoint.prototype.checkAlmostReached = function(x, y) { return this.isBonus ? !1 : Math.abs((x - this.x) * (x - this.x) + (y - this.y) * (y - this.y)) <= Math.pow(Config.END_POINT.COLLIDE_SIZE * Config.ACHIEVEMENT.ALMOST_SAVED_FACTOR, 2) }; var Entity = function(world, x, y, isEnnemy, invert, config, eggHatchTime) { this.fallFromMovingTileCheck = 0, this.config = config, this.world = world, this.isEnnemy = isEnnemy, this.isEgg = eggHatchTime ? !0 : !1, this.eggHatchTime = eggHatchTime, this.eggHatchDone = !0, this.eggHatchTime && (this.eggHatchDone = !1), this.minNextHitTime = 0, this.score = this.config.score, this.speed = this.config.final_speed, this.width = this.config.collide_width, this.height = this.config.collide_height, this.x = x - this.width / 2, this.y = y, this.xTranslation = 0, this.yTranslation = 0, this.opacity = this.config.opacity, this.opacity >= 1 && (this.opacity = !1), this.onGround = !1, this.startInvert = invert, this.revertDirection = this.startInvert, this.compensateY = 0, this.creationTime = this.world.game.timeData.local, this.nextSpawnTime = 0, this.spawnCount = 0, this.isEnnemy || (this.nextKwakTime = app.timeData.local + Math.round(Math.random() * this.getMaxKwakDelay())), this.config.spawn_dodo_type && this.config.spawn_count > 0 && (this.spawnCount = this.config.spawn_count, this.spawnDodoType = this.config.spawn_dodo_type, this.spawnDelay = this.config.spawn_delay, this.spawnDuration = this.config.spawn_duration, this.nextSpawnTime = this.creationTime + this.config.spawn_delay), this.deathTime = 0, this.config.life_time && (this.deathTime = this.creationTime + this.config.life_time), this.lifeCount = this.config.life_count, this.accessorySpriteList = {}; for (var i in DataStore.accessoryList) this.accessorySpriteList[i] = this.world.createAccessorySprite(i); this.spriteStartTime = 0, this.spriteList = {}, this.spriteDataList = {}; for (var a in DataStore.animationList) { var anim = DataStore.animationList[a]; if (!(anim.dodo_only && this.isEnnemy || anim.ennemy_only && !this.isEnnemy)) { var img; if (this.isEnnemy) img = this.world.assetManager.getImage("ennemy-" + anim.identifier); else { var spriteDodoType = this.config.id; this.config.sprite_dodo_type && (spriteDodoType = this.config.sprite_dodo_type), img = this.world.game.app.assetManager.getAtlasImage("data.dodos-opti." + spriteDodoType + "-" + anim.id) } this.spriteList[anim.identifier] = new Sprite(img, this.config.animationData[anim.identifier].col_count, this.config.animationData[anim.identifier].row_count, anim.loop), this.spriteList[anim.identifier].frameCount = this.config.animationData[anim.identifier].frame_count, this.spriteDataList[anim.identifier] = this.config.animationData[anim.identifier] } } this.iceSprite = this.world.createFxSprite("ICE"), this.eggSprite = this.world.createFxSprite("EGG"), this.eggSprite.stop(), this.spriteList.DEATH = this.world.createFxSprite("DEATH"), this.spriteDataList.DEATH = this.spriteDataList.WALK, this.world.goalType == GoalType.CAGE && (this.spriteList.DEATH_CAGE = this.world.createFxSprite("DEATH_CAGE"), this.spriteDataList.DEATH_CAGE = this.spriteDataList.WALK), this.setSprite("FALL"), this.fallSpeed = Config.PHYSICS.INIT_FALL_SPEED, this.onResize(), !Config.GENERAL.KILL_AT_MOVE || this.world.isFake || 0 != this.lifeCount || this.world.finished || this.world.nextDyingDodo && !(this.world.nextDyingDodo.lifeCount > 0) || (this.world.nextDyingDodo = this) }; Entity.WIN_DURATION = 2, Entity.prototype.getMaxKwakDelay = function() { return this.world.isFake ? 5 * Config.ENTITY.MAX_KWAK_DELAY : Config.ENTITY.MAX_KWAK_DELAY }, Entity.prototype.getMinKwakDelay = function() { return this.world.isFake ? 5 * Config.ENTITY.MIN_KWAK_DELAY : Config.ENTITY.MIN_KWAK_DELAY }, Entity.prototype.onResize = function() { this.refreshSize(), this.setPosition(this.x, this.y) }, Entity.prototype.refreshSize = function() { this.renderWidth = Math.round(this.world.squareSize * this.baseRenderWidth), this.renderHeight = Math.round(this.world.squareSize * this.baseRenderHeight), this.iceRenderHeight = Math.round(this.world.squareSize * Config.ENTITY.ICE_HEIGHT), this.iceRenderWidth = Math.round(this.iceSprite.width / this.iceSprite.height * this.iceRenderHeight), this.eggRenderHeight = Math.round(this.world.squareSize * Config.ENTITY.EGG_HEIGHT), this.eggRenderWidth = Math.round(this.eggSprite.width / this.eggSprite.height * this.eggRenderHeight), this.eggDecalY = Math.round(this.eggRenderHeight * Config.ENTITY.EGG_DECAL_Y), this.renderCollideWidth = Math.round(this.world.squareSize * this.width), this.renderCollideHeight = Math.round(this.world.squareSize * this.height), this.renderDecalX = Math.round((this.renderCollideWidth - this.renderWidth) / 2 + this.currentSpriteData.x_decal * this.baseRenderWidth * this.world.squareSize), this.renderDecalY = Math.round(this.renderCollideHeight - this.renderHeight + this.currentSpriteData.y_decal * this.baseRenderHeight * this.world.squareSize), this.itemDecalX = Math.round(this.currentSpriteData.item_x_decal * this.renderWidth), this.itemDecalY = Math.round(this.currentSpriteData.item_y_decal * this.renderHeight), this.accessoryData = []; for (var i in this.currentSpriteData.accessories) { var data = this.currentSpriteData.accessories[i]; if (!data.data) { data.data = []; for (var j = 0; j < this.currentSprite.frameCount; j++) data.data[j] = { x: 0, y: 0, r: 0 } } this.accessoryData[i] = { scale: data.scale * this.renderHeight / this.currentSprite.height, data: data.data } } }, Entity.prototype.setOnGround = function(b) { this.onGround != b && (this.onGround = b, this.onGround ? (this.isItem || this.setSprite("WALK"), this.fallSpeed = 0, this.isBumping = !1, this.shouldFall = !1) : (this.currentTile = !1, this.onGround = !1, this.shouldFall = !0, 0 == this.fallSpeed && (this.fallSpeed = Config.PHYSICS.INIT_FALL_SPEED))) }, Entity.prototype.setCurrentTile = function(tile) { this.currentTile = tile }, Entity.prototype.bump = function() { this.fallSpeed = -Config.PHYSICS.BUMP_IMPULSE, this.isBumping = !0, this.setSprite("FALL"), this.stop = !1, this.nextSpellApplyTime = !1, this.onGround = !1 }, Entity.prototype.setSprite = function(id, listener, randomizeStart) { this.currentSpriteId = id, this.currentSprite = this.spriteList[id], this.currentSpriteData = this.spriteDataList[id], this.currentSprite.currentFrame = 0, this.spriteStartTime = this.world.game.timeData.local, this.currentSprite.animDelay = randomizeStart ? Math.round(1e3 * Math.random()) : 0, this.currentSprite.lastFrameUpdate = this.world.game.timeData.local, this.currentSprite.onAnimationComplete = listener; var ratio = this.currentSprite.width / this.currentSprite.height; this.baseRenderHeight = this.currentSpriteData.height_factor * this.height, this.baseRenderWidth = this.baseRenderHeight * ratio, this.refreshSize() }, Entity.prototype.getSpeed = function() { return this.isEgg || this.isEnnemy && this.world.stopEnnemyFreezeTime || this.stop || this.world.finished && this.world.goalType == GoalType.SURVIVE ? 0 : this.isBumping ? Config.PHYSICS.BUMP_SPEED : this.speed }, Entity.prototype.getAnimSpeedFactor = function() { return this.speed / this.config.base_speed }, Entity.prototype.render = function(g, asIs, black) { if (g.save(), asIs) g.translate(this.renderX, this.renderY), this.renderAtOrigin(g, black); else { var x = this.renderX, y = this.renderY; x = (x + this.xTranslation + this.world.worldWidth) % this.world.worldWidth, y = (y + this.yTranslation + this.world.worldHeight) % this.world.worldHeight, g.translate(x, y), this.renderAtOrigin(g, black), x + this.renderWidth > this.world.worldWidth && (g.save(), g.translate(-this.world.worldWidth, 0), this.renderAtOrigin(g, black), g.restore()), y + this.renderHeight > this.world.worldHeight && (g.save(), g.translate(0, -this.world.worldHeight), this.renderAtOrigin(g, black), g.restore()) } if (g.restore(), this.isEgg || !this.eggHatchDone) { g.save(); var x = (this.eggRenderX + this.xTranslation + this.world.worldWidth) % this.world.worldWidth, y = (this.eggRenderY + this.yTranslation + this.world.worldHeight) % this.world.worldHeight; g.translate(x, y), this.renderEggAtOrigin(g), x + this.renderWidth > this.world.worldWidth && (g.save(), g.translate(-this.world.worldWidth, 0), this.renderEggAtOrigin(g), g.restore()), y + this.renderHeight > this.world.worldHeight && (g.save(), g.translate(0, -this.world.worldHeight), this.renderEggAtOrigin(g), g.restore()), g.restore() } }, Entity.prototype.renderEggAtOrigin = function(g) { var fadeDuration = 400, timeSinceDuration = g.timeData.local - this.creationTime, alpha = 1; if (this.startInvert && (g.translate(this.renderCollideWidth, 0), g.scale(-1, 1)), fadeDuration > timeSinceDuration) { var f = Math.easeOutElastic(timeSinceDuration / fadeDuration); g.translate(0, this.eggRenderHeight / 2), g.rotate((1 - f) * Math.PI / 2), g.scale(f, f), g.translate(0, -this.eggRenderHeight / 2) } g.translate(-Math.round(this.eggRenderWidth / 2), this.eggDecalY), (this.blink || this.world.game.timeData.local < this.minNextHitTime || this.world.stopImmunityTime && !this.isEnnemy) && (alpha = .5 * Math.cycleSin(g.timeData.local, 300) + .5), this.opacity && (alpha *= this.opacity), 1 > alpha && (g.globalAlpha = alpha), this.eggSprite.render(g, this.eggRenderWidth, this.eggRenderHeight) }, Entity.prototype.renderAtOrigin = function(g, black) { g.save(); var alpha = 1; if (!this.isEgg) { var fadeDuration = 200, timeSinceDuration = g.timeData.local - this.creationTime; fadeDuration > timeSinceDuration && (alpha = timeSinceDuration / fadeDuration) } if (this.revertDirection && (g.translate(this.renderCollideWidth, 0), g.scale(-1, 1)), this.compensateY ? (g.translate(this.renderDecalX, this.renderDecalY - this.compensateY * this.world.squareSize), this.compensateY > 0 ? (.5 * Config.PHYSICS.MAX_STEP_SIZE, this.compensateY -= this.compensateSpeed * g.timeData.localDelta / 1e3, this.compensateY < 0 && (this.compensateY = 0)) : this.compensateY < 0 && (this.compensateY -= this.compensateSpeed * g.timeData.localDelta / 1e3, this.compensateY > 0 && (this.compensateY = 0))) : g.translate(this.renderDecalX, this.renderDecalY), this.scale && g.scale(this.scale, this.scale), this.winning && this.world.goalType != GoalType.CAGE) { var f = 1 - (g.timeData.local - this.winStartTime) / Entity.WIN_DURATION / 1e3; 0 >= f && (f = 0, this.winEndListener && (this.winEndListener(), this.winEndListener = !1)); var fraction = .75; if (g.translate(this.renderWidth / 2, 0), fraction > f) { var f2 = Math.pow(f / fraction, 3); g.scale(f2, f2) } g.translate(-this.renderWidth / 2 + Math.round((1 - f) * this.world.squareSize * (this.winEndPointX + this.width / 2 - this.x)), .5 * -this.renderWidth * Math.pow(1 - f, .5)), alpha = Math.pow(f, 1.5) } else(this.blink || this.world.game.timeData.local < this.minNextHitTime || this.world.stopImmunityTime && !this.isEnnemy) && (alpha = .5 * Math.cycleSin(g.timeData.local, 300) + .5); this.opacity && (alpha *= this.opacity), 1 > alpha && (g.globalAlpha = alpha), this.spriteStartTime, this.itemDecalY, this.itemDecalX; var currentSprite = this.currentSprite, accessoryData = this.accessoryData; if (!this.isEgg) if (this.isEnnemy && this.world.stopEnnemyFreezeTime) black ? this.currentSprite.renderBlack(g, this.renderWidth, this.renderHeight, 0) : this.currentSprite.render(g, this.renderWidth, this.renderHeight, 0); else { if (this.world.nextDyingDodo == this && (this.world.tutoDeathTime || this.world.dragging)) { if (g.save(), this.world.tutoDeathTime || this.world.dragging) { var f = Math.cycleSin(g.timeData.global, 250); g.globalAlpha = .5 * f + .5, g.scale(1 + .1 * Math.random() - .05, 1 + .1 * Math.random() - .05) } black ? this.currentSprite.renderBlack(g, this.renderWidth, this.renderHeight, this.getAnimSpeedFactor()) : this.currentSprite.render(g, this.renderWidth, this.renderHeight, this.getAnimSpeedFactor()), g.restore() } else black ? this.currentSprite.renderBlack(g, this.renderWidth, this.renderHeight, this.getAnimSpeedFactor()) : this.currentSprite.render(g, this.renderWidth, this.renderHeight, this.getAnimSpeedFactor()); this.lifeCount > 1 && this.renderAccessory(g, "HELMET", currentSprite, accessoryData, !1, black) } if (this.item && this.renderAccessory(g, "FRUIT", currentSprite, accessoryData, !1, black), !this.isEnnemy && this.world.stopImmunityTime && this.renderAccessory(g, "AUREOLE", currentSprite, accessoryData, !1, black), !this.world.finished && this == this.world.nextDyingDodo) { if (this.world.tutoDeathTime || this.world.dragging) { var f = Math.cycleSin(g.timeData.global, 250); g.globalAlpha = .5 * f + .5 } this.renderAccessory(g, "SKULL", currentSprite, accessoryData, 1 + .5 * f, black), this.world.tutoDeathTimer && (g.globalAlpha = 1) } this.isEnnemy && this.world.stopEnnemyFreezeTime && this.iceSprite.render(g, this.iceRenderWidth, this.iceRenderHeight), this.spellSprite && (g.translate(this.spellSpriteDecalX, this.spellSpriteDecalY), this.spellSprite.render(g, this.spellSpriteRenderWidth, this.spellSpriteRenderHeight)), g.restore(), Debug.ENTITY && (g.fillStyle = "rgba(255, 0, 0, 0.5)", g.fillRect(0, 0, this.renderCollideWidth, this.renderCollideHeight)) }, Entity.prototype.playSpellSprite = function(loop) { var self = this; if (this.spellSprite) loop || this.spellSprite.resetAnim(); else { var scale = 1; this.world.worldConfig.ennemyData.spell_scale && (scale = this.world.worldConfig.ennemyData.spell_scale), this.spellSprite = new Sprite(this.world.assetManager.getImage("spell-sprite"), this.world.worldConfig.ennemyData.spell_col_count, this.world.worldConfig.ennemyData.spell_row_count, loop), this.spellSprite.frameCount = this.world.worldConfig.ennemyData.spell_frame_count, this.spellSpriteRenderHeight = Math.round(this.renderHeight * scale * this.spellSprite.height / this.currentSprite.height), this.spellSpriteRenderWidth = Math.round(this.spellSprite.width / this.spellSprite.height * this.spellSpriteRenderHeight), this.spellSpriteDecalX = -Math.round(this.spellSpriteRenderWidth / 2 - this.renderWidth / 2), this.spellSpriteDecalY = -Math.round(this.spellSpriteRenderHeight - this.renderHeight) + this.world.worldConfig.ennemyData.spell_decal_y * app.scale, this.spellSprite.onAnimationComplete = function() { self.spellSprite = !1 } } }, Entity.prototype.renderAccessory = function(g, type, currentSprite, accessoryData, scale, black) { var frameData = accessoryData[type].data[currentSprite.currentFrame]; frameData && (g.save(), g.scale(accessoryData[type].scale * frameData.sx, accessoryData[type].scale * frameData.sy), g.translate(frameData.x, frameData.y), g.rotate(frameData.r), scale && (g.translate(this.accessorySpriteList[type].width / 2, this.accessorySpriteList[type].height / 2), g.scale(scale, scale), g.translate(-this.accessorySpriteList[type].width / 2, -this.accessorySpriteList[type].height / 2)), black ? this.accessorySpriteList[type].renderBlack(g) : this.accessorySpriteList[type].render(g), g.restore()) }, Entity.prototype.doSpell = function() { this.speed = this.config.final_speed; for (var i in this.config.spellData) { var loop = !1, d = this.config.spellData[i], targetList = []; switch (d.spell_target) { case SpellTarget.RANDOM: var target = this.world.getRandomDodo(); target && targetList.push(target); break; case SpellTarget.ALL: targetList = this.world.getAllDodos(); break; case SpellTarget.SELF: targetList.push(this); break; case SpellTarget.AROUND: targetList = this.world.getDodosAroundPoint(this.x + this.width / 2, this.y, d.arg, .25) } for (var i in targetList) targetList[i].spellEndTime = this.world.game.timeData.local + this.config.spell_duration; switch (d.spell) { case Spell.CHARGE: for (var i in targetList) targetList[i].speed = targetList[i].config.final_speed * d.arg; break; case Spell.KILL: for (var i in targetList) this.world.trap(targetList[i]); break; case Spell.STUN: loop = !0; for (var i in targetList) targetList[i].speed = 0 } if (this.world.worldConfig.ennemyData.spell_frame_count) if (d.spell_target == SpellTarget.AROUND && d.spell == Spell.KILL) this.playSpellSprite(loop); else for (var i in targetList) targetList[i].playSpellSprite(loop) } }, Entity.prototype.stopSpell = function() { this.spellEndTime = !1, this.speed = this.config.final_speed, this.spellSprite && (this.spellSprite = !1) }, Entity.prototype.updateOnGround = function(timeData) { if (this.currentTile && this.currentTile.parentTile) { this.x += this.currentTile.lastMoveX; var y = this.y + this.height, x = (this.x + (this.revertDirection ? this.width : 0) - this.currentTile.parentTile.x - this.currentTile.x) / Config.GRAPHICS.MOVING_TILE_SIZE; if (x >= 1 || 0 >= x) this.currentTile = !1, this.fallFromMovingTileCheck = timeData.local + 500; else { var hit = this.currentTile.vRayHit(this, x, 0, 1, timeData); hit && (y = hit.pos * Config.GRAPHICS.MOVING_TILE_SIZE + this.currentTile.y + this.currentTile.parentTile.y - this.height, this.y - y < this.height / 2 && (this.y = y), this.compensateY = 0, this.compensateSpeed = 0) } } else if (!this.fallFromMovingTileCheck || timeData.local > this.fallFromMovingTileCheck) { var y = this.y + this.height, x = this.x + (this.revertDirection ? this.width : 0); this.currentTile = this.world.getTile(x, y), this.currentTile.movingTile && (this.currentTile = this.currentTile.getTileAt(x - this.currentTile.x, y - this.currentTile.y + 2 * GameScreen.EPSILON)) } }, Entity.prototype.update = function(timeData, kwakOnly) { var self = this; if (!kwakOnly && this.onGround && this.updateOnGround(timeData), this.spellEndTime && timeData.local > this.spellEndTime && this.stopSpell(), this.isEnnemy) { if (this.nextSpellTime || this.spellEndTime || !this.config.spellData.length || (this.nextSpellTime = timeData.local + Math.random() * (this.config.spell_max_delay - this.config.spell_min_delay) + this.config.spell_min_delay), timeData.local > this.nextSpellTime && this.onGround && this.currentSprite == this.spriteList.WALK && !this.world.stopEnnemyFreezeTime) { this.stop = !0, this.setSprite("POWER", function() { self.stop = !1, self.setSprite("WALK") }), this.nextSpellApplyTime = timeData.local + this.config.spell_apply_delay; var sound = this.world.game.app.assetManager.getSound("game.new-ennemy"); sound.reset(), sound.play(), this.nextSpellTime = !1 } this.nextSpellApplyTime && timeData.local > this.nextSpellApplyTime && (this.nextSpellApplyTime = !1, this.doSpell()) } else if (this.nextKwakTime || (this.nextKwakTime = timeData.local + Math.random() * (this.getMinKwakDelay() - this.getMaxKwakDelay()) + this.getMinKwakDelay()), timeData.local > this.nextKwakTime && this.currentSprite == this.spriteList.WALK) { var kwakId = Math.floor(Math.random() * Config.ENTITY.KWAK_COUNT - GameScreen.EPSILON); this.setSprite("KWAK", function() { self.setSprite("WALK") }); var sound = this.world.game.app.assetManager.getSound("game.kwak-" + kwakId); sound.reset(), sound.play(), this.nextKwakTime = !1 } if (!kwakOnly) { if (this.spawnCount > 0 && timeData.local > this.nextSpawnTime && (this.spawnCount--, this.nextSpawnTime += this.spawnDelay, this.nextPopTime = timeData.local + 500, this.setSprite("KWAK", function() { self.setSprite("WALK") })), this.nextPopTime && timeData.local > this.nextPopTime) { var entityData; entityData = this.isEnnemy ? this.world.worldConfig.ennemyData : DataStore.dodoTypeList[this.spawnDodoType], this.nextPopTime = !1, this.world.createEntity(this.x + (this.revertDirection ? this.width : 0), this.y, this.isEnnemy, this.revertDirection, entityData, timeData.local + this.spawnDuration) } if (this.isEgg) if (timeData.local > this.eggHatchTime) { if (this.eggSprite.isPlaying() || (this.eggSprite.resetAnim(), this.eggSprite.currentFrame = 3, this.eggSprite.onAnimationComplete = function() { self.eggHatchDone = !0 }, this.eggSprite.play(timeData)), this.eggSprite.currentFrame >= Config.ENTITY.EGG_HATCH_FRAME) { this.isEgg = !1; var kwakId = Math.floor(Math.random() * Config.ENTITY.KWAK_COUNT - GameScreen.EPSILON); this.setSprite("WALK"); var sound = this.world.game.app.assetManager.getSound("game.kwak-" + kwakId); sound.reset(), sound.play() } } else timeData.local > this.eggHatchTime - 1e3 ? this.eggSprite.currentFrame = 3 : timeData.local > this.eggHatchTime - 2e3 ? this.eggSprite.currentFrame = 2 : timeData.local > this.eggHatchTime - 4e3 && (this.eggSprite.currentFrame = 1); this.deathTime && timeData.local > this.deathTime - 3e3 && (this.blink = !0), this.deathTime && timeData.local > this.deathTime && (this.blink = !1, this.deathTime = 0, this.lifeCount = 1, this.world.trap(this)) } }, Entity.prototype.isOnMovingTile = function() { return this.currentTile && this.currentTile.parentTile }, Entity.prototype.setPosition = function(x, y, ignoreStep) { if (!Config.MOVE.PAUSE_DURING_DRAG) { var wasDecalY = this.world.selectedTile && this.x + this.width / 2 >= this.world.selectedTile.x && this.x + this.width / 2 < this.world.selectedTile.x + 1, isDecalY = this.world.selectedTile && x + this.width / 2 >= this.world.selectedTile.x && x + this.width / 2 < this.world.selectedTile.x + 1; if (wasDecalY != isDecalY) { var t = this.world.colTranslation / this.world.squareSize; isDecalY && (t = -t), this.y = (this.y + t) % this.world.mainSquare.length, y = (y + t) % this.world.mainSquare.length } else { var wasDecalX = this.world.selectedTile && this.y + this.height >= this.world.selectedTile.y && this.y + this.height < this.world.selectedTile.y + 1, isDecalX = this.world.selectedTile && y + this.height >= this.world.selectedTile.y && y + this.height < this.world.selectedTile.y + 1; if (wasDecalX != isDecalX) { var t = this.world.rowTranslation / this.world.squareSize; isDecalX && (t = -t), this.x = (this.x + t) % this.world.mainSquare[0].length, x = (x + t) % this.world.mainSquare[0].length } } } var dis = Math.abs(y - this.y); if (!ignoreStep && dis > Config.PHYSICS.MIN_STEP_SIZE && this.onGround) { var diff2, diff1 = y - this.y; diff2 = y > this.y ? y - this.world.getHeight() - this.y : y + this.world.getHeight() - this.y, this.compensateY += Math.abs(diff2) < Math.abs(diff1) ? diff2 : diff1, this.compensateSpeed = this.compensateY * this.getSpeed() * Config.PHYSICS.SLOPE_SPEED_FACTOR / .05 } this.x = x, this.y = y, this.renderX = Math.round(this.world.squareSize * this.x), this.renderY = Math.round(this.world.squareSize * this.y), this.isEgg && (this.eggRenderX = this.renderX, this.eggRenderY = this.renderY), this.shouldFall && (this.shouldFall = !1, this.setSprite("FALL")) }, Entity.prototype.startWin = function(listener, endPoint) { this.winning = !0, this.winEndPointX = endPoint ? endPoint.x : this.x, this.world.goalType == GoalType.CAGE ? this.setSprite("DEATH_CAGE", function() { listener() }) : (this.setSprite("SAVED"), this.winStartTime = this.world.game.timeData.local, this.winEndListener = listener) }, Entity.prototype.hit = function(listener, fromMove) { var self = this; if (!this.world.stopImmunityTime && !this.isEgg && !this.dying && this.lifeCount > 0 && this.world.game.timeData.local > this.minNextHitTime) if (this.lifeCount--, 0 == this.lifeCount) { var deadSound = this.world.game.app.assetManager.getSound("game.death"); if (deadSound.reset().play(), testLevel || this.isEnnemy || !StockManager.stockList[this.config.id] || StockManager.stockList[this.config.id].lost(), this.item && (this.item.setPosition(this.x + (this.revertDirection ? -1 : 1) * this.width / 2, this.y + this.compensateY + this.height / 2), this.item.entity = !1, this.item = !1), this.dying = !0, Achievement.record(DataStore.achievementType.SHORT_LIFE, (this.world.game.timeData.local - this.creationTime) / 1e3), !this.isEnnemy) { Achievement.record(DataStore.achievementType.KILL); for (var lostBuffer = [this.world.game.timeData.local], i = 0; i < this.world.lostBuffer.length; i++) this.world.game.timeData.local - this.world.lostBuffer[i] < Config.ACHIEVEMENT.MULTI_MAX_DELAY && lostBuffer.push(this.world.lostBuffer[i]); if (this.world.lostBuffer = lostBuffer, this.world.lostBuffer.length > 1 && Achievement.record(DataStore.achievementType.MULTI_KILL, this.world.lostBuffer.length), !fromMove) for (var i in this.world.endPointList) if (this.world.endPointList[i].checkAlmostReached(this.x + this.width / 2, this.y)) { Achievement.record(DataStore.achievementType.ALMOST_SAVED); break } } this.stopSpell(), this.world.oneDodoLess(this, this.score, !0), this.setSprite("DEATH", function() { self.destroy(), listener && listener() }) } else this.minNextHitTime = this.world.game.timeData.local + Config.ENTITY.HIT_DELAY, listener && listener() }, Entity.prototype.destroy = function() { this.toDelete = !0 }, Entity.prototype.checkReached = function(e) { var xDis = Math.abs(this.x - e.x), yDis = Math.abs(this.y - e.y); xDis > this.colCount / 2 && (xDis = this.colCount - xDis), yDis > this.rowCount / 2 && (yDis = this.rowCount - yDis); var dis = xDis * xDis + yDis * yDis; return dis < this.width * this.width }, Entity.prototype.checkAlmostReached = function(e) { var xDis = Math.abs(this.x - e.x), yDis = Math.abs(this.y - e.y); xDis > this.colCount / 2 && (xDis = this.colCount - xDis), yDis > this.rowCount / 2 && (yDis = this.rowCount - yDis); var dis = xDis * xDis + yDis * yDis; return dis < this.width * this.width * Config.ACHIEVEMENT.ALMOST_KILLED_FACTOR * Config.ACHIEVEMENT.ALMOST_KILLED_FACTOR }; var GoalType = { SAVE: 1, COLLECT: 2, SURVIVE: 3, CAGE: 4, getIdentifier: function(id) { for (var i in this) if (this[i] == id) return i; return !1 } }, Item = function(world, config) { this.world = world, this.config = config, this.isItem = !0, this.x = config.x, this.y = config.y, this.fallSpeed = Config.PHYSICS.INIT_FALL_SPEED, this.onGround = !1, this.isBumping = !1, this.width = 2 * Config.COLLECT.COLLIDE_SIZE, this.height = 2 * Config.COLLECT.COLLIDE_SIZE, this.fallFromMovingTileCheck = 0, this.entity = !1 }; Item.APPARITION_DELAY = 3e3, Item.APPARITION_DURATION = 250, Item.prototype.init = function(index) { this.image = App.instance.assetManager.getAtlasImage("gui.game.item"), this.ratio = this.image.width / this.image.height, this.apparitionTime = Item.APPARITION_DELAY + index * Item.APPARITION_DURATION, this.onResize() }, Item.prototype.getSpeed = function() { return 0 }, Item.prototype.isOnMovingTile = function() { return this.currentTile && this.currentTile.parentTile }, Item.prototype.onResize = function() { this.image && (this.renderHeight = .9 * Config.COLLECT.SIZE * this.world.squareSize, this.scale = this.renderHeight / this.image.height, this.renderDecalY = 0, this.refreshPosition()) }, Item.prototype.setOnGround = function(b) { this.onGround = b, this.onGround ? this.isBumping = !1 : 0 == this.fallSpeed && (this.fallSpeed = Config.PHYSICS.INIT_FALL_SPEED) }, Item.prototype.setPosition = function(x, y) { this.x = x, this.y = y, this.refreshPosition() }, Item.prototype.refreshPosition = function() { this.renderX = Math.round(this.x * this.world.squareSize), this.renderY = Math.round((this.y + .04) * this.world.squareSize) + this.renderDecalY }, Item.prototype.render = function(g) { if (g.timeData.local > this.apparitionTime) { g.save(); var x = (this.renderX + this.xTranslation + this.world.worldWidth) % this.world.worldWidth, y = (this.renderY + this.yTranslation + this.world.worldHeight) % this.world.worldHeight; g.translate(x, y), this.renderAtOrigin(g), g.restore() } }, Item.prototype.renderAtOrigin = function(g) { g.save(); var s = this.scale; if (g.timeData.local < this.apparitionTime + Item.APPARITION_DURATION) { this.soundPlayed || (this.world.game.assetManager.getSound("game.new-egg").reset().play(), this.soundPlayed = !0); var f = (g.timeData.local - this.apparitionTime) / Item.APPARITION_DURATION; g.globalAlpha = Math.easeOutCubic(f), s *= Math.easeOutBack(f, 2.5) } g.scale(s, s), this.image.render(g, -Math.round(this.image.width / 2), -Math.round(this.image.height / 2)), g.restore(), Debug.ENTITY && (g.translate(0, -this.renderDecalY), g.fillStyle = "rgba(255, 255, 0, 0.5)", g.fillCircle(this.x, this.y, Config.COLLECT.COLLIDE_SIZE * this.world.squareSize)) }, Item.prototype.checkReached = function(x, y) { return Math.abs((x - this.x) * (x - this.x) + (y - this.y) * (y - this.y)) <= Math.pow(Config.COLLECT.COLLIDE_SIZE, 2) }, Item.prototype.isInterpolating = function() { return !1 }, Item.prototype.update = function(timeData) { this.onGround && Entity.prototype.updateOnGround.call(this, timeData) }, Item.prototype.bump = function() { this.fallSpeed = -Config.PHYSICS.BUMP_IMPULSE, this.isBumping = !0, this.onGround = !1 }; var PopScore = function(value, timeData) { this.value = value, this.popTime = timeData.local, this.alpha = 1 }; PopScore.prototype.dispose = function() { this.canvas && (this.canvas.dispose(), this.canvas = !1) }, PopScore.prototype.render = function(g) { var f = (g.timeData.local - this.popTime) / Config.SCORE.FX_DURATION; f > 1 && (f = 1), this.alpha = 1 - Math.easeOutCubic(f), g.save(), g.globalAlpha = this.alpha; var scale = 1 + .5 * (1 - this.alpha); if (g.scale(scale, scale), g.translate(0, 20 * (1 - this.alpha)), !this.canvas) { this.canvas = Utils.createCanvas(), this.canvas.width = 128, this.canvas.height = 64; var g2 = this.canvas.getContext("2d"); app.setBaseFont(g2, 40), g2.textAlign = "center", g2.textBaseline = "middle", app.fillOutlineText(g2, "+" + this.value, Math.round(this.canvas.width / 2), Math.round(this.canvas.height / 2)) } g.drawImage(this.canvas, -Math.round(this.canvas.width / 2), -160), g.restore() }; var ProgressBar = function(game, assetManager) { this.chronoDuration = !1, this.value = 0, this.goal1 = 0, this.goal2 = 0, this.goal3 = 0, this.starCount = 0, this.game = game, this.assetManager = assetManager, this.setValue(0, !0), this.needRefresh = !0, this.badIndicator = this.assetManager.getAtlasImage("gui.game.bar-indicator-bad"), this.indicator = this.assetManager.getAtlasImage("gui.game.bar-indicator"), this.frame = this.assetManager.getAtlasImage("gui.game.bar-frame"), this.starMark = this.assetManager.getAtlasImage("gui.game.star-mark"), this.star = this.assetManager.getAtlasImage("gui.common.star"), this.dodoIndicator = this.assetManager.getAtlasImage("gui.game.dodo-head") }; ProgressBar.PROGRESS_BAR_0 = .05, ProgressBar.PROGRESS_BAR_1 = .2, ProgressBar.PROGRESS_BAR_2 = .5, ProgressBar.PROGRESS_BAR_3 = .9, ProgressBar.POSITION_LIST = [ProgressBar.PROGRESS_BAR_0, ProgressBar.PROGRESS_BAR_1, ProgressBar.PROGRESS_BAR_2, ProgressBar.PROGRESS_BAR_3], ProgressBar.prototype.declareNewDodo = function() { this.initialDodoCount++, this.initialValueCount++, this.remainingDodos++, this.needRefresh = !0 }, ProgressBar.prototype.declareEntityScore = function(score) { this.initialValueCount += score - 1 }, ProgressBar.prototype.addValue = function(amount) { amount || (amount = 1), this.setValue(this.value + amount, !1) }, ProgressBar.prototype.setValue = function(value, force) { if (this.value != value || force) { if (this.value = value, !this.chronoDuration && this.value > 0 && (this.value >= this.goal3 ? this.starCount = 3 : this.value >= this.goal2 ? this.starCount = 2 : this.value >= this.goal1 && (this.starCount = 1)), this.lastProgress = this.progress, this.chronoDuration) this.isBad = this.value <= 5, this.progress = this.value / this.chronoDuration * (1 - ProgressBar.PROGRESS_BAR_0) + ProgressBar.PROGRESS_BAR_0; else if (this.isBad = this.value < this.goal1, this.value >= this.goal3) { var total = this.initialValueCount - this.goal3; this.progress = total ? (this.value - this.goal3) / total * (1 - ProgressBar.PROGRESS_BAR_3) + ProgressBar.PROGRESS_BAR_3 : ProgressBar.PROGRESS_BAR_3 } else this.progress = this.value >= this.goal2 ? (this.value - this.goal2) / (this.goal3 - this.goal2) * (ProgressBar.PROGRESS_BAR_3 - ProgressBar.PROGRESS_BAR_2) + ProgressBar.PROGRESS_BAR_2 : this.value >= this.goal1 ? (this.value - this.goal1) / (this.goal2 - this.goal1) * (ProgressBar.PROGRESS_BAR_2 - ProgressBar.PROGRESS_BAR_1) + ProgressBar.PROGRESS_BAR_1 : this.value / this.goal1 * (ProgressBar.PROGRESS_BAR_1 - ProgressBar.PROGRESS_BAR_0) + ProgressBar.PROGRESS_BAR_0; this.refreshTime = this.game.timeData.global, this.chronoDuration && (this.value > 5 ? this.value % 2 ? this.game.app.assetManager.getSound("game.chrono-tac").reset().play() : this.game.app.assetManager.getSound("game.chrono-tic").reset().play() : 5 == this.value && this.game.app.assetManager.getSound("game.chrono-end").reset().playLoop(), 0 == this.value && (this.chronoDuration = !1, this.game.world.onChronoEnd())) } }, ProgressBar.prototype.oneDodoLess = function() { this.remainingDodos--, this.remainingDodos < 0 && (console.log("[ERROR] Trying to remove a unknown dodo !"), this.remainingDodos = 0), this.needRefresh = !0 }, ProgressBar.prototype.setChrono = function(duration) { this.chronoDuration = duration }, ProgressBar.prototype.init = function(initialDodoCount, goal1, goal2, goal3) { this.initialDodoCount = initialDodoCount, this.initialValueCount = this.initialDodoCount, this.remainingDodos = this.initialDodoCount, this.goal1 = goal1, this.goal2 = goal2, this.goal3 = goal3, this.progress = 0, this.starCount = 0, this.chronoDuration ? this.setValue(this.chronoDuration, !0) : this.setValue(0, !0) }, ProgressBar.prototype.render = function(g, force) { var duration = 350; if (force || g.timeData.global < this.refreshTime + 1.1 * duration || this.needRefresh) { g.save(); var f = 1; !force && g.timeData.global <= this.refreshTime + duration && (f = (g.timeData.global - this.refreshTime) / duration), 0 > f ? f = 0 : f > 1 && (f = 1), ButtonUtils.renderBackground({ g: g, bgActiveScale: 1, background: this.game.menuBackground, backgroundX: Math.round(g.width - this.game.screenDecal / 2 - this.game.menuBackgroundWidth * app.scale / 2), backgroundY: 0, backgroundWidth: this.game.menuBackgroundWidth, backgroundHeight: this.game.menuBackgroundHeight, width: this.frame.width + 50, height: 470 }, Math.round(g.width - this.game.screenDecal / 2), Math.round(385 * app.scale)), g.translate(0, 150), g.textAlign = "center", g.testBaseline = "middle", g.save(), g.translate(-Math.round(this.indicator.width / 2), 80); var lastHeight = Math.round(this.lastProgress * this.indicator.height), newHeight = Math.round(this.progress * this.indicator.height), height = (newHeight - lastHeight) * Math.easeOutQuad(f) + lastHeight; if (g.fillStyle = "rgba(0, 0, 0, 0.5)", g.fillRect(0, 0, this.indicator.width, this.indicator.height), !this.chronoDuration) { g.strokeStyle = "black", g.lineWidth = 2, g.beginPath(); for (var i = 1; i < ProgressBar.POSITION_LIST.length; i++) g.moveTo(0, (1 - ProgressBar.POSITION_LIST[i]) * this.indicator.height), g.lineTo(this.indicator.width, (1 - ProgressBar.POSITION_LIST[i]) * this.indicator.height); g.stroke(), g.closePath(), g.save(), this.game.app.setBaseFont(g, 24), g.globalAlpha = .5; for (var i = 1; i < ProgressBar.POSITION_LIST.length; i++) g.save(), g.translate(Math.round(this.indicator.width / 2), (1 - ProgressBar.POSITION_LIST[i]) * this.indicator.height + 5), g.strokeText(this["goal" + i], 0, 0), g.fillText(this["goal" + i], 0, 0), g.restore(); g.restore() } if (this.isBad ? this.badIndicator.render(g, 0, 0, this.indicator.width, height, 0, this.indicator.height - height, this.indicator.width, height) : this.indicator.render(g, 0, 0, this.indicator.width, height, 0, this.indicator.height - height, this.indicator.width, height), g.restore(), this.frame.render(g, -Math.round(this.frame.width / 2), 0), !this.chronoDuration) for (var i = 1; i < ProgressBar.POSITION_LIST.length; i++) { if (g.save(), g.translate(15, (1 - ProgressBar.POSITION_LIST[i]) * this.indicator.height + 75), this.starMark.render(g, 0, 0), g.translate(10 + Math.round(this.star.width / 4), 0), this.value == this["goal" + i]) { var scaleEffect = .75, scale = 1 + Math.easeOutCirc(Math.tweenBack(f, .5)) * scaleEffect; g.scale(scale, scale) } this.star.render(g, this.value >= this["goal" + i] ? Math.round(this.star.width / 2) : 0, 0, Math.round(this.star.width / 2), this.star.height, -Math.round(this.star.width / 4), -13, Math.round(this.star.width / 2), this.star.height), g.restore() } g.save(), this.game.world.goalType == GoalType.SAVE ? this.dodoIndicator.render(g, this.starCount * this.dodoIndicator.width / 4, 0, this.dodoIndicator.width / 4, this.dodoIndicator.height, -Math.round(this.game.goalTypeWidth / 2) - 6, -15, this.dodoIndicator.width / 4, this.dodoIndicator.height) : (g.scale(.8, .8), this.game.renderGoalType(g, this.game.getLevelGoalType(this.game.currentLevel), -Math.round(this.game.goalTypeWidth / 2) - 3, -12)), g.restore(), this.game.app.setBaseFont(g, 35), g.save(), g.translate(0, 88 + this.indicator.height - height); var scaleEffect = .75, scale = 1 + Math.easeOutQuad(Math.tweenBack(Math.min(1, 1.5 * f), .5)) * scaleEffect; g.scale(scale, scale), g.strokeText(this.value, 0, 0), g.fillText(this.value, 0, 0), g.restore(), this.game.app.setBaseFont(g, 50), g.textAlign = "center", g.testBaseline = "middle", g.translate(0, 515), g.strokeText(this.remainingDodos, 0, 0), g.fillText(this.remainingDodos, 0, 0), g.restore(), this.needRefresh = !1 } }; var Spell = { CHARGE: 1, STUN: 2, KILL: 3 }, SpellTarget = { SELF: 1, RANDOM: 2, ALL: 3, AROUND: 4 }, StartPoint = function(world, config) { this.world = world, this.config = config, this.lastPop = 0, this.x = config.x, this.y = config.y, this.invert = config.invert, this.startPopCount = this.config.popCount, this.popCount = this.startPopCount, this.popDelay = this.config.popDelay, this.popStartDelay = this.config.popStartDelay + Config.START_POINT.FADE_IN_DURATION + Config.START_POINT.FADE_IN_DELAY, this.ennemy = this.config.ennemy, this.alpha = .001, this.readyTime = 0, this.ratio = 1, this.apparitionTime = this.config.popStartDelay + Config.START_POINT.FADE_IN_DELAY }; StartPoint.prototype.init = function() { this.sprite = this.ennemy ? this.world.createFxSprite("ENNEMY_PORTAL") : this.world.createFxSprite("PORTAL") }, StartPoint.prototype.isReady = function() { return 1 == this.alpha }, StartPoint.prototype.spawnDodo = function(dodoType) { this.isReady() || (this.alpha = 1), this.lastPop = this.world.game.timeData.local, this.world.createEntity(this.x, this.y, !1, this.invert, DataStore.dodoTypeList[dodoType]), this.world.declareNewDodo() }, StartPoint.prototype.update = function(timeData) { if (timeData.local > this.popStartDelay && this.popCount > 0 && (!this.lastPop || this.lastPop && timeData.local > this.lastPop + this.popDelay)) { var entityData; if (this.ennemy) entityData = this.world.worldConfig.ennemyData; else { var dodoType = testLevel ? Config.GENERAL.DEFAULT_DODO_TYPE : StockManager.getAvailableDodoType(); dodoType || (dodoType = Config.GENERAL.DEFAULT_DODO_TYPE), "undefined" != typeof Debug.DODO_TYPE && Debug.DODO_TYPE > 0 && (dodoType = Debug.DODO_TYPE), entityData = DataStore.dodoTypeList[dodoType] } this.world.createEntity(this.x, this.y, this.ennemy, this.invert, entityData), this.lastPop = timeData.local, this.popCount-- } }, StartPoint.prototype.getTotalDodoCount = function() { return this.ennemy ? 0 : this.startPopCount }, StartPoint.prototype.onResize = function() { this.renderHeight = 1.5 * Config.START_POINT.SIZE * this.world.squareSize, this.renderWidth = this.renderHeight * this.ratio, this.renderX = Math.round(this.x * this.world.squareSize), this.renderY = Math.round(this.y * this.world.squareSize) }, StartPoint.prototype.render = function(g) { if (this.alpha > 0 && g.timeData.local > this.apparitionTime) { this.soundPlayed || (this.soundPlayed = !0, this.world.game.app.assetManager.getSound("game.apparition-portal").reset().play()), g.save(), g.translate(this.renderX, this.renderY), g.save(), g.translate(0, -.05 * this.renderHeight), g.scale(1, .3), 0 == this.popCount && g.timeData.local > this.lastPop + Config.START_POINT.FADE_OUT_DELAY ? (this.alpha -= g.timeData.localDelta * Config.START_POINT.FADE_OUT_SPEED, this.alpha < 0 && (this.alpha = 0, this.world.game.app.assetManager.getSound("game.apparition-portal").pause())) : this.popCount > 0 && 1 != this.alpha && (this.alpha += g.timeData.localDelta * Config.START_POINT.FADE_IN_SPEED, this.alpha >= 1 && (this.alpha = 1)); var f = this.alpha; f = 0 == this.popCount ? Math.easeOutElastic(this.alpha) : Math.easeOutElastic(this.alpha), g.globalAlpha = f, g.globalAlpha > 1 && (g.globalAlpha = 1), g.scale(f, f), g.rotate(2 * g.timeData.local * Config.START_POINT.ROTATE_SPEED * Math.PI / 1e3), g.translate(-this.renderWidth / 2, -this.renderHeight / 2), this.sprite.render(g, this.renderWidth, this.renderHeight), g.restore(), Debug.ENTITY && (g.globalAlpha = 1, g.fillStyle = this.ennemy ? "rgba(255, 0, 0, 0.5)" : "rgba(0, 255, 0, 0.5)", g.fillCircle(this.x, this.y, 10)), g.restore() } }; var Tile = function(world, data) { if (this.world = world, this.data = data, this.hasTrap = !1, this.data) { var tileId = data.tile.id; data.tile.extends_tile && (tileId = data.tile.extends_tile), this.tileId = "tile-" + tileId, this.ldId = "tile-ld-" + data.id, this.invert = this.data.invert, this.world.assetManager.addImage(this.tileId, WEB_DATA_URI + "img/tiles/" + data.graphic_template + "/" + tileId + ".png"), Debug.TILE && this.world.assetManager.addImage(this.ldId, WEB_DATA_URI + "img/tiles/" + data.id + ".png"), this.grid = this.data.tile.data; var newGrid = []; for (var y in this.grid) { var line = this.grid[y], newLine = []; if (this.invert) for (var x = line.length - 1; x >= 0; x--) newLine.push(line[x]); else for (var x = 0; x < line.length; x++) newLine.push(line[x]); newGrid.push(newLine) } this.grid = newGrid; for (var y in this.grid) for (var line = this.grid[y], x = line.length - 1; x >= 0; x--)(line[x] == Tile.groundType.TRAP || line[x] == Tile.groundType.TRAP_WALL_LEFT || line[x] == Tile.groundType.TRAP_WALL_RIGHT) && (this.hasTrap = !0); if (this.data.tile.moving_tile) { var tileData = { tile: tiles[this.data.tile.moving_tile], invert: this.invert, id: this.data.tile.moving_tile, world: this.world, graphic_template: this.data.graphic_template, name: "tile " + this.data.tile.moving_tile }; this.movingTile = new Tile(this.world, tileData), this.movingTile.parentTile = this } } else this.invert = !1, this.image = !1, this.grid = [ [0] ]; this.selected = !1, this.bumpList = [], this.trapList = [] }; Tile.groundType = { EMPTY: 0, BASIC: 1, TRAP: 2, BUMP: 3, TRAP_WALL_LEFT: 4, TRAP_WALL_RIGHT: 5, MOVING_TILE_START: 6, MOVING_TILE_END: 7 }, Tile.prototype.init = function() { if (this.data) { this.tileFactor = this.parentTile ? 1 / Config.GRAPHICS.MOVING_TILE_SIZE : 1, this.ldImage = this.world.assetManager.getImage("tile-ld-" + this.data.id), this.image = this.world.assetManager.getImage(this.tileId), this.trapImage = this.world.assetManager.getImage("trap"), this.trapHeight = this.trapImage.height * Config.TRAP.GROUND_WIDTH / this.trapImage.width * this.tileFactor, this.trapWallImage = this.world.assetManager.getImage("trap-wall"), this.trapWallHeight = this.trapWallImage.height * Config.TRAP.WALL_WIDTH / this.trapWallImage.width * this.tileFactor, this.bumpImage = this.world.bumpSpriteImage; var bumper = new Sprite(this.bumpImage, this.world.bumpFrameCount, 1, !1); this.bumperHeight = bumper.height * Config.BUMP.WIDTH / bumper.width * this.tileFactor; for (var squareWidth = 1 / this.grid[0].length, y = 0; y < this.grid.length; y++) for (var line = this.grid[y], xStart = !1, xEnd = !1, relY = y / this.grid.length, typeStart = !1, x = 0; x < line.length; x++) { var relX = x / line.length, effectType = this.grid[y][x]; if (effectType <= Tile.groundType.BASIC) effectType = !1; else { if (this.movingTile && effectType == Tile.groundType.MOVING_TILE_START) { this.movingTile.moveStartPoint = { x: this.invert ? -Config.GRAPHICS.MOVING_TILE_SIZE + squareWidth + relX : relX, y: relY - Config.GRAPHICS.MOVING_TILE_SIZE + squareWidth }, this.grid[y][x] = Tile.groundType.EMPTY; continue } if (this.movingTile && effectType == Tile.groundType.MOVING_TILE_END) { this.movingTile.moveEndPoint = { x: this.invert ? -Config.GRAPHICS.MOVING_TILE_SIZE + squareWidth + relX : relX, y: relY - Config.GRAPHICS.MOVING_TILE_SIZE + squareWidth }, this.grid[y][x] = Tile.groundType.EMPTY; continue } } if (xStart !== !1 && effectType != typeStart) { xEnd = relX; var itemWidth, itemMargin = 0; typeStart == Tile.groundType.BUMP ? itemWidth = Config.BUMP.WIDTH : typeStart == Tile.groundType.TRAP && (itemWidth = Config.TRAP.GROUND_WIDTH), itemWidth *= this.tileFactor, xStart -= 2 * itemMargin; for (var zoneWidth = xEnd - xStart, count = Math.ceil(zoneWidth / itemWidth), margin = (itemWidth * count - zoneWidth) / 2, i = 0; count > i; i++) typeStart == Tile.groundType.BUMP ? this.bumpList.push({ zoneWidth: zoneWidth, x: xStart + (i * itemWidth - margin) * (this.invert ? -1 : 1), y: relY + Config.BUMP.DECAL_Y * this.bumperHeight, sprite: new Sprite(this.bumpImage, this.world.bumpFrameCount, 1, !1) }) : typeStart == Tile.groundType.TRAP && this.trapList.push({ zoneWidth: zoneWidth, x: xStart + (i * itemWidth - margin) * (this.invert ? -1 : 1), y: relY + Config.TRAP.DECAL_Y * this.trapHeight, type: typeStart }); xStart = !1 } xStart !== !1 || effectType != Tile.groundType.BUMP && effectType != Tile.groundType.TRAP || (xStart = relX, typeStart = effectType) } for (var x = 0; x < this.grid[0].length; x++) for (var relX = x / this.grid[0].length, typeStart = !1, y = 0; y < this.grid.length; y++) { var relY = y / this.grid.length, effectType = this.grid[y][x]; effectType != typeStart && ((effectType == Tile.groundType.TRAP_WALL_LEFT || effectType == Tile.groundType.TRAP_WALL_RIGHT) && this.trapList.push({ zoneWidth: squareWidth, x: relX + (effectType == Tile.groundType.TRAP_WALL_LEFT ? 0 : this.invert ? -squareWidth : squareWidth), y: relY, type: effectType }), typeStart = effectType) } if (this.invert) { for (var i in this.trapList) this.trapList[i].x = 1 - this.trapList[i].x - this.trapList[i].zoneWidth; for (var i in this.bumpList) this.bumpList[i].x = 1 - this.bumpList[i].x - this.bumpList[i].zoneWidth } this.movingTile && this.movingTile.moveStartPoint && this.movingTile.moveEndPoint && this.movingTile.init(), this.parentTile ? this.setPosition(this.moveEndPoint.x, this.moveEndPoint.y) : (this.apparitionTime = (this.y * this.world.mainSquare.length + this.x) * Config.GRAPHICS.TILE_FADE_IN_DELAY_FACTOR, this.apparitionCompleteTime = this.apparitionTime + Config.GRAPHICS.TILE_FADE_IN_DURATION) } this.onResize() }, Tile.prototype.onResize = function() { this.size = this.world.squareSize * (this.parentTile ? Config.GRAPHICS.MOVING_TILE_SIZE : 1), this.movingTile && this.movingTile.onResize() }, Tile.prototype.drawGrid = function() { var s = ""; for (var y in this.grid) { for (var x in this.grid[y]) s += "[" + this.grid[y][x] + "]"; s += "\n" } console.log(s) }, Tile.prototype.setSelected = function(b) { this.selected = b }, Tile.prototype.getTileAt = function(x, y) { var ground = !1; return this.movingTile && (ground = this.movingTile.getGroundTypeAt((x - this.movingTile.x) / Config.GRAPHICS.MOVING_TILE_SIZE, (y - this.movingTile.y) / Config.GRAPHICS.MOVING_TILE_SIZE), ground != Tile.groundType.EMPTY) ? this.movingTile : this }, Tile.prototype.getGroundTypeAt = function(x, y, debug) { if (debug && console.log("ground : " + x + "," + y + " = " + Math.floor(x * this.grid[0].length) + "/" + Math.floor(y * this.grid.length) + " : " + this.grid[Math.floor(y * this.grid.length)][Math.floor(x * this.grid[0].length)]), 0 > x || x >= 1 || 0 > y || y >= 1) return Tile.groundType.EMPTY; var ground = !1; return this.movingTile && (ground = this.movingTile.getGroundTypeAt((x - this.movingTile.x) / Config.GRAPHICS.MOVING_TILE_SIZE, (y - this.movingTile.y) / Config.GRAPHICS.MOVING_TILE_SIZE, debug)), ground && ground != Tile.groundType.EMPTY || (ground = this.grid[Math.floor(y * this.grid.length)][Math.floor(x * this.grid[0].length)]), ground }, Tile.prototype.getLeftEdge = function(x) { return Math.floor(x * this.grid[0].length) / this.grid[0].length - GameScreen.EPSILON }, Tile.prototype.getRightEdge = function(x) { return Math.ceil(x * this.grid[0].length) / this.grid[0].length + GameScreen.EPSILON }, Tile.prototype.getTopEdge = function(x, y) { return Math.floor(y * this.grid.length) / this.grid.length - GameScreen.EPSILON }, Tile.prototype.getBottomEdge = function(x, y) { return Math.ceil(y * this.grid.length) / this.grid.length + GameScreen.EPSILON }, Tile.prototype.toString = function() { return "Tile " + this.data.id + " (" + this.x + "," + this.y + ")" }, Tile.prototype.vRayHit = function(entity, x, y1, y2, timeData) { if (timeData.local > entity.fallFromMovingTileCheck && this.movingTile && x >= this.movingTile.x && x <= this.movingTile.x + Config.GRAPHICS.MOVING_TILE_SIZE && (y1 >= this.movingTile.y && y1 <= this.movingTile.y + Config.GRAPHICS.MOVING_TILE_SIZE || y2 >= this.movingTile.y && y2 <= this.movingTile.y + Config.GRAPHICS.MOVING_TILE_SIZE)) { var hit = this.movingTile.vRayHit(entity, (x - this.movingTile.x) / Config.GRAPHICS.MOVING_TILE_SIZE, Math.max(0, Math.min(1, y1 - this.movingTile.y)) / Config.GRAPHICS.MOVING_TILE_SIZE, Math.max(0, Math.min(1, y2 - this.movingTile.y)) / Config.GRAPHICS.MOVING_TILE_SIZE, timeData); if (hit) return hit.pos = hit.pos * Config.GRAPHICS.MOVING_TILE_SIZE + this.movingTile.y, hit } y1 = Math.max(0, Math.min(1 - GameScreen.EPSILON, y1)), y2 = Math.max(0, Math.min(1 - GameScreen.EPSILON, y2)); for (var from = Math.floor(y1 * this.grid.length), to = Math.floor(y2 * this.grid.length), x = Math.floor(x * this.grid[0].length), y = from; to >= y; y++) if (this.grid[y][x]) return { pos: y / this.grid.length - GameScreen.EPSILON, type: this.grid[y][x] }; return !1 }, Tile.prototype.setPosition = function(x, y) { this.lastX = this.x, this.lastY = this.y, this.x = x, this.y = y, this.lastMoveX = this.x - this.lastX, this.lastMoveY = this.y - this.lastY }, Tile.prototype.bump = function(x, y) { var minDis = !1, minBump = !1; this.invert && (x = 1 - x); for (var i in this.bumpList) { var bump = this.bumpList[i], dis = Math.pow(x - (bump.x + Config.BUMP.WIDTH / 2), 2) + Math.pow(y - (bump.y + Config.BUMP.WIDTH / 2), 2); (minDis > dis || minDis === !1) && (minDis = dis, minBump = bump) } minBump ? minBump.sprite.currentFrame = 0 : this.movingTile && this.movingTile.bump(x, y) }, Tile.prototype.update = function(timeData) { if (this.movingTile && this.movingTile.update(timeData), this.parentTile) { var f = Math.cycleSin(timeData.local, 2 * (Config.MOVING_TILE.MOVE_DURATION + Config.MOVING_TILE.PAUSE_DURATION)), limit = Config.MOVING_TILE.PAUSE_DURATION / (Config.MOVING_TILE.MOVE_DURATION + Config.MOVING_TILE.PAUSE_DURATION) / 2; f > limit && 1 - limit > f && (f = Math.easeInOutSine((f - limit) / (1 - 2 * limit)), this.setPosition((this.moveEndPoint.x - this.moveStartPoint.x) * f + this.moveStartPoint.x, (this.moveEndPoint.y - this.moveStartPoint.y) * f + this.moveStartPoint.y)) } }, Tile.prototype.render = function(g, pass) { if (g.save(), this.parentTile) g.translate(this.x * this.parentTile.size, this.y * this.parentTile.size), this.renderAtOrigin(g); else { var roomX = (this.x * this.size + this.xTranslation + this.world.worldWidth) % this.world.worldWidth, roomY = (this.y * this.size + this.yTranslation + this.world.worldHeight) % this.world.worldHeight; g.translate(roomX, roomY), 1 == pass && this.renderAtOrigin(g), roomX + this.size > this.world.worldWidth && (g.save(), 1 == pass && (g.translate(-this.world.worldWidth, 0), this.renderAtOrigin(g)), 2 == pass && roomY + 2 * this.size > this.world.worldHeight && (g.translate(0, -this.world.worldHeight), this.renderAtOrigin(g), g.translate(-this.world.worldWidth, 0), this.renderAtOrigin(g)), g.restore()), 2 == pass && roomY + 2 * this.size > this.world.worldHeight ? (g.save(), g.translate(0, -this.world.worldHeight), this.renderAtOrigin(g), g.restore()) : 0 == pass && roomY < this.size && (g.save(), g.translate(0, this.world.worldHeight), this.renderAtOrigin(g), g.restore()) } g.restore() }, Tile.prototype.renderAtOrigin = function(g) { if (!(g.timeData.local < this.apparitionTime)) { if (this.parentTile || ((this.world.movingRow && this.world.selectedTile.y == this.y || this.world.movingCol && this.world.selectedTile.x == this.x || this.world.selectedTile == this) && (g.fillStyle = "rgba(255, 255, 255, 0.25)", g.fillRect(0, 0, this.size, this.size)), this.selected ? (g.strokeStyle = "rgba(0, 0, 0, 0.25)", g.lineWidth = 1, g.strokeRect(0, 0, this.size, this.size)) : this.world.dragging && (g.strokeStyle = "rgba(0,0,0, 0.25)", g.lineWidth = 1, g.strokeRect(0, 0, this.size, this.size))), this.invert && (g.save(), g.translate(this.size, 0), g.scale(-1, 1)), g.timeData.local < this.apparitionCompleteTime) { var f = Math.easeOutBack((g.timeData.local - this.apparitionTime) / Config.GRAPHICS.TILE_FADE_IN_DURATION); g.globalAlpha = f, g.translate(0, Math.round(-this.image.height / 2 * (1 - f))) } if (this.image && this.image.complete) { var margin = Config.GRAPHICS.TILE_MARGIN * this.size; try { g.drawImage(this.image, -Math.round(margin), -Math.round(margin), Math.round(this.size + 2 * margin), Math.round(this.size + 2 * margin)) } catch (e) {} } for (var i in this.trapList) { var trap = this.trapList[i]; switch (g.save(), g.translate(Math.round(trap.x * this.size), Math.round(trap.y * this.size)), trap.type) { case Tile.groundType.TRAP: g.scale(Config.TRAP.GROUND_WIDTH * this.size / this.trapImage.width * this.tileFactor, this.trapHeight * this.size / this.trapImage.height), g.drawImage(this.trapImage, 0, -this.trapImage.height); break; case Tile.groundType.TRAP_WALL_LEFT: g.scale(Config.TRAP.WALL_WIDTH * this.size / this.trapWallImage.width * this.tileFactor, this.trapWallHeight * this.size / this.trapWallImage.height), g.drawImage(this.trapWallImage, Math.round(Config.TRAP.WALL_DECAL_X * this.trapWallImage.width), Math.round(Config.TRAP.WALL_DECAL_Y * this.trapWallImage.height)); break; case Tile.groundType.TRAP_WALL_RIGHT: g.scale(-Config.TRAP.WALL_WIDTH * this.size / this.trapWallImage.width * this.tileFactor, this.trapWallHeight * this.size / this.trapWallImage.height), g.drawImage(this.trapWallImage, Math.round(Config.TRAP.WALL_DECAL_X * this.trapWallImage.width), Math.round(Config.TRAP.WALL_DECAL_Y * this.trapWallImage.height)) } g.restore() } for (var i in this.bumpList) { var bump = this.bumpList[i]; g.save(), g.translate(Math.round(bump.x * this.size), Math.round(bump.y * this.size)), bump.sprite.render(g, Math.round(Config.BUMP.WIDTH * this.size * this.tileFactor), Math.round(this.bumperHeight * this.size)), g.restore() } Debug.TILE && (g.globalAlpha = .25, this.ldImage ? g.drawImage(this.ldImage, 0, 0, this.size, this.size) : (g.fillStyle = "white", g.fillRect(0, 0, this.size, this.size)), g.globalAlpha = 1), this.invert && g.restore(), this.movingTile && this.movingTile.render(g) } }; var World = function(game, worldConfig, levelConfig) { var self = this; if (this.currentFrame = 0, this.game = game, this.worldConfig = worldConfig, this.config = levelConfig, this.dragging = !1, this.finished = !1, this.score = 0, this.lastScore = 0, this.mainSquare = [], this.goalType = this.game.getLevelGoalType(levelConfig), this.winBuffer = [], this.lostBuffer = [], this.tileMoveTrackBuffer = [], this.lastActionTime = 0, worldConfig) { this.defaultDodoType = this.config.dodoType ? this.config.dodoType : Config.GENERAL.DEFAULT_DODO_TYPE, this.tutoVertical = !1, this.tutoHorizontal = !1, this.config.id == Config.TUTO.START_LEVEL && (this.tutoHorizontal = !0), this.tutoHorizontalTile = !1, this.tutoVerticalTile = this.config.id == Config.TUTO.TILE_LEVEL ? !0 : !1, this.game.setBonusEnabled("freeze", !1), this.assetManager = new AssetManager(this.game.app.assetManager), this.assetManager.addImage("world-background-" + this.worldConfig.graphic_template, WEB_DATA_URI + "img/world/background-" + this.worldConfig.graphic_template + ".jpg"), this.assetManager.addImage("tile-" + Config.TUTO.BASE_TILE, WEB_DATA_URI + "img/tiles/" + this.config.graphic_template + "/" + Config.TUTO.BASE_TILE + ".png"), this.assetManager.addImage("trap", WEB_DATA_URI + "img/world/trap-" + this.config.graphic_template + ".png"), this.assetManager.addImage("trap-wall", WEB_DATA_URI + "img/world/trap-wall-" + this.config.graphic_template + ".png"), this.assetManager.addImage("bump", WEB_DATA_URI + "img/world/bump-" + this.config.graphic_template + ".png"), this.assetManager.addImage("exit", WEB_DATA_URI + "img/world/exit-" + this.config.graphic_template + ".png"), this.assetManager.addImage("defeat-sprite", WEB_DATA_URI + "img/world/defeat-sprite-" + this.config.graphic_template + ".png"), this.worldConfig.ennemyData.spell_frame_count && this.assetManager.addImage("spell-sprite", WEB_DATA_URI + "img/world-opti/spell-sprite-" + this.config.graphic_template + ".png"), this.assetManager.addSound("music", WEB_DATA_URI + "sound/world/music-" + this.config.graphic_template + AssetManager.SOUND_FILE_FORMAT); for (var a in DataStore.animationList) { var anim = DataStore.animationList[a]; anim.dodo_only || this.assetManager.addImage("ennemy-" + anim.identifier, WEB_DATA_URI + "img/ennemies-opti/" + this.config.graphic_template + "-" + a + ".png") } for (var i in DataStore.bonusList) { var b = DataStore.bonusList[i]; b.isFree = b.tuto_level == this.config.id, this.game.refreshBonusCount(i) } this.assetManager.addLoadingListener(function() { self.game.onWorldLoaded() }), this.hasTrap = !1; for (var y in this.config.startSquare) { var line = []; for (var x in this.config.startSquare[y]) { var tileData = this.config.startSquare[y][x]; tileData && (tileData = { tile: tiles[Math.abs(tileData)], invert: 0 > tileData, id: Math.abs(tileData), world: this.config.world, graphic_template: this.config.graphic_template, name: "tile " + tileData }); var tile = new Tile(this, tileData); tile.hasTrap && (this.hasTrap = !0), tile.setPosition(parseInt(x), parseInt(y)), line.push(tile) } this.mainSquare.push(line) } this.colCount = this.mainSquare[0].length, this.rowCount = this.mainSquare.length, this.game.setBonusEnabled("immune", this.hasTrap); var initialDodoCount = 0; this.startPointList = []; for (var i in this.config.startPoints) { var startPoint = new StartPoint(this, this.config.startPoints[i]); this.startPointList.push(startPoint), initialDodoCount += startPoint.getTotalDodoCount() } if (this.goalType == GoalType.SURVIVE && Config.GENERAL.SURVIVE_FIXED_TIME ? this.game.progressBar.setChrono(this.config.duration) : this.game.progressBar.setChrono(!1), this.game.progressBar.init(initialDodoCount, this.config.goal1, this.config.goal2, this.config.goal3), this.endPointList = [], this.goalType != GoalType.SURVIVE) for (var i in this.config.endPoints) this.endPointList.push(new EndPoint(this, this.config.endPoints[i], i)); if (this.checkPortalBonus(), this.itemList = [], this.goalType == GoalType.COLLECT) for (var i in this.config.items) this.itemList.push(new Item(this, this.config.items[i])) } else this.mainSquare = [ [new Tile(this, !1), new Tile(this, !1)], [new Tile(this, !1), new Tile(this, !1)] ], this.colCount = this.mainSquare[0].length, this.rowCount = this.mainSquare.length; this.onResize(game.height, game.height), this.entityList = [], this.ennemyList = [], this.lost = 0, this.addScore(0), worldConfig && (console.log("Start world loading"), this.assetManager.startLoading(), this.music = this.assetManager.getSound("music"), this.tutoArrow = this.game.app.assetManager.getAtlasImage("gui.game.tuto-arrow"), this.tutoTileArrow = this.game.app.assetManager.getAtlasImage("gui.game.tuto-start-arrow"), this.tutoFinger = this.game.app.assetManager.getAtlasImage("gui.game.tuto-finger"), this.tileLocker = this.game.app.assetManager.getAtlasImage("gui.game.tile-locker"), this.cageEndBackground = this.game.assetManager.getImage("gui.game.cage-end-background"), this.cageEndGround = this.game.app.assetManager.getAtlasImage("gui.game.cage-end-ground"), this.cageEndSpot = this.game.app.assetManager.getAtlasImage("gui.game.cage-end-spot"), this.treasureBottom = this.game.assetManager.getAtlasImage("gui.game.treasure-bottom"), this.treasureTop = this.game.assetManager.getAtlasImage("gui.game.treasure-top"), this.treasureContent = this.game.assetManager.getAtlasImage("gui.game.treasure-content"), this.treasureExplosion = this.game.assetManager.getImage("gui.game.star-glow"), this.musicPlaying = !1, this.gameStarted = !1, this.backgroundImage = this.assetManager.getImage("world-background-" + this.worldConfig.graphic_template), this.game.backgroundImage = this.backgroundImage) }; World.STAR_FLASH_DURATION = 400, World.CAGE_END_DELAY = 2e3, World.prototype.checkPortalBonus = function() { var hasBonusEnd = !1; for (var i in this.endPointList) if (this.endPointList[i].isBonus) { hasBonusEnd = !0; break } this.game.setBonusEnabled("portal", hasBonusEnd) }, World.prototype.createFxSprite = function(id, frameRate) { return app.createFxSprite(id, frameRate) }, World.prototype.createAccessorySprite = function(id) { var s = new Sprite(this.game.assetManager.getAtlasImage("data.accessories." + DataStore.accessoryList[id].id), DataStore.accessoryList[id].frame_count, 1); return s.stop(), s }, World.prototype.surviveEndLoop = function() { var self = this, entity = !1; for (var i in this.entityList) { var e = this.entityList[i]; if (!e.winning && !e.dying) { entity = e; break } } entity ? (this.win(entity), setTimeout(function() { self.surviveEndLoop() }, 1e3)) : setTimeout(function() { self.game.gameOver() }, 1e3) }, World.prototype.onChronoEnd = function() { var self = this; this.gameOver(); for (var i in this.entityList) this.entityList[i].dying || this.entityList[i].setSprite("FINISH", !1, !0); for (var i in this.ennemyList) this.ennemyList[i].spriteList.POWER.loop = !0, this.ennemyList[i].setSprite("FINISH"); Config.GENERAL.SURVIVE_FIXED_TIME && setTimeout(function() { self.surviveEndLoop() }, 2e3) }, World.prototype.init = function() { this.nextDyingDodo = !1; var bumpData = this.createBumpSprite(this.assetManager.getImage("bump")); this.bumpSpriteImage = bumpData.image, this.bumpFrameCount = bumpData.frameCount; for (var i = 0; i < DataStore.graphicTemplateList.length; i++) if (DataStore.graphicTemplateList[i].id == this.config.graphic_template) { this.game.defeatSprite = new Sprite(this.assetManager.getImage("defeat-sprite"), DataStore.graphicTemplateList[i].defeat_frame_count, 1, !0); break } for (var y in this.mainSquare) for (var x in this.mainSquare[y]) this.mainSquare[y][x].init(); for (var i in this.startPointList) this.startPointList[i].init(); for (var i in this.endPointList) this.endPointList[i].init(); for (var i in this.itemList) this.itemList[i].init(i); this.lastSecondUpdateTime = 0, this.lastGlobalSecondUpdateTime = 0, this.stopImmunityTime = !1, this.stopEnnemyFreezeTime = !1, this.ready = !0, this.game.onWorldReady() }, World.prototype.dispose = function() { this.music.pause(), this.assetManager.dispose(), this.tutoTextCanvas && this.tutoTextCanvas.dispose(), this.cageTextCanvas && this.cageTextCanvas.dispose() }, World.prototype.cageEndNext = function() { this.config.hasCageTuto && !this.cageTutoDisplayed ? (this.cageTutoDisplayed = !0, this.cageTutoDisplayTime = this.game.timeData.local, this.game.app.assetManager.getSound("start.tuto-roll").reset().play()) : this.game.gameOverTime || this.game.displayEndScreen() }, World.prototype.createBumpSprite = function(bumpImage, invert) { if (!bumpImage.bumpSprite && !invert || !bumpImage.bumpSpriteInvert && invert) { var frameList = invert ? [{ x: 1, y: 1 }, { x: .6, y: 1.1 }, { x: .8, y: 1.05 }, { x: 1.1, y: .9 }, { x: .95, y: 1.05 }, { x: 1, y: 1 }] : [{ x: 1, y: 1 }, { x: 1.2, y: .6 }, { x: .8, y: 1.2 }, { x: .7, y: 1.3 }, { x: 1.05, y: .95 }, { x: .95, y: 1.05 }, { x: 1, y: 1 }], margin = 1; for (var i in frameList) margin = Math.max(margin, frameList[i].x, frameList[i].y); var bumpFrameCount = frameList.length, bumpSpriteImage = Utils.createCanvas(); bumpSpriteImage.complete = !0, bumpSpriteImage.height = bumpImage.height; var frameWidth = Math.round(bumpImage.width * margin), frameHeight = Math.round(bumpImage.height * margin); bumpSpriteImage.width = Math.round(frameWidth * bumpFrameCount), bumpSpriteImage.height = frameHeight; var g = bumpSpriteImage.getContext("2d"); for (var i in frameList) { var size = frameList[i]; g.save(), g.translate(Math.round((parseInt(i) + .5) * frameWidth), invert ? 0 : frameHeight), (1 != size.x || 1 != size.y) && g.scale(size.x, size.y), g.drawImage(bumpImage, Math.round(-bumpImage.width / 2), invert ? 0 : -bumpImage.height, bumpImage.width, bumpImage.height), g.restore() } invert ? bumpImage.bumpSpriteInvert = { image: bumpSpriteImage, frameCount: bumpFrameCount } : bumpImage.bumpSprite = { image: bumpSpriteImage, frameCount: bumpFrameCount } } return invert ? bumpImage.bumpSpriteInvert : bumpImage.bumpSprite }, World.prototype.onResize = function(width, height) { width && (this.width = width), height && (this.height = height), this.squareSize = Math.round(this.height / this.rowCount), this.worldWidth = this.squareSize * this.colCount, this.worldHeight = this.squareSize * this.rowCount; for (var i in this.entityList) this.entityList[i].onResize(); if (this.unlockedDodoEntityList) for (var i in this.unlockedDodoEntityList) this.unlockedDodoEntityList[i].onResize(); for (var i in this.ennemyList) this.ennemyList[i].onResize(); for (var i in this.startPointList) this.startPointList[i].onResize(); for (var i in this.endPointList) this.endPointList[i].onResize(); for (var i in this.itemList) this.itemList[i].onResize(); for (var y in this.mainSquare) for (var x in this.mainSquare[y]) this.mainSquare[y][x].onResize() }, World.prototype.update = function(timeData) { if (this.currentFrame++, this.ready) { if (this.tileMoveTrackBuffer.length > 0) for (; timeData.global > this.tileMoveTrackBuffer[0] + Config.MOVE.ACHIEVEMENT_MOVE_DELAY;) this.tileMoveTrackBuffer.shift(); var self = this; this.musicPlaying || this.finished || this.game.startSoundPlaying || (this.musicPlaying = !0, this.music.playLoop()), this.tutoDeathTime && timeData.global > this.tutoDeathTime && (this.tutoDeathTime = !1, GameScreen.speedFactor = 1, this.waitingForTutoVertical = !0, this.nextDyingDodo.hit(function() { self.waitingForTutoVertical = !1, self.tutoVertical = !0, self.tutoMoveStartTime = self.game.timeData.global }, !0)), this.tutoTileTime && timeData.global > this.tutoTileTime && (this.tutoTileTime = !1, GameScreen.speedFactor = 1, this.tutoVerticalTile ? (this.tutoVerticalTile = !1, this.tutoHorizontalTile = !0, this.tutoTextCanvas && (this.tutoTextCanvas.dispose(), this.tutoTextCanvas = !1)) : this.tutoHorizontalTile = !1); var newSecond = timeData.local - this.lastSecondUpdateTime > 1e3, newGlobalSecond = timeData.global - this.lastGlobalSecondUpdateTime > 1e3; if (newSecond && !this.finished && (this.game.speedStartTime && Achievement.record(DataStore.achievementType.FORWARD, Math.floor((timeData.global - this.game.speedStartTime) / 1e3)), Achievement.record(DataStore.achievementType.NOTHING, Math.floor((timeData.local - this.lastActionTime) / 1e3))), this.dragging && newGlobalSecond && !this.finished && Achievement.record(DataStore.achievementType.DRAG_WAIT, Math.floor((timeData.global - this.dragStartTime) / 1e3)), !this.dragging || !Config.MOVE.PAUSE_DURING_DRAG) { for (var y in this.mainSquare) for (var x in this.mainSquare[y]) this.mainSquare[y][x].update(timeData); for (var i = 0; i < this.startPointList.length; i++) this.startPointList[i].update(timeData); for (var i = 0; i < this.endPointList.length; i++) this.endPointList[i].update(timeData); for (var needCleaning = !1, i = 0; i < this.entityList.length; i++) { var e = this.entityList[i]; if (!e.winning && !e.dying) { for (var j = 0; j < this.ennemyList.length; j++) this.ennemyList[j].checkReached(e) && this.trap(e); e.dying || this.updateEntity(e, timeData) } e.toDelete && (needCleaning = !0) } if (needCleaning) { for (var newList = [], i = 0; i < this.entityList.length; i++) this.entityList[i].toDelete || newList.push(this.entityList[i]); this.entityList = newList } for (var i = 0; i < this.ennemyList.length; i++) { var e = this.ennemyList[i]; this.updateEntity(e, timeData) } if (this.goalType == GoalType.COLLECT && !this.finished) { for (var finished = !0, i = 0; i < this.itemList.length; i++) { var e = this.itemList[i]; !e.winning && e && (finished = !1, !e.entity && timeData.local > e.apparitionTime && this.updateEntity(e, timeData)) } finished && this.gameOver() } if (0 == this.entityList.length && !this.finished) { var finished = !0; for (var i in this.startPointList) if (this.startPointList[i].popCount > 0) { finished = !1; break } finished && this.gameOver() } if (!this.finished && this.goalType == GoalType.SURVIVE && newSecond && this.game.progressBar.remainingDodos > 0) { for (var dodoCount = 0, i = 0; i < this.entityList.length; i++) { var e = this.entityList[i]; e.dying || e.winning || e.isEgg || e.noScore || dodoCount++ } this.addScore(Config.SCORE.SURVIVE_VALUE * dodoCount), this.game.progressBar.addValue(Config.GENERAL.SURVIVE_FIXED_TIME ? -1 : 1), 3 != this.game.progressBar.starCount || Config.GENERAL.SURVIVE_FIXED_TIME || this.onChronoEnd() } } this.stopImmunityTime && (timeData.local > this.stopImmunityTime ? this.setImmunity(!1) : newSecond && this.refreshBonusTimer("immune", this.stopImmunityTime)), this.stopEnnemyFreezeTime && (timeData.local > this.stopEnnemyFreezeTime ? this.setEnnemyFreeze(!1) : newSecond && this.refreshBonusTimer("freeze", this.stopEnnemyFreezeTime)), newSecond && (this.lastSecondUpdateTime = timeData.local), newGlobalSecond && (this.lastGlobalSecondUpdateTime = timeData.global) } }, World.prototype.gameOver = function() { var self = this; this.finished || (this.game.paused && this.game.togglePause(), this.finished = !0, this.game.needRefresh = !0, this.finishTime = this.game.timeData.local, this.musicPlaying = !1, this.goalType == GoalType.SURVIVE && (this.game.app.assetManager.getSound("game.chrono-end").pause(), this.game.progressBar.setChrono(!1), Config.GENERAL.SURVIVE_FIXED_TIME && this.game.progressBar.setValue(0)), this.goalType == GoalType.SURVIVE && 0 != this.game.progressBar.remainingDodos && Config.GENERAL.SURVIVE_FIXED_TIME || this.goalType == GoalType.CAGE && 0 != this.game.progressBar.starCount || (this.config.bonus && 3 == this.game.progressBar.starCount ? setStoredInt("bonus-" + this.config.bonus, getStoredInt("bonus-" + this.config.bonus) + 1) : this.goalType == GoalType.SURVIVE ? setTimeout(function() { self.game.gameOver() }, 3e3) : this.game.gameOver())) }, World.prototype.onMouseUp = function(x, y) { if (this.lastActionTime = this.game.timeData.local, x = this.pixelToWorldX(x), y = this.pixelToWorldY(y), this.selectedTile) { var rowMove = !1, colMove = !1, isFast = this.game.timeData.global - this.dragStartTime < Config.MOVE.FAST_MOVE_MAX_TIME; if (Math.abs(this.rowTranslation) > this.squareSize * (isFast ? Config.MOVE.FAST_MIN_MOVE_FACTOR : Config.MOVE.SLOW_MIN_MOVE_FACTOR)) { var squareCount; isFast ? squareCount = this.rowTranslation > 0 ? Math.ceil(this.rowTranslation / this.squareSize) : Math.floor(this.rowTranslation / this.squareSize) : this.rowTranslation > 0 ? (squareCount = Math.floor(this.rowTranslation / this.squareSize), this.rowTranslation % this.squareSize > this.squareSize * Config.MOVE.SLOW_MIN_MOVE_FACTOR && squareCount++) : (squareCount = Math.ceil(this.rowTranslation / this.squareSize), -this.rowTranslation % this.squareSize > this.squareSize * Config.MOVE.SLOW_MIN_MOVE_FACTOR && squareCount--); var newLine = []; for (var x in this.mainSquare[this.selectedTile.y]) { var tile = this.mainSquare[this.selectedTile.y][x]; tile.setPosition((tile.x + this.colCount + squareCount) % this.colCount, this.selectedTile.y), newLine.push(tile) } if (newLine.sort(function(a, b) { return a.x - b.x }), this.mainSquare[this.selectedTile.y] = newLine, Config.MOVE.FOLLOW_TILES) { for (var i in this.entityList) { var e = this.entityList[i]; !e.winning && e.y + e.height >= this.selectedTile.y && e.y + e.height < this.selectedTile.y + 1 && e.setPosition((e.x + squareCount + this.colCount) % this.colCount, e.y, !0) } for (var i in this.ennemyList) { var e = this.ennemyList[i]; !e.winning && e.y + e.height >= this.selectedTile.y && e.y + e.height < this.selectedTile.y + 1 && e.setPosition((e.x + squareCount + this.colCount) % this.colCount, e.y, !0) } for (var i in this.itemList) { var e = this.itemList[i]; !e.winning && e.y + e.height >= this.selectedTile.y && e.y + e.height < this.selectedTile.y + 1 && e.setPosition((e.x + squareCount + this.colCount) % this.colCount, e.y) } } rowMove = squareCount, this.tutoHorizontal && 1 == Math.abs(rowMove) % 2 && (this.tutoHorizontal = !1, Config.GENERAL.KILL_AT_MOVE ? (this.tutoDeathTime = this.game.timeData.global + Config.TUTO.DEATH_DURATION, GameScreen.speedFactor = 0) : (this.tutoVertical = !0, this.tutoMoveStartTime = this.game.timeData.global)) } else if (Math.abs(this.colTranslation) > this.squareSize * (isFast ? Config.MOVE.FAST_MIN_MOVE_FACTOR : Config.MOVE.SLOW_MIN_MOVE_FACTOR)) { var squareCount; isFast ? squareCount = this.colTranslation > 0 ? Math.ceil(this.colTranslation / this.squareSize) : Math.floor(this.colTranslation / this.squareSize) : this.colTranslation > 0 ? (squareCount = Math.floor(this.colTranslation / this.squareSize), this.colTranslation % this.squareSize > this.squareSize * Config.MOVE.SLOW_MIN_MOVE_FACTOR && squareCount++) : (squareCount = Math.ceil(this.colTranslation / this.squareSize), -this.colTranslation % this.squareSize > this.squareSize * Config.MOVE.SLOW_MIN_MOVE_FACTOR && squareCount--); var newCol = []; for (var y in this.mainSquare) { var tile = this.mainSquare[y][this.selectedTile.x]; tile.setPosition(this.selectedTile.x, (tile.y + this.rowCount + squareCount) % this.rowCount), newCol.push(tile) } newCol.sort(function(a, b) { return a.y - b.y }); for (var y in newCol) this.mainSquare[y][this.selectedTile.x] = newCol[y]; if (Config.MOVE.FOLLOW_TILES) { for (var i in this.entityList) { var e = this.entityList[i]; !e.winning && e.x + e.width / 2 >= this.selectedTile.x && e.x + e.width / 2 < this.selectedTile.x + 1 && e.setPosition(e.x, (e.y + squareCount + this.rowCount) % this.rowCount, !0) } for (var i in this.ennemyList) { var e = this.ennemyList[i]; !e.winning && e.x + e.width / 2 >= this.selectedTile.x && e.x + e.width / 2 < this.selectedTile.x + 1 && e.setPosition(e.x, (e.y + squareCount + this.rowCount) % this.rowCount, !0) } for (var i in this.itemList) { var e = this.itemList[i]; !e.winning && e.x >= this.selectedTile.x && e.x < this.selectedTile.x + 1 && e.setPosition(e.x, (e.y + squareCount + this.rowCount) % this.rowCount) } } colMove = squareCount, this.tutoVertical && 1 == Math.abs(colMove) % 2 && (this.tutoVertical = !1, this.endFirstTuto = !0, this.tutoTextCanvas && (this.tutoTextCanvas.dispose(), this.tutoTextCanvas = !1)) } this.compensateRow = this.selectedTile.y, this.compensateCol = this.selectedTile.x, this.compensateRowTranslation = this.rowTranslation, rowMove && (this.compensateRowTranslation = this.rowTranslation - rowMove * this.squareSize), this.compensateColTranslation = this.colTranslation, colMove && (this.compensateColTranslation = this.colTranslation - colMove * this.squareSize), this.rowTranslation = 0, this.colTranslation = 0, this.selectedTile.setSelected(!1), this.selectedTile = !1, this.movingRow = !1, this.movingCol = !1, this.moveLocked = !1, this.dragging = !1, !(rowMove % this.rowCount || colMove % this.colCount) || !this.nextDyingDodo && Config.GENERAL.KILL_AT_MOVE || this.tutoDeathTime || (this.nextDyingDodo && this.nextDyingDodo.hit(!1, !0), this.tileMoveTrackBuffer.push(this.game.timeData.global), Achievement.record(DataStore.achievementType.FLASH_MOVE, this.tileMoveTrackBuffer.length)) } }, World.prototype.canDrag = function() { var canDrag = !(this.finished || !this.gameStarted || this.tutoDeathTime || this.tutoTileTime || this.tutoVerticalTile || this.tutoHorizontalTile || this.endFirstTuto); if (canDrag) { canDrag = !1; for (var i = 0; i < this.entityList.length; i++) if (!this.entityList[i].dying && !this.entityList[i].winning) { canDrag = !0; break } } return canDrag }, World.prototype.onMouseDown = function(x, y) { this.lastActionTime = this.game.timeData.local; var xWorld = this.pixelToWorldX(x), yWorld = this.pixelToWorldY(y); this.canDrag() && xWorld > 0 && yWorld > 0 && xWorld < this.colCount && yWorld < this.rowCount && (this.waitingForTutoVertical || this.tutoHorizontal && 1 != Math.floor(yWorld) || this.tutoVertical && 0 != Math.floor(xWorld) || (this.startDrag = { x: x, y: y }, this.dragStartTime = this.game.timeData.global, this.selectedTile = this.getTile(xWorld, yWorld), this.selectedTile.setSelected(!0))) }, World.prototype.onMouseMove = function(x, y) { if (this.lastActionTime = this.game.timeData.local, this.selectedTile) { var xDis = x - this.startDrag.x, yDis = y - this.startDrag.y; this.tutoVertical && (xDis = 0), this.tutoHorizontal && (yDis = 0); var xDisAbs = Math.abs(xDis), yDisAbs = Math.abs(yDis); this.movingRow && this.moveLocked || xDisAbs > yDisAbs && !this.moveLocked ? (this.rowTranslation = xDis % this.width, this.colTranslation = 0, this.dragging = !0, this.movingRow = !0, this.movingCol = !1, xDisAbs > Config.MOVE.MIN_DRAG_LOCK_DISTANCE * this.squareSize && (this.moveLocked = !0)) : (this.movingCol && this.moveLocked || yDisAbs > xDisAbs && !this.moveLocked) && (this.colTranslation = yDis % this.height, this.rowTranslation = 0, this.movingCol = !0, this.movingRow = !1, this.dragging = !0, yDisAbs > Config.MOVE.MIN_DRAG_LOCK_DISTANCE * this.squareSize && (this.moveLocked = !0)) } else { var buttonSize = World.RETURN_BUTTON_SIZE * this.game.height, nextX = (this.game.width - this.worldWidth) / 2 + this.worldWidth - 1.1 * buttonSize, nextY = (this.game.height - this.worldHeight) / 2 + this.worldHeight - 1.1 * buttonSize; this.overNext = x >= nextX && nextX + buttonSize > x && y >= nextY && nextY + buttonSize > y ? !0 : !1; var renderMargin = World.RETURN_MARGIN * this.game.height, buttonSize = World.RETURN_BUTTON_SIZE * this.game.height, returnX = renderMargin, returnY = this.game.height - renderMargin - buttonSize; this.overReturn = x >= returnX && returnX + buttonSize > x && y >= returnY && returnY + buttonSize > y ? !0 : !1; var resetX = renderMargin, resetY = returnY - renderMargin - buttonSize; this.overReset = x >= resetX && resetX + buttonSize > x && y >= resetY && resetY + buttonSize > y ? !0 : !1 } }, World.prototype.pixelToWorldX = function(x) { return x / this.squareSize }, World.prototype.pixelToWorldY = function(y) { return y / this.squareSize }, World.FINISH_FADE_DURATION = 500, World.prototype.render = function(g) { if (this.ready) { if (this.goalType != GoalType.CAGE) for (var i in this.endPointList) this.endPointList[i].render(g); for (var i in this.startPointList) this.startPointList[i].render(g); if (this.compensateRowTranslation) { var f = 1 - .01 * g.timeData.localDelta; this.compensateRowTranslation *= f, Math.abs(this.compensateRowTranslation) < .01 && (this.compensateRowTranslation = 0) } if (this.compensateColTranslation) { var f = 1 - .01 * g.timeData.localDelta; this.compensateColTranslation *= f, Math.abs(this.compensateColTranslation) < .01 && (this.compensateColTranslation = 0) } for (var pass = 0; 3 > pass; pass++) for (var y = this.mainSquare.length - 1; y >= 0; y--) { var xTranslation = 0; this.rowTranslation && y == this.selectedTile.y ? xTranslation = this.rowTranslation : this.compensateRow == y && this.compensateRowTranslation && (xTranslation = this.compensateRowTranslation); for (var x in this.mainSquare[y]) { var yTranslation = 0; this.colTranslation && x == this.selectedTile.x ? yTranslation = this.colTranslation : this.compensateCol == x && this.compensateColTranslation && (yTranslation = this.compensateColTranslation); var tile = this.mainSquare[y][x]; tile.xTranslation = xTranslation, tile.yTranslation = yTranslation, tile.render(g, pass) } } if (this.goalType == GoalType.CAGE) for (var i in this.endPointList) this.endPointList[i].render(g); for (var i = 0; i < this.itemList.length; i++) { var e = this.itemList[i]; if (!e.entity) { var translateX = 0, translateY = 0; this.rowTranslation && e.y + e.height >= this.selectedTile.y && e.y + e.height < this.selectedTile.y + 1 ? translateX = this.rowTranslation : this.colTranslation && e.x >= this.selectedTile.x && e.x < this.selectedTile.x + 1 ? translateY = this.colTranslation : this.compensateRowTranslation && e.y + e.height >= this.compensateRow && e.y + e.height < this.compensateRow + 1 ? translateX = this.compensateRowTranslation : this.compensateColTranslation && e.x >= this.compensateCol && e.x < this.compensateCol + 1 && (translateY = this.compensateColTranslation), Config.MOVE.FOLLOW_TILES && (e.xTranslation = translateX, e.yTranslation = translateY), e.render(g) } } for (var i = 0; i < this.entityList.length; i++) { var e = this.entityList[i]; if (!this.tutoDeathTime || e != this.nextDyingDodo) { var translateX = 0, translateY = 0; e.winning || (this.rowTranslation && e.y + e.height >= this.selectedTile.y && e.y + e.height < this.selectedTile.y + 1 ? translateX = this.rowTranslation : this.colTranslation && e.x + e.width / 2 >= this.selectedTile.x && e.x + e.width / 2 < this.selectedTile.x + 1 ? translateY = this.colTranslation : this.compensateRowTranslation && e.y + e.height >= this.compensateRow && e.y + e.height < this.compensateRow + 1 ? translateX = this.compensateRowTranslation : this.compensateColTranslation && e.x + e.width / 2 >= this.compensateCol && e.x + e.width / 2 < this.compensateCol + 1 && (translateY = this.compensateColTranslation)), Config.MOVE.FOLLOW_TILES && (e.xTranslation = translateX, e.yTranslation = translateY), e.render(g) } } for (var i = 0; i < this.ennemyList.length; i++) { var e = this.ennemyList[i], translateX = 0, translateY = 0; this.rowTranslation && e.y + e.height >= this.selectedTile.y && e.y + e.height < this.selectedTile.y + 1 ? translateX = this.rowTranslation : this.colTranslation && e.x + e.width / 2 >= this.selectedTile.x && e.x + e.width / 2 < this.selectedTile.x + 1 ? translateY = this.colTranslation : this.compensateRowTranslation && e.y + e.height >= this.compensateRow && e.y + e.height < this.compensateRow + 1 ? translateX = this.compensateRowTranslation : this.compensateColTranslation && e.x + e.width / 2 >= this.compensateCol && e.x + e.width / 2 < this.compensateCol + 1 && (translateY = this.compensateColTranslation), Config.MOVE.FOLLOW_TILES && (e.xTranslation = translateX, e.yTranslation = translateY), e.render(g) } for (var i in this.endPointList) this.endPointList[i].renderScore(g); if (this.gameStarted && (this.tutoVertical || this.tutoHorizontal)) { g.save(); var f = .4 * Math.cycleSin(g.timeData.global - this.tutoMoveStartTime, 1e3) + .4, startDelay = 1e3, start2Delay = 500, moveDuration = 1e3, endDelay = 500, end2Delay = 1e3, total = moveDuration + start2Delay + end2Delay + startDelay + endDelay, f = (g.timeData.global - this.tutoMoveStartTime) / total % 1, fStart = startDelay / total, fStart2 = start2Delay / total, fEnd = endDelay / total, fMoveDuration = moveDuration / total, fAlpha = f, fAlpha2 = f, fMove = 0; fStart > f ? (fMove = 0, fAlpha = Math.min(1, 4 * f / fStart), fAlpha2 = 0) : f > fStart + fStart2 + fMoveDuration ? (fAlpha2 = 1, fMove = 1, fStart + fStart2 + fMoveDuration + fEnd > f ? (fAlpha = 1 - (f - (fStart + fStart2 + fMoveDuration)) / fEnd, fAlpha = Math.min(1, 2 * fAlpha)) : fAlpha = 0) : (fAlpha2 = (f - fStart) / (fStart2 + fMoveDuration), fAlpha = 1, fStart + fStart2 > f ? fMove = 0 : (fMove = (f - fStart - fStart2) / fMoveDuration, fMove = Math.easeOutExpo(fMove))), this.tutoVertical ? g.translate(Math.round(this.width / 4), Math.round(this.height / 2)) : g.translate(Math.round(this.width / 2), Math.round(.75 * this.height)); var scale = .5 * this.height / this.tutoArrow.height; g.scale(scale, scale), g.save(), this.tutoHorizontal && g.rotate(Math.PI / 2), g.translate(Math.round(-this.tutoArrow.width / 2), Math.round(-this.tutoArrow.height / 2)), g.globalAlpha = fAlpha, this.tutoArrow.render(g, 0, 0), g.restore(), g.globalAlpha = Math.easeOutCubic(Math.sin(fAlpha2 * Math.PI)); var from = .4 * this.tutoArrow.height, to = .4 * -this.tutoArrow.height, dis = to - from; this.tutoHorizontal ? this.tutoFinger.render(g, fMove * dis + from - 30, 0) : this.tutoFinger.render(g, 0, -fMove * dis + to), g.restore() } if (this.tutoDeathTime || this.tutoTileTime || this.endFirstTuto) { if (!this.endFirstTuto && (g.fillStyle = "black", g.globalAlpha = .5, g.fillRect(0, 0, this.width, this.height), g.globalAlpha = 1, this.nextDyingDodo)) { var e = this.nextDyingDodo, translateX = 0, translateY = 0; e.winning || (this.rowTranslation && e.y + e.height >= this.selectedTile.y && e.y + e.height < this.selectedTile.y + 1 ? translateX = this.rowTranslation : this.colTranslation && e.x + e.width / 2 >= this.selectedTile.x && e.x + e.width / 2 < this.selectedTile.x + 1 ? translateY = this.colTranslation : this.compensateRowTranslation && e.y + e.height >= this.compensateRow && e.y + e.height < this.compensateRow + 1 ? translateX = this.compensateRowTranslation : this.compensateColTranslation && e.x + e.width / 2 >= this.compensateCol && e.x + e.width / 2 < this.compensateCol + 1 && (translateY = this.compensateColTranslation)), e.xTranslation = translateX, e.yTranslation = translateY, e.render(g) } if (!this.tutoTextCanvas) { this.tutoTextCanvas = Utils.createCanvas(), this.tutoTextCanvas.width = 512, this.tutoTextCanvas.height = 128; var text, g2 = this.tutoTextCanvas.getContext("2d"); this.tutoDeathTime ? text = Utils.splitText(_2("tuto-death-text")) : this.tutoVerticalTile ? text = Utils.splitText(_2("tuto-vertical-tile-text")) : this.tutoHorizontalTile ? text = Utils.splitText(_2("tuto-horizontal-tile-text")) : this.endFirstTuto && (text = Utils.splitText(_2("end-first-tuto-text"))), app.setBaseFont(g2, 40), g2.textAlign = "center", g2.textBaseline = "middle", app.fillOutlineText(g2, text[0], Math.round(this.tutoTextCanvas.width / 2), Math.round(this.tutoTextCanvas.height / 2) - 20), app.fillOutlineText(g2, text[1], Math.round(this.tutoTextCanvas.width / 2), Math.round(this.tutoTextCanvas.height / 2) + 20) } if (g.save(), g.translate(Math.round(g.height / 2), Math.round(g.height / 6)), g.scale(this.game.app.scale, this.game.app.scale), g.drawImage(this.tutoTextCanvas, -Math.round(this.tutoTextCanvas.width / 2), 0), g.restore(), this.tutoTileTime) { g.save(); var scale = .15 * this.height / this.tutoTileArrow.height, duration = 1e3, switchDirection = Math.floor((g.timeData.global - this.tutoTileStartTime) / duration) % 2, f = Math.easeOutQuad((g.timeData.global - this.tutoTileStartTime) % duration / duration), f2 = f; switchDirection && (f2 = 1 - f), this.tutoVerticalTile ? g.translate(Math.round(.075 * this.width), .2 * (f2 - .5) * this.height) : g.translate(.2 * (f2 - .5) * this.height, Math.round(.2 * this.width)), .1 > f ? g.globalAlpha = f / .1 : f > .9 && (g.globalAlpha = 1 - (f - .9) / .1), g.scale(scale, scale), this.tutoHorizontalTile && g.rotate(Math.PI / 2), (switchDirection && this.tutoVerticalTile || !switchDirection && this.tutoHorizontalTile) && g.rotate(Math.PI), g.translate(Math.round(-this.tutoTileArrow.width / 2), Math.round(-this.tutoTileArrow.height / 2)), this.tutoTileArrow.render(g, 0, 0), switchDirection ? g.translate(0, -Math.round(this.height / scale)) : g.translate(0, Math.round(this.height / scale)), this.tutoTileArrow.render(g, 0, 0), g.restore() } } if (!this.canDrag() && !this.finished) { var f = Math.cycleSin(g.timeData.global, 1e3), scale = .12 * this.width / this.tileLocker.width; g.save(), g.globalAlpha = .6 + .3 * f, g.translate(this.width, 0), g.scale(scale, scale), this.tileLocker.render(g, -this.tileLocker.width - 20, 20), g.restore() } this.goalType == GoalType.CAGE && this.finished && g.timeData.local > this.finishTime + World.CAGE_END_DELAY && this.config.unlockedDodoType && this.game.progressBar.starCount > 0 ? this.renderCageEnd(g) : this.finished && this.config.bonus && 3 == this.game.progressBar.starCount && this.renderTreasureEnd(g) } }, World.prototype.renderCageEnd = function(g) { var self = this; g.save(); var finishTime = this.finishTime + World.CAGE_END_DELAY, dodoFadeDuration = 500, dodoFadeDelay = 200, textAnimDuration = 500, lightAnimDuration = 1500, lightDelay = World.FINISH_FADE_DURATION + dodoFadeDuration + dodoFadeDelay + 500, textDelay = lightDelay + lightAnimDuration + 500; g.timeData.local < finishTime + World.FINISH_FADE_DURATION ? g.globalAlpha = (g.timeData.local - finishTime) / World.FINISH_FADE_DURATION : this.cageBackgroundSet || (this.game.backgroundImage = this.cageEndBackground, this.cageBackgroundSet = !0), g.drawImage(this.cageEndBackground, 0, 0, this.cageEndBackground.width, this.cageEndBackground.height, 0, 0, g.height, g.height); var backgroundScale = this.game.app.scale; if (g.scale(backgroundScale, backgroundScale), !this.unlockedDodoEntityList) { this.rowCount = this.colCount = 2, this.onResize(this.width, this.height), this.unlockedDodoEntityList = []; for (var i = 0; i < this.config.unlockedDodoCount; i++) { var e = new Entity(this, 0, 0, !1, Math.random() > .5, DataStore.dodoTypeList[this.config.unlockedDodoType]); e.s = .9 + .5 * Math.random(), this.config.unlockedDodoCount > 1 ? e.setPosition(i / this.config.unlockedDodoCount + .9 * .05 * (Math.random() - .5) - .5, .05 + .02 * e.s, !0) : e.setPosition(0, .05 + .02 * e.s, !0), e.setSprite("FINISH", !1, !0), this.unlockedDodoEntityList.push(e) } this.unlockedDodoEntityList.sort(function(a, b) { return a.s - b.s }) } var decal = 110; if (g.timeData.local >= finishTime + World.FINISH_FADE_DURATION + dodoFadeDelay) { g.save(), g.timeData.local < finishTime + World.FINISH_FADE_DURATION + dodoFadeDelay + dodoFadeDuration && (g.globalAlpha = (g.timeData.local - finishTime - World.FINISH_FADE_DURATION - dodoFadeDelay) / dodoFadeDuration), g.translate(Math.round(App.BASE_HEIGHT / 2), Math.round(App.BASE_HEIGHT / 2) + decal); var img; if (g.timeData.local > finishTime + lightDelay) { if (this.lightSoundPlayed || (this.lightSoundPlayed = !0, this.game.app.assetManager.getSound("end.dodo-light").reset().play(), setTimeout(function() { self.game.assetManager.getSound("stock.infinite").reset().play() }, 2e3)), g.timeData.local < finishTime + lightDelay + lightAnimDuration) { g.save(); var f = (g.timeData.local - finishTime - lightDelay) / lightAnimDuration, fPart = .75, fFrac = .2; f = fPart > f ? Math.easeOutSine(f / fPart) * fFrac : fFrac + Math.easeOutElastic((f - fPart) / (1 - fPart)) * (1 - fFrac), g.scale(f, 1) } this.cageEndGround.render(g, -Math.round(this.cageEndGround.width / 2), 75), g.timeData.local < finishTime + lightDelay + lightAnimDuration && g.restore() } g.restore(), g.restore(), g.save(), g.timeData.local < finishTime + World.FINISH_FADE_DURATION + dodoFadeDelay + dodoFadeDuration && (g.globalAlpha = (g.timeData.local - finishTime - World.FINISH_FADE_DURATION - dodoFadeDelay) / dodoFadeDuration), g.translate(Math.round(this.width / 2), Math.round(.65 * this.height)); for (var i = 0; i < this.unlockedDodoEntityList.length; i++) { g.save(); var e = this.unlockedDodoEntityList[i]; g.scale(e.s, e.s), g.timeData.local <= finishTime + lightDelay + .8 * lightAnimDuration ? this.unlockedDodoEntityList[i].render(g, !0, !0) : this.unlockedDodoEntityList[i].render(g, !0), g.restore() } if (g.restore(), g.save(), g.scale(backgroundScale, backgroundScale), g.save(), g.timeData.local < finishTime + World.FINISH_FADE_DURATION + dodoFadeDelay + dodoFadeDuration && (g.globalAlpha = (g.timeData.local - finishTime - World.FINISH_FADE_DURATION - dodoFadeDelay) / dodoFadeDuration), g.translate(Math.round(App.BASE_HEIGHT / 2), Math.round(App.BASE_HEIGHT / 2) + decal), g.timeData.local > finishTime + lightDelay) { if (g.timeData.local < finishTime + lightDelay + lightAnimDuration) { g.save(); var f = (g.timeData.local - finishTime - lightDelay) / lightAnimDuration, fPart = .75, fFrac = .2; f = fPart > f ? Math.easeOutExpo(f / fPart) * fFrac : fFrac + Math.easeOutElastic((f - fPart) / (1 - fPart)) * (1 - fFrac), g.scale(f, 1) } this.cageEndSpot.render(g, -Math.round(this.cageEndSpot.width / 2), -this.cageEndSpot.height + 75), g.timeData.local < finishTime + lightDelay + lightAnimDuration && g.restore() } if (g.restore(), !this.cageTextCanvas) { this.cageTextCanvas = Utils.createCanvas(), this.cageTextCanvas.width = 1024, this.cageTextCanvas.height = 128; var g2 = this.cageTextCanvas.getContext("2d"); app.setBaseFont(g2, 80), g2.textAlign = "center", g2.textBaseline = "middle", app.fillOutlineText(g2, _2("well-done"), Math.round(this.cageTextCanvas.width / 2), Math.round(this.cageTextCanvas.height / 2) - 27), app.setBaseFont(g2, 55), app.fillOutlineText(g2, this.config.unlockedDodoCount > 1 ? _2("multiple-dodo-free").replace("%1", this.config.unlockedDodoCount).replace("%2", getDBText("dodo_type", "name", this.config.unlockedDodoType)) : _2("one-dodo-free"), Math.round(this.cageTextCanvas.width / 2), Math.round(this.cageTextCanvas.height / 2) + 33) } if (g.translate(Math.round(App.BASE_HEIGHT / 2), 200), g.timeData.local > finishTime + textDelay && !this.cageTutoDisplayed) { if (g.timeData.local < finishTime + textDelay + textAnimDuration) { var f = Math.easeOutBack((g.timeData.local - finishTime - textDelay) / textAnimDuration); g.globalAlpha = Math.min(1, f), g.scale(f, f) } else this.stockAdded || (this.stockAdded = !0, this.game.registerLevelScore(), StockManager.stockList[this.config.unlockedDodoType].addMaxStock(this.config.unlockedDodoCount, function() { self.cageNextButtonDisplayTime = g.timeData.global })); g.drawImage(this.cageTextCanvas, -Math.round(this.cageTextCanvas.width / 2), 0) } } if (g.timeData.local >= this.cageTutoDisplayTime + 1e3 && !this.tutoUnlockedDodoOver && (this.tutoUnlockedDodoOver = !0, this.cageNextButtonDisplayTime = g.timeData.global), this.cageNextButtonDisplayTime && g.timeData.global > this.cageNextButtonDisplayTime && ButtonUtils.render({ g: g, img: this.game.assetManager.getAtlasImage("gui.common.play"), id: "cage-tuto-next", x: Math.round(g.width / 2 + 250 * app.scale), y: g.height - 30 * app.scale, align: ButtonUtils.ALIGN_CENTER, valign: ButtonUtils.VALIGN_BOTTOM, listener: function() { self.cageEndNext(), Input.removeCollider("cage-tuto-next") }, needRefresh: !0 }), this.cageTutoDisplayed) { var img = app.assetManager.getAtlasImage("data.dodos." + this.config.unlockedDodoType + "-tuto"), tutoAnimDuration = 250; if (g.timeData.local < this.cageTutoDisplayTime + tutoAnimDuration) { var f = 1 - Math.easeOutBack((g.timeData.local - this.cageTutoDisplayTime) / tutoAnimDuration); g.translate(0, -Math.round(500 * f)) } img.render(g, -Math.round(img.width / 2), -Math.round(img.height / 2) + 50) } g.restore() }, World.prototype.renderTreasureEnd = function(g) { g.save(); var explodeDelay = 2e3, explodeDuration = 500, finishDelay = 2e3; g.globalAlpha = g.timeData.local < this.finishTime + World.FINISH_FADE_DURATION ? (g.timeData.local - this.finishTime) / World.FINISH_FADE_DURATION : 1, g.fillStyle = "black", g.fillRect(0, 0, this.width, this.height); var bonus = this.game.app.assetManager.getImage("gui.game.bonus-" + DataStore.bonusList[this.config.bonus].identifier); if (g.translate(Math.round(this.width / 2), Math.round(.55 * this.height)), g.scale(1.5 * this.game.app.scale, 1.5 * this.game.app.scale), g.translate(-Math.round(this.treasureBottom.width / 2), -Math.round(this.treasureBottom.height / 2)), g.timeData.local < this.finishTime + explodeDelay && g.translate(Math.round(3 * (2 * Math.random() - 1)), Math.round(3 * (2 * Math.random() - 1))), this.treasureBottom.render(g, 0, 0), g.timeData.local > this.finishTime + explodeDelay) { g.save(); var f = Math.cycleSin(g.timeData.local, 1500); if (g.globalAlpha = .85 + .15 * f, this.treasureContent.render(g, 0, 0), g.restore(), f = (g.timeData.local - (this.finishTime + explodeDelay)) / explodeDuration, g.save(), g.translate(90 + Math.round(bonus.width / 4), 45 + Math.round(bonus.height / 2)), 1 > f) g.scale(f, f); else { var f2 = Math.cycleSin(g.timeData.local, 1e3), scale = .97 + .06 * f2; g.scale(scale, scale) } g.drawImage(bonus, 0, 0, Math.round(bonus.width / 2), bonus.height, -Math.round(bonus.width / 4), -Math.round(bonus.height / 2), Math.round(bonus.width / 2), bonus.height), g.font = "40px brlnsr", g.fillStyle = "gold", g.strokeStyle = "black", g.textAlign = "center", g.textBaseline = "middle", g.fillStyle = "white", g.lineWidth = 2, g.strokeText("+1", 20, -30), g.fillText("+1", 20, -30), g.restore(), 1 > f ? (g.save(), g.translate(0, -Math.round(Math.easeOutCubic(f) * this.height / 1.5)), g.globalAlpha = f, this.treasureTop.render(g, 0, 0), g.restore(), g.save(), g.translate(Math.round(this.treasureBottom.width / 2), Math.round(this.treasureBottom.height / 2)), g.scale(10 * f + 5, 10 * f + 5), g.globalAlpha = .5 > f ? 1 : 2 * (1 - f), g.translate(-Math.round(this.treasureExplosion.width / 2), -Math.round(this.treasureExplosion.height / 2)), g.drawImage(this.treasureExplosion, 0, 0), g.restore()) : g.timeData.local > this.finishTime + explodeDelay + explodeDuration + finishDelay && !this.treasureAnimDone && (this.treasureAnimDone = !0, this.game.gameOver()) } else this.treasureTop.render(g, 0, 0); g.restore() }, World.prototype.getTile = function(x, y) { return x = Math.floor(x + this.colCount) % this.colCount, y = Math.floor(y + this.rowCount) % this.rowCount, this.mainSquare[y][x] }, World.prototype.getNextSpawnPoint = function() { var list = []; for (var i in this.startPointList) list.push(this.startPointList[i]); Array.shuffle(list); for (var i in list) { var p = list[i]; if (!p.ennemy && p.isReady()) return p } for (var i in list) { var p = list[i]; if (!p.ennemy) return p } return !1 }, World.prototype.createEntity = function(x, y, ennemy, invert, config, eggHatchTime) { var e = new Entity(this, x, y, ennemy, invert, config, eggHatchTime); eggHatchTime && (e.noScore = !0); var sound; ennemy ? (this.game.setBonusEnabled("immune", !0), this.game.setBonusEnabled("freeze", !0), sound = this.game.app.assetManager.getSound("game.new-ennemy"), this.ennemyList.push(e)) : (!this.nextDyingDodo && Config.GENERAL.KILL_AT_MOVE && (this.nextDyingDodo = e), this.entityList.unshift(e), eggHatchTime ? (sound = this.game.app.assetManager.getSound("game.new-egg"), this.game.progressBar.declareNewDodo()) : sound = this.game.app.assetManager.getSound("game.new-dodo"), 1 != config.score && this.game.progressBar.declareEntityScore(config.score)), sound.reset(), sound.play(), this.gameStarted || (this.game.needRefresh = !0, this.gameStarted = !0, this.gameStartTime = this.game.timeData.local, this.tutoMoveStartTime = this.game.timeData.global) }, World.prototype.getGroundTypeAt = function(x, y, debug) { var tile = this.getTile(x, y); return tile.getGroundTypeAt((x + 1) % 1, (y + 1) % 1, debug) }, World.prototype.updateEntity = function(e, timeData) { var newX = e.x, newY = e.y, effectToPlay = !1, fallDistance = 0; if (!e.onGround) { if (e.fallSpeed <= 0) { var f = 1 - timeData.localDelta * Config.PHYSICS.GRAVITY / 1e3; e.fallSpeed *= f * (1 + .008 * (GameScreen.speedFactor - 1)), 0 == e.fallSpeed ? e.fallSpeed = Config.PHYSICS.INIT_FALL_SPEED : e.fallSpeed > -Config.PHYSICS.INIT_FALL_SPEED && (e.fallSpeed = 0) } else e.fallSpeed > 0 && (e.fallSpeed = Math.min(Config.PHYSICS.MAX_FALL_SPEED, e.fallSpeed + e.fallSpeed * Config.PHYSICS.GRAVITY * timeData.localDelta / 1e3)); fallDistance = timeData.localDelta * e.fallSpeed / 1e3 } if (e.isBumping) { var groundTypeTopLeft, groundTypeTopRight, groundTypeBottomLeft, groundTypeBottomRight, moveDistance = timeData.localDelta * e.getSpeed() / 1e3; e.revertDirection && (moveDistance = -moveDistance), newX = e.x + moveDistance, newY = e.y + fallDistance; var tileLeftX = newX + GameScreen.EPSILON, tileRightX = newX + e.width - GameScreen.EPSILON, tileTopY = newY + GameScreen.EPSILON, tileBottomY = newY + e.height - GameScreen.EPSILON, tileTopLeft = this.getTile(tileLeftX, tileTopY), tileTopRight = this.getTile(tileRightX, tileTopY), tileBottomLeft = this.getTile(tileLeftX, tileBottomY), tileBottomRight = this.getTile(tileRightX, tileBottomY), relTileLeftX = (tileLeftX + 1) % 1, relTileRightX = (tileRightX + 1) % 1, relTileTopY = (tileTopY + 1) % 1, relTileBottomY = (tileBottomY + 1) % 1; if (groundTypeTopLeft = tileTopLeft.getGroundTypeAt(relTileLeftX, relTileTopY), groundTypeTopRight = tileTopRight.getGroundTypeAt(relTileRightX, relTileTopY), groundTypeBottomLeft = tileBottomLeft.getGroundTypeAt(relTileLeftX, relTileBottomY), groundTypeBottomRight = tileBottomRight.getGroundTypeAt(relTileRightX, relTileBottomY), groundTypeTopRight != Tile.groundType.EMPTY) { var newY2 = Math.floor(newY) + tileTopRight.getBottomEdge(relTileRightX, relTileTopY), tileTopY2 = newY2, tileTopRight2 = this.getTile(tileRightX, tileTopY2), relTileTopY2 = (tileTopY2 + 1) % 1, groundTypeTopRight2 = tileTopRight2.getGroundTypeAt(relTileRightX, relTileTopY2); if (groundTypeTopRight2 == Tile.groundType.EMPTY) newY = newY2, tileTopY = tileTopY2, tileTopRight = tileTopRight2, relTileTopY = relTileTopY2, groundTypeTopRight = groundTypeTopRight2, e.fallSpeed < 0 && (e.fallSpeed = -e.fallSpeed); else if (!e.revertDirection) { var newX3 = Math.floor(newX + e.width) + tileTopRight.getLeftEdge(relTileRightX, relTileTopY) - e.width, tileRightX3 = newX3 + e.width - GameScreen.EPSILON, tileTopRight3 = this.getTile(tileRightX3, tileTopY), relTileRightX3 = (tileRightX3 + 1) % 1, groundTypeTopRight3 = tileTopRight3.getGroundTypeAt(relTileRightX3, relTileTopY); groundTypeTopRight3 == Tile.groundType.EMPTY && (e.revertDirection = !e.revertDirection, newX = newX3, tileRightX = tileRightX3, tileTopRight = tileTopRight3, relTileRightX = relTileRightX3, groundTypeTopRight = groundTypeTopRight3) } } else if (groundTypeTopLeft != Tile.groundType.EMPTY) { var newY2 = Math.floor(newY) + tileTopLeft.getBottomEdge(relTileLeftX, relTileTopY), tileTopY2 = newY2, tileTopLeft2 = this.getTile(tileLeftX, tileTopY2), relTileTopY2 = (tileTopY2 + 1) % 1, groundTypeTopLeft2 = tileTopLeft2.getGroundTypeAt(relTileLeftX, relTileTopY2); if (groundTypeTopLeft2 == Tile.groundType.EMPTY) newY = newY2, tileTopY = tileTopY2, tileTopLeft = tileTopLeft2, relTileTopY = relTileTopY2, groundTypeTopLeft = groundTypeTopLeft2, e.fallSpeed < 0 && (e.fallSpeed = -e.fallSpeed); else if (e.revertDirection) { var newX3 = Math.floor(newX) + tileTopLeft.getRightEdge(relTileLeftX, relTileTopY), tileLeftX3 = newX3 - GameScreen.EPSILON, tileTopLeft3 = this.getTile(tileLeftX3, tileTopY), relTileLeftX3 = (tileLeftX3 + 1) % 1, groundTypeTopLeft3 = tileTopLeft3.getGroundTypeAt(relTileLeftX3, relTileTopY); groundTypeTopLeft3 == Tile.groundType.EMPTY && (e.revertDirection = !e.revertDirection, newX = newX3, tileLeftX = tileLeftX3, tileTopLeft = tileTopLeft3, relTileLeftX = relTileLeftX3, groundTypeTopLeft = groundTypeTopLeft3) } } else if (groundTypeBottomLeft != Tile.groundType.EMPTY) { var newY2 = Math.floor(newY + e.height) + tileBottomLeft.getTopEdge(relTileLeftX, relTileBottomY) - e.height, tileBottomY2 = newY2, tileBottomLeft2 = this.getTile(tileLeftX, tileBottomY2), relTileBottomY2 = (tileBottomY2 + 1) % 1, groundTypeBottomLeft2 = tileBottomLeft2.getGroundTypeAt(relTileLeftX, relTileBottomY2); if (groundTypeBottomLeft2 == Tile.groundType.EMPTY) newY = newY2, tileBottomY = tileBottomY2, tileBottomLeft = tileBottomLeft2, relTileBottomY = relTileBottomY2, groundTypeBottomLeft != Tile.groundType.BASIC && groundTypeBottomLeft != Tile.groundType.EMPTY && (effectToPlay = groundTypeBottomLeft), groundTypeBottomLeft = groundTypeBottomLeft2, e.setOnGround(!0); else if (e.revertDirection) { var newX3 = Math.floor(newX) + tileBottomLeft.getLeftEdge(relTileLeftX, relTileBottomY), tileLeftX3 = newX3 - GameScreen.EPSILON, tileBottomLeft3 = this.getTile(tileLeftX3, tileBottomY), relTileLeftX3 = (tileLeftX3 + 1) % 1, groundTypeBottomLeft3 = tileBottomLeft3.getGroundTypeAt(relTileLeftX3, relTileBottomY); groundTypeBottomLeft3 == Tile.groundType.EMPTY && (e.revertDirection = !e.revertDirection, newX = newX3, tileLeftX = tileLeftX3, tileBottomLeft = tileBottomLeft3, relTileLeftX = relTileLeftX3, groundTypeBottomLeft = groundTypeBottomLeft3) } } else if (groundTypeBottomRight != Tile.groundType.EMPTY) { var newY2 = Math.floor(newY + e.height) + tileBottomRight.getTopEdge(relTileRightX, relTileBottomY) - e.height, tileBottomY2 = newY2, tileBottomRight2 = this.getTile(tileRightX, tileBottomY2), relTileBottomY2 = (tileBottomY2 + 1) % 1, groundTypeBottomRight2 = tileBottomRight2.getGroundTypeAt(relTileRightX, relTileBottomY2); if (groundTypeBottomRight2 == Tile.groundType.EMPTY) newY = newY2, tileBottomY = tileBottomY2, tileBottomRight = tileBottomRight2, relTileBottomY = relTileBottomY2, groundTypeBottomRight = groundTypeBottomRight2, e.setOnGround(!0); else if (e.revertDirection) { var newX3 = Math.floor(newX + e.width) + tileBottomRight.getRightEdge(relTileRightX, relTileBottomY) - e.width, tileRightX3 = newX3 - GameScreen.EPSILON, tileBottomRight3 = this.getTile(tileRightX3, tileBottomY), relTileRightX3 = (tileRightX3 + 1) % 1, groundTypeBottomRight3 = tileBottomRight3.getGroundTypeAt(relTileRightX3, relTileBottomY); groundTypeBottomRight3 == Tile.groundType.EMPTY && (e.revertDirection = !e.revertDirection, newX = newX3, tileRightX = tileRightX3, tileBottomRight = tileBottomRight3, relTileRightX = relTileRightX3, groundTypeBottomRight = groundTypeBottomRight3) } } } else if (e.onGround) { var speed = e.getSpeed(); e.compensateY && (speed *= Config.PHYSICS.SLOPE_SPEED_FACTOR); var groundTypeTop, groundTypeBottom, groundTypeLeft, groundTypeRight, moveDistance = timeData.localDelta * speed / 1e3; e.revertDirection && (moveDistance = -moveDistance), newX = e.x + moveDistance; var tileX; tileX = e.revertDirection ? newX - GameScreen.EPSILON : newX + e.width + GameScreen.EPSILON; var currentTileX, relTileX = (tileX + 1) % 1; currentTileX = e.revertDirection ? e.x - GameScreen.EPSILON : e.x + e.width + GameScreen.EPSILON; var currentRelTileX = (currentTileX + 1) % 1, currentTileTopY = e.y + GameScreen.EPSILON, currentTileBottomY = e.y + e.height - GameScreen.EPSILON, currentRelTileTopY = (currentTileTopY + 1) % 1, currentRelTileBottomY = (currentTileBottomY + 1) % 1, currentTileTop = this.getTile(currentTileX, currentTileTopY), currentTileBottom = this.getTile(currentTileX, currentTileBottomY), tileTopY = e.y + GameScreen.EPSILON, tileBottomY = e.y + e.height - GameScreen.EPSILON, tileTop = this.getTile(tileX, tileTopY), tileBottom = this.getTile(tileX, tileBottomY), relTileTopY = (tileTopY + 1) % 1, relTileBottomY = (tileBottomY + 1) % 1; groundTypeTop = tileTop.getGroundTypeAt(relTileX, relTileTopY), groundTypeBottom = tileBottom.getGroundTypeAt(relTileX, relTileBottomY), groundTypeBottom == Tile.groundType.EMPTY || e.isOnMovingTile() || (newY = Math.floor(e.y + e.height) + currentTileBottom.getTopEdge(relTileX, currentRelTileBottomY) - e.height, Math.abs(newY - e.y) > .1 ? newY = e.y : (tileTopY = newY + GameScreen.EPSILON, tileBottomY = newY + e.height - GameScreen.EPSILON, tileTop = this.getTile(tileX, tileTopY), tileBottom = this.getTile(tileX, tileBottomY), relTileTopY = (tileTopY + 1) % 1, relTileBottomY = (tileBottomY + 1) % 1, groundTypeTop = tileTop.getGroundTypeAt(relTileX, relTileTopY), groundTypeBottom = tileBottom.getGroundTypeAt(relTileX, relTileBottomY))), groundTypeTop != Tile.groundType.EMPTY && currentTileTop.getGroundTypeAt(currentRelTileX, currentRelTileTopY) == Tile.groundType.EMPTY && (newX = e.revertDirection ? Math.floor(newX) + tileTop.getRightEdge(relTileX, relTileTopY) : Math.floor(newX + e.width) + tileTop.getLeftEdge(relTileX, relTileTopY) - e.width, e.revertDirection = !e.revertDirection, groundTypeTop != Tile.groundType.BASIC && (effectToPlay = groundTypeTop)); var yTest = newY + e.height + 2 * GameScreen.EPSILON, tileLeft = this.getTile(newX, yTest); groundTypeLeft = tileLeft.getGroundTypeAt((newX + 1) % 1, (yTest + 1) % 1); var tileCenter = this.getTile(newX + e.width / 2, yTest); groundTypeCenter = tileCenter.getGroundTypeAt((newX + e.width / 2 + 1) % 1, (yTest + 1) % 1); var tileRight = this.getTile(newX + e.width, yTest); if (groundTypeRight = tileRight.getGroundTypeAt((newX + e.width + 1) % 1, (yTest + 1) % 1), e.currentTile && e.currentTile.parentTile && 0 != moveDistance && 0 != e.currentTile.lastMoveX && Math.sameSign(moveDistance, e.currentTile.lastMoveX) || groundTypeLeft != Tile.groundType.EMPTY || groundTypeCenter != Tile.groundType.EMPTY || groundTypeRight != Tile.groundType.EMPTY) groundTypeLeft != Tile.groundType.BASIC && groundTypeLeft != Tile.groundType.EMPTY ? effectToPlay = groundTypeLeft : groundTypeCenter != Tile.groundType.BASIC && groundTypeCenter != Tile.groundType.EMPTY ? effectToPlay = groundTypeCenter : groundTypeRight != Tile.groundType.BASIC && groundTypeRight != Tile.groundType.EMPTY && (effectToPlay = groundTypeRight); else { var yTest2 = yTest + Config.PHYSICS.MAX_STEP_SIZE, topLeft = this.vRayHit(e, newX, yTest, yTest2, timeData), topCenter = this.vRayHit(e, newX + e.width / 2, yTest, yTest2, timeData), topRight = this.vRayHit(e, newX + e.width, yTest, yTest2, timeData); if (topLeft || topCenter || topRight) { var hit = topLeft; newY = hit.pos, topCenter && (!newY || topCenter.pos < newY) && (hit = topCenter, newY = hit.pos), topRight && (!newY || topRight.pos < newY) && (hit = topRight, newY = hit.pos), newY -= e.height, hit.type != Tile.groundType.BASIC && hit.type != Tile.groundType.EMPTY && (effectToPlay = hit.type) } else e.setOnGround(!1) } } else { newY = e.y + fallDistance; var topLeft = this.vRayHit(e, newX, e.y + e.height - GameScreen.EPSILON, newY + e.height, timeData), topRight = this.vRayHit(e, e.x + e.width - GameScreen.EPSILON, e.y + e.height - GameScreen.EPSILON, newY + e.height, timeData); (topLeft || topRight) && (e.setOnGround(!0), !topRight || topLeft.pos > topRight.pos ? (newY = topLeft.pos - e.height, effectToPlay = topLeft.type) : (newY = topRight.pos - e.height, effectToPlay = topRight.type)) } if (e.setPosition((newX + this.colCount) % this.colCount, (newY + this.rowCount) % this.rowCount), this.tutoVerticalTile && e.y + e.height / 2 > this.rowCount && !this.tutoTileTime ? (this.tutoTileStartTime = timeData.global, this.tutoTileTime = timeData.global + Config.TUTO.TILE_DURATION, GameScreen.speedFactor = 0) : this.tutoHorizontalTile && e.x + e.width > this.colCount && e.x + .55 * e.width < this.colCount && !this.tutoTileTime && (this.tutoTileStartTime = timeData.global, this.tutoTileTime = timeData.global + Config.TUTO.TILE_DURATION, GameScreen.speedFactor = 0), effectToPlay && this.playEffect(e, effectToPlay), e.update(timeData), !e.isEnnemy && !this.finished && !e.dying) { if (this.goalType == GoalType.COLLECT && !e.item) for (var i = 0; i < this.itemList.length; i++) e.item || this.itemList[i].entity || !this.itemList[i].checkReached(e.x + e.width / 2, e.y + e.height / 2, timeData) || (e.item = this.itemList[i], e.item.entity = e); if (this.goalType == GoalType.SAVE || this.goalType == GoalType.CAGE || e.item) for (var i in this.endPointList) if (this.endPointList[i].checkReached(e.x + e.width / 2, e.y, timeData, e.noScore)) { e.noScore || this.addScore(this.endPointList[i].score), this.win(e, this.endPointList[i]), this.endPointList[i].isSprite && (0 == this.game.progressBar.remainingDodos ? (this.game.app.assetManager.getSound("game.cage-destruction").reset().play(), this.endPointList[i].currentFrame = this.endPointList[i].cageSpriteList.length - 1) : (this.game.app.assetManager.getSound("game.cage-hit").reset().play(), this.endPointList[i].currentFrame = Math.min(this.game.progressBar.starCount, this.endPointList[i].cageSpriteList.length - 2))); for (var i in this.ennemyList) if (this.ennemyList[i].checkAlmostReached(e)) { Achievement.record(DataStore.achievementType.ALMOST_KILLED); break } } } }, World.prototype.vRayHit = function(entity, x, y1, y2, timeData) { var tileX = Math.floor(x), minTileY = Math.floor(y1), maxTileY = Math.floor(y2); x -= tileX; for (var y = minTileY; maxTileY >= y; y++) { var from = GameScreen.EPSILON; y == minTileY && (from = y1 - minTileY); var to = 1 - GameScreen.EPSILON; y == maxTileY && (to = y2 - maxTileY); var hit = this.getTile(tileX, y).vRayHit(entity, x, from, to, timeData); if (hit) return hit.pos += y, hit } return !1 }, World.prototype.playEffect = function(entity, effect) { switch (effect) { case Tile.groundType.TRAP: case Tile.groundType.TRAP_WALL_LEFT: case Tile.groundType.TRAP_WALL_RIGHT: this.trap(entity); break; case Tile.groundType.BUMP: this.bump(entity) } }, World.prototype.getHeight = function() { return this.mainSquare.length }, World.prototype.getWidth = function() { return this.mainSquare[0].length }, World.prototype.trap = function(entity) { entity.isEnnemy || entity.isItem || this.finished || entity.hit() }, World.prototype.hiddentrap = function(entity) { this.trap(entity) }, World.prototype.oneDodoLess = function(entity, score, isDead) { this.nextDyingDodo == entity && (this.nextDyingDodo = this.getRandomDodo(!0)), this.game.progressBar.oneDodoLess(), isDead && (this.lost++, this.game.lostCount = this.lost, this.lostRefreshTime = this.game.timeData.global); for (var i in DataStore.bonusList) { var bonus = DataStore.bonusList[i]; bonus.isFree && this.game.progressBar.remainingDodos == bonus.tuto_trigger && (this.showBonusIndicator = !0) } }, World.prototype.win = function(entity, endPoint) { if (!this.finished || this.goalType == GoalType.SURVIVE) { this.game.app.assetManager.getSound("game.saved").reset().play(); var isItem = !1; if (entity.item && (isItem = !0, entity.item.winning = !0), this.finished || this.goalType == GoalType.SAVE || this.goalType == GoalType.CAGE) { Achievement.record(DataStore.achievementType.SAVE); for (var winBuffer = [this.game.timeData.local], i = 0; i < this.winBuffer.length; i++) this.game.timeData.local - this.winBuffer[i] < Config.ACHIEVEMENT.MULTI_MAX_DELAY && winBuffer.push(this.winBuffer[i]); this.winBuffer = winBuffer, this.winBuffer.length > 1 && Achievement.record(DataStore.achievementType.MULTI_SAVE, this.winBuffer.length), entity.startWin(function() { entity.destroy() }, endPoint), this.oneDodoLess(entity, entity.score) } else entity.item = !1; this.game.progressBar.addValue(isItem ? 1 : entity.score) } }, World.prototype.bump = function(entity) { var x = entity.x; entity.revertDirection ? x -= entity.width / 2 : x += entity.width / 2; var y = entity.y + entity.height, tile = this.getTile(x, y); tile.bump((x + 1) % 1, (y + 1) % 1); var bumpSound = this.game.app.assetManager.getSound("game.bump"); bumpSound.reset(), bumpSound.play(), entity.bump() }, World.prototype.destroy = function() { this.game.app.assetManager.getSound("music").pause() }, World.prototype.activatePortal = function() { for (var i in this.endPointList) this.endPointList[i].isBonus && this.endPointList[i].activate(); this.checkPortalBonus() }, World.prototype.setImmunity = function(duration) { duration ? (this.stopImmunityTime = this.game.timeData.local + duration, this.refreshBonusTimer("immune", this.stopImmunityTime), this.game.setBonusEnabled("immune", !1)) : (this.stopImmunityTime = !1, this.game.setBonusEnabled("immune", !0)) }, World.prototype.setEnnemyFreeze = function(duration) { duration ? (this.stopEnnemyFreezeTime = this.game.timeData.local + duration, this.refreshBonusTimer("freeze", this.stopEnnemyFreezeTime), this.game.setBonusEnabled("freeze", !1)) : (this.stopEnnemyFreezeTime = !1, this.game.setBonusEnabled("freeze", !0)) }, World.prototype.refreshBonusTimer = function() {}, World.prototype.getRandomDodo = function(immuneFirst) { var list = this.getAllDodos(immuneFirst); return list.length > 0 ? list[Math.floor(Math.random() * list.length)] : immuneFirst ? this.getRandomDodo() : !1 }, World.prototype.getAllDodos = function(immuneOnly) { var list = []; for (var i in this.entityList) { var e = this.entityList[i]; e.dying || e.winning || immuneOnly && 0 != e.lifeCount || list.push(e) } return list }, World.prototype.getDodosAroundPoint = function(x, y, radius, radiusYFactor) { for (var list = this.getAllDodos(), newList = [], i = 0; i < list.length; i++) Math.distance(x, y, list[i].x + list[i].width / 2, list[i].y, 1 / radiusYFactor) <= radius && newList.push(list[i]); return newList }, World.prototype.addScore = function(amount) { this.lastScore = this.score, this.score += amount, this.scoreRefreshTime = this.game.timeData.global };