/// /* utils.js 工具类 */ 'use strict'; function utils() { this._init(); this.scan = { up: { x: 0, y: -1 }, left: { x: -1, y: 0 }, down: { x: 0, y: 1 }, right: { x: 1, y: 0 } }; this.scan2 = { up: { x: 0, y: -1 }, left: { x: -1, y: 0 }, down: { x: 0, y: 1 }, right: { x: 1, y: 0 }, leftup: { x: -1, y: -1 }, leftdown: { x: -1, y: 1 }, rightup: { x: 1, y: -1 }, rightdown: { x: 1, y: 1 } }; } utils.prototype._init = function () { // }; ////// 将文字中的${和}(表达式)进行替换 ////// utils.prototype.replaceText = function (text, prefix) { if (typeof text != 'string') return text; var index = text.indexOf('${'); if (index < 0) return text; var cnt = 0, curr = index; while (++curr < text.length) { if (text.charAt(curr) == '{') cnt++; if (text.charAt(curr) == '}') cnt--; if (cnt == 0) break; } if (cnt != 0) return text; var value = core.calValue(text.substring(index + 2, curr), prefix); if (value == null) value = ''; return ( text.substring(0, index) + value + core.replaceText(text.substring(curr + 1), prefix) ); }; utils.prototype.replaceValue = function (value) { if ( typeof value == 'string' && (value.indexOf(':') >= 0 || value.indexOf('flag:') >= 0 || value.indexOf('global:') >= 0) ) { if (value.indexOf('status:') >= 0) value = value.replace( /status:([a-zA-Z0-9_]+)/g, "core.getStatus('$1')" ); if (value.indexOf('buff:') >= 0) value = value.replace( /buff:([a-zA-Z0-9_]+)/g, "core.getBuff('$1')" ); if (value.indexOf('item:') >= 0) value = value.replace( /item:([a-zA-Z0-9_]+)/g, "core.itemCount('$1')" ); if (value.indexOf('flag:') >= 0 || value.indexOf('flag:') >= 0) value = value.replace( /flag[::]([a-zA-Z0-9_\u4E00-\u9FCC\u3040-\u30FF\u2160-\u216B\u0391-\u03C9]+)/g, "core.getFlag('$1', 0)" ); //if (value.indexOf('switch:' >= 0)) // value = value.replace(/switch:([a-zA-Z0-9_]+)/g, "core.getFlag('" + (prefix || ":f@x@y") + "@$1', 0)"); if (value.indexOf('global:') >= 0 || value.indexOf('global:') >= 0) value = value.replace( /global[::]([a-zA-Z0-9_\u4E00-\u9FCC\u3040-\u30FF\u2160-\u216B\u0391-\u03C9]+)/g, "core.getGlobal('$1', 0)" ); if (value.indexOf('enemy:') >= 0) value = value.replace( /enemy:([a-zA-Z0-9_]+)[\.:]([a-zA-Z0-9_]+)/g, "core.material.enemys['$1'].$2" ); if (value.indexOf('blockId:') >= 0) value = value.replace( /blockId:(\d+),(\d+)/g, 'core.getBlockId($1, $2)' ); if (value.indexOf('blockNumber:') >= 0) value = value.replace( /blockNumber:(\d+),(\d+)/g, 'core.getBlockNumber($1, $2)' ); if (value.indexOf('blockCls:') >= 0) value = value.replace( /blockCls:(\d+),(\d+)/g, 'core.getBlockCls($1, $2)' ); if (value.indexOf('equip:') >= 0) value = value.replace(/equip:(\d)/g, 'core.getEquip($1)'); if (value.indexOf('temp:') >= 0) value = value.replace( /temp:([a-zA-Z0-9_]+)/g, "core.getFlag('@temp@$1', 0)" ); } return value; }; ////// 计算表达式的值 ////// utils.prototype.calValue = function (value, prefix) { if (!core.isset(value)) return null; if (typeof value === 'string') { if ( value.indexOf(':') >= 0 || value.indexOf('flag:') >= 0 || value.indexOf('global:') >= 0 ) { if (value.indexOf('switch:') >= 0) value = value.replace( /switch:([a-zA-Z0-9_]+)/g, "core.getFlag('" + (prefix || ':f@x@y') + "@$1', 0)" ); value = this.replaceValue(value); } return eval(value); } if (value instanceof Function) { return value(); } return value; }; ////// 向某个数组前插入另一个数组或元素 ////// utils.prototype.unshift = function (a, b) { if (!(a instanceof Array) || b == null) return; if (b instanceof Array) { core.clone(b) .reverse() .forEach(function (e) { a.unshift(e); }); } else a.unshift(b); return a; }; ////// 向某个数组后插入另一个数组或元素 ////// utils.prototype.push = function (a, b) { if (!(a instanceof Array) || b == null) return; if (b instanceof Array) { core.clone(b).forEach(function (e) { a.push(e); }); } else a.push(b); return a; }; utils.prototype.decompress = function (value) { try { var output = lzw_decode(value); if (output) return JSON.parse(output); } catch (e) {} try { var output = LZString.decompress(value); if (output) return JSON.parse(output); } catch (e) {} try { return JSON.parse(value); } catch (e) { console.error(e); } return null; }; ////// 设置本地存储 ////// utils.prototype.setLocalStorage = function (key, value) { try { if (value == null) { this.removeLocalStorage(key); return; } var str = JSON.stringify(value).replace( /[\u007F-\uFFFF]/g, function (chr) { return ( '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).substr(-4) ); } ); localStorage.setItem(core.firstData.name + '_' + key, str); if (key == 'autoSave') core.saves.ids[0] = true; else if (/^save\d+$/.test(key)) core.saves.ids[parseInt(key.substring(4))] = true; return true; } catch (e) { console.error(e); return false; } }; ////// 获得本地存储 ////// utils.prototype.getLocalStorage = function (key, defaultValue) { try { var value = JSON.parse( localStorage.getItem(core.firstData.name + '_' + key) ); if (value == null) return defaultValue; return value; } catch (e) { return defaultValue; } }; ////// 移除本地存储 ////// utils.prototype.removeLocalStorage = function (key) { localStorage.removeItem(core.firstData.name + '_' + key); if (key == 'autoSave') delete core.saves.ids[0]; else if (/^save\d+$/.test(key)) delete core.saves.ids[parseInt(key.substring(4))]; }; utils.prototype.setLocalForage = function ( key, value, successCallback, errorCallback ) { if (value == null) { this.removeLocalForage(key); return; } var name = core.firstData.name + '_' + key; var str = JSON.stringify(value).replace(/[\u007F-\uFFFF]/g, function (chr) { return '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).substr(-4); }); var callback = function (err) { if (err) { if (errorCallback) errorCallback(err); } else { if (key == 'autoSave') core.saves.ids[0] = true; else if (/^save\d+$/.test(key)) core.saves.ids[parseInt(key.substring(4))] = true; if (successCallback) successCallback(); } }; this._setLocalForage_set(name, str, callback); }; utils.prototype._setLocalForage_set = function (name, str, callback) { if (window.jsinterface && window.jsinterface.setLocalForage) { var id = setTimeout(null); core['__callback' + id] = callback; core.saves.cache[name] = str; window.jsinterface.setLocalForage(id, name, str); } else { var compressed = str.length > 100000 ? LZString.compress(str) : lzw_encode(str); core.saves.cache[name] = compressed; localforage.setItem(name, compressed, callback); } }; utils.prototype.getLocalForage = function ( key, defaultValue, successCallback, errorCallback ) { var name = core.firstData.name + '_' + key; var callback = function (err, value) { if (err) { if (errorCallback) errorCallback(err); } else { core.saves.cache[name] = value; if (!successCallback) return; if (value != null) { var res = core.utils.decompress(value); successCallback(res == null ? defaultValue : res); return; } successCallback(defaultValue); } }; if (core.saves.cache[name] != null) { return callback(null, core.saves.cache[name]); } this._getLocalForage_get(name, callback); }; utils.prototype._getLocalForage_get = function (name, callback) { if (window.jsinterface && window.jsinterface.getLocalForage) { var id = setTimeout(null); core['__callback' + id] = callback; window.jsinterface.getLocalForage(id, name); } else { localforage.getItem(name, callback); } }; utils.prototype.removeLocalForage = function ( key, successCallback, errorCallback ) { var name = core.firstData.name + '_' + key; var callback = function (err) { if (err) { if (errorCallback) errorCallback(err); } else { if (key == 'autoSave') delete core.saves.ids[0]; else if (/^save\d+$/.test(key)) delete core.saves.ids[parseInt(key.substring(4))]; if (successCallback) successCallback(); } }; delete core.saves.cache[name]; this._removeLocalForage_remove(name, callback); }; utils.prototype._removeLocalForage_remove = function (name, callback) { if (window.jsinterface && window.jsinterface.removeLocalForage) { var id = setTimeout(null); core['__callback' + id] = callback; window.jsinterface.removeLocalForage(id, name); } else { localforage.removeItem(name, callback); } }; utils.prototype.clearLocalForage = function (callback) { core.saves.cache = {}; if (window.jsinterface && window.jsinterface.clearLocalForage) { var id = setTimeout(null); core['__callback' + id] = callback; window.jsinterface.clearLocalForage(id); } else { localforage.clear(callback); } }; utils.prototype.iterateLocalForage = function (iter, callback) { if (window.jsinterface && window.jsinterface.iterateLocalForage) { var id = setTimeout(null); core['__iter' + id] = iter; core['__callback' + id] = callback; window.jsinterface.iterateLocalForage(id); } else { localforage.iterate(iter, callback); } }; utils.prototype.keysLocalForage = function (callback) { if (window.jsinterface && window.jsinterface.keysLocalForage) { var id = setTimeout(null); core['__callback' + id] = callback; window.jsinterface.keysLocalForage(id); } else { localforage.keys(callback); } }; utils.prototype.lengthLocalForage = function (callback) { if (window.jsinterface && window.jsinterface.lengthLocalForage) { var id = setTimeout(null); core['__callback' + id] = callback; window.jsinterface.lengthLocalForage(id); } else { localforage.length(callback); } }; utils.prototype.setGlobal = function (key, value) { if (core.isReplaying()) return; core.setLocalStorage(key, value); }; utils.prototype.getGlobal = function (key, defaultValue) { var value; if (core.isReplaying()) { // 不考虑key不一致的情况 var action = core.status.replay.toReplay.shift(); if (action.indexOf('input2:') == 0) { value = JSON.parse(core.decodeBase64(action.substring(7))); core.setFlag('__global__' + key, value); core.status.route.push( 'input2:' + core.encodeBase64(JSON.stringify(value)) ); } else { // 录像兼容性:尝试从flag和localStorage获得 // 注意这里不再二次记录 input2: 到录像 core.status.replay.toReplay.unshift(action); value = core.getFlag( '__global__' + key, core.getLocalStorage(key, defaultValue) ); } } else { value = core.getLocalStorage(key, defaultValue); core.setFlag('__global__' + key, value); core.status.route.push( 'input2:' + core.encodeBase64(JSON.stringify(value)) ); } return value; }; ////// 深拷贝一个对象 ////// utils.prototype.clone = function (data, filter, recursion) { if (!core.isset(data)) return null; // date if (data instanceof Date) { var copy = new Date(); copy.setTime(data.getTime()); return copy; } // array if (data instanceof Array) { var copy = []; for (var i in data) { if (!filter || filter(i, data[i])) copy[i] = core.clone( data[i], recursion ? filter : null, recursion ); } return copy; } // 函数 if (data instanceof Function) { return data; } // object if (data instanceof Object) { var copy = {}; for (var i in data) { if (data.hasOwnProperty(i) && (!filter || filter(i, data[i]))) copy[i] = core.clone( data[i], recursion ? filter : null, recursion ); } return copy; } return data; }; ////// 深拷贝1D/2D数组优化 ////// utils.prototype.cloneArray = function (data) { if (!(data instanceof Array)) return this.clone(data); if (data[0] instanceof Array) { return data.map(function (one) { return one.slice(); }); } else { return data.slice(); } }; ////// 裁剪图片 ////// utils.prototype.splitImage = function (image, width, height) { if (typeof image == 'string') { image = core.getMappedName(image); image = core.material.images.images[image]; } if (!image) return []; width = width || 32; height = height || width; var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); var ans = []; for (var j = 0; j < image.height; j += height) { for (var i = 0; i < image.width; i += width) { var w = Math.min(width, image.width - i), h = Math.min(height, image.height - j); canvas.width = w; canvas.height = h; core.drawImage(ctx, image, i, j, w, h, 0, 0, w, h); var img = new Image(); img.src = canvas.toDataURL('image/png'); ans.push(img); } } return ans; }; ////// 格式化时间为字符串 ////// utils.prototype.formatDate = function (date) { if (!date) date = new Date(); return ( '' + date.getFullYear() + '-' + core.setTwoDigits(date.getMonth() + 1) + '-' + core.setTwoDigits(date.getDate()) + ' ' + core.setTwoDigits(date.getHours()) + ':' + core.setTwoDigits(date.getMinutes()) + ':' + core.setTwoDigits(date.getSeconds()) ); }; ////// 格式化时间为最简字符串 ////// utils.prototype.formatDate2 = function (date) { if (!date) date = new Date(); return ( '' + date.getFullYear() + core.setTwoDigits(date.getMonth() + 1) + core.setTwoDigits(date.getDate()) + core.setTwoDigits(date.getHours()) + core.setTwoDigits(date.getMinutes()) + core.setTwoDigits(date.getSeconds()) ); }; utils.prototype.formatTime = function (time) { return ( core.setTwoDigits(parseInt(time / 3600000)) + ':' + core.setTwoDigits(parseInt(time / 60000) % 60) + ':' + core.setTwoDigits(parseInt(time / 1000) % 60) ); }; ////// 两位数显示 ////// utils.prototype.setTwoDigits = function (x) { return parseInt(x) < 10 && parseInt(x) >= 0 ? '0' + x : x; }; utils.prototype.formatSize = function (size) { if (size < 1024) return size + 'B'; else if (size < 1024 * 1024) return (size / 1024).toFixed(2) + 'KB'; else return (size / 1024 / 1024).toFixed(2) + 'MB'; }; utils.prototype.formatBigNumber = function (x, digits) { if (typeof x === 'string') return x; if (digits === true) digits = 4; // 兼容旧版onMap参数 digits ??= 6; x = Math.trunc(parseFloat(x)); // 尝试识别为小数,然后向0取整 if (x == null || !Number.isFinite(x)) return '???'; // 无法识别的数或正负无穷大,显示'???' var units = [ // 单位及其后缀字母,可自定义,如改成千进制下的K、M、G、T、P { val: 1e4, suffix: 'w' }, { val: 1e8, suffix: 'e' }, { val: 1e12, suffix: 'z' }, { val: 1e16, suffix: 'j' }, { val: 1e20, suffix: 'g' } ]; if (Math.abs(x) > 1e20 * Math.pow(10, digits - 2)) return x.toExponential(0); // 绝对值过大以致于失去精度的数,直接使用科学记数法,系数只保留整数 var sign = x < 0 ? '-' : ''; x = Math.abs(x); if (x < Math.pow(10, digits)) return sign + x; for (var i = 0; i < units.length; ++i) { var each = units[i]; var u = (x / each.val) .toFixed(digits) .slice(0, sign === '-' ? digits : digits + 1); if (u.indexOf('.') < 0) continue; u = u.substring( 0, u[u.length - 2] == '.' ? u.length - 2 : u.length - 1 ); return sign + u + each.suffix; } return sign + x.toExponential(0); }; ////// 变速移动 ////// utils.prototype.applyEasing = function (name) { var list = { easeIn: function (t) { return Math.pow(t, 3); }, easeOut: function (t) { return 1 - Math.pow(1 - t, 3); }, easeInOut: function (t) { // easeInOut试了一下感觉二次方效果明显点 if (t < 0.5) return Math.pow(t, 2) * 2; else return 1 - Math.pow(1 - t, 2) * 2; }, linear: function (t) { return t; } }; if (name == 'random') { var keys = Object.keys(list); name = keys[Math.floor(Math.random() * keys.length)]; } return list[name] || list.linear; }; ////// 数组转RGB ////// utils.prototype.arrayToRGB = function (color) { if (!(color instanceof Array)) return color; var nowR = this.clamp(parseInt(color[0]), 0, 255), nowG = this.clamp(parseInt(color[1]), 0, 255), nowB = this.clamp(parseInt(color[2]), 0, 255); return ( '#' + ((1 << 24) + (nowR << 16) + (nowG << 8) + nowB).toString(16).slice(1) ); }; utils.prototype.arrayToRGBA = function (color) { if (!(color instanceof Array)) return color; if (color[3] == null) color[3] = 1; var nowR = this.clamp(parseInt(color[0]), 0, 255), nowG = this.clamp(parseInt(color[1]), 0, 255), nowB = this.clamp(parseInt(color[2]), 0, 255), nowA = this.clamp(parseFloat(color[3]), 0, 1); return 'rgba(' + nowR + ',' + nowG + ',' + nowB + ',' + nowA + ')'; }; ////// 加密路线 ////// utils.prototype.encodeRoute = function (route) { var ans = '', lastMove = '', cnt = 0; route.forEach(function (t) { if (t == 'up' || t == 'down' || t == 'left' || t == 'right') { if (t != lastMove && cnt > 0) { ans += lastMove.substring(0, 1).toUpperCase(); if (cnt > 1) ans += cnt; cnt = 0; } lastMove = t; cnt++; } else { if (cnt > 0) { ans += lastMove.substring(0, 1).toUpperCase(); if (cnt > 1) ans += cnt; cnt = 0; } ans += core.utils._encodeRoute_encodeOne(t); } }); if (cnt > 0) { ans += lastMove.substring(0, 1).toUpperCase(); if (cnt > 1) ans += cnt; } return LZString.compressToBase64(ans); }; utils.prototype._encodeRoute_id2number = function (id) { var number = core.maps.getNumberById(id); return number == 0 ? id : number; }; utils.prototype._encodeRoute_encodeOne = function (t) { if (t.indexOf('item:') == 0) return 'I' + this._encodeRoute_id2number(t.substring(5)) + ':'; else if (t.indexOf('unEquip:') == 0) return 'u' + t.substring(8); else if (t.indexOf('equip:') == 0) return 'e' + this._encodeRoute_id2number(t.substring(6)) + ':'; else if (t.indexOf('saveEquip:') == 0) return 's' + t.substring(10); else if (t.indexOf('loadEquip:') == 0) return 'l' + t.substring(10); else if (t.indexOf('fly:') == 0) return 'F' + t.substring(4) + ':'; else if (t == 'choices:none') return 'c'; else if (t.indexOf('choices:') == 0) return 'C' + t.substring(8); else if (t.indexOf('shop:') == 0) return 'S' + t.substring(5) + ':'; else if (t == 'turn') return 'T'; else if (t.indexOf('turn:') == 0) return 't' + t.substring(5).substring(0, 1).toUpperCase() + ':'; else if (t == 'getNext') return 'G'; else if (t == 'input:none') return 'p'; else if (t.indexOf('input:') == 0) return 'P' + t.substring(6); else if (t.indexOf('input2:') == 0) return 'Q' + t.substring(7) + ':'; else if (t == 'no') return 'N'; else if (t.indexOf('move:') == 0) return 'M' + t.substring(5); else if (t.indexOf('key:') == 0) return 'K' + t.substring(4); else if (t.indexOf('click:') == 0) return 'k' + t.substring(6); else if (t.indexOf('random:') == 0) return 'X' + t.substring(7); return '(' + t + ')'; }; ////// 解密路线 ////// utils.prototype.decodeRoute = function (route) { if (!route) return route; // 解压缩 try { var v = LZString.decompressFromBase64(route); if (v != null && /^[-_a-zA-Z0-9+\/=:()]*$/.test(v)) { if (v != '' || route.length < 8) route = v; } } catch (e) {} var decodeObj = { route: route, index: 0, ans: [] }; while (decodeObj.index < decodeObj.route.length) { this._decodeRoute_decodeOne( decodeObj, decodeObj.route.charAt(decodeObj.index++) ); } return decodeObj.ans; }; utils.prototype._decodeRoute_getNumber = function (decodeObj, noparse) { var num = ''; var first = true; while (true) { var ch = decodeObj.route.charAt(decodeObj.index); if (ch >= '0' && ch <= '9') num += ch; else if (ch == '-' && first) num += ch; else break; first = false; decodeObj.index++; } if (num.length == 0) num = '1'; return noparse ? num : parseInt(num); }; utils.prototype._decodeRoute_getString = function (decodeObj) { var str = ''; while ( decodeObj.index < decodeObj.route.length && decodeObj.route.charAt(decodeObj.index) != ':' ) { str += decodeObj.route.charAt(decodeObj.index++); } decodeObj.index++; return str; }; utils.prototype._decodeRoute_number2id = function (number) { if (/^\d+$/.test(number)) { var info = core.maps.blocksInfo[number]; if (info) return info.id; } return number; }; utils.prototype._decodeRoute_decodeOne = function (decodeObj, c) { // --- 特殊处理自定义项 if (c == '(') { var idx = decodeObj.route.indexOf(')', decodeObj.index); if (idx >= 0) { decodeObj.ans.push(decodeObj.route.substring(decodeObj.index, idx)); decodeObj.index = idx + 1; return; } } var nxt = c == 'I' || c == 'e' || c == 'F' || c == 'S' || c == 'Q' || c == 't' ? this._decodeRoute_getString(decodeObj) : this._decodeRoute_getNumber(decodeObj); var mp = { U: 'up', D: 'down', L: 'left', R: 'right' }; switch (c) { case 'U': case 'D': case 'L': case 'R': for (var i = 0; i < nxt; i++) decodeObj.ans.push(mp[c]); break; case 'I': decodeObj.ans.push('item:' + this._decodeRoute_number2id(nxt)); break; case 'u': decodeObj.ans.push('unEquip:' + nxt); break; case 'e': decodeObj.ans.push('equip:' + this._decodeRoute_number2id(nxt)); break; case 's': decodeObj.ans.push('saveEquip:' + nxt); break; case 'l': decodeObj.ans.push('loadEquip:' + nxt); break; case 'F': decodeObj.ans.push('fly:' + nxt); break; case 'c': decodeObj.ans.push('choices:none'); break; case 'C': decodeObj.ans.push('choices:' + nxt); break; case 'S': decodeObj.ans.push('shop:' + nxt); break; case 'T': decodeObj.ans.push('turn'); break; case 't': decodeObj.ans.push('turn:' + mp[nxt]); break; case 'G': decodeObj.ans.push('getNext'); break; case 'p': decodeObj.ans.push('input:none'); break; case 'P': decodeObj.ans.push('input:' + nxt); break; case 'Q': decodeObj.ans.push('input2:' + nxt); break; case 'N': decodeObj.ans.push('no'); break; case 'M': ++decodeObj.index; decodeObj.ans.push( 'move:' + nxt + ':' + this._decodeRoute_getNumber(decodeObj) ); break; case 'K': decodeObj.ans.push('key:' + nxt); break; case 'k': ++decodeObj.index; var px = this._decodeRoute_getNumber(decodeObj); ++decodeObj.index; var py = this._decodeRoute_getNumber(decodeObj); decodeObj.ans.push('click:' + nxt + ':' + px + ':' + py); break; case 'X': decodeObj.ans.push('random:' + nxt); break; } }; ////// 判断某对象是否不为null也不为NaN ////// utils.prototype.isset = function (val) { return val != null && !(typeof val == 'number' && isNaN(val)); }; ////// 获得子数组 ////// utils.prototype.subarray = function (a, b) { if (!(a instanceof Array) || !(b instanceof Array) || a.length < b.length) return null; for (var i = 0; i < b.length; ++i) { if (a[i] != b[i]) return null; } return a.slice(b.length); }; utils.prototype.inArray = function (array, element) { return array instanceof Array && array.indexOf(element) >= 0; }; utils.prototype.clamp = function (x, a, b) { var min = Math.min(a, b), max = Math.max(a, b); return Math.min(Math.max(x || 0, min), max); }; utils.prototype.getCookie = function (name) { var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)')); return match ? match[2] : null; }; ////// 设置statusBar的innerHTML,会自动斜体和放缩,也可以增加自定义css ////// utils.prototype.setStatusBarInnerHTML = function (name, value, css) { if (!core.statusBar[name]) return; if (typeof value == 'number') value = this.formatBigNumber(value); var italic = /^[-a-zA-Z0-9`~!@#$%^&*()_=+\[{\]}\\|;:'",<.>\/?]*$/.test( value ); var style = 'font-style: ' + (italic ? 'italic' : 'normal') + '; '; style += 'text-shadow: #000 1px 0 0, #000 0 1px 0, #000 -1px 0 0, #000 0 -1px 0; '; // 判定是否需要缩放 var length = this.strlen(value) || 1; style += 'font-size: ' + Math.min(1, 7 / length) + 'em; '; if (css) style += css; var _style = core.statusBar[name].getAttribute('_style'); var _value = core.statusBar[name].getAttribute('_value'); if (_style == style) { if (value == _value) return; core.statusBar[name].children[0].innerText = value; } else { core.statusBar[name].innerHTML = ""; core.statusBar[name].children[0].innerText = value; core.statusBar[name].setAttribute('_style', style); } core.statusBar[name].setAttribute('_value', value); }; utils.prototype.strlen = function (str) { var count = 0; for (var i = 0, len = str.length; i < len; i++) { count += str.charCodeAt(i) < 256 ? 1 : 2; } return count; }; utils.prototype.turnDirection = function (turn, direction) { direction = direction || core.getHeroLoc('direction'); var directionList = [ 'left', 'leftup', 'up', 'rightup', 'right', 'rightdown', 'down', 'leftdown' ]; if (directionList.indexOf(turn) >= 0) return turn; if (turn == ':hero') return core.getHeroLoc('direction'); if (turn == ':backhero') return this.turnDirection(':back', core.getHeroLoc('direction')); if (typeof turn === 'number' && turn % 45 == 0) turn /= 45; else { switch (turn) { case ':left': turn = 6; break; // turn left case ':right': turn = 2; break; // turn right case ':back': turn = 4; break; // turn back default: turn = 0; break; } } var index = directionList.indexOf(direction); if (index < 0) return direction; return directionList[(index + (turn || 0)) % directionList.length]; }; utils.prototype.matchWildcard = function (pattern, string) { try { return new RegExp( '^' + pattern .split(/\*+/) .map(function (s) { return s.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); }) .join('.*') + '$' ).test(string); } catch (e) { return false; } }; utils.prototype.matchRegex = function (pattern, string) { try { if (pattern.startsWith('^')) pattern = pattern.substring(1); if (pattern.endsWith('$')) pattern = pattern.substring(0, pattern.length - 1); return new RegExp('^' + pattern + '$').test(string); } catch (e) { return false; } }; ////// Base64加密 ////// utils.prototype.encodeBase64 = function (str) { return btoa( encodeURIComponent(str).replace( /%([0-9A-F]{2})/g, function (match, p1) { return String.fromCharCode(parseInt(p1, 16)); } ) ); }; ////// Base64解密 ////// utils.prototype.decodeBase64 = function (str) { return decodeURIComponent( atob(str) .split('') .map(function (c) { return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); }) .join('') ); }; utils.prototype.rand = function (num) { var rand = core.getFlag('__rand__'); rand = this.__next_rand(rand); core.setFlag('__rand__', rand); var ans = rand / 2147483647; if (num && num > 0) return Math.floor(ans * num); return ans; }; ////// 生成随机数(录像方法) ////// utils.prototype.rand2 = function (num) { num = num || 2147483648; num = Math.abs(num); var value; if (core.isReplaying()) { var action = core.status.replay.toReplay.shift(); if (action.indexOf('random:') == 0) { value = parseInt(action.substring(7)); if (isNaN(value) || value >= num || value < 0) { console.warn('错误!当前random:项超过范围。将重新随机生成!'); value = Math.floor(Math.random() * num); } } else { console.warn('错误!当前需要一个random:项。将重新随机生成!'); value = Math.floor(Math.random() * num); } } else { value = Math.floor(Math.random() * num); } core.status.route.push('random:' + value); return value; }; utils.prototype.__init_seed = function () { var rand = (new Date().getTime() % 34834795) + 3534; rand = this.__next_rand(rand); rand = this.__next_rand(rand); rand = this.__next_rand(rand); core.setFlag('__seed__', rand); core.setFlag('__rand__', rand); }; utils.prototype.__next_rand = function (_rand) { _rand = (_rand % 127773) * 16807 - ~~(_rand / 127773) * 2836; _rand += _rand < 0 ? 2147483647 : 0; return _rand; }; ////// 读取一个本地文件内容 ////// utils.prototype.readFile = function (success, error, accept, readType) { core.platform.successCallback = success; core.platform.errorCallback = error; if (window.jsinterface) { window.jsinterface.readFile(); return; } // step 0: 不为http/https,直接不支持 if (!core.platform.isOnline) { alert('离线状态下不支持文件读取!'); if (error) error(); return; } // Step 1: 如果不支持FileReader,直接不支持 if (core.platform.fileReader == null) { alert('当前浏览器不支持FileReader!'); if (error) error(); return; } if (core.platform.fileInput == null) { core.platform.fileInput = document.createElement('input'); core.platform.fileInput.style.opacity = 0; core.platform.fileInput.type = 'file'; core.platform.fileInput.onchange = function () { var files = core.platform.fileInput.files; if (files.length == 0) { if (core.platform.errorCallback) core.platform.errorCallback(); return; } if (!readType) core.platform.fileReader.readAsText( core.platform.fileInput.files[0] ); else core.platform.fileReader.readAsDataURL( core.platform.fileInput.files[0] ); core.platform.fileInput.value = ''; }; } core.platform.fileInput.value = ''; if (accept) core.platform.fileInput.accept = accept; core.platform.fileInput.click(); }; ////// 读取文件完毕 ////// utils.prototype.readFileContent = function (content) { var obj = null; if (content.slice(0, 4) === 'data') { if (core.platform.successCallback) core.platform.successCallback(content); return; } // 检查base64 try { obj = JSON.parse(LZString.decompressFromBase64(content)); } catch (e) {} if (!obj) { try { obj = JSON.parse(content); } catch (e) { console.error(e); } } if (obj) { if (core.platform.successCallback) core.platform.successCallback(obj); return; } if (core.platform.errorCallback) core.platform.errorCallback(); }; ////// 下载文件到本地 ////// utils.prototype.download = function (filename, content) { if (window.jsinterface) { window.jsinterface.download(filename, content); return; } // Step 0: 不为http/https,直接不支持 if (!core.platform.isOnline) { alert('离线状态下不支持下载操作!'); return; } // Step 1: 如果是iOS平台,直接不支持 if (core.platform.isIOS) { if (core.copy(content)) { alert( 'iOS平台下不支持直接下载文件!\n所有应下载内容已经复制到您的剪切板,请自行创建空白文件并粘贴。' ); } else { alert('iOS平台下不支持下载操作!'); } return; } // Step 2: 如果不是PC平台(Android),则只支持chrome if (!core.platform.isPC) { if ( !core.platform.isChrome || core.platform.isQQ || core.platform.isWeChat ) { // 检测chrome if (core.copy(content)) { alert( '移动端只有Chrome浏览器支持直接下载文件!\n所有应下载内容已经复制到您的剪切板,请自行创建空白文件并粘贴。' ); } else { alert('该平台或浏览器暂不支持下载操作!'); } return; } } // Step 3: 如果是Safari浏览器,则提示并打开新窗口 if (core.platform.isSafari) { alert( '你当前使用的是Safari浏览器,不支持直接下载文件。\n即将打开一个新窗口为应下载内容,请自行全选复制然后创建空白文件并粘贴。' ); var blob = new Blob([content], { type: 'text/plain;charset=utf-8' }); var href = window.URL.createObjectURL(blob); var opened = window.open(href, '_blank'); window.URL.revokeObjectURL(href); return; } // Step 4: 下载 var blob = new Blob([content], { type: 'text/plain;charset=utf-8' }); if (window.navigator.msSaveOrOpenBlob) { window.navigator.msSaveBlob(blob, filename); } else { var href = window.URL.createObjectURL(blob); var elem = window.document.createElement('a'); elem.href = href; elem.download = filename; document.body.appendChild(elem); elem.click(); document.body.removeChild(elem); window.URL.revokeObjectURL(href); } }; ////// 复制一段内容到剪切板 ////// utils.prototype.copy = function (data) { if (window.jsinterface) { window.jsinterface.copy(data); return true; } if (!core.platform.supportCopy) return false; var textArea = document.createElement('textarea'); textArea.style.position = 'fixed'; textArea.style.top = 0; textArea.style.left = 0; textArea.style.width = '2em'; textArea.style.height = '2em'; textArea.style.padding = 0; textArea.style.border = 'none'; textArea.style.outline = 'none'; textArea.style.boxShadow = 'none'; textArea.style.background = 'transparent'; textArea.value = data; document.body.appendChild(textArea); textArea.focus(); textArea.setSelectionRange(0, textArea.value.length); var successful = false; try { successful = document.execCommand('copy'); } catch (err) { successful = false; } document.body.removeChild(textArea); return successful; }; ////// 显示一段confirm ////// utils.prototype.myconfirm = function (hint, yesCallback, noCallback) { main.dom.inputDiv.style.display = 'block'; main.dom.inputMessage.innerHTML = hint.replace(/\n/g, '
'); main.dom.inputBox.style.display = 'none'; main.dom.inputYes.blur(); main.dom.inputNo.blur(); core.status.holdingKeys = []; core.platform.successCallback = yesCallback; core.platform.errorCallback = noCallback; }; ////// 让用户输入一段文字 ////// utils.prototype.myprompt = function (hint, value, callback) { main.dom.inputDiv.style.display = 'block'; main.dom.inputMessage.innerHTML = hint.replace(/\n/g, '
'); main.dom.inputBox.style.display = 'block'; main.dom.inputBox.value = value == null ? '' : value; main.dom.inputYes.blur(); main.dom.inputNo.blur(); setTimeout(function () { main.dom.inputBox.focus(); }); core.status.holdingKeys = []; core.platform.successCallback = core.platform.errorCallback = callback; }; ////// 动画显示某对象 ////// utils.prototype.showWithAnimate = function (obj, speed, callback) { obj.style.display = 'block'; if (!speed || main.mode != 'play') { obj.style.opacity = 1; if (callback) callback(); return; } obj.style.opacity = 0; var opacityVal = 0; var showAnimate = window.setInterval(function () { opacityVal += 0.03; obj.style.opacity = opacityVal; if (opacityVal > 1) { clearInterval(showAnimate); if (callback) callback(); } }, speed); }; ////// 动画使某对象消失 ////// utils.prototype.hideWithAnimate = function (obj, speed, callback) { if (!speed || main.mode != 'play') { obj.style.display = 'none'; if (callback) callback(); return; } obj.style.opacity = 1; var opacityVal = 1; var hideAnimate = window.setInterval(function () { opacityVal -= 0.03; obj.style.opacity = opacityVal; if (opacityVal < 0) { obj.style.display = 'none'; clearInterval(hideAnimate); if (callback) callback(); } }, speed); }; ////// 生成浏览器唯一的 guid ////// utils.prototype.getGuid = function () { var guid = localStorage.getItem('guid'); if (guid != null) return guid; guid = 'xxxxxxxx_xxxx_4xxx_yxxx_xxxxxxxxxxxx'.replace( /[xy]/g, function (c) { var r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); } ); localStorage.setItem('guid', guid); return guid; }; utils.prototype.hashCode = function (obj) { if (typeof obj == 'string') { var hash = 0, i, chr; if (obj.length === 0) return hash; for (i = 0; i < obj.length; i++) { chr = obj.charCodeAt(i); hash = (hash << 5) - hash + chr; hash |= 0; } return hash; } return this.hashCode(JSON.stringify(obj).split('').sort().join('')); }; utils.prototype.same = function (a, b) { if (a == null && b == null) return true; if (a == null || b == null) return false; if (a === b) return true; if (a instanceof Array && b instanceof Array) { if (a.length != b.length) return false; for (var i = 0; i < a.length; i++) { if (!this.same(a[i], b[i])) return false; } return true; } if (a instanceof Object && b instanceof Object) { var obj = {}; for (var i in a) obj[i] = true; for (var i in b) obj[i] = true; for (var i in obj) { if (!this.same(a[i], b[i])) return false; } return true; } return false; }; utils.prototype.unzip = function ( blobOrUrl, success, error, convertToText, onprogress ) { var _error = function (msg) { console.error(msg); if (error) error(msg); }; if (!window.zip) { return _error('zip.js not exists!'); } if (typeof blobOrUrl == 'string') { return core.http( 'GET', blobOrUrl, null, function (data) { core.unzip(data, success, error, convertToText); }, _error, null, 'blob', onprogress ); } if (!(blobOrUrl instanceof Blob)) { return _error('Should use Blob or URL as input'); } zip.createReader( new zip.BlobReader(blobOrUrl), function (reader) { reader.getEntries(function (entries) { core.utils._unzip_readEntries( entries, function (data) { reader.close(function () { if (success) success(data); }); }, convertToText ); }); }, _error ); }; utils.prototype._unzip_readEntries = function ( entries, success, convertToText ) { var results = {}; if (entries == null || entries.length == 0) { return success(results); } var length = entries.length; entries.forEach(function (entry) { entry.getData( convertToText ? new zip.TextWriter('utf8') : new zip.BlobWriter(), function (data) { results[entry.filename] = data; length--; if (length == 0) { success(results); } } ); }); }; utils.prototype.http = function ( type, url, formData, success, error, mimeType, responseType, onprogress ) { var xhr = new XMLHttpRequest(); xhr.open(type, url, true); if (mimeType) xhr.overrideMimeType(mimeType); if (responseType) xhr.responseType = responseType; xhr.onload = function (e) { if (xhr.status == 200) { if (success) success(xhr.response); } else { if (error) error('HTTP ' + xhr.status); } }; xhr.onprogress = function (e) { if (e.lengthComputable) { if (onprogress) onprogress(e.loaded, e.total); } }; xhr.onabort = function () { if (error) error('Abort'); }; xhr.ontimeout = function () { if (error) error('Timeout'); }; xhr.onerror = function () { if (error) error('Error on Connection'); }; if (formData) xhr.send(formData); else xhr.send(); }; // LZW-compress // https://gist.github.com/revolunet/843889 function lzw_encode(s) { var dict = {}; var data = (s + '').split(''); var out = []; var currChar; var phrase = data[0]; var code = 256; for (var i = 1; i < data.length; i++) { currChar = data[i]; if (dict[phrase + currChar] != null) { phrase += currChar; } else { out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0)); dict[phrase + currChar] = code; code++; phrase = currChar; } } out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0)); for (var i = 0; i < out.length; i++) { out[i] = String.fromCharCode(out[i]); } return out.join(''); } // Decompress an LZW-encoded string function lzw_decode(s) { var dict = {}; var data = (s + '').split(''); var currChar = data[0]; var oldPhrase = currChar; var out = [currChar]; var code = 256; var phrase; for (var i = 1; i < data.length; i++) { var currCode = data[i].charCodeAt(0); if (currCode < 256) { phrase = data[i]; } else { phrase = dict[currCode] ? dict[currCode] : oldPhrase + currChar; } out.push(phrase); currChar = phrase.charAt(0); dict[code] = oldPhrase + currChar; code++; oldPhrase = phrase; } return out.join(''); }