/* * This file is part of Deliantra clientV. * * Copyright (©) 2017 Marek Olszewski * * Deliantra clientV is free software: you can redistribute it and/or * modify it under the terms of the Affero GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the Affero GNU General Public Licens * and the GNU General Public License along with this program. If not, see * . * * The authors can be reached via e-mail to */ // GLOBAL FUNCTIONS /* * http://stackoverflow.com/questions/2752349/fast-rectangle-to-rectangle-intersection */ function intersect (a, b) { return a.left <= b.right && b.left <= a.right && a.top <= b.bottom && b.top <= a.bottom; } /* * http://stackoverflow.com/questions/6338217/get-a-css-value-with-javascript */ function getStyleRuleValue (styles, selector) { selector = selector.toLowerCase (); for (var i = 0; i < document.styleSheets.length; i++) { var mysheet = document.styleSheets[i]; var myrules = mysheet.cssRules ? mysheet.cssRules : mysheet.rules; for (var j = 0; j < myrules.length; j++) { if (myrules[j].selectorText && myrules[j].selectorText.toLowerCase () === selector) { var r = {}; for (var k = 0; k < styles.length; ++k) { r[styles[k]] = myrules[j].style[styles[k]]; } return r; } } } return null; } function unselectable (target) { target.setAttribute ("unselectable", "on"); if (typeof target.onselectstart != "undefined") // IE route target.onselectstart = function () { return false; }; else if (typeof target.style.MozUserSelect != "undefined") // Firefox route target.style.MozUserSelect = "none"; else // All other route (ie: Opera) target.onmousedown = function () { return false; }; } function registerVisibilityChangeCb (visibilityChangeCb) { var hidden, visibilityChange; if (typeof document.hidden !== "undefined") { hidden = "hidden", visibilityChange = "visibilitychange"; } else if (typeof document.msHidden !== "undefined") { hidden = "msHidden", visibilityChange = "msvisibilitychange"; } var document_hidden = document[hidden]; document.addEventListener (visibilityChange, function () { if (document_hidden != document[hidden]) { if (document[hidden]) { // Document hidden } else { // Document shown } document_hidden = document[hidden]; visibilityChangeCb (document_hidden); } }); } function isUndefined (o) { return typeof (o) === "undefined"; } function $_ (tag, properties) { var o = document.createElement (tag); for (var propName in properties) { o[propName] = properties[propName]; } return o; } // EXTENDS JS String.prototype.each = function (f, p) { for (var i = 0; i < this.length; ++i) { f.apply (this, [this[i], i, p]); } }; String.prototype.reverse = function () { var tmp = "" + this; return tmp.split ("").reverse ().join (""); }; String.rpad = function (o, p, s) { while (o.length < p) { o += s; } return o; }; Array.prototype.each = function (f, p) { for (var i = 0; i < this.length; ++i) { f.apply (this, [this[i], i, p]); } }; Array.prototype.contains = function (e) { return this.indexOf (e) >= 0 && this.indexOf (e) < this.length; }; function lsTest () { var test = "test"; try { localStorage.setItem (test, test); localStorage.removeItem (test); return true; } catch (e) { return false; } } var lsAvaible = lsTest (); /* GLOBAL */ function setCaretPosition (elem, caretPos) { elem = typeof (elem) === "string" ? document.getElementById (elemId) : elem; if (elem != null) { if (elem.createTextRange) { var range = elem.createTextRange (); range.move ("character", caretPos); range.select (); } else { if (elem.selectionStart) { elem.focus (); elem.setSelectionRange (caretPos, caretPos); } else { elem.focus (); } } } } var faces = {}; function getHeaderTime (req, callBackA, callBackB) { var nLastVisit = parseFloat (window.localStorage.getItem ("lm_" + this.filepath)), nLastModif = Date.parse (req.getResponseHeader ("Last-Modified")); if (isNaN (nLastVisit) || nLastModif > nLastVisit) { window.localStorage.setItem ("lm_" + this.filepath, Date.now ()); isFinite (nLastVisit) && callBackA (nLastModif, nLastVisit); } else { callBackB (nLastModif, nLastVisit); } } function ifHasChanged (sURL, fCallbackA, fCallbackB) { var oReq = new XMLHttpRequest (); oReq.open ("HEAD" /* use HEAD - we only need the headers! */ , sURL, true); oReq.onload = (function (ca, cb, req) { return function () { console.log (ca); getHeaderTime (req, ca, cb); }; }) (fCallbackA, fCallbackB, oReq); oReq.filepath = sURL; oReq.send (); } function getJSON (a, b, c) { var d = "undefined" != typeof XMLHttpRequest ? new XMLHttpRequest : new ActiveXObject ("Microsoft.XMLHTTP"); d.open ("get", a, !0); d.onreadystatechange = function () { var a, e; 4 == d.readyState && (a = d.status, 200 == a ? (e = JSON.parse (d.responseText), b && b (e)) : c && c (a)); }; d.send (); } function getJSONCached (a, b, c) { if (lsAvaible) { ifHasChanged (a, function () { getJSONEx (a, function (data) { localStorage.setItem ("fc_" + a, data); b (data); }); }, function () { b (localStorage.getItem ("fc_" + a)); }); } else { getJSONEx (a, b, c); } } function getData (a, b, c, t) { var d = "undefined" != typeof XMLHttpRequest ? new XMLHttpRequest : new ActiveXObject ("Microsoft.XMLHTTP"); d.open ("get", a, !0); d.onreadystatechange = function () { var a, e; 4 == d.readyState && (a = d.status, 200 == a ? (e = d.responseText, b && b (e)) : c && c (a)); }; if (t) { d.responseType = t; } d.send (); } function scriptLoadComplete () { document.body.innerHTML = ""; new CGame (); } window.addEventListener ("load", scriptLoadComplete); function fixedEncodeURIComponent (str) { return encodeURIComponent (str).replace (/[!'()*]/g, function (c) { return "%" + c.charCodeAt (0).toString (16); }); } var deliantra_util = { // these are not supposed to be fast, but short // why oh why do I have to reinvent a whole stdlib for this language utf8_encode: function (str) { return unescape (fixedEncodeURIComponent (str)); }, utf8_decode: function (str) { return decodeURIComponent (escape (str)); }, hex2bin: function (str) { return unescape (str.replace (/(..)/g, "%$1")); }, // bin2hex: function (str) { // str = str.split (""); // for (var i in str) // str [i] = str [i].charCodeAt (0).toString (16).replace (/^(.)$/, "0$1"); // return str.join (""); // }, // the hash used by deliantra dgst: function (data) { var h = new jsSHA ("SHA-512", "BYTES"); h.update (data); return this.hex2bin (h.getHash ("HEX")); }, // hashes a password - input unicode text, output binary hash_pw: function (pass) { pass = this.utf8_encode (pass).substr (0, 512); var hash = this.dgst (pass); for (var iteration = 0; iteration < 499; ++iteration) { hash = hash.split (""); for (var i = 0; i < hash.length; ++i) { hash[i] = String.fromCharCode (hash[i].charCodeAt (0) ^ pass.charCodeAt (i)); // assumes NaN ^ x == x } hash = this.dgst (hash.join ("")); } return hash; }, // the HMAC used by deliantra auth_pw: function (hash, nonce1, nonce2) { return this.dgst (this.utf8_decode (nonce1) + this.dgst (this.utf8_decode (nonce2) + hash)); }, }; String.prototype.each = function (f, p) { for (var i = 0; i < this.length; ++i) { f.apply (this, [this[i], i, p]); } }; Array.prototype.each = function (f, p) { for (var i = 0; i < this.length; ++i) { f.apply (this, [this[i], i, p]); } }; Array.prototype.contains = function (e) { return this.indexOf (e) >= 0 && this.indexOf (e) < this.length; }; function ptInRect (pt, rect) { if (pt.x < rect.x) return false; if (pt.y < rect.y) return false; if (pt.x > rect.x + rect.width) return false; if (pt.y > rect.y + rect.height) return false; return true; }