diff --git a/.gitignore b/.gitignore index d742b1fc..359a1962 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .vscode +*ce5eec52_2fa1_447b_8dad_764e267a7fab* # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 diff --git a/.idea/markdown-exported-files.xml b/.idea/markdown-exported-files.xml new file mode 100644 index 00000000..5d1f1293 --- /dev/null +++ b/.idea/markdown-exported-files.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index ec5f01ec..31bfb098 100644 --- a/README.md +++ b/README.md @@ -16,29 +16,44 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏! ``` bash ├── /_server/ # 为可视化地图编辑器提供一些支持的目录 ├── /docs/ # 文档目录 -├── /animates/ # 动画目录 -├── /images/ # 所有图片素材目录 -│ ├─ /常用素材/ # 可以被直接替换的素材 -│ └─ *.png # 对应的某个具体的图片素材 -├── /libs/ # JS源代码目录 -│ ├─ /floors/ # 剧本文件,记录了每个地图的数据和事件 +├── /libs/ # 系统库目录 │ ├─ /thirdparty/ # 游戏所用到的第三方库文件 -│ ├─ core.js # 系统核心文件 -│ ├─ data.js # 记录了勇士的初始化信息、各个全局变量和全局Flag值 -│ ├─ enemys.js # 记录了怪物的信息,包括怪物的数据和特殊属性、伤害计算公式、临界值计算等。 +│ ├─ actions.js # 处理用户交互的文件 +│ ├─ core.js # 系统核心文件(游戏入口,接口&转发) +│ ├─ control.js # 游戏逻辑控制 +│ ├─ data.js # 记录了一些初始化信息 +│ ├─ enemys.js # 记录了怪物的信息,包括特殊属性、伤害计算公式、临界值计算等。 │ ├─ events.js # 处理事件的文件,所有自定义事件都会在此文件中进行处理 -│ ├─ icons.js # 记录了图标信息,将元件的ID和images目录下的素材图标对应起来 -│ ├─ items.js # 记录了道具的信息,包括道具说明、道具效果等。 -│ ├─ maps.js # 记录了地图信息,负责将数字与元件的ID一一对应起来。 -│ └─ ui.js # UI绘制信息,主要负责绘制各个UI窗口。 -├── /sounds/ # 音效目录 +│ ├─ icons.js # 记录了图标信息 +│ ├─ items.js # 道具的使用 +│ ├─ loader.js # 动态加载JS代码、图片、音效等 +│ ├─ maps.js # 记录了地图信息,和地图绘制等操作 +│ ├─ ui.js # UI绘制信息,主要负责绘制各个UI窗口。 +│ └─ utils.js # 工具类 +├── /project/ # 项目目录,用户需要在这里做自己的塔 +│ ├─ /animates/ # 动画目录 +│ ├─ /floors/ # 剧本文件,记录了每个地图的数据和事件 +│ ├─ /images/ # 所有图片素材目录 +│ │ ├─ /常用素材/ # 可以被直接替换的素材 +│ │ └─ *.png # 对应的某个具体的图片素材 +│ ├─ /sounds/ # 音效目录 +│ ├─ comments.js # 对怪物、道具、楼层等的注释 +│ ├─ data.comment.js # 对全局变量的注释 +│ ├─ data.js # 全局变量信息 +│ ├─ enemys.js # 怪物属性数据 +│ ├─ functions.comment.js # 脚本编辑的注释 +│ ├─ functions.js # 可能会被修改的脚本代码 +│ ├─ icons.js # 素材和ID的对应关系定义 +│ ├─ items.js # 道具的定义,获得道具的效果 +│ ├─ maps.commment.js # 地图信息的注释 +│ └─ maps.js # 地图和数字的对应关系 ├── /常用工具/ # 一些常用工具,可以辅助造塔 │ ├─ RM动画导出器.exe # 能从RMXP中导出动画,以供H5使用。 http://github.com/ckcz123/animate_export/ │ ├─ JS代码压缩工具.exe # 能对Javascript代码进行压缩和整合,从而减少IO请求量。 http://github.com/ckcz123/JSCompressor/ │ ├─ 便捷PS工具.exe # 能只用复制和粘贴来快速对素材进行PS操作。 http://github.com/ckcz123/ps/ │ ├─ 地图生成器.exe # 能从一张截图识别出来具体的数字数组,方便复刻已有的塔。 http://github.com/ckcz123/map_generator/ │ └─ 伤害和临界值计算器.exe # 一个能帮助计算怪物的伤害和临界值的小工具。 http://github.com/ckcz123/magic-tower-calculator/ -├── drawMapGUI.html # 可视化地图编辑工具,能简单地在界面上绘制地图 +├── editor.html # 可视化地图编辑工具 ├── index.html # 主程序,游戏的入口 ├── main.js # JS程序的入口,将动态对所需JS进行加载 ├── style.css # 游戏所需要用到的样式表 @@ -47,6 +62,18 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏! ## 更新说明 +### 2018.3.14 V2.0 + +* [x] 全GUI造塔,现在用户无需打开任何文件直接编辑JS代码了。 +* [x] 整体改变目录架构,将数据和逻辑进行分离 +* [x] 支持48x32的怪物和NPC素材 +* [x] 加点改成系统开关进行处理,怪物手册会列出加点值 +* [x] 支持带有血量上限的塔 +* [x] 增加前景图片绘制 +* [x] 便捷PS工具对于非标准的图片可以自动进行调整 +* [x] 录像存储机制进行修改,对于道具记录全ID +* [x] 其他细节的优化 + ### 2018.2.9 V1.4.1 * [x] 改变图块(setBlock事件)。 diff --git a/_server/CodeMirror/LICENSE b/_server/CodeMirror/LICENSE new file mode 100644 index 00000000..ff7db4b9 --- /dev/null +++ b/_server/CodeMirror/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2017 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/_server/CodeMirror/codeMirror.bundle.min.js b/_server/CodeMirror/codeMirror.bundle.min.js new file mode 100644 index 00000000..f8a06300 --- /dev/null +++ b/_server/CodeMirror/codeMirror.bundle.min.js @@ -0,0 +1 @@ +!function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:r})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t){CodeMirror=function(){"use strict";var e=navigator.userAgent,t=navigator.platform,n=/gecko\/\d/i.test(e),r=/MSIE \d/.test(e),i=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(e),o=/Edge\/(\d+)/.exec(e),l=r||i||o,a=l&&(r?document.documentMode||6:+(o||i)[1]),s=!o&&/WebKit\//.test(e),u=s&&/Qt\/\d+\.\d+/.test(e),c=!o&&/Chrome\//.test(e),f=/Opera\//.test(e),h=/Apple Computer/.test(navigator.vendor),d=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(e),p=/PhantomJS/.test(e),g=!o&&/AppleWebKit/.test(e)&&/Mobile\/\w+/.test(e),m=/Android/.test(e),v=g||m||/webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(e),y=g||/Mac/.test(t),b=/\bCrOS\b/.test(e),x=/win/i.test(t),w=f&&e.match(/Version\/(\d*\.\d*)/);w&&(w=Number(w[1])),w&&w>=15&&(f=!1,s=!0);var C=y&&(u||f&&(null==w||w<12.11)),k=n||l&&a>=9;function S(e){return new RegExp("(^|\\s)"+e+"(?:$|\\s)\\s*")}var L,T=function(e,t){var n=e.className,r=S(t).exec(n);if(r){var i=n.slice(r.index+r[0].length);e.className=n.slice(0,r.index)+(i?r[1]+i:"")}};function M(e){for(var t=e.childNodes.length;t>0;--t)e.removeChild(e.firstChild);return e}function A(e,t){return M(e).appendChild(t)}function O(e,t,n,r){var i=document.createElement(e);if(n&&(i.className=n),r&&(i.style.cssText=r),"string"==typeof t)i.appendChild(document.createTextNode(t));else if(t)for(var o=0;o=t)return l+(t-o);l+=a-o,l+=n-l%n,o=a+1}}g?P=function(e){e.selectionStart=0,e.selectionEnd=e.value.length}:l&&(P=function(e){try{e.select()}catch(e){}});var R=function(){this.id=null};function B(e,t){for(var n=0;n=t)return r+Math.min(l,t-i);if(i+=o-r,r=o+1,(i+=n-i%n)>=t)return r}}var $=[""];function Y(e){for(;$.length<=e;)$.push(_($)+" ");return $[e]}function _(e){return e[e.length-1]}function q(e,t){for(var n=[],r=0;r"€"&&(e.toUpperCase()!=e.toLowerCase()||J.test(e))}function te(e,t){return t?!!(t.source.indexOf("\\w")>-1&&ee(e))||t.test(e):ee(e)}function ne(e){for(var t in e)if(e.hasOwnProperty(t)&&e[t])return!1;return!0}var re=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;function ie(e){return e.charCodeAt(0)>=768&&re.test(e)}function oe(e,t,n){for(;(n<0?t>0:tn?-1:1;;){if(t==n)return t;var i=(t+n)/2,o=r<0?Math.ceil(i):Math.floor(i);if(o==t)return e(o)?t:n;e(o)?n=o:t=o+r}}function ae(e,t){if((t-=e.first)<0||t>=e.size)throw new Error("There is no line "+(t+e.first)+" in the document.");for(var n=e;!n.lines;)for(var r=0;;++r){var i=n.children[r],o=i.chunkSize();if(t=e.first&&tn?ge(n,ae(e,n).text.length):function(e,t){var n=e.ch;return null==n||n>t?ge(e.line,t):n<0?ge(e.line,0):e}(t,ae(e,t.line).text.length)}function ke(e,t){for(var n=[],r=0;r=t:o.to>t);(r||(r=[])).push(new Te(l,o.from,s?null:o.to))}}return r}(n,i,l),s=function(e,t,n){var r;if(e)for(var i=0;i=t:o.to>t);if(a||o.from==t&&"bookmark"==l.type&&(!n||o.marker.insertLeft)){var s=null==o.from||(l.inclusiveLeft?o.from<=t:o.from0&&a)for(var x=0;x=0&&f<=0||c<=0&&f>=0)&&(c<=0&&(s.marker.inclusiveRight&&i.inclusiveLeft?me(u.to,n)>=0:me(u.to,n)>0)||c>=0&&(s.marker.inclusiveRight&&i.inclusiveLeft?me(u.from,r)<=0:me(u.from,r)<0)))return!0}}}function Be(e){for(var t;t=Ie(e);)e=t.find(-1,!0).line;return e}function je(e,t){var n=ae(e,t),r=Be(n);return n==r?t:fe(r)}function Ve(e,t){if(t>e.lastLine())return t;var n,r=ae(e,t);if(!Ge(e,r))return t;for(;n=ze(r);)r=n.find(1,!0).line;return fe(r)+1}function Ge(e,t){var n=Le&&t.markedSpans;if(n)for(var r=void 0,i=0;it.maxLineLength&&(t.maxLineLength=n,t.maxLine=e)})}var Ye=null;function _e(e,t,n){var r;Ye=null;for(var i=0;it)return i;o.to==t&&(o.from!=o.to&&"before"==n?r=i:Ye=i),o.from==t&&(o.from!=o.to&&"before"!=n?r=i:Ye=i)}return null!=r?r:Ye}var qe=function(){var e="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN",t="nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";var n=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,r=/[stwN]/,i=/[LRr]/,o=/[Lb1n]/,l=/[1n]/;function a(e,t,n){this.level=e,this.from=t,this.to=n}return function(s,u){var c,f="ltr"==u?"L":"R";if(0==s.length||"ltr"==u&&!n.test(s))return!1;for(var h=s.length,d=[],p=0;p-1&&(r[t]=i.slice(0,o).concat(i.slice(o+1)))}}}function nt(e,t){var n=et(e,t);if(n.length)for(var r=Array.prototype.slice.call(arguments,2),i=0;i0}function lt(e){e.prototype.on=function(e,t){Je(this,e,t)},e.prototype.off=function(e,t){tt(this,e,t)}}function at(e){e.preventDefault?e.preventDefault():e.returnValue=!1}function st(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0}function ut(e){return null!=e.defaultPrevented?e.defaultPrevented:0==e.returnValue}function ct(e){at(e),st(e)}function ft(e){return e.target||e.srcElement}function ht(e){var t=e.which;return null==t&&(1&e.button?t=1:2&e.button?t=3:4&e.button&&(t=2)),y&&e.ctrlKey&&1==t&&(t=3),t}var dt,pt,gt=function(){if(l&&a<9)return!1;var e=O("div");return"draggable"in e||"dragDrop"in e}();function mt(e){if(null==dt){var t=O("span","​");A(e,O("span",[t,document.createTextNode("x")])),0!=e.firstChild.offsetHeight&&(dt=t.offsetWidth<=1&&t.offsetHeight>2&&!(l&&a<8))}var n=dt?O("span","​"):O("span"," ",null,"display: inline-block; width: 1px; margin-right: -1px");return n.setAttribute("cm-text",""),n}function vt(e){if(null!=pt)return pt;var t=A(e,document.createTextNode("AخA")),n=L(t,0,1).getBoundingClientRect(),r=L(t,1,2).getBoundingClientRect();return M(e),!(!n||n.left==n.right)&&(pt=r.right-n.right<3)}var yt,bt=3!="\n\nb".split(/\n/).length?function(e){for(var t=0,n=[],r=e.length;t<=r;){var i=e.indexOf("\n",t);-1==i&&(i=e.length);var o=e.slice(t,"\r"==e.charAt(i-1)?i-1:i),l=o.indexOf("\r");-1!=l?(n.push(o.slice(0,l)),t+=l+1):(n.push(o),t=i+1)}return n}:function(e){return e.split(/\r\n?|\n/)},xt=window.getSelection?function(e){try{return e.selectionStart!=e.selectionEnd}catch(e){return!1}}:function(e){var t;try{t=e.ownerDocument.selection.createRange()}catch(e){}return!(!t||t.parentElement()!=e)&&0!=t.compareEndPoints("StartToEnd",t)},wt="oncopy"in(yt=O("div"))||(yt.setAttribute("oncopy","return;"),"function"==typeof yt.oncopy),Ct=null,kt={},St={};function Lt(e){if("string"==typeof e&&St.hasOwnProperty(e))e=St[e];else if(e&&"string"==typeof e.name&&St.hasOwnProperty(e.name)){var t=St[e.name];"string"==typeof t&&(t={name:t}),(e=Q(t,e)).name=t.name}else{if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+xml$/.test(e))return Lt("application/xml");if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+json$/.test(e))return Lt("application/json")}return"string"==typeof e?{name:e}:e||{name:"null"}}function Tt(e,t){t=Lt(t);var n=kt[t.name];if(!n)return Tt(e,"text/plain");var r=n(e,t);if(Mt.hasOwnProperty(t.name)){var i=Mt[t.name];for(var o in i)i.hasOwnProperty(o)&&(r.hasOwnProperty(o)&&(r["_"+o]=r[o]),r[o]=i[o])}if(r.name=t.name,t.helperType&&(r.helperType=t.helperType),t.modeProps)for(var l in t.modeProps)r[l]=t.modeProps[l];return r}var Mt={};function At(e,t){var n=Mt.hasOwnProperty(e)?Mt[e]:Mt[e]={};I(t,n)}function Ot(e,t){if(!0===t)return t;if(e.copyState)return e.copyState(t);var n={};for(var r in t){var i=t[r];i instanceof Array&&(i=i.concat([])),n[r]=i}return n}function Nt(e,t){for(var n;e.innerMode&&(n=e.innerMode(t))&&n.mode!=e;)t=n.state,e=n.mode;return n||{mode:e,state:t}}function Wt(e,t,n){return!e.startState||e.startState(t,n)}var Dt=function(e,t,n){this.pos=this.start=0,this.string=e,this.tabSize=t||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0,this.lineOracle=n};Dt.prototype.eol=function(){return this.pos>=this.string.length},Dt.prototype.sol=function(){return this.pos==this.lineStart},Dt.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},Dt.prototype.next=function(){if(this.post},Dt.prototype.eatSpace=function(){for(var e=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>e},Dt.prototype.skipToEnd=function(){this.pos=this.string.length},Dt.prototype.skipTo=function(e){var t=this.string.indexOf(e,this.pos);if(t>-1)return this.pos=t,!0},Dt.prototype.backUp=function(e){this.pos-=e},Dt.prototype.column=function(){return this.lastColumnPos0?null:(r&&!1!==t&&(this.pos+=r[0].length),r)}var i=function(e){return n?e.toLowerCase():e},o=this.string.substr(this.pos,e.length);if(i(o)==i(e))return!1!==t&&(this.pos+=e.length),!0},Dt.prototype.current=function(){return this.string.slice(this.start,this.pos)},Dt.prototype.hideFirstChars=function(e,t){this.lineStart+=e;try{return t()}finally{this.lineStart-=e}},Dt.prototype.lookAhead=function(e){var t=this.lineOracle;return t&&t.lookAhead(e)},Dt.prototype.baseToken=function(){var e=this.lineOracle;return e&&e.baseToken(this.pos)};var Ht=function(e,t){this.state=e,this.lookAhead=t},Et=function(e,t,n,r){this.state=t,this.doc=e,this.line=n,this.maxLookAhead=r||0,this.baseTokens=null,this.baseTokenPos=1};function Pt(e,t,n,r){var i=[e.state.modeGen],o={};Ut(e,t.text,e.doc.mode,n,function(e,t){return i.push(e,t)},o,r);for(var l=n.state,a=function(r){n.baseTokens=i;var a=e.state.overlays[r],s=1,u=0;n.state=!0,Ut(e,t.text,a.mode,n,function(e,t){for(var n=s;ue&&i.splice(s,1,e,i[s+1],r),s+=2,u=Math.min(e,r)}if(t)if(a.opaque)i.splice(n,s-n,e,"overlay "+t),s=n+2;else for(;ne.options.maxHighlightLength&&Ot(e.doc.mode,r.state),o=Pt(e,t,r);i&&(r.state=i),t.stateAfter=r.save(!i),t.styles=o.styles,o.classes?t.styleClasses=o.classes:t.styleClasses&&(t.styleClasses=null),n===e.doc.highlightFrontier&&(e.doc.modeFrontier=Math.max(e.doc.modeFrontier,++e.doc.highlightFrontier))}return t.styles}function It(e,t,n){var r=e.doc,i=e.display;if(!r.mode.startState)return new Et(r,!0,t);var o=function(e,t,n){for(var r,i,o=e.doc,l=n?-1:t-(e.doc.mode.innerMode?1e3:100),a=t;a>l;--a){if(a<=o.first)return o.first;var s=ae(o,a-1),u=s.stateAfter;if(u&&(!n||a+(u instanceof Ht?u.lookAhead:0)<=o.modeFrontier))return a;var c=z(s.text,null,e.options.tabSize);(null==i||r>c)&&(i=a-1,r=c)}return i}(e,t,n),l=o>r.first&&ae(r,o-1).stateAfter,a=l?Et.fromSaved(r,l,o):new Et(r,Wt(r.mode),o);return r.iter(o,t,function(n){zt(e,n.text,a);var r=a.line;n.stateAfter=r==t-1||r%5==0||r>=i.viewFrom&&rt.start)return o}throw new Error("Mode "+e.name+" failed to advance stream.")}Et.prototype.lookAhead=function(e){var t=this.doc.getLine(this.line+e);return null!=t&&e>this.maxLookAhead&&(this.maxLookAhead=e),t},Et.prototype.baseToken=function(e){if(!this.baseTokens)return null;for(;this.baseTokens[this.baseTokenPos]<=e;)this.baseTokenPos+=2;var t=this.baseTokens[this.baseTokenPos+1];return{type:t&&t.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-e}},Et.prototype.nextLine=function(){this.line++,this.maxLookAhead>0&&this.maxLookAhead--},Et.fromSaved=function(e,t,n){return t instanceof Ht?new Et(e,Ot(e.mode,t.state),n,t.lookAhead):new Et(e,Ot(e.mode,t),n)},Et.prototype.save=function(e){var t=!1!==e?Ot(this.doc.mode,this.state):this.state;return this.maxLookAhead>0?new Ht(t,this.maxLookAhead):t};var jt=function(e,t,n){this.start=e.start,this.end=e.pos,this.string=e.current(),this.type=t||null,this.state=n};function Vt(e,t,n,r){var i,o=e.doc,l=o.mode;t=Ce(o,t);var a,s=ae(o,t.line),u=It(e,t.line,n),c=new Dt(s.text,e.options.tabSize,u);for(r&&(a=[]);(r||c.pose.options.maxHighlightLength?(a=!1,l&&zt(e,t,r,f.pos),f.pos=t.length,s=null):s=Gt(Bt(n,f,r.state,h),o),h){var d=h[0].name;d&&(s="m-"+(s?d+" "+s:d))}if(!a||c!=s){for(;u1&&!/ /.test(e))return e;for(var n=t,r="",i=0;iu&&f.from<=u);h++);if(f.to>=c)return e(n,r,i,o,l,a,s);e(n,r.slice(0,f.to-u),i,o,null,a,s),o=null,r=r.slice(f.to-u),u=f.to}}}function en(e,t,n,r){var i=!r&&n.widgetNode;i&&e.map.push(e.pos,e.pos+t,i),!r&&e.cm.display.input.needsContentAttribute&&(i||(i=e.content.appendChild(document.createElement("span"))),i.setAttribute("cm-marker",n.id)),i&&(e.cm.display.input.setUneditable(i),e.content.appendChild(i)),e.pos+=t,e.trailingSpace=!1}function tn(e,t,n){var r=e.markedSpans,i=e.text,o=0;if(r)for(var l,a,s,u,c,f,h,d=i.length,p=0,g=1,m="",v=0;;){if(v==p){s=u=c=f=a="",h=null,v=1/0;for(var y=[],b=void 0,x=0;xp||C.collapsed&&w.to==p&&w.from==p)?(null!=w.to&&w.to!=p&&v>w.to&&(v=w.to,u=""),C.className&&(s+=" "+C.className),C.css&&(a=(a?a+";":"")+C.css),C.startStyle&&w.from==p&&(c+=" "+C.startStyle),C.endStyle&&w.to==v&&(b||(b=[])).push(C.endStyle,w.to),C.title&&!f&&(f=C.title),C.collapsed&&(!h||Pe(h.marker,C)<0)&&(h=w)):w.from>p&&v>w.from&&(v=w.from)}if(b)for(var k=0;k=d)break;for(var L=Math.min(d,v);;){if(m){var T=p+m.length;if(!h){var M=T>L?m.slice(0,L-p):m;t.addToken(t,M,l?l+s:s,c,p+M.length==v?u:"",f,a)}if(T>=L){m=m.slice(L-p),p=L;break}p=T,c=""}m=i.slice(o,o=n[g++]),l=_t(n[g++],t.cm.options)}}else for(var A=1;An)return{map:e.measure.maps[i],cache:e.measure.caches[i],before:!0}}function On(e,t,n,r){return Dn(e,Wn(e,t),n,r)}function Nn(e,t){if(t>=e.display.viewFrom&&t=n.lineN&&t2&&o.push((s.bottom+u.top)/2-n.top)}}o.push(n.bottom-n.top)}}(e,t.view,t.rect),t.hasHeights=!0),(o=function(e,t,n,r){var i,o=Pn(t.map,n,r),s=o.node,u=o.start,c=o.end,f=o.collapse;if(3==s.nodeType){for(var h=0;h<4;h++){for(;u&&ie(t.line.text.charAt(o.coverStart+u));)--u;for(;o.coverStart+c1}(e))return t;var n=screen.logicalXDPI/screen.deviceXDPI,r=screen.logicalYDPI/screen.deviceYDPI;return{left:t.left*n,right:t.right*n,top:t.top*r,bottom:t.bottom*r}}(e.display.measure,i))}else{var d;u>0&&(f=r="right"),i=e.options.lineWrapping&&(d=s.getClientRects()).length>1?d["right"==r?d.length-1:0]:s.getBoundingClientRect()}if(l&&a<9&&!u&&(!i||!i.left&&!i.right)){var p=s.parentNode.getClientRects()[0];i=p?{left:p.left,right:p.left+tr(e.display),top:p.top,bottom:p.bottom}:En}for(var g=i.top-t.rect.top,m=i.bottom-t.rect.top,v=(g+m)/2,y=t.view.measure.heights,b=0;bt)&&(i=(o=s-a)-1,t>=s&&(l="right")),null!=i){if(r=e[u+2],a==s&&n==(r.insertLeft?"left":"right")&&(l=n),"left"==n&&0==i)for(;u&&e[u-2]==e[u-3]&&e[u-1].insertLeft;)r=e[2+(u-=3)],l="left";if("right"==n&&i==s-a)for(;u=0&&(n=e[i]).left==n.right;i--);return n}function In(e){if(e.measure&&(e.measure.cache={},e.measure.heights=null,e.rest))for(var t=0;t=r.text.length?(s=r.text.length,u="before"):s<=0&&(s=0,u="after"),!a)return l("before"==u?s-1:s,"before"==u);function c(e,t,n){var r=a[t],i=1==r.level;return l(n?e-1:e,i!=n)}var f=_e(a,s,u),h=Ye,d=c(s,f,"before"==u);return null!=h&&(d.other=c(s,h,"before"!=u)),d}function $n(e,t){var n=0;t=Ce(e.doc,t),e.options.lineWrapping||(n=tr(e.display)*t.ch);var r=ae(e.doc,t.line),i=Ke(r)+Cn(e.display);return{left:n,right:n,top:i,bottom:i+r.height}}function Yn(e,t,n,r,i){var o=ge(e,t,n);return o.xRel=i,r&&(o.outside=!0),o}function _n(e,t,n){var r=e.doc;if((n+=e.display.viewOffset)<0)return Yn(r.first,0,null,!0,-1);var i=he(r,n),o=r.first+r.size-1;if(i>o)return Yn(r.first+r.size-1,ae(r,o).text.length,null,!0,1);t<0&&(t=0);for(var l=ae(r,i);;){var a=Jn(e,l,i,t,n),s=ze(l),u=s&&s.find(0,!0);if(!s||!(a.ch>u.from.ch||a.ch==u.from.ch&&a.xRel>0))return a;i=fe(l=u.to.line)}}function qn(e,t,n,r){r-=Vn(t);var i=t.text.length,o=le(function(t){return Dn(e,n,t-1).bottom<=r},i,0);return i=le(function(t){return Dn(e,n,t).top>r},o,i),{begin:o,end:i}}function Zn(e,t,n,r){n||(n=Wn(e,t));var i=Gn(e,t,Dn(e,n,r),"line").top;return qn(e,t,n,i)}function Qn(e,t,n,r){return!(e.bottom<=n)&&(e.top>n||(r?e.left:e.right)>t)}function Jn(e,t,n,r,i){i-=Ke(t);var o=Wn(e,t),l=Vn(t),a=0,s=t.text.length,u=!0,c=Ze(t,e.doc.direction);if(c){var f=(e.options.lineWrapping?function(e,t,n,r,i,o,l){var a=qn(e,t,r,l),s=a.begin,u=a.end;/\s/.test(t.text.charAt(u-1))&&u--;for(var c=null,f=null,h=0;h=u||d.to<=s)){var p=1!=d.level,g=Dn(e,r,p?Math.min(u,d.to)-1:Math.max(s,d.from)).right,m=gm)&&(c=d,f=m)}}return c||(c=i[i.length-1]),c.fromu&&(c={from:c.from,to:u,level:c.level}),c}:function(e,t,n,r,i,o,l){var a=le(function(a){var s=i[a],u=1!=s.level;return Qn(Xn(e,ge(n,u?s.to:s.from,u?"before":"after"),"line",t,r),o,l,!0)},0,i.length-1),s=i[a];if(a>0){var u=1!=s.level,c=Xn(e,ge(n,u?s.from:s.to,u?"after":"before"),"line",t,r);Qn(c,o,l,!0)&&c.top>l&&(s=i[a-1])}return s})(e,t,n,o,c,r,i);u=1!=f.level,a=u?f.from:f.to-1,s=u?f.to:f.from-1}var h,d,p=null,g=null,m=le(function(t){var n=Dn(e,o,t);return n.top+=l,n.bottom+=l,!!Qn(n,r,i,!1)&&(n.top<=i&&n.left<=r&&(p=t,g=n),!0)},a,s),v=!1;if(g){var y=r-g.left=x.bottom}return m=oe(t.text,m,1),Yn(n,m,d,v,r-h)}function er(e){if(null!=e.cachedTextHeight)return e.cachedTextHeight;if(null==Hn){Hn=O("pre");for(var t=0;t<49;++t)Hn.appendChild(document.createTextNode("x")),Hn.appendChild(O("br"));Hn.appendChild(document.createTextNode("x"))}A(e.measure,Hn);var n=Hn.offsetHeight/50;return n>3&&(e.cachedTextHeight=n),M(e.measure),n||1}function tr(e){if(null!=e.cachedCharWidth)return e.cachedCharWidth;var t=O("span","xxxxxxxxxx"),n=O("pre",[t]);A(e.measure,n);var r=t.getBoundingClientRect(),i=(r.right-r.left)/10;return i>2&&(e.cachedCharWidth=i),i||10}function nr(e){for(var t=e.display,n={},r={},i=t.gutters.clientLeft,o=t.gutters.firstChild,l=0;o;o=o.nextSibling,++l)n[e.options.gutters[l]]=o.offsetLeft+o.clientLeft+i,r[e.options.gutters[l]]=o.clientWidth;return{fixedPos:rr(t),gutterTotalWidth:t.gutters.offsetWidth,gutterLeft:n,gutterWidth:r,wrapperWidth:t.wrapper.clientWidth}}function rr(e){return e.scroller.getBoundingClientRect().left-e.sizer.getBoundingClientRect().left}function ir(e){var t=er(e.display),n=e.options.lineWrapping,r=n&&Math.max(5,e.display.scroller.clientWidth/tr(e.display)-3);return function(i){if(Ge(e.doc,i))return 0;var o=0;if(i.widgets)for(var l=0;l=e.display.viewTo)return null;if((t-=e.display.viewFrom)<0)return null;for(var n=e.display.view,r=0;r=e.display.viewTo||a.to().linet||t==n&&l.to==t)&&(r(Math.max(l.from,t),Math.min(l.to,n),1==l.level?"rtl":"ltr",o),i=!0)}i||r(t,n,"ltr")}(g,n||0,null==r?h:r,function(e,t,i,f){var m="ltr"==i,v=d(e,m?"left":"right"),y=d(t-1,m?"right":"left"),b=null==n&&0==e,x=null==r&&t==h,w=0==f,C=!g||f==g.length-1;if(y.top-v.top<=3){var k=(u?b:x)&&w,S=(u?x:b)&&C,L=k?a:(m?v:y).left,T=S?s:(m?y:v).right;c(L,v.top,T-L,v.bottom)}else{var M,A,O,N;m?(M=u&&b&&w?a:v.left,A=u?s:p(e,i,"before"),O=u?a:p(t,i,"after"),N=u&&x&&C?s:y.right):(M=u?p(e,i,"before"):a,A=!u&&b&&w?s:v.right,O=!u&&x&&C?a:y.left,N=u?p(t,i,"after"):s),c(M,v.top,A-M,v.bottom),v.bottom0?t.blinker=setInterval(function(){return t.cursorDiv.style.visibility=(n=!n)?"":"hidden"},e.options.cursorBlinkRate):e.options.cursorBlinkRate<0&&(t.cursorDiv.style.visibility="hidden")}}function pr(e){e.state.focused||(e.display.input.focus(),mr(e))}function gr(e){e.state.delayingBlurEvent=!0,setTimeout(function(){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1,vr(e))},100)}function mr(e,t){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1),"nocursor"!=e.options.readOnly&&(e.state.focused||(nt(e,"focus",e,t),e.state.focused=!0,H(e.display.wrapper,"CodeMirror-focused"),e.curOp||e.display.selForContextMenu==e.doc.sel||(e.display.input.reset(),s&&setTimeout(function(){return e.display.input.reset(!0)},20)),e.display.input.receivedFocus()),dr(e))}function vr(e,t){e.state.delayingBlurEvent||(e.state.focused&&(nt(e,"blur",e,t),e.state.focused=!1,T(e.display.wrapper,"CodeMirror-focused")),clearInterval(e.display.blinker),setTimeout(function(){e.state.focused||(e.display.shift=!1)},150))}function yr(e){for(var t=e.display,n=t.lineDiv.offsetTop,r=0;r.005||c<-.005)&&(ce(i.line,o),br(i.line),i.rest))for(var f=0;f=l&&(o=he(t,Ke(ae(t,s))-e.wrapper.clientHeight),l=s)}return{from:o,to:Math.max(l,o+1)}}function wr(e){var t=e.display,n=t.view;if(t.alignWidgets||t.gutters.firstChild&&e.options.fixedGutter){for(var r=rr(t)-t.scroller.scrollLeft+e.doc.scrollLeft,i=t.gutters.offsetWidth,o=r+"px",l=0;lo&&(t.bottom=t.top+o);var a=e.doc.height+kn(n),s=t.topa-r;if(t.topi+o){var c=Math.min(t.top,(u?a:t.bottom)-o);c!=i&&(l.scrollTop=c)}var f=e.curOp&&null!=e.curOp.scrollLeft?e.curOp.scrollLeft:n.scroller.scrollLeft,h=Tn(e)-(e.options.fixedGutter?n.gutters.offsetWidth:0),d=t.right-t.left>h;return d&&(t.right=t.left+h),t.left<10?l.scrollLeft=0:t.lefth+f-3&&(l.scrollLeft=t.right+(d?0:10)-h),l}function Sr(e,t){null!=t&&(Mr(e),e.curOp.scrollTop=(null==e.curOp.scrollTop?e.doc.scrollTop:e.curOp.scrollTop)+t)}function Lr(e){Mr(e);var t=e.getCursor();e.curOp.scrollToPos={from:t,to:t,margin:e.options.cursorScrollMargin}}function Tr(e,t,n){null==t&&null==n||Mr(e),null!=t&&(e.curOp.scrollLeft=t),null!=n&&(e.curOp.scrollTop=n)}function Mr(e){var t=e.curOp.scrollToPos;if(t){e.curOp.scrollToPos=null;var n=$n(e,t.from),r=$n(e,t.to);Ar(e,n,r,t.margin)}}function Ar(e,t,n,r){var i=kr(e,{left:Math.min(t.left,n.left),top:Math.min(t.top,n.top)-r,right:Math.max(t.right,n.right),bottom:Math.max(t.bottom,n.bottom)+r});Tr(e,i.scrollLeft,i.scrollTop)}function Or(e,t){Math.abs(e.doc.scrollTop-t)<2||(n||li(e,{top:t}),Nr(e,t,!0),n&&li(e),ti(e,100))}function Nr(e,t,n){t=Math.min(e.display.scroller.scrollHeight-e.display.scroller.clientHeight,t),(e.display.scroller.scrollTop!=t||n)&&(e.doc.scrollTop=t,e.display.scrollbars.setScrollTop(t),e.display.scroller.scrollTop!=t&&(e.display.scroller.scrollTop=t))}function Wr(e,t,n,r){t=Math.min(t,e.display.scroller.scrollWidth-e.display.scroller.clientWidth),(n?t==e.doc.scrollLeft:Math.abs(e.doc.scrollLeft-t)<2)&&!r||(e.doc.scrollLeft=t,wr(e),e.display.scroller.scrollLeft!=t&&(e.display.scroller.scrollLeft=t),e.display.scrollbars.setScrollLeft(t))}function Dr(e){var t=e.display,n=t.gutters.offsetWidth,r=Math.round(e.doc.height+kn(e.display));return{clientHeight:t.scroller.clientHeight,viewHeight:t.wrapper.clientHeight,scrollWidth:t.scroller.scrollWidth,clientWidth:t.scroller.clientWidth,viewWidth:t.wrapper.clientWidth,barLeft:e.options.fixedGutter?n:0,docHeight:r,scrollHeight:r+Ln(e)+t.barHeight,nativeBarWidth:t.nativeBarWidth,gutterWidth:n}}var Hr=function(e,t,n){this.cm=n;var r=this.vert=O("div",[O("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),i=this.horiz=O("div",[O("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");e(r),e(i),Je(r,"scroll",function(){r.clientHeight&&t(r.scrollTop,"vertical")}),Je(i,"scroll",function(){i.clientWidth&&t(i.scrollLeft,"horizontal")}),this.checkedZeroWidth=!1,l&&a<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")};Hr.prototype.update=function(e){var t=e.scrollWidth>e.clientWidth+1,n=e.scrollHeight>e.clientHeight+1,r=e.nativeBarWidth;if(n){this.vert.style.display="block",this.vert.style.bottom=t?r+"px":"0";var i=e.viewHeight-(t?r:0);this.vert.firstChild.style.height=Math.max(0,e.scrollHeight-e.clientHeight+i)+"px"}else this.vert.style.display="",this.vert.firstChild.style.height="0";if(t){this.horiz.style.display="block",this.horiz.style.right=n?r+"px":"0",this.horiz.style.left=e.barLeft+"px";var o=e.viewWidth-e.barLeft-(n?r:0);this.horiz.firstChild.style.width=Math.max(0,e.scrollWidth-e.clientWidth+o)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&e.clientHeight>0&&(0==r&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:n?r:0,bottom:t?r:0}},Hr.prototype.setScrollLeft=function(e){this.horiz.scrollLeft!=e&&(this.horiz.scrollLeft=e),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")},Hr.prototype.setScrollTop=function(e){this.vert.scrollTop!=e&&(this.vert.scrollTop=e),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")},Hr.prototype.zeroWidthHack=function(){var e=y&&!d?"12px":"18px";this.horiz.style.height=this.vert.style.width=e,this.horiz.style.pointerEvents=this.vert.style.pointerEvents="none",this.disableHoriz=new R,this.disableVert=new R},Hr.prototype.enableZeroWidthBar=function(e,t,n){e.style.pointerEvents="auto",t.set(1e3,function r(){var i=e.getBoundingClientRect(),o="vert"==n?document.elementFromPoint(i.right-1,(i.top+i.bottom)/2):document.elementFromPoint((i.right+i.left)/2,i.bottom-1);o!=e?e.style.pointerEvents="none":t.set(1e3,r)})},Hr.prototype.clear=function(){var e=this.horiz.parentNode;e.removeChild(this.horiz),e.removeChild(this.vert)};var Er=function(){};function Pr(e,t){t||(t=Dr(e));var n=e.display.barWidth,r=e.display.barHeight;Fr(e,t);for(var i=0;i<4&&n!=e.display.barWidth||r!=e.display.barHeight;i++)n!=e.display.barWidth&&e.options.lineWrapping&&yr(e),Fr(e,Dr(e)),n=e.display.barWidth,r=e.display.barHeight}function Fr(e,t){var n=e.display,r=n.scrollbars.update(t);n.sizer.style.paddingRight=(n.barWidth=r.right)+"px",n.sizer.style.paddingBottom=(n.barHeight=r.bottom)+"px",n.heightForcer.style.borderBottom=r.bottom+"px solid transparent",r.right&&r.bottom?(n.scrollbarFiller.style.display="block",n.scrollbarFiller.style.height=r.bottom+"px",n.scrollbarFiller.style.width=r.right+"px"):n.scrollbarFiller.style.display="",r.bottom&&e.options.coverGutterNextToScrollbar&&e.options.fixedGutter?(n.gutterFiller.style.display="block",n.gutterFiller.style.height=r.bottom+"px",n.gutterFiller.style.width=t.gutterWidth+"px"):n.gutterFiller.style.display=""}Er.prototype.update=function(){return{bottom:0,right:0}},Er.prototype.setScrollLeft=function(){},Er.prototype.setScrollTop=function(){},Er.prototype.clear=function(){};var Ir={native:Hr,null:Er};function zr(e){e.display.scrollbars&&(e.display.scrollbars.clear(),e.display.scrollbars.addClass&&T(e.display.wrapper,e.display.scrollbars.addClass)),e.display.scrollbars=new Ir[e.options.scrollbarStyle](function(t){e.display.wrapper.insertBefore(t,e.display.scrollbarFiller),Je(t,"mousedown",function(){e.state.focused&&setTimeout(function(){return e.display.input.focus()},0)}),t.setAttribute("cm-not-content","true")},function(t,n){"horizontal"==n?Wr(e,t):Or(e,t)},e),e.display.scrollbars.addClass&&H(e.display.wrapper,e.display.scrollbars.addClass)}var Rr=0;function Br(e){var t;e.curOp={cm:e,viewChanged:!1,startHeight:e.doc.height,forceUpdate:!1,updateInput:null,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++Rr},t=e.curOp,on?on.ops.push(t):t.ownsGroup=on={ops:[t],delayedCallbacks:[]}}function jr(e){var t=e.curOp;!function(e,t){var n=e.ownsGroup;if(n)try{!function(e){var t=e.delayedCallbacks,n=0;do{for(;n=n.viewTo)||n.maxLineChanged&&t.options.lineWrapping,e.update=e.mustUpdate&&new ri(t,e.mustUpdate&&{top:e.scrollTop,ensure:e.scrollToPos},e.forceUpdate)}function Gr(e){var t=e.cm,n=t.display;e.updatedDisplay&&yr(t),e.barMeasure=Dr(t),n.maxLineChanged&&!t.options.lineWrapping&&(e.adjustWidthTo=On(t,n.maxLine,n.maxLine.text.length).left+3,t.display.sizerWidth=e.adjustWidthTo,e.barMeasure.scrollWidth=Math.max(n.scroller.clientWidth,n.sizer.offsetLeft+e.adjustWidthTo+Ln(t)+t.display.barWidth),e.maxScrollLeft=Math.max(0,n.sizer.offsetLeft+e.adjustWidthTo-Tn(t))),(e.updatedDisplay||e.selectionChanged)&&(e.preparedSelection=n.input.prepareSelection())}function Ur(e){var t=e.cm;null!=e.adjustWidthTo&&(t.display.sizer.style.minWidth=e.adjustWidthTo+"px",e.maxScrollLeft1&&(l=!0)),null!=u.scrollLeft&&(Wr(e,u.scrollLeft),Math.abs(e.doc.scrollLeft-f)>1&&(l=!0)),!l)break}return i}(t,Ce(r,e.scrollToPos.from),Ce(r,e.scrollToPos.to),e.scrollToPos.margin);!function(e,t){if(!rt(e,"scrollCursorIntoView")){var n=e.display,r=n.sizer.getBoundingClientRect(),i=null;if(t.top+r.top<0?i=!0:t.bottom+r.top>(window.innerHeight||document.documentElement.clientHeight)&&(i=!1),null!=i&&!p){var o=O("div","​",null,"position: absolute;\n top: "+(t.top-n.viewOffset-Cn(e.display))+"px;\n height: "+(t.bottom-t.top+Ln(e)+n.barHeight)+"px;\n left: "+t.left+"px; width: "+Math.max(2,t.right-t.left)+"px;");e.display.lineSpace.appendChild(o),o.scrollIntoView(i),e.display.lineSpace.removeChild(o)}}}(t,i)}var o=e.maybeHiddenMarkers,l=e.maybeUnhiddenMarkers;if(o)for(var a=0;at)&&(i.updateLineNumbers=t),e.curOp.viewChanged=!0,t>=i.viewTo)Le&&je(e.doc,t)i.viewFrom?Qr(e):(i.viewFrom+=r,i.viewTo+=r);else if(t<=i.viewFrom&&n>=i.viewTo)Qr(e);else if(t<=i.viewFrom){var o=Jr(e,n,n+r,1);o?(i.view=i.view.slice(o.index),i.viewFrom=o.lineN,i.viewTo+=r):Qr(e)}else if(n>=i.viewTo){var l=Jr(e,t,t,-1);l?(i.view=i.view.slice(0,l.index),i.viewTo=l.lineN):Qr(e)}else{var a=Jr(e,t,t,-1),s=Jr(e,n,n+r,1);a&&s?(i.view=i.view.slice(0,a.index).concat(rn(e,a.lineN,s.lineN)).concat(i.view.slice(s.index)),i.viewTo+=r):Qr(e)}var u=i.externalMeasured;u&&(n=i.lineN&&t=r.viewTo)){var o=r.view[ar(e,t)];if(null!=o.node){var l=o.changes||(o.changes=[]);-1==B(l,n)&&l.push(n)}}}function Qr(e){e.display.viewFrom=e.display.viewTo=e.doc.first,e.display.view=[],e.display.viewOffset=0}function Jr(e,t,n,r){var i,o=ar(e,t),l=e.display.view;if(!Le||n==e.doc.first+e.doc.size)return{index:o,lineN:n};for(var a=e.display.viewFrom,s=0;s0){if(o==l.length-1)return null;i=a+l[o].size-t,o++}else i=a-t;t+=i,n+=i}for(;je(e.doc,n)!=n;){if(o==(r<0?0:l.length-1))return null;n+=r*l[o-(r<0?1:0)].size,o+=r}return{index:o,lineN:n}}function ei(e){for(var t=e.display.view,n=0,r=0;r=e.display.viewTo)){var n=+new Date+e.options.workTime,r=It(e,t.highlightFrontier),i=[];t.iter(r.line,Math.min(t.first+t.size,e.display.viewTo+500),function(o){if(r.line>=e.display.viewFrom){var l=o.styles,a=o.text.length>e.options.maxHighlightLength?Ot(t.mode,r.state):null,s=Pt(e,o,r,!0);a&&(r.state=a),o.styles=s.styles;var u=o.styleClasses,c=s.classes;c?o.styleClasses=c:u&&(o.styleClasses=null);for(var f=!l||l.length!=o.styles.length||u!=c&&(!u||!c||u.bgClass!=c.bgClass||u.textClass!=c.textClass),h=0;!f&&hn)return ti(e,e.options.workDelay),!0}),t.highlightFrontier=r.line,t.modeFrontier=Math.max(t.modeFrontier,r.line),i.length&&Xr(e,function(){for(var t=0;t=n.viewFrom&&t.visible.to<=n.viewTo&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo)&&n.renderedView==n.view&&0==ei(e))return!1;Cr(e)&&(Qr(e),t.dims=nr(e));var i=r.first+r.size,o=Math.max(t.visible.from-e.options.viewportMargin,r.first),l=Math.min(i,t.visible.to+e.options.viewportMargin);n.viewFroml&&n.viewTo-l<20&&(l=Math.min(i,n.viewTo)),Le&&(o=je(e.doc,o),l=Ve(e.doc,l));var a=o!=n.viewFrom||l!=n.viewTo||n.lastWrapHeight!=t.wrapperHeight||n.lastWrapWidth!=t.wrapperWidth;!function(e,t,n){var r=e.display;0==r.view.length||t>=r.viewTo||n<=r.viewFrom?(r.view=rn(e,t,n),r.viewFrom=t):(r.viewFrom>t?r.view=rn(e,t,r.viewFrom).concat(r.view):r.viewFromn&&(r.view=r.view.slice(0,ar(e,n)))),r.viewTo=n}(e,o,l),n.viewOffset=Ke(ae(e.doc,n.viewFrom)),e.display.mover.style.top=n.viewOffset+"px";var u=ei(e);if(!a&&0==u&&!t.force&&n.renderedView==n.view&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo))return!1;var c=function(e){if(e.hasFocus())return null;var t=D();if(!t||!W(e.display.lineDiv,t))return null;var n={activeElt:t};if(window.getSelection){var r=window.getSelection();r.anchorNode&&r.extend&&W(e.display.lineDiv,r.anchorNode)&&(n.anchorNode=r.anchorNode,n.anchorOffset=r.anchorOffset,n.focusNode=r.focusNode,n.focusOffset=r.focusOffset)}return n}(e);return u>4&&(n.lineDiv.style.display="none"),function(e,t,n){var r=e.display,i=e.options.lineNumbers,o=r.lineDiv,l=o.firstChild;function a(t){var n=t.nextSibling;return s&&y&&e.display.currentWheelTarget==t?t.style.display="none":t.parentNode.removeChild(t),n}for(var u=r.view,c=r.viewFrom,f=0;f-1&&(d=!1),un(e,h,c,n)),d&&(M(h.lineNumber),h.lineNumber.appendChild(document.createTextNode(pe(e.options,c)))),l=h.node.nextSibling}else{var p=mn(e,h,c,n);o.insertBefore(p,l)}c+=h.size}for(;l;)l=a(l)}(e,n.updateLineNumbers,t.dims),u>4&&(n.lineDiv.style.display=""),n.renderedView=n.view,function(e){if(e&&e.activeElt&&e.activeElt!=D()&&(e.activeElt.focus(),e.anchorNode&&W(document.body,e.anchorNode)&&W(document.body,e.focusNode))){var t=window.getSelection(),n=document.createRange();n.setEnd(e.anchorNode,e.anchorOffset),n.collapse(!1),t.removeAllRanges(),t.addRange(n),t.extend(e.focusNode,e.focusOffset)}}(c),M(n.cursorDiv),M(n.selectionDiv),n.gutters.style.height=n.sizer.style.minHeight=0,a&&(n.lastWrapHeight=t.wrapperHeight,n.lastWrapWidth=t.wrapperWidth,ti(e,400)),n.updateLineNumbers=null,!0}function oi(e,t){for(var n=t.viewport,r=!0;(r&&e.options.lineWrapping&&t.oldDisplayWidth!=Tn(e)||(n&&null!=n.top&&(n={top:Math.min(e.doc.height+kn(e.display)-Mn(e),n.top)}),t.visible=xr(e.display,e.doc,n),!(t.visible.from>=e.display.viewFrom&&t.visible.to<=e.display.viewTo)))&&ii(e,t);r=!1){yr(e);var i=Dr(e);sr(e),Pr(e,i),si(e,i),t.force=!1}t.signal(e,"update",e),e.display.viewFrom==e.display.reportedViewFrom&&e.display.viewTo==e.display.reportedViewTo||(t.signal(e,"viewportChange",e,e.display.viewFrom,e.display.viewTo),e.display.reportedViewFrom=e.display.viewFrom,e.display.reportedViewTo=e.display.viewTo)}function li(e,t){var n=new ri(e,t);if(ii(e,n)){yr(e),oi(e,n);var r=Dr(e);sr(e),Pr(e,r),si(e,r),n.finish()}}function ai(e){var t=e.display.gutters.offsetWidth;e.display.sizer.style.marginLeft=t+"px"}function si(e,t){e.display.sizer.style.minHeight=t.docHeight+"px",e.display.heightForcer.style.top=t.docHeight+"px",e.display.gutters.style.height=t.docHeight+e.display.barHeight+Ln(e)+"px"}function ui(e){var t=e.display.gutters,n=e.options.gutters;M(t);for(var r=0;r-1&&!e.lineNumbers&&(e.gutters=e.gutters.slice(0),e.gutters.splice(t,1))}ri.prototype.signal=function(e,t){ot(e,t)&&this.events.push(arguments)},ri.prototype.finish=function(){for(var e=0;ea.clientWidth,c=a.scrollHeight>a.clientHeight;if(i&&u||o&&c){if(o&&y&&s)e:for(var h=t.target,d=l.view;h!=a;h=h.parentNode)for(var p=0;p=0&&me(e,r.to())<=0)return n}return-1};var vi=function(e,t){this.anchor=e,this.head=t};function yi(e,t){var n=e[t];e.sort(function(e,t){return me(e.from(),t.from())}),t=B(e,n);for(var r=1;r=0){var l=xe(o.from(),i.from()),a=be(o.to(),i.to()),s=o.empty()?i.from()==i.head:o.from()==o.head;r<=t&&--t,e.splice(--r,2,new vi(s?a:l,s?l:a))}}return new mi(e,t)}function bi(e,t){return new mi([new vi(e,t||e)],0)}function xi(e){return e.text?ge(e.from.line+e.text.length-1,_(e.text).length+(1==e.text.length?e.from.ch:0)):e.to}function wi(e,t){if(me(e,t.from)<0)return e;if(me(e,t.to)<=0)return xi(t);var n=e.line+t.text.length-(t.to.line-t.from.line)-1,r=e.ch;return e.line==t.to.line&&(r+=xi(t).ch-t.to.ch),ge(n,r)}function Ci(e,t){for(var n=[],r=0;r1&&e.remove(a.line+1,p-1),e.insert(a.line+1,v)}an(e,"change",e,t)}function Ai(e,t,n){!function e(r,i,o){if(r.linked)for(var l=0;la-e.cm.options.historyEventDelay||"*"==t.origin.charAt(0)))&&(o=function(e,t){return t?(Hi(e.done),_(e.done)):e.done.length&&!_(e.done).ranges?_(e.done):e.done.length>1&&!e.done[e.done.length-2].ranges?(e.done.pop(),_(e.done)):void 0}(i,i.lastOp==r)))l=_(o.changes),0==me(t.from,t.to)&&0==me(t.from,l.to)?l.to=xi(t):o.changes.push(Di(e,t));else{var s=_(i.done);for(s&&s.ranges||Fi(e.sel,i.done),o={changes:[Di(e,t)],generation:i.generation},i.done.push(o);i.done.length>i.undoDepth;)i.done.shift(),i.done[0].ranges||i.done.shift()}i.done.push(n),i.generation=++i.maxGeneration,i.lastModTime=i.lastSelTime=a,i.lastOp=i.lastSelOp=r,i.lastOrigin=i.lastSelOrigin=t.origin,l||nt(e,"historyAdded")}function Pi(e,t,n,r){var i=e.history,o=r&&r.origin;n==i.lastSelOp||o&&i.lastSelOrigin==o&&(i.lastModTime==i.lastSelTime&&i.lastOrigin==o||function(e,t,n,r){var i=t.charAt(0);return"*"==i||"+"==i&&n.ranges.length==r.ranges.length&&n.somethingSelected()==r.somethingSelected()&&new Date-e.history.lastSelTime<=(e.cm?e.cm.options.historyEventDelay:500)}(e,o,_(i.done),t))?i.done[i.done.length-1]=t:Fi(t,i.done),i.lastSelTime=+new Date,i.lastSelOrigin=o,i.lastSelOp=n,r&&!1!==r.clearRedo&&Hi(i.undone)}function Fi(e,t){var n=_(t);n&&n.ranges&&n.equals(e)||t.push(e)}function Ii(e,t,n,r){var i=t["spans_"+e.id],o=0;e.iter(Math.max(e.first,n),Math.min(e.first+e.size,r),function(n){n.markedSpans&&((i||(i=t["spans_"+e.id]={}))[o]=n.markedSpans),++o})}function zi(e){if(!e)return null;for(var t,n=0;n-1&&(_(a)[f]=u[f],delete u[f])}}}return r}function ji(e,t,n,r){if(r){var i=e.anchor;if(n){var o=me(t,i)<0;o!=me(n,i)<0?(i=t,t=n):o!=me(t,n)<0&&(t=n)}return new vi(i,t)}return new vi(n||t,t)}function Vi(e,t,n,r,i){null==i&&(i=e.cm&&(e.cm.display.shift||e.extend)),$i(e,new mi([ji(e.sel.primary(),t,n,i)],0),r)}function Gi(e,t,n){for(var r=[],i=e.cm&&(e.cm.display.shift||e.extend),o=0;o=t.ch:a.to>t.ch))){if(i&&(nt(s,"beforeCursorEnter"),s.explicitlyCleared)){if(o.markedSpans){--l;continue}break}if(!s.atomic)continue;if(n){var u=s.find(r<0?1:-1),c=void 0;if((r<0?s.inclusiveRight:s.inclusiveLeft)&&(u=eo(e,u,-r,u&&u.line==t.line?o:null)),u&&u.line==t.line&&(c=me(u,n))&&(r<0?c<0:c>0))return Qi(e,u,t,r,i)}var f=s.find(r<0?-1:1);return(r<0?s.inclusiveLeft:s.inclusiveRight)&&(f=eo(e,f,r,f.line==t.line?o:null)),f?Qi(e,f,t,r,i):null}}return t}function Ji(e,t,n,r,i){var o=r||1,l=Qi(e,t,n,o,i)||!i&&Qi(e,t,n,o,!0)||Qi(e,t,n,-o,i)||!i&&Qi(e,t,n,-o,!0);return l||(e.cantEdit=!0,ge(e.first,0))}function eo(e,t,n,r){return n<0&&0==t.ch?t.line>e.first?Ce(e,ge(t.line-1)):null:n>0&&t.ch==(r||ae(e,t.line)).text.length?t.line0)){var c=[s,1],f=me(u.from,a.from),h=me(u.to,a.to);(f<0||!l.inclusiveLeft&&!f)&&c.push({from:u.from,to:a.from}),(h>0||!l.inclusiveRight&&!h)&&c.push({from:a.to,to:u.to}),i.splice.apply(i,c),s+=c.length-3}}return i}(e,t.from,t.to);if(r)for(var i=r.length-1;i>=0;--i)io(e,{from:r[i].from,to:r[i].to,text:i?[""]:t.text,origin:t.origin});else io(e,t)}}function io(e,t){if(1!=t.text.length||""!=t.text[0]||0!=me(t.from,t.to)){var n=Ci(e,t);Ei(e,t,n,e.cm?e.cm.curOp.id:NaN),ao(e,t,n,Oe(e,t));var r=[];Ai(e,function(e,n){n||-1!=B(r,e.history)||(fo(e.history,t),r.push(e.history)),ao(e,t,null,Oe(e,t))})}}function oo(e,t,n){var r=e.cm&&e.cm.state.suppressEdits;if(!r||n){for(var i,o=e.history,l=e.sel,a="undo"==t?o.done:o.undone,s="undo"==t?o.undone:o.done,u=0;u=0;--d){var p=h(d);if(p)return p.v}}}}function lo(e,t){if(0!=t&&(e.first+=t,e.sel=new mi(q(e.sel.ranges,function(e){return new vi(ge(e.anchor.line+t,e.anchor.ch),ge(e.head.line+t,e.head.ch))}),e.sel.primIndex),e.cm)){qr(e.cm,e.first,e.first-t,t);for(var n=e.cm.display,r=n.viewFrom;re.lastLine())){if(t.from.lineo&&(t={from:t.from,to:ge(o,ae(e,o).text.length),text:[t.text[0]],origin:t.origin}),t.removed=se(e,t.from,t.to),n||(n=Ci(e,t)),e.cm?function(e,t,n){var r=e.doc,i=e.display,o=t.from,l=t.to,a=!1,s=o.line;e.options.lineWrapping||(s=fe(Be(ae(r,o.line))),r.iter(s,l.line+1,function(e){if(e==i.maxLine)return a=!0,!0})),r.sel.contains(t.from,t.to)>-1&&it(e),Mi(r,t,n,ir(e)),e.options.lineWrapping||(r.iter(s,o.line+t.text.length,function(e){var t=Xe(e);t>i.maxLineLength&&(i.maxLine=e,i.maxLineLength=t,i.maxLineChanged=!0,a=!1)}),a&&(e.curOp.updateMaxLine=!0)),function(e,t){if(e.modeFrontier=Math.min(e.modeFrontier,t),!(e.highlightFrontiern;r--){var i=ae(e,r).stateAfter;if(i&&(!(i instanceof Ht)||r+i.lookAhead1||!(this.children[0]instanceof po))){var a=[];this.collapse(a),this.children=[new po(a)],this.children[0].parent=this}},collapse:function(e){for(var t=0;t50){for(var l=i.lines.length%25+25,a=l;a10);e.parent.maybeSpill()}},iterN:function(e,t,n){for(var r=0;r0||0==l&&!1!==o.clearWhenEmpty)return o;if(o.replacedWith&&(o.collapsed=!0,o.widgetNode=N("span",[o.replacedWith],"CodeMirror-widget"),r.handleMouseEvents||o.widgetNode.setAttribute("cm-ignore-events","true"),r.insertLeft&&(o.widgetNode.insertLeft=!0)),o.collapsed){if(Re(e,t.line,t,n,o)||t.line!=n.line&&Re(e,n.line,t,n,o))throw new Error("Inserting collapsed marker partially overlapping an existing one");Le=!0}o.addToHistory&&Ei(e,{from:t,to:n,origin:"markText"},e.sel,NaN);var a,s=t.line,u=e.cm;if(e.iter(s,n.line+1,function(e){u&&o.collapsed&&!u.options.lineWrapping&&Be(e)==u.display.maxLine&&(a=!0),o.collapsed&&s!=t.line&&ce(e,0),function(e,t){e.markedSpans=e.markedSpans?e.markedSpans.concat([t]):[t],t.marker.attachLine(e)}(e,new Te(o,s==t.line?t.ch:null,s==n.line?n.ch:null)),++s}),o.collapsed&&e.iter(t.line,n.line+1,function(t){Ge(e,t)&&ce(t,0)}),o.clearOnEnter&&Je(o,"beforeCursorEnter",function(){return o.clear()}),o.readOnly&&(Se=!0,(e.history.done.length||e.history.undone.length)&&e.clearHistory()),o.collapsed&&(o.id=++yo,o.atomic=!0),u){if(a&&(u.curOp.updateMaxLine=!0),o.collapsed)qr(u,t.line,n.line+1);else if(o.className||o.title||o.startStyle||o.endStyle||o.css)for(var c=t.line;c<=n.line;c++)Zr(u,c,"text");o.atomic&&qi(u.doc),an(u,"markerAdded",u,o)}return o}bo.prototype.clear=function(){if(!this.explicitlyCleared){var e=this.doc.cm,t=e&&!e.curOp;if(t&&Br(e),ot(this,"clear")){var n=this.find();n&&an(this,"clear",n.from,n.to)}for(var r=null,i=null,o=0;oe.display.maxLineLength&&(e.display.maxLine=u,e.display.maxLineLength=c,e.display.maxLineChanged=!0)}null!=r&&e&&this.collapsed&&qr(e,r,i+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,e&&qi(e.doc)),e&&an(e,"markerCleared",e,this,r,i),t&&jr(e),this.parent&&this.parent.clear()}},bo.prototype.find=function(e,t){var n,r;null==e&&"bookmark"==this.type&&(e=1);for(var i=0;i=0;s--)ro(this,r[s]);a?Xi(this,a):this.cm&&Lr(this.cm)}),undo:_r(function(){oo(this,"undo")}),redo:_r(function(){oo(this,"redo")}),undoSelection:_r(function(){oo(this,"undo",!0)}),redoSelection:_r(function(){oo(this,"redo",!0)}),setExtending:function(e){this.extend=e},getExtending:function(){return this.extend},historySize:function(){for(var e=this.history,t=0,n=0,r=0;r=e.ch)&&t.push(i.marker.parent||i.marker)}return t},findMarks:function(e,t,n){e=Ce(this,e),t=Ce(this,t);var r=[],i=e.line;return this.iter(e.line,t.line+1,function(o){var l=o.markedSpans;if(l)for(var a=0;a=s.to||null==s.from&&i!=e.line||null!=s.from&&i==t.line&&s.from>=t.ch||n&&!n(s.marker)||r.push(s.marker.parent||s.marker)}++i}),r},getAllMarks:function(){var e=[];return this.iter(function(t){var n=t.markedSpans;if(n)for(var r=0;re)return t=e,!0;e-=o,++n}),Ce(this,ge(n,t))},indexFromPos:function(e){var t=(e=Ce(this,e)).ch;if(e.linet&&(t=e.from),null!=e.to&&e.to-1)return t.state.draggingText(e),void setTimeout(function(){return t.display.input.focus()},20);try{var c=e.dataTransfer.getData("Text");if(c){var f;if(t.state.draggingText&&!t.state.draggingText.copy&&(f=t.listSelections()),Yi(t.doc,bi(n,n)),f)for(var h=0;h=0;t--)so(e.doc,"",r[t].from,r[t].to,"+delete");Lr(e)})}function Xo(e,t,n){var r=oe(e.text,t+n,n);return r<0||r>e.text.length?null:r}function $o(e,t,n){var r=Xo(e,t.ch,n);return null==r?null:new ge(t.line,r,n<0?"after":"before")}function Yo(e,t,n,r,i){if(e){var o=Ze(n,t.doc.direction);if(o){var l,a=i<0?_(o):o[0],s=i<0==(1==a.level),u=s?"after":"before";if(a.level>0||"rtl"==t.doc.direction){var c=Wn(t,n);l=i<0?n.text.length-1:0;var f=Dn(t,c,l).top;l=le(function(e){return Dn(t,c,e).top==f},i<0==(1==a.level)?a.from:a.to-1,l),"before"==u&&(l=Xo(n,l,1))}else l=i<0?a.to:a.from;return new ge(r,l,u)}}return new ge(r,i<0?n.text.length:0,i<0?"before":"after")}Io.basic={Left:"goCharLeft",Right:"goCharRight",Up:"goLineUp",Down:"goLineDown",End:"goLineEnd",Home:"goLineStartSmart",PageUp:"goPageUp",PageDown:"goPageDown",Delete:"delCharAfter",Backspace:"delCharBefore","Shift-Backspace":"delCharBefore",Tab:"defaultTab","Shift-Tab":"indentAuto",Enter:"newlineAndIndent",Insert:"toggleOverwrite",Esc:"singleSelection"},Io.pcDefault={"Ctrl-A":"selectAll","Ctrl-D":"deleteLine","Ctrl-Z":"undo","Shift-Ctrl-Z":"redo","Ctrl-Y":"redo","Ctrl-Home":"goDocStart","Ctrl-End":"goDocEnd","Ctrl-Up":"goLineUp","Ctrl-Down":"goLineDown","Ctrl-Left":"goGroupLeft","Ctrl-Right":"goGroupRight","Alt-Left":"goLineStart","Alt-Right":"goLineEnd","Ctrl-Backspace":"delGroupBefore","Ctrl-Delete":"delGroupAfter","Ctrl-S":"save","Ctrl-F":"find","Ctrl-G":"findNext","Shift-Ctrl-G":"findPrev","Shift-Ctrl-F":"replace","Shift-Ctrl-R":"replaceAll","Ctrl-[":"indentLess","Ctrl-]":"indentMore","Ctrl-U":"undoSelection","Shift-Ctrl-U":"redoSelection","Alt-U":"redoSelection",fallthrough:"basic"},Io.emacsy={"Ctrl-F":"goCharRight","Ctrl-B":"goCharLeft","Ctrl-P":"goLineUp","Ctrl-N":"goLineDown","Alt-F":"goWordRight","Alt-B":"goWordLeft","Ctrl-A":"goLineStart","Ctrl-E":"goLineEnd","Ctrl-V":"goPageDown","Shift-Ctrl-V":"goPageUp","Ctrl-D":"delCharAfter","Ctrl-H":"delCharBefore","Alt-D":"delWordAfter","Alt-Backspace":"delWordBefore","Ctrl-K":"killLine","Ctrl-T":"transposeChars","Ctrl-O":"openLine"},Io.macDefault={"Cmd-A":"selectAll","Cmd-D":"deleteLine","Cmd-Z":"undo","Shift-Cmd-Z":"redo","Cmd-Y":"redo","Cmd-Home":"goDocStart","Cmd-Up":"goDocStart","Cmd-End":"goDocEnd","Cmd-Down":"goDocEnd","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight","Cmd-Left":"goLineLeft","Cmd-Right":"goLineRight","Alt-Backspace":"delGroupBefore","Ctrl-Alt-Backspace":"delGroupAfter","Alt-Delete":"delGroupAfter","Cmd-S":"save","Cmd-F":"find","Cmd-G":"findNext","Shift-Cmd-G":"findPrev","Cmd-Alt-F":"replace","Shift-Cmd-Alt-F":"replaceAll","Cmd-[":"indentLess","Cmd-]":"indentMore","Cmd-Backspace":"delWrappedLineLeft","Cmd-Delete":"delWrappedLineRight","Cmd-U":"undoSelection","Shift-Cmd-U":"redoSelection","Ctrl-Up":"goDocStart","Ctrl-Down":"goDocEnd",fallthrough:["basic","emacsy"]},Io.default=y?Io.macDefault:Io.pcDefault;var _o={selectAll:to,singleSelection:function(e){return e.setSelection(e.getCursor("anchor"),e.getCursor("head"),G)},killLine:function(e){return Ko(e,function(t){if(t.empty()){var n=ae(e.doc,t.head.line).text.length;return t.head.ch==n&&t.head.line0)i=new ge(i.line,i.ch+1),e.replaceRange(o.charAt(i.ch-1)+o.charAt(i.ch-2),ge(i.line,i.ch-2),i,"+transpose");else if(i.line>e.doc.first){var l=ae(e.doc,i.line-1).text;l&&(i=new ge(i.line,1),e.replaceRange(o.charAt(0)+e.doc.lineSeparator()+l.charAt(l.length-1),ge(i.line-1,l.length-1),i,"+transpose"))}n.push(new vi(i,i))}e.setSelections(n)})},newlineAndIndent:function(e){return Xr(e,function(){for(var t=e.listSelections(),n=t.length-1;n>=0;n--)e.replaceRange(e.doc.lineSeparator(),t[n].anchor,t[n].head,"+input");t=e.listSelections();for(var r=0;r-1&&(me((i=u.ranges[i]).from(),t)<0||t.xRel>0)&&(me(i.to(),t)>0||t.xRel<0)?function(e,t,n,r){var i=e.display,o=!1,u=$r(e,function(t){s&&(i.scroller.draggable=!1),e.state.draggingText=!1,tt(document,"mouseup",u),tt(document,"mousemove",c),tt(i.scroller,"dragstart",f),tt(i.scroller,"drop",u),o||(at(t),r.addNew||Vi(e.doc,n,null,null,r.extend),s||l&&9==a?setTimeout(function(){document.body.focus(),i.input.focus()},20):i.input.focus())}),c=function(e){o=o||Math.abs(t.clientX-e.clientX)+Math.abs(t.clientY-e.clientY)>=10},f=function(){return o=!0};s&&(i.scroller.draggable=!0),e.state.draggingText=u,u.copy=!r.moveOnDrag,i.scroller.dragDrop&&i.scroller.dragDrop(),Je(document,"mouseup",u),Je(document,"mousemove",c),Je(i.scroller,"dragstart",f),Je(i.scroller,"drop",u),gr(e),setTimeout(function(){return i.input.focus()},20)}(e,r,t,o):function(e,t,n,r){var i=e.display,o=e.doc;at(t);var l,a,s=o.sel,u=s.ranges;if(r.addNew&&!r.extend?(a=o.sel.contains(n),l=a>-1?u[a]:new vi(n,n)):(l=o.sel.primary(),a=o.sel.primIndex),"rectangle"==r.unit)r.addNew||(l=new vi(n,n)),n=lr(e,t,!0,!0),a=-1;else{var c=fl(e,n,r.unit);l=r.extend?ji(l,c.anchor,c.head,r.extend):c}r.addNew?-1==a?(a=u.length,$i(o,yi(u.concat([l]),a),{scroll:!1,origin:"*mouse"})):u.length>1&&u[a].empty()&&"char"==r.unit&&!r.extend?($i(o,yi(u.slice(0,a).concat(u.slice(a+1)),0),{scroll:!1,origin:"*mouse"}),s=o.sel):Ui(o,a,l,U):(a=0,$i(o,new mi([l],0),U),s=o.sel);var f=n;function h(t){if(0!=me(f,t))if(f=t,"rectangle"==r.unit){for(var i=[],u=e.options.tabSize,c=z(ae(o,n.line).text,n.ch,u),h=z(ae(o,t.line).text,t.ch,u),d=Math.min(c,h),p=Math.max(c,h),g=Math.min(n.line,t.line),m=Math.min(e.lastLine(),Math.max(n.line,t.line));g<=m;g++){var v=ae(o,g).text,y=X(v,d,u);d==p?i.push(new vi(ge(g,y),ge(g,y))):v.length>y&&i.push(new vi(ge(g,y),ge(g,X(v,p,u))))}i.length||i.push(new vi(n,n)),$i(o,yi(s.ranges.slice(0,a).concat(i),a),{origin:"*mouse",scroll:!1}),e.scrollIntoView(t)}else{var b,x=l,w=fl(e,t,r.unit),C=x.anchor;me(w.anchor,C)>0?(b=w.head,C=xe(x.from(),w.anchor)):(b=w.anchor,C=be(x.to(),w.head));var k=s.ranges.slice(0);k[a]=function(e,t){var n=t.anchor,r=t.head,i=ae(e.doc,n.line);if(0==me(n,r)&&n.sticky==r.sticky)return t;var o=Ze(i);if(!o)return t;var l=_e(o,n.ch,n.sticky),a=o[l];if(a.from!=n.ch&&a.to!=n.ch)return t;var s,u=l+(a.from==n.ch==(1!=a.level)?0:1);if(0==u||u==o.length)return t;if(r.line!=n.line)s=(r.line-n.line)*("ltr"==e.doc.direction?1:-1)>0;else{var c=_e(o,r.ch,r.sticky),f=c-l||(r.ch-n.ch)*(1==a.level?-1:1);s=c==u-1||c==u?f<0:f>0}var h=o[u+(s?-1:0)],d=s==(1==h.level),p=d?h.from:h.to,g=d?"after":"before";return n.ch==p&&n.sticky==g?t:new vi(new ge(n.line,p,g),r)}(e,new vi(Ce(o,C),b)),$i(o,yi(k,a),U)}}var d=i.wrapper.getBoundingClientRect(),p=0;function g(t){e.state.selectingText=!1,p=1/0,at(t),i.input.focus(),tt(document,"mousemove",m),tt(document,"mouseup",v),o.history.lastSelOrigin=null}var m=$r(e,function(t){ht(t)?function t(n){var l=++p,a=lr(e,n,!0,"rectangle"==r.unit);if(a)if(0!=me(a,f)){e.curOp.focus=D(),h(a);var s=xr(i,o);(a.line>=s.to||a.lined.bottom?20:0;u&&setTimeout($r(e,function(){p==l&&(i.scroller.scrollTop+=u,t(n))}),50)}}(t):g(t)}),v=$r(e,g);e.state.selectingText=v,Je(document,"mousemove",m),Je(document,"mouseup",v)}(e,r,t,o)}(t,r,o,e):ft(e)==n.scroller&&at(e):2==i?(r&&Vi(t.doc,r),setTimeout(function(){return n.input.focus()},20)):3==i&&(k?pl(t,e):gr(t)))}}function fl(e,t,n){if("char"==n)return new vi(t,t);if("word"==n)return e.findWordAt(t);if("line"==n)return new vi(ge(t.line,0),Ce(e.doc,ge(t.line+1,0)));var r=n(e,t);return new vi(r.from,r.to)}function hl(e,t,n,r){var i,o;if(t.touches)i=t.touches[0].clientX,o=t.touches[0].clientY;else try{i=t.clientX,o=t.clientY}catch(t){return!1}if(i>=Math.floor(e.display.gutters.getBoundingClientRect().right))return!1;r&&at(t);var l=e.display,a=l.lineDiv.getBoundingClientRect();if(o>a.bottom||!ot(e,n))return ut(t);o-=a.top-l.viewOffset;for(var s=0;s=i){var c=he(e.doc,o),f=e.options.gutters[s];return nt(e,n,e,c,f,t),ut(t)}}}function dl(e,t){return hl(e,t,"gutterClick",!0)}function pl(e,t){wn(e.display,t)||function(e,t){return!!ot(e,"gutterContextMenu")&&hl(e,t,"gutterContextMenu",!1)}(e,t)||rt(e,t,"contextmenu")||e.display.input.onContextMenu(t)}function gl(e){e.display.wrapper.className=e.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+e.options.theme.replace(/(^|\s)\s*/g," cm-s-"),Rn(e)}ul.prototype.compare=function(e,t,n){return this.time+400>e&&0==me(t,this.pos)&&n==this.button};var ml={toString:function(){return"CodeMirror.Init"}},vl={},yl={};function bl(e){ui(e),qr(e),wr(e)}function xl(e,t,n){var r=n&&n!=ml;if(!t!=!r){var i=e.display.dragFunctions,o=t?Je:tt;o(e.display.scroller,"dragstart",i.start),o(e.display.scroller,"dragenter",i.enter),o(e.display.scroller,"dragover",i.over),o(e.display.scroller,"dragleave",i.leave),o(e.display.scroller,"drop",i.drop)}}function wl(e){e.options.lineWrapping?(H(e.display.wrapper,"CodeMirror-wrap"),e.display.sizer.style.minWidth="",e.display.sizerWidth=null):(T(e.display.wrapper,"CodeMirror-wrap"),$e(e)),or(e),qr(e),Rn(e),setTimeout(function(){return Pr(e)},100)}function Cl(e,t){var r=this;if(!(this instanceof Cl))return new Cl(e,t);this.options=t=t?I(t):{},I(vl,t,!1),ci(t);var i=t.value;"string"==typeof i&&(i=new Lo(i,t.mode,null,t.lineSeparator,t.direction)),this.doc=i;var o=new Cl.inputStyles[t.inputStyle](this),u=this.display=new function(e,t,r){var i=this;this.input=r,i.scrollbarFiller=O("div",null,"CodeMirror-scrollbar-filler"),i.scrollbarFiller.setAttribute("cm-not-content","true"),i.gutterFiller=O("div",null,"CodeMirror-gutter-filler"),i.gutterFiller.setAttribute("cm-not-content","true"),i.lineDiv=N("div",null,"CodeMirror-code"),i.selectionDiv=O("div",null,null,"position: relative; z-index: 1"),i.cursorDiv=O("div",null,"CodeMirror-cursors"),i.measure=O("div",null,"CodeMirror-measure"),i.lineMeasure=O("div",null,"CodeMirror-measure"),i.lineSpace=N("div",[i.measure,i.lineMeasure,i.selectionDiv,i.cursorDiv,i.lineDiv],null,"position: relative; outline: none");var o=N("div",[i.lineSpace],"CodeMirror-lines");i.mover=O("div",[o],null,"position: relative"),i.sizer=O("div",[i.mover],"CodeMirror-sizer"),i.sizerWidth=null,i.heightForcer=O("div",null,null,"position: absolute; height: "+j+"px; width: 1px;"),i.gutters=O("div",null,"CodeMirror-gutters"),i.lineGutter=null,i.scroller=O("div",[i.sizer,i.heightForcer,i.gutters],"CodeMirror-scroll"),i.scroller.setAttribute("tabIndex","-1"),i.wrapper=O("div",[i.scrollbarFiller,i.gutterFiller,i.scroller],"CodeMirror"),l&&a<8&&(i.gutters.style.zIndex=-1,i.scroller.style.paddingRight=0),s||n&&v||(i.scroller.draggable=!0),e&&(e.appendChild?e.appendChild(i.wrapper):e(i.wrapper)),i.viewFrom=i.viewTo=t.first,i.reportedViewFrom=i.reportedViewTo=t.first,i.view=[],i.renderedView=null,i.externalMeasured=null,i.viewOffset=0,i.lastWrapHeight=i.lastWrapWidth=0,i.updateLineNumbers=null,i.nativeBarWidth=i.barHeight=i.barWidth=0,i.scrollbarsClipped=!1,i.lineNumWidth=i.lineNumInnerWidth=i.lineNumChars=null,i.alignWidgets=!1,i.cachedCharWidth=i.cachedTextHeight=i.cachedPaddingH=null,i.maxLine=null,i.maxLineLength=0,i.maxLineChanged=!1,i.wheelDX=i.wheelDY=i.wheelStartX=i.wheelStartY=null,i.shift=!1,i.selForContextMenu=null,i.activeTouch=null,r.init(i)}(e,i,o);for(var c in u.wrapper.CodeMirror=this,ui(this),gl(this),t.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),zr(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:!1,cutIncoming:!1,selectingText:!1,draggingText:!1,highlight:new R,keySeq:null,specialChars:null},t.autofocus&&!v&&u.input.focus(),l&&a<11&&setTimeout(function(){return r.display.input.reset(!0)},20),function(e){var t=e.display;Je(t.scroller,"mousedown",$r(e,cl)),Je(t.scroller,"dblclick",l&&a<11?$r(e,function(t){if(!rt(e,t)){var n=lr(e,t);if(n&&!dl(e,t)&&!wn(e.display,t)){at(t);var r=e.findWordAt(n);Vi(e.doc,r.anchor,r.head)}}}):function(t){return rt(e,t)||at(t)}),k||Je(t.scroller,"contextmenu",function(t){return pl(e,t)});var n,r={end:0};function i(){t.activeTouch&&(n=setTimeout(function(){return t.activeTouch=null},1e3),(r=t.activeTouch).end=+new Date)}function o(e,t){if(null==t.left)return!0;var n=t.left-e.left,r=t.top-e.top;return n*n+r*r>400}Je(t.scroller,"touchstart",function(i){if(!rt(e,i)&&!function(e){if(1!=e.touches.length)return!1;var t=e.touches[0];return t.radiusX<=1&&t.radiusY<=1}(i)&&!dl(e,i)){t.input.ensurePolled(),clearTimeout(n);var o=+new Date;t.activeTouch={start:o,moved:!1,prev:o-r.end<=300?r:null},1==i.touches.length&&(t.activeTouch.left=i.touches[0].pageX,t.activeTouch.top=i.touches[0].pageY)}}),Je(t.scroller,"touchmove",function(){t.activeTouch&&(t.activeTouch.moved=!0)}),Je(t.scroller,"touchend",function(n){var r=t.activeTouch;if(r&&!wn(t,n)&&null!=r.left&&!r.moved&&new Date-r.start<300){var l,a=e.coordsChar(t.activeTouch,"page");l=!r.prev||o(r,r.prev)?new vi(a,a):!r.prev.prev||o(r,r.prev.prev)?e.findWordAt(a):new vi(ge(a.line,0),Ce(e.doc,ge(a.line+1,0))),e.setSelection(l.anchor,l.head),e.focus(),at(n)}i()}),Je(t.scroller,"touchcancel",i),Je(t.scroller,"scroll",function(){t.scroller.clientHeight&&(Or(e,t.scroller.scrollTop),Wr(e,t.scroller.scrollLeft,!0),nt(e,"scroll",e))}),Je(t.scroller,"mousewheel",function(t){return gi(e,t)}),Je(t.scroller,"DOMMouseScroll",function(t){return gi(e,t)}),Je(t.wrapper,"scroll",function(){return t.wrapper.scrollTop=t.wrapper.scrollLeft=0}),t.dragFunctions={enter:function(t){rt(e,t)||ct(t)},over:function(t){rt(e,t)||(function(e,t){var n=lr(e,t);if(n){var r=document.createDocumentFragment();cr(e,n,r),e.display.dragCursor||(e.display.dragCursor=O("div",null,"CodeMirror-cursors CodeMirror-dragcursors"),e.display.lineSpace.insertBefore(e.display.dragCursor,e.display.cursorDiv)),A(e.display.dragCursor,r)}}(e,t),ct(t))},start:function(t){return function(e,t){if(l&&(!e.state.draggingText||+new Date-To<100))ct(t);else if(!rt(e,t)&&!wn(e.display,t)&&(t.dataTransfer.setData("Text",e.getSelection()),t.dataTransfer.effectAllowed="copyMove",t.dataTransfer.setDragImage&&!h)){var n=O("img",null,null,"position: fixed; left: 0; top: 0;");n.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",f&&(n.width=n.height=1,e.display.wrapper.appendChild(n),n._top=n.offsetTop),t.dataTransfer.setDragImage(n,0,0),f&&n.parentNode.removeChild(n)}}(e,t)},drop:$r(e,Mo),leave:function(t){rt(e,t)||Ao(e)}};var s=t.input.getField();Je(s,"keyup",function(t){return ol.call(e,t)}),Je(s,"keydown",$r(e,il)),Je(s,"keypress",$r(e,ll)),Je(s,"focus",function(t){return mr(e,t)}),Je(s,"blur",function(t){return vr(e,t)})}(this),Wo(),Br(this),this.curOp.forceUpdate=!0,Oi(this,i),t.autofocus&&!v||this.hasFocus()?setTimeout(F(mr,this),20):vr(this),yl)yl.hasOwnProperty(c)&&yl[c](r,t[c],ml);Cr(this),t.finishInit&&t.finishInit(this);for(var d=0;d150)){if(!r)return;n="prev"}}else u=0,n="not";"prev"==n?u=t>o.first?z(ae(o,t-1).text,null,l):0:"add"==n?u=s+e.options.indentUnit:"subtract"==n?u=s-e.options.indentUnit:"number"==typeof n&&(u=s+n),u=Math.max(0,u);var f="",h=0;if(e.options.indentWithTabs)for(var d=Math.floor(u/l);d;--d)h+=l,f+="\t";if(h1)if(Ll&&Ll.text.join("\n")==t){if(r.ranges.length%Ll.text.length==0){u=[];for(var c=0;c=0;f--){var h=r.ranges[f],d=h.from(),p=h.to();h.empty()&&(n&&n>0?d=ge(d.line,d.ch-n):e.state.overwrite&&!a?p=ge(p.line,Math.min(ae(o,p.line).text.length,p.ch+_(s).length)):Ll&&Ll.lineWise&&Ll.text.join("\n")==t&&(d=p=ge(d.line,0))),l=e.curOp.updateInput;var g={from:d,to:p,text:u?u[f%u.length]:s,origin:i||(a?"paste":e.state.cutIncoming?"cut":"+input")};ro(e.doc,g),an(e,"inputRead",e,g)}t&&!a&&Ol(e,t),Lr(e),e.curOp.updateInput=l,e.curOp.typing=!0,e.state.pasteIncoming=e.state.cutIncoming=!1}function Al(e,t){var n=e.clipboardData&&e.clipboardData.getData("Text");if(n)return e.preventDefault(),t.isReadOnly()||t.options.disableInput||Xr(t,function(){return Ml(t,n,0,null,"paste")}),!0}function Ol(e,t){if(e.options.electricChars&&e.options.smartIndent)for(var n=e.doc.sel,r=n.ranges.length-1;r>=0;r--){var i=n.ranges[r];if(!(i.head.ch>100||r&&n.ranges[r-1].head.line==i.head.line)){var o=e.getModeAt(i.head),l=!1;if(o.electricChars){for(var a=0;a-1){l=Sl(e,i.head.line,"smart");break}}else o.electricInput&&o.electricInput.test(ae(e.doc,i.head.line).text.slice(0,i.head.ch))&&(l=Sl(e,i.head.line,"smart"));l&&an(e,"electricInput",e,i.head.line)}}}function Nl(e){for(var t=[],n=[],r=0;r=t.text.length?(n.ch=t.text.length,n.sticky="before"):n.ch<=0&&(n.ch=0,n.sticky="after");var o=_e(i,n.ch,n.sticky),l=i[o];if("ltr"==e.doc.direction&&l.level%2==0&&(r>0?l.to>n.ch:l.from=l.from&&h>=c.begin)){var d=f?"before":"after";return new ge(n.line,h,d)}}var p=function(e,t,r){for(var o=function(e,t){return t?new ge(n.line,s(e,1),"before"):new ge(n.line,e,"after")};e>=0&&e0==(1!=l.level),u=a?r.begin:s(r.end,-1);if(l.from<=u&&u0?c.end:s(c.begin,-1);return null==m||r>0&&m==t.text.length||!(g=p(r>0?0:i.length-1,r,u(m)))?null:g}(e.cm,a,t,n):$o(a,t,n))){if(r||((l=t.line+n)=e.first+e.size||(t=new ge(l,t.ch,t.sticky),!(a=ae(e,l)))))return!1;t=Yo(i,e.cm,a,t.line,n)}else t=o;return!0}if("char"==r)s();else if("column"==r)s(!0);else if("word"==r||"group"==r)for(var u=null,c="group"==r,f=e.cm&&e.cm.getHelper(t,"wordChars"),h=!0;!(n<0)||s(!h);h=!1){var d=a.text.charAt(t.ch)||"\n",p=te(d,f)?"w":c&&"\n"==d?"n":!c||/\s/.test(d)?null:"p";if(!c||h||p||(p="s"),u&&u!=p){n<0&&(n=1,s(),t.sticky="after");break}if(p&&(u=p),n>0&&!s(!h))break}var g=Ji(e,t,o,l,!0);return ve(o,g)&&(g.hitSide=!0),g}function El(e,t,n,r){var i,o,l=e.doc,a=t.left;if("page"==r){var s=Math.min(e.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight),u=Math.max(s-.5*er(e.display),3);i=(n>0?t.bottom:t.top)+n*u}else"line"==r&&(i=n>0?t.bottom+3:t.top-3);for(;(o=_n(e,a,i)).outside;){if(n<0?i<=0:i>=l.height){o.hitSide=!0;break}i+=5*n}return o}var Pl=function(e){this.cm=e,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new R,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null};function Fl(e,t){var n=Nn(e,t.line);if(!n||n.hidden)return null;var r=ae(e.doc,t.line),i=An(n,r,t.line),o=Ze(r,e.doc.direction),l="left";if(o){var a=_e(o,t.ch);l=a%2?"right":"left"}var s=Pn(i.map,t.ch,l);return s.offset="right"==s.collapse?s.end:s.start,s}function Il(e,t){return t&&(e.bad=!0),e}function zl(e,t,n){var r;if(t==e.display.lineDiv){if(!(r=e.display.lineDiv.childNodes[n]))return Il(e.clipPos(ge(e.display.viewTo-1)),!0);t=null,n=0}else for(r=t;;r=r.parentNode){if(!r||r==e.display.lineDiv)return null;if(r.parentNode&&r.parentNode==e.display.lineDiv)break}for(var i=0;i=t.display.viewTo||o.line=t.display.viewFrom&&Fl(t,i)||{node:s[0].measure.map[2],offset:0},c=o.liner.firstLine()&&(l=ge(l.line-1,ae(r.doc,l.line-1).length)),a.ch==ae(r.doc,a.line).text.length&&a.linei.viewTo-1)return!1;l.line==i.viewFrom||0==(e=ar(r,l.line))?(t=fe(i.view[0].line),n=i.view[0].node):(t=fe(i.view[e].line),n=i.view[e-1].node.nextSibling);var s,u,c=ar(r,a.line);if(c==i.view.length-1?(s=i.viewTo-1,u=i.lineDiv.lastChild):(s=fe(i.view[c+1].line)-1,u=i.view[c+1].node.previousSibling),!n)return!1;for(var f=r.doc.splitLines(function(e,t,n,r,i){var o="",l=!1,a=e.doc.lineSeparator();function s(){l&&(o+=a,l=!1)}function u(e){e&&(s(),o+=e)}function c(t){if(1==t.nodeType){var n=t.getAttribute("cm-text");if(null!=n)return void u(n||t.textContent.replace(/\u200b/g,""));var o,f=t.getAttribute("cm-marker");if(f){var h=e.findMarks(ge(r,0),ge(i+1,0),(g=+f,function(e){return e.id==g}));return void(h.length&&(o=h[0].find(0))&&u(se(e.doc,o.from,o.to).join(a)))}if("false"==t.getAttribute("contenteditable"))return;var d=/^(pre|div|p)$/i.test(t.nodeName);d&&s();for(var p=0;p1&&h.length>1;)if(_(f)==_(h))f.pop(),h.pop(),s--;else{if(f[0]!=h[0])break;f.shift(),h.shift(),t++}for(var d=0,p=0,g=f[0],m=h[0],v=Math.min(g.length,m.length);dl.ch&&y.charCodeAt(y.length-p-1)==b.charCodeAt(b.length-p-1);)d--,p++;f[f.length-1]=y.slice(0,y.length-p).replace(/^\u200b+/,""),f[0]=f[0].slice(d).replace(/\u200b+$/,"");var w=ge(t,d),C=ge(s,h.length?_(h).length-p:0);return f.length>1||f[0]||me(w,C)?(so(r.doc,f,w,C,"+input"),!0):void 0},Pl.prototype.ensurePolled=function(){this.forceCompositionEnd()},Pl.prototype.reset=function(){this.forceCompositionEnd()},Pl.prototype.forceCompositionEnd=function(){this.composing&&(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),this.div.blur(),this.div.focus())},Pl.prototype.readFromDOMSoon=function(){var e=this;null==this.readDOMTimeout&&(this.readDOMTimeout=setTimeout(function(){if(e.readDOMTimeout=null,e.composing){if(!e.composing.done)return;e.composing=null}e.updateFromDOM()},80))},Pl.prototype.updateFromDOM=function(){var e=this;!this.cm.isReadOnly()&&this.pollContent()||Xr(this.cm,function(){return qr(e.cm)})},Pl.prototype.setUneditable=function(e){e.contentEditable="false"},Pl.prototype.onKeyPress=function(e){0!=e.charCode&&(e.preventDefault(),this.cm.isReadOnly()||$r(this.cm,Ml)(this.cm,String.fromCharCode(null==e.charCode?e.keyCode:e.charCode),0))},Pl.prototype.readOnlyChanged=function(e){this.div.contentEditable=String("nocursor"!=e)},Pl.prototype.onContextMenu=function(){},Pl.prototype.resetPosition=function(){},Pl.prototype.needsContentAttribute=!0;var Bl=function(e){this.cm=e,this.prevInput="",this.pollingFast=!1,this.polling=new R,this.hasSelection=!1,this.composing=null};Bl.prototype.init=function(e){var t=this,n=this,r=this.cm,i=this.wrapper=Dl(),o=this.textarea=i.firstChild;function s(e){if(!rt(r,e)){if(r.somethingSelected())Tl({lineWise:!1,text:r.getSelections()});else{if(!r.options.lineWiseCopyCut)return;var t=Nl(r);Tl({lineWise:!0,text:t.text}),"cut"==e.type?r.setSelections(t.ranges,null,G):(n.prevInput="",o.value=t.text.join("\n"),P(o))}"cut"==e.type&&(r.state.cutIncoming=!0)}}e.wrapper.insertBefore(i,e.wrapper.firstChild),g&&(o.style.width="0px"),Je(o,"input",function(){l&&a>=9&&t.hasSelection&&(t.hasSelection=null),n.poll()}),Je(o,"paste",function(e){rt(r,e)||Al(e,r)||(r.state.pasteIncoming=!0,n.fastPoll())}),Je(o,"cut",s),Je(o,"copy",s),Je(e.scroller,"paste",function(t){wn(e,t)||rt(r,t)||(r.state.pasteIncoming=!0,n.focus())}),Je(e.lineSpace,"selectstart",function(t){wn(e,t)||at(t)}),Je(o,"compositionstart",function(){var e=r.getCursor("from");n.composing&&n.composing.range.clear(),n.composing={start:e,range:r.markText(e,r.getCursor("to"),{className:"CodeMirror-composing"})}}),Je(o,"compositionend",function(){n.composing&&(n.poll(),n.composing.range.clear(),n.composing=null)})},Bl.prototype.prepareSelection=function(){var e=this.cm,t=e.display,n=e.doc,r=ur(e);if(e.options.moveInputWithCursor){var i=Xn(e,n.sel.primary().head,"div"),o=t.wrapper.getBoundingClientRect(),l=t.lineDiv.getBoundingClientRect();r.teTop=Math.max(0,Math.min(t.wrapper.clientHeight-10,i.top+l.top-o.top)),r.teLeft=Math.max(0,Math.min(t.wrapper.clientWidth-10,i.left+l.left-o.left))}return r},Bl.prototype.showSelection=function(e){var t=this.cm,n=t.display;A(n.cursorDiv,e.cursors),A(n.selectionDiv,e.selection),null!=e.teTop&&(this.wrapper.style.top=e.teTop+"px",this.wrapper.style.left=e.teLeft+"px")},Bl.prototype.reset=function(e){if(!this.contextMenuPending&&!this.composing){var t=this.cm;if(t.somethingSelected()){this.prevInput="";var n=t.getSelection();this.textarea.value=n,t.state.focused&&P(this.textarea),l&&a>=9&&(this.hasSelection=n)}else e||(this.prevInput=this.textarea.value="",l&&a>=9&&(this.hasSelection=null))}},Bl.prototype.getField=function(){return this.textarea},Bl.prototype.supportsTouch=function(){return!1},Bl.prototype.focus=function(){if("nocursor"!=this.cm.options.readOnly&&(!v||D()!=this.textarea))try{this.textarea.focus()}catch(e){}},Bl.prototype.blur=function(){this.textarea.blur()},Bl.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0},Bl.prototype.receivedFocus=function(){this.slowPoll()},Bl.prototype.slowPoll=function(){var e=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,function(){e.poll(),e.cm.state.focused&&e.slowPoll()})},Bl.prototype.fastPoll=function(){var e=!1,t=this;t.pollingFast=!0,t.polling.set(20,function n(){var r=t.poll();r||e?(t.pollingFast=!1,t.slowPoll()):(e=!0,t.polling.set(60,n))})},Bl.prototype.poll=function(){var e=this,t=this.cm,n=this.textarea,r=this.prevInput;if(this.contextMenuPending||!t.state.focused||xt(n)&&!r&&!this.composing||t.isReadOnly()||t.options.disableInput||t.state.keySeq)return!1;var i=n.value;if(i==r&&!t.somethingSelected())return!1;if(l&&a>=9&&this.hasSelection===i||y&&/[\uf700-\uf7ff]/.test(i))return t.display.input.reset(),!1;if(t.doc.sel==t.display.selForContextMenu){var o=i.charCodeAt(0);if(8203!=o||r||(r="​"),8666==o)return this.reset(),this.cm.execCommand("undo")}for(var s=0,u=Math.min(r.length,i.length);s1e3||i.indexOf("\n")>-1?n.value=e.prevInput="":e.prevInput=i,e.composing&&(e.composing.range.clear(),e.composing.range=t.markText(e.composing.start,t.getCursor("to"),{className:"CodeMirror-composing"}))}),!0},Bl.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},Bl.prototype.onKeyPress=function(){l&&a>=9&&(this.hasSelection=null),this.fastPoll()},Bl.prototype.onContextMenu=function(e){var t=this,n=t.cm,r=n.display,i=t.textarea,o=lr(n,e),u=r.scroller.scrollTop;if(o&&!f){var c=n.options.resetSelectionOnContextMenu;c&&-1==n.doc.sel.contains(o)&&$r(n,$i)(n.doc,bi(o),G);var h=i.style.cssText,d=t.wrapper.style.cssText;t.wrapper.style.cssText="position: absolute";var p,g=t.wrapper.getBoundingClientRect();if(i.style.cssText="position: absolute; width: 30px; height: 30px;\n top: "+(e.clientY-g.top-5)+"px; left: "+(e.clientX-g.left-5)+"px;\n z-index: 1000; background: "+(l?"rgba(255, 255, 255, .05)":"transparent")+";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);",s&&(p=window.scrollY),r.input.focus(),s&&window.scrollTo(null,p),r.input.reset(),n.somethingSelected()||(i.value=t.prevInput=" "),t.contextMenuPending=!0,r.selForContextMenu=n.doc.sel,clearTimeout(r.detectingSelectAll),l&&a>=9&&v(),k){ct(e);var m=function(){tt(window,"mouseup",m),setTimeout(y,20)};Je(window,"mouseup",m)}else setTimeout(y,50)}function v(){if(null!=i.selectionStart){var e=n.somethingSelected(),o="​"+(e?i.value:"");i.value="⇚",i.value=o,t.prevInput=e?"":"​",i.selectionStart=1,i.selectionEnd=o.length,r.selForContextMenu=n.doc.sel}}function y(){if(t.contextMenuPending=!1,t.wrapper.style.cssText=d,i.style.cssText=h,l&&a<9&&r.scrollbars.setScrollTop(r.scroller.scrollTop=u),null!=i.selectionStart){(!l||l&&a<9)&&v();var e=0,o=function(){r.selForContextMenu==n.doc.sel&&0==i.selectionStart&&i.selectionEnd>0&&"​"==t.prevInput?$r(n,to)(n):e++<10?r.detectingSelectAll=setTimeout(o,500):(r.selForContextMenu=null,r.input.reset())};r.detectingSelectAll=setTimeout(o,200)}}},Bl.prototype.readOnlyChanged=function(e){e||this.reset(),this.textarea.disabled="nocursor"==e},Bl.prototype.setUneditable=function(){},Bl.prototype.needsContentAttribute=!1,function(e){var t=e.optionHandlers;function n(n,r,i,o){e.defaults[n]=r,i&&(t[n]=o?function(e,t,n){n!=ml&&i(e,t,n)}:i)}e.defineOption=n,e.Init=ml,n("value","",function(e,t){return e.setValue(t)},!0),n("mode",null,function(e,t){e.doc.modeOption=t,Si(e)},!0),n("indentUnit",2,Si,!0),n("indentWithTabs",!1),n("smartIndent",!0),n("tabSize",4,function(e){Li(e),Rn(e),qr(e)},!0),n("lineSeparator",null,function(e,t){if(e.doc.lineSep=t,t){var n=[],r=e.doc.first;e.doc.iter(function(e){for(var i=0;;){var o=e.text.indexOf(t,i);if(-1==o)break;i=o+t.length,n.push(ge(r,o))}r++});for(var i=n.length-1;i>=0;i--)so(e.doc,t,n[i],ge(n[i].line,n[i].ch+t.length))}}),n("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g,function(e,t,n){e.state.specialChars=new RegExp(t.source+(t.test("\t")?"":"|\t"),"g"),n!=ml&&e.refresh()}),n("specialCharPlaceholder",Zt,function(e){return e.refresh()},!0),n("electricChars",!0),n("inputStyle",v?"contenteditable":"textarea",function(){throw new Error("inputStyle can not (yet) be changed in a running editor")},!0),n("spellcheck",!1,function(e,t){return e.getInputField().spellcheck=t},!0),n("rtlMoveVisually",!x),n("wholeLineUpdateBefore",!0),n("theme","default",function(e){gl(e),bl(e)},!0),n("keyMap","default",function(e,t,n){var r=Uo(t),i=n!=ml&&Uo(n);i&&i.detach&&i.detach(e,r),r.attach&&r.attach(e,i||null)}),n("extraKeys",null),n("configureMouse",null),n("lineWrapping",!1,wl,!0),n("gutters",[],function(e){ci(e.options),bl(e)},!0),n("fixedGutter",!0,function(e,t){e.display.gutters.style.left=t?rr(e.display)+"px":"0",e.refresh()},!0),n("coverGutterNextToScrollbar",!1,function(e){return Pr(e)},!0),n("scrollbarStyle","native",function(e){zr(e),Pr(e),e.display.scrollbars.setScrollTop(e.doc.scrollTop),e.display.scrollbars.setScrollLeft(e.doc.scrollLeft)},!0),n("lineNumbers",!1,function(e){ci(e.options),bl(e)},!0),n("firstLineNumber",1,bl,!0),n("lineNumberFormatter",function(e){return e},bl,!0),n("showCursorWhenSelecting",!1,sr,!0),n("resetSelectionOnContextMenu",!0),n("lineWiseCopyCut",!0),n("pasteLinesPerSelection",!0),n("readOnly",!1,function(e,t){"nocursor"==t&&(vr(e),e.display.input.blur()),e.display.input.readOnlyChanged(t)}),n("disableInput",!1,function(e,t){t||e.display.input.reset()},!0),n("dragDrop",!0,xl),n("allowDropFileTypes",null),n("cursorBlinkRate",530),n("cursorScrollMargin",0),n("cursorHeight",1,sr,!0),n("singleCursorHeightPerLine",!0,sr,!0),n("workTime",100),n("workDelay",100),n("flattenSpans",!0,Li,!0),n("addModeClass",!1,Li,!0),n("pollInterval",100),n("undoDepth",200,function(e,t){return e.doc.history.undoDepth=t}),n("historyEventDelay",1250),n("viewportMargin",10,function(e){return e.refresh()},!0),n("maxHighlightLength",1e4,Li,!0),n("moveInputWithCursor",!0,function(e,t){t||e.display.input.resetPosition()}),n("tabindex",null,function(e,t){return e.display.input.getField().tabIndex=t||""}),n("autofocus",null),n("direction","ltr",function(e,t){return e.doc.setDirection(t)},!0)}(Cl),function(e){var t=e.optionHandlers,n=e.helpers={};e.prototype={constructor:e,focus:function(){window.focus(),this.display.input.focus()},setOption:function(e,n){var r=this.options,i=r[e];r[e]==n&&"mode"!=e||(r[e]=n,t.hasOwnProperty(e)&&$r(this,t[e])(this,n,i),nt(this,"optionChange",this,e))},getOption:function(e){return this.options[e]},getDoc:function(){return this.doc},addKeyMap:function(e,t){this.state.keyMaps[t?"push":"unshift"](Uo(e))},removeKeyMap:function(e){for(var t=this.state.keyMaps,n=0;nn&&(Sl(this,i.head.line,e,!0),n=i.head.line,r==this.doc.sel.primIndex&&Lr(this));else{var o=i.from(),l=i.to(),a=Math.max(n,o.line);n=Math.min(this.lastLine(),l.line-(l.ch?0:1))+1;for(var s=a;s0&&Ui(this.doc,r,new vi(o,u[r].to()),G)}}}),getTokenAt:function(e,t){return Vt(this,e,t)},getLineTokens:function(e,t){return Vt(this,ge(e),t,!0)},getTokenTypeAt:function(e){e=Ce(this.doc,e);var t,n=Ft(this,ae(this.doc,e.line)),r=0,i=(n.length-1)/2,o=e.ch;if(0==o)t=n[2];else for(;;){var l=r+i>>1;if((l?n[2*l-1]:0)>=o)i=l;else{if(!(n[2*l+1]o&&(e=o,i=!0),r=ae(this.doc,e)}else r=e;return Gn(this,r,{top:0,left:0},t||"page",n||i).top+(i?this.doc.height-Ke(r):0)},defaultTextHeight:function(){return er(this.display)},defaultCharWidth:function(){return tr(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(e,t,n,r,i){var o,l,a,s=this.display,u=(e=Xn(this,Ce(this.doc,e))).bottom,c=e.left;if(t.style.position="absolute",t.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(t),s.sizer.appendChild(t),"over"==r)u=e.top;else if("above"==r||"near"==r){var f=Math.max(s.wrapper.clientHeight,this.doc.height),h=Math.max(s.sizer.clientWidth,s.lineSpace.clientWidth);("above"==r||e.bottom+t.offsetHeight>f)&&e.top>t.offsetHeight?u=e.top-t.offsetHeight:e.bottom+t.offsetHeight<=f&&(u=e.bottom),c+t.offsetWidth>h&&(c=h-t.offsetWidth)}t.style.top=u+"px",t.style.left=t.style.right="","right"==i?(c=s.sizer.clientWidth-t.offsetWidth,t.style.right="0px"):("left"==i?c=0:"middle"==i&&(c=(s.sizer.clientWidth-t.offsetWidth)/2),t.style.left=c+"px"),n&&(o=this,l={left:c,top:u,right:c+t.offsetWidth,bottom:u+t.offsetHeight},null!=(a=kr(o,l)).scrollTop&&Or(o,a.scrollTop),null!=a.scrollLeft&&Wr(o,a.scrollLeft))},triggerOnKeyDown:Yr(il),triggerOnKeyPress:Yr(ll),triggerOnKeyUp:ol,triggerOnMouseDown:Yr(cl),execCommand:function(e){if(_o.hasOwnProperty(e))return _o[e].call(null,this)},triggerElectric:Yr(function(e){Ol(this,e)}),findPosH:function(e,t,n,r){var i=1;t<0&&(i=-1,t=-t);for(var o=Ce(this.doc,e),l=0;l0&&a(n.charAt(r-1));)--r;for(;i.5)&&or(this),nt(this,"refresh",this)}),swapDoc:Yr(function(e){var t=this.doc;return t.cm=null,Oi(this,e),Rn(this),this.display.input.reset(),Tr(this,e.scrollLeft,e.scrollTop),this.curOp.forceScroll=!0,an(this,"swapDoc",this,t),t}),getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},lt(e),e.registerHelper=function(t,r,i){n.hasOwnProperty(t)||(n[t]=e[t]={_global:[]}),n[t][r]=i},e.registerGlobalHelper=function(t,r,i,o){e.registerHelper(t,r,o),n[t]._global.push({pred:i,val:o})}}(Cl);var jl="iter insert remove copy getEditor constructor".split(" ");for(var Vl in Lo.prototype)Lo.prototype.hasOwnProperty(Vl)&&B(jl,Vl)<0&&(Cl.prototype[Vl]=function(e){return function(){return e.apply(this.doc,arguments)}}(Lo.prototype[Vl]));return lt(Lo),Cl.inputStyles={textarea:Bl,contenteditable:Pl},Cl.defineMode=function(e){Cl.defaults.mode||"null"==e||(Cl.defaults.mode=e),function(e,t){arguments.length>2&&(t.dependencies=Array.prototype.slice.call(arguments,2)),kt[e]=t}.apply(this,arguments)},Cl.defineMIME=function(e,t){St[e]=t},Cl.defineMode("null",function(){return{token:function(e){return e.skipToEnd()}}}),Cl.defineMIME("text/plain","null"),Cl.defineExtension=function(e,t){Cl.prototype[e]=t},Cl.defineDocExtension=function(e,t){Lo.prototype[e]=t},Cl.fromTextArea=function(e,t){if((t=t?I(t):{}).value=e.value,!t.tabindex&&e.tabIndex&&(t.tabindex=e.tabIndex),!t.placeholder&&e.placeholder&&(t.placeholder=e.placeholder),null==t.autofocus){var n=D();t.autofocus=n==e||null!=e.getAttribute("autofocus")&&n==document.body}function r(){e.value=a.getValue()}var i;if(e.form&&(Je(e.form,"submit",r),!t.leaveSubmitMethodAlone)){var o=e.form;i=o.submit;try{var l=o.submit=function(){r(),o.submit=i,o.submit(),o.submit=l}}catch(e){}}t.finishInit=function(t){t.save=r,t.getTextArea=function(){return e},t.toTextArea=function(){t.toTextArea=isNaN,r(),e.parentNode.removeChild(t.getWrapperElement()),e.style.display="",e.form&&(tt(e.form,"submit",r),"function"==typeof e.form.submit&&(e.form.submit=i))}},e.style.display="none";var a=Cl(function(t){return e.parentNode.insertBefore(t,e.nextSibling)},t);return a},function(e){e.off=tt,e.on=Je,e.wheelEventPixels=pi,e.Doc=Lo,e.splitLines=bt,e.countColumn=z,e.findColumn=X,e.isWordChar=ee,e.Pass=V,e.signal=nt,e.Line=Kt,e.changeEnd=xi,e.scrollbarModel=Ir,e.Pos=ge,e.cmpPos=me,e.modes=kt,e.mimeModes=St,e.resolveMode=Lt,e.getMode=Tt,e.modeExtensions=Mt,e.extendMode=At,e.copyState=Ot,e.startState=Wt,e.innerMode=Nt,e.commands=_o,e.keyMap=Io,e.keyName=Go,e.isModifierKey=jo,e.lookupKey=Bo,e.normalizeKeyMap=Ro,e.StringStream=Dt,e.SharedTextMarker=wo,e.TextMarker=bo,e.LineWidget=mo,e.e_preventDefault=at,e.e_stopPropagation=st,e.e_stop=ct,e.addClass=H,e.contains=W,e.rmClass=T,e.keyNames=Ho}(Cl),Cl.version="5.34.1",Cl}(),function(e){var t=/MSIE \d/.test(navigator.userAgent)&&(null==document.documentMode||document.documentMode<8),n=e.Pos,r={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<"};function i(e,t,i){var l=e.getLineHandle(t.line),a=t.ch-1,s=i&&i.afterCursor;null==s&&(s=/(^| )cm-fat-cursor($| )/.test(e.getWrapperElement().className));var u=!s&&a>=0&&r[l.text.charAt(a)]||r[l.text.charAt(++a)];if(!u)return null;var c=">"==u.charAt(1)?1:-1;if(i&&i.strict&&c>0!=(a==t.ch))return null;var f=e.getTokenTypeAt(n(t.line,a+1)),h=o(e,n(t.line,a+(c>0?1:0)),c,f||null,i);return null==h?null:{from:n(t.line,a),to:h&&h.pos,match:h&&h.ch==u.charAt(0),forward:c>0}}function o(e,t,i,o,l){for(var a=l&&l.maxScanLineLength||1e4,s=l&&l.maxScanLines||1e3,u=[],c=l&&l.bracketRegex?l.bracketRegex:/[(){}[\]]/,f=i>0?Math.min(t.line+s,e.lastLine()+1):Math.max(e.firstLine()-1,t.line-s),h=t.line;h!=f;h+=i){var d=e.getLine(h);if(d){var p=i>0?0:d.length-1,g=i>0?d.length:-1;if(!(d.length>a))for(h==t.line&&(p=t.ch-(i<0?1:0));p!=g;p+=i){var m=d.charAt(p);if(c.test(m)&&(void 0===o||e.getTokenTypeAt(n(h,p+1))==o)){var v=r[m];if(">"==v.charAt(1)==i>0)u.push(m);else{if(!u.length)return{pos:n(h,p),ch:m};u.pop()}}}}}return h-i!=(i>0?e.lastLine():e.firstLine())&&null}function l(e,r,o){for(var l=e.state.matchBrackets.maxHighlightLineLength||1e3,a=[],s=e.listSelections(),u=0;u-1&&d>f){if(u=c.slice(0,d),/\S/.test(u)){u="";for(var h=0;h-1&&!/\S/.test(c.slice(0,d))&&(u=c.slice(0,d));null!=u&&(u+=r.blockCommentContinue)}if(null==u&&r.lineComment&&n(t)){var c=t.getLine(a.line),d=c.indexOf(r.lineComment);d>-1&&(u=c.slice(0,d),/\S/.test(u)?u=null:u+=r.lineComment+c.slice(d+r.lineComment.length).match(/^\s*/)[0])}if(null==u)return e.Pass;o[l]="\n"+u}t.operation(function(){for(var e=i.length-1;e>=0;e--)t.replaceRange(o[e],i[e].from(),i[e].to(),"+insert")})}function n(e){var t=e.getOption("continueComments");return!t||"object"!=typeof t||!1!==t.continueLineComment}e.defineOption("continueComments",null,function(n,r,i){if(i&&i!=e.Init&&n.removeKeyMap("continueComment"),r){var o="Enter";"string"==typeof r?o=r:"object"==typeof r&&r.key&&(o=r.key);var l={name:"continueComment"};l[o]=t,n.addKeyMap(l)}})}(CodeMirror),function(e){"use strict";var t={},n=/[^\s\u00a0]/,r=e.Pos;function i(e){var t=e.search(n);return-1==t?0:t}function o(e,t){var n=e.getMode();return!1!==n.useInnerComments&&n.innerMode?e.getModeAt(t):n}e.commands.toggleComment=function(e){e.toggleComment()},e.defineExtension("toggleComment",function(e){e||(e=t);for(var n=1/0,i=this.listSelections(),o=null,l=i.length-1;l>=0;l--){var a=i[l].from(),s=i[l].to();a.line>=n||(s.line>=n&&(s=r(n,0)),n=a.line,null==o?this.uncomment(a,s,e)?o="un":(this.lineComment(a,s,e),o="line"):"un"==o?this.uncomment(a,s,e):this.lineComment(a,s,e))}}),e.defineExtension("lineComment",function(e,l,a){a||(a=t);var s=this,u=o(s,e),c=s.getLine(e.line);if(null!=c&&(f=e,h=c,!/\bstring\b/.test(s.getTokenTypeAt(r(f.line,0)))||/^[\'\"\`]/.test(h))){var f,h,d=a.lineComment||u.lineComment;if(d){var p=Math.min(0!=l.ch||l.line==e.line?l.line+1:l.line,s.lastLine()+1),g=null==a.padding?" ":a.padding,m=a.commentBlankLines||e.line==l.line;s.operation(function(){if(a.indent){for(var t=null,o=e.line;ou.length)&&(t=u)}for(var o=e.line;of||a.operation(function(){if(0!=l.fullLines){var t=n.test(a.getLine(f));a.replaceRange(h+c,r(f)),a.replaceRange(u+h,r(e.line,0));var o=l.blockCommentLead||s.blockCommentLead;if(null!=o)for(var d=e.line+1;d<=f;++d)(d!=f||t)&&a.replaceRange(o+h,r(d,0))}else a.replaceRange(c,i),a.replaceRange(u,e)})}}else(l.lineComment||s.lineComment)&&0!=l.fullLines&&a.lineComment(e,i,l)}),e.defineExtension("uncomment",function(e,i,l){l||(l=t);var a,s=this,u=o(s,e),c=Math.min(0!=i.ch||i.line==e.line?i.line:i.line-1,s.lastLine()),f=Math.min(e.line,c),h=l.lineComment||u.lineComment,d=[],p=null==l.padding?" ":l.padding;e:if(h){for(var g=f;g<=c;++g){var m=s.getLine(g),v=m.indexOf(h);if(v>-1&&!/comment/.test(s.getTokenTypeAt(r(g,v+1)))&&(v=-1),-1==v&&n.test(m))break e;if(v>-1&&n.test(m.slice(0,v)))break e;d.push(m)}if(s.operation(function(){for(var e=f;e<=c;++e){var t=d[e-f],n=t.indexOf(h),i=n+h.length;n<0||(t.slice(i,i+p.length)==p&&(i+=p.length),a=!0,s.replaceRange("",r(e,n),r(e,i)))}}),a)return!0}var y=l.blockCommentStart||u.blockCommentStart,b=l.blockCommentEnd||u.blockCommentEnd;if(!y||!b)return!1;var x=l.blockCommentLead||u.blockCommentLead,w=s.getLine(f),C=w.indexOf(y);if(-1==C)return!1;var k=c==f?w:s.getLine(c),S=k.indexOf(b,c==f?C+y.length:0),L=r(f,C+1),T=r(c,S+1);if(-1==S||!/comment/.test(s.getTokenTypeAt(L))||!/comment/.test(s.getTokenTypeAt(T))||s.getRange(L,T,"\n").indexOf(b)>-1)return!1;var M=w.lastIndexOf(y,e.ch),A=-1==M?-1:w.slice(0,e.ch).indexOf(b,M+y.length);if(-1!=M&&-1!=A&&A+b.length!=e.ch)return!1;A=k.indexOf(b,i.ch);var O=k.slice(i.ch).lastIndexOf(y,A-i.ch);return M=-1==A||-1==O?-1:i.ch+O,(-1==A||-1==M||M==i.ch)&&(s.operation(function(){s.replaceRange("",r(c,S-(p&&k.slice(S-p.length,S)==p?p.length:0)),r(c,S+b.length));var e=C+y.length;if(p&&w.slice(e,e+p.length)==p&&(e+=p.length),s.replaceRange("",r(f,C),r(f,e)),x)for(var t=f+1;t<=c;++t){var i=s.getLine(t),o=i.indexOf(x);if(-1!=o&&!n.test(i.slice(0,o))){var l=o+x.length;p&&i.slice(l,l+p.length)==p&&(l+=p.length),s.replaceRange("",r(t,o),r(t,l))}}}),!0)})}(CodeMirror),function(e){"use strict";e.defineMode("javascript",function(t,n){var r,i,o=t.indentUnit,l=n.statementIndent,a=n.jsonld,s=n.json||a,u=n.typescript,c=n.wordCharacters||/[\w$\xa1-\uffff]/,f=function(){function e(e){return{type:e,style:"keyword"}}var t=e("keyword a"),n=e("keyword b"),r=e("keyword c"),i=e("keyword d"),o=e("operator"),l={type:"atom",style:"atom"};return{if:e("if"),while:t,with:t,else:n,do:n,try:n,finally:n,return:i,break:i,continue:i,new:e("new"),delete:r,void:r,throw:r,debugger:e("debugger"),var:e("var"),const:e("var"),let:e("var"),function:e("function"),catch:e("catch"),for:e("for"),switch:e("switch"),case:e("case"),default:e("default"),in:o,typeof:o,instanceof:o,true:l,false:l,null:l,undefined:l,NaN:l,Infinity:l,this:e("this"),class:e("class"),super:e("atom"),yield:r,export:e("export"),import:e("import"),extends:r,await:r}}(),h=/[+\-*&%=<>!?|~^@]/,d=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;function p(e,t,n){return r=e,i=n,t}function g(e,t){var n,r=e.next();if('"'==r||"'"==r)return t.tokenize=(n=r,function(e,t){var r,i=!1;if(a&&"@"==e.peek()&&e.match(d))return t.tokenize=g,p("jsonld-keyword","meta");for(;null!=(r=e.next())&&(r!=n||i);)i=!i&&"\\"==r;return i||(t.tokenize=g),p("string","string")}),t.tokenize(e,t);if("."==r&&e.match(/^\d+(?:[eE][+\-]?\d+)?/))return p("number","number");if("."==r&&e.match(".."))return p("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(r))return p(r);if("="==r&&e.eat(">"))return p("=>","operator");if("0"==r&&e.eat(/x/i))return e.eatWhile(/[\da-f]/i),p("number","number");if("0"==r&&e.eat(/o/i))return e.eatWhile(/[0-7]/i),p("number","number");if("0"==r&&e.eat(/b/i))return e.eatWhile(/[01]/i),p("number","number");if(/\d/.test(r))return e.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/),p("number","number");if("/"==r)return e.eat("*")?(t.tokenize=m,m(e,t)):e.eat("/")?(e.skipToEnd(),p("comment","comment")):je(e,t,1)?(function(e){for(var t,n=!1,r=!1;null!=(t=e.next());){if(!n){if("/"==t&&!r)return;"["==t?r=!0:r&&"]"==t&&(r=!1)}n=!n&&"\\"==t}}(e),e.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/),p("regexp","string-2")):(e.eat("="),p("operator","operator",e.current()));if("`"==r)return t.tokenize=v,v(e,t);if("#"==r)return e.skipToEnd(),p("error","error");if(h.test(r))return">"==r&&t.lexical&&">"==t.lexical.type||(e.eat("=")?"!"!=r&&"="!=r||e.eat("="):/[<>*+\-]/.test(r)&&(e.eat(r),">"==r&&e.eat(r))),p("operator","operator",e.current());if(c.test(r)){e.eatWhile(c);var i=e.current();if("."!=t.lastType){if(f.propertyIsEnumerable(i)){var o=f[i];return p(o.type,o.style,i)}if("async"==i&&e.match(/^(\s|\/\*.*?\*\/)*[\(\w]/,!1))return p("async","keyword",i)}return p("variable","variable",i)}}function m(e,t){for(var n,r=!1;n=e.next();){if("/"==n&&r){t.tokenize=g;break}r="*"==n}return p("comment","comment")}function v(e,t){for(var n,r=!1;null!=(n=e.next());){if(!r&&("`"==n||"$"==n&&e.eat("{"))){t.tokenize=g;break}r=!r&&"\\"==n}return p("quasi","string-2",e.current())}var y="([{}])";function b(e,t){t.fatArrowAt&&(t.fatArrowAt=null);var n=e.string.indexOf("=>",e.start);if(!(n<0)){if(u){var r=/:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(e.string.slice(e.start,n));r&&(n=r.index)}for(var i=0,o=!1,l=n-1;l>=0;--l){var a=e.string.charAt(l),s=y.indexOf(a);if(s>=0&&s<3){if(!i){++l;break}if(0==--i){"("==a&&(o=!0);break}}else if(s>=3&&s<6)++i;else if(c.test(a))o=!0;else{if(/["'\/]/.test(a))return;if(o&&!i){++l;break}}}o&&!i&&(t.fatArrowAt=l)}}var x={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,this:!0,"jsonld-keyword":!0};function w(e,t,n,r,i,o){this.indented=e,this.column=t,this.type=n,this.prev=i,this.info=o,null!=r&&(this.align=r)}function C(e,t){for(var n=e.localVars;n;n=n.next)if(n.name==t)return!0;for(var r=e.context;r;r=r.prev)for(var n=r.vars;n;n=n.next)if(n.name==t)return!0}var k={state:null,column:null,marked:null,cc:null};function S(){for(var e=arguments.length-1;e>=0;e--)k.cc.push(arguments[e])}function L(){return S.apply(null,arguments),!0}function T(e){function t(t){for(var n=t;n;n=n.next)if(n.name==e)return!0;return!1}var r=k.state;if(k.marked="def",r.context){if(t(r.localVars))return;r.localVars={name:e,next:r.localVars}}else{if(t(r.globalVars))return;n.globalVars&&(r.globalVars={name:e,next:r.globalVars})}}function M(e){return"public"==e||"private"==e||"protected"==e||"abstract"==e||"readonly"==e}var A={name:"this",next:{name:"arguments"}};function O(){k.state.context={prev:k.state.context,vars:k.state.localVars},k.state.localVars=A}function N(){k.state.localVars=k.state.context.vars,k.state.context=k.state.context.prev}function W(e,t){var n=function(){var n=k.state,r=n.indented;if("stat"==n.lexical.type)r=n.lexical.indented;else for(var i=n.lexical;i&&")"==i.type&&i.align;i=i.prev)r=i.indented;n.lexical=new w(r,k.stream.column(),e,null,n.lexical,t)};return n.lex=!0,n}function D(){var e=k.state;e.lexical.prev&&(")"==e.lexical.type&&(e.indented=e.lexical.indented),e.lexical=e.lexical.prev)}function H(e){return function t(n){return n==e?L():";"==e?S():L(t)}}function E(e,t){return"var"==e?L(W("vardef",t.length),de,H(";"),D):"keyword a"==e?L(W("form"),I,E,D):"keyword b"==e?L(W("form"),E,D):"keyword d"==e?k.stream.match(/^\s*$/,!1)?L():L(W("stat"),R,H(";"),D):"debugger"==e?L(H(";")):"{"==e?L(W("}"),te,D):";"==e?L():"if"==e?("else"==k.state.lexical.info&&k.state.cc[k.state.cc.length-1]==D&&k.state.cc.pop()(),L(W("form"),I,E,D,ye)):"function"==e?L(Se):"for"==e?L(W("form"),be,E,D):"class"==e||u&&"interface"==t?(k.marked="keyword",L(W("form"),Me,D)):"variable"==e?u&&"declare"==t?(k.marked="keyword",L(E)):u&&("module"==t||"enum"==t||"type"==t)&&k.stream.match(/^\s*\w/,!1)?(k.marked="keyword","enum"==t?L(Re):"type"==t?L(oe,H("operator"),oe,H(";")):L(W("form"),pe,H("{"),W("}"),te,D,D)):u&&"namespace"==t?(k.marked="keyword",L(W("form"),P,te,D)):L(W("stat"),Y):"switch"==e?L(W("form"),I,H("{"),W("}","switch"),te,D,D):"case"==e?L(P,H(":")):"default"==e?L(H(":")):"catch"==e?L(W("form"),O,H("("),Le,H(")"),E,D,N):"export"==e?L(W("stat"),We,D):"import"==e?L(W("stat"),He,D):"async"==e?L(E):"@"==t?L(P,E):S(W("stat"),P,H(";"),D)}function P(e,t){return z(e,t,!1)}function F(e,t){return z(e,t,!0)}function I(e){return"("!=e?S():L(W(")"),P,H(")"),D)}function z(e,t,n){if(k.state.fatArrowAt==k.stream.start){var r=n?K:U;if("("==e)return L(O,W(")"),J(Le,")"),D,H("=>"),r,N);if("variable"==e)return S(O,pe,H("=>"),r,N)}var i=n?j:B;return x.hasOwnProperty(e)?L(i):"function"==e?L(Se,i):"class"==e||u&&"interface"==t?(k.marked="keyword",L(W("form"),Te,D)):"keyword c"==e||"async"==e?L(n?F:P):"("==e?L(W(")"),R,H(")"),D,i):"operator"==e||"spread"==e?L(n?F:P):"["==e?L(W("]"),ze,D,i):"{"==e?ee(q,"}",null,i):"quasi"==e?S(V,i):"new"==e?L(function(e){return function(t){return"."==t?L(e?$:X):"variable"==t&&u?L(ce,e?j:B):S(e?F:P)}}(n)):"import"==e?L(P):L()}function R(e){return e.match(/[;\}\)\],]/)?S():S(P)}function B(e,t){return","==e?L(P):j(e,t,!1)}function j(e,t,n){var r=0==n?B:j,i=0==n?P:F;return"=>"==e?L(O,n?K:U,N):"operator"==e?/\+\+|--/.test(t)||u&&"!"==t?L(r):u&&"<"==t&&k.stream.match(/^([^>]|<.*?>)*>\s*\(/,!1)?L(W(">"),J(oe,">"),D,r):"?"==t?L(P,H(":"),i):L(i):"quasi"==e?S(V,r):";"!=e?"("==e?ee(F,")","call",r):"."==e?L(_,r):"["==e?L(W("]"),R,H("]"),D,r):u&&"as"==t?(k.marked="keyword",L(oe,r)):"regexp"==e?(k.state.lastType=k.marked="operator",k.stream.backUp(k.stream.pos-k.stream.start-1),L(i)):void 0:void 0}function V(e,t){return"quasi"!=e?S():"${"!=t.slice(t.length-2)?L(V):L(P,G)}function G(e){if("}"==e)return k.marked="string-2",k.state.tokenize=v,L(V)}function U(e){return b(k.stream,k.state),S("{"==e?E:P)}function K(e){return b(k.stream,k.state),S("{"==e?E:F)}function X(e,t){if("target"==t)return k.marked="keyword",L(B)}function $(e,t){if("target"==t)return k.marked="keyword",L(j)}function Y(e){return":"==e?L(D,E):S(B,H(";"),D)}function _(e){if("variable"==e)return k.marked="property",L()}function q(e,t){if("async"==e)return k.marked="property",L(q);if("variable"==e||"keyword"==k.style){return k.marked="property","get"==t||"set"==t?L(Z):(u&&k.state.fatArrowAt==k.stream.start&&(n=k.stream.match(/^\s*:\s*/,!1))&&(k.state.fatArrowAt=k.stream.pos+n[0].length),L(Q));var n}else{if("number"==e||"string"==e)return k.marked=a?"property":k.style+" property",L(Q);if("jsonld-keyword"==e)return L(Q);if(u&&M(t))return k.marked="keyword",L(q);if("["==e)return L(P,ne,H("]"),Q);if("spread"==e)return L(F,Q);if("*"==t)return k.marked="keyword",L(q);if(":"==e)return S(Q)}}function Z(e){return"variable"!=e?S(Q):(k.marked="property",L(Se))}function Q(e){return":"==e?L(F):"("==e?S(Se):void 0}function J(e,t,n){function r(i,o){if(n?n.indexOf(i)>-1:","==i){var l=k.state.lexical;return"call"==l.info&&(l.pos=(l.pos||0)+1),L(function(n,r){return n==t||r==t?S():S(e)},r)}return i==t||o==t?L():L(H(t))}return function(n,i){return n==t||i==t?L():S(e,r)}}function ee(e,t,n){for(var r=3;r"==e)return L(oe)}function ae(e,t){return"variable"==e||"keyword"==k.style?(k.marked="property",L(ae)):"?"==t?L(ae):":"==e?L(oe):"["==e?L(P,ne,H("]"),ae):void 0}function se(e){return"variable"==e?L(se):":"==e?L(oe):void 0}function ue(e,t){return"<"==t?L(W(">"),J(oe,">"),D,ue):"|"==t||"."==e||"&"==t?L(oe):"["==e?L(H("]"),ue):"extends"==t||"implements"==t?(k.marked="keyword",L(oe)):void 0}function ce(e,t){if("<"==t)return L(W(">"),J(oe,">"),D,ue)}function fe(){return S(oe,he)}function he(e,t){if("="==t)return L(oe)}function de(e,t){return"enum"==t?(k.marked="keyword",L(Re)):S(pe,ne,me,ve)}function pe(e,t){return u&&M(t)?(k.marked="keyword",L(pe)):"variable"==e?(T(t),L()):"spread"==e?L(pe):"["==e?ee(pe,"]"):"{"==e?ee(ge,"}"):void 0}function ge(e,t){return"variable"!=e||k.stream.match(/^\s*:/,!1)?("variable"==e&&(k.marked="property"),"spread"==e?L(pe):"}"==e?S():L(H(":"),pe,me)):(T(t),L(me))}function me(e,t){if("="==t)return L(F)}function ve(e){if(","==e)return L(de)}function ye(e,t){if("keyword b"==e&&"else"==t)return L(W("form","else"),E,D)}function be(e,t){return"await"==t?L(be):"("==e?L(W(")"),xe,H(")"),D):void 0}function xe(e){return"var"==e?L(de,H(";"),Ce):";"==e?L(Ce):"variable"==e?L(we):S(P,H(";"),Ce)}function we(e,t){return"in"==t||"of"==t?(k.marked="keyword",L(P)):L(B,Ce)}function Ce(e,t){return";"==e?L(ke):"in"==t||"of"==t?(k.marked="keyword",L(P)):S(P,H(";"),ke)}function ke(e){")"!=e&&L(P)}function Se(e,t){return"*"==t?(k.marked="keyword",L(Se)):"variable"==e?(T(t),L(Se)):"("==e?L(O,W(")"),J(Le,")"),D,re,E,N):u&&"<"==t?L(W(">"),J(fe,">"),D,Se):void 0}function Le(e,t){return"@"==t&&L(P,Le),"spread"==e?L(Le):u&&M(t)?(k.marked="keyword",L(Le)):S(pe,ne,me)}function Te(e,t){return"variable"==e?Me(e,t):Ae(e,t)}function Me(e,t){if("variable"==e)return T(t),L(Ae)}function Ae(e,t){return"<"==t?L(W(">"),J(fe,">"),D,Ae):"extends"==t||"implements"==t||u&&","==e?("implements"==t&&(k.marked="keyword"),L(u?oe:P,Ae)):"{"==e?L(W("}"),Oe,D):void 0}function Oe(e,t){return"async"==e||"variable"==e&&("static"==t||"get"==t||"set"==t||u&&M(t))&&k.stream.match(/^\s+[\w$\xa1-\uffff]/,!1)?(k.marked="keyword",L(Oe)):"variable"==e||"keyword"==k.style?(k.marked="property",L(u?Ne:Se,Oe)):"["==e?L(P,ne,H("]"),u?Ne:Se,Oe):"*"==t?(k.marked="keyword",L(Oe)):";"==e?L(Oe):"}"==e?L():"@"==t?L(P,Oe):void 0}function Ne(e,t){return"?"==t?L(Ne):":"==e?L(oe,me):"="==t?L(F):S(Se)}function We(e,t){return"*"==t?(k.marked="keyword",L(Ie,H(";"))):"default"==t?(k.marked="keyword",L(P,H(";"))):"{"==e?L(J(De,"}"),Ie,H(";")):S(E)}function De(e,t){return"as"==t?(k.marked="keyword",L(H("variable"))):"variable"==e?S(F,De):void 0}function He(e){return"string"==e?L():"("==e?S(P):S(Ee,Pe,Ie)}function Ee(e,t){return"{"==e?ee(Ee,"}"):("variable"==e&&T(t),"*"==t&&(k.marked="keyword"),L(Fe))}function Pe(e){if(","==e)return L(Ee,Pe)}function Fe(e,t){if("as"==t)return k.marked="keyword",L(Ee)}function Ie(e,t){if("from"==t)return k.marked="keyword",L(P)}function ze(e){return"]"==e?L():S(J(F,"]"))}function Re(){return S(W("form"),pe,H("{"),W("}"),J(Be,"}"),D,D)}function Be(){return S(pe,me)}function je(e,t,n){return t.tokenize==g&&/^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(t.lastType)||"quasi"==t.lastType&&/\{\s*$/.test(e.string.slice(0,e.pos-(n||0)))}return D.lex=!0,{startState:function(e){var t={tokenize:g,lastType:"sof",cc:[],lexical:new w((e||0)-o,0,"block",!1),localVars:n.localVars,context:n.localVars&&{vars:n.localVars},indented:e||0};return n.globalVars&&"object"==typeof n.globalVars&&(t.globalVars=n.globalVars),t},token:function(e,t){if(e.sol()&&(t.lexical.hasOwnProperty("align")||(t.lexical.align=!1),t.indented=e.indentation(),b(e,t)),t.tokenize!=m&&e.eatSpace())return null;var n=t.tokenize(e,t);return"comment"==r?n:(t.lastType="operator"!=r||"++"!=i&&"--"!=i?r:"incdec",function(e,t,n,r,i){var o=e.cc;for(k.state=e,k.stream=i,k.marked=null,k.cc=o,k.style=t,e.lexical.hasOwnProperty("align")||(e.lexical.align=!0);;){var l=o.length?o.pop():s?P:E;if(l(n,r)){for(;o.length&&o[o.length-1].lex;)o.pop()();return k.marked?k.marked:"variable"==n&&C(e,r)?"variable-2":t}}}(t,n,r,i,e))},indent:function(t,r){if(t.tokenize==m)return e.Pass;if(t.tokenize!=g)return 0;var i,a=r&&r.charAt(0),s=t.lexical;if(!/^\s*else\b/.test(r))for(var u=t.cc.length-1;u>=0;--u){var c=t.cc[u];if(c==D)s=s.prev;else if(c!=ye)break}for(;("stat"==s.type||"form"==s.type)&&("}"==a||(i=t.cc[t.cc.length-1])&&(i==B||i==j)&&!/^[,\.=+\-*:?[\(]/.test(r));)s=s.prev;l&&")"==s.type&&"stat"==s.prev.type&&(s=s.prev);var f=s.type,d=a==f;return"vardef"==f?s.indented+("operator"==t.lastType||","==t.lastType?s.info+1:0):"form"==f&&"{"==a?s.indented:"form"==f?s.indented+o:"stat"==f?s.indented+(function(e,t){return"operator"==e.lastType||","==e.lastType||h.test(t.charAt(0))||/[,.]/.test(t.charAt(0))}(t,r)?l||o:0):"switch"!=s.info||d||0==n.doubleIndentSwitch?s.align?s.column+(d?0:1):s.indented+(d?0:o):s.indented+(/^(?:case|default)\b/.test(r)?o:2*o)},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:s?null:"/*",blockCommentEnd:s?null:"*/",blockCommentContinue:s?null:" * ",lineComment:s?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:s?"json":"javascript",jsonldMode:a,jsonMode:s,expressionAllowed:je,skipExpression:function(e){var t=e.cc[e.cc.length-1];t!=P&&t!=F||e.cc.pop()}}}),e.registerHelper("wordChars","javascript",/[\w$]/),e.defineMIME("text/javascript","javascript"),e.defineMIME("text/ecmascript","javascript"),e.defineMIME("application/javascript","javascript"),e.defineMIME("application/x-javascript","javascript"),e.defineMIME("application/ecmascript","javascript"),e.defineMIME("application/json",{name:"javascript",json:!0}),e.defineMIME("application/x-json",{name:"javascript",json:!0}),e.defineMIME("application/ld+json",{name:"javascript",jsonld:!0}),e.defineMIME("text/typescript",{name:"javascript",typescript:!0}),e.defineMIME("application/typescript",{name:"javascript",typescript:!0})}(CodeMirror)}]); \ No newline at end of file diff --git a/_server/CodeMirror/codemirror.css b/_server/CodeMirror/codemirror.css new file mode 100644 index 00000000..c7a8ae70 --- /dev/null +++ b/_server/CodeMirror/codemirror.css @@ -0,0 +1,346 @@ +/* BASICS */ + +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + height: 300px; + color: black; + direction: ltr; +} + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ +} +.CodeMirror pre { + padding: 0 4px; /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; +} +.CodeMirror-linenumbers {} +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; + white-space: nowrap; +} + +.CodeMirror-guttermarker { color: black; } +.CodeMirror-guttermarker-subtle { color: #999; } + +/* CURSOR */ + +.CodeMirror-cursor { + border-left: 1px solid black; + border-right: none; + width: 0; +} +/* Shown when moving in bi-directional text */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} +.cm-fat-cursor .CodeMirror-cursor { + width: auto; + border: 0 !important; + background: #7e7; +} +.cm-fat-cursor div.CodeMirror-cursors { + z-index: 1; +} +.cm-fat-cursor-mark { + background-color: rgba(20, 255, 20, 0.5); + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; +} +.cm-animate-fat-cursor { + width: auto; + border: 0; + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; + background-color: #7e7; +} +@-moz-keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} +@-webkit-keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} +@keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} + +/* Can style cursor different in overwrite (non-insert) mode */ +.CodeMirror-overwrite .CodeMirror-cursor {} + +.cm-tab { display: inline-block; text-decoration: inherit; } + +.CodeMirror-rulers { + position: absolute; + left: 0; right: 0; top: -50px; bottom: -20px; + overflow: hidden; +} +.CodeMirror-ruler { + border-left: 1px solid #ccc; + top: 0; bottom: 0; + position: absolute; +} + +/* DEFAULT THEME */ + +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} +.cm-strikethrough {text-decoration: line-through;} + +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} + +.cm-s-default .cm-error {color: #f00;} +.cm-invalidchar {color: #f00;} + +.CodeMirror-composing { border-bottom: 2px solid; } + +/* Default styles for common addons */ + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} +.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } +.CodeMirror-activeline-background {background: #e8f2ff;} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + position: relative; + overflow: hidden; + background: white; +} + +.CodeMirror-scroll { + overflow: scroll !important; /* Things will break if this is overridden */ + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; +} +.CodeMirror-sizer { + position: relative; + border-right: 30px solid transparent; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actual scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; +} +.CodeMirror-vscrollbar { + right: 0; top: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.CodeMirror-hscrollbar { + bottom: 0; left: 0; + overflow-y: hidden; + overflow-x: scroll; +} +.CodeMirror-scrollbar-filler { + right: 0; bottom: 0; +} +.CodeMirror-gutter-filler { + left: 0; bottom: 0; +} + +.CodeMirror-gutters { + position: absolute; left: 0; top: 0; + min-height: 100%; + z-index: 3; +} +.CodeMirror-gutter { + white-space: normal; + height: 100%; + display: inline-block; + vertical-align: top; + margin-bottom: -30px; +} +.CodeMirror-gutter-wrapper { + position: absolute; + z-index: 4; + background: none !important; + border: none !important; +} +.CodeMirror-gutter-background { + position: absolute; + top: 0; bottom: 0; + z-index: 4; +} +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; +} +.CodeMirror-gutter-wrapper ::selection { background-color: transparent } +.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent } + +.CodeMirror-lines { + cursor: text; + min-height: 1px; /* prevents collapsing before first draw */ +} +.CodeMirror pre { + /* Reset some styles that the rest of the page might have set */ + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; + -webkit-tap-highlight-color: transparent; + -webkit-font-variant-ligatures: contextual; + font-variant-ligatures: contextual; +} +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +.CodeMirror-linebackground { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + position: relative; + z-index: 2; + padding: 0.1px; /* Force widget margins to stay inside of the container */ +} + +.CodeMirror-widget {} + +.CodeMirror-rtl pre { direction: rtl; } + +.CodeMirror-code { + outline: none; +} + +/* Force content-box sizing for the elements where we expect it */ +.CodeMirror-scroll, +.CodeMirror-sizer, +.CodeMirror-gutter, +.CodeMirror-gutters, +.CodeMirror-linenumber { + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +.CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; +} + +.CodeMirror-cursor { + position: absolute; + pointer-events: none; +} +.CodeMirror-measure pre { position: static; } + +div.CodeMirror-cursors { + visibility: hidden; + position: relative; + z-index: 3; +} +div.CodeMirror-dragcursors { + visibility: visible; +} + +.CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; +} + +.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } +.CodeMirror-crosshair { cursor: crosshair; } +.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } +.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } + +.cm-searching { + background-color: #ffa; + background-color: rgba(255, 255, 0, .4); +} + +/* Used to force a border model for a node */ +.cm-force-border { padding-right: .1px; } + +@media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } +} + +/* See issue #2901 */ +.cm-tab-wrap-hack:after { content: ''; } + +/* Help users use markselection to safely style text background */ +span.CodeMirror-selectedtext { background: none; } diff --git a/_server/README.md b/_server/README.md new file mode 100644 index 00000000..4079db9c --- /dev/null +++ b/_server/README.md @@ -0,0 +1,184 @@ +# editor + +本目录下所有文件,以及`../editor.html`和`../启动服务.exe`([源码](http://github.com/ckcz123/mota-js-server/))是地图编辑器的所有组件. + +`editor.js`,`editor_file.js`和`editor_mode.js`耦合较强,`editor_blockly.js`和`editor_multi.js`和`fs.js`基本可以独立使用. + +## 各组件功能 + +### 总体上 + +以`display:none`的形式引入了`index.html`的`dom`,修改了原来的`.gameCanvas #ui #data`等的名字以避免冲突 + +通过`main.init('editor')`加载数据 + +`editor`模式关闭了部分动画 + +`core.drawMap`中`editor`模式下不再画图,而是生成画图的函数提供给`editor` + +`editor`模式下`GlobalAnimate`可以独立的选择是否播放 + +`core.playBgm`和`core.playSound`中非`play`模式不再播放声音 + +`core.show`和`core.hide`中非`play`模式不再进行动画而是立刻完成并执行回调 + +`editor`模式不执行`core.resize` + +### editor.js + +``` js +editor.mapInit();//清空地图 +editor.changeFloor('MT2')//切换地图 +editor.guid()//产生一个可以作为id的长随机字符串 +``` + +`editor.updateMap`中画未定义快的报错 + +### editor_file.js + +提供了以下函数进行楼层`map`数组相关的操作 +```javascript +editor.file.getFloorFileList +editor.file.loadFloorFile +editor.file.saveFloorFile +editor.file.saveFloorFileAs +``` + +编辑模式有关的查询 +```javascript +editor.file.editItem('redJewel',[],function(a){console.log(a)}); +editor.file.editEnemy('redBat',[],function(a){console.log(a)}); +editor.file.editLoc(2,0,[],function(a){console.log(a)}); +editor.file.editFloor([],function(a){console.log(a)}); +editor.file.editTower([],function(a){console.log(a)}); +editor.file.editFunctions([],function(a){console.log(a)}); +``` + +编辑模式有关的编辑 +```javascript +editor.info={images: "terrains", y: 9}; +editor.file.changeIdAndIdnum('yellowWall2',16,editor.info,function(a){console.log(a)}); +editor.file.editItem('book',[["change","['items']['name']","怪物手册的新名字"]],function(a){console.log(a)}); +editor.file.editEnemy('redBat',[['change',"['atk']",20]],function(a){console.log(a)}); +editor.file.editLoc(2,6,[["change","['afterBattle']",null]],function(a){console.log(a)}); +editor.file.editFloor([["change","['title']",'样板 33 层']],function(a){console.log(a)}); +editor.file.editTower([["change","['values']['lavaDamage']",200]],function(a){console.log(a)}); +editor.file.editFunctions(["change","['events']['afterChangeLight']","function(x,y){console.log(x,y)}"],function(a){console.log(a)}); +``` + +### editor_mode.js +生成表格并绑定事件的函数 +```javascript +editor.mode.loc(); +editor.mode.emenyitem(); +editor.mode.floor(); +editor.mode.tower(); +editor.mode.functions(); +``` + +切换模式 +```javascript +editor.mode.onmode('');//清空 +editor.mode.onmode('save');//保存 +editor.mode.onmode('nextChange');//下次onmode时前端进行切换 + +editor.mode.onmode('loc'); +editor.mode.onmode('emenyitem'); +editor.mode.onmode('floor'); +editor.mode.onmode('tower'); +editor.mode.onmode('functions'); +editor.mode.onmode('map'); +editor.mode.onmode('appendpic'); +``` +在`onmode('save')`时,改动才会保存到文件,涉及到图片的改动需要刷新页面使得`editor`能看到 + +表格的`onchange`的实现中,获得当前模式的方式.不注意的话,修改`index.html`中页面的结构,会被坑 +```javascript +var node = thisTr.parentNode; +while (!editor_mode._ids.hasOwnProperty(node.getAttribute('id'))) { + node = node.parentNode; +} +editor_mode.onmode(editor_mode._ids[node.getAttribute('id')]); +``` + +`editor.mode.listen`中提供了追加素材的支持. + +处理注释的特殊指令 +``` +$range(evalstr:thiseval)$end + 限制取值范围,要求修改后的eval(evalstr)为true +$leaf(evalstr:thiseval)$end + 强制指定为叶节点,如果eval(evalstr)为true + +//以下几个中选一个 [ +$select(evalstr)$end + 渲染成 +$textarea(evalstr)$end + 渲染成\n'].join(''); + } +} + +editor_mode.prototype.indent = function(field){ + var num = 4; + if(field.indexOf("['main']")===0)return 0; + if(field.indexOf("['flyRange']")!==-1)return 0; + if(field==="['special']")return 0; + return num; +} + +editor_mode.prototype.addAction = function(action){ + editor_mode.actionList.push(action); +} + +editor_mode.prototype.doActionList = function(mode,actionList){ + if (actionList.length==0)return; + printf('修改中...'); + switch (mode) { + case 'loc': + + editor.file.editLoc(editor_mode.pos.x,editor_mode.pos.y,actionList,function(objs_){/*console.log(objs_);*/if(objs_.slice(-1)[0]!=null){printe(objs_.slice(-1)[0]);throw(objs_.slice(-1)[0])};printf('修改成功')}); + break; + case 'emenyitem': + + if (editor_mode.info.images=='enemys'){ + editor.file.editEnemy(editor_mode.info.id,actionList,function(objs_){/*console.log(objs_);*/if(objs_.slice(-1)[0]!=null){printe(objs_.slice(-1)[0]);throw(objs_.slice(-1)[0])};printf('修改成功')}); + } else if (editor_mode.info.images=='items'){ + editor.file.editItem(editor_mode.info.id,actionList,function(objs_){/*console.log(objs_);*/if(objs_.slice(-1)[0]!=null){printe(objs_.slice(-1)[0]);throw(objs_.slice(-1)[0])};printf('修改成功')}); + } + break; + case 'floor': + + editor.file.editFloor(actionList,function(objs_){/*console.log(objs_);*/if(objs_.slice(-1)[0]!=null){printe(objs_.slice(-1)[0]);throw(objs_.slice(-1)[0])};printf('修改成功')}); + break; + case 'tower': + + editor.file.editTower(actionList,function(objs_){/*console.log(objs_);*/if(objs_.slice(-1)[0]!=null){printe(objs_.slice(-1)[0]);throw(objs_.slice(-1)[0])};printf('修改成功')}); + break; + case 'functions': + + editor.file.editFunctions(actionList,function(objs_){/*console.log(objs_);*/if(objs_.slice(-1)[0]!=null){printe(objs_.slice(-1)[0]);throw(objs_.slice(-1)[0])};printf('修改成功')}); + break; + default: + break; + } +} + +editor_mode.prototype.onmode = function (mode) { + if (editor_mode.mode!=mode) { + console.log('change mode into : '+mode); + if(mode==='save')editor_mode.doActionList(editor_mode.mode,editor_mode.actionList); + if(editor_mode.mode==='nextChange' && mode)editor_mode.showMode(mode); + editor_mode.mode=mode; + editor_mode.actionList=[]; + } +} + +editor_mode.prototype.showMode = function (mode) { + for(var name in this.dom){ + editor_mode.dom[name].style='z-index:-1;opacity: 0;'; + } + editor_mode.dom[mode].style=''; + if(editor_mode[mode])editor_mode[mode](); + document.getElementById('editModeSelect').value=mode; + var tips = tip_in_showMode; + if(!selectBox.isSelected)printf('tips: '+tips[~~(tips.length*Math.random())]); +} + +editor_mode.prototype.loc = function(callback){ + //editor.pos={x: 0, y: 0}; + if (!core.isset(editor.pos))return; + editor_mode.pos=editor.pos; + document.getElementById('pos_a6771a78_a099_417c_828f_0a24851ebfce').innerText=editor_mode.pos.x+','+editor_mode.pos.y; + + var objs=[]; + editor.file.editLoc(editor_mode.pos.x,editor_mode.pos.y,[],function(objs_){objs=objs_;/*console.log(objs_)*/}); + //只查询不修改时,内部实现不是异步的,所以可以这么写 + var tableinfo=editor_mode.objToTable(objs[0],objs[1]); + document.getElementById('table_3d846fc4_7644_44d1_aa04_433d266a73df').innerHTML=tableinfo.HTML; + tableinfo.listen(tableinfo.guids); + + if (Boolean(callback))callback(); +} + +editor_mode.prototype.emenyitem = function(callback){ + //editor.info=editor.ids[editor.indexs[201]]; + if (!core.isset(editor.info))return; + + if(Object.keys(editor.info).length!==0)editor_mode.info=editor.info;//避免editor.info被清空导致无法获得是物品还是怪物 + + if (!core.isset(editor_mode.info.id)){ + document.getElementById('table_a3f03d4c_55b8_4ef6_b362_b345783acd72').innerHTML=''; + document.getElementById('newIdIdnum').style.display=''; + return; + } + document.getElementById('newIdIdnum').style.display='none'; + + var objs=[]; + if (editor_mode.info.images=='enemys'){ + editor.file.editEnemy(editor_mode.info.id,[],function(objs_){objs=objs_;/*console.log(objs_)*/}); + } else if (editor_mode.info.images=='items'){ + editor.file.editItem(editor_mode.info.id,[],function(objs_){objs=objs_;/*console.log(objs_)*/}); + } else { + document.getElementById('table_a3f03d4c_55b8_4ef6_b362_b345783acd72').innerHTML=''; + return; + } + //只查询不修改时,内部实现不是异步的,所以可以这么写 + var tableinfo=editor_mode.objToTable(objs[0],objs[1]); + document.getElementById('table_a3f03d4c_55b8_4ef6_b362_b345783acd72').innerHTML=tableinfo.HTML; + tableinfo.listen(tableinfo.guids); + + if (Boolean(callback))callback(); +} + +editor_mode.prototype.floor = function(callback){ + var objs=[]; + editor.file.editFloor([],function(objs_){objs=objs_;/*console.log(objs_)*/}); + //只查询不修改时,内部实现不是异步的,所以可以这么写 + var tableinfo=editor_mode.objToTable(objs[0],objs[1]); + document.getElementById('table_4a3b1b09_b2fb_4bdf_b9ab_9f4cdac14c74').innerHTML=tableinfo.HTML; + tableinfo.listen(tableinfo.guids); + if (Boolean(callback))callback(); +} + +editor_mode.prototype.tower = function(callback){ + var objs=[]; + editor.file.editTower([],function(objs_){objs=objs_;/*console.log(objs_)*/}); + //只查询不修改时,内部实现不是异步的,所以可以这么写 + var tableinfo=editor_mode.objToTable(objs[0],objs[1]); + document.getElementById('table_b6a03e4c_5968_4633_ac40_0dfdd2c9cde5').innerHTML=tableinfo.HTML; + tableinfo.listen(tableinfo.guids); + if (Boolean(callback))callback(); +} + +editor_mode.prototype.functions = function(callback){ + var objs=[]; + editor.file.editFunctions([],function(objs_){objs=objs_;/*console.log(objs_)*/}); + //只查询不修改时,内部实现不是异步的,所以可以这么写 + var tableinfo=editor_mode.objToTable(objs[0],objs[1]); + document.getElementById('table_e260a2be_5690_476a_b04e_dacddede78b3').innerHTML=tableinfo.HTML; + tableinfo.listen(tableinfo.guids); + if (Boolean(callback))callback(); +} + +///////////////////////////////////////////////////////////////////////////// + +editor_mode.prototype.listen = function(callback){ + + var newIdIdnum = document.getElementById('newIdIdnum'); + newIdIdnum.children[2].onclick = function(){ + if (newIdIdnum.children[0].value && newIdIdnum.children[1].value){ + var id = newIdIdnum.children[0].value; + var idnum = parseInt(newIdIdnum.children[1].value); + editor.file.changeIdAndIdnum(id,idnum,editor_mode.info,function(err){ + if(err){printe(err);throw(err)} + printe('添加id的idnum成功,请F5刷新编辑器'); + }); + } else { + printe('请输入id和idnum'); + } + } + + var selectFloor = document.getElementById('selectFloor'); + editor.file.getFloorFileList(function(floors){ + var outstr=[]; + floors[0].forEach(function(floor){ + outstr.push(["\n'].join('')); + }); + selectFloor.innerHTML=outstr.join(''); + selectFloor.value=core.status.floorId; + selectFloor.onchange = function(){ + editor_mode.onmode('nextChange'); + editor_mode.onmode('floor'); + editor.changeFloor(selectFloor.value); + } + }); + + var saveFloor = document.getElementById('saveFloor'); + saveFloor.onclick = function(){ + editor_mode.onmode(''); + editor.file.saveFloorFile(function(err){if(err){printe(err);throw(err)};printf('保存成功');}); + } + + var saveFloorAs = document.getElementById('saveFloorAs'); + var saveAsName = document.getElementById('saveAsName'); + saveFloorAs.onclick = function(){ + if (!saveAsName.value)return; + editor_mode.onmode(''); + editor.file.saveFloorFileAs(saveAsName.value,function(err){ + if(err){printe(err);throw(err)} + core.floorIds.push(saveAsName.value); + editor.file.editTower([['change',"['main']['floorIds']",core.floorIds]],function(objs_){/*console.log(objs_);*/if(objs_.slice(-1)[0]!=null){printe(objs_.slice(-1)[0]);throw(objs_.slice(-1)[0])};printe('另存为成功,请F5刷新编辑器生效');}); + }); + } + + var ratio=1; + var appendPicCanvas = document.getElementById('appendPicCanvas'); + var bg = appendPicCanvas.children[0]; + var source = appendPicCanvas.children[1]; + var picClick = appendPicCanvas.children[2]; + var sprite = appendPicCanvas.children[3]; + var appendPicSelection = document.getElementById('appendPicSelection'); + + var selectAppend = document.getElementById('selectAppend'); + var selectAppend_str=[]; + ["terrains", "animates", "enemys", "enemy48", "items", "npcs", "npc48"].forEach(function(image){ + selectAppend_str.push(["\n'].join('')); + }); + selectAppend.innerHTML=selectAppend_str.join(''); + selectAppend.onchange = function(){ + var value = selectAppend.value; + var ysize = selectAppend.value.indexOf('48')===-1?32:48; + editor_mode.appendPic.imageName = value; + var img = editor.material.images[value]; + editor_mode.appendPic.toImg = img; + var num = ~~img.width/32; + editor_mode.appendPic.num = num; + editor_mode.appendPic.index = 0; + var selectStr = ''; + for(var ii=0;ii=num)editor_mode.appendPic.index=ii+1-num; + else editor_mode.appendPic.index++; + editor_mode.appendPic.selectPos[ii]=pos; + appendPicSelection.children[ii].style=[ + 'left:',pos.x*32,'px;', + 'top:',pos.y*pos.ysize,'px;', + 'height:',pos.ysize-6,'px;' + ].join(''); + } + + var appendConfirm = document.getElementById('appendConfirm'); + appendConfirm.onclick = function(){ + var ysize = selectAppend.value.indexOf('48')===-1?32:48; + var sprited = sprite.getContext('2d'); + //sprited.drawImage(img, 0, 0); + var height = editor_mode.appendPic.toImg.height; + var sourced = source.getContext('2d'); + for(var ii=0,v;v=editor_mode.appendPic.selectPos[ii];ii++){ + var imgData=sourced.getImageData(v.x*32,v.y*ysize,32,ysize); + sprited.putImageData(imgData,ii*32,height); + } + var imgbase64 = sprite.toDataURL().split(',')[1]; + fs.writeFile('./project/images/'+editor_mode.appendPic.imageName+'.png',imgbase64,'base64',function(err,data){ + if(err){printe(err);throw(err)} + printe('追加素材成功,请F5刷新编辑器'); + }); + } + + var editModeSelect = document.getElementById('editModeSelect'); + editModeSelect.onchange = function(){ + editor_mode.onmode('nextChange'); + editor_mode.onmode(editModeSelect.value); + } + + if (Boolean(callback))callback(); +} + +var editor_mode = new editor_mode(); +editor_mode.init_dom_ids(); + +return editor_mode; +} +//editor_mode = editor_mode(editor); \ No newline at end of file diff --git a/_server/editor_multi.js b/_server/editor_multi.js new file mode 100644 index 00000000..3d6100a0 --- /dev/null +++ b/_server/editor_multi.js @@ -0,0 +1,104 @@ +editor_multi = function(){ + +var editor_multi = {}; + +var codeEditor = CodeMirror.fromTextArea(document.getElementById("multiLineCode"), { + lineNumbers: true, + matchBrackets: true, + lineWrapping: true, + continueComments: "Enter", + extraKeys: {"Ctrl-Q": "toggleComment"} +}); + +editor_multi.id=''; +editor_multi.isString=false; + +editor_multi.show = function(){document.getElementById('left7').style='';} +editor_multi.hide = function(){document.getElementById('left7').style='z-index:-1;opacity: 0;';} + +editor_multi.indent = function(field){ + if(editor && editor.mode && editor.mode.indent)return editor.mode.indent(field); + return 4; +} + +editor_multi.import = function(id_){ + var thisTr = document.getElementById(id_); + if(!thisTr)return false; + var input = thisTr.children[2].children[0].children[0]; + var field = thisTr.children[0].getAttribute('title'); + if(!input.type || input.type!=='textarea')return false; + editor_multi.id=id_; + editor_multi.isString=false; + if(input.value.slice(0,1)==='"'){ + editor_multi.isString=true; + codeEditor.setValue(JSON.parse(input.value)||''); + } else { + var num = editor_multi.indent(field); + eval('var tobj='+(input.value||'null')); + var tmap={}; + var tstr = JSON.stringify(tobj,function(k,v){if(typeof(v)===typeof('') && v.slice(0,8)==='function'){var id_ = editor.guid();tmap[id_]=v.toString();return id_;}else return v},num); + for(var id_ in tmap){ + tstr = tstr.replace('"'+id_+'"',tmap[id_]) + } + codeEditor.setValue(tstr||''); + } + editor_multi.show(); + return true; +} + +editor_multi.cancel = function(){ + editor_multi.hide(); + editor_multi.id=''; + multiLineArgs=[null,null,null]; +} + +editor_multi.confirm = function (){ + if(!editor_multi.id){ + editor_multi.id=''; + return; + } + if(editor_multi.id==='callFromBlockly'){ + editor_multi.id=''; + editor_multi.multiLineDone(); + return; + } + var setvalue = function(value){ + var thisTr = document.getElementById(editor_multi.id); + editor_multi.id=''; + var input = thisTr.children[2].children[0].children[0]; + if(editor_multi.isString){ + input.value = JSON.stringify(value); + } else { + eval('var tobj='+(value||'null')); + var tmap={}; + var tstr = JSON.stringify(tobj,function(k,v){if(v instanceof Function){var id_ = editor.guid();tmap[id_]=v.toString();return id_;}else return v},4); + for(var id_ in tmap){ + tstr = tstr.replace('"'+id_+'"',JSON.stringify(tmap[id_])) + } + input.value = tstr; + } + editor_multi.hide(); + input.onchange(); + } + setvalue(codeEditor.getValue()||''); +} + +var multiLineArgs=[null,null,null]; +editor_multi.multiLineEdit = function(value,b,f,callback){ + editor_multi.id='callFromBlockly'; + codeEditor.setValue(value.split('\\n').join('\n')||''); + multiLineArgs[0]=b; + multiLineArgs[1]=f; + multiLineArgs[2]=callback; + editor_multi.show(); +} +editor_multi.multiLineDone = function(){ + editor_multi.hide(); + if(!multiLineArgs[0] || !multiLineArgs[1] || !multiLineArgs[2])return; + var newvalue = codeEditor.getValue()||''; + multiLineArgs[2](newvalue,multiLineArgs[0],multiLineArgs[1]) +} + +return editor_multi; +} +//editor_multi=editor_multi(); \ No newline at end of file diff --git a/_server/vm.js b/_server/vm.js index d23e1c91..a9dc2a6c 100644 --- a/_server/vm.js +++ b/_server/vm.js @@ -1,5 +1,26 @@ // vue 相关处理 +document.body.onmousedown = function(e){ + //console.log(e); + var eid=[]; + e.path.forEach(function(node){ + if(!node.getAttribute)return; + var id_ = node.getAttribute('id'); + if (id_){ + if(['left','left1','left2','left3','left4','left5','left8'].indexOf(id_)!==-1)eid.push('edit'); + eid.push(id_); + } + }); + //console.log(eid); + if(eid.indexOf('edit')===-1){ + if(eid.indexOf('tip')===-1)selectBox.isSelected = false; + } + //editor.mode.onmode(''); + editor.info = {}; +} +iconLib.onmousedown = function(e){ + e.stopPropagation(); +} var exportM = new Vue({ el: '#exportM', data: { @@ -166,6 +187,7 @@ var clear = new Vue({ methods: { clearMap: function(){ editor.mapInit(); + editor.updateMap(); clearTimeout(editArea.formatTimer); clearTimeout(tip.timer); pout.value = ''; @@ -175,6 +197,30 @@ var clear = new Vue({ } } }) +printf = function(str_,type) { + selectBox.isSelected = false; + if(!type){ + tip.whichShow=11; + } else { + tip.whichShow=12; + } + setTimeout(function(){ + if(!type){ + tip.msgs[11]=String(str_); + tip.whichShow=12; + } else { + tip.msgs[10]=String(str_); + tip.whichShow=11; + } + },1); +} +printe = function(str_){printf(str_,'error')} +tip_in_showMode = [ + '涉及图片的更改需要F5刷新浏览器来生效', + '文本域可以通过双击,在文本编辑器或事件编辑器中编辑', + '事件编辑器中的显示文本和自定义脚本的方块也可以双击', + "画出的地图要点击\"保存地图\"才会写入到文件中", +]; var tip = new Vue({ el: '#tip', data: { @@ -196,6 +242,8 @@ var tip = new Vue({ "修改成功!可点击复制按钮复制地图数组到剪切板", "选择背景图片失败!文件名格式错误或图片不存在!", "更新背景图片成功!", + "11:警告", + "12:成功" ], mapMsg: '', whichShow: 0, diff --git a/docs/V2.0.md b/docs/V2.0.md new file mode 100644 index 00000000..66fa428e --- /dev/null +++ b/docs/V2.0.md @@ -0,0 +1,89 @@ +# V2.0版本介绍 + +?> 目前版本**v2.0**,上次更新时间:* {docsify-updated} * + +目前样板已经更新到V2.0版本,本章将对V2.0的一些内容进行介绍。 + +请确保已经看过前面的几个文档(2.0都有部分更新),前面已经描述过的东西这里将不再赘述。 + +也欢迎通过看B站的视频教程来具体了解2.0版本的使用方法。 + +## 目录结构的改变 + +在1.x中,所有数据和逻辑都是一体的,例如怪物数据和怪物伤害计算公式等等。这导致样板的版本更新时会十分不便。 + +在2.0中,我们将数据和逻辑进行了分离,拆分成了libs和project两个目录。 + +- libs目录为游戏核心库文件,包括一些游戏逻辑等内容 +- project目录为针对每个塔的目录,是和游戏逻辑是分离的。 + +我们只需要修改project目录下的各项内容,而无需去动libs目录(有特殊需求除外); +将来如果想把塔迁移到新的版本上,也只需要迁移project即可。 + +另外一点的就是,我们将libs目录中的core.js进行了拆分,从而使每个文件的具体工作更加一目了然,也避免了接近6K行的大文件会导致打开IDE的卡顿问题。 + +## 全GUI造塔 + +在1.X版本中,我们提供了一个地图编辑器。但是它的功能十分弱,只能进行绘图的功能,实际的各项操作还是需要通过VSCode打开js文件实际进行编写代码。 + +但是在2.0中,我们大大拓展了地图编辑器的功能,从而达到了“全GUI造塔”的功能,用户再也不用手动打开任何一个文件进行编辑了。 + +GUI界面分为`地图编辑器`,`事件编辑器`和`文本编辑器`。 + +!> 即使现在可以全GUI造塔,也强烈建议对1.X的造塔方式进行了解,因为这是一切的基础。 + +### 地图编辑器 + +地图编辑器分为三个区域,左侧的`编辑区`,中间的`画布区`,右侧的`素材区`。 + +画布区下方有切换地图和编辑器模式的下拉菜单,点击`保存地图`后画布的内容才会真正写入到js文件中。 + +在素材区点击图块时,会选中该图块,此时tips会显示该图块的信息,编辑区会进入图块属性模式,怪物或物品可以直接在里面编辑数值。如果图块的数字和ID没有被定义,则可以直接在左侧定义,**定义新图块后需要保存并刷新页面后才能生效**。 + +在tips中有图块信息时,在画布上点击或拖拽可以把图块画上去,可以使用ctrl+Z撤销操作以及对应的ctrl+Y恢复撤销。擦除方块可以使用素材区最左上角的擦除块。 + +点击界面中的空白,tips中的图块信息会被清空,此时再点击画布上的点,则编辑器会进入地图选点模式。此模式下可以编辑改点的`events`,`afterBattle`,`changeFloor`等事件或者是`canMove`来改变各方向的通行状态。 + +切换地图会使编辑区进入楼层属性模式,这里可以修改首次到达该楼层时会触发的事件`firstArrive`,楼层显示的名称,默认的前景背景图片,默认天气和色调等等。 + +!> 这里不允许编辑楼层的ID,需要修改ID的场合请直接改js文件,并保持三个标识符完全一致。`data.js`中的`floorIds`也需要对应进行修改。 + +全塔属性中编辑整个塔为单位的属性,例如起始剧情`startText`,`name`,提供哪些难度,主角的起始属性,全局商店,各种数值以及系统FLAG等。**创建新塔时需要认真编辑这里面的所有选项。** + +脚本编辑模式可以修改常用的需要更改的函数。例如,给不同的难度设置不同的内容`setInitData`,加点`addPoint`,以及修改游戏中的关于界面`drawAbout`等等。 + +追加素材模式可以导入一个图片到该标签的画板中,然后依次点击画板中的图块,点追加就可以按顺序把这些图片添加到对应的画布区素材的最下方,**需要刷新来生效**。 + +地图编辑模式中可以导入来自地图生成器的地图数组,同时创建新楼层需要在这里通过另存为来实现,可以点清除地图把另存为出的新楼层清空。 + +!> 编辑区的表格可以直接修改,推荐通过双击,在事件编辑器和文本编辑器中进行编辑。编辑区中的修改需要点保存才会生效。 + +### 事件编辑器 + +地图选点中的事件类表格,以及楼层属性中的`firstArrive`和全塔属性的`startText`,在双击时会进入事件编辑器,是由[antlr-blockly](https://github.com/zhaouv/antlr-blockly)生成的图块式的可视化编辑器. + +把左侧的方块拖到面板中,下方就会实时的显示对应的js的代码(以及数值不正确时的提示). + +每个方块点击右键会展开一个菜单,点帮助可以跳转到此文档中对应的内容。利用好复制功能可以极大提高编辑的效率。注释选项请不要使用,编辑器并不会保留这里的注释。 + +`template`中提供了一些模板事件,例如战前剧情,打怪开门。 + +`显示文章`的两个方块,以及`自动剧情文本`,`选项`和`自定义JS脚本`这5个方块,可以通过双击在文本编辑器中(以多行的方式)编辑其中的文字。 + +### 文本编辑器 + +事件编辑器之外的内容双击后由文本编辑器来编辑,是有js高亮支持的多行文本编辑器[CodeMirror](https://github.com/codemirror/CodeMirror),点confirm即可使编辑的文本替换到表格中。 + +### 拓展地图编辑器 + +> 面向有一定编程基础的用户 + +修改`project/`下的`*comment.js`可以让地图编辑器对自己添加的属性有更好的支持.例如: ++ 给`comment.js`中`enemys`加入新的键值对,就可以更方便的给怪物在UI界面中添加对应的值. ++ 在`data.comment.js`中把自己添加的内容标记为叶节点,不再在表格中展开到最末端. + +地图编辑器的部分API见`_server/README.md` + +## 部分事件和API更新 + +在2.0中,有部分的事件和API存在更新,也增加了包括48x32素材的支持,在这里将不再赘述,请仔细阅读前面的几个文档进行了解。 diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 039c2ea0..a7960592 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -3,4 +3,5 @@ - [元件说明](element) - [事件](event) - [个性化](personalization) +- [V2.0版本介绍](V2.0) - [附录:API列表](api) diff --git a/docs/element.md b/docs/element.md index d66b2c41..299c00a6 100644 --- a/docs/element.md +++ b/docs/element.md @@ -1,6 +1,6 @@ # 元件说明 -?> 目前版本**v1.4.1**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.0**,上次更新时间:* {docsify-updated} * 在本章中,将对样板里的各个元件进行说明。各个元件主要包括道具、门、怪物、楼梯等等。 @@ -37,7 +37,7 @@ 怪物可以有特殊属性,每个怪物可以有多个自定义属性。 -怪物的特殊属性所对应的数字(special)在下面的`getSpecialText`中定义,请勿对已有的属性进行修改。 +怪物的特殊属性所对应的数字(special)在`libs/enemys.js`中的`getSpecialText`中定义,请勿对已有的属性进行修改。 ``` js enemys.prototype.getSpecialText = function (enemyId) { @@ -66,6 +66,8 @@ enemys.prototype.getSpecialText = function (enemyId) { if (this.hasSpecial(special, 19)) text.push("自爆"); if (this.hasSpecial(special, 20)) text.push("无敌"); if (this.hasSpecial(special, 21)) text.push("退化"); + if (this.hasSpecial(special, 22)) text.push("固伤"); + if (this.hasSpecial(special, 23)) text.push("重生"); return text.join(" "); } ``` @@ -125,6 +127,8 @@ N连击怪物的special是6,且我们可以为它定义n代表实际连击数 ![怪物退化](./img/tuihua.png) +固伤怪则需要在后面增加`damage`选项,代表战前扣血数值。 + 如有额外需求,可参见[自定义怪物属性](personalization#自定义自定义怪物属性),里面讲了如何设置一个新的怪物属性。 ## 路障,楼梯,传送门 @@ -153,10 +157,10 @@ floorId指定的是目标楼层的唯一标识符(ID)。 现在我们的H5魔塔支持播放动画,也支持天气系统了。 -要播放动画,你需要先使用“RM动画导出器”将动画导出,放在animates目录下,然后在main.js中定义。 +要播放动画,你需要先使用“RM动画导出器”将动画导出,放在animates目录下,然后再data.js中定义。 ``` js -this.animates = [// 在此存放所有可能使用的动画,必须是animate格式,在这里不写后缀名 +"animates": [// 在此存放所有可能使用的动画,必须是animate格式,在这里不写后缀名 // 动画必须放在animates目录下;文件名不能使用中文,不能带空格或特殊字符 "hand", "sword", "zone", "yongchang", "thunder" // 根据需求自行添加 ] @@ -164,8 +168,6 @@ this.animates = [// 在此存放所有可能使用的动画,必须是animate !> 动画必须是animate格式,名称不能使用中文,不能带空格或特殊字符。 -目前暂时不支持带旋转和翻转的帧。 - 导出动画时可能会进行一些压缩以节省流量,因此清晰度可能不如原版。 动画播放时,是按照每秒20帧的速度(即50ms/帧)。 @@ -192,13 +194,13 @@ this.animates = [// 在此存放所有可能使用的动画,必须是animate 要播放音乐和音效,你需要将对应的文件放在sounds目录下,然后在main.js中进行定义 ``` js -this.bgms = [ // 在此存放所有的bgm,和文件名一致。第一项为默认播放项 +"bgms": [ // 在此存放所有的bgm,和文件名一致。第一项为默认播放项 // 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 - '058-Slow01.mid', 'bgm.mp3', 'qianjin.mid', 'star.mid' + 'bgm.mp3', 'qianjin.mid', 'star.mid', ]; -this.sounds = [ // 在此存放所有的SE,和文件名一致 +"sounds": [ // 在此存放所有的SE,和文件名一致 // 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 - 'floor.mp3', 'attack.ogg', 'door.ogg', 'item.ogg' + 'floor.mp3', 'attack.ogg', 'door.ogg', 'item.ogg', 'zone.ogg' ] ``` @@ -245,7 +247,7 @@ this.sounds = [ // 在此存放所有的SE,和文件名一致 - **[ESC]** 打开/关闭系统菜单 - **[H]** 打开帮助页面 - **[Z]** 转向 -- **[R]** 回退 +- **[R]** 回放录像 - **[SPACE]** 轻按(仅在轻按开关打开时有效) - **[1]** 快捷使用破墙镐 - **[2]** 快捷使用炸弹/圣锤 diff --git a/docs/event.md b/docs/event.md index 879ac5d1..f661e1d3 100644 --- a/docs/event.md +++ b/docs/event.md @@ -1,6 +1,6 @@ # 事件 -?> 目前版本**v1.4.1**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.0**,上次更新时间:* {docsify-updated} * 本章内将对样板所支持的事件进行介绍。 @@ -20,6 +20,13 @@ 在事件列表中使用`type: show`和`type: hide`可以将一个禁用事件启用,或将一个启用事件给禁用。 +## 关于V2.0的重要说明 + +在V2.0版本中,所有事件均可以使用blockly来进行块的可视化编辑。 + +它能通过拖动、复制粘贴等方式帮助你快速生成事件列表,而不用手动打大量字符。 + +但是,仍然强烈建议要对每个事件的写法进行了解。 ## 自定义事件 @@ -615,13 +622,13 @@ loc可忽略,如果忽略则显示为事件当前点。 ``` js "x,y": [ // 实际执行的事件列表 - {"type": "showImage", "name": "bg", "loc": [231,297]}, // 在(231,297)显示bg.png - {"type": "showImage", "name": "1", "loc": [109,167]}, // 在(109,167)显示1.png + {"type": "showImage", "name": "bg.jpg", "loc": [231,297]}, // 在(231,297)显示bg.jpg + {"type": "showImage", "name": "1.png", "loc": [109,167]}, // 在(109,167)显示1.png {"type": "showImage"} // 如果不指定name则清除所有图片。 ] ``` -name为图片名。**请确保图片在main.js中的this.pngs中被定义过。** +name为图片名。**请确保图片在data.js中的images中被定义过。** loc为图片左上角坐标,以像素为单位进行计算。 @@ -769,10 +776,12 @@ move完毕后移动的NPC/怪物一定会消失,只不过可以通过immediate ### win: 获得胜利 -`{"type": "win", "reason": "xxx"}` 将会直接调用events.js中的win函数,并将reason作为参数传入。 +`{"type": "win", "reason": "xxx"}` 将会直接调用events.js中的win函数,并将reason作为结局传入。 该事件会显示获胜页面,并重新游戏。 +!> 如果`reason`不为空,则会以reason作为获胜的结局! + ### lose: 游戏失败 `{"type": "lose", "reason": "xxx"}` 将会直接调用`events.js`中的lose函数,并将reason作为参数传入。 @@ -1059,19 +1068,24 @@ core.insertAction(list) //往当前事件列表中插入一系列事件。使用 打败怪物后可以进行加点。 -如果要对某个怪物进行加点操作,则首先需要修改该怪物的点数值,即在怪物定义的后面添加`point`,代表怪物本身的加点数值。 +要启用加点,首先需要在`data.js`中将`enableAddPoint`置为true。 + +如果要对某个怪物进行加点操作,则首先需要修改该怪物的`point`数值,代表怪物本身的加点数值。 ``` js -... 'def': 0, 'money': 1, 'experience': 1, 'special': 0, 'point': 1}, // 在怪物后面添加point代表怪物的加点数 +... 'def': 0, 'money': 1, 'experience': 1, 'point': 1, 'special': 0}, // 在怪物后面添加point代表怪物的加点数 ``` -然后在`events.js`文件中找到`addPoint`函数。它将返回一个choices事件。修改此函数为我们需要的加点项即可。 +然后在`functions.js`文件中找到`addPoint`函数。它将返回一个choices事件。修改此函数为我们需要的加点项即可。 + +!> V2.0版本可以直接在“脚本编辑 - 加点事件”中双击进行修改! ``` js -////// 加点 ////// -events.prototype.addPoint = function (enemy) { - var point = enemy.point; // 获得该怪物的point - if (!core.isset(point) || point<=0) return []; +////// 加点事件 ////// +"addPoint" : function (enemy) { + // 加点事件 + var point = enemy.point; + if (!core.flags.enableAddPoint || !core.isset(point) || point<=0) return []; // 加点,返回一个choices事件 return [ @@ -1230,11 +1244,13 @@ events.prototype.addPoint = function (enemy) { 上面的afterBattle事件只对和怪物进行战斗后才有会被处理。 -如果我们想在使用炸弹后也能触发一些事件(如开门),则可以在`events.js`里面的`afterUseBomb`函数进行处理: +如果我们想在使用炸弹后也能触发一些事件(如开门),则可以在`functions.js`里面的`afterUseBomb`函数进行处理: + +!> V2.0版本可以直接在“脚本编辑 - 使用炸弹后的事件”中双击进行修改! ``` js ////// 使用炸弹/圣锤后的事件 ////// -events.prototype.afterUseBomb = function () { +"afterUseBomb": function () { // 这是一个使用炸弹也能开门的例子 if (core.status.floorId=='xxx' && core.terrainExists(x0,y0,'specialDoor') // 某个楼层,该机关门存在 && !core.enemyExists(x1,y1) && !core.enemyExists(x2,y2)) // 且守门的怪物都不存在 @@ -1262,11 +1278,11 @@ events.prototype.afterUseBomb = function () { !> 推箱子的前方不允许存在任何事件(花除外),包括已经禁用的自定义事件。 -推完箱子后将触发events.js中的afterPushBox事件,你可以在这里进行开门判断。 +推完箱子后将触发functions.js中的afterPushBox事件,你可以在这里进行开门判断。 ``` js ////// 推箱子后的事件 ////// -events.prototype.afterPushBox = function () { +"afterPushBox" = function () { var noBoxLeft = function () { // 地图上是否还存在未推到的箱子,如果不存在则返回true,存在则返回false @@ -1290,6 +1306,33 @@ events.prototype.afterPushBox = function () { } ``` +## 怪物数据的动态修改 + +有时候我们可能还需要在游戏过程中动态修改怪物数据,例如50层魔塔的封印魔王,或者根据难度分歧来调整最终Boss的属性数据。 + +而在我们的存档中,是不会对怪物数据进行存储的,只会存各个变量和Flag,因此我们需要在读档后根据变量或Flag来调整怪物数据。 + +我们可以在functions.js中的`afterLoadData`进行处理。 + +``` js +////// 读档事件后,载入事件前,可以执行的操作 ////// +"afterLoadData" : function(data) { + // 读档事件后,载入事件前,可以执行的操作 + if (core.hasFlag("fengyin")) { // 如果存在封印(flag为真) + core.material.enemys.blackKing.hp/=10; // 将怪物的血量变成原来的十分之一 + // ... + } + // 同样难度分歧可以类似写 if (core.getFlag('hard', 0)==3) {... +} + +// 在封印时,可以调用setValue将该flag置为真,然后调用自定义脚本 core.afterLoadData() 即可。 +"x,y": [ // 封印 + {"type": "setValue", "name": "flag:fengyin", "value": "true"}, + {"type": "function", "function": function() { + core.afterLoadData(); + }} +] +``` ## 战前剧情 @@ -1361,7 +1404,7 @@ events.prototype.afterPushBox = function () { ``` js ////// 不同难度分别设置初始属性 ////// -events.prototype.setInitData = function (hard) { +"setInitData": function (hard) { if (hard=='Easy') { // 简单难度 core.setFlag('hard', 1); // 可以用flag:hard来获得当前难度 // 可以在此设置一些初始福利,比如设置初始生命值可以调用: @@ -1386,7 +1429,7 @@ events.prototype.setInitData = function (hard) { ``` js ////// 游戏获胜事件 ////// -events.prototype.win = function(reason) { +"win": function(reason) { core.ui.closePanel(); var replaying = core.status.replay.replaying; core.stopReplay(); @@ -1396,19 +1439,21 @@ events.prototype.win = function(reason) { core.drawText([ "\t[恭喜通关]你的分数是${status:hp}。" ], function () { - core.events.gameOver('', replaying); + core.events.gameOver(reason||'', replaying); }) }); } ``` -其参数reason为获胜原因(即type:win事件里面的reason参数)。你可以在这里修改自己的获胜界面显示的文字。 +其参数reason为获胜原因(即type:win事件里面的reason参数)。 + +!> 如果reason不为空,则将会作为结局名! 当失败(`{"type": "lose"}`,或者被怪强制战斗打死、被领域怪扣血死、中毒导致扣血死,路障导致扣血死等等)事件发生时,将调用`events.js`中的`lose`事件。其直接显示一段文字,并重新开始游戏。 ``` js ////// 游戏失败事件 ////// -events.prototype.lose = function(reason) { +"lose": function(reason) { core.ui.closePanel(); var replaying = core.status.replay.replaying; core.stopReplay(); @@ -1424,26 +1469,6 @@ events.prototype.lose = function(reason) { 其参数reason为失败原因。你可以在这里修改失败界面时显示的文字。 -如果要设置多种不同的结局,只需要在win的传参中把`core.events.gameOver('', replaying);`的空字符串改成具体的结局名。 - -例如: - -``` js -events.prototype.win = function(reason) { // 传入参数"reason"为结局名 -// ... 上略 - ], function () { - core.events.gameOver(reason, replaying); // 使用reason作为结局名 - }) - }); -} - -// 然后在事件可以调用 -{"type": "win", "reason": "TRUE END"}, // TE结局 -{"type": "win", "reason": "NORMAL END"} // NE结局 -``` - -上面这个例子中,我们直接把reason作为结局名的参数传入gameOver函数,这样的话就可以直接在{"type": "win"}中加上"reason"代表具体的结局。 - ========================================================================================== [继续阅读下一章:个性化](personalization) diff --git a/docs/img/floordata.png b/docs/img/floordata.png index 64db97de..ed28b628 100644 Binary files a/docs/img/floordata.png and b/docs/img/floordata.png differ diff --git a/docs/img/server.png b/docs/img/server.png index 878f6d47..eb905427 100644 Binary files a/docs/img/server.png and b/docs/img/server.png differ diff --git a/docs/personalization.md b/docs/personalization.md index 1f4fbd0b..3e6fa458 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -1,18 +1,37 @@ # 个性化 -?> 目前版本**v1.4.1**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.0**,上次更新时间:* {docsify-updated} * 有时候只靠样板本身可能是不够的。我们需要一些个性化、自定义的素材,道具效果,怪物属性,等等。 +## 图层的说明 + +HTML5魔塔是使用画布(canvas)来绘制,存在若干个图层,它们之间有一个覆盖关系,后面的图层将覆盖前面的图层。 + +所有图层从低往高依次如下: + +- bg:背景层;绘制地面素材,或者作为背景的图片素材 +- event:事件层;所有事件(道具、墙壁、NPC、怪物等)都绘制在这一层进行处理 +- hero:勇士层;主要用来绘制勇士 +- event2:事件2层;本层主要用来绘制48x32的图片素材的上半部分(避免和勇士错位),也可以用来绘制该层的前景图片素材 +- fg:显伤层;主要用来绘制怪物显伤和领域显伤 +- animate:动画层;主要用来绘制动画,图块的淡入/淡出效果,图块的移动。showImage事件绘制的图片也是在这一层。 +- weather:天气层;主要用来绘制天气(雨/雪) +- curtain:色调层;用来控制当前楼层的画面色调 +- ui:UI层;用来绘制一切UI窗口,如剧情文本、怪物手册、楼传器、系统菜单等等 +- data:数据层;用来绘制一些顶层的或更新比较快的数据,如左上角的提示,战斗界面中数据的变化等等。 + ## 自定义素材 所有素材的图片都在`images`目录下。 - `animates.png` 为所有动画效果。主要是星空熔岩,开门,毒网,传送门之类的效果。为四帧。 - `autotile.png` 为Autotile块。 -- `enemys.png` 为所有怪物的图片。其对应的数字,从上至下依次是会从201开始计算(即,绿色史莱姆为201,小蝙蝠为205,依次类推)。请注意,动画效果为两帧,一般是原始四帧中的1和3。(四帧中12相同,34相同,因此只取1和3即可) +- `enemys.png` 为所有怪物的图片。 +- `enemy48.png` 为所有48x32怪物的图片。 - `heros.png` 为勇士行走图。 - `items.png` 为所有道具的图标。 -- `npcs.png` 为所有NPC的图标,也是两帧。 +- `npcs.png` 为所有NPC的图标。 +- `npc48.png` 为所有48x32的NPC图标。 - `terrains.png` 为所有地形的图标。 系统会读取`icon.js`文件,并获取每个ID对应的图标所在的位置。 @@ -23,40 +42,38 @@ 如果你需要某个素材已经存在,则可以直接将其覆盖images目录下的同名文件,就能看到效果。 -### 使用自己的图片作为某层楼的背景素材 +### 使用自己的图片作为某层楼的背景/前景素材 由于HTML5功能(素材)有限,导致了对很多比较复杂的素材(比如房子内)等无法有着较好的绘图方式。 为了解决这个问题,我们允许用户自己放置一张或多张图片作为某一层的背景素材。 -要启用这个功能,我们首先需要在`main.js`中将可能的图片进行加载。 +要启用这个功能,我们首先需要在`data.js`中将可能的图片进行加载。 ``` js -this.pngs = [ // 在此存放所有可能使用的图片,只能是png格式,可以不写后缀名 +"images": [ // 在此存放所有可能使用的图片 // 图片可以被作为背景图(的一部分),也可以直接用自定义事件进行显示。 // 图片名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 // 建议对于较大的图片,在网上使用在线的“图片压缩工具(http://compresspng.com/zh/)”来进行压缩,以节省流量 - "bg", // 依次向后添加 + "bg.jpg", "house.png", "bed.png"// 依次向后添加 ]; ``` -!> 背景素材只支持png格式。 +!> 请使用网上的一些[在线图片压缩工具](http://compresspng.com/zh/)对图片进行压缩,以节省流量。 -!> 请使用网上的一些[在线图片压缩工具](http://compresspng.com/zh/)对png图片进行压缩,以节省流量。一张500KB的png图片可以被压缩到20-30KB,显示效果不会有太大差异。 - -之后,我们可以在每层剧本的`"png"`里来定义该层的默认背景图片素材。 +之后,我们可以在每层剧本的`"images"`里来定义该层的默认背景图片素材。 ``` js -"png": [[x,y,"bg"]], // 背景图;你可以选择一张或多张png图片来作为背景素材。 -"png": [], // 无任何背景图 -"png": [[1,1,"house"], [6,7,"house2"]] // 在(1,1)放一个house.png,且(6,7)放house2.png +"images": [[x,y,"bg.jpg",false]], // 背景图;你可以选择一张或多张图片来作为背景/前景素材。 +"images": [], // 无任何背景图 +"images": [[1,1,"house.png",false], [6,7,"bed.png",true]] // 在(1,1)放一个house.png在背景层,且(6,7)放bed.png在前景层 ``` -png为一个数组,代表当前层所有作为背景素材的图片信息。 +images为一个数组,代表当前层所有作为背景素材的图片信息。 -每一项为一个三元组,分别为该背景素材的x,y和图片名。其中x和y分别为横纵坐标,在0-12之间;图片名则必须在上面的this.pngs中定义过。 +每一项为一个四元组,分别为该背景素材的x,y,图片名和是否为前景。其中x和y分别为横纵坐标,在0-12之间;图片名则必须在上面的images中定义过。 -你的图片背景素材将会覆盖原来本身的背景层。 +如果第四项为true,则会在前景层(event2)上绘制,能覆盖勇士,常常用来作为柱子的上半部分等情况。 **如果你需要让某些点不可通行(比如你建了个房子,墙壁和家具等位置不让通行),则需在`events`中指定`{"noPass": false}`,参见[自定义事件](event#自定义事件)的写法。 @@ -84,6 +101,8 @@ png为一个数组,代表当前层所有作为背景素材的图片信息。 这是因为,该素材没有被定义,无法被游戏所识别。 +!> 在V2.0中,我们可以简单的在地图编辑器中新增素材的ID和数字,但是仍然**强烈建议**对素材的机制进行了解。 + #### 素材的机制 本塔所有的素材都拥有三个属性:**ID**,**索引**,**数字**。 @@ -93,7 +112,7 @@ png为一个数组,代表当前层所有作为背景素材的图片信息。 **`ID-索引` 对应关系定义在icons.js文件中。该文件将唯一确定一个ID在图片上所在的位置。** -**`ID-数字` 对应关系定义在maps.js文件的getBlock函数中。该函数将唯一确定一个ID对应的数字是多少。** +**`ID-数字` 对应关系定义在maps.js文件中。该函数将唯一确定一个ID对应的数字是多少。** 如果需要添加一个素材到游戏,则必须为其分配一个唯一标识符,并同时修改`icons.js`和`maps.js`两个文件。 @@ -108,7 +127,7 @@ png为一个数组,代表当前层所有作为背景素材的图片信息。 3. 修改对应楼层的剧本文件的`defaultGround`项,改成新的ID。 **如果你要在游戏内使用本地形,则操作如下:** -3. 指定一个数字,在maps.js的getBlock函数下类似进行添加。 +3. 指定一个数字,在maps.js中类似进行添加。 #### 新添加Autotile @@ -116,24 +135,26 @@ png为一个数组,代表当前层所有作为背景素材的图片信息。 1. 将新的Autotile图片复制到images目录下。 2. 进入icons.js,在autotile分类下进行添加该文件的名称,索引简单的写0。 -3. 指定一个数字,在maps.js的getBlock函数下类似进行添加。 +3. 指定一个数字,在maps.js中类似进行添加。 !> Autotile的ID和文件名完全相同!且其ID/文件名不能含有中文、空格或特殊字符。 +!> V2.0版本不能在地图编辑器中添加Autotile,请按上面的操作来执行。 + #### 新添加道具 如果你需要新增一个未被定义的道具: 1. 指定一个唯一的英文ID,不能和现有的重复。 2. 进入icons.js,在items分类下进行添加索引(对应图标在图片上的位置,即index) -3. 指定一个数字,在maps.js的getBlock下类似进行添加。 +3. 指定一个数字,在maps.js中类似进行添加。 4. 在items.js中仿照其他道具,来添加道具的信息。 有关如何自行实现一个道具的效果,参见[自定义道具效果](#自定义道具效果)。 #### 新添加怪物 -如果我们需要新添加怪物,请在enemys.png中新增一行,然后复制粘贴上四帧怪物图的**1和3帧**。 +如果我们需要新添加怪物,请在enemys.png中新增一行。 你可以通过便捷PS工具的“更改色相”来将红头怪变成橙头怪等。 @@ -141,9 +162,11 @@ png为一个数组,代表当前层所有作为背景素材的图片信息。 1. 指定一个唯一的英文ID,不能和enemys中现有的重复。 2. 进入icons.js,在enemys分类下进行添加索引(对应图标在图片上的位置,即index) -3. 在maps.js的getBlock下继续进行添加。请注意其ID为200开始的顺序,即如果新增一行为261,依次类推 +3. 在maps.js中继续进行添加。 4. 在enemys.js中仿照其他怪物,来添加怪物的信息。 +!> 如果是48x32的怪物素材,请放在enemy48.png中,然后在icons.js的enemy48下添加索引。 + 有关如何自行实现一个怪物的特殊属性或伤害计算公式,参见[怪物的特殊属性](#怪物的特殊属性)。 #### 新添加NPC @@ -152,6 +175,8 @@ png为一个数组,代表当前层所有作为背景素材的图片信息。 2. 进入icons.js,在npcs分类下进行添加索引(对应图标在图片上的位置,即index) 3. 指定一个数字,在maps.js的getBlock下类似进行添加。 +!> 如果是48x32的怪物素材,请放在npc48.png中,然后在icons.js的npc48下添加索引。 + ### 地图生成器使用自定义素材 地图生成器是直接从js文件中读取数字-图标对应关系的。 @@ -168,30 +193,24 @@ png为一个数组,代表当前层所有作为背景素材的图片信息。 对于即捡即用类道具,如宝石、血瓶、剑盾等,我们可以简单地修改`data.js`中的value一栏即可。 -如果你有更高级的需求(例如每个区域的效果不同),则需要编辑`items.js`文件。具体方式是: +如果你想要同种宝石在不同层效果不同的话,可以进行如下操作: + +1. 在楼层的item_ratio中定义宝石的比率(比如1-10的写1,11-20层写2等) +2. 修改获得道具的itemEffect函数(在items.js中的itemEffect中编辑,V2.0中也可以使用编辑器) -1. 找到`getItemEffect`函数;所有即捡即用类道具的效果都在这里实现。 -2. 算道具效果系数,或应该增加的值。 ``` js -items.prototype.getItemEffect = function(itemId, itemNum) { - var itemCls = core.material.items[itemId].cls; - // 消耗品 - if (itemCls === 'items') { - var floor = parseInt(core.status.thisMap.name); // 获得当前楼层。此name和剧本中的name完全一致。 - var ratio = 1; // 道具效果系数 - if (floor>=11 && floor<=20 ) ratio = 2; // 11-20F(二区),道具效果翻倍 - if (floor>=21 && floor<=30 ) ratio = 3; // 21-30F(二区),道具效果三倍 - // ... 根据自己的需要来写 - - if (itemId === 'redJewel') core.status.hero.atk += core.values.redJewel * ratio; // 将初始效果乘以倍数 - if (itemId === 'blueJewel') core.status.hero.def += core.values.blueJewel * ratio; // 将初始效果乘以倍数 - if (itemId === 'greenJewel') core.status.hero.mdef += core.values.greenJewel * ratio; // 将初始效果乘以倍数 - if (itemId == 'yellowJewel') { // 黄宝石属性:需自己定义 -// ... 下略 +// ratio为楼层的item_ratio值,可以进行翻倍宝石属性 +core.status.hero.atk += core.values.redJewel * ratio ``` -3. 修改同样修改下面的`getItemEffectTip`函数,使提示文字相应变动。 -!> **请注意这里`core.status.thisMap.name`获取的是当前层中,你在剧本文件里写的name那一项(即状态栏中的层数显示)。然后可以通过几个简单的if来判断应该增加的值。** +这里我们可以直接写ratio来取用该楼层中定义的`item_ratio`的值。 + +如果不是倍数增加(比如线性增加)也可以类似来写 + +``` js +// 一个二倍线性增加的例子 +core.status.hero.atk += core.values.redJewel + 2*ratio +``` ### 消耗类道具(cls: tools);永久类道具(cls: constants) @@ -214,12 +233,10 @@ events.prototype.passNet = function (data) { ### 实战!拿到神圣盾后免疫吸血、领域、夹击效果 -1. 在getItemEffect中修改拿到神圣盾时的效果,标记一个自定义Flag。 +1. 在itemEffect中修改拿到神圣盾时的效果,标记一个自定义Flag。 ``` js -if (itemId === 'shield5') { - core.status.hero.def += core.values.shield5; - core.setFlag("shield5", true); // 增加一个自定义Flag:已经拿到神圣盾 -} +core.status.hero.def += core.values.shield5 * ratio; +core.setFlag("shield5", true); // 增加一个自定义Flag:已经拿到神圣盾 ``` 2. 免疫吸血效果:在`enemys.js`的伤害计算中,编辑成如果存在神圣盾标记,吸血伤害为0。 ``` js @@ -241,10 +258,10 @@ enemys.prototype.calDamage = function (monster, hero_hp, hero_atk, hero_def, her } // ... 下略 ``` -3. 免疫领域、夹击、阻击效果:在`core.js`中,找到checkBlock函数,并编辑成如果有神圣盾标记,则将伤害变成0。 +3. 免疫领域、夹击、阻击效果:在`control.js`中,找到checkBlock函数,并编辑成如果有神圣盾标记,则将伤害变成0。 ``` js // 检查领域、夹击、阻击事件 -core.prototype.checkBlock = function () { +control.prototype.checkBlock = function () { var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'); var damage = core.status.checkBlock.damage[13*x+y]; if (damage>0) { @@ -271,9 +288,9 @@ core.prototype.checkBlock = function () { 如果要修改伤害计算公式,请修改下面的calDamage函数。请注意,如果无法战斗,该函数必须返回`999999999`。 -对于毒衰弱怪物的战斗后结算在`events.js`中的afterBattle函数中。 +对于毒衰弱怪物的战斗后结算在`functions.js`中的afterBattle函数中。 -对于领域、夹击、阻击怪物的检查在`events.js`中的checkBlock函数中。 +对于领域、夹击、阻击怪物的检查在`control.js`中的checkBlock函数中。 `getCritical`, `getCriticalDamage`和`getDefDamage`三个函数依次计算的是该怪物的临界值、临界减伤和1防减伤。也可以适当进行修改。 diff --git a/docs/start.md b/docs/start.md index c9a838c0..07dddcde 100644 --- a/docs/start.md +++ b/docs/start.md @@ -1,6 +1,6 @@ # 快速上手 -?> 目前版本**v1.4.1**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.0**,上次更新时间:* {docsify-updated} * 在这一节中,将详细介绍做一部塔的流程。现在,让我们来做一部单层塔! @@ -12,9 +12,18 @@ - Chrome浏览器。其他浏览器可能会导致本地服务器产生闪退等现象。 - 一个很好的文本编辑器。推荐带有高亮染色、错误提示等效果。例如:WebStorm,VSCode,或者至少也要Sublime Text。 - ([VSCode下载地址](https://code.visualstudio.com/),群里的群文件中也有,强烈推荐之。) + - **2.0版本可以不需要,但是仍然强烈推荐有一个,从而能对H5造塔有更深的了解。** 只要满足了上述条件,你就可以开始做自己的塔啦! +## V2.0的使用 + +目前版本已经更新到V2.0,在2.0版本中,我们可以进行全GUI造塔。 + +下面的文档主要是讲如何通过代码编辑的方式来造,仍然强烈建议进行阅读从而有着一定的了解。 + +如果想直接知道如何在V2.0造塔,可以直接参见[V2.0版本介绍](V2.0)的说明,或者看[B站视频教程](http://www.bilibili.com/video/av17608025/)。 + ## 启动HTTP服务 在根目录下有一个“启动服务.exe”,运行之。 @@ -25,6 +34,7 @@ * “地图编辑器”允许你以可视化的方式进行编辑地图。 * “便捷PS工具”能让你很方便的对自定义素材进行添加。参见[自定义素材](personalization#自定义素材)。 * “地图生成器”能让你从已有的截图(如RMXP项目)中立刻生成可被本样板识别的地图数据。 +* “RM动画导出器”能让你从RMXP中导出动画而被H5魔塔使用。 * “JS代码压缩工具”能对JS代码进行压缩,从而减少IO请求数和文件大小。 * “伤害和临界值计算器”是一个很便捷的小工具,能对怪物的伤害和临界值进行计算。 @@ -34,7 +44,7 @@ 类似于RMXP,本塔每层楼都是一个“剧本”,剧本内主要定义了本层的地图和各种事件。主函数将读取每个剧本,并生成实际的地图供游戏使用。 -我们打开 `libs/floors/` 目录,这个目录是所有剧本的目录。我们需要指定一个楼层名,例如MT1;然后,我们可以将`MT0.js`(模板)复制重命名为为`MT1.js`,并使用文本编辑器打开。 +我们打开 `project/floors/` 目录,这个目录是所有剧本的目录。我们需要指定一个楼层名,例如MT1;然后,我们可以将`MT0.js`(模板)复制重命名为为`MT1.js`,并使用文本编辑器打开。 ![新建剧本](./img/script.png) @@ -43,11 +53,14 @@ 具体样板文件的每个要素如下: - **`floorId`** 楼层唯一标识符;必须和文件名,以及 `main.floors.xxx` 完全一致 - **`title`** 楼层中文名,将在切换楼层时进行显示 +- **`name`** 楼层再状态栏显示的名称 - **`canFlyTo`** 当前楼层可否被楼传器飞到。如果该层不能飞到,则也在该层也不允许使用楼传器。 - **`canUseQuickShop`** 当前楼层可否使用快捷商店。 -- **`defaultGround`** 该层的背景(地面)素材。需要是在`icon.js`里`terrains`中定义的一个ID,如`ground`, `grass2`等等。 -- **`color`** 该层的画面色调。本项可选,如果不写则色调为默认值(无色调),否则是一个RGBA数组,比如`[255,0,0,0.3]`等。 +- **`defaultGround`** 该层的背景(地面)素材。 +- **`images`** 该层默认显示的前景/背景图片 +- **`color`** 该层的画面色调。 - **`bgm`** 到达该层后默认播放的BGM。本项可忽略。 +- **`item_ratio`** 该层的宝石/血瓶倍率 - **`map`** 本层地图,需要是13x13数组,建议使用地图生成器或者可视化地图编辑器制作。 - **`firstArrive`** 第一次到该楼层触发的事件 - **`events`** 该楼的所有可能事件列表 @@ -55,6 +68,7 @@ - **`afterBattle`** 战斗后可能触发的事件列表 - **`afterGetItem`** 获得道具后可能触发的事件列表 - **`afterOpenDoor`** 开完门后可能触发的事件列表 +- **`cannotMove`** 每个图块不可通行的方向,也就是悬崖效果 我们最终的任务其实是,将每个楼层的剧本(地图&事件)给写完即可。 @@ -72,12 +86,14 @@ 然后可以在上面任意进行绘制地图。 -!> **如果地图的数字和ID未被定义,则会进行提示:数字和ID未被定义!此时可能需要手动在icons.js和maps.js中定义对应的数字和ID。请参见[自定义素材](personalization#自定义素材)。** +!> **如果地图的数字和ID未被定义,则会进行提示:数字和ID未被定义!此时要对素材的ID和数字进行定义,请参见[自定义素材](personalization#自定义素材)。** 绘制地图完毕后,点击"导出地图",即可在左边看到对应的JSON数组,并且已经复制到了剪切板。将其粘贴到剧本中的map位置即可。 ![地图数组](./img/maparray.png) +!> V2.0版本可以直接将当前地图进行保存或另存为,不需要这样手动打开进行编辑。 + ### 从RMXP导入已有的地图 如果我们想复刻一个现有的,已经被RMXP所制作的塔,也有很便捷的方式,那就是用到我们的“地图生成器”。 @@ -117,6 +133,8 @@ 我们打开`data.js`文件,这里面定义了各种全局属性和勇士初始值。 +!> V2.0版本可以直接在地图编辑器的`全塔属性`中进行修改! + 我们可以将本塔标题改名为“1层小塔”, 游戏的唯一标识符叫onefloor,然后可以直接修改勇士的各项初始数据. @@ -139,12 +157,12 @@ 其他的几项暂时不会被涉及到,因此不用考虑。 -全局变量修改完毕后,我们需要告诉主函数加载该楼层。打开`main.js`(该文件和index.html同级),找到`this.floorIds`项,将其值改为楼层ID即MT1。 - -![修改楼层数据](./img/floordata.png) +全局变量修改完毕后,我们需要告诉主函数加载该楼层。打开`data.js`,找到`floorIds`项,将其值改为楼层ID即MT1。 最后一步就是录入怪物数据。打开`enemys.js`文件,依次输入你在本塔内使用到的所有怪物的攻防血的数据。其中怪物的特殊属性(special项)与该文件下面的getSpecialText对应。 +!> V2.0版本可以直接在“图块属性”一栏进行修改怪物属性! + ![怪物数据](./img/enemyarray.png) 只需要修改自己用到的怪物属性即可,其他没有用到的怪物完全无所谓。 @@ -177,7 +195,7 @@ 1. 截图请务必刚好截取13x13的图片,并需要保证每个位置必须为32x32像素。一般无放缩的RMXP符合条件。 2. 游戏的唯一标识符name请务必修改。如果不修改可能会导致存档出现异常。 -3. 别忘了main.js中要修改floorIds指明所用到的所有楼层哦~ +3. 别忘了data.js中要修改floorIds指明所用到的所有楼层哦~ 下面是几个常见的FAQ: diff --git a/drawMapGUI.html b/drawMapGUI.html index 2a32d6c4..99a75938 100644 --- a/drawMapGUI.html +++ b/drawMapGUI.html @@ -1,698 +1 @@ - - - - - - - -
-
-
-
-
-
- -

{{ errors[error-1] }}

-
-
- -
-
-
- -
-
- -
- -
-
-
-
-
- - - -
-
-
-
-

当前选择为清除块,可擦除地图上块

-
-

图块编号:{{ infos['idnum'] }}

-

图块ID:{{ infos['id'] }}

-

该图块无对应的数字或ID存在,请先前往icons.js和maps.js中进行定义!

-

图块所在素材:{{ infos['images'] + (isAutotile ? '( '+infos['id']+' )' : '') }}

-

图块索引:{{ infos['y'] }}

-
-
-
-

{{ mapMsg }}

-
-
- - - -
- 当前地板: - -
- - -
-
-
-
- -
- - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/editor.html b/editor.html new file mode 100644 index 00000000..ff4a1793 --- /dev/null +++ b/editor.html @@ -0,0 +1,392 @@ + + + + + + + + + +
+
+
+
+
+
+ +

{{ errors[error-1] }}

+
+
+
+ + + +
+
+ + +
+
+
+ +
+
+ +
+ +
+
+

追加素材

+

+ + + +

+
+ + + + +
+
1
+
2
+
3
+
4
+
+
+
+
+

地图选点  

+

0,0

+
+ + + + +
条目注释
+
+
+
+

图块属性  

+
+ + + +
+
+
+ + + + +
条目注释
+
+
+
+
+

楼层属性  

+
+ + + + +
条目注释
+
+
+
+

全塔属性  

+
+ + + + +
条目注释
+
+
+
+

事件编辑器    + + + + + + + +

+
+
+ +
+
+
+ + + +
+
+

脚本编辑  

+
+ + + + +
条目注释
+
+
+
+
+
+
+ + + + +
+
+
+
+

当前选择为清除块,可擦除地图上块

+
+

图块编号:{{ infos['idnum'] }}

+

图块ID:{{ infos['id'] }}

+

该图块无对应的数字或ID存在,请先前往icons.js和maps.js中进行定义!

+

图块所在素材:{{ infos['images'] + (isAutotile ? '( '+infos['id']+' )' : '') }}

+

图块索引:{{ infos['y'] }}

+
+
+
+

{{ mapMsg }}

+
+
+ + + +



+ + + + + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/animates.png b/images/animates.png deleted file mode 100644 index c1c1cb1a..00000000 Binary files a/images/animates.png and /dev/null differ diff --git a/images/bg.png b/images/bg.png deleted file mode 100644 index d235379c..00000000 Binary files a/images/bg.png and /dev/null differ diff --git a/images/常用素材:如需使用请直接替换目录中的对应文件/animates0:经典.png b/images/常用素材:如需使用请直接替换目录中的对应文件/animates0:经典.png deleted file mode 100644 index c1c1cb1a..00000000 Binary files a/images/常用素材:如需使用请直接替换目录中的对应文件/animates0:经典.png and /dev/null differ diff --git a/images/常用素材:如需使用请直接替换目录中的对应文件/animates1:旋转门.png b/images/常用素材:如需使用请直接替换目录中的对应文件/animates1:旋转门.png deleted file mode 100644 index 3a6cdbb5..00000000 Binary files a/images/常用素材:如需使用请直接替换目录中的对应文件/animates1:旋转门.png and /dev/null differ diff --git a/images/常用素材:如需使用请直接替换目录中的对应文件/animates2:四方门.png b/images/常用素材:如需使用请直接替换目录中的对应文件/animates2:四方门.png deleted file mode 100644 index dead2aea..00000000 Binary files a/images/常用素材:如需使用请直接替换目录中的对应文件/animates2:四方门.png and /dev/null differ diff --git a/index.html b/index.html index 7d110562..e04a22e4 100644 --- a/index.html +++ b/index.html @@ -25,20 +25,15 @@

资源即将开始加载

- - - + +
开始游戏 载入游戏 录像回放
-
- 简单 - 普通 - 困难 -
+
@@ -48,39 +43,43 @@
- +

- +

+
+ +

+
- +

- +

- +

- +

- +

- +

- +

@@ -95,26 +94,28 @@
- - - - - - - + + + + + + +

- + + 此浏览器不支持HTML5 + \ No newline at end of file diff --git a/libs/actions.js b/libs/actions.js new file mode 100644 index 00000000..48601e6f --- /dev/null +++ b/libs/actions.js @@ -0,0 +1,1967 @@ +/* +actions.js:用户交互的事件的处理 +键盘、鼠标、触摸屏事件相关 + */ + +function actions() { + this.init(); +} + +actions.prototype.init = function () { + +} + +////// 按下某个键时 ////// +actions.prototype.onkeyDown = function (e) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; + if (!core.isset(core.status.holdingKeys))core.status.holdingKeys=[]; + var isArrow={37:true,38:true,39:true,40:true}[e.keyCode] + if(isArrow && !core.status.lockControl){ + for(var ii =0;iimax){ + index=ii; + max=directionDistance[ii]; + } + } + pos=[{'x':0,'y':1},{'x':-1,'y':0},{'x':0,'y':-1},{'x':1,'y':0},false][index] + if(pos){ + pos.x+=pos0.x; + pos.y+=pos0.y; + core.status.stepPostfix.push(pos); + core.fillPosWithPoint(pos); + } +} + +////// 当点击(触摸)事件放开时 ////// +actions.prototype.onup = function () { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; + + clearTimeout(core.timeout.onDownTimeout); + core.timeout.onDownTimeout = null; + clearInterval(core.interval.onDownInterval); + core.interval.onDownInterval = null; + + // core.status.holdingPath=0; + if(core.status.stepPostfix.length>0){ + var stepPostfix = []; + var direction={'0':{'1':'down','-1':'up'},'-1':{'0':'left'},'1':{'0':'right'}}; + for(var ii=1;ii=1000) { + core.waitHeroToStop(function () { + // 绘制快捷键 + core.ui.drawKeyBoard(); + }); + } + else { + //posx,posy是寻路的目标点,stepPostfix是后续的移动 + this.onclick(posx,posy,stepPostfix); + } + core.status.downTime=null; + } +} + +////// 获得点击事件相对左上角的坐标(0到12之间) ////// +actions.prototype.getClickLoc = function (x, y) { + + var statusBar = {'x': 0, 'y': 0}; + var size = 32; + size = size * core.domStyle.scale; + + switch (core.domStyle.screenMode) {// 这里的3是指statusBar和游戏画布之间的白线宽度 + case 'vertical': + statusBar.x = 0; + statusBar.y = core.dom.statusBar.offsetHeight + 3; + break; + case 'horizontal': + case 'bigScreen': + statusBar.x = core.dom.statusBar.offsetWidth + 3; + statusBar.y = 0; + break; + } + + var left = core.dom.gameGroup.offsetLeft + statusBar.x; + var top = core.dom.gameGroup.offsetTop + statusBar.y; + var loc={'x': x - left, 'y': y - top, 'size': size}; + return loc; +} + +////// 具体点击屏幕上(x,y)点时,执行的操作 ////// +actions.prototype.onclick = function (x, y, stepPostfix) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; + // console.log("Click: (" + x + "," + y + ")"); + + stepPostfix=stepPostfix||[]; + + // 非游戏屏幕内 + if (x<0 || y<0 || x>12 || y>12) return; + + // 中心对称飞行器 + if (core.status.usingCenterFly) { + if (x!=12-core.getHeroLoc('x') || y!=12-core.getHeroLoc('y')) { + core.clearMap('ui', (12-core.getHeroLoc('x'))*32,(12-core.getHeroLoc('y'))*32,32,32); + } else { + if (core.canUseItem('centerFly')) { + core.useItem('centerFly'); + core.clearMap('ui', core.getHeroLoc('x')*32,core.getHeroLoc('y')*32,32,32); + return; + } + else { + core.drawTip('当前不能使用中心对称飞行器'); + core.clearMap('ui', (12-core.getHeroLoc('x'))*32,(12-core.getHeroLoc('y'))*32,32,32); + } + } + core.status.usingCenterFly= false; + } + + // 寻路 + if (!core.status.lockControl) { + core.setAutomaticRoute(x, y, stepPostfix); + return; + } + + // 怪物手册 + if (core.status.event.id == 'book') { + this.clickBook(x,y); + return; + } + + // 怪物详细信息 + if (core.status.event.id == 'book-detail') { + this.clickBookDetail(x,y); + return; + } + + // 楼层飞行器 + if (core.status.event.id == 'fly') { + this.clickFly(x,y); + return; + } + + // 查看地图 + if (core.status.event.id == 'viewMaps') { + this.clickViewMaps(x,y); + return; + } + + // 开关 + if (core.status.event.id == 'switchs') { + this.clickSwitchs(x,y); + return; + } + + // 设置 + if (core.status.event.id == 'settings') { + this.clickSettings(x,y); + return; + } + + // 商店 + if (core.status.event.id == 'shop') { + this.clickShop(x,y); + return; + } + + // 快捷商店 + if (core.status.event.id == 'selectShop') { + this.clickQuickShop(x,y); + return; + } + + // 工具栏 + if (core.status.event.id == 'toolbox') { + this.clickToolbox(x,y); + return; + } + + // 存读档 + if (core.status.event.id == 'save' || core.status.event.id == 'load') { + this.clickSL(x,y); + return; + } + + // 选项 + if (core.status.event.id == 'confirmBox') { + this.clickConfirmBox(x,y); + return; + } + + if (core.status.event.id == 'keyBoard') { + this.clickKeyBoard(x,y); + return; + } + + // 关于 + if (core.status.event.id == 'about') { + this.clickAbout(x,y); + return; + } + + if (core.status.event.id == 'action') { + this.clickAction(x,y); + return; + } + + // 纯文本 + if (core.status.event.id == 'text') { + core.drawText(); + return; + } + + // 同步存档 + if (core.status.event.id == 'syncSave') { + this.clickSyncSave(x,y); + return; + } + + if (core.status.event.id == 'syncSelect') { + this.clickSyncSelect(x,y); + return; + } + + if (core.status.event.id == 'localSaveSelect') { + this.clickLocalSaveSelect(x,y); + return; + } + if (core.status.event.id=='storageRemove') { + this.clickStorageRemove(x,y); + return; + } + + if (core.status.event.id == 'cursor') { + this.clickCursor(x,y); + return; + } + +} + +////// 滑动鼠标滚轮时的操作 ////// +actions.prototype.onmousewheel = function (direct) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; + // 向下滚动是 -1 ,向上是 1 + + // 楼层飞行器 + if (core.status.lockControl && core.status.event.id == 'fly') { + if (direct==1) core.ui.drawFly(core.status.event.data+1); + if (direct==-1) core.ui.drawFly(core.status.event.data-1); + return; + } + + // 怪物手册 + if (core.status.lockControl && core.status.event.id == 'book') { + if (direct==1) core.ui.drawBook(core.status.event.data - 6); + if (direct==-1) core.ui.drawBook(core.status.event.data + 6); + return; + } + + // 存读档 + if (core.status.lockControl && (core.status.event.id == 'save' || core.status.event.id == 'load')) { + if (direct==1) core.ui.drawSLPanel(core.status.event.data - 10); + if (direct==-1) core.ui.drawSLPanel(core.status.event.data + 10); + return; + } + + // 浏览地图 + if (core.status.lockControl && core.status.event.id == 'viewMaps') { + if (direct==1) core.ui.drawMaps(core.status.event.data+1); + if (direct==-1) core.ui.drawMaps(core.status.event.data-1); + return; + } +} + +/////////////////// 在某个界面时的按键点击效果 /////////////////// + +////// 长按 ////// +actions.prototype.longClick = function () { + if (!core.isPlaying()) return false; + if (core.status.event.id=='text') { + core.drawText(); + return true; + } + if (core.status.event.id=='action' && core.status.event.data.type=='text') { + core.doAction(); + return true; + } + return false; +} + +////// 按下Ctrl键时(快捷跳过对话) ////// +actions.prototype.keyDownCtrl = function () { + if (core.status.event.id=='text') { + core.drawText(); + return; + } + if (core.status.event.id=='action' && core.status.event.data.type=='text') { + core.doAction(); + return; + } +} + +////// 点击确认框时 ////// +actions.prototype.clickConfirmBox = function (x,y) { + if ((x == 4 || x == 5) && y == 7 && core.isset(core.status.event.data.yes)) + core.status.event.data.yes(); + if ((x == 7 || x == 8) && y == 7 && core.isset(core.status.event.data.no)) + core.status.event.data.no(); +} + +////// 键盘操作确认框时 ////// +actions.prototype.keyUpConfirmBox = function (keycode) { + if (keycode==37) { + core.status.event.selection=0; + core.ui.drawConfirmBox(core.status.event.ui, core.status.event.data.yes, core.status.event.data.no); + } + + if (keycode==39) { + core.status.event.selection=1; + core.ui.drawConfirmBox(core.status.event.ui, core.status.event.data.yes, core.status.event.data.no); + } + + if (keycode==13 || keycode==32 || keycode==67) { + if (core.status.event.selection==0 && core.isset(core.status.event.data.yes)) { + core.status.event.selection=null; + core.status.event.data.yes(); + } + if (core.status.event.selection==1 && core.isset(core.status.event.data.no)) { + core.status.event.selection=null; + core.status.event.data.no(); + } + } +} + +////// 自定义事件时的点击操作 ////// +actions.prototype.clickAction = function (x,y) { + + if (core.status.event.data.type=='text') { + // 文字 + core.doAction(); + return; + } + if (core.status.event.data.type=='choices') { + // 选项 + var data = core.status.event.data.current; + var choices = data.choices; + if (choices.length==0) return; + if (x >= 5 && x <= 7) { + var topIndex = 6 - parseInt((choices.length - 1) / 2); + if (y>=topIndex && y0) { + if (keycode==38) { + core.status.event.selection--; + core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); + } + if (keycode==40) { + core.status.event.selection++; + core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); + } + } + } +} + +////// 自定义事件时,放开某个键的操作 ////// +actions.prototype.keyUpAction = function (keycode) { + if (core.status.event.data.type=='text' && (keycode==13 || keycode==32 || keycode==67)) { + core.doAction(); + return; + } + if (core.status.event.data.type=='choices') { + var data = core.status.event.data.current; + var choices = data.choices; + if (choices.length>0) { + if (keycode==13 || keycode==32 || keycode==67) { + core.status.route.push("choices:"+core.status.event.selection); + core.insertAction(choices[core.status.event.selection].action); + core.doAction(); + } + } + } +} + +////// 怪物手册界面的点击操作 ////// +actions.prototype.clickBook = function(x,y) { + // 上一页 + if ((x == 3 || x == 4) && y == 12) { + core.ui.drawBook(core.status.event.data - 6); + return; + } + // 下一页 + if ((x == 8 || x == 9) && y == 12) { + core.ui.drawBook(core.status.event.data + 6); + return; + } + // 返回 + if (x>=10 && x<=12 && y==12) { + if (core.status.event.selection==null) + core.ui.closePanel(); + else { + core.status.boxAnimateObjs = []; + core.ui.drawMaps(core.status.event.selection); + } + return; + } + // 怪物信息 + var data = core.status.event.data; + if (core.isset(data) && y<12) { + var page=parseInt(data/6); + var index=6*page+parseInt(y/2); + core.ui.drawBook(index); + core.ui.drawBookDetail(index); + } + return; +} + +////// 怪物手册界面时,按下某个键的操作 ////// +actions.prototype.keyDownBook = function (keycode) { + if (keycode==37) core.ui.drawBook(core.status.event.data-6); + if (keycode==38) core.ui.drawBook(core.status.event.data-1); + if (keycode==39) core.ui.drawBook(core.status.event.data+6); + if (keycode==40) core.ui.drawBook(core.status.event.data+1); + if (keycode==33) core.ui.drawBook(core.status.event.data-6); + if (keycode==34) core.ui.drawBook(core.status.event.data+6); + return; +} + +////// 怪物手册界面时,放开某个键的操作 ////// +actions.prototype.keyUpBook = function (keycode) { + if (keycode==27 || keycode==88) { + if (core.status.event.selection==null) + core.ui.closePanel(); + else { + core.status.boxAnimateObjs = []; + core.ui.drawMaps(core.status.event.selection); + } + return; + } + if (keycode==13 || keycode==32 || keycode==67) { + var data=core.status.event.data; + if (core.isset(data)) { + this.clickBook(6, 2*(data%6)); + } + return; + } +} + +////// 怪物手册属性显示界面时的点击操作 ////// +actions.prototype.clickBookDetail = function () { + core.clearMap('data', 0, 0, 416, 416); + core.status.event.id = 'book'; +} + +////// 楼层传送器界面时的点击操作 ////// +actions.prototype.clickFly = function(x,y) { + if ((x==10 || x==11) && y==9) core.ui.drawFly(core.status.event.data-1); + if ((x==10 || x==11) && y==5) core.ui.drawFly(core.status.event.data+1); + if (x>=5 && x<=7 && y==12) core.ui.closePanel(); + if (x>=0 && x<=9 && y>=3 && y<=11) { + var index=core.status.hero.flyRange.indexOf(core.status.floorId); + var stair=core.status.event.data=8) { + core.ui.drawMaps(core.status.event.data-1); + } + else { + core.clearMap('data', 0, 0, 416, 416); + core.setOpacity('data', 1); + core.ui.closePanel(); + } +} + +////// 查看地图界面时,按下某个键的操作 ////// +actions.prototype.keyDownViewMaps = function (keycode) { + if (keycode==37 || keycode==38 || keycode==33) core.ui.drawMaps(core.status.event.data+1); + else if (keycode==39 || keycode==40 || keycode==34) core.ui.drawMaps(core.status.event.data-1); + return; +} + +////// 查看地图界面时,放开某个键的操作 ////// +actions.prototype.keyUpViewMaps = function (keycode) { + if (keycode==27 || keycode==13 || keycode==32 || keycode==67) { + core.clearMap('data', 0, 0, 416, 416); + core.setOpacity('data', 1); + core.ui.closePanel(); + } + if (keycode==88) { + core.openBook(false); + } + return; +} + +////// 商店界面时的点击操作 ////// +actions.prototype.clickShop = function(x,y) { + var shop = core.status.event.data.shop; + var choices = shop.choices; + if (x >= 5 && x <= 7) { + var topIndex = 6 - parseInt(choices.length / 2); + if (y>=topIndex && y eval(use)) { + core.drawTip("你的"+use_text+"不足"); + return false; + } + + core.status.event.data.actions.push(y-topIndex); + + eval(use+'-='+need); + core.setStatus('money', money); + core.setStatus('experience', experience); + + // 更新属性 + choice.effect.split(";").forEach(function (t) { + core.doEffect(t); + }); + core.updateStatusBar(); + shop.times++; + core.events.openShop(core.status.event.data.id); + } + // 离开 + else if (y==topIndex+choices.length) { + if (core.status.event.data.actions.length>0) { + core.status.route.push("shop:"+core.status.event.data.id+":"+core.status.event.data.actions.join("")); + } + + core.status.event.data.actions = []; + core.status.boxAnimateObjs = []; + if (core.status.event.data.fromList) + core.ui.drawQuickShop(); + else core.ui.closePanel(); + } + else return false; + } + return true; +} + +////// 商店界面时,按下某个键的操作 ////// +actions.prototype.keyDownShop = function (keycode) { + if (keycode==38) { + core.status.event.selection--; + core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); + } + if (keycode==40) { + core.status.event.selection++; + core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); + } +} + +////// 商店界面时,放开某个键的操作 ////// +actions.prototype.keyUpShop = function (keycode) { + if (keycode==27 || keycode==88) { + if (core.status.event.data.actions.length>0) { + core.status.route.push("shop:"+core.status.event.data.id+":"+core.status.event.data.actions.join("")); + } + + core.status.event.data.actions = []; + + core.status.boxAnimateObjs = []; + + if (core.status.event.data.fromList) + core.ui.drawQuickShop(); + else + core.ui.closePanel(); + return; + } + var shop = core.status.event.data.shop; + var choices = shop.choices; + if (keycode==13 || keycode==32 || keycode==67) { + var topIndex = 6 - parseInt(choices.length / 2); + this.clickShop(6, topIndex+core.status.event.selection); + } + return; +} + +////// 快捷商店界面时的点击操作 ////// +actions.prototype.clickQuickShop = function(x, y) { + var shopList = core.status.shops, keys = Object.keys(shopList); + if (x >= 5 && x <= 7) { + var topIndex = 6 - parseInt(keys.length / 2); + if (y>=topIndex && y=10 && x<=12 && y==12) { + core.ui.closePanel(); + return; + } + if (x>=10 && x<=12 && y<=1) { + if (!core.isset(core.status.event.data)) return; + if (!core.flags.enableDeleteItem) { + core.drawTip("不支持删除道具!"); + return; + } + core.removeItem(core.status.event.data); + core.status.event.data = null; + core.ui.drawToolbox(); + return; + } + + var index=0; + if (y==4||y==5||y==9||y==10) index=parseInt(x/2); + else index=6+parseInt(x/2); + if (y>=9) index+=100; + this.clickToolboxIndex(index); +} + +////// 选择工具栏界面中某个Index后的操作 ////// +actions.prototype.clickToolboxIndex = function(index) { + var items = null; + var ii=index; + if (ii<100) + items = Object.keys(core.status.hero.items.tools).sort(); + else { + ii-=100; + items = Object.keys(core.status.hero.items.constants).sort(); + } + if (items==null) return; + if (ii>=items.length) return; + var itemId=items[ii]; + if (itemId==core.status.event.data) { + core.events.useItem(itemId); + } + else { + core.ui.drawToolbox(index); + } +} + +////// 工具栏界面时,按下某个键的操作 ////// +actions.prototype.keyDownToolbox = function (keycode) { + if (!core.isset(core.status.event.data)) return; + + var tools = Object.keys(core.status.hero.items.tools).sort(); + var constants = Object.keys(core.status.hero.items.constants).sort(); + var index=core.status.event.selection; + + if (keycode==37) { // left + if ((index>0 && index<100) || index>100) { + this.clickToolboxIndex(index-1); + return; + } + if (index==100 && tools.length>0) { + this.clickToolboxIndex(tools.length-1); + return; + } + } + if (keycode==38) { // up + if ((index>5 && index<100) || index>105) { + this.clickToolboxIndex(index-6); + return; + } + if (index>=100 && index<=105) { + if (tools.length>6) { + this.clickToolboxIndex(Math.min(tools.length-1, index-100+6)); + } + else if (tools.length>0) { + this.clickToolboxIndex(Math.min(tools.length-1, index-100)); + } + return; + } + } + if (keycode==39) { // right + if ((index=100 && index0) { + this.clickToolboxIndex(100); + return; + } + } + if (keycode==40) { // down + if (index<=5) { + if (tools.length>6) { + this.clickToolboxIndex(Math.min(tools.length-1, index+6)); + } + else if (constants.length>0) { + this.clickToolboxIndex(100+Math.min(constants.length-1, index)); + } + return; + } + if (index>5 && index<100 && constants.length>0) { + this.clickToolboxIndex(100+Math.min(constants.length-1, index-6)); + return; + } + if (index>=100 && index<=105 && constants.length>6) { + this.clickToolboxIndex(Math.min(100+constants.length-1, index+6)); + return; + } + } +} + +////// 工具栏界面时,放开某个键的操作 ////// +actions.prototype.keyUpToolbox = function (keycode) { + if (keycode==84 || keycode==27 || keycode==88) { + core.ui.closePanel(); + return; + } + if (!core.isset(core.status.event.data)) return; + + if (keycode==13 || keycode==32 || keycode==67) { + this.clickToolboxIndex(core.status.event.selection); + return; + } + + if (keycode==46) { // delete + if (!core.isset(core.status.event.data)) return; + if (!core.flags.enableDeleteItem) { + core.drawTip("不支持删除道具!"); + return; + } + core.removeItem(core.status.event.data); + core.status.event.data = null; + core.ui.drawToolbox(); + return; + } + +} + +////// 存读档界面时的点击操作 ////// +actions.prototype.clickSL = function(x,y) { + + var index=core.status.event.data; + var page = parseInt(index/10), offset=index%10; + + // 上一页 + if ((x == 3 || x == 4) && y == 12) { + core.ui.drawSLPanel(10*(page-1)+offset); + } + // 下一页 + if ((x == 8 || x == 9) && y == 12) { + core.ui.drawSLPanel(10*(page+1)+offset); + } + // 返回 + if (x>=10 && x<=12 && y==12) { + core.ui.closePanel(); + if (!core.isPlaying()) { + core.showStartAnimate(); + } + return; + } + + var index=6*page+1; + if (y>=1 && y<=4) { + if (x>=1 && x<=3) core.doSL("autoSave", core.status.event.id); + if (x>=5 && x<=7) core.doSL(5*page+1, core.status.event.id); + if (x>=9 && x<=11) core.doSL(5*page+2, core.status.event.id); + } + if (y>=7 && y<=10) { + if (x>=1 && x<=3) core.doSL(5*page+3, core.status.event.id); + if (x>=5 && x<=7) core.doSL(5*page+4, core.status.event.id); + if (x>=9 && x<=11) core.doSL(5*page+5, core.status.event.id); + } +} + +////// 存读档界面时,按下某个键的操作 ////// +actions.prototype.keyDownSL = function(keycode) { + + var index=core.status.event.data; + var page = parseInt(index/10), offset=index%10; + + if (keycode==37) { // left + if (offset==0) { + core.ui.drawSLPanel(10*(page-1) + 5); + } + else { + core.ui.drawSLPanel(index - 1); + } + return; + } + if (keycode==38) { // up + if (offset<3) { + core.ui.drawSLPanel(10*(page-1) + offset + 3); + } + else { + core.ui.drawSLPanel(index - 3); + } + return; + } + if (keycode==39) { // right + if (offset==5) { + core.ui.drawSLPanel(10*(page+1)+1); + } + else { + core.ui.drawSLPanel(index + 1); + } + return; + } + if (keycode==40) { // down + if (offset>=3) { + core.ui.drawSLPanel(10*(page+1) + offset - 3); + } + else { + core.ui.drawSLPanel(index + 3); + } + return; + } + if (keycode==33) { // PAGEUP + core.ui.drawSLPanel(10*(page-1) + offset); + return; + } + if (keycode==34) { // PAGEDOWN + core.ui.drawSLPanel(10*(page+1) + offset); + return; + } +} + +////// 存读档界面时,放开某个键的操作 ////// +actions.prototype.keyUpSL = function (keycode) { + + var index=core.status.event.data; + var page = parseInt(index/10), offset=index%10; + + if (keycode==27 || keycode==88 || (core.status.event.id == 'save' && keycode==83) || (core.status.event.id == 'load' && keycode==68)) { + core.ui.closePanel(); + if (!core.isPlaying()) { + core.showStartAnimate(); + } + return; + } + if (keycode==13 || keycode==32 || keycode==67) { + if (offset==0) { + core.doSL("autoSave", core.status.event.id); + } + else { + core.doSL(5*page+offset, core.status.event.id); + } + return; + } +} + +////// 系统设置界面时的点击操作 ////// +actions.prototype.clickSwitchs = function (x,y) { + if (x<5 || x>7) return; + var choices = core.status.event.ui.choices; + var topIndex = 6 - parseInt((choices.length - 1) / 2); + if (y>=topIndex && y7) return; + var choices = core.status.event.ui.choices; + var topIndex = 6 - parseInt((choices.length - 1) / 2); + if (y>=topIndex && y0) { + text+="\n当前MAX为"+ending.max+",最早由 "+(ending.username||"匿名")+" 于"+core.formatDate(new Date(1000*ending.timestamp))+"打出。"; + } + }) + }) + core.drawText(text); + } + } + else { + core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:HTTP "+xhr.status); + } + }; + xhr.ontimeout = function() { + core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:Timeout"); + } + xhr.onerror = function() { + core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:XHR Error"); + } + xhr.send(formData); + break; + case 6: + core.ui.drawHelp(); + break; + case 7: + core.ui.drawAbout(); + break; + case 8: + core.ui.closePanel(); + break; + } + } + return; +} + +////// 系统菜单栏界面时,按下某个键的操作 ////// +actions.prototype.keyDownSettings = function (keycode) { + if (keycode==38) { + core.status.event.selection--; + core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); + } + if (keycode==40) { + core.status.event.selection++; + core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); + } +} + +////// 系统菜单栏界面时,放开某个键的操作 ////// +actions.prototype.keyUpSettings = function (keycode) { + if (keycode==27 || keycode==88) { + core.ui.closePanel(); + return; + } + var choices = core.status.event.ui.choices; + if (keycode==13 || keycode==32 || keycode==67) { + var topIndex = 6 - parseInt((choices.length - 1) / 2); + this.clickSettings(6, topIndex+core.status.event.selection); + } +} + +////// 同步存档界面时的点击操作 ////// +actions.prototype.clickSyncSave = function (x,y) { + if (x<5 || x>7) return; + var choices = core.status.event.ui.choices; + var topIndex = 6 - parseInt((choices.length - 1) / 2); + if (y>=topIndex && y=1;i--) { + if (core.getLocalStorage("save"+i, null)==null) + index=i; + else break; + } + core.setLocalStorage("save"+index, data); + core.drawText("同步成功!\n单存档已覆盖至存档"+index); + } + }, function () { + + }); + break; + case 4: + core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5route", JSON.stringify({ + 'name': core.firstData.name, + 'hard': core.status.hard, + 'route': core.encodeRoute(core.status.route) + })); + break; + case 5: + core.status.event.selection=0; + core.ui.drawStorageRemove(); + break; + case 6: + core.status.event.selection=3; + core.ui.drawSettings(); + break; + + } + } + return; +} + +////// 同步存档界面时,按下某个键的操作 ////// +actions.prototype.keyDownSyncSave = function (keycode) { + if (keycode==38) { + core.status.event.selection--; + core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); + } + if (keycode==40) { + core.status.event.selection++; + core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); + } +} + +////// 同步存档界面时,放开某个键的操作 ////// +actions.prototype.keyUpSyncSave = function (keycode) { + if (keycode==27 || keycode==88) { + core.status.event.selection=2; + core.ui.drawSettings(); + return; + } + var choices = core.status.event.ui.choices; + if (keycode==13 || keycode==32 || keycode==67) { + var topIndex = 6 - parseInt((choices.length - 1) / 2); + this.clickSyncSave(6, topIndex+core.status.event.selection); + } +} + +////// 同步存档选择界面时的点击操作 ////// +actions.prototype.clickSyncSelect = function (x, y) { + if (x<5 || x>7) return; + var choices = core.status.event.ui.choices; + + var topIndex = 6 - parseInt((choices.length - 1) / 2); + if (y>=topIndex && y7) return; + var choices = core.status.event.ui.choices; + + var topIndex = 6 - parseInt((choices.length - 1) / 2); + + var saves=null; + + if (y>=topIndex && y=1;i--) { + saves=core.getLocalStorage("save"+i, null); + if (core.isset(saves)) { + break; + } + } + break; + case 2: + break; + } + } + if (core.isset(saves)) { + var content = { + "name": core.firstData.name, + "version": core.firstData.version, + "data": saves + } + core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5save", JSON.stringify(content)); + } + core.status.event.selection=2; + core.ui.drawSyncSave(); +} + +////// 存档下载界面时,按下某个键的操作 ////// +actions.prototype.keyDownLocalSaveSelect = function (keycode) { + if (keycode==38) { + core.status.event.selection--; + core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); + } + if (keycode==40) { + core.status.event.selection++; + core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); + } +} + +////// 存档下载界面时,放开某个键的操作 ////// +actions.prototype.keyUpLocalSaveSelect = function (keycode) { + if (keycode==27 || keycode==88) { + core.status.event.selection=0; + core.ui.drawSettings(); + return; + } + var choices = core.status.event.ui.choices; + if (keycode==13 || keycode==32 || keycode==67) { + var topIndex = 6 - parseInt((choices.length - 1) / 2); + this.clickLocalSaveSelect(6, topIndex+core.status.event.selection); + } +} + +////// 存档删除界面时的点击操作 ////// +actions.prototype.clickStorageRemove = function (x, y) { + if (x<5 || x>7) return; + var choices = core.status.event.ui.choices; + + var topIndex = 6 - parseInt((choices.length - 1) / 2); + + if (y>=topIndex && y=1 && x<=11) { + core.ui.closePanel(); + core.keyUp(112+x-1); // F1-F12: 112-122 + } + if (y==4 && x>=1 && x<=10) { + core.ui.closePanel(); + core.keyUp(x==10?48:48+x); // 1-9: 49-57; 0: 48 + } + // 字母 + var lines = [ + ["Q","W","E","R","T","Y","U","I","O","P"], + ["A","S","D","F","G","H","J","K","L"], + ["Z","X","C","V","B","N","M"], + ]; + if (y==5 && x>=1 && x<=10) { + core.ui.closePanel(); + core.keyUp(lines[0][x-1].charCodeAt(0)); + } + if (y==6 && x>=1 && x<=9) { + core.ui.closePanel(); + core.keyUp(lines[1][x-1].charCodeAt(0)); + } + if (y==7 && x>=1 && x<=7) { + core.ui.closePanel(); + core.keyUp(lines[2][x-1].charCodeAt(0)); + } + if (y==8 && x>=1 && x<=11) { + core.ui.closePanel(); + if (x==1) core.keyUp(189); // - + if (x==2) core.keyUp(187); // = + if (x==3) core.keyUp(219); // [ + if (x==4) core.keyUp(221); // ] + if (x==5) core.keyUp(220); // \ + if (x==6) core.keyUp(186); // ; + if (x==7) core.keyUp(222); // ' + if (x==8) core.keyUp(188); // , + if (x==9) core.keyUp(190); // . + if (x==10) core.keyUp(191); // / + if (x==11) core.keyUp(192); // ` + } + if (y==9 && x>=1 && x<=10) { + core.ui.closePanel(); + if (x==1) core.keyUp(27); // ESC + if (x==2) core.keyUp(9); // TAB + if (x==3) core.keyUp(20); // CAPS + if (x==4) core.keyUp(16); // SHIFT + if (x==5) core.keyUp(17); // CTRL + if (x==6) core.keyUp(18); // ALT + if (x==7) core.keyUp(32); // SPACE + if (x==8) core.keyUp(8); // BACKSPACE + if (x==9) core.keyUp(13); // ENTER + if (x==10) core.keyUp(46); // DEL + } + if (y==10 && x>=9 && x<=11) + core.ui.closePanel(); +} + +////// 光标界面时的点击操作 ////// +actions.prototype.clickCursor = function (x,y) { + + if (x==core.status.automaticRoute.cursorX && y==core.status.automaticRoute.cursorY) { + core.ui.closePanel(); + core.onclick(x,y,[]); + return; + } + core.status.automaticRoute.cursorX=x; + core.status.automaticRoute.cursorY=y; + core.ui.drawCursor(); +} + +////// 光标界面时,按下某个键的操作 ////// +actions.prototype.keyDownCursor = function (keycode) { + if (keycode==37) { // left + core.status.automaticRoute.cursorX--; + core.ui.drawCursor(); + return; + } + if (keycode==38) { // up + core.status.automaticRoute.cursorY--; + core.ui.drawCursor(); + return; + } + if (keycode==39) { // right + core.status.automaticRoute.cursorX++; + core.ui.drawCursor(); + return; + } + if (keycode==40) { // down + core.status.automaticRoute.cursorY++; + core.ui.drawCursor(); + return; + } +} + +////// 光标界面时,放开某个键的操作 ////// +actions.prototype.keyUpCursor = function (keycode) { + if (keycode==27 || keycode==88) { + core.ui.closePanel(); + return; + } + if (keycode==13 || keycode==32 || keycode==67 || keycode==69) { + core.ui.closePanel(); + core.onclick(core.status.automaticRoute.cursorX, core.status.automaticRoute.cursorY, []); + return; + } +} + +////// “关于”界面时的点击操作 ////// +actions.prototype.clickAbout = function () { + if (core.isPlaying()) + core.ui.closePanel(); + else + core.restart(); +} diff --git a/libs/control.js b/libs/control.js new file mode 100644 index 00000000..4a0fdd2d --- /dev/null +++ b/libs/control.js @@ -0,0 +1,2491 @@ +/* +control.js:游戏主要逻辑控制 +主要负责status相关内容,以及各种变量获取/存储 +寻路算法和人物行走也在此文件内 + */ + +function control() { + this.init(); +} + +control.prototype.init = function () { + +} + +////// 设置requestAnimationFrame ////// +control.prototype.setRequestAnimationFrame = function () { + + (function() { + var lastTime = 0; + var vendors = ['webkit', 'moz']; + for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; + window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || // Webkit中此取消方法的名字变了 + window[vendors[x] + 'CancelRequestAnimationFrame']; + } + + if (!window.requestAnimationFrame) { + window.requestAnimationFrame = function(callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16.7 - (currTime - lastTime)); + var id = window.setTimeout(function() { + callback(currTime + timeToCall); + }, timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + } + if (!window.cancelAnimationFrame) { + window.cancelAnimationFrame = function(id) { + clearTimeout(id); + }; + } + }()); + + core.animateFrame.speed = core.values.animateSpeed; + core.animateFrame.background = core.canvas.ui.createPattern(core.material.ground, "repeat"); + + var scan = { + 'up': {'x': 0, 'y': -1}, + 'left': {'x': -1, 'y': 0}, + 'down': {'x': 0, 'y': 1}, + 'right': {'x': 1, 'y': 0} + }; + + var draw = function(timestamp) { + + core.animateFrame.globalTime = core.animateFrame.globalTime||timestamp; + core.animateFrame.boxTime = core.animateFrame.boxTime||timestamp; + core.animateFrame.moveTime = core.animateFrame.moveTime||timestamp; + core.animateFrame.weather.time = core.animateFrame.weather.time||timestamp; + + // Global Animate + if (core.animateFrame.globalAnimate && core.isPlaying()) { + + if (timestamp-core.animateFrame.globalTime>core.animateFrame.speed && core.isset(core.status.globalAnimateObjs)) { + + for (var a = 0; a < core.status.globalAnimateObjs.length; a++) { + var obj = core.status.globalAnimateObjs[a]; + obj.status = (obj.status+1)%(obj.event.animate||1); + core.drawBlock(obj, obj.status); + } + + core.animateFrame.globalTime = timestamp; + } + } + + // Box + if (timestamp-core.animateFrame.boxTime>core.animateFrame.speed && core.isset(core.status.boxAnimateObjs) && core.status.boxAnimateObjs.length>0) { + core.drawBoxAnimate(); + core.animateFrame.boxTime = timestamp; + } + + // Hero move + if (timestamp-core.animateFrame.moveTime>16 && core.isset(core.status.heroMoving) && core.status.heroMoving>0) { + var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'), direction = core.getHeroLoc('direction'); + if (core.status.heroMoving<=4) { + core.drawHero(direction, x, y, 'leftFoot', 4*core.status.heroMoving*scan[direction].x, 4*core.status.heroMoving*scan[direction].y); + } + else if (core.status.heroMoving<=8) { + core.drawHero(direction, x, y, 'rightFoot', 4*core.status.heroMoving*scan[direction].x, 4*core.status.heroMoving*scan[direction].y); + } + core.animateFrame.moveTime = timestamp; + } + + // weather + if (core.isPlaying() && timestamp-core.animateFrame.weather.time>30) { + if (core.animateFrame.weather.type == 'rain' && core.animateFrame.weather.level > 0) { + + core.clearMap('weather', 0, 0, 416, 416); + + core.canvas.weather.strokeStyle = 'rgba(174,194,224,0.8)'; + core.canvas.weather.lineWidth = 1; + core.canvas.weather.lineCap = 'round'; + + core.animateFrame.weather.nodes.forEach(function (p) { + core.canvas.weather.beginPath(); + core.canvas.weather.moveTo(p.x, p.y); + core.canvas.weather.lineTo(p.x + p.l * p.xs, p.y + p.l * p.ys); + core.canvas.weather.stroke(); + + p.x += p.xs; + p.y += p.ys; + if (p.x > 416 || p.y > 416) { + p.x = Math.random() * 416; + p.y = -10; + } + + }) + + core.canvas.weather.fill(); + + } + else if (core.animateFrame.weather.type == 'snow' && core.animateFrame.weather.level > 0) { + + core.clearMap('weather', 0, 0, 416, 416); + + core.canvas.weather.fillStyle = "rgba(255, 255, 255, 0.8)"; + core.canvas.weather.beginPath(); + + if (!core.isset(core.animateFrame.weather.data)) + core.animateFrame.weather.data = 0; + core.animateFrame.weather.data += 0.01; + + var angle = core.animateFrame.weather.data; + core.animateFrame.weather.nodes.forEach(function (p) { + core.canvas.weather.moveTo(p.x, p.y); + core.canvas.weather.arc(p.x, p.y, p.r, 0, Math.PI * 2, true); + + // update + p.x += Math.sin(angle) * 2; + p.y += Math.cos(angle + p.d) + 1 + p.r / 2; + + if (p.x > 416 + 5 || p.x < -5 || p.y > 416) { + if (Math.random() > 1 / 3) { + p.x = Math.random() * 416; + p.y = -10; + } + else { + if (Math.sin(angle) > 0) { + p.x = -5; + p.y = Math.random() * 416; + } + else { + p.x = 416 + 5; + p.y = Math.random() * 416; + } + } + } + + }) + + core.canvas.weather.fill(); + + } + core.animateFrame.weather.time = timestamp; + + } + window.requestAnimationFrame(draw); + } + window.requestAnimationFrame(draw); +} + +////// 显示游戏开始界面 ////// +control.prototype.showStartAnimate = function (callback) { + core.dom.startPanel.style.opacity=1; + core.dom.startPanel.style.display="block"; + core.dom.startTop.style.opacity=1; + core.dom.startTop.style.display="block"; + core.dom.startButtonGroup.style.display = 'none'; + core.dom.startButtons.style.display = 'block'; + core.dom.levelChooseButtons.style.display = 'none'; + core.dom.curtain.style.background = "#000000"; + core.dom.curtain.style.opacity = 0; + core.status.played = false; + core.clearStatus(); + core.clearMap('all'); + + var opacityVal = 1; + var startAnimate = window.setInterval(function () { + opacityVal -= 0.03; + if (opacityVal < 0) { + clearInterval(startAnimate); + core.dom.startTop.style.display = 'none'; + // core.playGame(); + core.dom.startButtonGroup.style.display = 'block'; + if (core.isset(callback)) callback(); + } + core.dom.startTop.style.opacity = opacityVal; + }, 20); +} + +////// 隐藏游戏开始界面 ////// +control.prototype.hideStartAnimate = function (callback) { + var opacityVal = 1; + var startAnimate = window.setInterval(function () { + opacityVal -= 0.03; + if (opacityVal < 0) { + clearInterval(startAnimate); + core.dom.startPanel.style.display = 'none'; + if (core.isset(callback)) callback(); + } + core.dom.startPanel.style.opacity = opacityVal; + }, 20); +} + +////// 游戏是否已经开始 ////// +control.prototype.isPlaying = function() { + return core.isset(core.status.played) && core.status.played; +} + +////// 清除游戏状态和数据 ////// +control.prototype.clearStatus = function() { + // 停止各个Timeout和Interval + for (var i in core.timeout) { + clearTimeout(core.timeout[i]); + core.timeout[i] = null; + } + for (var i in core.interval) { + clearInterval(core.interval[i]); + core.interval[i] = null; + } + core.status = {}; + core.clearStatusBar(); + core.resize(main.dom.body.clientWidth, main.dom.body.clientHeight); +} + +////// 重置游戏状态和初始数据 ////// +control.prototype.resetStatus = function(hero, hard, floorId, route, maps) { + + this.clearStatus(); + + // 初始化status + core.status = core.clone(core.initStatus); + core.status.played = true; + // 初始化maps + core.status.floorId = floorId; + core.status.maps = core.clone(maps); + // 初始化怪物 + core.material.enemys = core.clone(core.enemys.getEnemys()); + // 初始化人物属性 + core.status.hero = core.clone(hero); + core.status.hard = hard; + // 初始化路线 + if (core.isset(route)) + core.status.route = route; + // 保存的Index + core.status.saveIndex = core.getLocalStorage('saveIndex2', 1); + +} + +////// 开始游戏 ////// +control.prototype.startGame = function (hard, callback) { + console.log('开始游戏'); + + this.resetStatus(core.firstData.hero, hard, core.firstData.floorId, null, core.initStatus.maps); + + core.changeFloor(core.status.floorId, null, core.firstData.hero.loc, null, function() { + if (core.isset(callback)) callback(); + }, true); + + setTimeout(function () { + // Upload + var formData = new FormData(); + formData.append('type', 'people'); + formData.append('name', core.firstData.name); + formData.append('version', core.firstData.version); + formData.append('platform', core.platform.isPC?"PC":core.platform.isAndroid?"Android":core.platform.isIOS?"iOS":""); + formData.append('hard', hard); + formData.append('hardCode', core.getFlag('hard', 0)); + + core.utils.http("POST", "/games/upload.php", formData); + }) + +} + +////// 重新开始游戏;此函数将回到标题页面 ////// +control.prototype.restart = function() { + this.showStartAnimate(); + if (core.bgms.length>0) + core.playBgm(core.bgms[0]); +} + + + + + + +/////////////////////// 寻路算法 & 人物行走控制 /////////////////////// + +////// 清除自动寻路路线 ////// +control.prototype.clearAutomaticRouteNode = function (x, y) { + if (core.status.event.id==null) + core.canvas.ui.clearRect(x * 32 + 5, y * 32 + 5, 27, 27); +} + +////// 停止自动寻路操作 ////// +control.prototype.stopAutomaticRoute = function () { + if (!core.status.played) { + return; + } + core.status.automaticRoute.autoHeroMove = false; + core.status.automaticRoute.autoStep = 0; + core.status.automaticRoute.destStep = 0; + core.status.automaticRoute.movedStep = 0; + core.status.automaticRoute.autoStepRoutes = []; + core.status.automaticRoute.destX=null; + core.status.automaticRoute.destY=null; + core.status.automaticRoute.lastDirection = null; + core.stopHero(); + if (core.status.automaticRoute.moveStepBeforeStop.length==0) + core.canvas.ui.clearRect(0, 0, 416, 416); +} + +////// 继续剩下的自动寻路操作 ////// +control.prototype.continueAutomaticRoute = function () { + // 此函数只应由events.afterOpenDoor和events.afterBattle调用 + var moveStep = core.status.automaticRoute.moveStepBeforeStop; + //core.status.automaticRoute.moveStepBeforeStop = []; + if(moveStep.length===0 || (moveStep.length===1 && moveStep[0].step===1)) { + core.status.automaticRoute.moveStepBeforeStop = []; + } + else { + core.setAutoHeroMove(moveStep); + } +} + +////// 清空剩下的自动寻路列表 ////// +control.prototype.clearContinueAutomaticRoute = function () { + core.canvas.ui.clearRect(0, 0, 416, 416); + core.status.automaticRoute.moveStepBeforeStop=[]; +} + +////// 设置自动寻路路线 ////// +control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) { + if (!core.status.played || core.status.lockControl) { + return; + } + // 正在寻路中 + if (core.status.automaticRoute.autoHeroMove) { + var lastX = core.status.automaticRoute.destX, lastY=core.status.automaticRoute.destY; + core.stopAutomaticRoute(); + if (lastX==destX && lastY==destY) { + core.status.automaticRoute.moveDirectly = true; + setTimeout(function () { + if (core.status.automaticRoute.moveDirectly && core.status.heroMoving==0) { + if (core.canMoveDirectly(destX, destY)) { + core.clearMap('hero', 0, 0, 416, 416); + core.setHeroLoc('x', destX); + core.setHeroLoc('y', destY); + core.drawHero(core.getHeroLoc('direction'), core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); + core.status.route.push("move:"+destX+":"+destY); + } + } + core.status.automaticRoute.moveDirectly = false; + }, 100); + } + return; + } + if (destX == core.status.hero.loc.x && destY == core.status.hero.loc.y && stepPostfix.length==0) { + if (core.timeout.turnHeroTimeout==null) { + core.timeout.turnHeroTimeout = setTimeout(function() { + core.turnHero(); + clearTimeout(core.timeout.turnHeroTimeout); + core.timeout.turnHeroTimeout = null; + }, 250); + } + else { + clearTimeout(core.timeout.turnHeroTimeout); + core.timeout.turnHeroTimeout = null; + core.getNextItem(); + } + return; + } + var step = 0; + var tempStep = null; + var moveStep; + if (!(moveStep = core.automaticRoute(destX, destY))) { + if (destX == core.status.hero.loc.x && destY == core.status.hero.loc.y){ + moveStep=[]; + } else { + core.canvas.ui.clearRect(0, 0, 416, 416); + return; + } + } + moveStep=moveStep.concat(stepPostfix); + core.status.automaticRoute.destX=destX; + core.status.automaticRoute.destY=destY; + core.canvas.ui.save(); + core.canvas.ui.clearRect(0, 0, 416, 416); + core.canvas.ui.fillStyle = '#bfbfbf'; + core.canvas.ui.strokeStyle = '#bfbfbf'; + core.canvas.ui.lineWidth = 8; + for (var m = 0; m < moveStep.length; m++) { + if (tempStep == null) { + step++; + tempStep = moveStep[m].direction; + } + else if (tempStep == moveStep[m].direction) { + step++; + } + else { + //core.status.automaticRoutingTemp.moveStep.push({'direction': tempStep, 'step': step}); + core.status.automaticRoute.autoStepRoutes.push({'direction': tempStep, 'step': step}); + step = 1; + tempStep = moveStep[m].direction; + } + if (m == moveStep.length - 1) { + // core.status.automaticRoutingTemp.moveStep.push({'direction': tempStep, 'step': step}); + core.status.automaticRoute.autoStepRoutes.push({'direction': tempStep, 'step': step}); + core.canvas.ui.fillRect(moveStep[m].x * 32 + 10, moveStep[m].y * 32 + 10, 12, 12); + } + else { + core.canvas.ui.beginPath(); + if (core.isset(moveStep[m + 1]) && tempStep != moveStep[m + 1].direction) { + if (tempStep == 'up' && moveStep[m + 1].direction == 'left' || tempStep == 'right' && moveStep[m + 1].direction == 'down') { + core.canvas.ui.moveTo(moveStep[m].x * 32 + 5, moveStep[m].y * 32 + 16); + core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 16); + core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 27); + } + else if (tempStep == 'up' && moveStep[m + 1].direction == 'right' || tempStep == 'left' && moveStep[m + 1].direction == 'down') { + core.canvas.ui.moveTo(moveStep[m].x * 32 + 27, moveStep[m].y * 32 + 16); + core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 16); + core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 27); + } + else if (tempStep == 'left' && moveStep[m + 1].direction == 'up' || tempStep == 'down' && moveStep[m + 1].direction == 'right') { + core.canvas.ui.moveTo(moveStep[m].x * 32 + 27, moveStep[m].y * 32 + 16); + core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 16); + core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 5); + } + else if (tempStep == 'right' && moveStep[m + 1].direction == 'up' || tempStep == 'down' && moveStep[m + 1].direction == 'left') { + core.canvas.ui.moveTo(moveStep[m].x * 32 + 5, moveStep[m].y * 32 + 16); + core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 16); + core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 5); + } + core.canvas.ui.stroke(); + continue; + } + switch (tempStep) { + case 'up': + case 'down': + core.canvas.ui.beginPath(); + core.canvas.ui.moveTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 5); + core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 27); + core.canvas.ui.stroke(); + break; + case 'left': + case 'right': + core.canvas.ui.beginPath(); + core.canvas.ui.moveTo(moveStep[m].x * 32 + 5, moveStep[m].y * 32 + 16); + core.canvas.ui.lineTo(moveStep[m].x * 32 + 27, moveStep[m].y * 32 + 16); + core.canvas.ui.stroke(); + break; + } + } + } + core.canvas.ui.restore(); + + // 立刻移动 + core.setAutoHeroMove(); + +} + +////// 自动寻路算法,找寻最优路径 ////// +control.prototype.automaticRoute = function (destX, destY) { + var startX = core.getHeroLoc('x'); + var startY = core.getHeroLoc('y'); + var scan = { + 'up': {'x': 0, 'y': -1}, + 'left': {'x': -1, 'y': 0}, + 'down': {'x': 0, 'y': 1}, + 'right': {'x': 1, 'y': 0} + }; + var queue = []; + var nowDeep = 0; + var route = []; + var ans = [] + + if (destX == startX && destY == startY) return false; + queue.push(13 * startX + startY); + queue.push(-1); + route[13 * startX + startY] = ''; + + while (queue.length != 1) { + var f = queue.shift(); + if (f===-1) {nowDeep+=1;queue.push(-1);continue;} + var deep = ~~(f/169); + if (deep!==nowDeep) {queue.push(f);continue;} + f=f%169; + var nowX = parseInt(f / 13), nowY = f % 13; + var nowIsArrow = false, nowId, nowBlock = core.getBlock(nowX,nowY); + for (var direction in scan) { + if (!core.canMoveHero(nowX, nowY, direction)) + continue; + + var nx = nowX + scan[direction].x; + var ny = nowY + scan[direction].y; + + if (nx<0 || nx>12 || ny<0 || ny>12) continue; + + var nid = 13 * nx + ny; + + if (core.isset(route[nid])) continue; + + var deepAdd=1; + + var nextId, nextBlock = core.getBlock(nx,ny); + if (nextBlock!=null){ + nextId = nextBlock.block.event.id; + // 绕过亮灯(因为只有一次通行机会很宝贵) + if(nextId == "light") deepAdd=100; + // 绕过路障 + if (nextId.substring(nextId.length-3)=="Net") deepAdd=core.values.lavaDamage; + // 绕过血瓶 + if (!core.flags.potionWhileRouting && nextId.substring(nextId.length-6)=="Potion") deepAdd=20; + // 绕过传送点 + if (nextBlock.block.event.trigger == 'changeFloor') deepAdd = 10; + } + if (core.status.checkBlock.damage[nid]>0) + deepAdd = core.status.checkBlock.damage[nid]; + + if (nx == destX && ny == destY) { + route[nid] = direction; + break; + } + if (core.noPassExists(nx, ny)) + continue; + + route[nid] = direction; + queue.push(169*(nowDeep+deepAdd)+nid); + } + if (core.isset(route[13 * destX + destY])) break; + } + + if (!core.isset(route[13 * destX + destY])) { + return false; + } + + var nowX = destX, nowY = destY; + while (nowX != startX || nowY != startY) { + var dir = route[13 * nowX + nowY]; + ans.push({'direction': dir, 'x': nowX, 'y': nowY}); + nowX -= scan[dir].x; + nowY -= scan[dir].y; + } + + ans.reverse(); + return ans; +} + +////// 显示离散的寻路点 ////// +control.prototype.fillPosWithPoint = function (pos) { + core.fillRect('ui', pos.x*32+12,pos.y*32+12,8,8, '#bfbfbf'); +} + +////// 设置勇士的自动行走路线 ////// +control.prototype.setAutoHeroMove = function (steps) { + steps=steps||core.status.automaticRoute.autoStepRoutes; + if (steps.length == 0) { + return; + } + core.status.automaticRoute.autoStepRoutes=steps; + core.status.automaticRoute.autoHeroMove = true; + core.status.automaticRoute.autoStep = 1; + core.status.automaticRoute.destStep = steps[0].step; + core.moveHero(steps[0].direction); +} + +////// 设置行走的效果动画 ////// +control.prototype.setHeroMoveInterval = function (direction, x, y, callback) { + if (core.status.heroMoving>0) { + return; + } + core.status.heroMoving=1; + var scan = { + 'up': {'x': 0, 'y': -1}, + 'left': {'x': -1, 'y': 0}, + 'down': {'x': 0, 'y': 1}, + 'right': {'x': 1, 'y': 0} + }; + core.interval.heroMoveInterval = window.setInterval(function () { + core.status.heroMoving++; + if (core.status.heroMoving==8) { + core.setHeroLoc('x', x+scan[direction].x); + core.setHeroLoc('y', y+scan[direction].y); + core.moveOneStep(); + core.clearMap('hero', 0, 0, 416, 416); + core.drawHero(direction, core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); + //if (core.status.heroStop) + // core.drawHero(direction, core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); + clearInterval(core.interval.heroMoveInterval); + core.status.heroMoving = 0; + if (core.isset(callback)) callback(); + } + }, 12.5 / core.status.replay.speed); +} + +////// 实际每一步的行走过程 ////// +control.prototype.moveAction = function (callback) { + if (core.interval.openDoorAnimate!=null) return; // 开门判断 + if (core.status.heroMoving>0) return; + var scan = { + 'up': {'x': 0, 'y': -1}, + 'left': {'x': -1, 'y': 0}, + 'down': {'x': 0, 'y': 1}, + 'right': {'x': 1, 'y': 0} + }; + var direction = core.getHeroLoc('direction'); + var x = core.getHeroLoc('x'); + var y = core.getHeroLoc('y'); + var noPass = core.noPass(x + scan[direction].x, y + scan[direction].y), canMove = core.canMoveHero(); + if (noPass || !canMove) { + if (core.status.event.id!='ski') + core.status.route.push(direction); + core.status.automaticRoute.moveStepBeforeStop = []; + if (canMove) // 非箭头:触发 + core.trigger(x + scan[direction].x, y + scan[direction].y); + core.drawHero(direction, x, y, 'stop'); + + if (core.status.automaticRoute.moveStepBeforeStop.length==0) { + core.clearContinueAutomaticRoute(); + core.stopAutomaticRoute(); + } + if (core.isset(callback)) + callback(); + } + else { + core.setHeroMoveInterval(direction, x, y, function () { + if (core.status.automaticRoute.autoHeroMove) { + core.status.automaticRoute.movedStep++; + core.status.automaticRoute.lastDirection = core.getHeroLoc('direction'); + if (core.status.automaticRoute.destStep == core.status.automaticRoute.movedStep) { + if (core.status.automaticRoute.autoStep == core.status.automaticRoute.autoStepRoutes.length) { + core.clearContinueAutomaticRoute(); + core.stopAutomaticRoute(); + } + else { + core.status.automaticRoute.movedStep = 0; + core.status.automaticRoute.destStep = core.status.automaticRoute.autoStepRoutes[core.status.automaticRoute.autoStep].step; + core.setHeroLoc('direction', core.status.automaticRoute.autoStepRoutes[core.status.automaticRoute.autoStep].direction); + core.status.automaticRoute.autoStep++; + } + } + } + else if (core.status.heroStop) { + core.drawHero(core.getHeroLoc('direction'), core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); + } + if (core.status.event.id!='ski') + core.status.route.push(direction); + core.trigger(core.getHeroLoc('x'), core.getHeroLoc('y')); + core.checkBlock(); + if (core.isset(callback)) callback(); + }); + } +} + +////// 转向 ////// +control.prototype.turnHero = function() { + if (core.status.hero.loc.direction == 'up') core.status.hero.loc.direction = 'right'; + else if (core.status.hero.loc.direction == 'right') core.status.hero.loc.direction = 'down'; + else if (core.status.hero.loc.direction == 'down') core.status.hero.loc.direction = 'left'; + else if (core.status.hero.loc.direction == 'left') core.status.hero.loc.direction = 'up'; + core.drawHero(core.status.hero.loc.direction, core.status.hero.loc.x, core.status.hero.loc.y, 'stop', 0, 0); + core.canvas.ui.clearRect(0, 0, 416, 416); + core.status.route.push("turn"); +} + +////// 让勇士开始移动 ////// +control.prototype.moveHero = function (direction, callback) { + // 如果正在移动,直接return + if (core.status.heroMoving>0) return; + if (core.isset(direction)) + core.setHeroLoc('direction', direction); + if (!core.isset(callback)) { // 如果不存在回调函数,则使用heroMoveTrigger + core.status.heroStop = false; + core.status.automaticRoute.moveDirectly = false; + + var doAction = function () { + if (!core.status.heroStop) { + core.moveAction(); + setTimeout(doAction, 50); + } + else { + core.stopHero(); + } + } + doAction(); + } + else { // 否则,只向某个方向移动一步,然后调用callback + core.moveAction(function () { + callback(); + }) + } +} + +/////// 使用事件让勇士移动。这个函数将不会触发任何事件 ////// +control.prototype.eventMoveHero = function(steps, time, callback) { + + time = time || 100; + + core.clearMap('ui', 0, 0, 416, 416); + core.setAlpha('ui', 1.0); + + // 要运行的轨迹:将steps展开 + var moveSteps=[]; + steps.forEach(function (e) { + if (typeof e=="string") { + moveSteps.push(e); + } + else { + if (!core.isset(e.value)) { + moveSteps.push(e.direction) + } + else { + for (var i=0;i12 || ny<0 || ny>12) continue; + if (!zoneSquare && Math.abs(dx)+Math.abs(dy)>range) continue; + core.status.checkBlock.damage[13*nx+ny]+=enemy.value; + } + } + } + // 存在阻击 + if (core.enemys.hasSpecial(enemy.special, 18)) { + for (var dx=-1;dx<=1;dx++) { + for (var dy=-1;dy<=1;dy++) { + if (dx==0 && dy==0) continue; + var nx=x+dx, ny=y+dy; + if (nx<0 || nx>12 || ny<0 || ny>12 || Math.abs(dx)+Math.abs(dy)>1) continue; + core.status.checkBlock.damage[13*nx+ny]+=enemy.value; + } + } + } + } + } + } + + + // Step3: 更新夹击点坐标,并将夹击伤害加入到damage中 + core.status.checkBlock.betweenAttack = []; // 记录(x,y)点是否有夹击 + for (var x=0;x<13;x++) { + for (var y=0;y<13;y++) { + var has=false; + if (x>0 && x<12) { + var id1=core.status.checkBlock.map[13*(x-1)+y], + id2=core.status.checkBlock.map[13*(x+1)+y]; + if (core.isset(id1) && core.isset(id2) && id1==id2) { + var enemy = core.enemys.getEnemys(id1); + if (core.enemys.hasSpecial(enemy.special, 16)) { + has = true; + } + } + } + if (y>0 && y<12) { + var id1=core.status.checkBlock.map[13*x+y-1], + id2=core.status.checkBlock.map[13*x+y+1]; + if (core.isset(id1) && core.isset(id2) && id1==id2) { + var enemy = core.enemys.getEnemys(id1); + if (core.enemys.hasSpecial(enemy.special, 16)) { + has = true; + } + } + } + // 存在夹击 + if (has) { + core.status.checkBlock.betweenAttack[13*x+y]=true; + var leftHp = core.status.hero.hp - core.status.checkBlock.damage[13*x+y]; + if (leftHp>1) + core.status.checkBlock.damage[13*x+y] += parseInt((leftHp+(core.flags.betweenAttackCeil?0:1))/2); + } + } + } +} + +////// 检查并执行领域、夹击、阻击事件 ////// +control.prototype.checkBlock = function () { + var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'); + var damage = core.status.checkBlock.damage[13*x+y]; + if (damage>0) { + core.status.hero.hp -= damage; + + // 检查阻击事件 + var snipe = []; + var scan = { + 'up': {'x': 0, 'y': -1}, + 'left': {'x': -1, 'y': 0}, + 'down': {'x': 0, 'y': 1}, + 'right': {'x': 1, 'y': 0} + } + for (var direction in scan) { + var nx = x+scan[direction].x, ny=y+scan[direction].y; + if (nx<0 || nx>12 || ny<0 || ny>12) continue; + var id=core.status.checkBlock.map[13*nx+ny]; + if (core.isset(id)) { + var enemy = core.enemys.getEnemys(id); + if (core.isset(enemy) && core.enemys.hasSpecial(enemy.special, 18)) { + snipe.push({'direction': direction, 'x': nx, 'y': ny}); + } + } + } + + if (core.status.checkBlock.betweenAttack[13*x+y] && damage>0) { + core.drawTip('受到夹击,生命变成一半'); + } + // 阻击 + else if (snipe.length>0 && damage>0) { + core.drawTip('受到阻击伤害'+damage+'点'); + } + else if (damage>0) { + core.drawTip('受到领域伤害'+damage+'点'); + } + + core.playSound('zone.ogg'); + core.drawAnimate("zone", x, y); + + if (core.status.hero.hp<=0) { + core.status.hero.hp=0; + core.updateStatusBar(); + core.events.lose('zone'); + return; + } + snipe = snipe.filter(function (t) { + var x=t.x, y=t.y, direction = t.direction; + var nx = x+scan[direction].x, ny=y+scan[direction].y; + + return nx>=0 && nx<=12 && ny>=0 && ny<=12 && core.getBlock(nx, ny, core.status.floorId, false)==null; + }); + core.updateStatusBar(); + if (snipe.length>0) + core.snipe(snipe); + } +} + +////// 阻击事件(动画效果) ////// +control.prototype.snipe = function (snipes) { + + var scan = { + 'up': {'x': 0, 'y': -1}, + 'left': {'x': -1, 'y': 0}, + 'down': {'x': 0, 'y': 1}, + 'right': {'x': 1, 'y': 0} + }; + + snipes.forEach(function (snipe) { + var x=snipe.x, y=snipe.y, direction = snipe.direction; + snipe.nx = x+scan[snipe.direction].x; + snipe.ny = y+scan[snipe.direction].y; + + core.removeGlobalAnimate(x, y); + + var block = core.getBlock(x,y).block; + + var cls = block.event.cls; + var height = block.event.height || 32; + + snipe.animate = block.event.animate || 1; + snipe.blockIcon = core.material.icons[cls][block.event.id]; + snipe.blockImage = core.material.images[cls]; + snipe.height = height; + var damage = core.enemys.getDamage(block.event.id); + + var color = "#000000"; + if (damage <= 0) color = '#00FF00'; + else if (damage < core.status.hero.hp / 3) color = '#FFFFFF'; + else if (damage < core.status.hero.hp * 2 / 3) color = '#FFFF00'; + else if (damage < core.status.hero.hp) color = '#FF7F00'; + else color = '#FF0000'; + + if (damage >= 999999999) damage = "???"; + else if (damage > 100000) damage = (damage / 10000).toFixed(1) + "w"; + + snipe.damage = damage; + snipe.color = color; + snipe.block = core.clone(block); + }) + + var finishSnipe = function () { + snipes.forEach(function (t) { + core.removeBlock(t.x, t.y); + var nBlock = core.clone(t.block); + nBlock.x = t.nx; nBlock.y = t.ny; + core.status.thisMap.blocks.push(nBlock); + core.drawBlock(nBlock); + core.addGlobalAnimate(nBlock); + }); + core.syncGlobalAnimate(); + core.updateStatusBar(); + return; + } + + if (core.status.replay.replaying) { + finishSnipe(); + } + else { + core.waitHeroToStop(function() { + + core.lockControl(); + + var time = 500, step = 0; + + var animateCurrent = 0; + var animateTime = 0; + + core.canvas.fg.textAlign = 'left'; + + var animate=window.setInterval(function() { + + step++; + animateTime += time / 16; + if (animateTime >= core.values.animateSpeed) { + animateCurrent++; + animateTime = 0; + } + + snipes.forEach(function (snipe) { + var x=snipe.x, y=snipe.y, direction = snipe.direction; + + var dx = scan[direction].x*2*step, dy = scan[direction].y*2*step; + var nowX = 32*x+dx, nowY = 32*y+dy; + + // 清空上一次 + core.clearMap('fg', nowX-2*scan[direction].x, nowY-2*scan[direction].y, 32, 32); + core.canvas.event.clearRect(nowX-2*scan[direction].x, nowY-2*scan[direction].y, 32, 32); + core.canvas.event2.clearRect(nowX-2*scan[direction].x, nowY-2*scan[direction].y-32, 32, 32) + + core.drawBlock(snipe.block, animateCurrent, dx, dy); + + if (core.hasItem('book')) { + // drawFG + core.setFillStyle('fg', '#000000'); + core.canvas.fg.fillText(snipe.damage, nowX + 2, nowY + 30); + core.canvas.fg.fillText(snipe.damage, nowX, nowY + 30); + core.canvas.fg.fillText(snipe.damage, nowX + 2, nowY + 32); + core.canvas.fg.fillText(snipe.damage, nowX, nowY + 32); + + core.setFillStyle('fg', snipe.color); + core.canvas.fg.fillText(snipe.damage, nowX + 1, nowY + 31); + } + + }) + + if (step==16) { // 移动完毕 + clearInterval(animate); + finishSnipe(); + // 不存在自定义事件 + if (core.status.event.id==null) + core.unLockControl(); + } + }, time/16); + }); + } +} + +////// 更改天气效果 ////// +control.prototype.setWeather = function (type, level) { + + // 非雨雪 + if (type!='rain' && type!='snow') { + core.clearMap('weather', 0, 0, 416, 416) + core.animateFrame.weather.type = null; + core.animateFrame.weather.level = 0; + core.animateFrame.weather.nodes = []; + return; + } + + level = parseInt(level); + + // 当前天气:则忽略 + if (type==core.animateFrame.weather.type && + (!core.isset(level) || 20*level==core.animateFrame.weather.level)) { + return; + } + + if (!core.isset(level)) level=5; + if (level<1) level=1; if (level>10) level=10; + level *= 20; + + core.clearMap('weather', 0, 0, 416, 416) + core.animateFrame.weather.type = type; + core.animateFrame.weather.level = level; + + core.animateFrame.weather.nodes = []; + + if (type == 'rain') { + for (var a=0;a1) color[3]=1; + + if (time==0) { + // 直接变色 + core.dom.curtain.style.background = core.arrayToRGB(color); + core.dom.curtain.style.opacity = color[3]; + core.status.curtainColor = color; + if (core.isset(callback)) callback(); + return; + } + + var step=0; + core.status.replay.animate=true; + var changeAnimate = setInterval(function() { + step++; + + var nowAlpha = fromColor[3]+(color[3]-fromColor[3])*step/25; + var nowR = parseInt(fromColor[0]+(color[0]-fromColor[0])*step/25); + var nowG = parseInt(fromColor[1]+(color[1]-fromColor[1])*step/25); + var nowB = parseInt(fromColor[2]+(color[2]-fromColor[2])*step/25); + core.dom.curtain.style.background = core.arrayToRGB([nowR,nowG,nowB]); + core.dom.curtain.style.opacity = nowAlpha; + + if (step>=25) { + clearInterval(changeAnimate); + core.status.curtainColor = color; + core.status.replay.animate=false; + if (core.isset(callback)) callback(); + } + }, time/25); +} + +////// 更新全地图显伤 ////// +control.prototype.updateFg = function () { + + if (!core.isset(core.status.thisMap) || !core.isset(core.status.thisMap.blocks)) return; + // 更新显伤 + var mapBlocks = core.status.thisMap.blocks; + core.clearMap('fg', 0, 0, 416, 416); + // 没有怪物手册 + if (!core.hasItem('book')) return; + core.setFont('fg', "bold 11px Arial"); + var hero_hp = core.status.hero.hp; + if (core.flags.displayEnemyDamage) { + core.canvas.fg.textAlign = 'left'; + for (var b = 0; b < mapBlocks.length; b++) { + var x = mapBlocks[b].x, y = mapBlocks[b].y; + if (core.isset(mapBlocks[b].event) && mapBlocks[b].event.cls.indexOf('enemy')==0 + && !(core.isset(mapBlocks[b].enable) && !mapBlocks[b].enable)) { + + // 非系统默认的战斗事件(被覆盖) + if (mapBlocks[b].event.trigger != 'battle') { + // 判断显伤 + var event = core.floors[core.status.floorId].events[x+","+y]; + if (core.isset(event) && !(event instanceof Array)) { + if (core.isset(event.displayDamage) && !event.displayDamage) + continue; + } + } + + var id = mapBlocks[b].event.id; + + var damage = core.enemys.getDamage(id); + var color = "#000000"; + if (damage <= 0) color = '#00FF00'; + else if (damage < hero_hp / 3) color = '#FFFFFF'; + else if (damage < hero_hp * 2 / 3) color = '#FFFF00'; + else if (damage < hero_hp) color = '#FF7F00'; + else color = '#FF0000'; + + if (damage >= 999999999) damage = "???"; + else if (damage > 100000) damage = (damage / 10000).toFixed(1) + "w"; + + core.setFillStyle('fg', '#000000'); + core.canvas.fg.fillText(damage, 32 * x + 2, 32 * (y + 1) - 2); + core.canvas.fg.fillText(damage, 32 * x, 32 * (y + 1) - 2); + core.canvas.fg.fillText(damage, 32 * x + 2, 32 * (y + 1)); + core.canvas.fg.fillText(damage, 32 * x, 32 * (y + 1)); + + core.setFillStyle('fg', color); + core.canvas.fg.fillText(damage, 32 * x + 1, 32 * (y + 1) - 1); + + } + } + } + // 如果是领域&夹击 + if (core.flags.displayExtraDamage) { + core.canvas.fg.textAlign = 'center'; + for (var x=0;x<13;x++) { + for (var y=0;y<13;y++) { + var damage = core.status.checkBlock.damage[13*x+y]; + if (damage>0) { + core.setFillStyle('fg', '#000000'); + core.canvas.fg.fillText(damage, 32 * x + 17, 32 * (y + 1) - 13); + core.canvas.fg.fillText(damage, 32 * x + 15, 32 * (y + 1) - 15); + core.canvas.fg.fillText(damage, 32 * x + 17, 32 * (y + 1) - 15); + core.canvas.fg.fillText(damage, 32 * x + 15, 32 * (y + 1) - 13); + + core.setFillStyle('fg', '#FF7F00'); + core.canvas.fg.fillText(damage, 32 * x + 16, 32 * (y + 1) - 14); + } + } + } + } +} + +////// 执行一个表达式的effect操作 ////// +control.prototype.doEffect = function (expression) { + // 必须使用"+=" + var arr = expression.split("+="); + if (arr.length!=2) return; + var name=arr[0], value=core.calValue(arr[1]); + if (name.indexOf("status:")==0) { + var status=name.substring(7); + core.setStatus(status, core.getStatus(status)+value); + } + else if (name.indexOf("item:")==0) { + var itemId=name.substring(5); + core.setItem(itemId, core.itemCount(itemId)+value); + } +} + +////// 作弊 ////// +control.prototype.debug = function() { + core.setStatus('hp', 999999); + core.setStatus('atk', 10000); + core.setStatus('def', 10000); + core.setStatus('mdef', 10000); + core.setStatus('money', 10000); + core.setStatus('experience', 10000); + core.setItem('yellowKey', 50); + core.setItem('blueKey', 50); + core.setItem('redKey', 50); + core.setItem('book', 1); + core.setItem('fly', 1); + for (var i in core.status.maps) + if (core.status.maps[i].canFlyTo && core.status.hero.flyRange.indexOf(i)<0) + core.status.hero.flyRange.push(i); + core.updateStatusBar(); + core.drawTip("作弊成功"); +} + +////// 开始播放 ////// +control.prototype.startReplay = function (list) { + core.status.replay.replaying=true; + core.status.replay.pausing=false; + core.status.replay.speed=1.0; + core.status.replay.toReplay = core.clone(list); + core.status.replay.totalList = core.clone(list); + core.updateStatusBar(); + core.drawTip("开始播放"); + this.replay(); + return; +} + +////// 更改播放状态 ////// +control.prototype.triggerReplay = function () { + if (core.status.replay.pausing) this.resumeReplay(); + else this.pauseReplay(); +} + +////// 暂停播放 ////// +control.prototype.pauseReplay = function () { + if (!core.status.replay.replaying) return; + core.status.replay.pausing = true; + core.updateStatusBar(); + core.drawTip("暂停播放"); +} + +////// 恢复播放 ////// +control.prototype.resumeReplay = function () { + if (!core.status.replay.replaying) return; + core.status.replay.pausing = false; + core.updateStatusBar(); + core.drawTip("恢复播放"); + core.replay(); +} + +////// 加速播放 ////// +control.prototype.forwardReplay = function () { + if (!core.status.replay.replaying) return; + core.status.replay.speed = parseInt(10*core.status.replay.speed + 1)/10; + if (core.status.replay.speed>2.5) core.status.replay.speed=2.5; + core.drawTip("x"+core.status.replay.speed+"倍"); +} + +////// 减速播放 ////// +control.prototype.rewindReplay = function () { + if (!core.status.replay.replaying) return; + core.status.replay.speed = parseInt(10*core.status.replay.speed - 1)/10; + if (core.status.replay.speed<0.3) core.status.replay.speed=0.3; + core.drawTip("x"+core.status.replay.speed+"倍"); +} + +////// 停止播放 ////// +control.prototype.stopReplay = function () { + if (!core.status.replay.replaying) return; + core.status.replay.toReplay = []; + core.status.replay.totalList = []; + core.status.replay.replaying=false; + core.status.replay.pausing=false; + core.status.replay.speed=1.0; + core.updateStatusBar(); + core.drawTip("停止播放并恢复游戏"); +} + +////// 回放 ////// +control.prototype.replay = function () { + + if (!core.status.replay.replaying) return; // 没有回放 + if (core.status.replay.pausing) return; // 暂停状态 + if (core.status.replay.animate) return; // 正在某段动画中 + + if (core.status.replay.toReplay.length==0) { // 回放完毕 + core.stopReplay(); + core.insertAction("录像回放完毕!"); + return; + } + + var action=core.status.replay.toReplay.shift(); + + if (action=='up' || action=='down' || action=='left' || action=='right') { + core.moveHero(action, function () { + core.replay(); + }); + return; + } + else if (action.indexOf("item:")==0) { + var itemId = action.substring(5); + if (core.canUseItem(itemId)) { + var tools = Object.keys(core.status.hero.items.tools).sort(); + var constants = Object.keys(core.status.hero.items.constants).sort(); + var index; + if ((index=tools.indexOf(itemId))>=0 || (index=constants.indexOf(itemId)+100)>=100) { + core.ui.drawToolbox(index); + setTimeout(function () { + core.ui.closePanel(); + core.useItem(itemId, function () { + core.replay(); + }); + }, 750); + } + return; + } + } + else if (action.indexOf("fly:")==0) { + var floorId=action.substring(4); + var toIndex=core.status.hero.flyRange.indexOf(floorId); + var nowIndex=core.status.hero.flyRange.indexOf(core.status.floorId); + if (core.hasItem('fly') && toIndex>=0 && nowIndex>=0) { + core.ui.drawFly(toIndex); + setTimeout(function () { + core.ui.closePanel(); + var stair=toIndex0) { + var shop=core.status.shops[shopId]; + if (core.isset(shop) && shop.visited) { // 商店可用 + var choices = shop.choices; + var topIndex = 6 - parseInt(choices.length / 2); + + core.status.event.selection = parseInt(selections.shift()); + + core.events.openShop(shopId, false); + var shopInterval = setInterval(function () { + if (!core.actions.clickShop(6, topIndex+core.status.event.selection)) { + clearInterval(shopInterval); + core.stopReplay(); + core.drawTip("录像文件出错"); + return; + } + if (selections.length==0) { + clearInterval(shopInterval); + core.actions.clickShop(6, topIndex+choices.length); + core.replay(); + return; + } + core.status.event.selection = parseInt(selections.shift()); + core.events.openShop(shopId, false); + + }, 750); + return; + } + } + } + else if (action=='turn') { + core.turnHero(); + core.replay(); + return; + } + else if (action=='getNext') { + if (core.flags.enableGentleClick && core.getBlock(core.nextX(), core.nextY())!=null) { + var nextX = core.nextX(), nextY = core.nextY(); + var block = core.getBlock(nextX, nextY); + if (block!=null && block.block.event.trigger=='getItem') { + core.getItem(block.block.event.id, 1, nextX, nextY); + core.status.route.push("getNext"); + core.replay(); + return; + } + } + } + else if (action.indexOf('move:')==0) { + var pos=action.substring(5).split(":"); + var x=parseInt(pos[0]), y=parseInt(pos[1]); + if (core.canMoveDirectly(x,y)) { + core.clearMap('hero', 0, 0, 416, 416); + core.setHeroLoc('x', x); + core.setHeroLoc('y', y); + core.drawHero(core.getHeroLoc('direction'), core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); + core.status.route.push("move:"+x+":"+y); + core.replay(); + return; + } + } + else if (action.indexOf('key:')==0) { + core.actions.keyUp(parseInt(action.substring(4)), true); + core.replay(); + return; + } + + core.stopReplay(); + core.insertAction("录像文件出错"); + +} + +////// 判断当前能否进入某个事件 ////// +control.prototype.checkStatus = function (name, need, item) { + if (need && core.status.event.id == name) { + core.ui.closePanel(); + return false; + } + + if (need && core.status.lockControl) return false; + if (core.isset(item) && item && !core.hasItem(name)) { + core.drawTip("你没有" + core.material.items[name].name); + return false; + } + if (!core.status.heroStop) { + core.drawTip("请先停止勇士行动"); + return false; + } + + core.lockControl(); + core.status.event.id = name; + return true; +} + +////// 点击怪物手册时的打开操作 ////// +control.prototype.openBook = function (need) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; + + // 当前是book,且从“浏览地图”打开 + if (core.status.event.id == 'book' && core.isset(core.status.event.selection)) { + core.status.boxAnimateObjs = []; + core.ui.drawMaps(core.status.event.selection); + return; + } + + // 从“浏览地图”页面打开 + if (core.status.event.id=='viewMaps') { + need=false; + core.status.event.selection = core.status.event.data; + } + + if (!core.checkStatus('book', need, true)) + return; + core.useItem('book'); +} + +////// 点击楼层传送器时的打开操作 ////// +control.prototype.useFly = function (need) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; + if (!core.checkStatus('fly', need, true)) + return; + if (core.flags.flyNearStair && !core.nearStair()) { + core.drawTip("只有在楼梯边才能使用传送器"); + core.unLockControl(); + core.status.event.data = null; + core.status.event.id = null; + return; + } + if (!core.canUseItem('fly')) { + core.drawTip("楼层传送器好像失效了"); + core.unLockControl(); + core.status.event.data = null; + core.status.event.id = null; + return; + } + core.useItem('fly'); + return; +} + +////// 点击工具栏时的打开操作 ////// +control.prototype.openToolbox = function (need) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; + if (!core.checkStatus('toolbox', need)) + return; + core.ui.drawToolbox(); +} + +////// 点击快捷商店按钮时的打开操作 ////// +control.prototype.openQuickShop = function (need) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; + if (!core.checkStatus('selectShop', need)) + return; + core.ui.drawQuickShop(); +} + +////// 点击保存按钮时的打开操作 ////// +control.prototype.save = function(need) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; + if (!core.checkStatus('save', need)) + return; + + var saveIndex = core.status.saveIndex; + var page=parseInt((saveIndex-1)/5), offset=saveIndex-5*page; + + core.ui.drawSLPanel(10*page+offset); +} + +////// 点击读取按钮时的打开操作 ////// +control.prototype.load = function (need) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; + + var saveIndex = core.getLocalStorage('saveIndex2', 1); + var page=parseInt((saveIndex-1)/5), offset=saveIndex-5*page; + + // 游戏开始前读档 + if (!core.isPlaying()) { + core.status.event = {'id': 'load', 'data': null}; + core.status.lockControl = true; + core.dom.startPanel.style.display = 'none'; + core.ui.drawSLPanel(10*page+offset); + return; + } + + if (!core.checkStatus('load', need)) + return; + core.ui.drawSLPanel(10*page+offset); +} + +////// 点击设置按钮时的操作 ////// +control.prototype.openSettings = function (need) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; + if (!core.checkStatus('settings', need)) + return; + core.ui.drawSettings(); +} + +////// 自动存档 ////// +control.prototype.autosave = function (removeLast) { + var x=null; + if (removeLast) + x=core.status.route.pop(); + core.saveData("autoSave"); + if (removeLast && core.isset(x)) + core.status.route.push(x); +} + +////// 实际进行存读档事件 ////// +control.prototype.doSL = function (id, type) { + if (type=='save') { + if (id=='autoSave') { + core.drawTip('不能覆盖自动存档!'); + return; + } + if (core.saveData("save"+id)) { + core.ui.closePanel(); + core.drawTip('存档成功!'); + if (id!="autoSave") { + core.status.saveIndex=id; + core.setLocalStorage('saveIndex2', core.status.saveIndex); + } + } + else { + core.drawTip('存储空间不足,请覆盖已有的存档或在菜单栏中进行清理'); + } + return; + } + else if (type=='load') { + var data = core.getLocalStorage(id=='autoSave'?id:"save"+id, null); + if (!core.isset(data)) { + core.drawTip("无效的存档"); + return; + } + if (data.version != core.firstData.version) { + // core.drawTip("存档版本不匹配"); + if (confirm("存档版本不匹配!\n你想回放此存档的录像吗?")) { + core.dom.startPanel.style.display = 'none'; + core.resetStatus(core.firstData.hero, data.hard, core.firstData.floorId, null, core.initStatus.maps); + core.events.setInitData(data.hard); + core.changeFloor(core.status.floorId, null, core.firstData.hero.loc, null, function() { + core.startReplay(core.decodeRoute(data.route)); + }, true); + } + return; + } + core.ui.closePanel(); + core.loadData(data, function() { + core.drawTip("读档成功"); + if (id!="autoSave") { + core.status.saveIndex=id; + core.setLocalStorage('saveIndex2', core.status.saveIndex); + } + }); + return; + } +} + +////// 同步存档到服务器 ////// +control.prototype.syncSave = function (type) { + var saves=null; + // data + if (type=='all') { + saves=[]; + for (var i=1;i<=150;i++) { + var data = core.getLocalStorage("save"+i, null); + if (core.isset(data)) { + saves.push(data); + } + } + } + else { + for (var i=150;i>=1;i--) { + saves=core.getLocalStorage("save"+i, null); + if (core.isset(saves)) { + break; + } + } + } + if (!core.isset(saves)) { + core.drawText("没有要同步的存档"); + return; + } + core.ui.drawWaiting("正在同步,请稍后..."); + + var formData = new FormData(); + formData.append('type', 'save'); + formData.append('name', core.firstData.name); + var save_text = JSON.stringify(saves); + formData.append('data', save_text); + + core.http("POST", "/games/sync.php", formData, function (data) { + var response = JSON.parse(data); + if (response.code<0) { + core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:"+response.msg); + } + else { + core.drawText("同步成功!\n\n您的存档编号: "+response.code+"\n您的存档密码: "+response.msg+"\n\n请牢记以上两个信息(如截图等),在从服务器\n同步存档时使用。") + } + }, function (e) { + core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:"+e); + }) +} + +////// 从服务器加载存档 ////// +control.prototype.syncLoad = function () { + var id = prompt("请输入存档编号:"); + if (id==null || id=="") { + core.ui.drawSyncSave(); return; + } + var password = prompt("请输入存档密码:"); + if (password==null || password=="") { + core.ui.drawSyncSave(); return; + } + core.ui.drawWaiting("正在同步,请稍后..."); + + var formData = new FormData(); + formData.append('type', 'load'); + formData.append('name', core.firstData.name); + formData.append('id', id); + formData.append('password', password); + + core.http("POST", "/games/sync.php", formData, function (data) { + var response = JSON.parse(data); + switch (response.code) { + case 0: + // 成功 + var data=JSON.parse(response.msg); + // console.log(data); + + if (data instanceof Array) { + core.status.event.selection=1; + core.ui.drawConfirmBox("所有本地存档都将被覆盖,确认?", function () { + for (var i=1;i<=150;i++) { + if (i<=data.length) { + core.setLocalStorage("save"+i, data[i-1]); + } + else { + core.removeLocalStorage("save"+i); + } + } + core.drawText("同步成功!\n你的本地所有存档均已被覆盖。"); + }, function () { + core.status.event.selection=0; + core.ui.drawSyncSave(); + }) + } + else { + // 只覆盖单存档 + var index=150; + for (var i=150;i>=1;i--) { + if (core.getLocalStorage("save"+i, null)==null) + index=i; + else break; + } + core.setLocalStorage("save"+index, data); + core.drawText("同步成功!\n单存档已覆盖至存档"+index); + } + break; + case -1: + core.drawText("出错啦!\n存档编号"+id+"不存在!"); + break; + case -2: + core.drawText("出错啦!\n存档密码错误!"); + break; + default: + core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:"+response.msg); + break; + } + }, function (e) { + core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:"+e); + }); +} + +////// 存档到本地 ////// +control.prototype.saveData = function(dataId) { + var data = { + 'floorId': core.status.floorId, + 'hero': core.clone(core.status.hero), + 'hard': core.status.hard, + 'maps': core.maps.save(core.status.maps), + 'route': core.encodeRoute(core.status.route), + 'shops': {}, + 'version': core.firstData.version, + "time": new Date().getTime() + }; + // set shop times + for (var shop in core.status.shops) { + data.shops[shop]={ + 'times': core.status.shops[shop].times || 0, + 'visited': core.status.shops[shop].visited || false + } + } + core.events.beforeSaveData(data); + + return core.setLocalStorage(dataId, data); +} + +////// 从本地读档 ////// +control.prototype.loadData = function (data, callback) { + + core.resetStatus(data.hero, data.hard, data.floorId, core.decodeRoute(data.route), core.maps.load(data.maps)); + + // load shop times + for (var shop in core.status.shops) { + if (core.isset(data.shops[shop])) { + core.status.shops[shop].times = data.shops[shop].times; + core.status.shops[shop].visited = data.shops[shop].visited; + } + } + + core.events.afterLoadData(data); + + core.changeFloor(data.floorId, null, data.hero.loc, 0, function() { + if (core.isset(callback)) callback(); + }, true); +} + +////// 设置勇士属性 ////// +control.prototype.setStatus = function (statusName, statusVal) { + core.status.hero[statusName] = statusVal; +} + +////// 获得勇士属性 ////// +control.prototype.getStatus = function (statusName) { + return core.status.hero[statusName]; +} + +////// 获得某个等级的名称 ////// +control.prototype.getLvName = function () { + if (core.status.hero.lv>core.firstData.levelUp.length) return core.status.hero.lv; + return core.firstData.levelUp[core.status.hero.lv-1].name || core.status.hero.lv; +} + +////// 设置某个自定义变量或flag ////// +control.prototype.setFlag = function(flag, value) { + if (!core.isset(core.status.hero)) return; + core.status.hero.flags[flag]=value; +} + +////// 获得某个自定义变量或flag ////// +control.prototype.getFlag = function(flag, defaultValue) { + if (!core.isset(core.status.hero)) return defaultValue; + var value = core.status.hero.flags[flag]; + if (core.isset(value)) return value; + return defaultValue; +} + +////// 是否存在某个自定义变量或flag,且值为true ////// +control.prototype.hasFlag = function(flag) { + if (core.getFlag(flag)) return true; + return false; +} + +////// 锁定状态栏,常常用于事件处理 ////// +control.prototype.lockControl = function () { + core.status.lockControl = true; +} + +////// 解锁状态栏 ////// +control.prototype.unLockControl = function () { + core.status.lockControl = false; +} + +////// 播放背景音乐 ////// +control.prototype.playBgm = function (bgm) { + if (main.mode!='play')return; + // 如果不允许播放 + if (!core.musicStatus.bgmStatus) return; + // 音频不存在 + if (!core.isset(core.material.bgms[bgm])) return; + + // 延迟播放 + if (core.material.bgms[bgm] == 'loading') { + core.material.bgms[bgm] = 'starting'; + return; + } + + try { + // 如果当前正在播放,且和本BGM相同,直接忽略 + if (core.musicStatus.playingBgm == bgm && core.musicStatus.isPlaying) { + return; + } + // 如果正在播放中,暂停 + if (core.isset(core.musicStatus.playingBgm) && core.musicStatus.isPlaying) { + core.material.bgms[core.musicStatus.playingBgm].pause(); + } + // 播放当前BGM + core.musicStatus.playingBgm = bgm; + core.material.bgms[bgm].play(); + core.musicStatus.isPlaying = true; + + } + catch (e) { + console.log("无法播放BGM "+bgm); + console.log(e); + core.musicStatus.playingBgm = null; + } +} + +////// 暂停背景音乐的播放 ////// +control.prototype.pauseBgm = function () { + // 直接暂停播放 + try { + if (core.isset(core.musicStatus.playingBgm)) { + core.material.bgms[core.musicStatus.playingBgm].pause(); + } + core.musicStatus.isPlaying = false; + } + catch (e) { + console.log("无法暂停BGM "+bgm); + console.log(e); + } +} + +////// 恢复背景音乐的播放 ////// +control.prototype.resumeBgm = function () { + if (main.mode!='play')return; + // 如果不允许播放 + if (!core.musicStatus.bgmStatus) return; + + // 恢复BGM + try { + if (core.isset(core.musicStatus.playingBgm)) { + core.material.bgms[core.musicStatus.playingBgm].play(); + core.musicStatus.isPlaying = true; + } + else { + if (core.bgms.length>0) { + if (core.isset(core.floors[core.status.floorId].bgm)) { + core.playBgm(core.floors[core.status.floorId].bgm); + } + else + core.playBgm(core.bgms[0]); + core.musicStatus.isPlaying = true; + } + } + } + catch (e) { + console.log("无法恢复BGM "+bgm); + console.log(e); + } +} + +////// 播放音频 ////// +control.prototype.playSound = function (sound) { + if (main.mode!='play')return; + // 如果不允许播放 + if (!core.musicStatus.soundStatus) return; + // 音频不存在 + if (!core.isset(core.material.sounds[sound])) return; + + try { + if (core.musicStatus.audioContext != null) { + var source = core.musicStatus.audioContext.createBufferSource(); + source.buffer = core.material.sounds[sound]; + source.connect(core.musicStatus.audioContext.destination); + try { + source.start(0); + } + catch (e) { + try { + source.noteOn(0); + } + catch (ee) { + } + } + } + else { + core.material.sounds[sound].play(); + } + } + catch (eee) { + console.log("无法播放SE "+bgm); + console.log(eee); + } +} + +////// 清空状态栏 ////// +control.prototype.clearStatusBar = function() { + var statusList = ['floor', 'lv', 'hp', 'atk', 'def', 'mdef', 'money', 'experience', 'up', 'yellowKey', 'blueKey', 'redKey', 'poison', 'weak', 'curse', 'hard']; + statusList.forEach(function (e) { + core.statusBar[e].innerHTML = " "; + }); + core.statusBar.image.book.style.opacity = 0.3; + core.statusBar.image.fly.style.opacity = 0.3; +} + +////// 更新状态栏 ////// +control.prototype.updateStatusBar = function () { + + // 检查等级 + core.events.checkLvUp(); + + // 检查HP上限 + if (core.flags.enableHPMax) { + core.setStatus('hp', Math.min(core.getStatus('hpmax'), core.getStatus('hp'))); + } + + // 更新领域、阻击、显伤 + core.updateCheckBlock(); + + var lvName = core.getLvName(); + core.statusBar.lv.innerHTML = lvName; + if (/^[+-]?\d+$/.test(lvName)) + core.statusBar.lv.style.fontStyle = 'italic'; + else core.statusBar.lv.style.fontStyle = 'normal'; + + var statusList = ['hpmax', 'hp', 'atk', 'def', 'mdef', 'money', 'experience']; + statusList.forEach(function (item) { + core.statusBar[item].innerHTML = core.getStatus(item); + }); + // 进阶 + if (core.flags.enableLevelUp && core.status.hero.lv clientHeight && clientHeight < ADAPT_WIDTH){ + isHorizontal = true; + width = clientHeight; + } + // 各元素大小的变量声明 + var gameGroupWidth, gameGroupHeight, borderRight, + canvasWidth, canvasTop, // canvasLeft, + statusBarWidth, statusBarHeight, statusBarBorder, + statusWidth, statusHeight, statusMaxWidth,statusLabelsLH, + toolBarWidth, toolBarHeight, toolBarTop, toolBarBorder, + toolsWidth, toolsHeight,toolsMargin,toolsPMaxwidth, + fontSize, toolbarFontSize, margin; + + var count = core.dom.statusBar.children.length; + if (!core.flags.enableFloor) count--; + if (!core.flags.enableLv) count--; + if (!core.flags.enableHPMax) count--; + if (!core.flags.enableMDef) count--; + if (!core.flags.enableMoney) count--; + if (!core.flags.enableExperience) count--; + if (!core.flags.enableLevelUp) count--; + if (!core.flags.enableDebuff) count--; + + var statusLineHeight = BASE_LINEHEIGHT * 9 / count; + var statusLineFontSize = DEFAULT_FONT_SIZE; + if (count>9) statusLineFontSize = statusLineFontSize * 9 / count; + + var shopDisplay; + + statusBarBorder = '3px #fff solid'; + toolBarBorder = '3px #fff solid'; + var zoom = (ADAPT_WIDTH - width) / 4.22; + var aScale = 1 - zoom / 100; + + // 移动端 + if (width < CHANGE_WIDTH) { + if(width < ADAPT_WIDTH){ + + core.domStyle.scale = aScale; + canvasWidth = width; + }else{ + canvasWidth = DEFAULT_CANVAS_WIDTH; + core.domStyle.scale = 1; + } + + var scale = core.domStyle.scale + var tempWidth = DEFAULT_CANVAS_WIDTH * scale; + if(!isHorizontal){ //竖屏 + core.domStyle.screenMode = 'vertical'; + //显示快捷商店图标 + shopDisplay = 'block'; + //判断应该显示几行 + // var col = core.flags.enableMDef || core.flags.enableExperience || core.flags.enableDebuff ? 3 : 2; + var col = parseInt((count-1)/3)+1; + + var tempTopBarH = scale * (BASE_LINEHEIGHT * col + SPACE * 2) + 6; + var tempBotBarH = scale * (BASE_LINEHEIGHT + SPACE * 4) + 6; + + gameGroupHeight = tempWidth + tempTopBarH + tempBotBarH; + + gameGroupWidth = tempWidth + canvasTop = tempTopBarH; + // canvasLeft = 0; + toolBarWidth = statusBarWidth = canvasWidth; + statusBarHeight = tempTopBarH; + statusBarBorder = '3px #fff solid'; + + statusHeight = scale*BASE_LINEHEIGHT * .8; + statusLabelsLH = .8 * BASE_LINEHEIGHT *scale; + statusMaxWidth = scale * DEFAULT_BAR_WIDTH * .95; + toolBarHeight = tempBotBarH; + + toolBarTop = statusBarHeight + canvasWidth; + toolBarBorder = '3px #fff solid'; + toolsHeight = scale * BASE_LINEHEIGHT; + toolsPMaxwidth = scale * DEFAULT_BAR_WIDTH * .4; + borderRight = '3px #fff solid'; + + margin = scale * SPACE * 2; + toolsMargin = scale * SPACE * 4; + fontSize = DEFAULT_FONT_SIZE * scale; + toolbarFontSize = DEFAULT_FONT_SIZE * scale; + }else { //横屏 + core.domStyle.screenMode = 'horizontal'; + shopDisplay = 'none'; + gameGroupWidth = tempWidth + DEFAULT_BAR_WIDTH * scale; + gameGroupHeight = tempWidth; + canvasTop = 0; + // canvasLeft = DEFAULT_BAR_WIDTH * scale; + toolBarWidth = statusBarWidth = DEFAULT_BAR_WIDTH * scale; + statusBarHeight = scale * statusLineHeight * count + SPACE * 2; //一共有9行加上两个padding空隙 + statusBarBorder = '3px #fff solid'; + + statusHeight = scale*statusLineHeight * .8; + statusLabelsLH = .8 * statusLineHeight *scale; + toolBarHeight = canvasWidth - statusBarHeight; + toolBarTop = scale*statusLineHeight * count + SPACE * 2; + toolBarBorder = '3px #fff solid'; + toolsHeight = scale * BASE_LINEHEIGHT; + fontSize = statusLineFontSize * scale; + toolbarFontSize = DEFAULT_FONT_SIZE * scale; + borderRight = ''; + statusMaxWidth = scale * DEFAULT_BAR_WIDTH; + toolsPMaxwidth = scale * DEFAULT_BAR_WIDTH; + + margin = scale * SPACE * 2; + toolsMargin = 2 * SPACE * scale; + } + + }else { //大屏设备 pc端 + core.domStyle.scale = 1; + core.domStyle.screenMode = 'bigScreen'; + shopDisplay = 'none'; + + gameGroupWidth = DEFAULT_CANVAS_WIDTH + DEFAULT_BAR_WIDTH; + gameGroupHeight = DEFAULT_CANVAS_WIDTH; + canvasWidth = DEFAULT_CANVAS_WIDTH; + canvasTop = 0; + // canvasLeft = DEFAULT_BAR_WIDTH; + + toolBarWidth = statusBarWidth = DEFAULT_BAR_WIDTH; + statusBarHeight = statusLineHeight * count + SPACE * 2; //一共有9行 + + statusHeight = statusLineHeight * .8; + statusLabelsLH = .8 * statusLineHeight; + toolBarHeight = DEFAULT_CANVAS_WIDTH - statusBarHeight; + toolBarTop = statusLineHeight * count + SPACE * 2; + + toolsHeight = BASE_LINEHEIGHT; + borderRight = ''; + fontSize = statusLineFontSize; + toolbarFontSize = DEFAULT_FONT_SIZE; + statusMaxWidth = DEFAULT_BAR_WIDTH; + toolsPMaxwidth = DEFAULT_BAR_WIDTH * .9; + margin = SPACE * 2; + toolsMargin = 2 * SPACE; + } + + var unit = 'px' + core.domStyle.styles = [ + { + id: 'gameGroup', + rules:{ + width: gameGroupWidth + unit, + height: gameGroupHeight + unit, + top: (clientHeight-gameGroupHeight)/2 + unit, + left: (clientWidth-gameGroupWidth)/2 + unit, + } + }, + { + className: 'gameCanvas', + rules:{ + width: canvasWidth + unit, + height: canvasWidth + unit, + top: canvasTop + unit, + right: 0, + border: '3px #fff solid', + } + }, + { + id: 'curtain', + rules: { + width: (canvasWidth - SPACE*2) + unit, + height:(canvasWidth - SPACE*2) + unit, + top: (canvasTop + SPACE) + unit, + right: SPACE + unit, + } + }, + { + id: 'floorMsgGroup', + rules:{ + width: (canvasWidth - SPACE*2) + unit, + height: (gameGroupHeight - SPACE*2) + unit, + top: SPACE + unit, + right: SPACE + unit, + } + }, + { + id: 'statusBar', + rules:{ + width: statusBarWidth + unit, + height: statusBarHeight + unit, + top: 0, + left: 0, + padding: SPACE + unit, + + borderTop: statusBarBorder, + borderLeft: statusBarBorder, + borderRight: borderRight, + fontSize: fontSize + unit + } + }, + { + className: 'status', + rules:{ + width: '100%', + maxWidth: statusMaxWidth + unit, + height: statusHeight + unit, + margin: margin/2 + unit + } + }, + { + className: 'statusLabels', + rules:{ + marginLeft: margin + unit, + lineHeight: statusLabelsLH + unit, + } + }, + { + id: 'toolBar', + rules:{ + width: toolBarWidth + unit, + height: toolBarHeight + unit, + top: toolBarTop +unit, + left: 0, + padding: SPACE + unit, + borderBottom: toolBarBorder, + borderLeft: toolBarBorder, + borderRight: borderRight, + fontSize: toolbarFontSize + unit + } + }, + { + className: 'tools', + rules:{ + height: toolsHeight + unit, + maxWidth: toolsPMaxwidth + unit, + marginLeft: toolsMargin + unit, + marginTop: margin + unit, + } + }, + { + imgId: 'shop', + rules:{ + display: shopDisplay + } + }, + { + id: 'floorCol', + rules: { + display: core.flags.enableFloor ? 'block': 'none' + } + }, + { + id: 'lvCol', + rules: { + display: core.flags.enableLv ? 'block': 'none' + } + }, + { + id: 'hpmaxCol', + rules: { + display: core.flags.enableHPMax ? 'block': 'none' + } + }, + { + id: 'mdefCol', + rules: { + display: core.flags.enableMDef ? 'block': 'none' + } + }, + { + id: 'moneyCol', + rules: { + display: core.flags.enableMoney ? 'block': 'none' + } + }, + { + id: 'expCol', + rules: { + display: core.flags.enableExperience ? 'block': 'none' + } + }, + { + id: 'upCol', + rules: { + display: core.flags.enableLevelUp ? 'block': 'none' + } + }, + { + 'id': 'debuffCol', + rules: { + display: core.flags.enableDebuff ? 'block': 'none' + } + }, + { + id: 'hard', + rules: { + lineHeight: toolsHeight + unit + } + } + ] + core.domRenderer(); +} + +////// 渲染DOM ////// +control.prototype.domRenderer = function(){ + + core.dom.statusBar.style.display = 'block'; + core.dom.toolBar.style.display = 'block'; + + var styles = core.domStyle.styles; + + for(var i=0; icore.animateFrame.speed && core.isset(core.status.twoAnimateObjs)) { - - for (var a = 0; a < core.status.twoAnimateObjs.length; a++) { - var obj = core.status.twoAnimateObjs[a]; - obj.status = (obj.status+1)%2; - core.canvas.event.clearRect(obj.x, obj.y, 32, 32); - core.canvas.event.drawImage(obj.image, obj.status * 32, obj.loc * 32, 32, 32, obj.x, obj.y, 32, 32); - } - - core.animateFrame.twoTime = timestamp; - } - - if (timestamp-core.animateFrame.fourTime>core.animateFrame.speed/2 && core.isset(core.status.fourAnimateObjs)) { - for (var a = 0; a < core.status.fourAnimateObjs.length; a++) { - var obj=core.status.fourAnimateObjs[a]; - obj.status = (obj.status+1)%4; - core.canvas.event.clearRect(obj.x, obj.y, 32, 32); - core.canvas.event.drawImage(obj.image, obj.status * 32, obj.loc * 32, 32, 32, obj.x, obj.y, 32, 32); - } - // fourtime = timestamp % fourDelta; - core.animateFrame.fourTime = timestamp; - } - - } - - // Box - if (timestamp-core.animateFrame.boxTime>core.animateFrame.speed && core.isset(core.status.boxAnimateObjs) && core.status.boxAnimateObjs.length>0) { - core.drawBoxAnimate(); - core.animateFrame.boxTime = timestamp; - } - - // Hero move - if (timestamp-core.animateFrame.moveTime>16 && core.isset(core.status.heroMoving) && core.status.heroMoving>0) { - var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'), direction = core.getHeroLoc('direction'); - if (core.status.heroMoving<=4) { - core.drawHero(direction, x, y, 'leftFoot', 4*core.status.heroMoving*scan[direction].x, 4*core.status.heroMoving*scan[direction].y); - } - else if (core.status.heroMoving<=8) { - core.drawHero(direction, x, y, 'rightFoot', 4*core.status.heroMoving*scan[direction].x, 4*core.status.heroMoving*scan[direction].y); - } - core.animateFrame.moveTime = timestamp; - } - - // weather - if (core.isPlaying() && timestamp-core.animateFrame.weather.time>30) { - if (core.animateFrame.weather.type == 'rain' && core.animateFrame.weather.level > 0) { - - core.clearMap('weather', 0, 0, 416, 416); - - core.canvas.weather.strokeStyle = 'rgba(174,194,224,0.8)'; - core.canvas.weather.lineWidth = 1; - core.canvas.weather.lineCap = 'round'; - - core.animateFrame.weather.nodes.forEach(function (p) { - core.canvas.weather.beginPath(); - core.canvas.weather.moveTo(p.x, p.y); - core.canvas.weather.lineTo(p.x + p.l * p.xs, p.y + p.l * p.ys); - core.canvas.weather.stroke(); - - p.x += p.xs; - p.y += p.ys; - if (p.x > 416 || p.y > 416) { - p.x = Math.random() * 416; - p.y = -10; - } - - }) - - core.canvas.weather.fill(); - - } - else if (core.animateFrame.weather.type == 'snow' && core.animateFrame.weather.level > 0) { - - core.clearMap('weather', 0, 0, 416, 416); - - core.canvas.weather.fillStyle = "rgba(255, 255, 255, 0.8)"; - core.canvas.weather.beginPath(); - - if (!core.isset(core.animateFrame.weather.data)) - core.animateFrame.weather.data = 0; - core.animateFrame.weather.data += 0.01; - - var angle = core.animateFrame.weather.data; - core.animateFrame.weather.nodes.forEach(function (p) { - core.canvas.weather.moveTo(p.x, p.y); - core.canvas.weather.arc(p.x, p.y, p.r, 0, Math.PI * 2, true); - - // update - p.x += Math.sin(angle) * 2; - p.y += Math.cos(angle + p.d) + 1 + p.r / 2; - - if (p.x > 416 + 5 || p.x < -5 || p.y > 416) { - if (Math.random() > 1 / 3) { - p.x = Math.random() * 416; - p.y = -10; - } - else { - if (Math.sin(angle) > 0) { - p.x = -5; - p.y = Math.random() * 416; - } - else { - p.x = 416 + 5; - p.y = Math.random() * 416; - } - } - } - - }) - - core.canvas.weather.fill(); - - } - core.animateFrame.weather.time = timestamp; - - } - window.requestAnimationFrame(draw); - } - window.requestAnimationFrame(draw); + core.control.setRequestAnimationFrame(); } ////// 显示游戏开始界面 ////// core.prototype.showStartAnimate = function (callback) { - core.dom.startPanel.style.opacity=1; - core.dom.startPanel.style.display="block"; - core.dom.startTop.style.opacity=1; - core.dom.startTop.style.display="block"; - core.dom.startButtonGroup.style.display = 'none'; - core.dom.startButtons.style.display = 'block'; - core.dom.levelChooseButtons.style.display = 'none'; - core.dom.curtain.style.background = "#000000"; - core.dom.curtain.style.opacity = 0; - core.status.played = false; - core.clearStatus(); - core.clearMap('all'); - - var opacityVal = 1; - var startAnimate = window.setInterval(function () { - opacityVal -= 0.03; - if (opacityVal < 0) { - clearInterval(startAnimate); - core.dom.startTop.style.display = 'none'; - // core.playGame(); - core.dom.startButtonGroup.style.display = 'block'; - if (core.isset(callback)) callback(); - } - core.dom.startTop.style.opacity = opacityVal; - }, 20); + core.control.showStartAnimate(callback); } ////// 隐藏游戏开始界面 ////// core.prototype.hideStartAnimate = function (callback) { - var opacityVal = 1; - var startAnimate = window.setInterval(function () { - opacityVal -= 0.03; - if (opacityVal < 0) { - clearInterval(startAnimate); - core.dom.startPanel.style.display = 'none'; - if (core.isset(callback)) callback(); - } - core.dom.startPanel.style.opacity = opacityVal; - }, 20); -} - -////// 设置加载进度条进度 ////// -core.prototype.setStartProgressVal = function (val) { - core.dom.startTopProgress.style.width = val + '%'; -} - -////// 设置加载进度条提示文字 ////// -core.prototype.setStartLoadTipText = function (text) { - core.dom.startTopLoadTips.innerHTML = text; -} - -////// 加载图片和音频 ////// -core.prototype.loader = function (callback) { - var loadedImageNum = 0, allImageNum = 0, allSoundNum = 0; - allImageNum = core.images.length; - for (var key in core.sounds) { - allSoundNum += core.sounds[key].length; - } - for (var i = 0; i < core.images.length; i++) { - core.loadImage(core.images[i], function (imgName, image) { - core.setStartLoadTipText('正在加载图片 ' + imgName + "..."); - core.material.images[imgName] = image; - loadedImageNum++; - core.setStartLoadTipText(imgName + ' 加载完毕...'); - core.setStartProgressVal(loadedImageNum * (100 / allImageNum)); - if (loadedImageNum == allImageNum) { - - // 加载pngs - core.material.images.pngs = {}; - if (core.pngs.length==0) { - core.loadAutotile(callback); - return; - } - for (var x=0;x0) - core.playBgm(core.bgms[0]); - - callback(); + core.control.hideStartAnimate(callback); } ////// 游戏是否已经开始 ////// core.prototype.isPlaying = function() { - if (core.isset(core.status.played) && core.status.played) - return true; - return false; + return core.control.isPlaying(); } ////// 清除游戏状态和数据 ////// core.prototype.clearStatus = function() { - // 停止各个Timeout和Interval - for (var i in core.interval) { - clearInterval(core.interval[i]); - } - core.status = {}; - core.clearStatusBar(); - core.resize(main.dom.body.clientWidth, main.dom.body.clientHeight); + core.control.clearStatus(); } ////// 重置游戏状态和初始数据 ////// core.prototype.resetStatus = function(hero, hard, floorId, route, maps) { - - // 停止各个Timeout和Interval - for (var i in core.timeout) { - clearTimeout(core.timeout[i]); - core.timeout[i] = null; - } - for (var i in core.interval) { - clearInterval(core.interval[i]); - core.interval[i] = null; - } - - // 初始化status - core.status = core.clone(core.initStatus); - core.status.played = true; - // 初始化maps - core.status.floorId = floorId; - core.status.maps = core.clone(maps); - // 初始化怪物 - core.material.enemys = core.clone(core.enemys.getEnemys()); - // 初始化人物属性 - core.status.hero = core.clone(hero); - core.status.hard = hard; - // 初始化路线 - if (core.isset(route)) - core.status.route = route; - // 保存的Index - core.status.saveIndex = core.getLocalStorage('saveIndex2', 1); - - core.resize(main.dom.body.clientWidth, main.dom.body.clientHeight); + core.control.resetStatus(hero, hard, floorId, route, maps) } ////// 开始游戏 ////// core.prototype.startGame = function (hard, callback) { - console.log('开始游戏'); - - core.resetStatus(core.firstData.hero, hard, core.firstData.floorId, null, core.initStatus.maps); - - core.changeFloor(core.status.floorId, null, core.firstData.hero.loc, null, function() { - if (core.isset(callback)) callback(); - }); - - - setTimeout(function () { - // Upload - var formData = new FormData(); - formData.append('type', 'people'); - formData.append('name', core.firstData.name); - formData.append('version', core.firstData.version); - formData.append('platform', core.platform.isPC?"PC":core.platform.isAndroid?"Android":core.platform.isIOS?"iOS":""); - formData.append('hard', hard); - formData.append('hardCode', core.getFlag('hard', 0)); - - var xhr = new XMLHttpRequest(); - xhr.open("POST", "/games/upload.php"); - xhr.send(formData); - - }) - + core.control.startGame(hard, callback); } ////// 重新开始游戏;此函数将回到标题页面 ////// core.prototype.restart = function() { - core.showStartAnimate(); + core.control.restart(); } /////////// 系统事件相关 END /////////// - - /////////// 键盘、鼠标事件相关 /////////// ////// 按下某个键时 ////// core.prototype.onkeyDown = function(e) { - if (core.isset(core.status.replay)&&core.status.replay.replaying) return; - if (!core.isset(core.status.holdingKeys))core.status.holdingKeys=[]; - var isArrow={37:true,38:true,39:true,40:true}[e.keyCode] - if(isArrow && !core.status.lockControl){ - for(var ii =0;iimax){ - index=ii; - max=directionDistance[ii]; - } - } - pos=[{'x':0,'y':1},{'x':-1,'y':0},{'x':0,'y':-1},{'x':1,'y':0},false][index] - if(pos){ - pos.x+=pos0.x; - pos.y+=pos0.y; - core.status.stepPostfix.push(pos); - core.fillPosWithPoint(pos); - } + return core.actions.onmove(x,y); } ////// 当点击(触摸)事件放开时 ////// core.prototype.onup = function () { - if (core.isset(core.status.replay)&&core.status.replay.replaying) return; - - clearTimeout(core.timeout.onDownTimeout); - core.timeout.onDownTimeout = null; - clearInterval(core.interval.onDownInterval); - core.interval.onDownInterval = null; - - // core.status.holdingPath=0; - if(core.status.stepPostfix.length>0){ - var stepPostfix = []; - var direction={'0':{'1':'down','-1':'up'},'-1':{'0':'left'},'1':{'0':'right'}}; - for(var ii=1;ii=1000) { - core.waitHeroToStop(function () { - // 绘制快捷键 - core.ui.drawKeyBoard(); - }); - } - else { - //posx,posy是寻路的目标点,stepPostfix是后续的移动 - core.onclick(posx,posy,stepPostfix); - } - core.status.downTime=null; - } + return core.actions.onup(); } ////// 获得点击事件相对左上角的坐标(0到12之间) ////// core.prototype.getClickLoc = function (x, y) { - - var statusBar = {'x': 0, 'y': 0}; - var size = 32; - size = size * core.domStyle.scale; - - switch (core.domStyle.screenMode) {// 这里的3是指statusBar和游戏画布之间的白线宽度 - case 'vertical': - statusBar.x = 0; - statusBar.y = core.dom.statusBar.offsetHeight + 3; - break; - case 'horizontal': - case 'bigScreen': - statusBar.x = core.dom.statusBar.offsetWidth + 3; - statusBar.y = 0; - break; - } - - var left = core.dom.gameGroup.offsetLeft + statusBar.x; - var top = core.dom.gameGroup.offsetTop + statusBar.y; - var loc={'x': x - left, 'y': y - top, 'size': size}; - return loc; + return core.actions.getClickLoc(x,y); } ////// 具体点击屏幕上(x,y)点时,执行的操作 ////// core.prototype.onclick = function (x, y, stepPostfix) { - if (core.isset(core.status.replay)&&core.status.replay.replaying) return; - // console.log("Click: (" + x + "," + y + ")"); - - stepPostfix=stepPostfix||[]; - - // 非游戏屏幕内 - if (x<0 || y<0 || x>12 || y>12) return; - - // 中心对称飞行器 - if (core.status.usingCenterFly) { - if (x!=12-core.getHeroLoc('x') || y!=12-core.getHeroLoc('y')) { - core.clearMap('ui', (12-core.getHeroLoc('x'))*32,(12-core.getHeroLoc('y'))*32,32,32); - } else { - if (core.canUseItem('centerFly')) { - core.useItem('centerFly'); - core.clearMap('ui', core.getHeroLoc('x')*32,core.getHeroLoc('y')*32,32,32); - return; - } - else { - core.drawTip('当前不能使用中心对称飞行器'); - core.clearMap('ui', (12-core.getHeroLoc('x'))*32,(12-core.getHeroLoc('y'))*32,32,32); - } - } - core.status.usingCenterFly= false; - } - - // 寻路 - if (!core.status.lockControl) { - core.setAutomaticRoute(x, y, stepPostfix); - return; - } - - // 怪物手册 - if (core.status.event.id == 'book') { - core.events.clickBook(x,y); - return; - } - - // 怪物详细信息 - if (core.status.event.id == 'book-detail') { - core.events.clickBookDetail(x,y); - return; - } - - // 楼层飞行器 - if (core.status.event.id == 'fly') { - core.events.clickFly(x,y); - return; - } - - // 查看地图 - if (core.status.event.id == 'viewMaps') { - core.events.clickViewMaps(x,y); - return; - } - - // 开关 - if (core.status.event.id == 'switchs') { - core.events.clickSwitchs(x,y); - return; - } - - // 设置 - if (core.status.event.id == 'settings') { - core.events.clickSettings(x,y); - return; - } - - // 商店 - if (core.status.event.id == 'shop') { - core.events.clickShop(x,y); - return; - } - - // 快捷商店 - if (core.status.event.id == 'selectShop') { - core.events.clickQuickShop(x,y); - return; - } - - // 工具栏 - if (core.status.event.id == 'toolbox') { - core.events.clickToolbox(x,y); - return; - } - - // 存读档 - if (core.status.event.id == 'save' || core.status.event.id == 'load') { - core.events.clickSL(x,y); - return; - } - - // 选项 - if (core.status.event.id == 'confirmBox') { - core.events.clickConfirmBox(x,y); - return; - } - - if (core.status.event.id == 'keyBoard') { - core.events.clickKeyBoard(x,y); - return; - } - - // 关于 - if (core.status.event.id == 'about') { - core.events.clickAbout(x,y); - return; - } - - if (core.status.event.id == 'action') { - core.events.clickAction(x,y); - return; - } - - // 纯文本 - if (core.status.event.id == 'text') { - core.drawText(); - return; - } - - // 同步存档 - if (core.status.event.id == 'syncSave') { - core.events.clickSyncSave(x,y); - return; - } - - if (core.status.event.id == 'syncSelect') { - core.events.clickSyncSelect(x,y); - return; - } - - if (core.status.event.id == 'localSaveSelect') { - core.events.clickLocalSaveSelect(x,y); - return; - } - - if (core.status.event.id == 'cursor') { - core.events.clickCursor(x,y); - return; - } - + return core.actions.onclick(x,y,stepPostfix); } ////// 滑动鼠标滚轮时的操作 ////// core.prototype.onmousewheel = function (direct) { - if (core.isset(core.status.replay)&&core.status.replay.replaying) return; - // 向下滚动是 -1 ,向上是 1 - - // 楼层飞行器 - if (core.status.lockControl && core.status.event.id == 'fly') { - if (direct==1) core.ui.drawFly(core.status.event.data+1); - if (direct==-1) core.ui.drawFly(core.status.event.data-1); - return; - } - - // 怪物手册 - if (core.status.lockControl && core.status.event.id == 'book') { - if (direct==1) core.ui.drawBook(core.status.event.data - 6); - if (direct==-1) core.ui.drawBook(core.status.event.data + 6); - return; - } - - // 存读档 - if (core.status.lockControl && (core.status.event.id == 'save' || core.status.event.id == 'load')) { - if (direct==1) core.ui.drawSLPanel(core.status.event.data - 10); - if (direct==-1) core.ui.drawSLPanel(core.status.event.data + 10); - return; - } - - // 浏览地图 - if (core.status.lockControl && core.status.event.id == 'viewMaps') { - if (direct==1) core.ui.drawMaps(core.status.event.data+1); - if (direct==-1) core.ui.drawMaps(core.status.event.data-1); - return; - } + return core.actions.onmousewheel(direct); } /////////// 键盘、鼠标事件相关 END /////////// - - - /////////// 寻路代码相关 /////////// ////// 清除自动寻路路线 ////// core.prototype.clearAutomaticRouteNode = function (x, y) { - if (core.status.event.id==null) - core.canvas.ui.clearRect(x * 32 + 5, y * 32 + 5, 27, 27); + core.control.clearAutomaticRouteNode(x,y); } ////// 停止自动寻路操作 ////// core.prototype.stopAutomaticRoute = function () { - if (!core.status.played) { - return; - } - core.status.automaticRoute.autoHeroMove = false; - core.status.automaticRoute.autoStep = 0; - core.status.automaticRoute.destStep = 0; - core.status.automaticRoute.movedStep = 0; - core.status.automaticRoute.autoStepRoutes = []; - core.status.automaticRoute.destX=null; - core.status.automaticRoute.destY=null; - core.status.automaticRoute.lastDirection = null; - core.stopHero(); - if (core.status.automaticRoute.moveStepBeforeStop.length==0) - core.canvas.ui.clearRect(0, 0, 416, 416); + core.control.stopAutomaticRoute(); } ////// 继续剩下的自动寻路操作 ////// core.prototype.continueAutomaticRoute = function () { - // 此函数只应由events.afterOpenDoor和events.afterBattle调用 - var moveStep = core.status.automaticRoute.moveStepBeforeStop; - //core.status.automaticRoute.moveStepBeforeStop = []; - if(moveStep.length===0 || (moveStep.length===1 && moveStep[0].step===1)) { - core.status.automaticRoute.moveStepBeforeStop = []; - } - else { - core.setAutoHeroMove(moveStep); - } + core.control.continueAutomaticRoute(); } ////// 清空剩下的自动寻路列表 ////// core.prototype.clearContinueAutomaticRoute = function () { - core.canvas.ui.clearRect(0, 0, 416, 416); - core.status.automaticRoute.moveStepBeforeStop=[]; + core.control.clearContinueAutomaticRoute(); } ////// 设置自动寻路路线 ////// core.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) { - if (!core.status.played || core.status.lockControl) { - return; - } - // 正在寻路中 - if (core.status.automaticRoute.autoHeroMove) { - var lastX = core.status.automaticRoute.destX, lastY=core.status.automaticRoute.destY; - core.stopAutomaticRoute(); - if (lastX==destX && lastY==destY) { - core.status.automaticRoute.moveDirectly = true; - setTimeout(function () { - if (core.status.automaticRoute.moveDirectly && core.status.heroMoving==0) { - if (core.canMoveDirectly(destX, destY)) { - core.clearMap('hero', 0, 0, 416, 416); - core.setHeroLoc('x', destX); - core.setHeroLoc('y', destY); - core.drawHero(core.getHeroLoc('direction'), core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); - core.status.route.push("move:"+destX+":"+destY); - } - } - core.status.automaticRoute.moveDirectly = false; - }, 100); - } - return; - } - if (destX == core.status.hero.loc.x && destY == core.status.hero.loc.y && stepPostfix.length==0) { - if (core.timeout.turnHeroTimeout==null) { - core.timeout.turnHeroTimeout = setTimeout(function() { - core.turnHero(); - clearTimeout(core.timeout.turnHeroTimeout); - core.timeout.turnHeroTimeout = null; - }, 250); - } - else { - clearTimeout(core.timeout.turnHeroTimeout); - core.timeout.turnHeroTimeout = null; - core.getNextItem(); - } - return; - } - var step = 0; - var tempStep = null; - var moveStep; - if (!(moveStep = core.automaticRoute(destX, destY))) { - if (destX == core.status.hero.loc.x && destY == core.status.hero.loc.y){ - moveStep=[]; - } else { - core.canvas.ui.clearRect(0, 0, 416, 416); - return; - } - } - moveStep=moveStep.concat(stepPostfix); - core.status.automaticRoute.destX=destX; - core.status.automaticRoute.destY=destY; - core.canvas.ui.save(); - core.canvas.ui.clearRect(0, 0, 416, 416); - core.canvas.ui.fillStyle = '#bfbfbf'; - core.canvas.ui.strokeStyle = '#bfbfbf'; - core.canvas.ui.lineWidth = 8; - for (var m = 0; m < moveStep.length; m++) { - if (tempStep == null) { - step++; - tempStep = moveStep[m].direction; - } - else if (tempStep == moveStep[m].direction) { - step++; - } - else { - //core.status.automaticRoutingTemp.moveStep.push({'direction': tempStep, 'step': step}); - core.status.automaticRoute.autoStepRoutes.push({'direction': tempStep, 'step': step}); - step = 1; - tempStep = moveStep[m].direction; - } - if (m == moveStep.length - 1) { - // core.status.automaticRoutingTemp.moveStep.push({'direction': tempStep, 'step': step}); - core.status.automaticRoute.autoStepRoutes.push({'direction': tempStep, 'step': step}); - core.canvas.ui.fillRect(moveStep[m].x * 32 + 10, moveStep[m].y * 32 + 10, 12, 12); - } - else { - core.canvas.ui.beginPath(); - if (core.isset(moveStep[m + 1]) && tempStep != moveStep[m + 1].direction) { - if (tempStep == 'up' && moveStep[m + 1].direction == 'left' || tempStep == 'right' && moveStep[m + 1].direction == 'down') { - core.canvas.ui.moveTo(moveStep[m].x * 32 + 5, moveStep[m].y * 32 + 16); - core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 16); - core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 27); - } - else if (tempStep == 'up' && moveStep[m + 1].direction == 'right' || tempStep == 'left' && moveStep[m + 1].direction == 'down') { - core.canvas.ui.moveTo(moveStep[m].x * 32 + 27, moveStep[m].y * 32 + 16); - core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 16); - core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 27); - } - else if (tempStep == 'left' && moveStep[m + 1].direction == 'up' || tempStep == 'down' && moveStep[m + 1].direction == 'right') { - core.canvas.ui.moveTo(moveStep[m].x * 32 + 27, moveStep[m].y * 32 + 16); - core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 16); - core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 5); - } - else if (tempStep == 'right' && moveStep[m + 1].direction == 'up' || tempStep == 'down' && moveStep[m + 1].direction == 'left') { - core.canvas.ui.moveTo(moveStep[m].x * 32 + 5, moveStep[m].y * 32 + 16); - core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 16); - core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 5); - } - core.canvas.ui.stroke(); - continue; - } - switch (tempStep) { - case 'up': - case 'down': - core.canvas.ui.beginPath(); - core.canvas.ui.moveTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 5); - core.canvas.ui.lineTo(moveStep[m].x * 32 + 16, moveStep[m].y * 32 + 27); - core.canvas.ui.stroke(); - break; - case 'left': - case 'right': - core.canvas.ui.beginPath(); - core.canvas.ui.moveTo(moveStep[m].x * 32 + 5, moveStep[m].y * 32 + 16); - core.canvas.ui.lineTo(moveStep[m].x * 32 + 27, moveStep[m].y * 32 + 16); - core.canvas.ui.stroke(); - break; - } - } - } - core.canvas.ui.restore(); - - // 立刻移动 - core.setAutoHeroMove(); - + core.control.setAutomaticRoute(destX,destY,stepPostfix); } ////// 自动寻路算法,找寻最优路径 ////// core.prototype.automaticRoute = function (destX, destY) { - var startX = core.getHeroLoc('x'); - var startY = core.getHeroLoc('y'); - var scan = { - 'up': {'x': 0, 'y': -1}, - 'left': {'x': -1, 'y': 0}, - 'down': {'x': 0, 'y': 1}, - 'right': {'x': 1, 'y': 0} - }; - var queue = []; - var nowDeep = 0; - var route = []; - var ans = [] - - if (destX == startX && destY == startY) return false; - queue.push(13 * startX + startY); - queue.push(-1); - route[13 * startX + startY] = ''; - - while (queue.length != 1) { - var f = queue.shift(); - if (f===-1) {nowDeep+=1;queue.push(-1);continue;} - var deep = ~~(f/169); - if (deep!==nowDeep) {queue.push(f);continue;} - f=f%169; - var nowX = parseInt(f / 13), nowY = f % 13; - var nowIsArrow = false, nowId, nowBlock = core.getBlock(nowX,nowY); - /* - if (nowBlock!=null){ - nowId = nowBlock.block.event.id; - nowIsArrow = nowId.slice(0, 5).toLowerCase() == 'arrow'; - } - */ - for (var direction in scan) { - /* - if(nowIsArrow){ - var nowArrow = nowId.slice(5).toLowerCase(); - if (direction != nowArrow) continue; - } - */ - if (!core.canMoveHero(nowX, nowY, direction)) - continue; - - var nx = nowX + scan[direction].x; - var ny = nowY + scan[direction].y; - - if (nx<0 || nx>12 || ny<0 || ny>12) continue; - - var nid = 13 * nx + ny; - - if (core.isset(route[nid])) continue; - - var deepAdd=1; - - var nextId, nextBlock = core.getBlock(nx,ny); - if (nextBlock!=null){ - nextId = nextBlock.block.event.id; - /* - // 遇到单向箭头处理 - var isArrow = nextId.slice(0, 5).toLowerCase() == 'arrow'; - if(isArrow){ - var nextArrow = nextId.slice(5).toLowerCase(); - if ( (scan[direction].x + scan[nextArrow].x) == 0 && (scan[direction].y + scan[nextArrow].y) == 0 ) continue; - } - */ - // 绕过亮灯(因为只有一次通行机会很宝贵) - if(nextId == "light") deepAdd=100; - // 绕过路障 - if (nextId.substring(nextId.length-3)=="Net") deepAdd=core.values.lavaDamage; - // 绕过血瓶 - if (!core.flags.potionWhileRouting && nextId.substring(nextId.length-6)=="Potion") deepAdd=20; - // 绕过传送点 - if (nextBlock.block.event.trigger == 'changeFloor') deepAdd = 10; - } - if (core.status.checkBlock.damage[nid]>0) - deepAdd = core.status.checkBlock.damage[nid]; - - if (nx == destX && ny == destY) { - route[nid] = direction; - break; - } - if (core.noPassExists(nx, ny)) - continue; - - route[nid] = direction; - queue.push(169*(nowDeep+deepAdd)+nid); - } - if (core.isset(route[13 * destX + destY])) break; - } - - if (!core.isset(route[13 * destX + destY])) { - return false; - } - - var nowX = destX, nowY = destY; - while (nowX != startX || nowY != startY) { - var dir = route[13 * nowX + nowY]; - ans.push({'direction': dir, 'x': nowX, 'y': nowY}); - nowX -= scan[dir].x; - nowY -= scan[dir].y; - } - - ans.reverse(); - return ans; + return core.control.automaticRoute(destX, destY); } ////// 显示离散的寻路点 ////// core.prototype.fillPosWithPoint = function (pos) { - core.fillRect('ui', pos.x*32+12,pos.y*32+12,8,8, '#bfbfbf'); + core.control.fillPosWithPoint(pos); } -/* -////// 清除已经寻路过的部分 ////// -core.prototype.clearStepPostfix = function () { - if(core.status.mouseOutCheck >0){ - core.status.mouseOutCheck--; - window.setTimeout(core.clearStepPostfix,1000); - return; - } - core.status.holdingPath=0; - if(core.status.stepPostfix.length>0){ - core.status.stepPostfix=[]; - core.canvas.ui.clearRect(0, 0, 416,416); - core.canvas.ui.restore(); - } -} -*/ - /////////// 寻路代码相关 END /////////// @@ -1847,406 +432,82 @@ core.prototype.clearStepPostfix = function () { ////// 设置勇士的自动行走路线 ////// core.prototype.setAutoHeroMove = function (steps) { - steps=steps||core.status.automaticRoute.autoStepRoutes; - if (steps.length == 0) { - return; - } - core.status.automaticRoute.autoStepRoutes=steps; - core.status.automaticRoute.autoHeroMove = true; - core.status.automaticRoute.autoStep = 1; - core.status.automaticRoute.destStep = steps[0].step; - core.moveHero(steps[0].direction); + core.control.setAutoHeroMove(steps); } ////// 设置行走的效果动画 ////// core.prototype.setHeroMoveInterval = function (direction, x, y, callback) { - if (core.status.heroMoving>0) { - return; - } - core.status.heroMoving=1; - // core.status.heroMoving = true; - // var moveStep = 0; - var scan = { - 'up': {'x': 0, 'y': -1}, - 'left': {'x': -1, 'y': 0}, - 'down': {'x': 0, 'y': 1}, - 'right': {'x': 1, 'y': 0} - }; - core.interval.heroMoveInterval = window.setInterval(function () { - core.status.heroMoving++; - /* - if (moveStep<=4) { - core.drawHero(direction, x, y, 'leftFoot', 4*moveStep*scan[direction].x, 4*moveStep*scan[direction].y); - } - else if (moveStep<8) { - core.drawHero(direction, x, y, 'rightFoot', 4*moveStep*scan[direction].x, 4*moveStep*scan[direction].y); - } - */ - if (core.status.heroMoving==8) { - core.setHeroLoc('x', x+scan[direction].x); - core.setHeroLoc('y', y+scan[direction].y); - core.moveOneStep(); - core.clearMap('hero', 0, 0, 416, 416); - core.drawHero(direction, core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); - //if (core.status.heroStop) - // core.drawHero(direction, core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); - clearInterval(core.interval.heroMoveInterval); - core.status.heroMoving = 0; - if (core.isset(callback)) callback(); - } - }, 12.5 / core.status.replay.speed); + core.control.setHeroMoveInterval(direction, x, y, callback); } ////// 实际每一步的行走过程 ////// core.prototype.moveAction = function (callback) { - if (core.interval.openDoorAnimate!=null) return; // 开门判断 - if (core.status.heroMoving>0) return; - var scan = { - 'up': {'x': 0, 'y': -1}, - 'left': {'x': -1, 'y': 0}, - 'down': {'x': 0, 'y': 1}, - 'right': {'x': 1, 'y': 0} - }; - var direction = core.getHeroLoc('direction'); - var x = core.getHeroLoc('x'); - var y = core.getHeroLoc('y'); - var noPass = core.noPass(x + scan[direction].x, y + scan[direction].y), canMove = core.canMoveHero(); - if (noPass || !canMove) { - if (core.status.event.id!='ski') - core.status.route.push(direction); - core.status.automaticRoute.moveStepBeforeStop = []; - if (canMove) // 非箭头:触发 - core.trigger(x + scan[direction].x, y + scan[direction].y); - core.drawHero(direction, x, y, 'stop'); - - // core.clearContinueAutomaticRoute(); - if (core.status.automaticRoute.moveStepBeforeStop.length==0) { - core.clearContinueAutomaticRoute(); - core.stopAutomaticRoute(); - } - - /* - if (core.status.automaticRoute.autoHeroMove) { - - core.status.automaticRoute.movedStep++; - if (core.status.automaticRoute.destStep == core.status.automaticRoute.movedStep) { - core.status.automaticRoute.autoHeroMove = false; - core.status.automaticRoute.destStep = 0; - core.status.automaticRoute.movedStep = 0; - core.status.automaticRoute.moveStepBeforeStop=[]; - core.stopAutomaticRoute(); - } - } - else { - // core.status.heroStop = true; - core.stopHero(); - } - */ - if (core.isset(callback)) - callback(); - } - else { - core.setHeroMoveInterval(direction, x, y, function () { - if (core.status.automaticRoute.autoHeroMove) { - core.status.automaticRoute.movedStep++; - core.status.automaticRoute.lastDirection = core.getHeroLoc('direction'); - if (core.status.automaticRoute.destStep == core.status.automaticRoute.movedStep) { - if (core.status.automaticRoute.autoStep == core.status.automaticRoute.autoStepRoutes.length) { - core.clearContinueAutomaticRoute(); - core.stopAutomaticRoute(); - } - else { - core.status.automaticRoute.movedStep = 0; - core.status.automaticRoute.destStep = core.status.automaticRoute.autoStepRoutes[core.status.automaticRoute.autoStep].step; - core.setHeroLoc('direction', core.status.automaticRoute.autoStepRoutes[core.status.automaticRoute.autoStep].direction); - core.status.automaticRoute.autoStep++; - } - } - } - else if (core.status.heroStop) { - core.drawHero(core.getHeroLoc('direction'), core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); - } - if (core.status.event.id!='ski') - core.status.route.push(direction); - core.trigger(core.getHeroLoc('x'), core.getHeroLoc('y')); - core.checkBlock(); - if (core.isset(callback)) callback(); - }); - } + core.control.moveAction(callback); } ////// 转向 ////// core.prototype.turnHero = function() { - if (core.status.hero.loc.direction == 'up') core.status.hero.loc.direction = 'right'; - else if (core.status.hero.loc.direction == 'right') core.status.hero.loc.direction = 'down'; - else if (core.status.hero.loc.direction == 'down') core.status.hero.loc.direction = 'left'; - else if (core.status.hero.loc.direction == 'left') core.status.hero.loc.direction = 'up'; - core.drawHero(core.status.hero.loc.direction, core.status.hero.loc.x, core.status.hero.loc.y, 'stop', 0, 0); - core.canvas.ui.clearRect(0, 0, 416, 416); - core.status.route.push("turn"); + core.control.turnHero(); } ////// 勇士能否前往某方向 ////// core.prototype.canMoveHero = function(x,y,direction,floorId) { - if (!core.isset(x)) x=core.getHeroLoc('x'); - if (!core.isset(y)) y=core.getHeroLoc('y'); - if (!core.isset(direction)) direction=core.getHeroLoc('direction'); - if (!core.isset(floorId)) floorId=core.status.floorId; - - // 检查当前块的cannotMove - if (core.isset(core.floors[floorId].cannotMove)) { - var cannotMove = core.floors[floorId].cannotMove[x+","+y]; - if (core.isset(cannotMove) && cannotMove instanceof Array && cannotMove.indexOf(direction)>=0) - return false; - } - - var nowBlock = core.getBlock(x,y,floorId); - if (nowBlock!=null){ - nowId = nowBlock.block.event.id; - var nowIsArrow = nowId.slice(0, 5).toLowerCase() == 'arrow'; - if(nowIsArrow){ - var nowArrow = nowId.slice(5).toLowerCase(); - if (direction != nowArrow) { - return false; - } - } - } - var scan = { - 'up': {'x': 0, 'y': -1}, - 'left': {'x': -1, 'y': 0}, - 'down': {'x': 0, 'y': 1}, - 'right': {'x': 1, 'y': 0} - }; - var nextBlock = core.getBlock(x+scan[direction].x,y+scan[direction].y,floorId); - if (nextBlock!=null){ - nextId = nextBlock.block.event.id; - // 遇到单向箭头处理 - var isArrow = nextId.slice(0, 5).toLowerCase() == 'arrow'; - if(isArrow){ - var nextArrow = nextId.slice(5).toLowerCase(); - if ( (scan[direction].x + scan[nextArrow].x) == 0 && (scan[direction].y + scan[nextArrow].y) == 0 ) { - return false; - } - } - } - return true; + return core.maps.canMoveHero(x,y,direction,floorId); } ////// 能否瞬间移动 ////// core.prototype.canMoveDirectly = function (destX,destY) { - if (!core.flags.enableMoveDirectly) return false; - - // 中毒状态:不能 - if (core.hasFlag('poison')) return false; - - var fromX = core.getHeroLoc('x'), fromY = core.getHeroLoc('y'); - if (fromX==destX&&fromY==destY) return false; - - if (core.getBlock(fromX,fromY)!=null||core.status.checkBlock.damage[13*fromX+fromY]>0) - return false; - - // BFS - var visited=[], queue=[]; - visited[13*fromX+fromY]=true; - queue.push(13*fromX+fromY); - - var directions = [[-1,0],[1,0],[0,1],[0,-1]]; - while (queue.length>0) { - var now=queue.shift(), nowX=parseInt(now/13), nowY=now%13; - - for (var dir in directions) { - var nx=nowX+directions[dir][0], ny=nowY+directions[dir][1]; - if (nx<0||nx>=13||ny<0||ny>=13||visited[13*nx+ny]||core.getBlock(nx,ny)!=null||core.status.checkBlock.damage[13*nx+ny]>0) continue; - if (nx==destX&&ny==destY) return true; - visited[13*nx+ny]=true; - queue.push(13*nx+ny); - } - } - return false; + return core.maps.canMoveDirectly(destX, destY); } ////// 让勇士开始移动 ////// core.prototype.moveHero = function (direction, callback) { - // 如果正在移动,直接return - if (core.status.heroMoving>0) return; - if (core.isset(direction)) - core.setHeroLoc('direction', direction); - if (!core.isset(callback)) { // 如果不存在回调函数,则使用heroMoveTrigger - core.status.heroStop = false; - core.status.automaticRoute.moveDirectly = false; - - var doAction = function () { - if (!core.status.heroStop) { - core.moveAction(); - setTimeout(doAction, 50); - } - else { - core.stopHero(); - } - } - doAction(); - } - else { // 否则,只向某个方向移动一步,然后调用callback - core.moveAction(function () { - callback(); - }) - } + core.control.moveHero(direction, callback); } /////// 使用事件让勇士移动。这个函数将不会触发任何事件 ////// core.prototype.eventMoveHero = function(steps, time, callback) { - - time = time || 100; - - core.clearMap('ui', 0, 0, 416, 416); - core.setAlpha('ui', 1.0); - - // 要运行的轨迹:将steps展开 - var moveSteps=[]; - steps.forEach(function (e) { - if (typeof e=="string") { - moveSteps.push(e); - } - else { - if (!core.isset(e.value)) { - moveSteps.push(e.direction) - } - else { - for (var i=0;i=1)core.status.automaticRoute.moveStepBeforeStop[0].step-=core.status.automaticRoute.movedStep; - } - - core.stopAutomaticRoute(); - var speed=30; - if (needKey) { - var key = id.replace("Door", "Key"); - if (!core.hasItem(key)) { - if (key != "specialKey") - core.drawTip("你没有" + core.material.items[key].name); - else core.drawTip("无法开启此门"); - core.clearContinueAutomaticRoute(); - return; - } - core.autosave(true); - core.removeItem(key); - } - - // open - core.playSound("door.ogg"); - var state = 0; - var doorId = id; - if (!(doorId.substring(doorId.length-4)=="Door")) { - doorId=doorId+"Door"; - speed=100; - } - var door = core.material.icons.animates[doorId]; - core.status.replay.animate=true; - core.interval.openDoorAnimate = window.setInterval(function () { - state++; - if (state == 4) { - clearInterval(core.interval.openDoorAnimate); - core.interval.openDoorAnimate=null; - core.removeBlock(x, y); - core.status.replay.animate=false; - core.events.afterOpenDoor(id,x,y,callback); - return; - } - core.canvas.event.clearRect(32 * x, 32 * y, 32, 32); - core.canvas.event.drawImage(core.material.images.animates, 32 * state, 32 * door, 32, 32, 32 * x, 32 * y, 32, 32); - }, speed) + core.events.openDoor(id, x, y, needKey, callback); } ////// 战斗 ////// core.prototype.battle = function (id, x, y, force, callback) { - if (core.status.automaticRoute.moveStepBeforeStop.length==0) { - core.status.automaticRoute.moveStepBeforeStop=core.status.automaticRoute.autoStepRoutes.slice(core.status.automaticRoute.autoStep-1,core.status.automaticRoute.autoStepRoutes.length); - if (core.status.automaticRoute.moveStepBeforeStop.length>=1)core.status.automaticRoute.moveStepBeforeStop[0].step-=core.status.automaticRoute.movedStep; - } - core.stopHero(); - core.stopAutomaticRoute(); - - var damage = core.enemys.getDamage(id); - // 非强制战斗 - if (damage >= core.status.hero.hp && !force) { - core.drawTip("你打不过此怪物!"); - core.clearContinueAutomaticRoute(); - return; - } - - if (!core.isset(core.status.event.id)) // 自动存档 - core.autosave(true); - - if (core.flags.battleAnimate&&!core.status.replay.replaying) { - core.waitHeroToStop(function() { - core.ui.drawBattleAnimate(id, function() { - core.afterBattle(id, x, y, callback); - }); - }); - } - else { - - if (core.flags.equipment && core.getFlag('sword', 'sword0')!='sword0') { - core.playSound('zone.ogg'); - core.drawAnimate('sword', x, y); - } - else { - core.playSound('attack.ogg'); - core.drawAnimate('hand', x, y); - } - - core.afterBattle(id, x, y, callback); - } + core.events.battle(id,x,y,force,callback); } ////// 战斗完毕 ////// core.prototype.afterBattle = function(id, x, y, callback) { - core.status.hero.hp -= core.enemys.getDamage(id); - if (core.status.hero.hp<=0) { - core.status.hero.hp=0; - core.updateStatusBar(); - core.events.lose('battle'); - return; - } - var money = core.material.enemys[id].money; - if (core.hasItem('coin')) money *= 2; - if (core.hasFlag('curse')) money=0; - core.status.hero.money += money; - var experience = core.material.enemys[id].experience; - if (core.hasFlag('curse')) experience=0; - core.status.hero.experience += experience; - if (core.isset(x) && core.isset(y)) { - core.removeBlock(x, y); - core.canvas.event.clearRect(32 * x, 32 * y, 32, 32); - } - // core.updateStatusBar(); - var hint = "打败 " + core.material.enemys[id].name; - if (core.flags.enableMoney) - hint += ",金币+" + money; - if (core.flags.enableExperience) - hint += ",经验+" + experience; - core.drawTip(hint); - - // 打完怪物,触发事件 - core.events.afterBattle(id,x,y,callback); - + core.events.afterBattle(id, x, y, callback); } ////// 触发(x,y)点的事件 ////// core.prototype.trigger = function (x, y) { - var mapBlocks = core.status.thisMap.blocks; - var noPass; - for (var b = 0; b < mapBlocks.length; b++) { - if (mapBlocks[b].x == x && mapBlocks[b].y == y && !(core.isset(mapBlocks[b].enable) && !mapBlocks[b].enable)) { // 启用事件 - noPass = mapBlocks[b].event && mapBlocks[b].event.noPass; - if (noPass) { - core.clearAutomaticRouteNode(x, y); - } - if (core.isset(mapBlocks[b].event) && core.isset(mapBlocks[b].event.trigger)) { - var trigger = mapBlocks[b].event.trigger; - - // 转换楼层能否穿透 - if (trigger=='changeFloor' && !noPass) { - var canCross = core.flags.portalWithoutTrigger; - if (core.isset(mapBlocks[b].event.data) && core.isset(mapBlocks[b].event.data.portalWithoutTrigger)) - canCross=mapBlocks[b].event.data.portalWithoutTrigger; - if (canCross) { - if (core.status.replay.replaying) { - if (core.status.replay.toReplay[0]=='no') { - core.status.replay.toReplay.shift(); - core.status.route.push("no"); - continue; - } - } - else if (core.status.automaticRoute.autoHeroMove || core.status.automaticRoute.autoStepcore.floorIds.indexOf(core.status.floorId)) - core.status.hero.flyRange.push(floorId); - else - core.status.hero.flyRange.unshift(floorId); - } - - window.setTimeout(function () { - - var changing = function () { - - // 根据文字判断是否斜体 - var floorName = core.status.maps[floorId].name; - if (!core.isset(floorName) || floorName=="") floorName=" " - core.statusBar.floor.innerHTML = floorName; - if (/^[+-]?\d+$/.test(floorName)) - core.statusBar.floor.style.fontStyle = 'italic'; - else core.statusBar.floor.style.fontStyle = 'normal'; - - // 更改BGM - if (core.isset(core.floors[floorId].bgm)) { - core.playBgm(core.floors[floorId].bgm); - } - - // 不存在事件时,更改画面色调 - if (core.status.event.id == null) { - // 默认画面色调 - if (core.isset(core.floors[floorId].color)) { - var color = core.floors[floorId].color; - - // 直接变色 - core.dom.curtain.style.background = core.arrayToRGB(color); - if (core.isset(color[3])) - core.dom.curtain.style.opacity = color[3]; - else core.dom.curtain.style.opacity=1; - core.status.curtainColor = color; - } - else { - core.dom.curtain.style.background = "#000000"; - core.dom.curtain.style.opacity = 0; - } - } - - // 更改天气 - if (core.isset(core.floors[floorId].weather)) { - core.setWeather(core.floors[floorId].weather[0], core.floors[floorId].weather[1]) - } - else core.setWeather(); - - core.drawMap(floorId, function () { - setTimeout(function() { - if (core.isset(heroLoc.direction)) - core.setHeroLoc('direction', heroLoc.direction); - core.setHeroLoc('x', heroLoc.x); - core.setHeroLoc('y', heroLoc.y); - core.drawHero(core.getHeroLoc('direction'), core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); - core.updateStatusBar(); - - var changed = function () { - core.unLockControl(); - core.status.replay.animate=false; - core.events.afterChangeFloor(floorId); - if (core.isset(callback)) callback(); - } - if (displayAnimate) { - core.mapChangeAnimate('hide', time/4, function () { - changed(); - }); - } - else { - changed(); - } - }, 25) - }); - } - core.playSound('floor.mp3'); - if (displayAnimate) { - core.mapChangeAnimate('show', time/2, function () { - changing(); - }); - } - else { - changing(); - } - }, 25); -} - -////// 地图切换动画效果 ////// -core.prototype.mapChangeAnimate = function (mode, time, callback) { - if (mode == 'show') { - core.show(core.dom.floorMsgGroup, time, function () { - callback(); - }); - } - else { - core.hide(core.dom.floorMsgGroup, time, function () { - callback(); - }); - } +core.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback, fromLoad) { + core.events.changeFloor(floorId, stair, heroLoc, time, callback, fromLoad); } ////// 清除地图 ////// core.prototype.clearMap = function (map, x, y, width, height) { - if (map == 'all') { - for (var m in core.canvas) { - core.canvas[m].clearRect(0, 0, 416, 416); - } - } - else { - core.canvas[map].clearRect(x, y, width, height); - } + core.ui.clearMap(map, x, y, width, height); } ////// 在某个canvas上绘制一段文字 ////// core.prototype.fillText = function (map, text, x, y, style, font) { - if (core.isset(style)) { - core.setFillStyle(map, style); - } - if (core.isset(font)) { - core.setFont(map, font); - } - core.canvas[map].fillText(text, x, y); + core.ui.fillText(map, text, x, y, style, font); } ////// 在某个canvas上绘制一个矩形 ////// core.prototype.fillRect = function (map, x, y, width, height, style) { - if (core.isset(style)) { - core.setFillStyle(map, style); - } - core.canvas[map].fillRect(x, y, width, height); + core.ui.fillRect(map, x, y, width, height, style) } ////// 在某个canvas上绘制一个矩形的边框 ////// core.prototype.strokeRect = function (map, x, y, width, height, style, lineWidth) { - if (core.isset(style)) { - core.setStrokeStyle(map, style); - } - if (core.isset(lineWidth)) { - core.setLineWidth(map, lineWidth); - } - core.canvas[map].strokeRect(x, y, width, height); + core.ui.strokeRect(map, x, y, width, height, style, lineWidth) } ////// 在某个canvas上绘制一条线 ////// core.prototype.drawLine = function (map, x1, y1, x2, y2, style, lineWidth) { - if (core.isset(style)) { - core.setStrokeStyle(map, style); - } - if (core.isset(lineWidth)) { - core.setLineWidth(map, lineWidth); - } - core.canvas[map].beginPath(); - core.canvas[map].moveTo(x1, y1); - core.canvas[map].lineTo(x2, y2); - core.canvas[map].closePath(); - core.canvas[map].stroke(); + core.ui.drawLine(map, x1, y1, x2, y2, style, lineWidth); } ////// 设置某个canvas的文字字体 ////// core.prototype.setFont = function (map, font) { - core.canvas[map].font = font; + core.ui.setFont(map, font); } ////// 设置某个canvas的线宽度 ////// core.prototype.setLineWidth = function (map, lineWidth) { - if (map == 'all') { - for (var m in core.canvas) { - core.canvas[m].lineWidth = lineWidth; - } - } - core.canvas[map].lineWidth = lineWidth; + core.ui.setLineWidth(map, lineWidth); } ////// 保存某个canvas状态 ////// core.prototype.saveCanvas = function (map) { - core.canvas[map].save(); + core.ui.saveCanvas(map); } ////// 加载某个canvas状态 ////// core.prototype.loadCanvas = function (map) { - core.canvas[map].restore(); + core.ui.loadCanvas(map); } ////// 设置某个canvas边框属性 ////// core.prototype.setStrokeStyle = function (map, style) { - if (map == 'all') { - for (var m in core.canvas) { - core.canvas[m].strokeStyle = style; - } - } - else { - core.canvas[map].strokeStyle = style; - } + core.ui.setStrokeStyle(map, style); } ////// 设置某个canvas的alpha值 ////// core.prototype.setAlpha = function (map, alpha) { - if (map == 'all') { - for (var m in core.canvas) { - core.canvas[m].globalAlpha = alpha; - } - } - else core.canvas[map].globalAlpha = alpha; + core.ui.setAlpha(map, alpha); } ////// 设置某个canvas的透明度 ////// core.prototype.setOpacity = function (map, opacity) { - if (map == 'all') { - for (var m in core.canvas) { - core.canvas[m].canvas.style.opacity = opacity; - } - } - else core.canvas[map].canvas.style.opacity = opacity; + core.ui.setOpacity(map, opacity); } ////// 设置某个canvas的绘制属性(如颜色等) ////// core.prototype.setFillStyle = function (map, style) { - if (map == 'all') { - for (var m in core.canvas) { - core.canvas[m].fillStyle = style; - } - } - else { - core.canvas[map].fillStyle = style; - } + core.ui.setFillStyle(map, style); +} + +core.prototype.drawBlock = function (block, animate, dx, dy) { + core.maps.drawBlock(block, animate, dx, dy); } ////// 绘制某张地图 ////// core.prototype.drawMap = function (mapName, callback) { - var mapData = core.status.maps[mapName]; - var mapBlocks = mapData.blocks; - core.status.floorId = mapName; - core.status.thisMap = mapData; - core.clearMap('all'); - core.removeGlobalAnimate(null, null, true); - var groundId = core.floors[mapName].defaultGround || "ground"; - var blockIcon = core.material.icons.terrains[groundId]; - var blockImage = core.material.images.terrains; - for (var x = 0; x < 13; x++) { - for (var y = 0; y < 13; y++) { - core.canvas.bg.drawImage(blockImage, 0, blockIcon * 32, 32, 32, x * 32, y * 32, 32, 32); - } - } - - // 如果存在png - if (core.isset(core.floors[mapName].png)) { - - var x=0, y=0, size=416; - - var png = core.floors[mapName].png; - - var ratio = size/416; - - if (typeof png == 'string') { - if (core.isset(core.material.images.pngs[png])) { - core.canvas.bg.drawImage(core.material.images.pngs[png], x, y, size, size); - } - } - else if (png instanceof Array) { - png.forEach(function (t) { - if (t.length!=3) return; - var dx=parseInt(t[0]), dy=parseInt(t[1]), p=t[2]; - if (core.isset(dx) && core.isset(dy) && core.isset(core.material.images.pngs[p])) { - dx*=32; dy*=32; - var image = core.material.images.pngs[p]; - core.canvas.bg.drawImage(image, x+dx*ratio, y+dy*ratio, Math.min(size-dx*ratio, ratio*image.width), Math.min(size-dy*ratio, ratio*image.height)); - } - }) - } - } - - var mapArray = core.maps.getMapArray(mapBlocks); - for (var b = 0; b < mapBlocks.length; b++) { - // 事件启用 - var block = mapBlocks[b]; - if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable)) { - if (block.event.cls == 'autotile') { - core.drawAutotile(core.canvas.event, mapArray, block, 32, 0, 0); - } - else { - if (block.event.id!='none') { - blockIcon = core.material.icons[block.event.cls][block.event.id]; - blockImage = core.material.images[block.event.cls]; - core.canvas.event.drawImage(core.material.images[block.event.cls], 0, blockIcon * 32, 32, 32, block.x * 32, block.y * 32, 32, 32); - core.addGlobalAnimate(block.event.animate, block.x * 32, block.y * 32, blockIcon, blockImage); - } - } - } - } - core.setGlobalAnimate(core.values.animateSpeed); - if (core.isset(callback)) - callback(); + core.maps.drawMap(mapName, callback); } ////// 绘制Autotile ////// core.prototype.drawAutotile = function(ctx, mapArr, block, size, left, top){ - var indexArrs = [ //16种组合的图块索引数组; // 将autotile分割成48块16*16的小块; 数组索引即对应各个小块 - // +----+----+----+----+----+----+ - [10, 9, 4, 3 ], //0 bin:0000 | 1 | 2 | 3 | 4 | 5 | 6 | - [10, 9, 4, 13], //1 bin:0001 +----+----+----+----+----+----+ - [10, 9, 18, 3 ], //2 bin:0010 | 7 | 8 | 9 | 10 | 11 | 12 | - [10, 9, 16, 15], //3 bin:0011 +----+----+----+----+----+----+ - [10, 43, 4, 3 ], //4 bin:0100 | 13 | 14 | 15 | 16 | 17 | 18 | - [10, 31, 4, 25], //5 bin:0101 +----+----+----+----+----+----+ - [10, 7, 2, 3 ], //6 bin:0110 | 19 | 20 | 21 | 22 | 23 | 24 | - [10, 31, 16, 5 ], //7 bin:0111 +----+----+----+----+----+----+ - [48, 9, 4, 3 ], //8 bin:1000 | 25 | 26 | 27 | 28 | 29 | 30 | - [ 8, 9, 4, 1 ], //9 bin:1001 +----+----+----+----+----+----+ - [36, 9, 30, 3 ], //10 bin:1010 | 31 | 32 | 33 | 34 | 35 | 36 | - [36, 9, 6, 15], //11 bin:1011 +----+----+----+----+----+----+ - [46, 45, 4, 3 ], //12 bin:1100 | 37 | 38 | 39 | 40 | 41 | 42 | - [46, 11, 4, 25], //13 bin:1101 +----+----+----+----+----+----+ - [12, 45, 30, 3 ], //14 bin:1110 | 43 | 44 | 45 | 46 | 47 | 48 | - [34, 33, 28, 27] //15 bin:1111 +----+----+----+----+----+----+ - ]; - - var drawBlockByIndex = function(ctx, dx, dy, autotileImg, index, size){ //index为autotile的图块索引1-48 - var sx = 16*((index-1)%6), sy = 16*(~~((index-1)/6)); - ctx.drawImage(autotileImg, sx, sy, 16, 16, dx, dy, size/2, size/2); - } - var getAutotileAroundId = function(currId, x, y){ - if(x<0 || y<0 || x>12 || y>12) return 1; - else return mapArr[y][x]==currId ? 1:0; - } - var checkAround = function(x, y){ // 得到周围四个32*32块(周围每块都包含当前块的1/4,不清楚的话画下图你就明白)的数组索引 - var currId = mapArr[y][x]; - var pointBlock = []; - for(var i=0; i<4; i++){ - var bsum = 0; - var offsetx = i%2, offsety = ~~(i/2); - for(var j=0; j<4; j++){ - var mx = j%2, my = ~~(j/2); - var b = getAutotileAroundId(currId, x+offsetx+mx-1, y+offsety+my-1); - bsum += b*(Math.pow(2, 3-j)); - } - pointBlock.push(bsum); - } - return pointBlock; - } - var getAutotileIndexs = function(x, y){ - var indexArr = []; - var pointBlocks = checkAround(x, y); - for(var i=0; i<4; i++){ - var arr = indexArrs[pointBlocks[i]] - indexArr.push(arr[3-i]); - } - return indexArr; - } - // 开始绘制autotile - var x = block.x, y = block.y; - var pieceIndexs = getAutotileIndexs(x, y); - - //修正四个边角的固定搭配 - if(pieceIndexs[0] == 13){ - if(pieceIndexs[1] == 16) pieceIndexs[1] = 14; - if(pieceIndexs[2] == 31) pieceIndexs[2] = 19; - } - if(pieceIndexs[1] == 18){ - if(pieceIndexs[0] == 15) pieceIndexs[0] = 17; - if(pieceIndexs[3] == 36) pieceIndexs[3] = 24; - } - if(pieceIndexs[2] == 43){ - if(pieceIndexs[0] == 25) pieceIndexs[0] = 37; - if(pieceIndexs[3] == 46) pieceIndexs[3] = 44; - } - if(pieceIndexs[3] == 48){ - if(pieceIndexs[1] == 30) pieceIndexs[1] = 42; - if(pieceIndexs[2] == 45) pieceIndexs[2] = 47; - } - for(var i=0; i<4; i++){ - var index = pieceIndexs[i]; - var dx = x*size + size/2*(i%2), dy = y*size + size/2*(~~(i/2)); - drawBlockByIndex(ctx, dx+left, dy+top, core.material.images['autotile'][block.event.id], index, size); - } + core.maps.drawAutotile(ctx, mapArr, block, size, left, top); } ////// 某个点是否不可通行 ////// core.prototype.noPassExists = function (x, y, floorId) { - var block = core.getBlock(x,y,floorId); - if (block==null) return false; - return core.isset(block.block.event.noPass) && block.block.event.noPass; + return core.maps.noPassExists(x,y,floorId); } ////// 某个点是否在区域内且不可通行 ////// core.prototype.noPass = function (x, y) { - return x<0 || x>12 || y<0 || y>12 || core.noPassExists(x,y); + return core.maps.noPass(x,y); } ////// 某个点是否存在NPC ////// core.prototype.npcExists = function (x, y, floorId) { - var block = core.getBlock(x,y,floorId); - if (block==null) return false; - return block.block.event.cls == 'npcs'; + return core.maps.npcExists(x, y, floorId); } ////// 某个点是否存在(指定的)地形 ////// core.prototype.terrainExists = function (x, y, id, floorId) { - var block = core.getBlock(x,y,floorId); - if (block==null) return false; - return block.block.event.cls=='terrains' && (core.isset(id)?block.block.event.id==id:true); + return core.maps.terrainExists(x, y, id, floorId); } ////// 某个点是否存在楼梯 ////// core.prototype.stairExists = function (x, y, floorId) { - var block = core.getBlock(x,y,floorId); - if (block==null) return false; - return block.block.event.cls=='terrains' && (block.block.event.id=='upFloor' || block.block.event.id=='downFloor'); + return core.maps.stairExists(x, y, floorId); } ////// 当前位置是否在楼梯边 ////// core.prototype.nearStair = function() { - var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'); - return core.stairExists(x,y) || core.stairExists(x-1,y) || core.stairExists(x,y-1) || core.stairExists(x+1,y) || core.stairExists(x,y+1); + return core.maps.nearStair(); } ////// 某个点是否存在(指定的)怪物 ////// core.prototype.enemyExists = function (x, y, id,floorId) { - var block = core.getBlock(x,y,floorId); - if (block==null) return false; - return block.block.event.cls=='enemys' && (core.isset(id)?block.block.event.id==id:true); + return core.maps.enemyExists(x, y, id, floorId); } ////// 获得某个点的block ////// core.prototype.getBlock = function (x, y, floorId, needEnable) { - if (!core.isset(floorId)) floorId=core.status.floorId; - if (!core.isset(needEnable)) needEnable=true; - var blocks = core.status.maps[floorId].blocks; - for (var n=0;n= core.values.animateSpeed * 2 / animateValue) { - animateCurrent++; - animateTime = 0; - if (animateCurrent>=animateValue) animateCurrent=0; - } - - // 已经移动完毕,消失 - if (moveSteps.length==0) { - if (immediateHide) opacityVal=0; - else opacityVal -= 0.06; - core.setOpacity('animate', opacityVal); - core.clearMap('animate', nowX, nowY, 32, 32); - core.canvas.animate.drawImage(blockImage, animateCurrent * 32, blockIcon * 32, 32, 32, nowX, nowY, 32, 32); - if (opacityVal<=0) { - clearInterval(animate); - core.loadCanvas('animate'); - core.clearMap('animate', 0, 0, 416, 416); - core.setOpacity('animate', 1); - core.status.replay.animate=false; - if (core.isset(callback)) callback(); - } - } - else { - // 移动中 - step++; - nowX+=scan[moveSteps[0]].x*2; - nowY+=scan[moveSteps[0]].y*2; - core.clearMap('animate', nowX-32, nowY-32, 96, 96); - // 绘制 - core.canvas.animate.drawImage(blockImage, animateCurrent * 32, blockIcon * 32, 32, 32, nowX, nowY, 32, 32); - if (step==16) { - // 该移动完毕,继续 - step=0; - moveSteps.shift(); - } - } - }, time / 16 / core.status.replay.speed); + core.maps.moveBlock(x,y,steps,time,immediateHide,callback) } ////// 显示/隐藏某个块时的动画效果 ////// core.prototype.animateBlock = function (loc,type,time,callback) { - if (type!='hide') type='show'; - - //clearInterval(core.interval.tipAnimate); - core.saveCanvas('animate'); - core.clearMap('animate', 0, 0, 416, 416); - - if (typeof loc[0] == 'number' && typeof loc[1] == 'number') - loc = [loc]; - - var list = []; - loc.forEach(function (t) { - var block = core.getBlock(t[0],t[1],core.status.floorId,false); - if (block==null) return; - block=block.block; - list.push({ - 'x': t[0], 'y': t[1], - 'blockIcon': core.material.icons[block.event.cls][block.event.id], - 'blockImage': core.material.images[block.event.cls] - }) - }) - - if (list.length==0) { - if (core.isset(callback)) callback(); - return; - } - - core.status.replay.animate=true; - var draw = function () { - list.forEach(function (t) { - core.canvas.animate.drawImage(t.blockImage, 0, t.blockIcon * 32, 32, 32, t.x * 32, t.y * 32, 32, 32); - }) - } - - var opacityVal = 0; - if (type=='hide') opacityVal=1; - - core.setOpacity('animate', opacityVal); - draw(); - - var animate = window.setInterval(function () { - if (type=='show') opacityVal += 0.1; - else opacityVal -= 0.1; - core.setOpacity('animate', opacityVal); - core.clearMap('animate',0,0,416,416); - - // core.canvas.animate.drawImage(blockImage, 0, blockIcon * 32, 32, 32, block.x * 32, block.y * 32, 32, 32); - draw(); - if (opacityVal >=1 || opacityVal<=0) { - clearInterval(animate); - core.loadCanvas('animate'); - core.clearMap('animate', 0, 0, 416, 416); - core.setOpacity('animate', 1); - core.status.replay.animate=false; - if (core.isset(callback)) callback(); - } - }, time / 10 / core.status.replay.speed); + core.maps.animateBlock(loc,type,time,callback) } ////// 将某个块从禁用变成启用状态 ////// core.prototype.showBlock = function(x, y, floodId) { - floodId = floodId || core.status.floorId; - var block = core.getBlock(x,y,floodId,false); - if (block==null) return; // 不存在 - block=block.block; - // 本身是禁用事件,启用之 - if (core.isset(block.enable) && !block.enable) { - block.enable = true; - // 在本层,添加动画 - if (floodId == core.status.floorId && core.isset(block.event)) { - blockIcon = core.material.icons[block.event.cls][block.event.id]; - blockImage = core.material.images[block.event.cls]; - core.canvas.event.drawImage(core.material.images[block.event.cls], 0, blockIcon * 32, 32, 32, block.x * 32, block.y * 32, 32, 32); - core.addGlobalAnimate(block.event.animate, block.x * 32, block.y * 32, blockIcon, blockImage); - // core.setGlobalAnimate(core.values.animateSpeed); - core.syncGlobalAnimate(); - } - core.updateStatusBar(); - } + core.maps.showBlock(x,y,floodId); } ////// 将某个块从启用变成禁用状态 ////// core.prototype.removeBlock = function (x, y, floorId) { - floorId = floorId || core.status.floorId; - - var block = core.getBlock(x,y,floorId,false); - if (block==null) return; // 不存在 - - var index=block.index; - - // 删除动画,清除地图 - if (floorId==core.status.floorId) { - core.removeGlobalAnimate(x, y); - core.canvas.event.clearRect(x * 32, y * 32, 32, 32); - } - - // 删除Index - core.removeBlockById(index, floorId); - core.updateFg(); + core.maps.removeBlock(x,y,floorId); } ////// 根据block的索引删除该块 ////// core.prototype.removeBlockById = function (index, floorId) { - - var blocks = core.status.maps[floorId].blocks; - var x=blocks[index].x, y=blocks[index].y; - - // 检查该点是否存在事件 - var event = core.floors[floorId].events[x+","+y]; - if (!core.isset(event)) - event = core.floors[floorId].changeFloor[x+","+y]; - - // 不存在事件,直接删除 - if (!core.isset(event)) { - blocks.splice(index,1); - return; - } - blocks[index].enable = false; + core.maps.removeBlockById(index, floorId); } ////// 一次性删除多个block ////// core.prototype.removeBlockByIds = function (floorId, ids) { - ids.sort(function (a,b) {return b-a}).forEach(function (id) { - core.removeBlockById(id, floorId); - }); + core.maps.removeBlockByIds(floorId, ids); } ////// 添加一个全局动画 ////// -core.prototype.addGlobalAnimate = function (animateMore, x, y, loc, image) { - if (animateMore == 2) { - core.status.twoAnimateObjs.push({ - 'x': x, - 'y': y, - 'status': 0, - 'loc': loc, - 'image': image - }); - } - else if (animateMore == 4) { - core.status.fourAnimateObjs.push({ - 'x': x, - 'y': y, - 'status': 0, - 'loc': loc, - 'image': image - }); - } +core.prototype.addGlobalAnimate = function (block) { + core.maps.addGlobalAnimate(block); } ////// 删除一个或所有全局动画 ////// core.prototype.removeGlobalAnimate = function (x, y, all) { - if (all == true) { - core.status.twoAnimateObjs = []; - core.status.fourAnimateObjs = []; - } - for (var t = 0; t < core.status.twoAnimateObjs.length; t++) { - if (core.status.twoAnimateObjs[t].x == x * 32 && core.status.twoAnimateObjs[t].y == y * 32) { - core.status.twoAnimateObjs.splice(t, 1); - return; - } - } - for (var f = 0; f < core.status.fourAnimateObjs.length; f++) { - if (core.status.fourAnimateObjs[f].x == x * 32 && core.status.fourAnimateObjs[f].y == y * 32) { - core.status.fourAnimateObjs.splice(f, 1); - return; - } - } + core.maps.removeGlobalAnimate(x, y, all); } ////// 设置全局动画的显示效果 ////// core.prototype.setGlobalAnimate = function (speed) { - /* - clearInterval(core.interval.twoAnimate); - clearInterval(core.interval.fourAnimate); - var animateClose = false; - core.interval.twoAnimate = window.setInterval(function () { - for (var a = 0; a < core.status.twoAnimateObjs.length; a++) { - var obj = core.status.twoAnimateObjs[a]; - obj.status = (obj.status+1)%2; - core.canvas.event.clearRect(obj.x, obj.y, 32, 32); - if (!animateClose) { - core.canvas.event.drawImage(obj.image, obj.status * 32, obj.loc * 32, 32, 32, obj.x, obj.y, 32, 32); - } - animateClose = false; - } - }, speed); - core.interval.fourAnimate = window.setInterval(function () { - for (var a = 0; a < core.status.fourAnimateObjs.length; a++) { - var obj=core.status.fourAnimateObjs[a]; - obj.status = (obj.status+1)%4; - core.canvas.event.clearRect(obj.x, obj.y, 32, 32); - if (!animateClose) { - core.canvas.event.drawImage(obj.image, obj.status * 32, obj.loc * 32, 32, 32, obj.x, obj.y, 32, 32); - } - animateClose = false; - } - }, speed / 2); - */ - core.syncGlobalAnimate(); - core.animateFrame.speed = speed; - core.animateFrame.globalAnimate = true; + core.maps.setGlobalAnimate(speed); } ////// 同步所有的全局动画效果 ////// core.prototype.syncGlobalAnimate = function () { - core.status.twoAnimateObjs.forEach(function (t) { - t.status=0; - }) - core.status.fourAnimateObjs.forEach(function (t) { - t.status=0; - }) + core.maps.syncGlobalAnimate(); } ////// 绘制UI层的box动画 ////// core.prototype.drawBoxAnimate = function () { - for (var a = 0; a < core.status.boxAnimateObjs.length; a++) { - var obj = core.status.boxAnimateObjs[a]; - obj.status = ((obj.status||0)+1)%2; - core.clearMap('ui', obj.bgx, obj.bgy, obj.bgsize, obj.bgsize); - core.fillRect('ui', obj.bgx, obj.bgy, obj.bgsize, obj.bgsize, core.animateFrame.background); - core.canvas.ui.drawImage(obj.image, obj.status * 32, obj.icon * 32, - 32, 32, obj.x, obj.y, 32, 32); - } + core.maps.drawBoxAnimate(); } ////// 绘制动画 ////// core.prototype.drawAnimate = function (name, x, y, callback) { - - // 正在播放录像:不显示动画 - if (core.isset(core.status.replay) && core.status.replay.replaying) { - if (core.isset(callback)) callback(); - return; - } - - // 检测动画是否存在 - if (!core.isset(core.material.animates[name]) || !core.isset(x) || !core.isset(y)) { - if (core.isset(callback)) callback(); - return; - } - - // 清空animate层 - clearInterval(core.interval.animateInterval); - core.clearMap('animate', 0, 0, 416, 416); - - // 开始绘制 - var animate = core.material.animates[name]; - var ratio = animate.ratio; - var centerX = 32*x+16, centerY = 32*y+16; - var index=0; - - var draw = function (index) { - core.clearMap('animate', 0, 0, 416, 416); - - var frame = animate.frames[index]; - frame.forEach(function (t) { - var image = animate.images[t.index]; - if (!core.isset(image)) return; - var realWidth = image.width * ratio * t.zoom / 100; - var realHeight = image.height * ratio * t.zoom / 100; - core.setAlpha('animate', t.opacity / 255); - - var cx = centerX+t.x, cy=centerY+t.y; - - if (!t.mirror && !t.angle) { - core.canvas.animate.drawImage(image, cx-realWidth/2, cy-realHeight/2, realWidth, realHeight); - } - else { - core.saveCanvas('animate'); - core.canvas.animate.translate(cx,cy); - if (t.angle) - core.canvas.animate.rotate(-t.angle*Math.PI/180); - if (t.mirror) - core.canvas.animate.scale(-1,1); - core.canvas.animate.drawImage(image, -realWidth/2, -realHeight/2, realWidth, realHeight); - core.loadCanvas('animate'); - } - }) - } - - draw(index++); - - core.interval.animateInterval = setInterval(function (t) { - if (index == animate.frames.length) { - clearInterval(core.interval.animateInterval); - core.clearMap('animate', 0, 0, 416, 416); - core.setAlpha('animate', 1); - if (core.isset(callback)) callback(); - return; - } - draw(index++); - }, 50); + core.maps.drawAnimate(name, x, y, callback); } ////// 更新领域、夹击、阻击的伤害地图 ////// core.prototype.updateCheckBlock = function() { - core.status.checkBlock = {}; - if (!core.isset(core.status.thisMap)) return; - var blocks = core.status.thisMap.blocks; - - // Step1: 更新怪物地图 - core.status.checkBlock.map = []; // 记录怪物地图 - for (var n=0;n12 || ny<0 || ny>12) continue; - if (!zoneSquare && Math.abs(dx)+Math.abs(dy)>range) continue; - core.status.checkBlock.damage[13*nx+ny]+=enemy.value; - } - } - } - // 存在阻击 - if (core.enemys.hasSpecial(enemy.special, 18)) { - for (var dx=-1;dx<=1;dx++) { - for (var dy=-1;dy<=1;dy++) { - if (dx==0 && dy==0) continue; - var nx=x+dx, ny=y+dy; - if (nx<0 || nx>12 || ny<0 || ny>12 || Math.abs(dx)+Math.abs(dy)>1) continue; - core.status.checkBlock.damage[13*nx+ny]+=enemy.value; - } - } - } - } - } - } - - - // Step3: 更新夹击点坐标,并将夹击伤害加入到damage中 - core.status.checkBlock.betweenAttack = []; // 记录(x,y)点是否有夹击 - for (var x=0;x<13;x++) { - for (var y=0;y<13;y++) { - var has=false; - if (x>0 && x<12) { - var id1=core.status.checkBlock.map[13*(x-1)+y], - id2=core.status.checkBlock.map[13*(x+1)+y]; - if (core.isset(id1) && core.isset(id2) && id1==id2) { - var enemy = core.enemys.getEnemys(id1); - if (core.enemys.hasSpecial(enemy.special, 16)) { - has = true; - } - } - } - if (y>0 && y<12) { - var id1=core.status.checkBlock.map[13*x+y-1], - id2=core.status.checkBlock.map[13*x+y+1]; - if (core.isset(id1) && core.isset(id2) && id1==id2) { - var enemy = core.enemys.getEnemys(id1); - if (core.enemys.hasSpecial(enemy.special, 16)) { - has = true; - } - } - } - // 存在夹击 - if (has) { - core.status.checkBlock.betweenAttack[13*x+y]=true; - var leftHp = core.status.hero.hp - core.status.checkBlock.damage[13*x+y]; - if (leftHp>1) - core.status.checkBlock.damage[13*x+y] += parseInt((leftHp+(core.flags.betweenAttackCeil?0:1))/2); - } - } - } + core.control.updateCheckBlock(); } ////// 检查并执行领域、夹击、阻击事件 ////// core.prototype.checkBlock = function () { - var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'); - var damage = core.status.checkBlock.damage[13*x+y]; - if (damage>0) { - core.status.hero.hp -= damage; - - // 检查阻击事件 - var snipe = []; - var scan = { - 'up': {'x': 0, 'y': -1}, - 'left': {'x': -1, 'y': 0}, - 'down': {'x': 0, 'y': 1}, - 'right': {'x': 1, 'y': 0} - } - for (var direction in scan) { - var nx = x+scan[direction].x, ny=y+scan[direction].y; - if (nx<0 || nx>12 || ny<0 || ny>12) continue; - var id=core.status.checkBlock.map[13*nx+ny]; - if (core.isset(id)) { - var enemy = core.enemys.getEnemys(id); - if (core.isset(enemy) && core.enemys.hasSpecial(enemy.special, 18)) { - snipe.push({'direction': direction, 'x': nx, 'y': ny}); - } - } - } - - if (core.status.checkBlock.betweenAttack[13*x+y] && damage>0) { - core.drawTip('受到夹击,生命变成一半'); - } - // 阻击 - else if (snipe.length>0 && damage>0) { - core.drawTip('受到阻击伤害'+damage+'点'); - } - else if (damage>0) { - core.drawTip('受到领域伤害'+damage+'点'); - } - - core.playSound('zone.ogg'); - core.drawAnimate("zone", x, y); - - if (core.status.hero.hp<=0) { - core.status.hero.hp=0; - core.updateStatusBar(); - core.events.lose('zone'); - return; - } - snipe = snipe.filter(function (t) { - var x=t.x, y=t.y, direction = t.direction; - var nx = x+scan[direction].x, ny=y+scan[direction].y; - - return nx>=0 && nx<=12 && ny>=0 && ny<=12 && core.getBlock(nx, ny, core.status.floorId, false)==null; - }); - core.updateStatusBar(); - if (snipe.length>0) - core.snipe(snipe); - } + core.control.checkBlock(); } ////// 阻击事件(动画效果) ////// core.prototype.snipe = function (snipes) { - - var scan = { - 'up': {'x': 0, 'y': -1}, - 'left': {'x': -1, 'y': 0}, - 'down': {'x': 0, 'y': 1}, - 'right': {'x': 1, 'y': 0} - }; - - snipes.forEach(function (snipe) { - var x=snipe.x, y=snipe.y, direction = snipe.direction; - snipe.nx = x+scan[snipe.direction].x; - snipe.ny = y+scan[snipe.direction].y; - - core.removeGlobalAnimate(x, y); - - var block = core.getBlock(x,y).block; - - snipe.blockIcon = core.material.icons[block.event.cls][block.event.id]; - snipe.blockImage = core.material.images[block.event.cls]; - var damage = core.enemys.getDamage(block.event.id); - - var color = "#000000"; - if (damage <= 0) color = '#00FF00'; - else if (damage < core.status.hero.hp / 3) color = '#FFFFFF'; - else if (damage < core.status.hero.hp * 2 / 3) color = '#FFFF00'; - else if (damage < core.status.hero.hp) color = '#FF7F00'; - else color = '#FF0000'; - - if (damage >= 999999999) damage = "???"; - else if (damage > 100000) damage = (damage / 10000).toFixed(1) + "w"; - - snipe.damage = damage; - snipe.color = color; - snipe.block = core.clone(block); - }) - - var finishSnipe = function () { - snipes.forEach(function (t) { - core.removeBlock(t.x, t.y); - var nBlock = core.clone(t.block); - nBlock.x = t.nx; nBlock.y = t.ny; - core.status.thisMap.blocks.push(nBlock); - core.addGlobalAnimate(2, 32*t.nx, 32*t.ny, t.blockIcon, t.blockImage); - core.canvas.event.drawImage(t.blockImage, 0, t.blockIcon*32, 32, 32, 32*t.nx, 32*t.ny, 32, 32); - }); - core.syncGlobalAnimate(); - core.updateStatusBar(); - return; - } - - if (core.status.replay.replaying) { - finishSnipe(); - } - else { - core.waitHeroToStop(function() { - - core.lockControl(); - - var time = 500, step = 0; - - var animateValue = 2; - var animateCurrent = 0; - var animateTime = 0; - - core.canvas.fg.textAlign = 'left'; - - var animate=window.setInterval(function() { - - step++; - animateTime += time / 16; - if (animateTime >= core.values.animateSpeed * 2 / animateValue) { - animateCurrent++; - animateTime = 0; - if (animateCurrent>=animateValue) animateCurrent=0; - } - - snipes.forEach(function (snipe) { - var x=snipe.x, y=snipe.y, direction = snipe.direction; - - var nowX=32*x+scan[direction].x*2*step, nowY=32*y+scan[direction].y*2*step; - - // 清空上一次 - core.clearMap('event', nowX-2*scan[direction].x, nowY-2*scan[direction].y, 32, 32); - core.clearMap('fg', nowX-2*scan[direction].x, nowY-2*scan[direction].y, 32, 32); - - core.canvas.event.drawImage(snipe.blockImage, animateCurrent*32, snipe.blockIcon*32, 32, 32, nowX, nowY, 32, 32); - - if (core.hasItem('book')) { - // drawFG - core.setFillStyle('fg', '#000000'); - core.canvas.fg.fillText(snipe.damage, nowX + 2, nowY + 30); - core.canvas.fg.fillText(snipe.damage, nowX, nowY + 30); - core.canvas.fg.fillText(snipe.damage, nowX + 2, nowY + 32); - core.canvas.fg.fillText(snipe.damage, nowX, nowY + 32); - - core.setFillStyle('fg', snipe.color); - core.canvas.fg.fillText(snipe.damage, nowX + 1, nowY + 31); - } - - }) - - if (step==16) { // 移动完毕 - clearInterval(animate); - finishSnipe(); - // 不存在自定义事件 - if (core.status.event.id==null) - core.unLockControl(); - } - }, time/16); - }); - } - - + core.control.snipe(snipes); } ////// 更改天气效果 ////// core.prototype.setWeather = function (type, level) { - - // 非雨雪 - if (type!='rain' && type!='snow') { - core.clearMap('weather', 0, 0, 416, 416) - core.animateFrame.weather.type = null; - core.animateFrame.weather.level = 0; - core.animateFrame.weather.nodes = []; - return; - } - - level = parseInt(level); - - // 当前天气:则忽略 - if (type==core.animateFrame.weather.type && - (!core.isset(level) || 20*level==core.animateFrame.weather.level)) { - return; - } - - if (!core.isset(level)) level=5; - if (level<1) level=1; if (level>10) level=10; - level *= 20; - - core.clearMap('weather', 0, 0, 416, 416) - core.animateFrame.weather.type = type; - core.animateFrame.weather.level = level; - - core.animateFrame.weather.nodes = []; - - if (type == 'rain') { - for (var a=0;a1) color[3]=1; - - if (time==0) { - // 直接变色 - core.dom.curtain.style.background = core.arrayToRGB(color); - core.dom.curtain.style.opacity = color[3]; - core.status.curtainColor = color; - if (core.isset(callback)) callback(); - return; - } - - var step=0; - core.status.replay.animate=true; - var changeAnimate = setInterval(function() { - step++; - - var nowAlpha = fromColor[3]+(color[3]-fromColor[3])*step/25; - var nowR = parseInt(fromColor[0]+(color[0]-fromColor[0])*step/25); - var nowG = parseInt(fromColor[1]+(color[1]-fromColor[1])*step/25); - var nowB = parseInt(fromColor[2]+(color[2]-fromColor[2])*step/25); - core.dom.curtain.style.background = core.arrayToRGB([nowR,nowG,nowB]); - core.dom.curtain.style.opacity = nowAlpha; - - if (step>=25) { - clearInterval(changeAnimate); - core.status.curtainColor = color; - core.status.replay.animate=false; - if (core.isset(callback)) callback(); - } - }, time/25); - + core.control.setFg(color, time, callback); } ////// 更新全地图显伤 ////// core.prototype.updateFg = function () { - - if (!core.isset(core.status.thisMap) || !core.isset(core.status.thisMap.blocks)) return; - // 更新显伤 - var mapBlocks = core.status.thisMap.blocks; - core.clearMap('fg', 0, 0, 416, 416); - // 没有怪物手册 - if (!core.hasItem('book')) return; - core.setFont('fg', "bold 11px Arial"); - var hero_hp = core.status.hero.hp; - if (core.flags.displayEnemyDamage) { - core.canvas.fg.textAlign = 'left'; - for (var b = 0; b < mapBlocks.length; b++) { - var x = mapBlocks[b].x, y = mapBlocks[b].y; - if (core.isset(mapBlocks[b].event) && mapBlocks[b].event.cls == 'enemys' - && !(core.isset(mapBlocks[b].enable) && !mapBlocks[b].enable)) { - - // 非系统默认的战斗事件(被覆盖) - if (mapBlocks[b].event.trigger != 'battle') { - // 判断显伤 - var event = core.floors[core.status.floorId].events[x+","+y]; - if (core.isset(event) && !(event instanceof Array)) { - if (core.isset(event.displayDamage) && !event.displayDamage) - continue; - } - } - - var id = mapBlocks[b].event.id; - - var damage = core.enemys.getDamage(id); - var color = "#000000"; - if (damage <= 0) color = '#00FF00'; - else if (damage < hero_hp / 3) color = '#FFFFFF'; - else if (damage < hero_hp * 2 / 3) color = '#FFFF00'; - else if (damage < hero_hp) color = '#FF7F00'; - else color = '#FF0000'; - - if (damage >= 999999999) damage = "???"; - else if (damage > 100000) damage = (damage / 10000).toFixed(1) + "w"; - - core.setFillStyle('fg', '#000000'); - core.canvas.fg.fillText(damage, 32 * x + 2, 32 * (y + 1) - 2); - core.canvas.fg.fillText(damage, 32 * x, 32 * (y + 1) - 2); - core.canvas.fg.fillText(damage, 32 * x + 2, 32 * (y + 1)); - core.canvas.fg.fillText(damage, 32 * x, 32 * (y + 1)); - - core.setFillStyle('fg', color); - core.canvas.fg.fillText(damage, 32 * x + 1, 32 * (y + 1) - 1); - - } - } - } - // 如果是领域&夹击 - if (core.flags.displayExtraDamage) { - core.canvas.fg.textAlign = 'center'; - for (var x=0;x<13;x++) { - for (var y=0;y<13;y++) { - var damage = core.status.checkBlock.damage[13*x+y]; - if (damage>0) { - core.setFillStyle('fg', '#000000'); - core.canvas.fg.fillText(damage, 32 * x + 17, 32 * (y + 1) - 13); - core.canvas.fg.fillText(damage, 32 * x + 15, 32 * (y + 1) - 15); - core.canvas.fg.fillText(damage, 32 * x + 17, 32 * (y + 1) - 15); - core.canvas.fg.fillText(damage, 32 * x + 15, 32 * (y + 1) - 13); - - core.setFillStyle('fg', '#FF7F00'); - core.canvas.fg.fillText(damage, 32 * x + 16, 32 * (y + 1) - 14); - } - } - } - } + core.control.updateFg(); } ////// 获得某个物品的个数 ////// core.prototype.itemCount = function (itemId) { - if (!core.isset(itemId) || !core.isset(core.material.items[itemId])) return 0; - var itemCls = core.material.items[itemId].cls; - if (itemCls=="items") return 0; - return core.isset(core.status.hero.items[itemCls][itemId]) ? core.status.hero.items[itemCls][itemId] : 0; + return core.items.itemCount(itemId); } ////// 是否存在某个物品 ////// core.prototype.hasItem = function (itemId) { - return core.itemCount(itemId) > 0; + return core.items.hasItem(itemId); } ////// 设置某个物品的个数 ////// core.prototype.setItem = function (itemId, itemNum) { - var itemCls = core.material.items[itemId].cls; - if (itemCls == 'items') return; - if (!core.isset(core.status.hero.items[itemCls])) { - core.status.hero.items[itemCls] = {}; - } - core.status.hero.items[itemCls][itemId] = itemNum; - if (itemCls!='keys' && itemNum==0) { - delete core.status.hero.items[itemCls][itemId]; - } + core.items.setItem(itemId, itemNum); } ////// 删除某个物品 ////// core.prototype.removeItem = function (itemId) { - if (!core.hasItem(itemId)) return false; - var itemCls = core.material.items[itemId].cls; - core.status.hero.items[itemCls][itemId]--; - if (itemCls!='keys' && core.status.hero.items[itemCls][itemId]==0) { - delete core.status.hero.items[itemCls][itemId]; - } - core.updateStatusBar(); - return true; + return core.items.removeItem(itemId); } ////// 使用某个物品 ////// core.prototype.useItem = function (itemId, callback) { core.items.useItem(itemId, callback); - return; } ////// 能否使用某个物品 ////// @@ -3784,155 +782,27 @@ core.prototype.canUseItem = function (itemId) { ////// 增加某个物品的个数 ////// core.prototype.addItem = function (itemId, itemNum) { - var itemData = core.material.items[itemId]; - var itemCls = itemData.cls; - if (itemCls == 'items') return; - if (!core.isset(core.status.hero.items[itemCls])) { - core.status.hero.items[itemCls] = {}; - core.status.hero.items[itemCls][itemId] = 0; - } - else if (!core.isset(core.status.hero.items[itemCls][itemId])) { - core.status.hero.items[itemCls][itemId] = 0; - } - core.status.hero.items[itemCls][itemId] += itemNum; + core.items.addItem(itemId, itemNum); } ////// 获得面前的物品(轻按) ////// core.prototype.getNextItem = function() { - if (!core.status.heroStop || !core.flags.enableGentleClick) return; - var nextX = core.nextX(), nextY = core.nextY(); - var block = core.getBlock(nextX, nextY); - if (block==null) return; - if (block.block.event.trigger=='getItem') { - core.getItem(block.block.event.id, 1, nextX, nextY); - core.status.route.push("getNext"); - } + core.events.getNextItem(); } ////// 获得某个物品 ////// core.prototype.getItem = function (itemId, itemNum, itemX, itemY, callback) { - // core.getItemAnimate(itemId, itemNum, itemX, itemY); - core.playSound('item.ogg'); - var itemCls = core.material.items[itemId].cls; - core.items.getItemEffect(itemId, itemNum); - core.removeBlock(itemX, itemY); - var text = '获得 ' + core.material.items[itemId].name; - if (itemNum > 1) text += "x" + itemNum; - if (itemCls === 'items') text += core.items.getItemEffectTip(itemId); - core.drawTip(text, core.material.icons.items[itemId]); - core.canvas.event.clearRect(itemX * 32, itemY * 32, 32, 32); - core.updateStatusBar(); - - // 检查处理后的事件。 - var event = core.floors[core.status.floorId].afterGetItem[itemX+","+itemY]; - if (core.isset(event)) { - core.events.doEvents(event, itemX, itemY, callback); - } - else if (core.isset(callback)) callback(); + core.events.getItem(itemId, itemNum, itemX, itemY, callback); } ////// 左上角绘制一段提示 ////// core.prototype.drawTip = function (text, itemIcon) { - var textX, textY, width, height, hide = false, opacityVal = 0; - clearInterval(core.interval.tipAnimate); - core.setFont('data', "16px Arial"); - core.saveCanvas('data'); - core.setOpacity('data', 0); - core.canvas.data.textAlign = 'left'; - if (!core.isset(itemIcon)) { - textX = 16; - textY = 18; - width = textX + core.canvas.data.measureText(text).width + 16; - height = 42; - } - else { - textX = 44; - textY = 18; - width = textX + core.canvas.data.measureText(text).width + 8; - height = 42; - } - core.interval.tipAnimate = window.setInterval(function () { - if (hide) { - opacityVal -= 0.1; - } - else { - opacityVal += 0.1; - } - core.setOpacity('data', opacityVal); - core.clearMap('data', 5, 5, 400, height); - core.fillRect('data', 5, 5, width, height, '#000'); - if (core.isset(itemIcon)) { - core.canvas.data.drawImage(core.material.images.items, 0, itemIcon * 32, 32, 32, 10, 8, 32, 32); - } - core.fillText('data', text, textX + 5, textY + 15, '#fff'); - if (opacityVal > 0.6 || opacityVal < 0) { - if (hide) { - core.loadCanvas('data'); - core.clearMap('data', 5, 5, 400, height); - core.setOpacity('data', 1); - clearInterval(core.interval.tipAnimate); - return; - } - else { - if (!core.isset(core.timeout.getItemTipTimeout)) { - core.timeout.getItemTipTimeout = window.setTimeout(function () { - hide = true; - core.timeout.getItemTipTimeout = null; - }, 750); - } - opacityVal = 0.6; - core.setOpacity('data', opacityVal); - } - } - }, 30); + core.ui.drawTip(text, itemIcon); } ////// 地图中间绘制一段文字 ////// core.prototype.drawText = function (contents, callback) { - if (core.isset(contents)) { - - // 合并 - if (core.isset(core.status.event)&&core.status.event.id=='action') { - core.insertAction(contents,null,null,callback); - return; - } - - if (typeof contents == 'string') { - contents = [{'content': contents}]; - } - else if (contents instanceof Object && core.isset(contents.content)) { - contents = [contents]; - } - else if (!(contents instanceof Array)) { - core.drawTip("出错了"); - console.log(contents); - return; - } - - core.status.event = {'id': 'text', 'data': {'list': contents, 'callback': callback}}; - core.lockControl(); - - // wait the hero to stop - core.stopAutomaticRoute(); - setTimeout(function() { - core.drawText(); - }, 30); - return; - } - - if (core.status.event.data.list.length==0) { - var callback = core.status.event.data.callback; - core.ui.closePanel(false); - if (core.isset(callback)) callback(); - return; - } - - var data=core.status.event.data.list.shift(); - if (typeof data == 'string') - core.ui.drawTextBox(data); - else - core.ui.drawTextBox(data.content, data.id); - // core.drawTextBox(content); + core.ui.drawText(contents, callback); } /////////// 地图相关 END /////////// @@ -3944,996 +814,231 @@ core.prototype.drawText = function (contents, callback) { ////// 将文字中的${和}(表达式)进行替换 ////// core.prototype.replaceText = function (text) { - return text.replace(/\${([^}]+)}/g, function (word, value) { - return core.calValue(value); - }); + return core.utils.replaceText(text); } ////// 计算表达式的值 ////// core.prototype.calValue = function (value) { - value=value.replace(/status:([\w\d_]+)/g, "core.getStatus('$1')"); - value=value.replace(/item:([\w\d_]+)/g, "core.itemCount('$1')"); - value=value.replace(/flag:([\w\d_]+)/g, "core.getFlag('$1', false)"); - return eval(value); + return core.utils.calValue(value); } ////// 执行一个表达式的effect操作 ////// core.prototype.doEffect = function (expression) { - // 必须使用"+=" - var arr = expression.split("+="); - if (arr.length!=2) return; - var name=arr[0], value=core.calValue(arr[1]); - if (name.indexOf("status:")==0) { - var status=name.substring(7); - core.setStatus(status, core.getStatus(status)+value); - } - else if (name.indexOf("item:")==0) { - var itemId=name.substring(5); - core.setItem(itemId, core.itemCount(itemId)+value); - } + core.control.doEffect(expression); } ////// 字符串自动换行的分割 ////// core.prototype.splitLines = function(canvas, text, maxLength, font) { - if (core.isset(font)) core.setFont(canvas, font); - - var contents = []; - var last = 0; - for (var i=0;imaxLength) { - contents.push(text.substring(last, i)); - last=i; - } - } - } - contents.push(text.substring(last)); - return contents; + return core.utils.splitLines(canvas, text, maxLength, font); } ////// 向某个数组前插入另一个数组或元素 ////// core.prototype.unshift = function (a,b) { - if (!(a instanceof Array) || !core.isset(b)) return; - if (b instanceof Array) { - core.clone(b).reverse().forEach(function (e) { - a.unshift(e); - }); - } - else a.unshift(b); - return a; + return core.utils.unshift(a,b); } ////// 设置本地存储 ////// core.prototype.setLocalStorage = function(key, value) { - try { - localStorage.setItem(core.firstData.name + "_" + key, JSON.stringify(value)); - return true; - } - catch (e) { - console.log(e); - return false; - } + return core.utils.setLocalStorage(key, value); } ////// 获得本地存储 ////// core.prototype.getLocalStorage = function(key, defaultValue) { - var value = localStorage.getItem(core.firstData.name+"_"+key); - if (core.isset(value)) return JSON.parse(value); - return defaultValue; + return core.utils.getLocalStorage(key, defaultValue); } ////// 移除本地存储 ////// core.prototype.removeLocalStorage = function (key) { - localStorage.removeItem(core.firstData.name+"_"+key); + core.utils.removeLocalStorage(key); } ////// 深拷贝一个对象 ////// core.prototype.clone = function (data) { - if (!core.isset(data)) return data; - // 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=0;i255) nowR=255; if (nowB>255) nowB=255; if (nowG>255) nowG=255; - return "#"+((1<<24)+(nowR<<16)+(nowG<<8)+nowB).toString(16).slice(1); + return core.utils.arrayToRGB(color); } ////// 作弊 ////// core.prototype.debug = function() { - core.setStatus('hp', 999999); - core.setStatus('atk', 10000); - core.setStatus('def', 10000); - core.setStatus('mdef', 10000); - core.setStatus('money', 10000); - core.setStatus('experience', 10000); - core.setItem('yellowKey', 50); - core.setItem('blueKey', 50); - core.setItem('redKey', 50); - core.setItem('book', 1); - core.setItem('fly', 1); - for (var i in core.status.maps) - if (core.status.maps[i].canFlyTo && core.status.hero.flyRange.indexOf(i)<0) - core.status.hero.flyRange.push(i); - core.updateStatusBar(); - core.drawTip("作弊成功"); + core.control.debug(); } ////// 开始播放 ////// core.prototype.startReplay = function (list) { - core.status.replay.replaying=true; - core.status.replay.pausing=false; - core.status.replay.speed=1.0; - core.status.replay.toReplay = core.clone(list); - core.status.replay.totalList = core.clone(list); - core.updateStatusBar(); - core.drawTip("开始播放"); - this.replay(); - return; + core.control.startReplay(list); } ////// 更改播放状态 ////// core.prototype.triggerReplay = function () { - if (core.status.replay.pausing) this.resumeReplay(); - else this.pauseReplay(); + core.control.triggerReplay(); } ////// 暂停播放 ////// core.prototype.pauseReplay = function () { - if (!core.status.replay.replaying) return; - core.status.replay.pausing = true; - core.updateStatusBar(); - core.drawTip("暂停播放"); + core.control.pauseReplay(); } ////// 恢复播放 ////// core.prototype.resumeReplay = function () { - if (!core.status.replay.replaying) return; - core.status.replay.pausing = false; - core.updateStatusBar(); - core.drawTip("恢复播放"); - core.replay(); + core.control.resumeReplay(); } ////// 加速播放 ////// core.prototype.forwardReplay = function () { - if (!core.status.replay.replaying) return; - core.status.replay.speed = parseInt(10*core.status.replay.speed + 1)/10; - if (core.status.replay.speed>2.5) core.status.replay.speed=2.5; - core.drawTip("x"+core.status.replay.speed+"倍"); + core.control.forwardReplay(); } ////// 减速播放 ////// core.prototype.rewindReplay = function () { - if (!core.status.replay.replaying) return; - core.status.replay.speed = parseInt(10*core.status.replay.speed - 1)/10; - if (core.status.replay.speed<0.3) core.status.replay.speed=0.3; - core.drawTip("x"+core.status.replay.speed+"倍"); + core.control.rewindReplay(); } ////// 停止播放 ////// core.prototype.stopReplay = function () { - if (!core.status.replay.replaying) return; - core.status.replay.toReplay = []; - core.status.replay.totalList = []; - core.status.replay.replaying=false; - core.status.replay.pausing=false; - core.status.replay.speed=1.0; - core.updateStatusBar(); - core.drawTip("停止播放并恢复游戏"); + core.control.stopReplay(); } ////// 回放 ////// core.prototype.replay = function () { - - if (!core.status.replay.replaying) return; // 没有回放 - if (core.status.replay.pausing) return; // 暂停状态 - if (core.status.replay.animate) return; // 正在某段动画中 - - if (core.status.replay.toReplay.length==0) { // 回放完毕 - core.stopReplay(); - core.insertAction("录像回放完毕!"); - return; - } - - var action=core.status.replay.toReplay.shift(); - - if (action=='up' || action=='down' || action=='left' || action=='right') { - core.moveHero(action, function () { - core.replay(); - }); - return; - } - else if (action.indexOf("item:")==0) { - var itemId = action.substring(5); - if (core.canUseItem(itemId)) { - var tools = Object.keys(core.status.hero.items.tools).sort(); - var constants = Object.keys(core.status.hero.items.constants).sort(); - var index; - if ((index=tools.indexOf(itemId))>=0 || (index=constants.indexOf(itemId)+100)>=100) { - core.ui.drawToolbox(index); - setTimeout(function () { - core.ui.closePanel(); - core.useItem(itemId, function () { - core.replay(); - }); - }, 750); - } - return; - } - } - else if (action.indexOf("fly:")==0) { - var floorId=action.substring(4); - var toIndex=core.status.hero.flyRange.indexOf(floorId); - var nowIndex=core.status.hero.flyRange.indexOf(core.status.floorId); - if (core.hasItem('fly') && toIndex>=0 && nowIndex>=0) { - core.ui.drawFly(toIndex); - setTimeout(function () { - core.ui.closePanel(); - var stair=toIndex0) { - var shop=core.status.shops[shopId]; - if (core.isset(shop) && shop.visited) { // 商店可用 - var choices = shop.choices; - var topIndex = 6 - parseInt(choices.length / 2); - - core.status.event.selection = parseInt(selections.shift()); - - core.events.openShop(shopId, false); - var shopInterval = setInterval(function () { - if (!core.events.clickShop(6, topIndex+core.status.event.selection)) { - clearInterval(shopInterval); - core.stopReplay(); - core.drawTip("录像文件出错"); - return; - } - if (selections.length==0) { - clearInterval(shopInterval); - core.events.clickShop(6, topIndex+choices.length); - core.replay(); - return; - } - core.status.event.selection = parseInt(selections.shift()); - core.events.openShop(shopId, false); - - }, 750); - return; - } - } - } - else if (action=='turn') { - core.turnHero(); - core.replay(); - return; - } - else if (action=='getNext') { - if (core.flags.enableGentleClick && core.getBlock(core.nextX(), core.nextY())!=null) { - var nextX = core.nextX(), nextY = core.nextY(); - var block = core.getBlock(nextX, nextY); - if (block!=null && block.block.event.trigger=='getItem') { - core.getItem(block.block.event.id, 1, nextX, nextY); - core.status.route.push("getNext"); - core.replay(); - return; - } - } - } - else if (action.indexOf('move:')==0) { - var pos=action.substring(5).split(":"); - var x=parseInt(pos[0]), y=parseInt(pos[1]); - if (core.canMoveDirectly(x,y)) { - core.clearMap('hero', 0, 0, 416, 416); - core.setHeroLoc('x', x); - core.setHeroLoc('y', y); - core.drawHero(core.getHeroLoc('direction'), core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); - core.status.route.push("move:"+x+":"+y); - core.replay(); - return; - } - } - - core.stopReplay(); - core.insertAction("录像文件出错"); - + core.control.replay(); } ////// 判断当前能否进入某个事件 ////// core.prototype.checkStatus = function (name, need, item) { - if (need && core.status.event.id == name) { - core.ui.closePanel(); - return false; - } - - if (need && core.status.lockControl) return false; - if (core.isset(item) && item && !core.hasItem(name)) { - core.drawTip("你没有" + core.material.items[name].name); - return false; - } - if (!core.status.heroStop) { - core.drawTip("请先停止勇士行动"); - return false; - } - - core.lockControl(); - core.status.event.id = name; - return true; + return core.control.checkStatus(name, need, item); } ////// 点击怪物手册时的打开操作 ////// core.prototype.openBook = function (need) { - if (core.isset(core.status.replay)&&core.status.replay.replaying) return; - - // 当前是book,且从“浏览地图”打开 - if (core.status.event.id == 'book' && core.isset(core.status.event.selection)) { - core.status.boxAnimateObjs = []; - core.ui.drawMaps(core.status.event.selection); - return; - } - - // 从“浏览地图”页面打开 - if (core.status.event.id=='viewMaps') { - need=false; - core.status.event.selection = core.status.event.data; - } - - if (!core.checkStatus('book', need, true)) - return; - core.useItem('book'); + core.control.openBook(need); } ////// 点击楼层传送器时的打开操作 ////// core.prototype.useFly = function (need) { - if (core.isset(core.status.replay)&&core.status.replay.replaying) return; - if (!core.checkStatus('fly', need, true)) - return; - if (core.flags.flyNearStair && !core.nearStair()) { - core.drawTip("只有在楼梯边才能使用传送器"); - core.unLockControl(); - core.status.event.data = null; - core.status.event.id = null; - return; - } - if (!core.canUseItem('fly')) { - core.drawTip("楼层传送器好像失效了"); - core.unLockControl(); - core.status.event.data = null; - core.status.event.id = null; - return; - } - core.useItem('fly'); - return; + core.control.useFly(need); } ////// 点击工具栏时的打开操作 ////// core.prototype.openToolbox = function (need) { - if (core.isset(core.status.replay)&&core.status.replay.replaying) return; - if (!core.checkStatus('toolbox', need)) - return; - core.ui.drawToolbox(); + core.control.openToolbox(need); } ////// 点击快捷商店按钮时的打开操作 ////// core.prototype.openQuickShop = function (need) { - if (core.isset(core.status.replay)&&core.status.replay.replaying) return; - if (!core.checkStatus('selectShop', need)) - return; - core.ui.drawQuickShop(); + core.control.openQuickShop(need); } ////// 点击保存按钮时的打开操作 ////// core.prototype.save = function(need) { - if (core.isset(core.status.replay)&&core.status.replay.replaying) return; - if (!core.checkStatus('save', need)) - return; - - var saveIndex = core.status.saveIndex; - var page=parseInt((saveIndex-1)/5), offset=saveIndex-5*page; - - core.ui.drawSLPanel(10*page+offset); + core.control.save(need); } ////// 点击读取按钮时的打开操作 ////// core.prototype.load = function (need) { - if (core.isset(core.status.replay)&&core.status.replay.replaying) return; - - var saveIndex = core.getLocalStorage('saveIndex2', 1); - var page=parseInt((saveIndex-1)/5), offset=saveIndex-5*page; - - // 游戏开始前读档 - if (!core.isPlaying()) { - core.status.event = {'id': 'load', 'data': null}; - core.status.lockControl = true; - core.dom.startPanel.style.display = 'none'; - core.ui.drawSLPanel(10*page+offset); - return; - } - - if (!core.checkStatus('load', need)) - return; - core.ui.drawSLPanel(10*page+offset); + core.control.load(need); } ////// 点击设置按钮时的操作 ////// core.prototype.openSettings = function (need) { - if (core.isset(core.status.replay)&&core.status.replay.replaying) return; - if (!core.checkStatus('settings', need)) - return; - core.ui.drawSettings(); + core.control.openSettings(need); } ////// 自动存档 ////// core.prototype.autosave = function (removeLast) { - var x=null; - if (removeLast) - x=core.status.route.pop(); - core.saveData("autoSave"); - if (removeLast && core.isset(x)) - core.status.route.push(x); + core.control.autosave(removeLast); } ////// 实际进行存读档事件 ////// core.prototype.doSL = function (id, type) { - if (type=='save') { - if (id=='autoSave') { - core.drawTip('不能覆盖自动存档!'); - return; - } - if (core.saveData("save"+id)) { - core.ui.closePanel(); - core.drawTip('存档成功!'); - if (id!="autoSave") { - core.status.saveIndex=id; - core.setLocalStorage('saveIndex2', core.status.saveIndex); - } - } - else { - core.drawTip('存储空间不足,请覆盖已有的存档或在菜单栏中进行清理'); - } - return; - } - else if (type=='load') { - var data = core.getLocalStorage(id=='autoSave'?id:"save"+id, null); - if (!core.isset(data)) { - core.drawTip("无效的存档"); - return; - } - if (data.version != core.firstData.version) { - // core.drawTip("存档版本不匹配"); - if (confirm("存档版本不匹配!\n你想回放此存档的录像吗?")) { - core.dom.startPanel.style.display = 'none'; - core.resetStatus(core.firstData.hero, data.hard, core.firstData.floorId, null, core.initStatus.maps); - core.events.setInitData(data.hard); - core.changeFloor(core.status.floorId, null, core.firstData.hero.loc, null, function() { - core.startReplay(core.decodeRoute(data.route)); - }); - } - return; - } - core.ui.closePanel(); - core.loadData(data, function() { - core.drawTip("读档成功"); - if (id!="autoSave") { - core.status.saveIndex=id; - core.setLocalStorage('saveIndex2', core.status.saveIndex); - } - }); - return; - } + core.control.doSL(id, type); } ////// 同步存档到服务器 ////// core.prototype.syncSave = function (type) { - var saves=null; - // data - if (type=='all') { - saves=[]; - for (var i=1;i<=150;i++) { - var data = core.getLocalStorage("save"+i, null); - if (core.isset(data)) { - saves.push(data); - } - } - } - else { - for (var i=150;i>=1;i--) { - saves=core.getLocalStorage("save"+i, null); - if (core.isset(saves)) { - break; - } - } - } - if (!core.isset(saves)) { - core.drawText("没有要同步的存档"); - return; - } - core.ui.drawWaiting("正在同步,请稍后..."); - - var formData = new FormData(); - formData.append('type', 'save'); - formData.append('name', core.firstData.name); - var save_text = JSON.stringify(saves); - formData.append('data', save_text); - - // send - var xhr = new XMLHttpRequest(); - xhr.open("POST", "/games/sync.php"); - xhr.onload = function(e) { - if (xhr.status==200) { - // console.log("同步成功。"); - var response = JSON.parse(xhr.response); - if (response.code<0) { - core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:"+response.msg); - } - else { - core.drawText("同步成功!\n\n您的存档编号: "+response.code+"\n您的存档密码: "+response.msg+"\n\n请牢记以上两个信息(如截图等),在从服务器\n同步存档时使用。") - } - } - else { - core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:HTTP "+xhr.status); - } - }; - xhr.ontimeout = function() { - core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:Timeout"); - } - xhr.onerror = function() { - core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:XHR Error"); - } - xhr.send(formData); + core.control.syncSave(type); } ////// 从服务器加载存档 ////// core.prototype.syncLoad = function () { - var id = prompt("请输入存档编号:"); - if (id==null || id=="") { - core.ui.drawSyncSave(); return; - } - var password = prompt("请输入存档密码:"); - if (password==null || password=="") { - core.ui.drawSyncSave(); return; - } - core.ui.drawWaiting("正在同步,请稍后..."); - - var formData = new FormData(); - formData.append('type', 'load'); - formData.append('name', core.firstData.name); - formData.append('id', id); - formData.append('password', password); - - // send - var xhr = new XMLHttpRequest(); - xhr.open("POST", "/games/sync.php"); - xhr.onload = function(e) { - if (xhr.status==200) { - // console.log("同步成功。"); - var response = JSON.parse(xhr.response); - switch (response.code) { - case 0: - // 成功 - var data=JSON.parse(response.msg); - // console.log(data); - - if (data instanceof Array) { - core.status.event.selection=1; - core.ui.drawConfirmBox("所有本地存档都将被覆盖,确认?", function () { - for (var i=1;i<=150;i++) { - if (i<=data.length) { - core.setLocalStorage("save"+i, data[i-1]); - } - else { - core.removeLocalStorage("save"+i); - } - } - core.drawText("同步成功!\n你的本地所有存档均已被覆盖。"); - }, function () { - core.status.event.selection=0; - core.ui.drawSyncSave(); - }) - } - else { - // 只覆盖单存档 - var index=150; - for (var i=150;i>=1;i--) { - if (core.getLocalStorage("save"+i, null)==null) - index=i; - else break; - } - core.setLocalStorage("save"+index, data); - core.drawText("同步成功!\n单存档已覆盖至存档"+index); - } - break; - case -1: - core.drawText("出错啦!\n存档编号"+id+"不存在!"); - break; - case -2: - core.drawText("出错啦!\n存档密码错误!"); - break; - default: - core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:"+response.msg); - break; - } - } - else { - core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:HTTP "+xhr.status); - } - }; - xhr.ontimeout = function() { - core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:Timeout"); - } - xhr.onerror = function() { - core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:XHR Error"); - } - xhr.send(formData); + core.control.synvLoad(); } -/* - -////// 存档同步操作 ////// -core.prototype.syncSave = function(type) { - if (type=='save') { - core.status.event.selection=1; - core.ui.drawConfirmBox("你确定要将本地存档同步到服务器吗?", function(){ - // console.log("同步存档..."); - core.ui.drawWaiting("正在同步,请稍后..."); - - var formData = new FormData(); - formData.append('type', 'save'); - formData.append('name', core.firstData.name); - var saves = []; - for (var i=1;i<=150;i++) { - var data = core.getLocalStorage("save"+i, null); - if (core.isset(data)) { - saves.push(data); - } - } - var save_text = JSON.stringify(saves); - formData.append('data', save_text); - - // send - var xhr = new XMLHttpRequest(); - xhr.open("POST", "/games/sync.php"); - xhr.onload = function(e) { - if (xhr.status==200) { - // console.log("同步成功。"); - var response = JSON.parse(xhr.response); - if (response.code<0) { - core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:"+response.msg); - } - else { - core.drawText("同步成功!\n\n您的存档编号: "+response.code+"\n您的存档密码: "+response.msg+"\n\n请牢记以上两个信息(如截图等),在从服务器\n同步存档时使用。") - } - } - else { - core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:HTTP "+xhr.status); - } - }; - xhr.ontimeout = function() { - core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:Timeout"); - } - xhr.onerror = function() { - core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:XHR Error"); - } - xhr.send(formData); - }, function() { - core.status.event.selection=0; - core.ui.drawSyncSave(); - }) - } - else if (type=='load') { - core.status.event.selection=1; - core.ui.drawConfirmBox("你确定要从服务器加载存档吗?\n该操作将覆盖所有本地存档且不可逆!", function(){ - var id = prompt("请输入存档编号:"); - if (id==null || id=="") { - core.ui.drawSyncSave(); return; - } - var password = prompt("请输入存档密码:"); - if (password==null || password=="") { - core.ui.drawSyncSave(); return; - } - core.ui.drawWaiting("正在同步,请稍后..."); - - var formData = new FormData(); - formData.append('type', 'load'); - formData.append('name', core.firstData.name); - formData.append('id', id); - formData.append('password', password); - - // send - var xhr = new XMLHttpRequest(); - xhr.open("POST", "/games/sync.php"); - xhr.onload = function(e) { - if (xhr.status==200) { - // console.log("同步成功。"); - var response = JSON.parse(xhr.response); - switch (response.code) { - case 0: - // 成功 - var data=JSON.parse(response.msg); - // console.log(data); - for (var i=1;i<=150;i++) { - if (i<=data.length) { - core.setLocalStorage("save"+i, data[i-1]); - } - else { - core.removeLocalStorage("save"+i); - } - } - core.drawText("同步成功!\n你的本地所有存档均已被覆盖。"); - break; - case -1: - core.drawText("出错啦!\n存档编号"+id+"不存在!"); - break; - case -2: - core.drawText("出错啦!\n存档密码错误!"); - break; - default: - core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:"+response.msg); - break; - } - } - else { - core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:HTTP "+xhr.status); - } - }; - xhr.ontimeout = function() { - core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:Timeout"); - } - xhr.onerror = function() { - core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:XHR Error"); - } - xhr.send(formData); - }, function() { - core.status.event.selection=1; - core.ui.drawSyncSave(); - }) - } - -} -*/ ////// 存档到本地 ////// core.prototype.saveData = function(dataId) { - var data = { - 'floorId': core.status.floorId, - 'hero': core.clone(core.status.hero), - 'hard': core.status.hard, - 'maps': core.maps.save(core.status.maps), - 'route': core.encodeRoute(core.status.route), - 'shops': {}, - 'version': core.firstData.version, - "time": new Date().getTime() - }; - // set shop times - for (var shop in core.status.shops) { - data.shops[shop]={ - 'times': core.status.shops[shop].times || 0, - 'visited': core.status.shops[shop].visited || false - } - } - core.events.beforeSaveData(data); - - return core.setLocalStorage(dataId, data); + return core.control.saveData(dataId); } ////// 从本地读档 ////// core.prototype.loadData = function (data, callback) { - - core.resetStatus(data.hero, data.hard, data.floorId, core.decodeRoute(data.route), core.maps.load(data.maps)); - - // load shop times - for (var shop in core.status.shops) { - if (core.isset(data.shops[shop])) { - core.status.shops[shop].times = data.shops[shop].times; - core.status.shops[shop].visited = data.shops[shop].visited; - } - } - - core.events.afterLoadData(data); - - core.changeFloor(data.floorId, null, data.hero.loc, 0, function() { - if (core.isset(callback)) callback(); - }); + core.control.loadData(data, callback); } ////// 加密路线 ////// core.prototype.encodeRoute = function (route) { - var ans=""; - var lastMove = "", cnt=0; - - var items=Object.keys(core.material.items).sort(); - var shops=Object.keys(core.initStatus.shops).sort(); - 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; - } - if (t.indexOf('item:')==0) - ans+="I"+items.indexOf(t.substring(5)); - else if (t.indexOf('fly:')==0) - ans+="F"+core.floorIds.indexOf(t.substring(4)); - else if (t.indexOf('choices:')==0) - ans+="C"+t.substring(8); - else if (t.indexOf('shop:')==0) { - var sp=t.substring(5).split(":"); - ans+="S"+shops.indexOf(sp[0])+":"+sp[1]; - } - else if (t=='turn') - ans+='T'; - else if (t=='getNext') - ans+='G'; - else if (t.indexOf('input:')==0) - ans+="P"+t.substring(6); - else if (t=='no') - ans+='N'; - else if (t.indexOf('move:')==0) { - ans+="M"+t.substring(5); - } - } - }); - if (cnt>0) { - ans+=lastMove.substring(0,1).toUpperCase(); - if (cnt>1) ans+=cnt; - } - return ans; + return core.utils.encodeRoute(route); } ////// 解密路线 ////// core.prototype.decodeRoute = function (route) { + return core.utils.decodeRoute(route); +} - if (!core.isset(route)) return route; - - var ans=[], index=0; - - var getNumber = function (noparse) { - var num=""; - while (indexcore.firstData.levelUp.length) return core.status.hero.lv; - return core.firstData.levelUp[core.status.hero.lv-1].name || core.status.hero.lv; + return core.control.getLvName(); } ////// 设置某个自定义变量或flag ////// core.prototype.setFlag = function(flag, value) { - if (!core.isset(core.status.hero)) return; - core.status.hero.flags[flag]=value; + core.control.setFlag(flag, value); } ////// 获得某个自定义变量或flag ////// core.prototype.getFlag = function(flag, defaultValue) { - if (!core.isset(core.status.hero)) return defaultValue; - var value = core.status.hero.flags[flag]; - if (core.isset(value)) return value; - return defaultValue; + return core.control.getFlag(flag, defaultValue); } ////// 是否存在某个自定义变量或flag,且值为true ////// core.prototype.hasFlag = function(flag) { - if (core.getFlag(flag)) return true; - return false; + return core.control.hasFlag(flag); +} + +core.prototype.doAction = function() { + core.events.doAction(); } ////// 往当前事件列表之前插入一系列事件 ////// @@ -4943,742 +1048,86 @@ core.prototype.insertAction = function (list, x, y, callback) { ////// 锁定状态栏,常常用于事件处理 ////// core.prototype.lockControl = function () { - core.status.lockControl = true; + core.control.lockControl(); } ////// 解锁状态栏 ////// core.prototype.unLockControl = function () { - core.status.lockControl = false; + core.control.unLockControl(); } ////// 判断某对象是否不为undefined也不会null ////// core.prototype.isset = function (val) { - if (val == undefined || val == null || (typeof val=='number' && isNaN(val))) { - return false; - } - return true + return core.utils.isset(val); } ////// 读取一个本地文件内容 ////// -core.prototype.readFile = function (success, error) { - - // step 0: 不为http/https,直接不支持 - if (!core.platform.isOnline) { - alert("离线状态下不支持文件读取!"); - if (core.isset(error)) error(); - return; - } - - // Step 1: 如果不支持FileReader,直接不支持 - if (core.platform.fileReader==null) { - alert("当前浏览器不支持FileReader!"); - if (core.isset(error)) error(); - return; - } - - if (core.platform.fileInput==null) { - core.platform.fileInput = document.createElement("input"); - core.platform.fileInput.style.display = 'none'; - core.platform.fileInput.type = 'file'; - core.platform.fileInput.onchange = function () { - var files = core.platform.fileInput.files; - if (files.length==0) { - if (core.isset(core.platform.errorCallback)) - core.platform.errorCallback(); - return; - } - core.platform.fileReader.readAsText(core.platform.fileInput.files[0]); - core.platform.fileInput.value = ''; - } - } - - core.platform.successCallback = success; - core.platform.errorCallback = error; - core.platform.fileInput.click(); +core.prototype.readFile = function (success, error, readType) { + core.utils.readFile(success, error, readType); } ////// 下载文件到本地 ////// core.prototype.download = function (filename, content) { - - // Step 0: 不为http/https,直接不支持 - if (!core.platform.isOnline) { - alert("离线状态下不支持下载操作!"); - return; - } - - // Step 1: 如果是iOS平台,直接不支持 - if (core.platform.isIOS) { - 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"); - // if (!opened) window.location.href=href; - 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); - } + core.utils.download(filename, content); } ////// 复制一段内容到剪切板 ////// core.prototype.copy = function (data) { - 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.select(); - var successful = false; - try { - successful = document.execCommand('copy'); - } catch (err) { - successful = false; - } - - document.body.removeChild(textArea); - return successful; + return core.utils.copy(data); } ////// 播放背景音乐 ////// core.prototype.playBgm = function (bgm) { - - // 如果不允许播放 - if (!core.musicStatus.bgmStatus) return; - // 音频不存在 - if (!core.isset(core.material.bgms[bgm])) return; - - // 延迟播放 - if (core.material.bgms[bgm] == 'loading') { - core.material.bgms[bgm] = 'starting'; - return; - } - - try { - // 如果当前正在播放,且和本BGM相同,直接忽略 - if (core.musicStatus.playingBgm == bgm && core.musicStatus.isPlaying) { - return; - } - // 如果正在播放中,暂停 - if (core.isset(core.musicStatus.playingBgm) && core.musicStatus.isPlaying) { - core.material.bgms[core.musicStatus.playingBgm].pause(); - } - // 播放当前BGM - core.musicStatus.playingBgm = bgm; - core.material.bgms[bgm].play(); - core.musicStatus.isPlaying = true; - - } - catch (e) { - console.log("无法播放BGM "+bgm); - console.log(e); - core.musicStatus.playingBgm = null; - } + core.control.playBgm(bgm); } ////// 暂停背景音乐的播放 ////// core.prototype.pauseBgm = function () { - // 直接暂停播放 - try { - if (core.isset(core.musicStatus.playingBgm)) { - core.material.bgms[core.musicStatus.playingBgm].pause(); - } - core.musicStatus.isPlaying = false; - } - catch (e) { - console.log("无法暂停BGM "+bgm); - console.log(e); - } + core.control.pauseBgm(); } ////// 恢复背景音乐的播放 ////// core.prototype.resumeBgm = function () { - - // 如果不允许播放 - if (!core.musicStatus.bgmStatus) return; - - // 恢复BGM - try { - if (core.isset(core.musicStatus.playingBgm)) { - core.material.bgms[core.musicStatus.playingBgm].play(); - core.musicStatus.isPlaying = true; - } - else { - if (core.bgms.length>0) { - core.playBgm(core.bgms[0]); - core.musicStatus.isPlaying = true; - } - } - } - catch (e) { - console.log("无法恢复BGM "+bgm); - console.log(e); - } + core.control.resumeBgm(); } ////// 播放音频 ////// core.prototype.playSound = function (sound) { - - // 如果不允许播放 - if (!core.musicStatus.soundStatus) return; - // 音频不存在 - if (!core.isset(core.material.sounds[sound])) return; - - try { - if (core.musicStatus.audioContext != null) { - var source = core.musicStatus.audioContext.createBufferSource(); - source.buffer = core.material.sounds[sound]; - source.connect(core.musicStatus.audioContext.destination); - try { - source.start(0); - } - catch (e) { - try { - source.noteOn(0); - } - catch (ee) { - } - } - } - else { - core.material.sounds[sound].play(); - } - } - catch (eee) { - console.log("无法播放SE "+bgm); - console.log(eee); - } + core.control.playSound(sound); } ////// 动画显示某对象 ////// core.prototype.show = function (obj, speed, callback) { - if (!core.isset(speed)) { - obj.style.display = 'block'; - return; - } - obj.style.display = 'block'; - 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 (core.isset(callback)) { - callback(); - } - } - }, speed); + core.utils.show(obj, speed, callback); } ////// 动画使某对象消失 ////// core.prototype.hide = function (obj, speed, callback) { - if (!core.isset(speed)) { - obj.style.display = 'none'; - return; - } - 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 (core.isset(callback)) { - callback(); - } - } - }, speed); + core.utils.hide(obj, speed, callback); } - ////// 清空状态栏 ////// core.prototype.clearStatusBar = function() { - var statusList = ['floor', 'lv', 'hp', 'atk', 'def', 'mdef', 'money', 'experience', 'up', 'yellowKey', 'blueKey', 'redKey', 'poison', 'weak', 'curse', 'hard']; - statusList.forEach(function (e) { - core.statusBar[e].innerHTML = " "; - }); - core.statusBar.image.book.style.opacity = 0.3; - core.statusBar.image.fly.style.opacity = 0.3; + core.control.clearStatusBar(); } ////// 更新状态栏 ////// core.prototype.updateStatusBar = function () { - - // 检查等级 - core.events.checkLvUp(); - - // 检查HP上限 - if (core.values.HPMAX>0) { - core.setStatus('hp', Math.min(core.values.HPMAX, core.getStatus('hp'))); - } - - // 更新领域、阻击、显伤 - core.updateCheckBlock(); - - var lvName = core.getLvName(); - core.statusBar.lv.innerHTML = lvName; - if (/^[+-]?\d+$/.test(lvName)) - core.statusBar.lv.style.fontStyle = 'italic'; - else core.statusBar.lv.style.fontStyle = 'normal'; - - var statusList = ['hp', 'atk', 'def', 'mdef', 'money', 'experience']; - statusList.forEach(function (item) { - core.statusBar[item].innerHTML = core.getStatus(item); - }); - // 进阶 - if (core.flags.enableLevelUp && core.status.hero.lv clientHeight && clientHeight < ADAPT_WIDTH){ - isHorizontal = true; - width = clientHeight; - } - // 各元素大小的变量声明 - var gameGroupWidth, gameGroupHeight, borderRight, - canvasWidth, canvasTop, // canvasLeft, - statusBarWidth, statusBarHeight, statusBarBorder, - statusWidth, statusHeight, statusMaxWidth,statusLabelsLH, - toolBarWidth, toolBarHeight, toolBarTop, toolBarBorder, - toolsWidth, toolsHeight,toolsMargin,toolsPMaxwidth, - fontSize, toolbarFontSize, margin; - - var count = 11; - if (!core.flags.enableFloor) count--; - if (!core.flags.enableLv) count--; - if (!core.flags.enableMDef) count--; - if (!core.flags.enableMoney) count--; - if (!core.flags.enableExperience) count--; - if (!core.flags.enableLevelUp) count--; - if (!core.flags.enableDebuff) count--; - - var statusLineHeight = BASE_LINEHEIGHT * 9 / count; - var statusLineFontSize = DEFAULT_FONT_SIZE; - if (count>9) statusLineFontSize = statusLineFontSize * 9 / count; - - var shopDisplay; - - statusBarBorder = '3px #fff solid'; - toolBarBorder = '3px #fff solid'; - var zoom = (ADAPT_WIDTH - width) / 4.22; - var aScale = 1 - zoom / 100; - - // 移动端 - if (width < CHANGE_WIDTH) { - if(width < ADAPT_WIDTH){ - - core.domStyle.scale = aScale; - canvasWidth = width; - }else{ - canvasWidth = DEFAULT_CANVAS_WIDTH; - core.domStyle.scale = 1; - } - - var scale = core.domStyle.scale - var tempWidth = DEFAULT_CANVAS_WIDTH * scale; - if(!isHorizontal){ //竖屏 - core.domStyle.screenMode = 'vertical'; - //显示快捷商店图标 - shopDisplay = 'block'; - //判断应该显示几行 - // var col = core.flags.enableMDef || core.flags.enableExperience || core.flags.enableDebuff ? 3 : 2; - var col = parseInt((count-1)/3)+1; - - var tempTopBarH = scale * (BASE_LINEHEIGHT * col + SPACE * 2) + 6; - var tempBotBarH = scale * (BASE_LINEHEIGHT + SPACE * 4) + 6; - - gameGroupHeight = tempWidth + tempTopBarH + tempBotBarH; - - gameGroupWidth = tempWidth - canvasTop = tempTopBarH; - // canvasLeft = 0; - toolBarWidth = statusBarWidth = canvasWidth; - statusBarHeight = tempTopBarH; - statusBarBorder = '3px #fff solid'; - - statusHeight = scale*BASE_LINEHEIGHT * .8; - statusLabelsLH = .8 * BASE_LINEHEIGHT *scale; - statusMaxWidth = scale * DEFAULT_BAR_WIDTH * .95; - toolBarHeight = tempBotBarH; - - toolBarTop = statusBarHeight + canvasWidth; - toolBarBorder = '3px #fff solid'; - toolsHeight = scale * BASE_LINEHEIGHT; - toolsPMaxwidth = scale * DEFAULT_BAR_WIDTH * .4; - borderRight = '3px #fff solid'; - - margin = scale * SPACE * 2; - toolsMargin = scale * SPACE * 4; - fontSize = DEFAULT_FONT_SIZE * scale; - toolbarFontSize = DEFAULT_FONT_SIZE * scale; - }else { //横屏 - core.domStyle.screenMode = 'horizontal'; - shopDisplay = 'none'; - gameGroupWidth = tempWidth + DEFAULT_BAR_WIDTH * scale; - gameGroupHeight = tempWidth; - canvasTop = 0; - // canvasLeft = DEFAULT_BAR_WIDTH * scale; - toolBarWidth = statusBarWidth = DEFAULT_BAR_WIDTH * scale; - statusBarHeight = scale * statusLineHeight * count + SPACE * 2; //一共有9行加上两个padding空隙 - statusBarBorder = '3px #fff solid'; - - statusHeight = scale*statusLineHeight * .8; - statusLabelsLH = .8 * statusLineHeight *scale; - toolBarHeight = canvasWidth - statusBarHeight; - toolBarTop = scale*statusLineHeight * count + SPACE * 2; - toolBarBorder = '3px #fff solid'; - toolsHeight = scale * BASE_LINEHEIGHT; - fontSize = statusLineFontSize * scale; - toolbarFontSize = DEFAULT_FONT_SIZE * scale; - borderRight = ''; - statusMaxWidth = scale * DEFAULT_BAR_WIDTH; - toolsPMaxwidth = scale * DEFAULT_BAR_WIDTH; - - margin = scale * SPACE * 2; - toolsMargin = 2 * SPACE * scale; - } - - }else { //大屏设备 pc端 - core.domStyle.scale = 1; - core.domStyle.screenMode = 'bigScreen'; - shopDisplay = 'none'; - - gameGroupWidth = DEFAULT_CANVAS_WIDTH + DEFAULT_BAR_WIDTH; - gameGroupHeight = DEFAULT_CANVAS_WIDTH; - canvasWidth = DEFAULT_CANVAS_WIDTH; - canvasTop = 0; - // canvasLeft = DEFAULT_BAR_WIDTH; - - toolBarWidth = statusBarWidth = DEFAULT_BAR_WIDTH; - statusBarHeight = statusLineHeight * count + SPACE * 2; //一共有9行 - - statusHeight = statusLineHeight * .8; - statusLabelsLH = .8 * statusLineHeight; - toolBarHeight = DEFAULT_CANVAS_WIDTH - statusBarHeight; - toolBarTop = statusLineHeight * count + SPACE * 2; - - toolsHeight = BASE_LINEHEIGHT; - borderRight = ''; - fontSize = statusLineFontSize; - toolbarFontSize = DEFAULT_FONT_SIZE; - statusMaxWidth = DEFAULT_BAR_WIDTH; - toolsPMaxwidth = DEFAULT_BAR_WIDTH * .9; - margin = SPACE * 2; - toolsMargin = 2 * SPACE; - } - - var unit = 'px' - core.domStyle.styles = [ - { - id: 'gameGroup', - rules:{ - width: gameGroupWidth + unit, - height: gameGroupHeight + unit, - top: (clientHeight-gameGroupHeight)/2 + unit, - left: (clientWidth-gameGroupWidth)/2 + unit, - } - }, - { - className: 'gameCanvas', - rules:{ - width: canvasWidth + unit, - height: canvasWidth + unit, - top: canvasTop + unit, - right: 0, - border: '3px #fff solid', - } - }, - { - id: 'curtain', - rules: { - width: (canvasWidth - SPACE*2) + unit, - height:(canvasWidth - SPACE*2) + unit, - top: (canvasTop + SPACE) + unit, - right: SPACE + unit, - } - }, - { - id: 'floorMsgGroup', - rules:{ - width: (canvasWidth - SPACE*2) + unit, - height: (gameGroupHeight - SPACE*2) + unit, - top: SPACE + unit, - right: SPACE + unit, - } - }, - { - id: 'statusBar', - rules:{ - width: statusBarWidth + unit, - height: statusBarHeight + unit, - top: 0, - left: 0, - padding: SPACE + unit, - - borderTop: statusBarBorder, - borderLeft: statusBarBorder, - borderRight: borderRight, - fontSize: fontSize + unit - } - }, - { - className: 'status', - rules:{ - width: '100%', - maxWidth: statusMaxWidth + unit, - height: statusHeight + unit, - margin: margin/2 + unit - } - }, - { - className: 'statusLabels', - rules:{ - marginLeft: margin + unit, - lineHeight: statusLabelsLH + unit, - } - }, - { - id: 'toolBar', - rules:{ - width: toolBarWidth + unit, - height: toolBarHeight + unit, - top: toolBarTop +unit, - left: 0, - padding: SPACE + unit, - borderBottom: toolBarBorder, - borderLeft: toolBarBorder, - borderRight: borderRight, - fontSize: toolbarFontSize + unit - } - }, - { - className: 'tools', - rules:{ - height: toolsHeight + unit, - maxWidth: toolsPMaxwidth + unit, - marginLeft: toolsMargin + unit, - marginTop: margin + unit, - } - }, - { - imgId: 'shop', - rules:{ - display: shopDisplay - } - }, - { - id: 'floorCol', - rules: { - display: core.flags.enableFloor ? 'block': 'none' - } - }, - { - id: 'lvCol', - rules: { - display: core.flags.enableLv ? 'block': 'none' - } - }, - { - id: 'mdefCol', - rules: { - display: core.flags.enableMDef ? 'block': 'none' - } - }, - { - id: 'moneyCol', - rules: { - display: core.flags.enableMoney ? 'block': 'none' - } - }, - { - id: 'expCol', - rules: { - display: core.flags.enableExperience ? 'block': 'none' - } - }, - { - id: 'upCol', - rules: { - display: core.flags.enableLevelUp ? 'block': 'none' - } - }, - { - 'id': 'debuffCol', - rules: { - display: core.flags.enableDebuff ? 'block': 'none' - } - }, - { - id: 'hard', - rules: { - lineHeight: toolsHeight + unit - } - } - ] - core.domRenderer(); + core.control.resize(clientWidth, clientHeight); } ////// 渲染DOM ////// core.prototype.domRenderer = function(){ - - core.dom.statusBar.style.display = 'block'; - core.dom.toolBar.style.display = 'block'; - - var styles = core.domStyle.styles; - - for(var i=0; i=3) specialText = "多属性..."; @@ -345,6 +291,4 @@ enemys.prototype.getCurrentEnemys = function (floorId) { return a.damage - b.damage; }); return enemys; -} - -main.instance.enemys = new enemys(); \ No newline at end of file +} \ No newline at end of file diff --git a/libs/events.js b/libs/events.js index 6d1b8fae..1a4e2e46 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1,9 +1,10 @@ function events() { - + this.init(); } ////// 初始化 ////// events.prototype.init = function () { + this.eventdata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.events; this.events = { 'battle': function (data, core, callback) { //core.autosave(true); @@ -70,10 +71,6 @@ events.prototype.getEvents = function (eventName) { return this.events[eventName]; } -main.instance.events = new events(); - - - ////// 游戏开始事件 ////// events.prototype.startGame = function (hard) { @@ -106,50 +103,17 @@ events.prototype.startGame = function (hard) { ////// 不同难度分别设置初始属性 ////// events.prototype.setInitData = function (hard) { - if (hard=='Easy') { // 简单难度 - core.setFlag('hard', 1); // 可以用flag:hard来获得当前难度 - // 可以在此设置一些初始福利,比如设置初始生命值可以调用: - // core.setStatus("hp", 10000); - // 赠送一把黄钥匙可以调用 - // core.setItem("yellowKey", 1); - } - if (hard=='Normal') { // 普通难度 - core.setFlag('hard', 2); // 可以用flag:hard来获得当前难度 - } - if (hard=='Hard') { // 困难难度 - core.setFlag('hard', 3); // 可以用flag:hard来获得当前难度 - } - this.afterLoadData(); + return this.eventdata.setInitData(hard); } ////// 游戏获胜事件 ////// -events.prototype.win = function(reason) { - core.ui.closePanel(); - var replaying = core.status.replay.replaying; - core.stopReplay(); - core.waitHeroToStop(function() { - core.removeGlobalAnimate(0,0,true); - core.clearMap('all'); // 清空全地图 - core.drawText([ - "\t[恭喜通关]你的分数是${status:hp}。" - ], function () { - core.events.gameOver(reason||'', replaying); - }) - }); +events.prototype.win = function (reason) { + return this.eventdata.win(reason); } ////// 游戏失败事件 ////// -events.prototype.lose = function(reason) { - core.ui.closePanel(); - var replaying = core.status.replay.replaying; - core.stopReplay(); - core.waitHeroToStop(function() { - core.drawText([ - "\t[结局1]你死了。\n如题。" - ], function () { - core.events.gameOver(null, replaying); - }); - }) +events.prototype.lose = function (reason) { + return this.eventdata.lose(reason); } ////// 游戏结束 ////// @@ -185,9 +149,7 @@ events.prototype.gameOver = function (ending, fromReplay) { formData.append('steps', core.status.hero.steps); formData.append('route', core.encodeRoute(core.status.route)); - var xhr = new XMLHttpRequest(); - xhr.open("POST", "/games/upload.php"); - xhr.send(formData); + core.http("POST", "/games/upload.php", formData); core.restart(); } @@ -231,18 +193,7 @@ events.prototype.gameOver = function (ending, fromReplay) { ////// 转换楼层结束的事件 ////// events.prototype.afterChangeFloor = function (floorId) { - if (core.isset(core.status.event.id)) return; // 当前存在事件 - - if (!core.hasFlag("visited_"+floorId)) { - this.doEvents(core.floors[floorId].firstArrive, null, null, function () { - //core.autosave(); - }); - core.setFlag("visited_"+floorId, true); - return; - } - - // 自动存档 - //core.autosave(); + return this.eventdata.afterChangeFloor(floorId); } ////// 开始执行一系列自定义事件 ////// @@ -273,9 +224,10 @@ events.prototype.doAction = function() { // 事件处理完毕 if (core.status.event.data.list.length==0) { - if (core.isset(core.status.event.data.callback)) - core.status.event.data.callback(); + var callback = core.status.event.data.callback; core.ui.closePanel(); + if (core.isset(callback)) + callback(); core.replay(); return; } @@ -378,7 +330,7 @@ events.prototype.doAction = function() { } var floorId = data.floorId||core.status.floorId; var originBlock=core.getBlock(x,y,floorId,false); - var block = core.maps.getBlock(x,y,data.number); + var block = core.maps.initBlock(x,y,data.number); core.maps.addInfo(block); core.maps.addEvent(block,x,y,core.floors[floorId].events[x+","+y]); core.maps.addChangeFloor(block,x,y,core.floors[floorId].changeFloor[x+","+y]); @@ -447,8 +399,8 @@ events.prototype.doAction = function() { this.doAction(); break; case "showImage": // 显示图片 - if (core.isset(data.loc) && core.isset(core.material.images.pngs[data.name])) { - core.canvas.animate.drawImage(core.material.images.pngs[data.name], data.loc[0], data.loc[1]); + if (core.isset(data.loc) && core.isset(core.material.images.images[data.name])) { + core.canvas.animate.drawImage(core.material.images.images[data.name], data.loc[0], data.loc[1]); } else core.clearMap('animate', 0, 0, 416, 416); this.doAction(); @@ -677,6 +629,305 @@ events.prototype.insertAction = function (action, x, y, callback) { } } +////// 获得面前的物品(轻按) ////// +events.prototype.getNextItem = function() { + if (!core.status.heroStop || !core.flags.enableGentleClick) return; + var nextX = core.nextX(), nextY = core.nextY(); + var block = core.getBlock(nextX, nextY); + if (block==null) return; + if (block.block.event.trigger=='getItem') { + core.getItem(block.block.event.id, 1, nextX, nextY); + core.status.route.push("getNext"); + } +} + +////// 获得某个物品 ////// +events.prototype.getItem = function (itemId, itemNum, itemX, itemY, callback) { + // core.getItemAnimate(itemId, itemNum, itemX, itemY); + core.playSound('item.ogg'); + var itemCls = core.material.items[itemId].cls; + core.items.getItemEffect(itemId, itemNum); + core.removeBlock(itemX, itemY); + var text = '获得 ' + core.material.items[itemId].name; + if (itemNum > 1) text += "x" + itemNum; + if (itemCls === 'items') text += core.items.getItemEffectTip(itemId); + core.drawTip(text, core.material.icons.items[itemId]); + core.canvas.event.clearRect(itemX * 32, itemY * 32, 32, 32); + core.updateStatusBar(); + + // 检查处理后的事件。 + var event = core.floors[core.status.floorId].afterGetItem[itemX+","+itemY]; + if (core.isset(event)) { + core.events.doEvents(event, itemX, itemY, callback); + } + else if (core.isset(callback)) callback(); +} + +////// 开门 ////// +events.prototype.openDoor = function (id, x, y, needKey, callback) { + + if (core.interval.openDoorAnimate!=null) return; + + // 是否存在门 + if (!core.terrainExists(x, y, id)) { + if (core.isset(callback)) callback(); + return; + } + if (core.status.automaticRoute.moveStepBeforeStop.length==0) { + core.status.automaticRoute.moveStepBeforeStop=core.status.automaticRoute.autoStepRoutes.slice(core.status.automaticRoute.autoStep-1,core.status.automaticRoute.autoStepRoutes.length); + if (core.status.automaticRoute.moveStepBeforeStop.length>=1)core.status.automaticRoute.moveStepBeforeStop[0].step-=core.status.automaticRoute.movedStep; + } + + core.stopAutomaticRoute(); + var speed=30; + if (needKey) { + var key = id.replace("Door", "Key"); + if (!core.hasItem(key)) { + if (key != "specialKey") + core.drawTip("你没有" + core.material.items[key].name); + else core.drawTip("无法开启此门"); + core.clearContinueAutomaticRoute(); + return; + } + core.autosave(true); + core.removeItem(key); + } + + // open + core.playSound("door.ogg"); + var state = 0; + var doorId = id; + if (!(doorId.substring(doorId.length-4)=="Door")) { + doorId=doorId+"Door"; + speed=100; + } + var door = core.material.icons.animates[doorId]; + core.status.replay.animate=true; + core.interval.openDoorAnimate = window.setInterval(function () { + state++; + if (state == 4) { + clearInterval(core.interval.openDoorAnimate); + core.interval.openDoorAnimate=null; + core.removeBlock(x, y); + core.status.replay.animate=false; + core.events.afterOpenDoor(id,x,y,callback); + return; + } + core.canvas.event.clearRect(32 * x, 32 * y, 32, 32); + core.canvas.event.drawImage(core.material.images.animates, 32 * state, 32 * door, 32, 32, 32 * x, 32 * y, 32, 32); + }, speed) +} + +////// 战斗 ////// +events.prototype.battle = function (id, x, y, force, callback) { + if (core.status.automaticRoute.moveStepBeforeStop.length==0) { + core.status.automaticRoute.moveStepBeforeStop=core.status.automaticRoute.autoStepRoutes.slice(core.status.automaticRoute.autoStep-1,core.status.automaticRoute.autoStepRoutes.length); + if (core.status.automaticRoute.moveStepBeforeStop.length>=1)core.status.automaticRoute.moveStepBeforeStop[0].step-=core.status.automaticRoute.movedStep; + } + core.stopHero(); + core.stopAutomaticRoute(); + + var damage = core.enemys.getDamage(id); + // 非强制战斗 + if (damage >= core.status.hero.hp && !force) { + core.drawTip("你打不过此怪物!"); + core.clearContinueAutomaticRoute(); + return; + } + + if (!core.isset(core.status.event.id)) // 自动存档 + core.autosave(true); + + if (core.flags.battleAnimate&&!core.status.replay.replaying) { + core.waitHeroToStop(function() { + core.ui.drawBattleAnimate(id, function() { + core.events.afterBattle(id, x, y, callback); + }); + }); + } + else { + + if (core.flags.equipment && core.getFlag('sword', 'sword0')!='sword0') { + core.playSound('zone.ogg'); + core.drawAnimate('sword', x, y); + } + else { + core.playSound('attack.ogg'); + core.drawAnimate('hand', x, y); + } + + core.events.afterBattle(id, x, y, callback); + } +} + +////// 触发(x,y)点的事件 ////// +events.prototype.trigger = function (x, y) { + var mapBlocks = core.status.thisMap.blocks; + var noPass; + for (var b = 0; b < mapBlocks.length; b++) { + if (mapBlocks[b].x == x && mapBlocks[b].y == y && !(core.isset(mapBlocks[b].enable) && !mapBlocks[b].enable)) { // 启用事件 + noPass = mapBlocks[b].event && mapBlocks[b].event.noPass; + if (noPass) { + core.clearAutomaticRouteNode(x, y); + } + if (core.isset(mapBlocks[b].event) && core.isset(mapBlocks[b].event.trigger)) { + var trigger = mapBlocks[b].event.trigger; + + // 转换楼层能否穿透 + if (trigger=='changeFloor' && !noPass) { + var canCross = core.flags.portalWithoutTrigger; + if (core.isset(mapBlocks[b].event.data) && core.isset(mapBlocks[b].event.data.portalWithoutTrigger)) + canCross=mapBlocks[b].event.data.portalWithoutTrigger; + if (canCross) { + if (core.status.replay.replaying) { + if (core.status.replay.toReplay[0]=='no') { + core.status.replay.toReplay.shift(); + core.status.route.push("no"); + continue; + } + } + else if (core.status.automaticRoute.autoHeroMove || core.status.automaticRoute.autoStepcore.floorIds.indexOf(core.status.floorId)) + core.status.hero.flyRange.push(floorId); + else + core.status.hero.flyRange.unshift(floorId); + } + + window.setTimeout(function () { + + var changing = function () { + + // 根据文字判断是否斜体 + var floorName = core.status.maps[floorId].name; + if (!core.isset(floorName) || floorName=="") floorName=" " + core.statusBar.floor.innerHTML = floorName; + if (/^[+-]?\d+$/.test(floorName)) + core.statusBar.floor.style.fontStyle = 'italic'; + else core.statusBar.floor.style.fontStyle = 'normal'; + + // 更改BGM + if (core.isset(core.floors[floorId].bgm)) { + core.playBgm(core.floors[floorId].bgm); + } + + // 不存在事件时,更改画面色调 + if (core.status.event.id == null) { + // 默认画面色调 + if (core.isset(core.floors[floorId].color)) { + var color = core.floors[floorId].color; + + // 直接变色 + core.dom.curtain.style.background = core.arrayToRGB(color); + if (core.isset(color[3])) + core.dom.curtain.style.opacity = color[3]; + else core.dom.curtain.style.opacity=1; + core.status.curtainColor = color; + } + else { + core.dom.curtain.style.background = "#000000"; + core.dom.curtain.style.opacity = 0; + } + } + + // 更改天气 + if (core.isset(core.floors[floorId].weather)) { + core.setWeather(core.floors[floorId].weather[0], core.floors[floorId].weather[1]) + } + else core.setWeather(); + + // 检查重生 + if (!core.isset(fromLoad)) { + core.status.maps[floorId].blocks.forEach(function(block) { + if (core.isset(block.enable) && !block.enable && core.isset(block.event) && block.event.cls.indexOf('enemy')==0 + && core.enemys.hasSpecial(core.material.enemys[block.event.id].special, 23)) { + block.enable = true; + } + }) + } + + core.drawMap(floorId, function () { + setTimeout(function() { + if (core.isset(heroLoc.direction)) + core.setHeroLoc('direction', heroLoc.direction); + core.setHeroLoc('x', heroLoc.x); + core.setHeroLoc('y', heroLoc.y); + core.drawHero(core.getHeroLoc('direction'), core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); + core.updateStatusBar(); + + var changed = function () { + core.unLockControl(); + core.status.replay.animate=false; + core.events.afterChangeFloor(floorId); + if (core.isset(callback)) callback(); + } + if (displayAnimate) { + core.hide(core.dom.floorMsgGroup, time/4, function () { + changed(); + }); + } + else { + changed(); + } + }, 25) + }); + } + core.playSound('floor.mp3'); + if (displayAnimate) { + core.show(core.dom.floorMsgGroup, time/2, function () { + changing(); + }); + } + else { + changing(); + } + }, 25); +} + ////// 打开一个全局商店 ////// events.prototype.openShop = function(shopId, needVisited) { var shop = core.status.shops[shopId]; @@ -793,122 +1044,17 @@ events.prototype.useItem = function(itemId) { ////// 加点事件 ////// events.prototype.addPoint = function (enemy) { - var point = enemy.point; - if (!core.isset(point) || point<=0) return []; - - // 加点,返回一个choices事件 - return [ - {"type": "choices", - "choices": [ - {"text": "攻击+"+(1*point), "action": [ - {"type": "setValue", "name": "status:atk", "value": "status:atk+"+(1*point)} - ]}, - {"text": "防御+"+(2*point), "action": [ - {"type": "setValue", "name": "status:def", "value": "status:def+"+(2*point)} - ]}, - {"text": "生命+"+(200*point), "action": [ - {"type": "setValue", "name": "status:hp", "value": "status:hp+"+(200*point)} - ]}, - ] - } - ]; + return this.eventdata.addPoint(enemy); } ////// 战斗结束后触发的事件 ////// -events.prototype.afterBattle = function(enemyId,x,y,callback) { - - var enemy = core.material.enemys[enemyId]; - - // 毒衰咒的处理 - var special = enemy.special; - // 中毒 - if (core.enemys.hasSpecial(special, 12) && !core.hasFlag('poison')) { - core.setFlag('poison', true); - } - // 衰弱 - if (core.enemys.hasSpecial(special, 13) && !core.hasFlag('weak')) { - core.setFlag('weak', true); - core.status.hero.atk-=core.values.weakValue; - core.status.hero.def-=core.values.weakValue; - } - // 诅咒 - if (core.enemys.hasSpecial(special, 14) && !core.hasFlag('curse')) { - core.setFlag('curse', true); - } - // 仇恨属性:减半 - if (core.flags.hatredDecrease && core.enemys.hasSpecial(special, 17)) { - core.setFlag('hatred', parseInt(core.getFlag('hatred', 0)/2)); - } - // 自爆 - if (core.enemys.hasSpecial(special, 19)) { - core.status.hero.hp = 1; - } - // 退化 - if (core.enemys.hasSpecial(special, 21)) { - core.status.hero.atk -= (enemy.atkValue||0); - core.status.hero.def -= (enemy.defValue||0); - if (core.status.hero.atk<0) core.status.hero.atk=0; - if (core.status.hero.def<0) core.status.hero.def=0; - } - // 增加仇恨值 - core.setFlag('hatred', core.getFlag('hatred',0)+core.values.hatred); - core.updateStatusBar(); - - - // 事件的处理 - var todo = []; - // 如果不为阻击,且该点存在,且有事件 - if (!core.enemys.hasSpecial(special, 18) && core.isset(x) && core.isset(y)) { - var event = core.floors[core.status.floorId].afterBattle[x+","+y]; - if (core.isset(event)) { - // 插入事件 - core.unshift(todo, event); - } - } - // 如果有加点 - var point = core.material.enemys[enemyId].point; - if (core.isset(point) && point>0) { - core.unshift(todo, core.events.addPoint(core.material.enemys[enemyId])); - } - - // 如果事件不为空,将其插入 - if (todo.length>0) { - this.insertAction(todo,x,y); - } - - // 如果已有事件正在处理中 - if (core.status.event.id == null) { - core.continueAutomaticRoute(); - } - else { - core.clearContinueAutomaticRoute(); - } - if (core.isset(callback)) callback(); - +events.prototype.afterBattle = function (enemyId,x,y,callback) { + return this.eventdata.afterBattle(enemyId,x,y,callback); } ////// 开一个门后触发的事件 ////// -events.prototype.afterOpenDoor = function(doorId,x,y,callback) { - - var todo = []; - if (core.isset(x) && core.isset(y)) { - var event = core.floors[core.status.floorId].afterOpenDoor[x+","+y]; - if (core.isset(event)) { - core.unshift(todo, event); - } - } - - if (todo.length>0) { - this.insertAction(todo,x,y); - } - - if (core.status.event.id == null) { - core.continueAutomaticRoute(); - } - else { - core.clearContinueAutomaticRoute(); - } - if (core.isset(callback)) callback(); +events.prototype.afterOpenDoor = function (doorId,x,y,callback) { + return this.eventdata.afterOpenDoor(doorId,x,y,callback); } ////// 经过一个路障 ////// @@ -952,16 +1098,13 @@ events.prototype.changeLight = function(x, y) { // 改变为dark block.id = 166; block.event = {'cls': 'terrains', 'id': 'darkLight', 'noPass': true}; - // 更新地图 - core.canvas.event.clearRect(x * 32, y * 32, 32, 32); - var blockIcon = core.material.icons[block.event.cls][block.event.id]; - core.canvas.event.drawImage(core.material.images[block.event.cls], 0, blockIcon * 32, 32, 32, block.x * 32, block.y * 32, 32, 32); + core.drawBlock(block); this.afterChangeLight(x,y); } ////// 改变亮灯之后,可以触发的事件 ////// -events.prototype.afterChangeLight = function(x,y) { - +events.prototype.afterChangeLight = function (x,y) { + return this.eventdata.afterChangeLight(x,y); } ////// 滑冰 ////// @@ -1005,27 +1148,23 @@ events.prototype.pushBox = function (data) { if (block!=null && !(core.isset(block.block.event) && block.block.event.id=='flower')) return; - var blockIcon; if (block==null) { - core.status.thisMap.blocks.push(core.maps.getBlock(nx, ny, 169)); - blockIcon=core.material.icons.terrains.box; + core.status.thisMap.blocks.push(core.maps.initBlock(nx, ny, 169)); + block = core.getBlock(nx, ny); } else { block.block.id=170; - block.block.event=core.maps.getBlock(null,null,170).event; - blockIcon=core.material.icons.terrains.boxed; + block.block.event=core.maps.initBlock(null,null,170).event; } - core.canvas.event.clearRect(nx * 32, ny * 32, 32, 32); - core.canvas.event.drawImage(core.material.images.terrains, 0, blockIcon * 32, 32, 32, nx * 32, ny * 32, 32, 32); + core.drawBlock(block.block); if (data.event.id=='box') { core.removeBlock(data.x, data.y); } else { data.id=168; - data.event=core.maps.getBlock(null,null,168).event; - core.canvas.event.clearRect(data.x * 32, data.y * 32, 32, 32); - core.canvas.event.drawImage(core.material.images.terrains, 0, core.material.icons.terrains.flower * 32, 32, 32, data.x * 32, data.y * 32, 32, 32); + data.event=core.maps.initBlock(null,null,168).event; + core.drawBlock(data); } core.updateStatusBar(); @@ -1040,1286 +1179,22 @@ events.prototype.pushBox = function (data) { ////// 推箱子后的事件 ////// events.prototype.afterPushBox = function () { - - var noBoxLeft = function () { - // 地图上是否还存在未推到的箱子,如果不存在则返回true,存在则返回false - for (var i=0;i= 5 && x <= 7) { - var topIndex = 6 - parseInt((choices.length - 1) / 2); - if (y>=topIndex && y0) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - } - } -} - -////// 自定义事件时,放开某个键的操作 ////// -events.prototype.keyUpAction = function (keycode) { - if (core.status.event.data.type=='text' && (keycode==13 || keycode==32 || keycode==67)) { - this.doAction(); - return; - } - if (core.status.event.data.type=='choices') { - var data = core.status.event.data.current; - var choices = data.choices; - if (choices.length>0) { - if (keycode==13 || keycode==32 || keycode==67) { - core.status.route.push("choices:"+core.status.event.selection); - this.insertAction(choices[core.status.event.selection].action); - this.doAction(); - } - } - } -} - -////// 怪物手册界面的点击操作 ////// -events.prototype.clickBook = function(x,y) { - // 上一页 - if ((x == 3 || x == 4) && y == 12) { - core.ui.drawBook(core.status.event.data - 6); - return; - } - // 下一页 - if ((x == 8 || x == 9) && y == 12) { - core.ui.drawBook(core.status.event.data + 6); - return; - } - // 返回 - if (x>=10 && x<=12 && y==12) { - if (core.status.event.selection==null) - core.ui.closePanel(); - else { - core.status.boxAnimateObjs = []; - core.ui.drawMaps(core.status.event.selection); - } - return; - } - // 怪物信息 - var data = core.status.event.data; - if (core.isset(data) && y<12) { - var page=parseInt(data/6); - var index=6*page+parseInt(y/2); - core.ui.drawBook(index); - core.ui.drawBookDetail(index); - } - return; -} - -////// 怪物手册界面时,按下某个键的操作 ////// -events.prototype.keyDownBook = function (keycode) { - if (keycode==37) core.ui.drawBook(core.status.event.data-6); - if (keycode==38) core.ui.drawBook(core.status.event.data-1); - if (keycode==39) core.ui.drawBook(core.status.event.data+6); - if (keycode==40) core.ui.drawBook(core.status.event.data+1); - if (keycode==33) core.ui.drawBook(core.status.event.data-6); - if (keycode==34) core.ui.drawBook(core.status.event.data+6); - return; -} - -////// 怪物手册界面时,放开某个键的操作 ////// -events.prototype.keyUpBook = function (keycode) { - if (keycode==27 || keycode==88) { - if (core.status.event.selection==null) - core.ui.closePanel(); - else { - core.status.boxAnimateObjs = []; - core.ui.drawMaps(core.status.event.selection); - } - return; - } - if (keycode==13 || keycode==32 || keycode==67) { - var data=core.status.event.data; - if (core.isset(data)) { - this.clickBook(6, 2*(data%6)); - } - return; - } -} - -////// 怪物手册属性显示界面时的点击操作 ////// -events.prototype.clickBookDetail = function () { - core.clearMap('data', 0, 0, 416, 416); - core.status.event.id = 'book'; -} - -////// 楼层传送器界面时的点击操作 ////// -events.prototype.clickFly = function(x,y) { - if ((x==10 || x==11) && y==9) core.ui.drawFly(core.status.event.data-1); - if ((x==10 || x==11) && y==5) core.ui.drawFly(core.status.event.data+1); - if (x>=5 && x<=7 && y==12) core.ui.closePanel(); - if (x>=0 && x<=9 && y>=3 && y<=11) { - var index=core.status.hero.flyRange.indexOf(core.status.floorId); - var stair=core.status.event.data=8) { - core.ui.drawMaps(core.status.event.data-1); - } - else { - core.clearMap('data', 0, 0, 416, 416); - core.setOpacity('data', 1); - core.ui.closePanel(); - } -} - -////// 查看地图界面时,按下某个键的操作 ////// -events.prototype.keyDownViewMaps = function (keycode) { - if (keycode==37 || keycode==38 || keycode==33) core.ui.drawMaps(core.status.event.data+1); - else if (keycode==39 || keycode==40 || keycode==34) core.ui.drawMaps(core.status.event.data-1); - return; -} - -////// 查看地图界面时,放开某个键的操作 ////// -events.prototype.keyUpViewMaps = function (keycode) { - if (keycode==27 || keycode==13 || keycode==32 || keycode==67) { - core.clearMap('data', 0, 0, 416, 416); - core.setOpacity('data', 1); - core.ui.closePanel(); - } - if (keycode==88) { - core.openBook(false); - } - return; -} - -////// 商店界面时的点击操作 ////// -events.prototype.clickShop = function(x,y) { - var shop = core.status.event.data.shop; - var choices = shop.choices; - if (x >= 5 && x <= 7) { - var topIndex = 6 - parseInt(choices.length / 2); - if (y>=topIndex && y eval(use)) { - core.drawTip("你的"+use_text+"不足"); - return false; - } - - core.status.event.data.actions.push(y-topIndex); - - eval(use+'-='+need); - core.setStatus('money', money); - core.setStatus('experience', experience); - - // 更新属性 - choice.effect.split(";").forEach(function (t) { - core.doEffect(t); - }); - core.updateStatusBar(); - shop.times++; - this.openShop(core.status.event.data.id); - } - // 离开 - else if (y==topIndex+choices.length) { - if (core.status.event.data.actions.length>0) { - core.status.route.push("shop:"+core.status.event.data.id+":"+core.status.event.data.actions.join("")); - } - - core.status.event.data.actions = []; - core.status.boxAnimateObjs = []; - if (core.status.event.data.fromList) - core.ui.drawQuickShop(); - else core.ui.closePanel(); - } - else return false; - } - return true; -} - -////// 商店界面时,按下某个键的操作 ////// -events.prototype.keyDownShop = function (keycode) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } -} - -////// 商店界面时,放开某个键的操作 ////// -events.prototype.keyUpShop = function (keycode) { - if (keycode==27 || keycode==88) { - if (core.status.event.data.actions.length>0) { - core.status.route.push("shop:"+core.status.event.data.id+":"+core.status.event.data.actions.join("")); - } - - core.status.event.data.actions = []; - - core.status.boxAnimateObjs = []; - - if (core.status.event.data.fromList) - core.ui.drawQuickShop(); - else - core.ui.closePanel(); - return; - } - var shop = core.status.event.data.shop; - var choices = shop.choices; - if (keycode==13 || keycode==32 || keycode==67) { - var topIndex = 6 - parseInt(choices.length / 2); - this.clickShop(6, topIndex+core.status.event.selection); - } - return; -} - -////// 快捷商店界面时的点击操作 ////// -events.prototype.clickQuickShop = function(x, y) { - var shopList = core.status.shops, keys = Object.keys(shopList); - if (x >= 5 && x <= 7) { - var topIndex = 6 - parseInt(keys.length / 2); - if (y>=topIndex && y=10 && x<=12 && y==12) { - core.ui.closePanel(); - return; - } - if (x>=10 && x<=12 && y<=1) { - if (!core.isset(core.status.event.data)) return; - if (!core.flags.enableDeleteItem) { - core.drawTip("不支持删除道具!"); - return; - } - core.removeItem(core.status.event.data); - core.status.event.data = null; - core.ui.drawToolbox(); - return; - } - - var index=0; - if (y==4||y==5||y==9||y==10) index=parseInt(x/2); - else index=6+parseInt(x/2); - if (y>=9) index+=100; - this.clickToolboxIndex(index); -} - -////// 选择工具栏界面中某个Index后的操作 ////// -events.prototype.clickToolboxIndex = function(index) { - var items = null; - var ii=index; - if (ii<100) - items = Object.keys(core.status.hero.items.tools).sort(); - else { - ii-=100; - items = Object.keys(core.status.hero.items.constants).sort(); - } - if (items==null) return; - if (ii>=items.length) return; - var itemId=items[ii]; - if (itemId==core.status.event.data) { - core.events.useItem(itemId); - } - else { - core.ui.drawToolbox(index); - } -} - -////// 工具栏界面时,按下某个键的操作 ////// -events.prototype.keyDownToolbox = function (keycode) { - if (!core.isset(core.status.event.data)) return; - - var tools = Object.keys(core.status.hero.items.tools).sort(); - var constants = Object.keys(core.status.hero.items.constants).sort(); - var index=core.status.event.selection; - - if (keycode==37) { // left - if ((index>0 && index<100) || index>100) { - this.clickToolboxIndex(index-1); - return; - } - if (index==100 && tools.length>0) { - this.clickToolboxIndex(tools.length-1); - return; - } - } - if (keycode==38) { // up - if ((index>5 && index<100) || index>105) { - this.clickToolboxIndex(index-6); - return; - } - if (index>=100 && index<=105) { - if (tools.length>6) { - this.clickToolboxIndex(Math.min(tools.length-1, index-100+6)); - } - else if (tools.length>0) { - this.clickToolboxIndex(Math.min(tools.length-1, index-100)); - } - return; - } - } - if (keycode==39) { // right - if ((index=100 && index0) { - this.clickToolboxIndex(100); - return; - } - } - if (keycode==40) { // down - if (index<=5) { - if (tools.length>6) { - this.clickToolboxIndex(Math.min(tools.length-1, index+6)); - } - else if (constants.length>0) { - this.clickToolboxIndex(100+Math.min(constants.length-1, index)); - } - return; - } - if (index>5 && index<100 && constants.length>0) { - this.clickToolboxIndex(100+Math.min(constants.length-1, index-6)); - return; - } - if (index>=100 && index<=105 && constants.length>6) { - this.clickToolboxIndex(Math.min(100+constants.length-1, index+6)); - return; - } - } -} - -////// 工具栏界面时,放开某个键的操作 ////// -events.prototype.keyUpToolbox = function (keycode) { - if (keycode==84 || keycode==27 || keycode==88) { - core.ui.closePanel(); - return; - } - if (!core.isset(core.status.event.data)) return; - - if (keycode==13 || keycode==32 || keycode==67) { - this.clickToolboxIndex(core.status.event.selection); - return; - } - - if (keycode==46) { // delete - if (!core.isset(core.status.event.data)) return; - if (!core.flags.enableDeleteItem) { - core.drawTip("不支持删除道具!"); - return; - } - core.removeItem(core.status.event.data); - core.status.event.data = null; - core.ui.drawToolbox(); - return; - } - -} - -////// 存读档界面时的点击操作 ////// -events.prototype.clickSL = function(x,y) { - - var index=core.status.event.data; - var page = parseInt(index/10), offset=index%10; - - // 上一页 - if ((x == 3 || x == 4) && y == 12) { - core.ui.drawSLPanel(10*(page-1)+offset); - } - // 下一页 - if ((x == 8 || x == 9) && y == 12) { - core.ui.drawSLPanel(10*(page+1)+offset); - } - // 返回 - if (x>=10 && x<=12 && y==12) { - core.ui.closePanel(); - if (!core.isPlaying()) { - core.showStartAnimate(); - } - return; - } - - var index=6*page+1; - if (y>=1 && y<=4) { - if (x>=1 && x<=3) core.doSL("autoSave", core.status.event.id); - if (x>=5 && x<=7) core.doSL(5*page+1, core.status.event.id); - if (x>=9 && x<=11) core.doSL(5*page+2, core.status.event.id); - } - if (y>=7 && y<=10) { - if (x>=1 && x<=3) core.doSL(5*page+3, core.status.event.id); - if (x>=5 && x<=7) core.doSL(5*page+4, core.status.event.id); - if (x>=9 && x<=11) core.doSL(5*page+5, core.status.event.id); - } -} - -////// 存读档界面时,按下某个键的操作 ////// -events.prototype.keyDownSL = function(keycode) { - - var index=core.status.event.data; - var page = parseInt(index/10), offset=index%10; - - if (keycode==37) { // left - if (offset==0) { - core.ui.drawSLPanel(10*(page-1) + 5); - } - else { - core.ui.drawSLPanel(index - 1); - } - return; - } - if (keycode==38) { // up - if (offset<3) { - core.ui.drawSLPanel(10*(page-1) + offset + 3); - } - else { - core.ui.drawSLPanel(index - 3); - } - return; - } - if (keycode==39) { // right - if (offset==5) { - core.ui.drawSLPanel(10*(page+1)+1); - } - else { - core.ui.drawSLPanel(index + 1); - } - return; - } - if (keycode==40) { // down - if (offset>=3) { - core.ui.drawSLPanel(10*(page+1) + offset - 3); - } - else { - core.ui.drawSLPanel(index + 3); - } - return; - } - if (keycode==33) { // PAGEUP - core.ui.drawSLPanel(10*(page-1) + offset); - return; - } - if (keycode==34) { // PAGEDOWN - core.ui.drawSLPanel(10*(page+1) + offset); - return; - } -} - -////// 存读档界面时,放开某个键的操作 ////// -events.prototype.keyUpSL = function (keycode) { - - var index=core.status.event.data; - var page = parseInt(index/10), offset=index%10; - - if (keycode==27 || keycode==88 || (core.status.event.id == 'save' && keycode==83) || (core.status.event.id == 'load' && keycode==68)) { - core.ui.closePanel(); - if (!core.isPlaying()) { - core.showStartAnimate(); - } - return; - } - if (keycode==13 || keycode==32 || keycode==67) { - if (offset==0) { - core.doSL("autoSave", core.status.event.id); - } - else { - core.doSL(5*page+offset, core.status.event.id); - } - return; - } -} - -////// 系统设置界面时的点击操作 ////// -events.prototype.clickSwitchs = function (x,y) { - if (x<5 || x>7) return; - var choices = core.status.event.ui.choices; - var topIndex = 6 - parseInt((choices.length - 1) / 2); - if (y>=topIndex && y7) return; - var choices = core.status.event.ui.choices; - var topIndex = 6 - parseInt((choices.length - 1) / 2); - if (y>=topIndex && y0) { - text+="\n当前MAX为"+ending.max+",最早由 "+(ending.username||"匿名")+" 于"+core.formatDate(new Date(1000*ending.timestamp))+"打出。"; - } - }) - }) - core.drawText(text); - } - } - else { - core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:HTTP "+xhr.status); - } - }; - xhr.ontimeout = function() { - core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:Timeout"); - } - xhr.onerror = function() { - core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:XHR Error"); - } - xhr.send(formData); - break; - case 6: - core.ui.drawHelp(); - break; - case 7: - core.ui.drawAbout(); - break; - case 8: - core.ui.closePanel(); - break; - } - } - return; -} - -////// 系统菜单栏界面时,按下某个键的操作 ////// -events.prototype.keyDownSettings = function (keycode) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } -} - -////// 系统菜单栏界面时,放开某个键的操作 ////// -events.prototype.keyUpSettings = function (keycode) { - if (keycode==27 || keycode==88) { - core.ui.closePanel(); - return; - } - var choices = core.status.event.ui.choices; - if (keycode==13 || keycode==32 || keycode==67) { - var topIndex = 6 - parseInt((choices.length - 1) / 2); - this.clickSettings(6, topIndex+core.status.event.selection); - } -} - -////// 同步存档界面时的点击操作 ////// -events.prototype.clickSyncSave = function (x,y) { - if (x<5 || x>7) return; - var choices = core.status.event.ui.choices; - var topIndex = 6 - parseInt((choices.length - 1) / 2); - if (y>=topIndex && y=1;i--) { - if (core.getLocalStorage("save"+i, null)==null) - index=i; - else break; - } - core.setLocalStorage("save"+index, data); - core.drawText("同步成功!\n单存档已覆盖至存档"+index); - } - }, function () { - - }); - break; - case 4: - core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5route", JSON.stringify({ - 'name': core.firstData.name, - 'hard': core.status.hard, - 'route': core.encodeRoute(core.status.route) - })); - break; - case 5: - core.status.event.selection=1; - core.ui.drawConfirmBox("你确定要清空所有存档吗?", function() { - localStorage.clear(); - core.drawText("\t[操作成功]你的所有存档已被清空。"); - }, function() { - core.status.event.selection=5; - core.ui.drawSyncSave(); - }) - break; - case 6: - core.status.event.selection=3; - core.ui.drawSettings(); - break; - - } - } - return; -} - -////// 同步存档界面时,按下某个键的操作 ////// -events.prototype.keyDownSyncSave = function (keycode) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } -} - -////// 同步存档界面时,放开某个键的操作 ////// -events.prototype.keyUpSyncSave = function (keycode) { - if (keycode==27 || keycode==88) { - core.status.event.selection=2; - core.ui.drawSettings(); - return; - } - var choices = core.status.event.ui.choices; - if (keycode==13 || keycode==32 || keycode==67) { - var topIndex = 6 - parseInt((choices.length - 1) / 2); - this.clickSyncSave(6, topIndex+core.status.event.selection); - } -} - -////// 同步存档选择界面时的点击操作 ////// -events.prototype.clickSyncSelect = function (x, y) { - if (x<5 || x>7) return; - var choices = core.status.event.ui.choices; - - var topIndex = 6 - parseInt((choices.length - 1) / 2); - if (y>=topIndex && y7) return; - var choices = core.status.event.ui.choices; - - var topIndex = 6 - parseInt((choices.length - 1) / 2); - - var saves=null; - - if (y>=topIndex && y=1;i--) { - saves=core.getLocalStorage("save"+i, null); - if (core.isset(saves)) { - break; - } - } - break; - case 2: - break; - } - } - if (core.isset(saves)) { - var content = { - "name": core.firstData.name, - "version": core.firstData.version, - "data": saves - } - core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5save", JSON.stringify(content)); - } - core.status.event.selection=2; - core.ui.drawSyncSave(); -} - -////// 存档下载界面时,按下某个键的操作 ////// -events.prototype.keyDownLocalSaveSelect = function (keycode) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } -} - -////// 存档下载界面时,放开某个键的操作 ////// -events.prototype.keyUpLocalSaveSelect = function (keycode) { - if (keycode==27 || keycode==88) { - core.status.event.selection=0; - core.ui.drawSettings(); - return; - } - var choices = core.status.event.ui.choices; - if (keycode==13 || keycode==32 || keycode==67) { - var topIndex = 6 - parseInt((choices.length - 1) / 2); - this.clickLocalSaveSelect(6, topIndex+core.status.event.selection); - } -} - -////// “虚拟键盘”界面时的点击操作 ////// -events.prototype.clickKeyBoard = function (x, y) { - if (y==3 && x>=1 && x<=11) { - core.ui.closePanel(); - core.keyUp(112+x-1); // F1-F12: 112-122 - } - if (y==4 && x>=1 && x<=10) { - core.ui.closePanel(); - core.keyUp(x==10?48:48+x); // 1-9: 49-57; 0: 48 - } - // 字母 - var lines = [ - ["Q","W","E","R","T","Y","U","I","O","P"], - ["A","S","D","F","G","H","J","K","L"], - ["Z","X","C","V","B","N","M"], - ]; - if (y==5 && x>=1 && x<=10) { - core.ui.closePanel(); - core.keyUp(lines[0][x-1].charCodeAt(0)); - } - if (y==6 && x>=1 && x<=9) { - core.ui.closePanel(); - core.keyUp(lines[1][x-1].charCodeAt(0)); - } - if (y==7 && x>=1 && x<=7) { - core.ui.closePanel(); - core.keyUp(lines[2][x-1].charCodeAt(0)); - } - if (y==8 && x>=1 && x<=11) { - core.ui.closePanel(); - if (x==1) core.keyUp(189); // - - if (x==2) core.keyUp(187); // = - if (x==3) core.keyUp(219); // [ - if (x==4) core.keyUp(221); // ] - if (x==5) core.keyUp(220); // \ - if (x==6) core.keyUp(186); // ; - if (x==7) core.keyUp(222); // ' - if (x==8) core.keyUp(188); // , - if (x==9) core.keyUp(190); // . - if (x==10) core.keyUp(191); // / - if (x==11) core.keyUp(192); // ` - } - if (y==9 && x>=1 && x<=10) { - core.ui.closePanel(); - if (x==1) core.keyUp(27); // ESC - if (x==2) core.keyUp(9); // TAB - if (x==3) core.keyUp(20); // CAPS - if (x==4) core.keyUp(16); // SHIFT - if (x==5) core.keyUp(17); // CTRL - if (x==6) core.keyUp(18); // ALT - if (x==7) core.keyUp(32); // SPACE - if (x==8) core.keyUp(8); // BACKSPACE - if (x==9) core.keyUp(13); // ENTER - if (x==10) core.keyUp(46); // DEL - } - if (y==10 && x>=9 && x<=11) - core.ui.closePanel(); -} - -////// 光标界面时的点击操作 ////// -events.prototype.clickCursor = function (x,y) { - - if (x==core.status.automaticRoute.cursorX && y==core.status.automaticRoute.cursorY) { - core.ui.closePanel(); - core.onclick(x,y,[]); - return; - } - core.status.automaticRoute.cursorX=x; - core.status.automaticRoute.cursorY=y; - core.ui.drawCursor(); -} - -////// 光标界面时,按下某个键的操作 ////// -events.prototype.keyDownCursor = function (keycode) { - if (keycode==37) { // left - core.status.automaticRoute.cursorX--; - core.ui.drawCursor(); - return; - } - if (keycode==38) { // up - core.status.automaticRoute.cursorY--; - core.ui.drawCursor(); - return; - } - if (keycode==39) { // right - core.status.automaticRoute.cursorX++; - core.ui.drawCursor(); - return; - } - if (keycode==40) { // down - core.status.automaticRoute.cursorY++; - core.ui.drawCursor(); - return; - } -} - -////// 光标界面时,放开某个键的操作 ////// -events.prototype.keyUpCursor = function (keycode) { - if (keycode==27 || keycode==88) { - core.ui.closePanel(); - return; - } - if (keycode==13 || keycode==32 || keycode==67 || keycode==69) { - core.ui.closePanel(); - core.onclick(core.status.automaticRoute.cursorX, core.status.automaticRoute.cursorY, []); - return; - } -} - -////// “关于”界面时的点击操作 ////// -events.prototype.clickAbout = function () { - if (core.isPlaying()) - core.ui.closePanel(); - else - core.showStartAnimate(); -} - diff --git a/libs/icons.js b/libs/icons.js index f69ce405..f1a557a1 100644 --- a/libs/icons.js +++ b/libs/icons.js @@ -1,232 +1,12 @@ function icons() { - + this.init(); } icons.prototype.init = function () { - this.icons = { - 'hero': { - 'down': {'loc': 0, 'stop': 0, 'leftFoot': 1, 'rightFoot': 3}, - 'left': {'loc': 1, 'stop': 0, 'leftFoot': 1, 'rightFoot': 3}, - 'right': {'loc': 2, 'stop': 0, 'leftFoot': 1, 'rightFoot': 3}, - 'up': {'loc': 3, 'stop': 0, 'leftFoot': 1, 'rightFoot': 3} - }, - 'terrains': { - 'ground': 0, - 'grass': 1, - 'grass2': 2, - 'yellowWall': 3, - 'whiteWall': 4, - 'blueWall': 5, - 'snowGround': 6, - 'ground2': 7, - 'ground3': 8, - 'ground4': 9, - 'sand': 10, - 'ground5': 11, - 'yellowWall2': 12, - 'whiteWall2': 13, - 'blueWall2': 14, - 'blockWall': 15, - 'grayWall': 16, - 'white': 17, - 'ground6': 18, - 'soil': 19, - 'star': 20, - 'lava': 21, - 'ice': 22, - 'downFloor': 23, - 'upFloor': 24, - 'yellowDoor': 25, - 'blueDoor': 26, - 'redDoor': 27, - 'greenDoor': 28, - 'specialDoor': 29, - 'steelDoor': 30, - 'blueShop-left': 31, - 'blueShop-right': 32, - 'pinkShop-left': 33, - 'pinkShop-right': 34, - 'arrowUp': 35, - 'arrowDown': 36, - 'arrowLeft': 37, - 'arrowRight': 38, - 'light': 39, - 'darkLight': 40, - 'ski': 41, - 'flower': 42, - 'box': 43, - 'boxed': 44 - }, - 'animates': { - 'star': 0, - 'lava': 1, - 'waterWall': 2, - 'yellowDoor': 3, - 'blueDoor': 4, - 'redDoor': 5, - 'greenDoor': 6, - 'specialDoor': 7, - 'blueWallDoor': 8, - 'yellowWallDoor': 9, - 'whiteWallDoor': 10, - 'steelDoor': 11, - 'lavaDoor': 12, - 'grayLavaDoor': 13, - 'starDoor': 14, - 'mockBlueWallDoor': 15, - 'mockYellowWallDoor': 16, - 'mockWhiteWallDoor': 17, - 'iceYellowWallDoor': 18, - 'starPortal': 19, - 'exclamation': 20, - 'portal': 21, - 'switch': 22, - 'lavaNet': 23, - 'poisonNet': 24, - 'weakNet': 25, - 'curseNet': 26, - 'downPortal': 27, - 'leftPortal': 28, - 'rightPortal': 29, - 'upPortal': 30, - 'water': 31, - }, - 'npcs': { - 'man': 0, - 'woman': 1, - 'thief': 2, - 'fairy': 3, - 'magician': 4, - 'womanMagician': 5, - 'oldMan': 6, - 'child': 7, - 'wood': 8, - 'pinkShop': 9, - 'blueShop': 10, - 'princess': 11 - }, - 'enemys': { - 'greenSlime': 0, - 'redSlime': 1, - 'blackSlime': 2, - 'slimelord': 3, - 'bat': 4, - 'bigBat': 5, - 'redBat': 6, - 'vampire': 7, - 'skeleton': 8, - 'skeletonSoilder': 9, - 'skeletonCaptain': 10, - 'ghostSkeleton': 11, - 'zombie': 12, - 'zombieKnight': 13, - 'rock': 14, - 'slimeMan': 15, - 'bluePriest': 16, - 'redPriest': 17, - 'brownWizard': 18, - 'redWizard': 19, - 'yellowGuard': 20, - 'blueGuard': 21, - 'redGuard': 22, - 'swordsman': 23, - 'soldier': 24, - 'yellowKnight': 25, - 'redKnight': 26, - 'darkKnight': 27, - 'blackKing': 28, - 'yellowKing': 29, - 'greenKing': 30, - 'blueKnight': 31, - 'goldSlime': 32, - 'poisonSkeleton': 33, - 'poisonBat': 34, - 'steelRock': 35, - 'skeletonPriest': 36, - 'skeletonKing': 37, - 'skeletonWizard': 38, - 'redSkeletonCaption': 39, - 'badHero': 40, - 'demon': 41, - 'demonPriest': 42, - 'goldHornSlime': 43, - 'redKing': 44, - 'whiteKing': 45, - 'blackMagician': 46, - 'silverSlime': 47, - 'swordEmperor': 48, - 'whiteHornSlime': 49, - 'badPrincess': 50, - 'badFairy': 51, - 'grayPriest': 52, - 'redSwordsman': 53, - 'whiteGhost': 54, - 'poisonZombie': 55, - 'magicDragon': 56, - 'octopus': 57, - 'darkFairy': 58, - 'greenKnight': 59, - }, - 'items': { - 'yellowKey': 0, - 'blueKey': 1, - 'redKey': 2, - 'greenKey': 3, - 'steelKey': 4, - 'bigKey': 6, - 'redJewel': 16, - 'blueJewel': 17, - 'greenJewel': 18, - 'yellowJewel': 19, - 'redPotion': 20, - 'bluePotion': 21, - 'greenPotion': 22, - 'yellowPotion': 23, - 'sword0': 60, - 'sword1': 50, - 'sword2': 51, - 'sword3': 52, - 'sword4': 53, - 'sword5': 54, - 'shield0': 61, - 'shield1': 55, - 'shield2': 56, - 'shield3': 57, - 'shield4': 58, - 'shield5': 59, - 'book': 9, - 'fly': 12, - 'pickaxe': 45, - 'icePickaxe': 44, - 'bomb': 43, - 'centerFly': 13, - 'upFly': 15, - 'downFly': 14, - 'coin': 11, - 'snow': 41, - 'cross': 40, - 'superPotion': 29, - 'earthquake': 8, - 'poisonWine': 24, - 'weakWine': 25, - 'curseWine': 27, - 'superWine': 28, - 'knife': 42, - 'moneyPocket': 46, - 'shoes': 47, - 'hammer': 48 - }, - 'autotile': { // 所有的Autotile列表;后面的index简单取0即可 - 'autotile': 0, - 'autotile1': 0, - 'autotile2': 0, - 'autotile3': 0, - } - } + this.icons = icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1; + //delete(icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1); } icons.prototype.getIcons = function () { return this.icons; -} - -main.instance.icons = new icons(); \ No newline at end of file +} \ No newline at end of file diff --git a/libs/items.js b/libs/items.js index ccd386e5..8616d607 100644 --- a/libs/items.js +++ b/libs/items.js @@ -1,65 +1,13 @@ function items() { - + this.init(); } ////// 初始化 ////// items.prototype.init = function () { - this.items = { - // 钥匙 - 'yellowKey': {'cls': 'keys', 'name': '黄钥匙'}, - 'blueKey': {'cls': 'keys', 'name': '蓝钥匙'}, - 'redKey': {'cls': 'keys', 'name': '红钥匙'}, - - // 宝石、血瓶 - 'redJewel': {'cls': 'items', 'name': '红宝石'}, - 'blueJewel': {'cls': 'items', 'name': '蓝宝石'}, - 'greenJewel': {'cls': 'items', 'name': '绿宝石'}, - 'yellowJewel': {'cls': 'items', 'name': '黄宝石'}, - 'redPotion': {'cls': 'items', 'name': '红血瓶'}, - 'bluePotion': {'cls': 'items', 'name': '蓝血瓶'}, - 'yellowPotion': {'cls': 'items', 'name': '黄血瓶'}, - 'greenPotion': {'cls': 'items', 'name': '绿血瓶'}, - 'sword1': {'cls': 'items', 'name': '铁剑'}, - 'sword2': {'cls': 'items', 'name': '银剑'}, - 'sword3': {'cls': 'items', 'name': '骑士剑'}, - 'sword4': {'cls': 'items', 'name': '圣剑'}, - 'sword5': {'cls': 'items', 'name': '神圣剑'}, - 'shield1': {'cls': 'items', 'name': '铁盾'}, - 'shield2': {'cls': 'items', 'name': '银盾'}, - 'shield3': {'cls': 'items', 'name': '骑士盾'}, - 'shield4': {'cls': 'items', 'name': '圣盾'}, - 'shield5': {'cls': 'items', 'name': '神圣盾'}, - 'superPotion': {'cls': 'items', 'name': '圣水'}, - 'moneyPocket': {'cls': 'items', 'name': '金钱袋'}, - - // 物品 - 'sword0': {'cls': 'constants', 'name': '折断的剑', 'text': '没有任何作用的剑,相当于脱掉装备。'}, - 'shield0': {'cls': 'constants', 'name': '残破的盾', 'text': '没有任何作用的盾,相当于脱掉装备。'}, - 'book': {'cls': 'constants', 'name': '怪物手册', 'text': '可以查看当前楼层各怪物属性'}, - 'fly': {'cls': 'constants', 'name': '楼层传送器', 'text': '可以自由往来去过的楼层'}, - 'coin': {'cls': 'constants', 'name': '幸运金币', 'text': '持有时打败怪物可得双倍金币'}, - 'snow': {'cls': 'constants', 'name': '冰冻徽章', 'text': '可以将四周的熔岩变成平地'}, - 'cross': {'cls': 'constants', 'name': '十字架', 'text': '持有后无视怪物的无敌属性'}, - 'knife': {'cls': 'constants', 'name': '屠龙匕首', 'text': '该道具尚未被定义'}, - 'shoes': {'cls': 'constants', 'name': '绿鞋', 'text': '持有时无视负面地形'}, - - // 道具 - 'bigKey': {'cls': 'tools', 'name': '大黄门钥匙', 'text': '可以开启当前层所有黄门'}, - 'greenKey': {'cls': 'tools', 'name': '绿钥匙', 'text': '可以打开一扇绿门'}, - 'steelKey': {'cls': 'tools', 'name': '铁门钥匙', 'text': '可以打开一扇铁门'}, - 'pickaxe': {'cls': 'tools', 'name': '破墙镐', 'text': '可以破坏勇士面前的墙'}, - 'icePickaxe': {'cls': 'tools', 'name': '破冰镐', 'text': '可以破坏勇士面前的一堵冰墙'}, - 'bomb': {'cls': 'tools', 'name': '炸弹', 'text': '可以炸掉勇士面前的怪物'}, - 'centerFly': {'cls': 'tools', 'name': '中心对称飞行器', 'text': '可以飞向当前楼层中心对称的位置'}, - 'upFly': {'cls': 'tools', 'name': '上楼器', 'text': '可以飞往楼上的相同位置'}, - 'downFly': {'cls': 'tools', 'name': '下楼器', 'text': '可以飞往楼下的相同位置'}, - 'earthquake': {'cls': 'tools', 'name': '地震卷轴', 'text': '可以破坏当前层的所有墙'}, - 'poisonWine': {'cls': 'tools', 'name': '解毒药水', 'text': '可以解除中毒状态'}, - 'weakWine': {'cls': 'tools', 'name': '解衰药水', 'text': '可以解除衰弱状态'}, - 'curseWine': {'cls': 'tools', 'name': '解咒药水', 'text': '可以解除诅咒状态'}, - 'superWine': {'cls': 'tools', 'name': '万能药水', 'text': '可以解除所有不良状态'}, - 'hammer': {'cls': 'tools', 'name': '圣锤', 'text': '可以炸掉勇士面前的怪物'} - } + this.items = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.items; + this.itemEffect = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.itemEffect; + this.itemEffectTip = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.itemEffectTip; + //delete(items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a); } ////// 获得所有道具 ////// @@ -88,43 +36,13 @@ items.prototype.getItems = function () { return this.items; } -main.instance.items = new items(); - ////// “即捡即用类”道具的使用效果 ////// items.prototype.getItemEffect = function(itemId, itemNum) { var itemCls = core.material.items[itemId].cls; // 消耗品 if (itemCls === 'items') { - if (itemId === 'redJewel') core.status.hero.atk += core.values.redJewel; - if (itemId === 'blueJewel') core.status.hero.def += core.values.blueJewel; - if (itemId === 'greenJewel') core.status.hero.mdef += core.values.greenJewel; - if (itemId == 'yellowJewel') { // 黄宝石属性:需自己定义 - core.status.hero.hp+=1000; - core.status.hero.atk+=6; - core.status.hero.def+=6; - core.status.hero.mdef+=10; - } - if (itemId === 'redPotion') core.status.hero.hp += core.values.redPotion; - if (itemId === 'bluePotion') core.status.hero.hp += core.values.bluePotion; - if (itemId === 'yellowPotion') core.status.hero.hp += core.values.yellowPotion; - if (itemId === 'greenPotion') core.status.hero.hp += core.values.greenPotion; - if (itemId === 'sword1') core.status.hero.atk += core.values.sword1; - if (itemId === 'sword2') core.status.hero.atk += core.values.sword2; - if (itemId == 'sword3') core.status.hero.atk += core.values.sword3; - if (itemId == 'sword4') core.status.hero.atk += core.values.sword4; - if (itemId === 'sword5') core.status.hero.atk += core.values.sword5; - if (itemId === 'shield1') core.status.hero.def += core.values.shield1; - if (itemId === 'shield2') core.status.hero.def += core.values.shield2; - if (itemId === 'shield3') core.status.hero.def += core.values.shield3; - if (itemId === 'shield4') core.status.hero.def += core.values.shield4; - if (itemId === 'shield5') core.status.hero.def += core.values.shield5; - if (itemId === 'bigKey') { // 只有是钥匙盒才会执行这一步 - core.status.hero.items.keys.yellowKey++; - core.status.hero.items.keys.blueKey++; - core.status.hero.items.keys.redKey++; - } - if (itemId == 'superPotion') core.status.hero.hp *= 2; - if (itemId == 'moneyPocket') core.status.hero.money += core.values.moneyPocket; + var ratio = parseInt(core.floors[core.status.floorId].item_ratio) || 1; + if (itemId in this.itemEffect)eval(this.itemEffect[itemId]); } else { core.addItem(itemId, itemNum); @@ -133,27 +51,10 @@ items.prototype.getItemEffect = function(itemId, itemNum) { ////// “即捡即用类”道具的文字提示 ////// items.prototype.getItemEffectTip = function(itemId) { - if (itemId == 'redJewel') return ",攻击+"+core.values.redJewel; - if (itemId == 'blueJewel') return ",防御+"+core.values.blueJewel; - if (itemId == 'greenJewel') return ",魔防+"+core.values.greenJewel; - if (itemId == 'yellowJewel') return ",全属性提升"; - if (itemId == 'redPotion') return ",生命+"+core.values.redPotion; - if (itemId == 'bluePotion') return ",生命+"+core.values.bluePotion; - if (itemId == 'yellowPotion') return ",生命+"+core.values.yellowPotion; - if (itemId == 'greenPotion') return ",生命+"+core.values.greenPotion; - if (!core.flags.equipment && itemId == 'sword1') return ",攻击+"+core.values.sword1; - if (!core.flags.equipment && itemId == 'sword2') return ",攻击+"+core.values.sword2; - if (!core.flags.equipment && itemId == 'sword3') return ",攻击+"+core.values.sword3; - if (!core.flags.equipment && itemId == 'sword4') return ",攻击+"+core.values.sword4; - if (!core.flags.equipment && itemId == 'sword5') return ",攻击+"+core.values.sword5; - if (!core.flags.equipment && itemId == 'shield1') return ",防御+"+core.values.shield1; - if (!core.flags.equipment && itemId == 'shield2') return ",防御+"+core.values.shield2; - if (!core.flags.equipment && itemId == 'shield3') return ",防御+"+core.values.shield3; - if (!core.flags.equipment && itemId == 'shield4') return ",防御+"+core.values.shield4; - if (!core.flags.equipment && itemId == 'shield5') return ",防御+"+core.values.shield5; - if (itemId === 'bigKey') return ",全钥匙+1"; - if (itemId === 'superPotion') return ",生命值翻倍"; - if (itemId == 'moneyPocket') return ",金币+"+core.values.moneyPocket; + var ratio = parseInt(core.floors[core.status.floorId].item_ratio) || 1; + if (itemId in this.itemEffectTip && (!this.items[itemId].isEquipment || !core.flags.equipment)) { + return eval(this.itemEffectTip[itemId]); + } return ""; } @@ -299,7 +200,7 @@ items.prototype.canUseItem = function (itemId) { var ids = []; for (var i in core.status.thisMap.blocks) { var block = core.status.thisMap.blocks[i]; - if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable) && block.event.cls == 'enemys' && Math.abs(block.x-core.status.hero.loc.x)+Math.abs(block.y-core.status.hero.loc.y)<=1) { + if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable) && block.event.cls.indexOf('enemy')==0 && Math.abs(block.x-core.status.hero.loc.x)+Math.abs(block.y-core.status.hero.loc.y)<=1) { var enemy = core.material.enemys[block.event.id]; if (core.isset(enemy.bomb) && !enemy.bomb) continue; if (core.flags.bombFourDirections || (block.x==core.nextX() && block.y==core.nextY())) @@ -316,7 +217,7 @@ items.prototype.canUseItem = function (itemId) { // 圣锤 for (var i in core.status.thisMap.blocks) { var block = core.status.thisMap.blocks[i]; - if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable) && block.event.cls == 'enemys' && block.x==core.nextX() && block.y==core.nextY()) { + if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable) && block.event.cls.indexOf('enemy')==0 && block.x==core.nextX() && block.y==core.nextY()) { var enemy = core.material.enemys[block.event.id]; if (core.isset(enemy.bomb) && !enemy.bomb) continue; core.status.event.data = [i]; @@ -418,3 +319,57 @@ items.prototype.canUseItem = function (itemId) { return false; } + +////// 获得某个物品的个数 ////// +items.prototype.itemCount = function (itemId) { + if (!core.isset(itemId) || !core.isset(core.material.items[itemId])) return 0; + var itemCls = core.material.items[itemId].cls; + if (itemCls=="items") return 0; + return core.isset(core.status.hero.items[itemCls][itemId]) ? core.status.hero.items[itemCls][itemId] : 0; +} + +////// 是否存在某个物品 ////// +items.prototype.hasItem = function (itemId) { + return core.itemCount(itemId) > 0; +} + +////// 设置某个物品的个数 ////// +items.prototype.setItem = function (itemId, itemNum) { + var itemCls = core.material.items[itemId].cls; + if (itemCls == 'items') return; + if (!core.isset(core.status.hero.items[itemCls])) { + core.status.hero.items[itemCls] = {}; + } + core.status.hero.items[itemCls][itemId] = itemNum; + if (itemCls!='keys' && itemNum==0) { + delete core.status.hero.items[itemCls][itemId]; + } +} + +////// 删除某个物品 ////// +items.prototype.removeItem = function (itemId) { + if (!core.hasItem(itemId)) return false; + var itemCls = core.material.items[itemId].cls; + core.status.hero.items[itemCls][itemId]--; + if (itemCls!='keys' && core.status.hero.items[itemCls][itemId]==0) { + delete core.status.hero.items[itemCls][itemId]; + } + core.updateStatusBar(); + return true; +} + +////// 增加某个物品的个数 ////// +items.prototype.addItem = function (itemId, itemNum) { + var itemData = core.material.items[itemId]; + var itemCls = itemData.cls; + if (itemCls == 'items') return; + if (!core.isset(core.status.hero.items[itemCls])) { + core.status.hero.items[itemCls] = {}; + core.status.hero.items[itemCls][itemId] = 0; + } + else if (!core.isset(core.status.hero.items[itemCls][itemId])) { + core.status.hero.items[itemCls][itemId] = 0; + } + core.status.hero.items[itemCls][itemId] += itemNum; +} + diff --git a/libs/loader.js b/libs/loader.js new file mode 100644 index 00000000..48844bb6 --- /dev/null +++ b/libs/loader.js @@ -0,0 +1,224 @@ +/* +loader.js:负责对资源的加载 + + */ + +function loader() { + this.init(); +} + +loader.prototype.init = function () { + +} + +////// 设置加载进度条进度 ////// +loader.prototype.setStartProgressVal = function (val) { + core.dom.startTopProgress.style.width = val + '%'; +} + +////// 设置加载进度条提示文字 ////// +loader.prototype.setStartLoadTipText = function (text) { + core.dom.startTopLoadTips.innerHTML = text; +} + +loader.prototype.load = function (callback) { + + // 加载图片 + core.loader.loadImages(core.materials, core.material.images, function () { + // 加载png图片 + core.material.images.images = {}; + core.loader.loadImages(core.images, core.material.images.images, function () { + // 加载autotile + core.material.images.autotile = {}; + core.loader.loadImages(Object.keys(core.material.icons.autotile), core.material.images.autotile, function () { + core.loader.loadAnimates(); + core.loader.loadMusic(); + if (core.isset(callback)) + callback(); + }) + }) + }) +} + +loader.prototype.loadImages = function (names, toSave, callback) { + if (names.length==0) { + if (core.isset(callback)) callback(); + return; + } + var items = 0; + for (var i=0;i0) + core.playBgm(core.bgms[0]); +} diff --git a/libs/maps.js b/libs/maps.js index 60f14182..6b3eecc5 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -1,5 +1,11 @@ -function maps() {} -maps.prototype.init = function() {} +function maps() { + this.init(); +} + +maps.prototype.init = function() { + this.blocksInfo = maps_90f36752_8815_4be8_b32b_d7fad1d0542e; + //delete(maps_90f36752_8815_4be8_b32b_d7fad1d0542e); +} ////// 加载某个楼层(从剧本或存档中) ////// maps.prototype.loadFloor = function (floorId, map) { @@ -10,23 +16,31 @@ maps.prototype.loadFloor = function (floorId, map) { content['title'] = floor.title; content['canFlyTo'] = floor.canFlyTo; if (!core.isset(map)) map=floor.map; - var blocks = []; - for (var i = 0; i < 13; i++) { - for (var j = 0; j < 13; j++) { - var block = this.getBlock(j, i, map[i][j]); - this.addInfo(block); - this.addEvent(block,j,i,floor.events[j+","+i]) - this.addChangeFloor(block,j,i,floor.changeFloor[j+","+i]); - if (core.isset(block.event)) blocks.push(block); + var mapIntoBlocks = function(map,maps,floor){ + var blocks = []; + for (var i = 0; i < 13; i++) { + for (var j = 0; j < 13; j++) { + var block = maps.initBlock(j, i, map[i][j]); + maps.addInfo(block); + maps.addEvent(block,j,i,floor.events[j+","+i]) + maps.addChangeFloor(block,j,i,floor.changeFloor[j+","+i]); + if (core.isset(block.event)) blocks.push(block); + } + } + return blocks; + } + if (main.mode=='editor'){ + main.editor.mapIntoBlocks = function(map,floor){ + return mapIntoBlocks(map,core.maps,floor); } } // 事件处理 - content['blocks'] = blocks; + content['blocks'] = mapIntoBlocks(map,this,floor); return content; } ////// 数字和ID的对应关系 ////// -maps.prototype.getBlock = function (x, y, id) { +maps.prototype.initBlock = function (x, y, id) { var enable=null; id = ""+id; if (id.length>2) { @@ -43,199 +57,7 @@ maps.prototype.getBlock = function (x, y, id) { var tmp = {'x': x, 'y': y, 'id': id}; if (enable!=null) tmp.enable = enable; - ////////////////////////// 地形部分 ////////////////////////// - - // 0-20 地形 - if (id == 1) tmp.event = {'cls': 'terrains', 'id': 'yellowWall'}; // 黄墙 - if (id == 2) tmp.event = {'cls': 'terrains', 'id': 'whiteWall'}; // 白墙 - if (id == 3) tmp.event = {'cls': 'terrains', 'id': 'blueWall'}; // 蓝墙 - if (id == 4) tmp.event = {'cls': 'animates', 'id': 'star', 'noPass': true}; // 星空 - if (id == 5) tmp.event = {'cls': 'animates', 'id': 'lava', 'noPass': true}; // 岩浆 - if (id == 6) tmp.event = {'cls': 'terrains', 'id': 'ice'}; // 冰面 - if (id == 7) tmp.event = {'cls': 'terrains', 'id': 'blueShop-left'}; // 蓝色商店左 - if (id == 8) tmp.event = {'cls': 'terrains', 'id': 'blueShop-right'}; // 蓝色商店右 - if (id == 9) tmp.event = {'cls': 'terrains', 'id': 'pinkShop-left'}; // 粉色商店左 - if (id == 10) tmp.event = {'cls': 'terrains', 'id': 'pinkShop-right'}; // 粉色商店左 - if (id == 11) tmp.event = {'cls': 'animates', 'id': 'lavaNet', 'noPass': false, 'trigger': 'passNet'}; // 血网 - if (id == 12) tmp.event = {'cls': 'animates', 'id': 'poisonNet', 'noPass': false, 'trigger': 'passNet'}; // 毒网 - if (id == 13) tmp.event = {'cls': 'animates', 'id': 'weakNet', 'noPass': false, 'trigger': 'passNet'}; // 衰网 - if (id == 14) tmp.event = {'cls': 'animates', 'id': 'curseNet', 'noPass': false, 'trigger': 'passNet'}; // 咒网 - if (id == 15) tmp.event = {'cls': 'animates', 'id': 'water', 'noPass': true}; // 水 - // 在这里添加更多地形 - // 如果空位不足,可以从180以后开始继续放,只要不和现有的数字冲突即可 - - // Autotile - if (id == 20) tmp.event = {'cls': 'autotile', 'id': 'autotile', 'noPass': true}; // autotile - // 更多的autotile从151到160等,只要不和现有的数字冲突即可 - if (id == 151) tmp.event = {'cls': 'autotile', 'id': 'autotile1', 'noPass': true}; - if (id == 152) tmp.event = {'cls': 'autotile', 'id': 'autotile2', 'noPass': true}; - if (id == 153) tmp.event = {'cls': 'autotile', 'id': 'autotile3', 'noPass': true}; - - ////////////////////////// 物品部分 ////////////////////////// - - // 21-80 物品 - if (id == 21) tmp.event = {'cls': 'items', 'id': 'yellowKey'}; // 黄钥匙 - if (id == 22) tmp.event = {'cls': 'items', 'id': 'blueKey'}; // 蓝钥匙 - if (id == 23) tmp.event = {'cls': 'items', 'id': 'redKey'}; // 红钥匙 - if (id == 24) tmp.event = {'cls': 'items', 'id': 'greenKey'}; // 绿钥匙 - if (id == 25) tmp.event = {'cls': 'items', 'id': 'steelKey'}; // 铁门钥匙 - if (id == 26) tmp.event = {'cls': 'items', 'id': 'bigKey'}; // 大黄门钥匙(钥匙盒) - if (id == 27) tmp.event = {'cls': 'items', 'id': 'redJewel'}; // 红宝石 - if (id == 28) tmp.event = {'cls': 'items', 'id': 'blueJewel'}; // 蓝宝石 - if (id == 29) tmp.event = {'cls': 'items', 'id': 'greenJewel'}; // 绿宝石 - if (id == 30) tmp.event = {'cls': 'items', 'id': 'yellowJewel'}; // 黄宝石 - if (id == 31) tmp.event = {'cls': 'items', 'id': 'redPotion'}; // 红血瓶 - if (id == 32) tmp.event = {'cls': 'items', 'id': 'bluePotion'}; // 蓝血瓶 - if (id == 33) tmp.event = {'cls': 'items', 'id': 'greenPotion'}; // 绿血瓶 - if (id == 34) tmp.event = {'cls': 'items', 'id': 'yellowPotion'}; // 黄血瓶 - if (id == 35) tmp.event = {'cls': 'items', 'id': 'sword1'}; // 铁剑 - if (id == 36) tmp.event = {'cls': 'items', 'id': 'shield1'}; // 铁盾 - if (id == 37) tmp.event = {'cls': 'items', 'id': 'sword2'}; // 银剑 - if (id == 38) tmp.event = {'cls': 'items', 'id': 'shield2'}; // 银盾 - if (id == 39) tmp.event = {'cls': 'items', 'id': 'sword3'}; // 骑士剑 - if (id == 40) tmp.event = {'cls': 'items', 'id': 'shield3'}; // 骑士盾 - if (id == 41) tmp.event = {'cls': 'items', 'id': 'sword4'}; // 圣剑 - if (id == 42) tmp.event = {'cls': 'items', 'id': 'shield4'}; // 圣盾 - if (id == 43) tmp.event = {'cls': 'items', 'id': 'sword5'}; // 神圣剑 - if (id == 44) tmp.event = {'cls': 'items', 'id': 'shield5'}; // 神圣盾 - if (id == 45) tmp.event = {'cls': 'items', 'id': 'book'}; // 怪物手册 - if (id == 46) tmp.event = {'cls': 'items', 'id': 'fly'}; // 楼层传送器 - if (id == 47) tmp.event = {'cls': 'items', 'id': 'pickaxe'}; // 破墙镐 - if (id == 48) tmp.event = {'cls': 'items', 'id': 'icePickaxe'}; // 破冰镐 - if (id == 49) tmp.event = {'cls': 'items', 'id': 'bomb'}; // 炸弹 - if (id == 50) tmp.event = {'cls': 'items', 'id': 'centerFly'}; // 中心对称 - if (id == 51) tmp.event = {'cls': 'items', 'id': 'upFly'}; // 上楼器 - if (id == 52) tmp.event = {'cls': 'items', 'id': 'downFly'}; // 下楼器 - if (id == 53) tmp.event = {'cls': 'items', 'id': 'coin'}; // 幸运金币 - if (id == 54) tmp.event = {'cls': 'items', 'id': 'snow'}; // 冰冻徽章 - if (id == 55) tmp.event = {'cls': 'items', 'id': 'cross'}; // 十字架 - if (id == 56) tmp.event = {'cls': 'items', 'id': 'superPotion'}; // 圣水 - if (id == 57) tmp.event = {'cls': 'items', 'id': 'earthquake'} // 地震卷轴 - if (id == 58) tmp.event = {'cls': 'items', 'id': 'poisonWine'} // 解毒药水 - if (id == 59) tmp.event = {'cls': 'items', 'id': 'weakWine'} // 解衰药水 - if (id == 60) tmp.event = {'cls': 'items', 'id': 'curseWine'} // 解咒药水 - if (id == 61) tmp.event = {'cls': 'items', 'id': 'superWine'} // 万能药水 - if (id == 62) tmp.event = {'cls': 'items', 'id': 'knife'} // 屠龙匕首 - if (id == 63) tmp.event = {'cls': 'items', 'id': 'moneyPocket'} // 金钱袋 - if (id == 64) tmp.event = {'cls': 'items', 'id': 'shoes'} // 绿鞋 - if (id == 65) tmp.event = {'cls': 'items', 'id': 'hammer'} // 圣锤 - - - ////////////////////////// 门、楼梯、传送点部分 ////////////////////////// - - // 81-100 门 - if (id == 81) tmp.event = {'cls': 'terrains', 'id': 'yellowDoor', 'trigger': 'openDoor'}; // 黄门 - if (id == 82) tmp.event = {'cls': 'terrains', 'id': 'blueDoor', 'trigger': 'openDoor'}; // 蓝门 - if (id == 83) tmp.event = {'cls': 'terrains', 'id': 'redDoor', 'trigger': 'openDoor'}; // 红门 - if (id == 84) tmp.event = {'cls': 'terrains', 'id': 'greenDoor', 'trigger': 'openDoor'}; // 绿门 - if (id == 85) tmp.event = {'cls': 'terrains', 'id': 'specialDoor', 'trigger': 'openDoor'}; // 机关门左 - if (id == 86) tmp.event = {'cls': 'terrains', 'id': 'steelDoor', 'trigger': 'openDoor'}; // 铁门 - if (id == 87) tmp.event = {'cls': 'terrains', 'id': 'upFloor', 'noPass': false}; // 上楼梯 - if (id == 88) tmp.event = {'cls': 'terrains', 'id': 'downFloor', 'noPass': false}; // 下楼梯 - if (id == 89) tmp.event = {'cls': 'animates', 'id': 'portal', 'noPass': false}; // 传送门 - if (id == 90) tmp.event = {'cls': 'animates', 'id': 'starPortal', 'noPass': false}; // 星空传送门 - if (id == 91) tmp.event = {'cls': 'animates', 'id': 'upPortal', 'noPass': false}; // 上箭头 - if (id == 92) tmp.event = {'cls': 'animates', 'id': 'leftPortal', 'noPass': false}; // 左箭头 - if (id == 93) tmp.event = {'cls': 'animates', 'id': 'downPortal', 'noPass': false}; // 下箭头 - if (id == 94) tmp.event = {'cls': 'animates', 'id': 'rightPortal', 'noPass': false}; // 右箭头 - - - ////////////////////////// NPC部分 ////////////////////////// - - // 121-150 NPC - if (id == 121) tmp.event = {'cls': 'npcs', 'id': 'man'}; - if (id == 122) tmp.event = {'cls': 'npcs', 'id': 'woman'}; - if (id == 123) tmp.event = {'cls': 'npcs', 'id': 'thief'}; - if (id == 124) tmp.event = {'cls': 'npcs', 'id': 'fairy'}; - if (id == 125) tmp.event = {'cls': 'npcs', 'id': 'magician'}; - if (id == 126) tmp.event = {'cls': 'npcs', 'id': 'womanMagician'}; - if (id == 127) tmp.event = {'cls': 'npcs', 'id': 'oldMan'}; - if (id == 128) tmp.event = {'cls': 'npcs', 'id': 'child'}; - if (id == 129) tmp.event = {'cls': 'npcs', 'id': 'wood'}; - if (id == 130) tmp.event = {'cls': 'npcs', 'id': 'pinkShop'}; - if (id == 131) tmp.event = {'cls': 'npcs', 'id': 'blueShop'}; - if (id == 132) tmp.event = {'cls': 'npcs', 'id': 'princess'}; - - ////////////////////////// 其他部分 ////////////////////////// - - // 161-200 其他(单向箭头、灯、箱子等等) - if (id == 161) tmp.event = {'cls': 'terrains', 'id': 'arrowUp', 'noPass': false}; // 单向上箭头 - if (id == 162) tmp.event = {'cls': 'terrains', 'id': 'arrowDown', 'noPass': false}; // 单向下箭头 - if (id == 163) tmp.event = {'cls': 'terrains', 'id': 'arrowLeft', 'noPass': false}; // 单向左箭头 - if (id == 164) tmp.event = {'cls': 'terrains', 'id': 'arrowRight', 'noPass': false}; // 单向右箭头 - if (id == 165) tmp.event = {'cls': 'terrains', 'id': 'light', 'trigger': 'changeLight', 'noPass': false}; // 灯 - if (id == 166) tmp.event = {'cls': 'terrains', 'id': 'darkLight', 'noPass': true}; // 暗灯 - if (id == 167) tmp.event = {'cls': 'terrains', 'id': 'ski', 'trigger': 'ski', 'noPass': false}; // 滑冰 - if (id == 168) tmp.event = {'cls': 'terrains', 'id': 'flower', 'noPass': false}; // 花 - if (id == 169) tmp.event = {'cls': 'terrains', 'id': 'box', 'trigger': 'pushBox', 'noPass': true}; // 箱子 - if (id == 170) tmp.event = {'cls': 'terrains', 'id': 'boxed', 'trigger': 'pushBox', 'noPass': true}; // 完成的箱子 - - ////////////////////////// 怪物部分 ////////////////////////// - - // 201-300 怪物 - if (id == 201) tmp.event = {'cls': 'enemys', 'id': 'greenSlime'}; - if (id == 202) tmp.event = {'cls': 'enemys', 'id': 'redSlime'}; - if (id == 203) tmp.event = {'cls': 'enemys', 'id': 'blackSlime'}; - if (id == 204) tmp.event = {'cls': 'enemys', 'id': 'slimelord'}; - if (id == 205) tmp.event = {'cls': 'enemys', 'id': 'bat'}; - if (id == 206) tmp.event = {'cls': 'enemys', 'id': 'bigBat'}; - if (id == 207) tmp.event = {'cls': 'enemys', 'id': 'redBat'}; - if (id == 208) tmp.event = {'cls': 'enemys', 'id': 'vampire'}; - if (id == 209) tmp.event = {'cls': 'enemys', 'id': 'skeleton'}; - if (id == 210) tmp.event = {'cls': 'enemys', 'id': 'skeletonSoilder'}; - if (id == 211) tmp.event = {'cls': 'enemys', 'id': 'skeletonCaptain'}; - if (id == 212) tmp.event = {'cls': 'enemys', 'id': 'ghostSkeleton'}; - if (id == 213) tmp.event = {'cls': 'enemys', 'id': 'zombie'}; - if (id == 214) tmp.event = {'cls': 'enemys', 'id': 'zombieKnight'}; - if (id == 215) tmp.event = {'cls': 'enemys', 'id': 'rock'}; - if (id == 216) tmp.event = {'cls': 'enemys', 'id': 'slimeMan'}; - if (id == 217) tmp.event = {'cls': 'enemys', 'id': 'bluePriest'}; - if (id == 218) tmp.event = {'cls': 'enemys', 'id': 'redPriest'}; - if (id == 219) tmp.event = {'cls': 'enemys', 'id': 'brownWizard'}; - if (id == 220) tmp.event = {'cls': 'enemys', 'id': 'redWizard'}; - if (id == 221) tmp.event = {'cls': 'enemys', 'id': 'yellowGuard'}; - if (id == 222) tmp.event = {'cls': 'enemys', 'id': 'blueGuard'}; - if (id == 223) tmp.event = {'cls': 'enemys', 'id': 'redGuard'}; - if (id == 224) tmp.event = {'cls': 'enemys', 'id': 'swordsman'}; - if (id == 225) tmp.event = {'cls': 'enemys', 'id': 'soldier'}; - if (id == 226) tmp.event = {'cls': 'enemys', 'id': 'yellowKnight'}; - if (id == 227) tmp.event = {'cls': 'enemys', 'id': 'redKnight'}; - if (id == 228) tmp.event = {'cls': 'enemys', 'id': 'darkKnight'}; - if (id == 229) tmp.event = {'cls': 'enemys', 'id': 'blackKing'}; - if (id == 230) tmp.event = {'cls': 'enemys', 'id': 'yellowKing'}; - if (id == 231) tmp.event = {'cls': 'enemys', 'id': 'greenKing'}; - if (id == 232) tmp.event = {'cls': 'enemys', 'id': 'blueKnight'}; - if (id == 233) tmp.event = {'cls': 'enemys', 'id': 'goldSlime'}; - if (id == 234) tmp.event = {'cls': 'enemys', 'id': 'poisonSkeleton'}; - if (id == 235) tmp.event = {'cls': 'enemys', 'id': 'poisonBat'}; - if (id == 236) tmp.event = {'cls': 'enemys', 'id': 'steelRock'}; - if (id == 237) tmp.event = {'cls': 'enemys', 'id': 'skeletonPriest'}; - if (id == 238) tmp.event = {'cls': 'enemys', 'id': 'skeletonKing'}; - if (id == 239) tmp.event = {'cls': 'enemys', 'id': 'skeletonWizard'}; - if (id == 240) tmp.event = {'cls': 'enemys', 'id': 'redSkeletonCaption'}; - if (id == 241) tmp.event = {'cls': 'enemys', 'id': 'badHero'}; - if (id == 242) tmp.event = {'cls': 'enemys', 'id': 'demon'}; - if (id == 243) tmp.event = {'cls': 'enemys', 'id': 'demonPriest'}; - if (id == 244) tmp.event = {'cls': 'enemys', 'id': 'goldHornSlime'}; - if (id == 245) tmp.event = {'cls': 'enemys', 'id': 'redKing'}; - if (id == 246) tmp.event = {'cls': 'enemys', 'id': 'whiteKing'}; - if (id == 247) tmp.event = {'cls': 'enemys', 'id': 'blackMagician'}; - if (id == 248) tmp.event = {'cls': 'enemys', 'id': 'silverSlime'}; - if (id == 249) tmp.event = {'cls': 'enemys', 'id': 'swordEmperor'}; - if (id == 250) tmp.event = {'cls': 'enemys', 'id': 'whiteHornSlime'}; - if (id == 251) tmp.event = {'cls': 'enemys', 'id': 'badPrincess'}; - if (id == 252) tmp.event = {'cls': 'enemys', 'id': 'badFairy'}; - if (id == 253) tmp.event = {'cls': 'enemys', 'id': 'grayPriest'}; - if (id == 254) tmp.event = {'cls': 'enemys', 'id': 'redSwordsman'}; - if (id == 255) tmp.event = {'cls': 'enemys', 'id': 'whiteGhost'}; - if (id == 256) tmp.event = {'cls': 'enemys', 'id': 'poisonZombie'}; - if (id == 257) tmp.event = {'cls': 'enemys', 'id': 'magicDragon'}; - if (id == 258) tmp.event = {'cls': 'enemys', 'id': 'octopus'}; - if (id == 259) tmp.event = {'cls': 'enemys', 'id': 'darkFairy'}; - if (id == 260) tmp.event = {'cls': 'enemys', 'id': 'greenKnight'}; - - ////////////////////////// 待定... ////////////////////////// - // 目前ID暂时不要超过400 + if (id in this.blocksInfo) tmp.event = JSON.parse(JSON.stringify(this.blocksInfo[id])); return tmp; } @@ -243,14 +65,14 @@ maps.prototype.getBlock = function (x, y, id) { ////// 添加一些信息到block上 ////// maps.prototype.addInfo = function (block) { if (core.isset(block.event)) { - if (block.event.cls == 'enemys' && block.event.trigger==undefined) { + if (block.event.cls.indexOf("enemy")==0 && block.event.trigger==undefined) { block.event.trigger = 'battle'; } if (block.event.cls == 'items' && block.event.trigger==undefined) { block.event.trigger = 'getItem'; } if (block.event.noPass == undefined) { - if (block.event.cls=='enemys' || block.event.cls=='terrains' || block.event.cls=='npcs') { + if (block.event.cls.indexOf("enemy")==0 || block.event.cls.indexOf("npc")==0 || block.event.cls=='terrains') { block.event.noPass = true; } } @@ -258,10 +80,13 @@ maps.prototype.addInfo = function (block) { if (block.event.cls=='enemys' || block.event.cls=='npcs') { block.event.animate = 2; } - if (block.event.cls == 'animates') { + if (block.event.cls == 'animates' || block.event.cls == 'enemy48' || block.event.cls == 'npc48') { block.event.animate = 4; } } + block.event.height = 32; + if (block.event.cls == 'enemy48' || block.event.cls == 'npc48') + block.event.height = 48; } } @@ -380,4 +205,677 @@ maps.prototype.getMapArray = function (blockArray){ return blocks; } -main.instance.maps = new maps(); \ No newline at end of file + + +////// 勇士能否前往某方向 ////// +maps.prototype.canMoveHero = function(x,y,direction,floorId) { + if (!core.isset(x)) x=core.getHeroLoc('x'); + if (!core.isset(y)) y=core.getHeroLoc('y'); + if (!core.isset(direction)) direction=core.getHeroLoc('direction'); + if (!core.isset(floorId)) floorId=core.status.floorId; + + // 检查当前块的cannotMove + if (core.isset(core.floors[floorId].cannotMove)) { + var cannotMove = core.floors[floorId].cannotMove[x+","+y]; + if (core.isset(cannotMove) && cannotMove instanceof Array && cannotMove.indexOf(direction)>=0) + return false; + } + + var nowBlock = core.getBlock(x,y,floorId); + if (nowBlock!=null){ + nowId = nowBlock.block.event.id; + var nowIsArrow = nowId.slice(0, 5).toLowerCase() == 'arrow'; + if(nowIsArrow){ + var nowArrow = nowId.slice(5).toLowerCase(); + if (direction != nowArrow) { + return false; + } + } + } + var scan = { + 'up': {'x': 0, 'y': -1}, + 'left': {'x': -1, 'y': 0}, + 'down': {'x': 0, 'y': 1}, + 'right': {'x': 1, 'y': 0} + }; + var nextBlock = core.getBlock(x+scan[direction].x,y+scan[direction].y,floorId); + if (nextBlock!=null){ + nextId = nextBlock.block.event.id; + // 遇到单向箭头处理 + var isArrow = nextId.slice(0, 5).toLowerCase() == 'arrow'; + if(isArrow){ + var nextArrow = nextId.slice(5).toLowerCase(); + if ( (scan[direction].x + scan[nextArrow].x) == 0 && (scan[direction].y + scan[nextArrow].y) == 0 ) { + return false; + } + } + } + return true; +} + +////// 能否瞬间移动 ////// +maps.prototype.canMoveDirectly = function (destX,destY) { + if (!core.flags.enableMoveDirectly) return false; + + // 中毒状态:不能 + if (core.hasFlag('poison')) return false; + + var fromX = core.getHeroLoc('x'), fromY = core.getHeroLoc('y'); + if (fromX==destX&&fromY==destY) return false; + + if (core.getBlock(fromX,fromY)!=null||core.status.checkBlock.damage[13*fromX+fromY]>0) + return false; + + // BFS + var visited=[], queue=[]; + visited[13*fromX+fromY]=true; + queue.push(13*fromX+fromY); + + var directions = [[-1,0],[1,0],[0,1],[0,-1]]; + while (queue.length>0) { + var now=queue.shift(), nowX=parseInt(now/13), nowY=now%13; + + for (var dir in directions) { + var nx=nowX+directions[dir][0], ny=nowY+directions[dir][1]; + if (nx<0||nx>=13||ny<0||ny>=13||visited[13*nx+ny]||core.getBlock(nx,ny)!=null||core.status.checkBlock.damage[13*nx+ny]>0) continue; + if (nx==destX&&ny==destY) return true; + visited[13*nx+ny]=true; + queue.push(13*nx+ny); + } + } + return false; +} + +maps.prototype.drawBlock = function (block, animate, dx, dy) { + var cls = block.event.cls, height = block.event.height || 32; + var blockIcon = core.material.icons[cls][block.event.id]; + var blockImage = core.material.images[cls]; + animate=(animate||0)%(block.event.animate||1); + dx = dx || 0; + dy = dy || 0; + core.canvas.event.clearRect(block.x * 32 + dx, block.y * 32 + dy, 32, 32); + core.canvas.event.drawImage(blockImage, animate * 32, blockIcon * height + height-32, 32, 32, block.x * 32 + dx, block.y * 32 + dy, 32, 32); + if (height>32) { + core.canvas.event2.clearRect(block.x * 32 + dx, block.y * 32 + 32 - height + dy, 32, height-32) + core.canvas.event2.drawImage(blockImage, animate * 32, blockIcon * height, 32, height-32, block.x * 32 + dx, block.y*32 + 32 - height + dy, 32, height-32); + } +} + +////// 绘制某张地图 ////// +maps.prototype.drawMap = function (mapName, callback) { + core.clearMap('all'); + core.removeGlobalAnimate(null, null, true); + var drawBg = function(){ + var groundId = core.floors[mapName].defaultGround || "ground"; + var blockIcon = core.material.icons.terrains[groundId]; + var blockImage = core.material.images.terrains; + for (var x = 0; x < 13; x++) { + for (var y = 0; y < 13; y++) { + core.canvas.bg.drawImage(blockImage, 0, blockIcon * 32, 32, 32, x * 32, y * 32, 32, 32); + } + } + + var images = []; + if (core.isset(core.floors[mapName].images)) { + images = core.floors[mapName].images; + if (typeof images == 'string') { + images = [[0, 0, images]]; + } + } + images.forEach(function (t) { + var size=416, ratio=1; + var dx=parseInt(t[0]), dy=parseInt(t[1]), p=t[2]; + if (core.isset(dx) && core.isset(dy) && core.isset(core.material.images.images[p])) { + dx*=32; dy*=32; + var image = core.material.images.images[p]; + if (!t[3]) + core.canvas.bg.drawImage(image, dx*ratio, dy*ratio, Math.min(size-dx*ratio, ratio*image.width), Math.min(size-dy*ratio, ratio*image.height)); + else + core.canvas.event2.drawImage(image, dx*ratio, dy*ratio, Math.min(size-dx*ratio, ratio*image.width), Math.min(size-dy*ratio, ratio*image.height)); + } + }) + + } + if (main.mode=='editor'){ + main.editor.drawMapBg = function(){ + core.clearMap('bg', 0, 0, 416, 416); + drawBg(); + } + } else { + drawBg(); + } + + core.status.floorId = mapName; + core.status.thisMap = core.status.maps[mapName]; + var drawEvent = function(){ + var mapData = core.status.maps[core.status.floorId]; + var mapBlocks = mapData.blocks; + + var mapArray = core.maps.getMapArray(mapBlocks); + for (var b = 0; b < mapBlocks.length; b++) { + // 事件启用 + var block = mapBlocks[b]; + if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable)) { + if (block.event.cls == 'autotile') { + core.drawAutotile(core.canvas.event, mapArray, block, 32, 0, 0); + } + else { + if (block.event.id!='none') { + core.drawBlock(block); + core.addGlobalAnimate(block); + } + } + } + } + } + + if (main.mode=='editor'){ + main.editor.updateMap = function(){ + core.removeGlobalAnimate(null, null, true); + core.clearMap('event', 0, 0, 416, 416); + drawEvent(); + core.setGlobalAnimate(core.values.animateSpeed); + } + } else { + drawEvent(); + } + core.setGlobalAnimate(core.values.animateSpeed); + if (core.isset(callback)) + callback(); +} + +////// 绘制Autotile ////// +maps.prototype.drawAutotile = function(ctx, mapArr, block, size, left, top){ + var indexArrs = [ //16种组合的图块索引数组; // 将autotile分割成48块16*16的小块; 数组索引即对应各个小块 + // +----+----+----+----+----+----+ + [10, 9, 4, 3 ], //0 bin:0000 | 1 | 2 | 3 | 4 | 5 | 6 | + [10, 9, 4, 13], //1 bin:0001 +----+----+----+----+----+----+ + [10, 9, 18, 3 ], //2 bin:0010 | 7 | 8 | 9 | 10 | 11 | 12 | + [10, 9, 16, 15], //3 bin:0011 +----+----+----+----+----+----+ + [10, 43, 4, 3 ], //4 bin:0100 | 13 | 14 | 15 | 16 | 17 | 18 | + [10, 31, 4, 25], //5 bin:0101 +----+----+----+----+----+----+ + [10, 7, 2, 3 ], //6 bin:0110 | 19 | 20 | 21 | 22 | 23 | 24 | + [10, 31, 16, 5 ], //7 bin:0111 +----+----+----+----+----+----+ + [48, 9, 4, 3 ], //8 bin:1000 | 25 | 26 | 27 | 28 | 29 | 30 | + [ 8, 9, 4, 1 ], //9 bin:1001 +----+----+----+----+----+----+ + [36, 9, 30, 3 ], //10 bin:1010 | 31 | 32 | 33 | 34 | 35 | 36 | + [36, 9, 6, 15], //11 bin:1011 +----+----+----+----+----+----+ + [46, 45, 4, 3 ], //12 bin:1100 | 37 | 38 | 39 | 40 | 41 | 42 | + [46, 11, 4, 25], //13 bin:1101 +----+----+----+----+----+----+ + [12, 45, 30, 3 ], //14 bin:1110 | 43 | 44 | 45 | 46 | 47 | 48 | + [34, 33, 28, 27] //15 bin:1111 +----+----+----+----+----+----+ + ]; + + var drawBlockByIndex = function(ctx, dx, dy, autotileImg, index, size){ //index为autotile的图块索引1-48 + var sx = 16*((index-1)%6), sy = 16*(~~((index-1)/6)); + ctx.drawImage(autotileImg, sx, sy, 16, 16, dx, dy, size/2, size/2); + } + var getAutotileAroundId = function(currId, x, y){ + if(x<0 || y<0 || x>12 || y>12) return 1; + else return mapArr[y][x]==currId ? 1:0; + } + var checkAround = function(x, y){ // 得到周围四个32*32块(周围每块都包含当前块的1/4,不清楚的话画下图你就明白)的数组索引 + var currId = mapArr[y][x]; + var pointBlock = []; + for(var i=0; i<4; i++){ + var bsum = 0; + var offsetx = i%2, offsety = ~~(i/2); + for(var j=0; j<4; j++){ + var mx = j%2, my = ~~(j/2); + var b = getAutotileAroundId(currId, x+offsetx+mx-1, y+offsety+my-1); + bsum += b*(Math.pow(2, 3-j)); + } + pointBlock.push(bsum); + } + return pointBlock; + } + var getAutotileIndexs = function(x, y){ + var indexArr = []; + var pointBlocks = checkAround(x, y); + for(var i=0; i<4; i++){ + var arr = indexArrs[pointBlocks[i]] + indexArr.push(arr[3-i]); + } + return indexArr; + } + // 开始绘制autotile + var x = block.x, y = block.y; + var pieceIndexs = getAutotileIndexs(x, y); + + //修正四个边角的固定搭配 + if(pieceIndexs[0] == 13){ + if(pieceIndexs[1] == 16) pieceIndexs[1] = 14; + if(pieceIndexs[2] == 31) pieceIndexs[2] = 19; + } + if(pieceIndexs[1] == 18){ + if(pieceIndexs[0] == 15) pieceIndexs[0] = 17; + if(pieceIndexs[3] == 36) pieceIndexs[3] = 24; + } + if(pieceIndexs[2] == 43){ + if(pieceIndexs[0] == 25) pieceIndexs[0] = 37; + if(pieceIndexs[3] == 46) pieceIndexs[3] = 44; + } + if(pieceIndexs[3] == 48){ + if(pieceIndexs[1] == 30) pieceIndexs[1] = 42; + if(pieceIndexs[2] == 45) pieceIndexs[2] = 47; + } + for(var i=0; i<4; i++){ + var index = pieceIndexs[i]; + var dx = x*size + size/2*(i%2), dy = y*size + size/2*(~~(i/2)); + drawBlockByIndex(ctx, dx+left, dy+top, core.material.images['autotile'][block.event.id], index, size); + } +} + +////// 某个点是否不可通行 ////// +maps.prototype.noPassExists = function (x, y, floorId) { + var block = core.getBlock(x,y,floorId); + if (block==null) return false; + return core.isset(block.block.event.noPass) && block.block.event.noPass; +} + +////// 某个点是否在区域内且不可通行 ////// +maps.prototype.noPass = function (x, y) { + return x<0 || x>12 || y<0 || y>12 || this.noPassExists(x,y); +} + +////// 某个点是否存在NPC ////// +maps.prototype.npcExists = function (x, y, floorId) { + var block = this.getBlock(x,y,floorId); + if (block==null) return false; + return block.block.event.cls.indexOf('npc')==0; +} + +////// 某个点是否存在(指定的)地形 ////// +maps.prototype.terrainExists = function (x, y, id, floorId) { + var block = this.getBlock(x,y,floorId); + if (block==null) return false; + return block.block.event.cls=='terrains' && (core.isset(id)?block.block.event.id==id:true); +} + +////// 某个点是否存在楼梯 ////// +maps.prototype.stairExists = function (x, y, floorId) { + var block = this.getBlock(x,y,floorId); + if (block==null) return false; + return block.block.event.cls=='terrains' && (block.block.event.id=='upFloor' || block.block.event.id=='downFloor'); +} + +////// 当前位置是否在楼梯边 ////// +maps.prototype.nearStair = function() { + var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'); + return this.stairExists(x,y) || this.stairExists(x-1,y) || this.stairExists(x,y-1) || this.stairExists(x+1,y) || this.stairExists(x,y+1); +} + +////// 某个点是否存在(指定的)怪物 ////// +maps.prototype.enemyExists = function (x, y, id,floorId) { + var block = this.getBlock(x,y,floorId); + if (block==null) return false; + return block.block.event.cls.indexOf('enemy')==0 && (core.isset(id)?block.block.event.id==id:true); +} + +////// 获得某个点的block ////// +maps.prototype.getBlock = function (x, y, floorId, needEnable) { + if (!core.isset(floorId)) floorId=core.status.floorId; + if (!core.isset(needEnable)) needEnable=true; + var blocks = core.status.maps[floorId].blocks; + for (var n=0;n= core.values.animateSpeed) { + animateCurrent++; + animateTime = 0; + if (animateCurrent>=animateValue) animateCurrent=0; + } + + // 已经移动完毕,消失 + if (moveSteps.length==0) { + if (immediateHide) opacityVal=0; + else opacityVal -= 0.06; + core.setOpacity('animate', opacityVal); + core.clearMap('animate', nowX, nowY-height+32, 32, height); + core.canvas.animate.drawImage(blockImage, animateCurrent * 32, blockIcon * height, 32, height, nowX, nowY-height+32, 32, height); + if (opacityVal<=0) { + clearInterval(animate); + core.clearMap('animate', 0, 0, 416, 416); + core.setOpacity('animate', 1); + core.status.replay.animate=false; + if (core.isset(callback)) callback(); + } + } + else { + // 移动中 + step++; + nowX+=scan[moveSteps[0]].x*2; + nowY+=scan[moveSteps[0]].y*2; + core.clearMap('animate', nowX-32, nowY-32, 96, 96); + // 绘制 + core.canvas.animate.drawImage(blockImage, animateCurrent * 32, blockIcon * height, 32, height, nowX, nowY-height+32, 32, height); + if (step==16) { + // 该移动完毕,继续 + step=0; + moveSteps.shift(); + } + } + }, time / 16 / core.status.replay.speed); +} + +////// 显示/隐藏某个块时的动画效果 ////// +maps.prototype.animateBlock = function (loc,type,time,callback) { + if (type!='hide') type='show'; + + core.clearMap('animate', 0, 0, 416, 416); + + if (typeof loc[0] == 'number' && typeof loc[1] == 'number') + loc = [loc]; + + var list = []; + loc.forEach(function (t) { + var block = core.getBlock(t[0],t[1],core.status.floorId,false); + if (block==null) return; + block=block.block; + list.push({ + 'x': t[0], 'y': t[1], 'height': block.event.height||32, + 'blockIcon': core.material.icons[block.event.cls][block.event.id], + 'blockImage': core.material.images[block.event.cls] + }) + }) + + if (list.length==0) { + if (core.isset(callback)) callback(); + return; + } + + core.status.replay.animate=true; + var draw = function () { + list.forEach(function (t) { + core.canvas.animate.drawImage(t.blockImage, 0, t.blockIcon*t.height, 32, t.height, t.x*32, t.y*32+32-t.height, 32, t.height); + }) + } + + var opacityVal = 0; + if (type=='hide') opacityVal=1; + + core.setOpacity('animate', opacityVal); + draw(); + + var animate = window.setInterval(function () { + if (type=='show') opacityVal += 0.1; + else opacityVal -= 0.1; + core.setOpacity('animate', opacityVal); + core.clearMap('animate',0,0,416,416); + + draw(); + if (opacityVal >=1 || opacityVal<=0) { + clearInterval(animate); + core.clearMap('animate', 0, 0, 416, 416); + core.setOpacity('animate', 1); + core.status.replay.animate=false; + if (core.isset(callback)) callback(); + } + }, time / 10 / core.status.replay.speed); +} + +////// 将某个块从禁用变成启用状态 ////// +maps.prototype.showBlock = function(x, y, floodId) { + floodId = floodId || core.status.floorId; + var block = core.getBlock(x,y,floodId,false); + if (block==null) return; // 不存在 + block=block.block; + // 本身是禁用事件,启用之 + if (core.isset(block.enable) && !block.enable) { + block.enable = true; + // 在本层,添加动画 + if (floodId == core.status.floorId && core.isset(block.event)) { + core.drawBlock(block); + core.addGlobalAnimate(block); + core.syncGlobalAnimate(); + } + core.updateStatusBar(); + } +} + +////// 将某个块从启用变成禁用状态 ////// +maps.prototype.removeBlock = function (x, y, floorId) { + floorId = floorId || core.status.floorId; + + var block = core.getBlock(x,y,floorId,false); + if (block==null) return; // 不存在 + + var index=block.index; + + // 删除动画,清除地图 + if (floorId==core.status.floorId) { + core.removeGlobalAnimate(x, y); + core.canvas.event.clearRect(x * 32, y * 32, 32, 32); + var height = 32; + if (core.isset(block.block.event)) height=block.block.event.height||32; + if (height>32) + core.canvas.event2.clearRect(x * 32, y * 32 +32-height, 32, height-32); + } + + // 删除Index + core.removeBlockById(index, floorId); + core.updateFg(); +} + +////// 根据block的索引删除该块 ////// +maps.prototype.removeBlockById = function (index, floorId) { + + var blocks = core.status.maps[floorId].blocks, block = blocks[index]; + var x=block.x, y=block.y; + + // 检查该点是否存在事件 + var event = core.floors[floorId].events[x+","+y]; + if (!core.isset(event)) + event = core.floors[floorId].changeFloor[x+","+y]; + + // 检查是否存在重生 + var isReborn = false; + if (core.isset(block.event) && block.event.cls.indexOf('enemy')==0 + && core.enemys.hasSpecial(core.material.enemys[block.event.id].special, 23)) + isReborn = true; + + // 不存在事件,直接删除 + if (!isReborn && !core.isset(event)) { + blocks.splice(index,1); + return; + } + block.enable = false; +} + +////// 一次性删除多个block ////// +maps.prototype.removeBlockByIds = function (floorId, ids) { + ids.sort(function (a,b) {return b-a}).forEach(function (id) { + core.removeBlockById(id, floorId); + }); +} + +////// 添加一个全局动画 ////// +maps.prototype.addGlobalAnimate = function (b) { + if (main.mode=='editor' && main.editor.disableGlobalAnimate) return; + if (!core.isset(b.event) || !core.isset(b.event.animate) || b.event.animate==1) return; + + var block = core.clone(b); + block.status = 0; + + core.status.globalAnimateObjs.push(block); + +} + +////// 删除一个或所有全局动画 ////// +maps.prototype.removeGlobalAnimate = function (x, y, all) { + if (main.mode=='editor' && main.editor.disableGlobalAnimate) return; + + if (all) { + core.status.globalAnimateObjs = []; + return; + } + + for (var t = 0; t < core.status.globalAnimateObjs.length; t++) { + if (core.status.globalAnimateObjs[t].x == x && core.status.globalAnimateObjs[t].y == y) { + core.status.globalAnimateObjs.splice(t, 1); + return; + } + } +} + +////// 设置全局动画的显示效果 ////// +maps.prototype.setGlobalAnimate = function (speed) { + if (main.mode=='editor' && main.editor.disableGlobalAnimate) return; + core.syncGlobalAnimate(); + core.animateFrame.speed = speed; + core.animateFrame.globalAnimate = true; +} + +////// 同步所有的全局动画效果 ////// +maps.prototype.syncGlobalAnimate = function () { + core.status.globalAnimateObjs.forEach(function (t) { + t.status=0; + }) +} + +////// 绘制UI层的box动画 ////// +maps.prototype.drawBoxAnimate = function () { + for (var a = 0; a < core.status.boxAnimateObjs.length; a++) { + var obj = core.status.boxAnimateObjs[a]; + obj.status = ((obj.status||0)+1)%obj.animate; + core.clearMap('ui', obj.bgx, obj.bgy, obj.bgWidth, obj.bgHeight); + core.fillRect('ui', obj.bgx, obj.bgy, obj.bgWidth, obj.bgHeight, core.animateFrame.background); + core.canvas.ui.drawImage(obj.image, obj.status * 32, obj.pos, + 32, obj.height, obj.x, obj.y, 32, obj.height); + } +} + +////// 绘制动画 ////// +maps.prototype.drawAnimate = function (name, x, y, callback) { + + // 正在播放录像:不显示动画 + if (core.isset(core.status.replay) && core.status.replay.replaying) { + if (core.isset(callback)) callback(); + return; + } + + // 检测动画是否存在 + if (!core.isset(core.material.animates[name]) || !core.isset(x) || !core.isset(y)) { + if (core.isset(callback)) callback(); + return; + } + + // 清空animate层 + clearInterval(core.interval.animateInterval); + core.clearMap('animate', 0, 0, 416, 416); + + // 开始绘制 + var animate = core.material.animates[name]; + var ratio = animate.ratio; + var centerX = 32*x+16, centerY = 32*y+16; + var index=0; + + var draw = function (index) { + core.clearMap('animate', 0, 0, 416, 416); + + var frame = animate.frames[index]; + frame.forEach(function (t) { + var image = animate.images[t.index]; + if (!core.isset(image)) return; + var realWidth = image.width * ratio * t.zoom / 100; + var realHeight = image.height * ratio * t.zoom / 100; + core.setAlpha('animate', t.opacity / 255); + + var cx = centerX+t.x, cy=centerY+t.y; + + if (!t.mirror && !t.angle) { + core.canvas.animate.drawImage(image, cx-realWidth/2, cy-realHeight/2, realWidth, realHeight); + } + else { + core.saveCanvas('animate'); + core.canvas.animate.translate(cx,cy); + if (t.angle) + core.canvas.animate.rotate(-t.angle*Math.PI/180); + if (t.mirror) + core.canvas.animate.scale(-1,1); + core.canvas.animate.drawImage(image, -realWidth/2, -realHeight/2, realWidth, realHeight); + core.loadCanvas('animate'); + } + }) + } + + draw(index++); + + core.interval.animateInterval = setInterval(function (t) { + if (index == animate.frames.length) { + clearInterval(core.interval.animateInterval); + core.clearMap('animate', 0, 0, 416, 416); + core.setAlpha('animate', 1); + if (core.isset(callback)) callback(); + return; + } + draw(index++); + }, 50); +} \ No newline at end of file diff --git a/libs/ui.js b/libs/ui.js index afb9e107..8a75c0f3 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -3,14 +3,146 @@ * 包括: * 自动寻路、怪物手册、楼传器、存读档、菜单栏、NPC对话事件、等等 */ -function ui() {} +function ui() { + this.init(); +} // 初始化UI ui.prototype.init = function () { + this.uidata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.ui; } -main.instance.ui = new ui(); +////////////////// 地图设置 +////// 清除地图 ////// +ui.prototype.clearMap = function (map, x, y, width, height) { + if (map == 'all') { + for (var m in core.canvas) { + core.canvas[m].clearRect(0, 0, 416, 416); + } + } + else { + core.canvas[map].clearRect(x||0, y||0, width||416, height||416); + } +} + +////// 在某个canvas上绘制一段文字 ////// +ui.prototype.fillText = function (map, text, x, y, style, font) { + if (core.isset(style)) { + core.setFillStyle(map, style); + } + if (core.isset(font)) { + core.setFont(map, font); + } + core.canvas[map].fillText(text, x, y); +} + +////// 在某个canvas上绘制一个矩形 ////// +ui.prototype.fillRect = function (map, x, y, width, height, style) { + if (core.isset(style)) { + core.setFillStyle(map, style); + } + core.canvas[map].fillRect(x, y, width, height); +} + +////// 在某个canvas上绘制一个矩形的边框 ////// +ui.prototype.strokeRect = function (map, x, y, width, height, style, lineWidth) { + if (core.isset(style)) { + core.setStrokeStyle(map, style); + } + if (core.isset(lineWidth)) { + core.setLineWidth(map, lineWidth); + } + core.canvas[map].strokeRect(x, y, width, height); +} + +////// 在某个canvas上绘制一条线 ////// +ui.prototype.drawLine = function (map, x1, y1, x2, y2, style, lineWidth) { + if (core.isset(style)) { + core.setStrokeStyle(map, style); + } + if (core.isset(lineWidth)) { + core.setLineWidth(map, lineWidth); + } + core.canvas[map].beginPath(); + core.canvas[map].moveTo(x1, y1); + core.canvas[map].lineTo(x2, y2); + core.canvas[map].closePath(); + core.canvas[map].stroke(); +} + +////// 设置某个canvas的文字字体 ////// +ui.prototype.setFont = function (map, font) { + core.canvas[map].font = font; +} + +////// 设置某个canvas的线宽度 ////// +ui.prototype.setLineWidth = function (map, lineWidth) { + if (map == 'all') { + for (var m in core.canvas) { + core.canvas[m].lineWidth = lineWidth; + } + } + core.canvas[map].lineWidth = lineWidth; +} + +////// 保存某个canvas状态 ////// +ui.prototype.saveCanvas = function (map) { + core.canvas[map].save(); +} + +////// 加载某个canvas状态 ////// +ui.prototype.loadCanvas = function (map) { + core.canvas[map].restore(); +} + +////// 设置某个canvas边框属性 ////// +ui.prototype.setStrokeStyle = function (map, style) { + if (map == 'all') { + for (var m in core.canvas) { + core.canvas[m].strokeStyle = style; + } + } + else { + core.canvas[map].strokeStyle = style; + } +} + +////// 设置某个canvas的alpha值 ////// +ui.prototype.setAlpha = function (map, alpha) { + if (map == 'all') { + for (var m in core.canvas) { + core.canvas[m].globalAlpha = alpha; + } + } + else core.canvas[map].globalAlpha = alpha; +} + +////// 设置某个canvas的透明度 ////// +ui.prototype.setOpacity = function (map, opacity) { + if (map == 'all') { + for (var m in core.canvas) { + core.canvas[m].canvas.style.opacity = opacity; + } + } + else core.canvas[map].canvas.style.opacity = opacity; +} + +////// 设置某个canvas的绘制属性(如颜色等) ////// +ui.prototype.setFillStyle = function (map, style) { + if (map == 'all') { + for (var m in core.canvas) { + core.canvas[m].fillStyle = style; + } + } + else { + core.canvas[map].fillStyle = style; + } +} + + + +///////////////// UI绘制 ////// 结束一切事件和绘制,关闭UI窗口,返回游戏进程 ////// ui.prototype.closePanel = function () { @@ -26,13 +158,115 @@ ui.prototype.closePanel = function () { core.status.event.interval = null; } +////// 左上角绘制一段提示 ////// +ui.prototype.drawTip = function (text, itemIcon) { + var textX, textY, width, height, hide = false, opacityVal = 0; + clearInterval(core.interval.tipAnimate); + core.setFont('data', "16px Arial"); + core.setOpacity('data', 0); + core.canvas.data.textAlign = 'left'; + if (!core.isset(itemIcon)) { + textX = 16; + textY = 18; + width = textX + core.canvas.data.measureText(text).width + 16; + height = 42; + } + else { + textX = 44; + textY = 18; + width = textX + core.canvas.data.measureText(text).width + 8; + height = 42; + } + core.interval.tipAnimate = window.setInterval(function () { + if (hide) { + opacityVal -= 0.1; + } + else { + opacityVal += 0.1; + } + core.setOpacity('data', opacityVal); + core.clearMap('data', 5, 5, 400, height); + core.fillRect('data', 5, 5, width, height, '#000'); + if (core.isset(itemIcon)) { + core.canvas.data.drawImage(core.material.images.items, 0, itemIcon * 32, 32, 32, 10, 8, 32, 32); + } + core.fillText('data', text, textX + 5, textY + 15, '#fff'); + if (opacityVal > 0.6 || opacityVal < 0) { + if (hide) { + core.clearMap('data', 5, 5, 400, height); + core.setOpacity('data', 1); + clearInterval(core.interval.tipAnimate); + return; + } + else { + if (!core.isset(core.timeout.getItemTipTimeout)) { + core.timeout.getItemTipTimeout = window.setTimeout(function () { + hide = true; + core.timeout.getItemTipTimeout = null; + }, 750); + } + opacityVal = 0.6; + core.setOpacity('data', opacityVal); + } + } + }, 30); +} + +////// 地图中间绘制一段文字 ////// +ui.prototype.drawText = function (contents, callback) { + if (core.isset(contents)) { + + // 合并 + if ((core.isset(core.status.event)&&core.status.event.id=='action') || (core.isset(core.status.replay)&&core.status.replay.replaying)) { + core.insertAction(contents,null,null,callback); + return; + } + + if (typeof contents == 'string') { + contents = [{'content': contents}]; + } + else if (contents instanceof Object && core.isset(contents.content)) { + contents = [contents]; + } + else if (!(contents instanceof Array)) { + core.drawTip("出错了"); + console.log(contents); + return; + } + + core.status.event = {'id': 'text', 'data': {'list': contents, 'callback': callback}}; + core.lockControl(); + + // wait the hero to stop + core.stopAutomaticRoute(); + setTimeout(function() { + core.drawText(); + }, 30); + return; + } + + if (core.status.event.data.list.length==0) { + var callback = core.status.event.data.callback; + core.ui.closePanel(false); + if (core.isset(callback)) callback(); + return; + } + + var data=core.status.event.data.list.shift(); + if (typeof data == 'string') + core.ui.drawTextBox(data); + else + core.ui.drawTextBox(data.content, data.id); + // core.drawTextBox(content); +} + ////// 绘制一个对话框 ////// ui.prototype.drawTextBox = function(content) { clearInterval(core.status.event.interval); // 获得name, image, icon - var id=null, name=null, image=null, icon=null; + var id=null, name=null, image=null, icon=null, iconHeight=32, animate=null; if (content.indexOf("\t[")==0 || content.indexOf("\\t[")==0) { var index = content.indexOf("]"); if (index>=0) { @@ -45,11 +279,21 @@ ui.prototype.drawTextBox = function(content) { id=ss[0]; // monster if (id!='hero') { - var enemys = core.material.enemys[id]; - if (core.isset(enemys)) { + if (core.isset(core.material.enemys[id])) { name = core.material.enemys[id].name; - image = core.material.images.enemys; - icon = core.material.icons.enemys[id]; + + if (core.isset(core.material.icons.enemy48[id])) { + image = core.material.images.enemy48; + icon = core.material.icons.enemy48[id]; + iconHeight = 48; + animate=4; + } + else { + image = core.material.images.enemys; + icon = core.material.icons.enemys[id]; + iconHeight = 32; + animate=2; + } } else { name=id; @@ -62,8 +306,18 @@ ui.prototype.drawTextBox = function(content) { else { id='npc'; name=ss[0]; - image=core.material.images.npcs; - icon=core.material.icons.npcs[ss[1]]; + if (core.isset(core.material.icons.npc48[ss[1]])) { + image = core.material.images.npc48; + icon = core.material.icons.npc48[ss[1]]; + iconHeight = 48; + animate=4; + } + else { + image = core.material.images.npcs; + icon = core.material.icons.npcs[ss[1]]; + iconHeight = 32; + animate=2; + } } } } @@ -72,7 +326,7 @@ ui.prototype.drawTextBox = function(content) { var textAttribute = core.status.textAttribute || core.initStatus.textAttribute; - var position = textAttribute.position, px=null, py=null, ydelta=0; + var position = textAttribute.position, px=null, py=null, ydelta=iconHeight-32; if (content.indexOf("\b[")==0 || content.indexOf("\\b[")==0) { var index = content.indexOf("]"); if (index>=0) { @@ -121,7 +375,7 @@ ui.prototype.drawTextBox = function(content) { if (textAttribute.bold) font = "bold "+font; var contents = core.splitLines("ui", content, validWidth, font); - var height = 20 + 21*(contents.length+1) + (id=='hero'?core.material.icons.hero.height-10:core.isset(name)?32-10:0); + var height = 20 + 21*(contents.length+1) + (id=='hero'?core.material.icons.hero.height-10:core.isset(name)?iconHeight-10:0); var xoffset = 6, yoffset = 22; @@ -157,7 +411,7 @@ ui.prototype.drawTextBox = function(content) { core.fillRect('ui', left, top, right, height); core.strokeRect('ui', left - 1, top - 1, right + 1, height + 1, '#FFFFFF', 2); - var xoffset = 6; + var xoffset = 9; // draw triangle if (position=='up' && core.isset(px) && core.isset(py)) { @@ -213,12 +467,16 @@ ui.prototype.drawTextBox = function(content) { else { core.fillText('ui', name, content_left, top + 30, null, 'bold 22px Verdana'); if (core.isset(icon)) { - core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, 34, null, 2); + + core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, iconHeight + 2, null, 2); core.status.boxAnimateObjs = []; core.status.boxAnimateObjs.push({ - 'bgx': left + 15, 'bgy': top + 40, 'bgsize': 32, - 'image': image, 'x': left + 15, 'y': top + 40, 'icon': icon + 'bgx': left + 15, 'bgy': top + 40, 'bgWidth': 32, 'bgHeight': iconHeight, + 'x': left+15, 'y': top+40, 'height': iconHeight, 'animate': animate, + 'image': image, + 'pos': icon*iconHeight }); + core.drawBoxAnimate(); } } @@ -276,7 +534,7 @@ ui.prototype.drawChoices = function(content, choices) { if (length%2==0) bottom+=16; var choice_top = bottom-height+56; - var id=null, name=null, image=null, icon=null; + var id=null, name=null, image=null, icon=null, iconHeight=32, animate=null; var contents = null; var content_left = left + 15; @@ -294,11 +552,21 @@ ui.prototype.drawChoices = function(content, choices) { id=ss[0]; // monster if (id!='hero') { - var enemys = core.material.enemys[id]; - if (core.isset(enemys)) { + if (core.isset(core.material.enemys[id])) { name = core.material.enemys[id].name; - image = core.material.images.enemys; - icon = core.material.icons.enemys[id]; + + if (core.isset(core.material.icons.enemy48[id])) { + image = core.material.images.enemy48; + icon = core.material.icons.enemy48[id]; + iconHeight = 48; + animate=4; + } + else { + image = core.material.images.enemys; + icon = core.material.icons.enemys[id]; + iconHeight = 32; + animate=2; + } } else { name=id; @@ -311,8 +579,18 @@ ui.prototype.drawChoices = function(content, choices) { else { id='npc'; name=ss[0]; - image=core.material.images.npcs; - icon=core.material.icons.npcs[ss[1]]; + if (core.isset(core.material.icons.npc48[ss[1]])) { + image = core.material.images.npc48; + icon = core.material.icons.npc48[ss[1]]; + iconHeight = 48; + animate=4; + } + else { + image = core.material.images.npcs; + icon = core.material.icons.npcs[ss[1]]; + iconHeight = 32; + animate=2; + } } } } @@ -361,11 +639,13 @@ ui.prototype.drawChoices = function(content, choices) { else { core.fillText('ui', name, title_offset, top + 27, '#FFD700', 'bold 19px Verdana'); if (core.isset(icon)) { - core.strokeRect('ui', left + 15 - 1, top + 30 - 1, 34, 34, '#DDDDDD', 2); + core.strokeRect('ui', left + 15 - 1, top + 30 - 1, 34, iconHeight + 2, '#DDDDDD', 2); core.status.boxAnimateObjs = []; core.status.boxAnimateObjs.push({ - 'bgx': left + 15, 'bgy': top + 30, 'bgsize': 32, - 'image': image, 'x': left + 15, 'y': top + 30, 'icon': icon + 'bgx': left + 15, 'bgy': top + 30, 'bgWidth': 32, 'bgHeight': iconHeight, + 'x': left+15, 'y': top+30, 'height': iconHeight, 'animate': animate, + 'image': image, + 'pos': icon*iconHeight }); core.drawBoxAnimate(); } @@ -575,19 +855,28 @@ ui.prototype.drawBattleAnimate = function(monsterId, callback) { var margin = 35; var boxWidth = 40; + var monsterHeight = 32, animate=2; + + var image = core.material.images.enemys, icon = core.material.icons.enemys; + if (core.isset(core.material.icons.enemy48[monsterId])) { + image = core.material.images.enemy48; + icon = core.material.icons.enemy48; + monsterHeight = 48; + animate=4; + } // 方块 var heroHeight = core.material.icons.hero.height; core.strokeRect('ui', left + margin - 1, top + margin - 1, boxWidth+2, heroHeight+boxWidth-32+2, '#FFD700', 2); - core.strokeRect('ui', left + right - margin - boxWidth - 1 , top+margin-1, boxWidth+2, boxWidth+2); + core.strokeRect('ui', left + right - margin - boxWidth - 1 , top+margin-1, boxWidth+2, monsterHeight+boxWidth-32+2); // 名称 core.canvas.ui.textAlign='center'; core.fillText('ui', core.status.hero.name, left+margin+boxWidth/2, top+margin+heroHeight+40, '#FFD700', 'bold 22px Verdana'); - core.fillText('ui', "怪物", left+right-margin-boxWidth/2, top+margin+32+40); + core.fillText('ui', "怪物", left+right-margin-boxWidth/2, top+margin+monsterHeight+40); for (var i=0, j=0; i0) @@ -832,6 +1121,14 @@ ui.prototype.drawLocalSaveSelect = function () { ]); } +////// 绘制存档删除页面 ////// +ui.prototype.drawStorageRemove = function () { + core.status.event.id = 'storageRemove'; + this.drawChoices(null, [ + "清空全部塔的存档", "只清空当前塔的存档", "返回上级菜单" + ]); +} + ////// 绘制分页 ////// ui.prototype.drawPagination = function (page, totalPage) { @@ -924,11 +1221,18 @@ ui.prototype.drawBook = function (index) { var enemy = enemys[i]; core.strokeRect('ui', 22, 62 * i + 22, 42, 42, '#DDDDDD', 2); + var cls = 'enemys'; + if (core.isset(core.material.icons.enemy48[enemy.id])) + cls = 'enemy48'; + var height = cls=='enemy48'?48:32; + var animate = cls=='enemy48'?4:2; + // 怪物 core.status.boxAnimateObjs.push({ - 'bgx': 22, 'bgy': 62 * i + 22, 'bgsize': 42, - 'image': core.material.images.enemys, - 'x': 27, 'y': 62 * i + 27, 'icon': core.material.icons.enemys[enemy.id] + 'bgx': 22, 'bgy': 62 * i + 22, 'bgWidth': 42, 'bgHeight': 42, + 'x': 27, 'y': 62 * i + 27, 'height': 32, 'animate': animate, + 'image': core.material.images[cls], + 'pos': core.material.icons[cls][enemy.id] * height }); // 数据 @@ -949,24 +1253,41 @@ ui.prototype.drawBook = function (index) { core.fillText('ui', '防御', 335, 62 * i + 32, '#DDDDDD', '13px Verdana'); core.fillText('ui', enemy.def, 365, 62 * i + 32, '#DDDDDD', 'bold 13px Verdana'); - var expOffset = 165; + var expOffset = 165, line_cnt=0; if (core.flags.enableMoney) { core.fillText('ui', '金币', 165, 62 * i + 50, '#DDDDDD', '13px Verdana'); core.fillText('ui', enemy.money, 195, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); expOffset = 255; + line_cnt++; } - if (core.flags.enableExperience) { + // 加点 + if (core.flags.enableAddPoint) { + core.canvas.ui.textAlign = "left"; + core.fillText('ui', '加点', expOffset, 62 * i + 50, '#DDDDDD', '13px Verdana'); + core.fillText('ui', enemy.point, expOffset + 30, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); + expOffset = 255; + line_cnt++; + } + + if (core.flags.enableExperience && line_cnt<2) { core.canvas.ui.textAlign = "left"; core.fillText('ui', '经验', expOffset, 62 * i + 50, '#DDDDDD', '13px Verdana'); core.fillText('ui', enemy.experience, expOffset + 30, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); + line_cnt++; } + var damageOffset = 281; + if (line_cnt==1) damageOffset=326; + if (line_cnt==2) damageOffset=361; + + /* var damageOffet = 281; if (core.flags.enableMoney && core.flags.enableExperience) damageOffet = 361; else if (core.flags.enableMoney || core.flags.enableExperience) damageOffet = 326; + */ core.canvas.ui.textAlign = "center"; @@ -975,7 +1296,7 @@ ui.prototype.drawBook = function (index) { if (damage >= core.status.hero.hp) color = '#FF0000'; if (damage <= 0) color = '#00FF00'; if (damage >= 999999999) damage = '无法战斗'; - core.fillText('ui', damage, damageOffet, 62 * i + 50, color, 'bold 13px Verdana'); + core.fillText('ui', damage, damageOffset, 62 * i + 50, color, 'bold 13px Verdana'); core.canvas.ui.textAlign = "left"; @@ -1297,35 +1618,24 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, heroL } } - if (core.isset(core.floors[floorId].png)) { - var png = core.floors[floorId].png; - /* - if (core.isset(core.material.images.pngs[png])) { - core.canvas.ui.drawImage(core.material.images.pngs[png], x, y, size, size); + var images = []; + if (core.isset(core.floors[floorId].images)) { + images = core.floors[floorId].images; + if (typeof images == 'string') { + images = [[0, 0, images]]; } - */ - - var ratio = size/416; - - if (typeof png == 'string') { - if (core.isset(core.material.images.pngs[png])) { - core.canvas.ui.drawImage(core.material.images.pngs[png], x, y, size, size); - } - } - else if (png instanceof Array) { - png.forEach(function (t) { - if (t.length!=3) return; - var dx=parseInt(t[0]), dy=parseInt(t[1]), p=t[2]; - if (core.isset(dx) && core.isset(dy) && core.isset(core.material.images.pngs[p])) { - dx*=32; dy*=32; - var image = core.material.images.pngs[p]; - core.canvas.ui.drawImage(image, x+dx*ratio, y+dy*ratio, Math.min(size-dx*ratio, ratio*image.width), Math.min(size-dy*ratio, ratio*image.height)); - } - }) - } - } + images.forEach(function (t) { + var ratio = size/416; + var dx=parseInt(t[0]), dy=parseInt(t[1]), p=t[2]; + if (core.isset(dx) && core.isset(dy) && !t[3] && core.isset(core.material.images.images[p])) { + dx*=32; dy*=32; + var image = core.material.images.images[p]; + core.canvas.ui.drawImage(image, x+dx*ratio, y+dy*ratio, Math.min(size-dx*ratio, ratio*image.width), Math.min(size-dy*ratio, ratio*image.height)); + } + }) + var mapArray = core.maps.getMapArray(blocks); for (var b in blocks) { var block = blocks[b]; @@ -1337,7 +1647,8 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, heroL if (block.event.id!='none') { var blockIcon = core.material.icons[block.event.cls][block.event.id]; var blockImage = core.material.images[block.event.cls]; - core.canvas[canvas].drawImage(blockImage, 0, blockIcon * 32, 32, 32, x + block.x * persize, y + block.y * persize, persize, persize); + var height = block.event.height || 32; + core.canvas[canvas].drawImage(blockImage, 0, blockIcon * height, 32, height, x + block.x * persize, y + block.y * persize + (persize-persize*height/32), persize, persize * height/32); } } } @@ -1349,6 +1660,17 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, heroL var realHeight = persize*height/32; core.canvas[canvas].drawImage(core.material.images.hero, heroIcon.stop * 32, heroIcon.loc * height, 32, height, x+persize*heroLoc.x, y+persize*heroLoc.y+persize-realHeight, persize, realHeight); } + + images.forEach(function (t) { + var ratio = size/416; + var dx=parseInt(t[0]), dy=parseInt(t[1]), p=t[2]; + if (core.isset(dx) && core.isset(dy) && t[3] && core.isset(core.material.images.images[p])) { + dx*=32; dy*=32; + var image = core.material.images.images[p]; + core.canvas.ui.drawImage(image, x+dx*ratio, y+dy*ratio, Math.min(size-dx*ratio, ratio*image.width), Math.min(size-dy*ratio, ratio*image.height)); + } + }) + } ui.prototype.drawKeyBoard = function () { @@ -1390,32 +1712,8 @@ ui.prototype.drawKeyBoard = function () { } ////// 绘制“关于”界面 ////// -ui.prototype.drawAbout = function() { - - if (!core.isPlaying()) { - core.status.event = {'id': null, 'data': null}; - core.dom.startPanel.style.display = 'none'; - } - core.lockControl(); - core.status.event.id = 'about'; - - core.clearMap('ui', 0, 0, 416, 416); - var left = 48, top = 36, right = 416 - 2 * left, bottom = 416 - 2 * top; - - core.setAlpha('ui', 0.85); - core.fillRect('ui', left, top, right, bottom, '#000000'); - core.setAlpha('ui', 1); - core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, '#FFFFFF', 2); - - var text_start = left + 24; - - // 名称 - core.canvas.ui.textAlign = "left"; - core.fillText('ui', "HTML5 魔塔样板", text_start, top+35, "#FFD700", "bold 22px Verdana"); - core.fillText('ui', "版本: "+core.firstData.version, text_start, top + 80, "#FFFFFF", "bold 17px Verdana"); - core.fillText('ui', "作者: 艾之葵", text_start, top + 112); - core.fillText('ui', 'HTML5魔塔交流群:539113091', text_start, top+112+32); - // TODO: 写自己的“关于”页面,每次增加32像素即可 +ui.prototype.drawAbout = function () { + return this.uidata.drawAbout(); } ////// 绘制帮助页面 ////// @@ -1445,4 +1743,5 @@ ui.prototype.drawHelp = function () { "双击勇士: 轻按(仅在轻按开关打开时有效)\n"+ "长按任意位置:跳过剧情对话或打开虚拟键盘\n" ]); -} \ No newline at end of file +} + diff --git a/libs/utils.js b/libs/utils.js new file mode 100644 index 00000000..29adb15a --- /dev/null +++ b/libs/utils.js @@ -0,0 +1,468 @@ +/* +utils.js 工具类 + + */ + +function utils() { + +} + +utils.prototype.init = function () { + +} + +////// 将文字中的${和}(表达式)进行替换 ////// +utils.prototype.replaceText = function (text) { + return text.replace(/\${([^}]+)}/g, function (word, value) { + return core.calValue(value); + }); +} + +////// 计算表达式的值 ////// +utils.prototype.calValue = function (value) { + value=value.replace(/status:([\w\d_]+)/g, "core.getStatus('$1')"); + value=value.replace(/item:([\w\d_]+)/g, "core.itemCount('$1')"); + value=value.replace(/flag:([\w\d_]+)/g, "core.getFlag('$1', false)"); + return eval(value); +} + +////// 字符串自动换行的分割 ////// +utils.prototype.splitLines = function(canvas, text, maxLength, font) { + if (core.isset(font)) core.setFont(canvas, font); + + var contents = []; + var last = 0; + for (var i=0;imaxLength) { + contents.push(text.substring(last, i)); + last=i; + } + } + } + contents.push(text.substring(last)); + return contents; +} + +////// 向某个数组前插入另一个数组或元素 ////// +utils.prototype.unshift = function (a,b) { + if (!(a instanceof Array) || !core.isset(b)) return; + if (b instanceof Array) { + core.clone(b).reverse().forEach(function (e) { + a.unshift(e); + }); + } + else a.unshift(b); + return a; +} + +////// 设置本地存储 ////// +utils.prototype.setLocalStorage = function(key, value) { + try { + localStorage.setItem(core.firstData.name + "_" + key, JSON.stringify(value)); + return true; + } + catch (e) { + console.log(e); + return false; + } +} + +////// 获得本地存储 ////// +utils.prototype.getLocalStorage = function(key, defaultValue) { + var value = localStorage.getItem(core.firstData.name+"_"+key); + if (core.isset(value)) return JSON.parse(value); + return defaultValue; +} + +////// 移除本地存储 ////// +utils.prototype.removeLocalStorage = function (key) { + localStorage.removeItem(core.firstData.name+"_"+key); +} + +////// 深拷贝一个对象 ////// +utils.prototype.clone = function (data) { + if (!core.isset(data)) return data; + // 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=0;i255) nowR=255; if (nowB>255) nowB=255; if (nowG>255) nowG=255; + return "#"+((1<<24)+(nowR<<16)+(nowG<<8)+nowB).toString(16).slice(1); +} + +////// 加密路线 ////// +utils.prototype.encodeRoute = function (route) { + var ans=""; + var 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; + } + if (t.indexOf('item:')==0) + ans+="I"+t.substring(5)+":"; + else if (t.indexOf('fly:')==0) + ans+="F"+t.substring(4)+":"; + else if (t.indexOf('choices:')==0) + ans+="C"+t.substring(8); + else if (t.indexOf('shop:')==0) + ans+="S"+t.substring(5); + else if (t=='turn') + ans+='T'; + else if (t=='getNext') + ans+='G'; + else if (t.indexOf('input:')==0) + ans+="P"+t.substring(6); + else if (t=='no') + ans+='N'; + else if (t.indexOf('move:')==0) + ans+="M"+t.substring(5); + else if (t=='key:') + ans+='K'+t.substring(4); + } + }); + if (cnt>0) { + ans+=lastMove.substring(0,1).toUpperCase(); + if (cnt>1) ans+=cnt; + } + return ans; +} + +////// 解密路线 ////// +utils.prototype.decodeRoute = function (route) { + + if (!core.isset(route)) return route; + + var ans=[], index=0; + + var getNumber = function (noparse) { + var num=""; + while (index 1) { + clearInterval(showAnimate); + if (core.isset(callback)) { + callback(); + } + } + }, speed); +} + +////// 动画使某对象消失 ////// +utils.prototype.hide = function (obj, speed, callback) { + if (!core.isset(speed)) { + obj.style.display = 'none'; + return; + } + if (main.mode!='play'){ + obj.style.display = 'none'; + if (core.isset(callback)) {callback();} + return; + } + 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 (core.isset(callback)) { + callback(); + } + } + }, speed); +} + +utils.prototype.http = function (type, url, formData, success, error, mimeType) { + var xhr = new XMLHttpRequest(); + xhr.open(type, url, true); + if (core.isset(mimeType)) + xhr.overrideMimeType(mimeType); + xhr.onload = function(e) { + if (xhr.status==200) { + if (core.isset(success)) { + success(xhr.response); + } + } + else { + if (core.isset(error)) + error("HTTP "+xhr.status); + } + }; + xhr.onabort = function () { + if (core.isset(error)) + error("Abort"); + } + xhr.ontimeout = function() { + if (core.isset(error)) + error("Timeout"); + } + xhr.onerror = function() { + if (core.isset(error)) + error("Error on Connection"); + } + if (core.isset(formData)) + xhr.send(formData); + else xhr.send(); +} diff --git a/main.js b/main.js index d0879e40..7da8aa9a 100644 --- a/main.js +++ b/main.js @@ -9,29 +9,6 @@ function main() { // 请注意,只有useCompress是false时才会读取floors目录下的文件,为true时会直接读取libs目录下的floors.min.js文件。 // 如果要进行剧本的修改请务必将其改成false。 - this.floorIds = [ // 在这里按顺序放所有的楼层;其顺序直接影响到楼层传送器的顺序和上楼器/下楼器的顺序 - "sample0", "sample1", "sample2" - ]; - this.pngs = [ // 在此存放所有可能使用的图片,只能是png格式,可以不写后缀名 - // 图片可以被作为背景图(的一部分),也可以直接用自定义事件进行显示。 - // 图片名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 - // 建议对于较大的图片,在网上使用在线的“图片压缩工具(http://compresspng.com/zh/)”来进行压缩,以节省流量 - "bg", // 依次向后添加 - ]; - this.animates = [ // 在此存放所有可能使用的动画,必须是animate格式,在这里不写后缀名 - // 动画必须放在animates目录下;文件名不能使用中文,不能带空格或特殊字符 - "hand", "sword", "zone", "yongchang", // "jianji", "thunder" // 根据需求自行添加 - ]; - this.bgms = [ // 在此存放所有的bgm,和文件名一致。第一项为默认播放项 - // 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 - 'bgm.mp3', 'qianjin.mid', 'star.mid', - ]; - this.sounds = [ // 在此存放所有的SE,和文件名一致 - // 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 - 'floor.mp3', 'attack.ogg', 'door.ogg', 'item.ogg', 'zone.ogg' - ]; - this.bgmRemote = false; // 是否使用远程的背景音乐;此项一般不要开启 - //------------------------ 用户修改内容 END ------------------------// this.dom = { @@ -45,6 +22,7 @@ function main() { 'startTopProgress': document.getElementById('startTopProgress'), 'startTopLoadTips': document.getElementById('startTopLoadTips'), 'startBackground': document.getElementById('startBackground'), + 'startLogo': document.getElementById('startLogo'), 'startButtonGroup': document.getElementById('startButtonGroup'), 'floorMsgGroup': document.getElementById('floorMsgGroup'), 'logoLabel': document.getElementById('logoLabel'), @@ -61,13 +39,11 @@ function main() { 'loadGame': document.getElementById('loadGame'), 'replayGame': document.getElementById('replayGame'), 'levelChooseButtons': document.getElementById('levelChooseButtons'), - 'easyLevel': document.getElementById('easyLevel'), - 'normalLevel': document.getElementById('normalLevel'), - 'hardLevel': document.getElementById('hardLevel'), 'data': document.getElementById('data'), 'statusLabels': document.getElementsByClassName('statusLabel'), 'floorCol': document.getElementById('floorCol'), 'lvCol': document.getElementById('lvCol'), + 'hpmaxCol': document.getElementById('hpmaxCol'), 'mdefCol': document.getElementById('mdefCol'), 'moneyCol': document.getElementById('moneyCol'), 'expCol': document.getElementById('expCol'), @@ -75,17 +51,22 @@ function main() { 'debuffCol': document.getElementById('debuffCol'), 'hard': document.getElementById('hard'), }; + this.mode = 'play'; this.loadList = [ - 'items', 'icons', 'maps', 'enemys', 'events', 'data', 'ui', 'core' + 'loader', 'control', 'utils', 'items', 'icons', 'maps', 'enemys', 'events', 'actions', 'data', 'ui', 'core' ]; - this.images = [ - 'animates', 'enemys', 'hero', 'items', 'npcs', 'terrains' + this.pureData = [ + "data","enemys","icons","maps","items","functions" + ]; + this.materials = [ + 'animates', 'enemys', 'hero', 'items', 'npcs', 'terrains', 'enemy48', 'npc48' ]; this.statusBar = { 'image': { 'floor': document.getElementById('img-floor'), 'lv': document.getElementById('img-lv'), + 'hpmax': document.getElementById('img-hpmax'), 'hp': document.getElementById("img-hp"), 'atk': document.getElementById("img-atk"), 'def': document.getElementById("img-def"), @@ -116,6 +97,7 @@ function main() { }, 'floor': document.getElementById('floor'), 'lv': document.getElementById('lv'), + 'hpmax': document.getElementById('hpmax'), 'hp': document.getElementById('hp'), 'atk': document.getElementById('atk'), 'def': document.getElementById("def"), @@ -132,60 +114,89 @@ function main() { 'hard': document.getElementById("hard") } this.floors = {} - this.instance = {}; this.canvas = {}; } -////// 初始化 ////// -main.prototype.init = function () { +main.prototype.init = function (mode, callback) { for (var i = 0; i < main.dom.gameCanvas.length; i++) { main.canvas[main.dom.gameCanvas[i].id] = main.dom.gameCanvas[i].getContext('2d'); } + if (({"editor":0}).hasOwnProperty(mode)) { + main.mode = mode; + if (mode === 'editor')main.editor = {'disableGlobalAnimate':true}; + } Object.keys(this.statusBar.icons).forEach(function (t) { var image=new Image(); - image.src="images/"+t+".png"; + image.src="project/images/"+t+".png"; main.statusBar.icons[t] = image; }) - main.loaderJs(function () { - var coreData = {}; - for (i = 0; i < main.loadList.length; i++) { - var name = main.loadList[i]; - if (name === 'core') continue; - main[name].init(main.dom); - coreData[name] = main[name]; - } - main.loaderFloors(function() { - ["dom", "statusBar", "canvas", "images", "pngs", + main.loaderJs('project', main.pureData, function(){ + var mainData = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.main; + for(var ii in mainData)main[ii]=mainData[ii]; + + main.dom.startBackground.src="project/images/"+main.startBackground; + main.dom.startLogo.style=main.startLogoStyle; + main.levelChoose.forEach(function(value){ + var span = document.createElement('span'); + span.setAttribute('class','startButton'); + span.innerText=value[0]; + (function(span,str_){ + span.onclick = function () { + core.events.startGame(str_); + } + })(span,value[1]); + main.dom.levelChooseButtons.appendChild(span); + }); + + main.loaderJs('libs', main.loadList, function () { + main.core = core; + + for (i = 0; i < main.loadList.length; i++) { + var name = main.loadList[i]; + if (name === 'core') continue; + main.core[name] = new (eval(name))(); + } + + main.loaderFloors(function() { + var coreData = {}; + ["dom", "statusBar", "canvas", "images", "materials", "animates", "bgms", "sounds", "floorIds", "floors"].forEach(function (t) { coreData[t] = main[t]; - }) - main.core.init(coreData); - main.core.resize(main.dom.body.clientWidth, main.dom.body.clientHeight); - }) + }) + main.core.init(coreData, callback); + main.core.resize(main.dom.body.clientWidth, main.dom.body.clientHeight); + }); + }); }); } ////// 动态加载所有核心JS文件 ////// -main.prototype.loaderJs = function (callback) { +main.prototype.loaderJs = function (dir, loadList, callback) { var instanceNum = 0; // 加载js main.setMainTipsText('正在加载核心js文件...') - for (var i = 0; i < main.loadList.length; i++) { - main.loadMod(main.loadList[i], function (modName) { - instanceNum = 0; + for (var i = 0; i < loadList.length; i++) { + main.loadMod(dir, loadList[i], function (modName) { main.setMainTipsText(modName + '.js 加载完毕'); - for (var key in main.instance) { - instanceNum++; - } - if (instanceNum === main.loadList.length) { - delete main.instance; - // main.dom.mainTips.style.display = 'none'; + instanceNum++; + if (instanceNum === loadList.length) { callback(); } }); } } +////// 加载某一个JS文件 ////// +main.prototype.loadMod = function (dir, modName, callback) { + var script = document.createElement('script'); + var name = modName; + script.src = dir + '/' + modName + (this.useCompress?".min":"") + '.js?v=' + this.version; + main.dom.body.appendChild(script); + script.onload = function () { + callback(name); + } +} + ////// 动态加载所有楼层(剧本) ////// main.prototype.loaderFloors = function (callback) { @@ -193,7 +204,7 @@ main.prototype.loaderFloors = function (callback) { main.setMainTipsText('正在加载楼层文件...') if (this.useCompress) { // 读取压缩文件 var script = document.createElement('script'); - script.src = 'libs/floors.min.js?v=' + this.version; + script.src = 'project/floors.min.js?v=' + this.version; main.dom.body.appendChild(script); script.onload = function () { main.dom.mainTips.style.display = 'none'; @@ -213,22 +224,10 @@ main.prototype.loaderFloors = function (callback) { } } -////// 加载某一个JS文件 ////// -main.prototype.loadMod = function (modName, callback) { - var script = document.createElement('script'); - var name = modName; - script.src = 'libs/' + modName + (this.useCompress?".min":"") + '.js?v=' + this.version; - main.dom.body.appendChild(script); - script.onload = function () { - main[name] = main.instance[name]; - callback(name); - } -} - ////// 加载某一个楼层 ////// main.prototype.loadFloor = function(floorId, callback) { var script = document.createElement('script'); - script.src = 'libs/floors/' + floorId +'.js?v=' + this.version; + script.src = 'project/floors/' + floorId +'.js?v=' + this.version; main.dom.body.appendChild(script); script.onload = function () { callback(floorId); @@ -240,8 +239,8 @@ main.prototype.setMainTipsText = function (text) { main.dom.mainTips.innerHTML = text; } -var main = new main(); -main.init(); + +main.prototype.listen = function () { ////// 窗口大小变化时 ////// window.onresize = function () { @@ -436,8 +435,9 @@ main.dom.replayGame.onclick = function () { return; } if (core.isset(obj.version) && obj.version!=core.firstData.version) { - alert("游戏版本不一致!"); - return; + // alert("游戏版本不一致!"); + if (!confirm("游戏版本不一致!\n你仍然想播放录像吗?")) + return; } if (!core.isset(obj.route) || !core.isset(obj.hard)) { alert("无效的录像!"); @@ -448,25 +448,14 @@ main.dom.replayGame.onclick = function () { core.resetStatus(core.firstData.hero, obj.hard, core.firstData.floorId, null, core.initStatus.maps); core.events.setInitData(obj.hard); core.changeFloor(core.status.floorId, null, core.firstData.hero.loc, null, function() { - //core.setHeroMoveTriggerInterval(); core.startReplay(core.decodeRoute(obj.route)); - }); + }, true); }, function () { }) } -////// 点击“简单难度”时 ////// -main.dom.easyLevel.onclick = function() { - core.events.startGame('Easy'); -} -////// 点击“普通难度”时 ////// -main.dom.normalLevel.onclick = function () { - core.events.startGame('Normal'); -} +}//listen end -////// 点击“困难难度”时 ////// -main.dom.hardLevel.onclick = function () { - core.events.startGame('Hard'); -} +var main = new main(); \ No newline at end of file diff --git a/animates/hand.animate b/project/animates/hand.animate similarity index 100% rename from animates/hand.animate rename to project/animates/hand.animate diff --git a/animates/jianji.animate b/project/animates/jianji.animate similarity index 100% rename from animates/jianji.animate rename to project/animates/jianji.animate diff --git a/animates/sword.animate b/project/animates/sword.animate similarity index 100% rename from animates/sword.animate rename to project/animates/sword.animate diff --git a/animates/thunder.animate b/project/animates/thunder.animate similarity index 100% rename from animates/thunder.animate rename to project/animates/thunder.animate diff --git a/animates/yongchang.animate b/project/animates/yongchang.animate similarity index 100% rename from animates/yongchang.animate rename to project/animates/yongchang.animate diff --git a/animates/zone.animate b/project/animates/zone.animate similarity index 100% rename from animates/zone.animate rename to project/animates/zone.animate diff --git a/project/comment.js b/project/comment.js new file mode 100644 index 00000000..7b10198d --- /dev/null +++ b/project/comment.js @@ -0,0 +1,89 @@ +comment_c456ea59_6018_45ef_8bcc_211a24c627dc = +{ + "items" : { + 'items':{ + 'cls': "只能取keys(钥匙) items(宝石、血瓶) constants(物品) tools(道具)\n$select({\"values\":[\"keys\",\"items\",\"constants\",\"tools\"]})$end", + 'name': '名称', + 'text': '道具在道具栏中显示的描述', + 'isEquipment': '物品是否属于装备(仅在core.flags.equipment时有效)\n$select({\"values\":[true,false]})$end' + }, + 'itemEffect':'cls为items的即捡即用类物品的效果,执行时会对这里的字符串执行eval()', + 'itemEffectTip':'cls为items的即捡即用类物品,在获得时左上角额外显示的文字,执行时会对这里的字符串执行eval()得到字符串' + }, + "items_template" : {'cls': 'items', 'name': '新物品'}, + "enemys" : { + 'name': '名称', + 'hp': '生命值', + 'atk': '攻击力', + 'def': '防御力', + 'money': '金币', + 'experience': '经验', + 'point': '加点', + 'special': '特殊属性\n\n0:无,1:先攻,2:魔攻,3:坚固,4:2连击,\n5:3连击,6:n连击,7:破甲,8:反击,9:净化,\n10:模仿,11:吸血,12:中毒,13:衰弱,14:诅咒,\n15:领域,16:夹击,17:仇恨,18:阻击,19:自爆,\n20:无敌,21:退化,22:固伤,23:重生\n\n多个属性例如用[1,4,11]表示先攻2连击吸血\n模仿怪的攻防设为0就好\n$leaf(true)$end', + 'value': '特殊属性的数值\n领域怪需要加value表示领域伤害的数值\n吸血怪需要在后面添加value代表吸血比例', + 'zoneSquare': '领域怪zoneSquare代表是否九宫格伤害', + 'range': 'range可选,代表领域伤害的范围;不加默认为1\n$range((thiseval==~~thiseval && thiseval>0)||thiseval==null)$end', + 'bomb':' 加入 "bomb": false 代表该怪物不可被炸弹或圣锤炸掉\n$select({\"values\":[true,false]})$end', + 'n': '多连击需要在后面指定n代表是几连击\n$range((thiseval==~~thiseval && thiseval>0)||thiseval==null)$end', + 'add': '代表吸血后是否加到自身\n$select({\"values\":[true,false]})$end', + 'atkValue':'退化时勇士下降的攻击力点数\n$range(thiseval==~~thiseval||thiseval==null)$end', + 'defValue':'退化时勇士下降的防御力点数\n$range(thiseval==~~thiseval||thiseval==null)$end', + 'damage':'战前扣血的点数\n$range(thiseval==~~thiseval||thiseval==null)$end' + }, + "enemys_template" : {'name': '新敌人', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + "floors" : { + 'floor' : { + "floorId": "文件名和floorId需要保持完全一致 \n楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头 \n推荐用法:第20层就用MT20,第38层就用MT38,地下6层就用MT_6(用下划线代替负号),隐藏3层用MT3h(h表示隐藏),等等 \n楼层唯一标识符,需要和名字完全一致 \n这里不能更改floorId,请通过另存为来实现\n$range(false)$end", + "title": "楼层中文名 ", + "name": "显示在状态栏中的层数 ", + "canFlyTo": "该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器) \n$select({\"values\":[true,false]})$end", + "canUseQuickShop": "该层是否允许使用快捷商店 \n$select({\"values\":[true,false]})$end", + "defaultGround": "默认地面的图块ID(terrains中) \n$select({\"values\":Object.keys(editor.core.icons.icons.terrains)})$end", + "images": "背景/前景图;你可以选择一张图片来作为背景/前景素材。详细用法请参见文档“自定义素材”中的说明。 \n$leaf(true)$end", + "color": "该层的默认画面色调。本项可不写(代表无色调),如果写需要是一个RGBA数组。 \n$leaf(true)$end", + "weather": "该层的默认天气。本项可忽略表示晴天,如果写则第一项为\"rain\"或\"snow\"代表雨雪,第二项为1-10之间的数代表强度。 \n$leaf(true)$end", + "bgm": "到达该层后默认播放的BGM。本项可忽略。 ", + //"map": "地图数据,需要是13x13,建议使用地图生成器来生成 ", + "item_ratio": "每一层的宝石/血瓶效果,即获得宝石和血瓶时框内\"ratio\"的值。$range((thiseval==~~thiseval && thiseval>0)||thiseval==null)$end", + "firstArrive": "第一次到该楼层触发的事件 \n$leaf(true)$end", + }, + 'loc' : { + "events": "该楼的所有可能事件列表 \n$leaf(true)$end", + "changeFloor": "楼层转换事件;该事件不能和上面的events有冲突(同位置点),否则会被覆盖 \n$leaf(true)$end", + "afterBattle": "战斗后可能触发的事件列表 \n$leaf(true)$end", + "afterGetItem": "获得道具后可能触发的事件列表 \n$leaf(true)$end", + "afterOpenDoor": "开完门后可能触发的事件列表 \n$leaf(true)$end", + "cannotMove": "每个图块不可通行的方向 \n 可以在这里定义每个点不能前往哪个方向,例如悬崖边不能跳下去 \n'x,y': ['up', 'left'], // (x,y)点不能往上和左走\n$leaf(true)$end", + } + }, + /* + 'floors_template' : { + "floorId": "tempfloor", + "title": "主塔 0 层", + "name": "0", + "canFlyTo": true, + "canUseQuickShop": true, + "defaultGround": "ground", + "map": [ + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ], + "firstArrive": [], + "events": {}, + "changeFloor": {}, + "afterBattle": {}, + "afterGetItem": {}, + "afterOpenDoor": {} + }, */ +} \ No newline at end of file diff --git a/project/data.comment.js b/project/data.comment.js new file mode 100644 index 00000000..3526688c --- /dev/null +++ b/project/data.comment.js @@ -0,0 +1,179 @@ +data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = +{ + "main": { + "floorIds": " 在这里按顺序放所有的楼层;其顺序直接影响到楼层传送器的顺序和上楼器/下楼器的顺序 \n$leaf(true)$end", + "images": " 在此存放所有可能使用的图片 \n 图片可以被作为背景图(的一部分),也可以直接用自定义事件进行显示。 \n 图片名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 \n 建议对于较大的图片,在网上使用在线的“图片压缩工具(http://compresspng.com/zh/)”来进行压缩,以节省流量 \n 依次向后添加 \n$leaf(true)$end", + "animates": " 在此存放所有可能使用的动画,必须是animate格式,在这里不写后缀名 \n 动画必须放在animates目录下;文件名不能使用中文,不能带空格或特殊字符 \n \"jianji\", \"thunder\" \n 根据需求自行添加 \n$leaf(true)$end", + "bgms": " 在此存放所有的bgm,和文件名一致。第一项为默认播放项 \n 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 \n$leaf(true)$end", + "sounds": " 在此存放所有的SE,和文件名一致 \n 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 \n$leaf(true)$end", + "bgmRemote" : " 是否使用远程的背景音乐;此项一般不要开启 \n$select({\"values\":[false]})$end", + "startBackground" : "标题界面的背景,建议使用jpg格式以压缩背景图空间", + "startLogoStyle" : "标题样式:可以改变颜色,也可以隐藏标题(如果背景图自带)", + "levelChoose" : " 难度选择:每个数组的第一个是其在标题界面显示的难度,第二个是在游戏内部传输的字符串,会显示在状态栏,修改此处后需要在project/functions中作相应更改 \n$leaf(true)$end" + }, + "firstData": { + "title": " 游戏名,将显示在标题页面以及切换楼层的界面中 ", + "name": " 游戏的唯一英文标识符。由英文、数字、下划线组成,不能超过20个字符。 ", + "version": " 当前游戏版本;版本不一致的存档不能通用。 ", + "floorId": " 初始楼层ID ", + "hero": { + "name": " 勇士初始数据 \n 勇士名;可以改成喜欢的 ", + "lv": " 初始等级,该项必须为正整数 \n$range(thiseval==~~thiseval &&thiseval>0)$end", + "hpmax": " 初始生命上限,只有在enableHPMax开启时才有效", + "hp": " 初始生命值 ", + "atk": " 初始攻击 ", + "def": " 初始防御 ", + "mdef": " 初始魔防 ", + "money": " 初始金币 ", + "experience": " 初始经验 ", + "items": { + "keys": " 初始道具个数 \n$leaf(true)$end"/* { + "yellowKey": " 初始道具个数 ", + "blueKey": "", + "redKey": "" + } */, + "constants": "\n$leaf(true)$end", + "tools": "\n$leaf(true)$end" + }, + "flyRange": " 初始可飞的楼层;一般留空数组即可 \n$leaf(true)$end", + "loc": { + "direction": " 勇士初始位置 ", + "x": "", + "y": "" + }, + "flags": " 游戏过程中的变量或flags \n$leaf(true)$end"/* { + "poison": " 游戏过程中的变量或flags \n 毒 ", + "weak": " 衰 ", + "curse": " 咒 " + } */, + "steps": " 行走步数统计 ", + }, + "startText": " 游戏开始前剧情。如果无剧情直接留一个空数组即可。 \n$leaf(true)$end", + "shops": "全局商店\n$leaf(true)$end",/*{ + "moneyShop1": { + "name": " 定义全局商店(即快捷商店) \n 商店唯一ID \n 商店名称(标题) ", + "icon": " 商店图标,blueShop为蓝色商店,pinkShop为粉色商店 ", + "textInList": " 在快捷商店栏中显示的名称 ", + "use": " 商店所要使用的。只能是\"money\"或\"experience\"。 ", + "need": " 商店需要的金币/经验数值;可以是一个表达式,以times作为参数计算。 \n 这里用到的times为该商店的已经的访问次数。首次访问该商店时times的值为0。 \n 上面的例子是50层商店的计算公式。你也可以写任意其他的计算公式,只要以times作为参数即可。 \n 例如: \"need\": \"25\" 就是恒定需要25金币的商店; \"need\": \"20+2*times\" 就是第一次访问要20金币,以后每次递增2金币的商店。 \n 如果是对于每个选项有不同的计算公式,写 \"need\": \"-1\" 即可。可参见下面的经验商店。 ", + "text": " 显示的文字,需手动加换行符。可以使用${need}表示上面的need值。 ", + "choices": [ + { + "text": "", + "effect": " 商店的选项 \n 如果有多个effect以分号分开,参见下面的经验商店 " + }, + { + "text": "", + "effect": "" + }, + { + "text": "", + "effect": "" + }, + { + "text": "", + "effect": " effect只能对status和item进行操作,不能修改flag值。 \n 必须是X+=Y的形式,其中Y可以是一个表达式,以status:xxx或item:xxx为参数 \n 其他effect样例: \n \"item:yellowKey+=1\" 黄钥匙+1 \n \"item:pickaxe+=3\" 破墙镐+3 \n \"status:hp+=2*(status:atk+status:def)\" 将生命提升攻防和的数值的两倍 " + } + ] + }, + "expShop1": { + "name": " 商店唯一ID ", + "icon": "", + "textInList": "", + "use": " 该商店使用的是经验进行计算 ", + "need": " 如果是对于每个选项所需要的数值不同,这里直接写-1,然后下面选项里给定具体数值 ", + "text": "", + "choices": [ + { + "text": "", + "need": "", + "effect": " 在choices中写need,可以针对每个选项都有不同的需求。 \n 这里的need同样可以以times作为参数,比如 \"need\": \"100+20*times\" 多个effect直接以分号分开即可。如上面的意思是生命+1000,攻击+7,防御+7。 " + }, + { + "text": "", + "need": "", + "effect": "" + }, + { + "text": "", + "need": "", + "effect": "" + } + ] + } + },*/ + "levelUp": " 经验升级所需要的数值,是一个数组 \n 第一项为初始等级,可以简单留空,也可以写name \n 每一个里面可以含有三个参数 need, name, effect \n need为所需要的经验数值,是一个正整数。请确保need所需的依次递增 \n name为该等级的名称,也可以省略代表使用系统默认值;本项将显示在状态栏中 \n effect为本次升级所执行的操作,可由若干项组成,由分号分开 \n 其中每一项写法和上面的商店完全相同,同样必须是X+=Y的形式,Y是一个表达式,同样可以使用status:xxx或item:xxx代表勇士的某项数值/道具个数 \n$leaf(true)$end"/* [ + " 经验升级所需要的数值,是一个数组 \n 第一项为初始等级,可以简单留空,也可以写name \n 每一个里面可以含有三个参数 need, name, effect \n need为所需要的经验数值,是一个正整数。请确保need所需的依次递增 \n name为该等级的名称,也可以省略代表使用系统默认值;本项将显示在状态栏中 \n effect为本次升级所执行的操作,可由若干项组成,由分号分开 \n 其中每一项写法和上面的商店完全相同,同样必须是X+=Y的形式,Y是一个表达式,同样可以使用status:xxx或item:xxx代表勇士的某项数值/道具个数 \n$leaf(true)$end", + { + "need": "", + "name": "", + "effect": " 先将生命提升攻防和的2倍;再将攻击+10,防御+10 " + }, + { + "need": "", + "effect": " effect也允许写一个function,代表本次升级将会执行的操作 \n 依次往下写需要的数值即可 " + } + ] */ + }, + "values": { + "lavaDamage": " 各种数值;一些数值可以在这里设置\n /****** 角色相关 ******/ \n 经过血网受到的伤害 ", + "poisonDamage": " 中毒后每步受到的伤害 ", + "weakValue": " 衰弱状态下攻防减少的数值 ", + "redJewel": " /****** 道具相关 ******/ \n 红宝石加攻击的数值 ", + "blueJewel": " 蓝宝石加防御的数值 ", + "greenJewel": " 绿宝石加魔防的数值 ", + "redPotion": " 红血瓶加血数值 ", + "bluePotion": " 蓝血瓶加血数值 ", + "yellowPotion": " 黄血瓶加血数值 ", + "greenPotion": " 绿血瓶加血数值 ", + "sword0": " 默认装备折断的剑的攻击力 ", + "shield0": " 默认装备残破的盾的防御力 ", + "sword1": " 铁剑加攻数值 ", + "shield1": " 铁盾加防数值 ", + "sword2": " 银剑加攻数值 ", + "shield2": " 银盾加防数值 ", + "sword3": " 骑士剑加攻数值 ", + "shield3": " 骑士盾加防数值 ", + "sword4": " 圣剑加攻数值 ", + "shield4": " 圣盾加防数值 ", + "sword5": " 神圣剑加攻数值 ", + "shield5": " 神圣盾加防数值 ", + "moneyPocket": " 金钱袋加金币的数值 ", + "breakArmor": " /****** 怪物相关 ******/ \n 破甲的比例(战斗前,怪物附加角色防御的x%作为伤害) ", + "counterAttack": " 反击的比例(战斗时,怪物每回合附加角色攻击的x%作为伤害,无视角色防御) ", + "purify": " 净化的比例(战斗前,怪物附加勇士魔防的x倍作为伤害) ", + "hatred": " 仇恨属性中,每杀死一个怪物获得的仇恨值 ", + "animateSpeed": " /****** 系统相关 ******/ \n 动画时间 " + }, + "flags": { + "enableFloor": " 系统FLAG,在游戏运行中中请不要修改它。 /****** 状态栏相关 ******/ \n 是否在状态栏显示当前楼层 \n$select({\"values\":[true,false]})$end", + "enableLv": " 是否在状态栏显示当前等级 \n$select({\"values\":[true,false]})$end", + "enableHPMax": " 是否是否启用生命上限 \n$select({\"values\":[true,false]})$end", + "enableMDef": " 是否在状态栏及战斗界面显示魔防(护盾) \n$select({\"values\":[true,false]})$end", + "enableMoney": " 是否在状态栏、怪物手册及战斗界面显示金币 \n$select({\"values\":[true,false]})$end", + "enableExperience": " 是否在状态栏、怪物手册及战斗界面显示经验 \n$select({\"values\":[true,false]})$end", + "enableLevelUp": " 是否允许等级提升(进阶);如果上面enableExperience为false,则此项恒视为false \n$select({\"values\":[true,false]})$end", + "enableDebuff": " 是否涉及毒衰咒;如果此项为false则不会在状态栏中显示毒衰咒的debuff ////// 上述的几个开关将直接影响状态栏的显示效果 ////// \n$select({\"values\":[true,false]})$end", + "flyNearStair": " /****** 道具相关 ******/ \n 是否需要在楼梯边使用传送器 \n$select({\"values\":[true,false]})$end", + "pickaxeFourDirections": " 使用破墙镐是否四个方向都破坏;如果false则只破坏面前的墙壁 \n$select({\"values\":[true,false]})$end", + "bombFourDirections": " 使用炸弹是否四个方向都会炸;如果false则只炸面前的怪物(即和圣锤等价) \n$select({\"values\":[true,false]})$end", + "bigKeyIsBox": " 如果此项为true,则视为钥匙盒,红黄蓝钥匙+1;若为false,则视为大黄门钥匙 \n$select({\"values\":[true,false]})$end", + "equipment": " 剑和盾是否直接作为装备。如果此项为true,则作为装备,需要在道具栏使用,否则将直接加属性。 \n$select({\"values\":[true,false]})$end", + "enableDeleteItem": " 是否允许删除(丢弃)道具 \n$select({\"values\":[true,false]})$end", + "enableAddPoint": " /****** 怪物相关 ******/ \n 是否支持加点 \n$select({\"values\":[true,false]})$end", + "enableNegativeDamage": "是否支持负伤害(回血) \n$select({\"values\":[true,false]})$end", + "hatredDecrease": " 是否在和仇恨怪战斗后减一半的仇恨值,此项为false则和仇恨怪不会扣减仇恨值。 \n$select({\"values\":[true,false]})$end", + "betweenAttackCeil": " 夹击方式是向上取整还是向下取整。如果此项为true则为向上取整,为false则为向下取整 \n$select({\"values\":[true,false]})$end", + "startDirectly": " /****** 系统相关 ******/ \n 点击“开始游戏”后是否立刻开始游戏而不显示难度选择界面 \n$select({\"values\":[true,false]})$end", + "canOpenBattleAnimate": " 是否允许用户开启战斗过程;如果此项为false,则下面两项均强制视为false \n$select({\"values\":[true,false]})$end", + "showBattleAnimateConfirm": " 是否在游戏开始时提供“是否开启战斗动画”的选项 \n$select({\"values\":[true,false]})$end", + "battleAnimate": " 是否默认显示战斗动画;用户可以手动在菜单栏中开关 \n$select({\"values\":[true,false]})$end", + "displayEnemyDamage": " 是否地图怪物显伤;用户可以手动在菜单栏中开关 \n$select({\"values\":[true,false]})$end", + "displayExtraDamage": " 是否地图高级显伤(领域、夹击等);用户可以手动在菜单栏中开关 \n$select({\"values\":[true,false]})$end", + "enableGentleClick": " 是否允许轻触(获得面前物品) \n$select({\"values\":[true,false]})$end", + "potionWhileRouting": " 寻路算法是否经过血瓶;如果该项为false,则寻路算法会自动尽量绕过血瓶 \n$select({\"values\":[true,false]})$end", + "enableViewMaps": " 是否支持在菜单栏中查看所有楼层的地图 \n$select({\"values\":[true,false]})$end", + "portalWithoutTrigger": " 经过楼梯、传送门时是否能“穿透”。穿透的意思是,自动寻路得到的的路径中间经过了楼梯,行走时是否触发楼层转换事件 \n$select({\"values\":[true,false]})$end", + "enableMoveDirectly": " 是否允许瞬间移动 \n$select({\"values\":[true,false]})$end" + } +} \ No newline at end of file diff --git a/project/data.js b/project/data.js new file mode 100644 index 00000000..5e3c5775 --- /dev/null +++ b/project/data.js @@ -0,0 +1,168 @@ +data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = +{ + "main" : { + "floorIds" : [ + "sample0", "sample1", "sample2" + ], + "images" : [ + "bg.jpg", + ], + "animates" : [ + "hand", "sword", "zone", "yongchang", + ], + "bgms" : [ + 'bgm.mp3', 'qianjin.mid', 'star.mid', + ], + "sounds" : [ + 'floor.mp3', 'attack.ogg', 'door.ogg', 'item.ogg', 'zone.ogg' + ], + "bgmRemote" : false, + "startBackground" : "bg.jpg", + "startLogoStyle" : "color: black", + "levelChoose" : [["简单","Easy"],["普通","Normal"],["困难","Hard"],["噩梦","Hell"]], + }, + "firstData" : { + "title": "魔塔样板", + "name": "template", + "version": "Ver 1.4.1", + "floorId": "sample0", + "hero": { + "name": "阳光", + 'lv': 1, + "hpmax": 9999, + "hp": 1000, + "atk": 100, + "def": 100, + "mdef": 100, + "money": 100, + "experience": 0, + "items": { + "keys": { + "yellowKey": 0, + "blueKey": 0, + "redKey": 0 + }, + "constants": {}, + "tools": {} + }, + "flyRange": [], + "loc": {"direction": "up", "x": 6, "y": 10}, + "flags": { + "poison": false, + "weak": false, + "curse": false, + }, + "steps": 0, + }, + "startText": [ + "Hi,欢迎来到 HTML5 魔塔样板!\n\n本样板由艾之葵制作,可以让你在不会写任何代码\n的情况下也能做出属于自己的H5魔塔!", + "这里游戏开始时的剧情。\n定义在data.js的startText处。\n\n你可以在这里写上自己的内容。", + "赶快来试一试吧!" + ], + "shops": [ + { + "id": "moneyShop1", + "name": "贪婪之神", + "icon": "blueShop", + "textInList": "1F金币商店", + "use": "money", + "need": "20+10*times*(times+1)", + "text": "勇敢的武士啊,给我${need}金币就可以:", + "choices": [ + {"text": "生命+800", "effect": "status:hp+=800"}, + {"text": "攻击+4", "effect": "status:atk+=4"}, + {"text": "防御+4", "effect": "status:def+=4"}, + {"text": "魔防+10", "effect": "status:mdef+=10"} + ] + }, + { + "id": "expShop1", + "name": "经验之神", + "icon": "pinkShop", + "textInList": "1F经验商店", + "use": "experience", + "need": "-1", + "text": "勇敢的武士啊,给我若干经验就可以:", + "choices": [ + {"text": "等级+1", "need": "100", "effect": "status:lv+=1;status:hp+=1000;status:atk+=7;status:def+=7"}, + {"text": "攻击+5", "need": "30", "effect": "status:atk+=5"}, + {"text": "防御+5", "need": "30", "effect": "status:def+=5"}, + ] + } + ], + "levelUp": [ + {}, + {"need": 20, "name": "第二级", "effect": "status:hp+=2*(status:atk+status:def);status:atk+=10;status:def+=10"}, + {"need": 40, "effect": function () { + core.insertAction("恭喜升级!"); + core.status.hero.hp *= 2; + core.status.hero.atk += 100; + core.status.hero.def += 100; + }}, + ] + }, + + "values" : { + "lavaDamage": 100, + "poisonDamage": 10, + "weakValue": 20, + "redJewel": 3, + "blueJewel": 3, + "greenJewel": 5, + "redPotion": 100, + "bluePotion": 250, + "yellowPotion": 500, + "greenPotion": 800, + "sword0": 0, + "shield0": 0, + "sword1": 10, + "shield1": 10, + "sword2": 20, + "shield2": 20, + "sword3": 40, + "shield3": 40, + "sword4": 80, + "shield4": 80, + "sword5": 160, + "shield5": 160, + "moneyPocket": 500, + /****** 怪物相关 ******/ + 'breakArmor': 0.9, + 'counterAttack': 0.1, + 'purify': 3, + 'hatred': 2, + 'animateSpeed': 300, + }, + + "flags" : { + "enableFloor": true, + "enableLv": false, + "enableHPMax": false, + "enableMDef": true, + "enableMoney": true, + "enableExperience": false, + "enableLevelUp": false, + "enableDebuff": false, + "flyNearStair": true, + "pickaxeFourDirections": true, + "bombFourDirections": true, + "bigKeyIsBox": false, + "equipment": false, + "enableDeleteItem": true, + "enableAddPoint": false, + "enableNegativeDamage": true, + "hatredDecrease": true, + "betweenAttackCeil": false, + "startDirectly": false, + "canOpenBattleAnimate": true, + "showBattleAnimateConfirm": true, + "battleAnimate": true, + "displayEnemyDamage": true, + "displayExtraDamage": true, + "enableGentleClick": true, + "potionWhileRouting": false, + "enableViewMaps": true, + "portalWithoutTrigger": true, + "enableMoveDirectly": true, + } +} \ No newline at end of file diff --git a/project/enemys.js b/project/enemys.js new file mode 100644 index 00000000..8be699d0 --- /dev/null +++ b/project/enemys.js @@ -0,0 +1,67 @@ +enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 = +{ + 'greenSlime': {'name': '绿头怪', 'hp': 100, 'atk': 120, 'def': 0, 'money': 1, 'experience': 1, 'point': 0, 'special': [1,5,7,8]}, + 'redSlime': {'name': '红头怪', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'blackSlime': {'name': '青头怪', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'slimelord': {'name': '怪王', 'hp': 100, 'atk': 120, 'def': 0, 'money': 10, 'experience': 0, 'point': 0, 'special': [1,9]}, + 'bat': {'name': '小蝙蝠', 'hp': 100, 'atk': 120, 'def': 0, 'money': 2, 'experience': 0, 'point': 0, 'special': 1}, + 'bigBat': {'name': '大蝙蝠', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'redBat': {'name': '红蝙蝠', 'hp': 100, 'atk': 120, 'def': 0, 'money': 5, 'experience': 0, 'point': 0, 'special': 4}, + 'vampire': {'name': '冥灵魔王', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'skeleton': {'name': '骷髅人', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'skeletonSoilder': {'name': '骷髅士兵', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'skeletonCaptain': {'name': '骷髅队长', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'ghostSkeleton': {'name': '冥队长', 'hp': 100, 'atk': 120, 'def': 0, 'money': 8, 'experience': 0, 'point': 0, 'special': 7}, + 'zombie': {'name': '兽人', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'zombieKnight': {'name': '兽人武士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'rock': {'name': '石头人', 'hp': 100, 'atk': 120, 'def': 0, 'money': 4, 'experience': 0, 'point': 0, 'special': 3}, + 'slimeMan': {'name': '影子战士', 'hp': 100, 'atk': 0, 'def': 0, 'money': 11, 'experience': 0, 'point': 0, 'special': [10,21], 'atkValue': 2, 'defValue': 3}, // 退化怪可以在后面写atkValue和defValue表示退化的数值 + 'bluePriest': {'name': '初级法师', 'hp': 100, 'atk': 120, 'def': 0, 'money': 3, 'experience': 0, 'point': 1, 'special': 2}, + 'redPriest': {'name': '高级法师', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'brownWizard': {'name': '初级巫师', 'hp': 100, 'atk': 120, 'def': 0, 'money': 16, 'experience': 0, 'point': 0, 'special': 15, 'value': 100, 'range': 2}, // 领域怪需要加value表示领域伤害的数值;range可选,代表领域伤害的范围;不加默认为1 + 'redWizard': {'name': '高级巫师', 'hp': 1000, 'atk': 1200, 'def': 0, 'money': 160, 'experience': 0, 'point': 0, 'special': 15, 'value': 200, 'zoneSquare': true}, // zoneSquare可选,代表是否九宫格伤害,true为是九宫格伤害,false或不设置为十字伤害 + 'yellowGuard': {'name': '初级卫兵', 'hp': 100, 'atk': 120, 'def': 0, 'money': 10, 'experience': 0, 'point': 0, 'special': 0}, + 'blueGuard': {'name': '中级卫兵', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'redGuard': {'name': '高级卫兵', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'swordsman': {'name': '双手剑士', 'hp': 100, 'atk': 120, 'def': 0, 'money': 6, 'experience': 0, 'point': 0, 'special': [5,23]}, + 'soldier': {'name': '冥战士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'yellowKnight': {'name': '金骑士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'redKnight': {'name': '红骑士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'darkKnight': {'name': '黑骑士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'blackKing': {'name': '黑衣魔王', 'hp': 1000, 'atk': 500, 'def': 0, 'money': 1000, 'experience': 1000, 'point': 0, 'special': 0, 'bomb': false}, // 加入 'bomb': false 代表该怪物不可被炸弹或圣锤炸掉 + 'yellowKing': {'name': '黄衣魔王', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'greenKing': {'name': '青衣武士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'blueKnight': {'name': '蓝骑士', 'hp': 100, 'atk': 120, 'def': 0, 'money': 9, 'experience': 0, 'point': 0, 'special': 8}, + 'goldSlime': {'name': '黄头怪', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'poisonSkeleton': {'name': '紫骷髅', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'poisonBat': {'name': '紫蝙蝠', 'hp': 100, 'atk': 120, 'def': 0, 'money': 14, 'experience': 0, 'point': 0, 'special': 13}, + 'steelRock': {'name': '铁面人', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'skeletonPriest': {'name': '骷髅法师', 'hp': 100, 'atk': 100, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 18, 'value': 20}, + 'skeletonKing': {'name': '骷髅王', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'skeletonWizard': {'name': '骷髅巫师', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'redSkeletonCaption': {'name': '骷髅武士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'badHero': {'name': '迷失勇者', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'demon': {'name': '魔神武士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'demonPriest': {'name': '魔神法师', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'goldHornSlime': {'name': '金角怪', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'redKing': {'name': '红衣魔王', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'whiteKing': {'name': '白衣武士', 'hp': 100, 'atk': 120, 'def': 0, 'money': 17, 'experience': 0, 'point': 0, 'special': 16}, + 'blackMagician': {'name': '黑暗大法师', 'hp': 100, 'atk': 120, 'def': 0, 'money': 12, 'experience': 0, 'point': 0, 'special': 11, 'value': 1/3, 'add': true, 'bomb': false}, // 吸血怪需要在后面添加value代表吸血比例;添加add: true可以将吸血的伤害加到自身 + 'silverSlime': {'name': '银头怪', 'hp': 100, 'atk': 120, 'def': 0, 'money': 15, 'experience': 0, 'point': 0, 'special': 14}, + 'swordEmperor': {'name': '剑圣', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'whiteHornSlime': {'name': '尖角怪', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'badPrincess': {'name': '痛苦魔女', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'badFairy': {'name': '黑暗仙子', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'grayPriest': {'name': '中级法师', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'redSwordsman': {'name': '剑王', 'hp': 100, 'atk': 120, 'def': 0, 'money': 7, 'experience': 0, 'point': 0, 'special': 6, 'n': 8}, // 多连击需要在后面指定n代表是几连击 + 'whiteGhost': {'name': '水银战士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'poisonZombie': {'name': '绿兽人', 'hp': 100, 'atk': 120, 'def': 0, 'money': 13, 'experience': 0, 'point': 0, 'special': 12}, + 'magicDragon': {'name': '魔龙', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'octopus': {'name': '血影', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'darkFairy': {'name': '仙子', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'greenKnight': {'name': '强盾骑士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'angel': {'name': '天使', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'elemental': {'name': '元素生物', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 0}, + 'steelGuard': {'name': '铁守卫', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': 18, 'value': 20}, + 'evilBat': {'name': '邪恶蝙蝠', 'hp': 1000, 'atk': 1, 'def': 0, 'money': 0, 'experience': 0, 'point': 0, 'special': [2,3]}, +} \ No newline at end of file diff --git a/libs/floors/MT0.js b/project/floors/MT0.js similarity index 71% rename from libs/floors/MT0.js rename to project/floors/MT0.js index 602637a4..03a7db4b 100644 --- a/libs/floors/MT0.js +++ b/project/floors/MT0.js @@ -1,17 +1,19 @@ -// 这里需要改楼层名,请和文件名及下面的floorId保持完全一致 -// 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头 -// 推荐用法:第20层就用MT20,第38层就用MT38,地下6层就用MT_6(用下划线代替负号),隐藏3层用MT3h(h表示隐藏),等等 -main.floors.MT0 = { - "floorId": "MT0", // 楼层唯一标识符,需要和名字完全一致 +main.floors.MT0 = +{ + "floorId": "MT0", // 这里需要改楼层名,请和文件名及下面的floorId保持完全一致 + // 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头 + // 推荐用法:第20层就用MT20,第38层就用MT38,地下6层就用MT_6(用下划线代替负号),隐藏3层用MT3h(h表示隐藏),等等 + // 楼层唯一标识符,需要和名字完全一致 "title": "主塔 0 层", // 楼层中文名 "name": "0", // 显示在状态栏中的层数 "canFlyTo": true, // 该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器) "canUseQuickShop": true, // 该层是否允许使用快捷商店 "defaultGround": "ground", // 默认地面的图块ID(terrains中) - "png": [], // 该层默认显示的所有图片;详细用法请查看文档“自定义素材”中的说明。 + "images": [], // 该层默认显示的所有图片;详细用法请查看文档“自定义素材”中的说明。 // "color": [0,0,0,0.3], // 该层的默认画面色调。本项可不写(代表无色调),如果写需要是一个RGBA数组。 // "weather": ["snow",5], // 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain"或"snow"代表雨雪,第二项为1-10之间的数代表强度。 // "bgm": "bgm.mp3", // 到达该层后默认播放的BGM。本项可忽略。 + "item_ratio": 1, // 该层的宝石/血瓶倍率 "map": [ // 地图数据,需要是13x13,建议使用地图生成器来生成 ], diff --git a/libs/floors/sample0.js b/project/floors/sample0.js similarity index 86% rename from libs/floors/sample0.js rename to project/floors/sample0.js index 5f0fa6d7..804dee94 100644 --- a/libs/floors/sample0.js +++ b/project/floors/sample0.js @@ -1,29 +1,31 @@ -// 这里需要改楼层名,请和文件名及下面的floorId保持完全一致 -// 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头 -// 推荐用法:第20层就用MT20,第38层就用MT38,地下6层就用MT_6(用下划线代替负号),隐藏3层用MT3h(h表示隐藏),等等 -main.floors.sample0 = { - "floorId": "sample0", // 楼层唯一标识符,需要和名字完全一致 +main.floors.sample0 = +{ + "floorId": "sample0", // 这里需要改楼层名,请和文件名及下面的floorId保持完全一致 + // 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头 + // 推荐用法:第20层就用MT20,第38层就用MT38,地下6层就用MT_6(用下划线代替负号),隐藏3层用MT3h(h表示隐藏),等等 + // 楼层唯一标识符,需要和名字完全一致 "title": "样板 0 层", // 楼层中文名 "name": "0", // 显示在状态栏中的层数 "canFlyTo": true, // 该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器) "canUseQuickShop": true, // 该层是否允许使用快捷商店 "defaultGround": "ground", // 默认地面的图块ID(terrains中) - "png": [], // 该层默认显示的所有图片;详细用法请查看文档“自定义素材”中的说明。 + "images": [], // 该层默认显示的所有图片;详细用法请查看文档“自定义素材”中的说明。 // "color": [0,0,0,0.3] // 该层的默认画面色调。本项可不写(代表无色调),如果写需要是一个RGBA数组。 // "weather": ["snow",5], // 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain"或"snow"代表雨雪,第二项为1-10之间的数代表强度。 "bgm": "bgm.mp3", // 到达该层后默认播放的BGM。本项可忽略。 + "item_ratio": 2, // 该层的宝石/血瓶倍率 "map": [ // 地图数据,需要是13x13,建议使用地图生成器来生成 [0, 0, 220, 0, 0, 20, 87, 3, 65, 64, 44, 43, 42], [0, 246, 0, 246, 0, 20, 0, 3, 58, 59, 60, 61, 41], [219, 0, 0, 0, 219, 20, 0, 3, 57, 26, 62, 63, 40], [20, 20, 125, 20, 20, 20, 0, 3, 53, 54, 55, 56, 39], - [216, 247, 256, 235, 248, 6, 0, 3, 49, 50, 51, 52, 38], + [216, 247, 263, 235, 248, 6, 0, 3, 49, 50, 51, 52, 38], [6, 6, 125, 6, 6, 6, 0, 1, 45, 46, 47, 48, 37], - [224, 254, 212, 232, 204, 5, 0, 1, 31, 32, 34, 33, 36], - [201, 205, 217, 215, 207, 5, 0, 1, 27, 28, 29, 30, 35], + [224, 254, 212, 262, 204, 5, 0, 1, 31, 32, 34, 33, 36], + [201, 261, 217, 264, 207, 5, 0, 1, 27, 28, 29, 30, 35], [5, 5, 125, 5, 5, 5, 0, 1, 21, 22, 23, 24, 25], [0, 0, 237, 0, 0, 0, 45, 1, 1, 1, 121, 1, 1], - [4, 4, 126, 4, 4, 4, 0, 0, 0, 0, 0, 85, 124], + [4, 4, 133, 4, 4, 4, 0, 0, 0, 0, 0, 85, 124], [87, 11, 12, 13, 14, 4, 4, 2, 2, 2, 122, 2, 2], [88, 89, 90, 91, 92, 93, 94, 2, 81, 82, 83, 84, 86], ], @@ -44,12 +46,12 @@ main.floors.sample0 = { "10,11": [ // 守着门的老人 "\t[老人,woman]这些是门,需要对应的钥匙打开。\n机关门必须使用特殊的开法。", "\t[老人,woman]开门后可触发 afterOpenDoor 事件。\n\n有关事件的各种信息在下一层会有更为详细的说明。", - {'type': 'hide', "time": 500} + {"type": "hide", "time": 500} ], "2,10": [ // 守着楼梯、传送门、路障的老人 - "\t[老人,womanMagician]这些是路障、楼梯、传送门。", - "\t[老人,womanMagician]血网的伤害数值、中毒后每步伤害数值、衰弱时攻防下降的数值,都在 data.js 内定义。\n\n路障同样会尽量被自动寻路绕过。", - "\t[老人,womanMagician]楼梯和传送门需要在changeFloor中定义目标楼层和位置,可参见样板里已有的的写法。", + "\t[少女,npc0]这些是路障、楼梯、传送门。", + "\t[少女,npc0]血网的伤害数值、中毒后每步伤害数值、衰弱时攻防下降的数值,都在 data.js 内定义。\n\n路障同样会尽量被自动寻路绕过。", + "\t[少女,npc0]楼梯和传送门需要在changeFloor中定义目标楼层和位置,可参见样板里已有的的写法。", {"type": "hide", "time": 500} ], "2,8": [ // 守着第一批怪物的老人 @@ -64,7 +66,7 @@ main.floors.sample0 = { ], "2,3": [ // 守着第三批怪物的老人 "\t[老人,magician]领域、夹击。\n请注意领域怪需要设置value为伤害数值,可参见样板中初级巫师的写法。", - "\t[老人,magician]夹击和领域同时发生时先计算领域,再夹击。\n自动寻路同样会尽量绕过你设置的这些点。\n\n另:本塔不支持阻击怪。", + "\t[老人,magician]夹击和领域同时发生时先计算领域,再夹击。\n自动寻路同样会尽量绕过你设置的这些点。", {"type": "hide", "time": 500} ], "12,10": { // 隐藏的仙子 @@ -76,7 +78,6 @@ main.floors.sample0 = { }, }, "changeFloor": { // 楼层转换事件;该事件不能和上面的events有冲突(同位置点),否则会被覆盖 - "7,9": {"floorId": "sample1", "stair": "downFloor"}, "6,0": {"floorId": "sample1", "stair": "downFloor"}, // 目标点:sample1层的下楼梯位置 "0,11": {"floorId": "sample0", "loc": [0,12]}, // 目标点:sample0层的x=0,y=12位置 "0,12": {"floorId": "sample0", "stair": "upFloor"}, // 注意,目标层有多个楼梯的话,写stair可能会导致到达位置不确定。这时候推荐写loc指明目标点位置。 diff --git a/libs/floors/sample1.js b/project/floors/sample1.js similarity index 97% rename from libs/floors/sample1.js rename to project/floors/sample1.js index 85163853..669d67b1 100644 --- a/libs/floors/sample1.js +++ b/project/floors/sample1.js @@ -1,17 +1,19 @@ -// 这里需要改楼层名,请和文件名及下面的floorId保持完全一致 -// 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头 -// 推荐用法:第20层就用MT20,第38层就用MT38,地下6层就用MT_6(用下划线代替负号),隐藏3层用MT3h(h表示隐藏),等等 -main.floors.sample1 = { - "floorId": "sample1", // 楼层唯一标识符,需要和名字完全一致 +main.floors.sample1 = +{ + "floorId": "sample1", // 这里需要改楼层名,请和文件名及下面的floorId保持完全一致 + // 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头 + // 推荐用法:第20层就用MT20,第38层就用MT38,地下6层就用MT_6(用下划线代替负号),隐藏3层用MT3h(h表示隐藏),等等 + // 楼层唯一标识符,需要和名字完全一致 "title": "样板 1 层", // 楼层中文名 "name": "1", // 显示在状态栏中的层数 "canFlyTo": true, // 该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器) "canUseQuickShop": true, // 该层是否允许使用快捷商店 "defaultGround": "grass", // 默认地面的图块ID(terrains中) - "png": [[0,0,"bg"]], // // 该层默认显示的所有图片;详细用法请查看文档“自定义素材”中的说明。 + "images": [[0,0,"bg.jpg",false]], // 该层默认显示的所有图片;详细用法请查看文档“自定义素材”中的说明。 // "color": [0,0,0,0.3] // 该层的默认画面色调。本项可不写(代表无色调),如果写需要是一个RGBA数组。 "weather": ["snow",6], // 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain"或"snow"代表雨雪,第二项为1-10之间的数代表强度。 // "bgm": "bgm.mp3", // 到达该层后默认播放的BGM。本项可忽略。 + "item_ratio": 1, // 该层的宝石/血瓶倍率 "map": [ // 地图数据,需要是13x13,建议使用地图生成器来生成 [7, 131, 8, 152, 9, 130, 10, 152, 166, 165, 132, 165, 166], [0, 0, 0, 0, 0, 0, 0, 152, 165, 164, 0, 162, 165], @@ -60,9 +62,9 @@ main.floors.sample1 = { {"type": "hide", "loc": [[1,6],[0,7],[2,7],[1,8]]}, // 直接隐藏四个白衣武士,没有动画效果 {"type": "hide", "loc": [1,5], "time": 500}, // 隐藏红衣魔王,动画500ms {"type": "hide"}, // 隐藏本事件 - {"type": "setFg", "color": [0,0,0], 'time': 1250}, // 渐变为白色 + {"type": "setFg", "color": [0,0,0], "time": 1250}, // 渐变为白色 {"type": "sleep", "time": 700}, - {"type": "changeFloor", "floorId": "sample1", "loc": [1,11], 'direction': 'right', 'time': 1000}, // 楼层切换。changeFloor必须指定floorId和loc。 + {"type": "changeFloor", "floorId": "sample1", "loc": [1,11], "direction": "right", "time": 1000}, // 楼层切换。changeFloor必须指定floorId和loc。 // 备注:这里也可以下面的这种写法: // {"type": "changePos", "loc": [1,11]} // 使用这种写法将不会有“楼层切换动画”,而是直接让勇士到达本层的loc位置。 diff --git a/libs/floors/sample2.js b/project/floors/sample2.js similarity index 97% rename from libs/floors/sample2.js rename to project/floors/sample2.js index c24c78f0..6f6e5f7b 100644 --- a/libs/floors/sample2.js +++ b/project/floors/sample2.js @@ -1,17 +1,19 @@ -// 这里需要改楼层名,请和文件名及下面的floorId保持完全一致 -// 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头 -// 推荐用法:第20层就用MT20,第38层就用MT38,地下6层就用MT_6(用下划线代替负号),隐藏3层用MT3h(h表示隐藏),等等 -main.floors.sample2 = { - "floorId": "sample2", // 楼层唯一标识符,需要和名字完全一致 +main.floors.sample2 = +{ + "floorId": "sample2", // 这里需要改楼层名,请和文件名及下面的floorId保持完全一致 + // 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头 + // 推荐用法:第20层就用MT20,第38层就用MT38,地下6层就用MT_6(用下划线代替负号),隐藏3层用MT3h(h表示隐藏),等等 + // 楼层唯一标识符,需要和名字完全一致 "title": "主塔 40 层", // 楼层中文名 "name": "40", // 显示在状态栏中的层数 "canFlyTo": false, // 该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器) "canUseQuickShop": true, // 该层是否允许使用快捷商店 "defaultGround": "snowGround", // 默认地面的图块ID(terrains中) - "png": [], // // 该层默认显示的所有图片;详细用法请查看文档“自定义素材”中的说明。 + "images": [], // // 该层默认显示的所有图片;详细用法请查看文档“自定义素材”中的说明。 "color": [255,0,0,0.3], // 该层的默认画面色调。本项可不写(代表无色调),如果写需要是一个RGBA数组。 "weather": ["rain",10], // 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain"或"snow"代表雨雪,第二项为1-10之间的数代表强度。 "bgm": "qianjin.mid", // 到达该层后默认播放的BGM。本项可忽略。 + "item_ratio": 1, // 该层的宝石/血瓶倍率 "map": [ // 地图数据,需要是13x13,建议使用地图生成器来生成 [5, 5, 5, 5, 5, 5, 87, 5, 5, 5, 5, 5, 5], [5, 4, 4, 4, 4, 1, 0, 1, 4, 4, 4, 4, 5], diff --git a/project/functions.comment.js b/project/functions.comment.js new file mode 100644 index 00000000..8093f009 --- /dev/null +++ b/project/functions.comment.js @@ -0,0 +1,21 @@ +functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = +{ + "events" : { + "setInitData" : "不同难度分别设置初始属性", + "win" : "游戏获胜事件", + "lose" : "游戏失败事件", + "afterChangeFloor":"转换楼层结束的事件", + "addPoint":"加点事件", + "afterBattle" : "战斗结束后触发的事件", + "afterOpenDoor" : "开一个门后触发的事件", + "afterChangeLight" : "改变亮灯之后,可以触发的事件", + "afterPushBox" : "推箱子后的事件", + "afterUseBomb" : "使用炸弹/圣锤后的事件", + "beforeSaveData" : "即将存档前可以执行的操作", + "afterLoadData" : "读档事件后,载入事件前,可以执行的操作" + + }, + "ui" : { + "drawAbout" : "绘制“关于”界面" + } +} \ No newline at end of file diff --git a/project/functions.js b/project/functions.js new file mode 100644 index 00000000..ee0b7a21 --- /dev/null +++ b/project/functions.js @@ -0,0 +1,301 @@ +functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = +{ +"events":{ +////// 不同难度分别设置初始属性 ////// +"setInitData":function (hard) { + // 不同难度分别设置初始属性 + if (hard=='Easy') { // 简单难度 + core.setFlag('hard', 1); // 可以用flag:hard来获得当前难度 + // 可以在此设置一些初始福利,比如设置初始生命值可以调用: + // core.setStatus("hp", 10000); + // 赠送一把黄钥匙可以调用 + // core.setItem("yellowKey", 1); + } + if (hard=='Normal') { // 普通难度 + core.setFlag('hard', 2); // 可以用flag:hard来获得当前难度 + } + if (hard=='Hard') { // 困难难度 + core.setFlag('hard', 3); // 可以用flag:hard来获得当前难度 + } + if (hard=='Hell') { // 噩梦难度 + core.setFlag('hard', 4); // 可以用flag:hard来获得当前难度 + } + core.events.afterLoadData(); +}, +////// 游戏获胜事件 ////// +"win" : function(reason) { + // 游戏获胜事件 + core.ui.closePanel(); + var replaying = core.status.replay.replaying; + core.stopReplay(); + core.waitHeroToStop(function() { + core.removeGlobalAnimate(0,0,true); + core.clearMap('all'); // 清空全地图 + core.drawText([ + "\t[恭喜通关]你的分数是${status:hp}。" + ], function () { + core.events.gameOver(reason||'', replaying); + }) + }); +}, +////// 游戏失败事件 ////// +"lose" : function(reason) { + // 游戏失败事件 + core.ui.closePanel(); + var replaying = core.status.replay.replaying; + core.stopReplay(); + core.waitHeroToStop(function() { + core.drawText([ + "\t[结局1]你死了。\n如题。" + ], function () { + core.events.gameOver(null, replaying); + }); + }) +}, +////// 转换楼层结束的事件 ////// +"afterChangeFloor" : function (floorId) { + // 转换楼层结束的事件 + if (!core.hasFlag("visited_"+floorId)) { + core.insertAction(core.floors[floorId].firstArrive); + core.setFlag("visited_"+floorId, true); + } +}, +////// 加点事件 ////// +"addPoint" : function (enemy) { + // 加点事件 + var point = enemy.point; + if (!core.flags.enableAddPoint || !core.isset(point) || point<=0) return []; + + // 加点,返回一个choices事件 + return [ + {"type": "choices", + "choices": [ + {"text": "攻击+"+(1*point), "action": [ + {"type": "setValue", "name": "status:atk", "value": "status:atk+"+(1*point)} + ]}, + {"text": "防御+"+(2*point), "action": [ + {"type": "setValue", "name": "status:def", "value": "status:def+"+(2*point)} + ]}, + {"text": "生命+"+(200*point), "action": [ + {"type": "setValue", "name": "status:hp", "value": "status:hp+"+(200*point)} + ]}, + ] + } + ]; +}, +////// 战斗结束后触发的事件 ////// +"afterBattle" : function(enemyId,x,y,callback) { + // 战斗结束后触发的事件 + + var enemy = core.material.enemys[enemyId]; + + // 扣减体力值 + core.status.hero.hp -= core.enemys.getDamage(enemyId); + if (core.status.hero.hp<=0) { + core.status.hero.hp=0; + core.updateStatusBar(); + core.events.lose('battle'); + return; + } + // 获得金币和经验 + var money = enemy.money; + if (core.hasItem('coin')) money *= 2; + if (core.hasFlag('curse')) money=0; + core.status.hero.money += money; + var experience =enemy.experience; + if (core.hasFlag('curse')) experience=0; + core.status.hero.experience += experience; + var hint = "打败 " + enemy.name; + if (core.flags.enableMoney) + hint += ",金币+" + money; + if (core.flags.enableExperience) + hint += ",经验+" + experience; + core.drawTip(hint); + + // 删除该块 + if (core.isset(x) && core.isset(y)) { + core.removeBlock(x, y); + core.canvas.event.clearRect(32 * x, 32 * y, 32, 32); + } + + // 毒衰咒的处理 + var special = enemy.special; + // 中毒 + if (core.enemys.hasSpecial(special, 12) && !core.hasFlag('poison')) { + core.setFlag('poison', true); + } + // 衰弱 + if (core.enemys.hasSpecial(special, 13) && !core.hasFlag('weak')) { + core.setFlag('weak', true); + core.status.hero.atk-=core.values.weakValue; + core.status.hero.def-=core.values.weakValue; + } + // 诅咒 + if (core.enemys.hasSpecial(special, 14) && !core.hasFlag('curse')) { + core.setFlag('curse', true); + } + // 仇恨属性:减半 + if (core.flags.hatredDecrease && core.enemys.hasSpecial(special, 17)) { + core.setFlag('hatred', parseInt(core.getFlag('hatred', 0)/2)); + } + // 自爆 + if (core.enemys.hasSpecial(special, 19)) { + core.status.hero.hp = 1; + } + // 退化 + if (core.enemys.hasSpecial(special, 21)) { + core.status.hero.atk -= (enemy.atkValue||0); + core.status.hero.def -= (enemy.defValue||0); + if (core.status.hero.atk<0) core.status.hero.atk=0; + if (core.status.hero.def<0) core.status.hero.def=0; + } + // 增加仇恨值 + core.setFlag('hatred', core.getFlag('hatred',0)+core.values.hatred); + core.updateStatusBar(); + + + // 事件的处理 + var todo = []; + // 如果不为阻击,且该点存在,且有事件 + if (!core.enemys.hasSpecial(special, 18) && core.isset(x) && core.isset(y)) { + var event = core.floors[core.status.floorId].afterBattle[x+","+y]; + if (core.isset(event)) { + // 插入事件 + core.unshift(todo, event); + } + } + // 如果有加点 + var point = core.material.enemys[enemyId].point; + if (core.isset(point) && point>0) { + core.unshift(todo, core.events.addPoint(core.material.enemys[enemyId])); + } + + // 如果事件不为空,将其插入 + if (todo.length>0) { + core.events.insertAction(todo,x,y); + } + + // 如果已有事件正在处理中 + if (core.status.event.id == null) { + core.continueAutomaticRoute(); + } + else { + core.clearContinueAutomaticRoute(); + } + if (core.isset(callback)) callback(); + +}, +////// 开一个门后触发的事件 ////// +"afterOpenDoor" : function(doorId,x,y,callback) { + // 开一个门后触发的事件 + + var todo = []; + if (core.isset(x) && core.isset(y)) { + var event = core.floors[core.status.floorId].afterOpenDoor[x+","+y]; + if (core.isset(event)) { + core.unshift(todo, event); + } + } + + if (todo.length>0) { + core.events.insertAction(todo,x,y); + } + + if (core.status.event.id == null) { + core.continueAutomaticRoute(); + } + else { + core.clearContinueAutomaticRoute(); + } + if (core.isset(callback)) callback(); +}, +////// 改变亮灯之后,可以触发的事件 ////// +"afterChangeLight" : function(x,y) { + // 改变亮灯之后,可以触发的事件 + +}, +////// 推箱子后的事件 ////// +"afterPushBox" : function () { + // 推箱子后的事件 + + var noBoxLeft = function () { + // 地图上是否还存在未推到的箱子,如果不存在则返回true,存在则返回false + for (var i=0;i