V2.0 to Master

V2.0 to Master
This commit is contained in:
Zhang Chen 2018-03-14 00:41:52 +08:00 committed by GitHub
commit c163327379
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
178 changed files with 16273 additions and 8136 deletions

1
.gitignore vendored
View File

@ -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

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MarkdownExportedFiles">
<htmlFiles />
<imageFiles />
<otherFiles />
</component>
</project>

View File

@ -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事件

View File

@ -0,0 +1,21 @@
MIT License
Copyright (C) 2017 by Marijn Haverbeke <marijnh@gmail.com> 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.

File diff suppressed because one or more lines are too long

View File

@ -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; }

184
_server/README.md Normal file
View File

@ -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
渲染成<select>,选项为数组eval(evalstr)['values']
$input(evalstr)$end
渲染成<input>
$textarea(evalstr)$end
渲染成<textarea>
默认选项为$textarea()$end
// ]
```
### editor_blockly.js
把选定`id_`的事件用blockly编辑
``` js
editor_blockly.import(id_);
```
把文本区域的代码转换成图块
``` js
editor_blockly.parse();
```
### editor_multi.js
用[CodeMirror](https://github.com/codemirror/CodeMirror) 实现有高亮的多行文本编辑
编辑选定`id_`的文本域
``` js
editor_multi.import(id_)
```
编辑blockly方块的特定域
``` js
editor_multi.multiLineEdit(value,b,f,callback)
```
### fs.js
模仿node的fs模块提供如下api,与`启动服务.exe`配合为js提供文件读写功能
``` js
fs.readFile('file.in','utf-8',callback)
//读文本文件
//callback:function(err, data)
//data:字符串
fs.readFile('file.in','base64',callback)
//读二进制文件
//callback:function(err, data)
//data:base64字符串
fs.writeFile('file.out', data ,'utf-8', callback)
//写文本文件
//callback:function(err)
//data:字符串
fs.writeFile('file.out', data ,'base64', callback)
//写二进制文件
//callback:function(err)
//data:base64字符串
fs.readdir(path, callback)
//callback:function(err, data)
//path:支持"/"做分隔符
//data:[filename1,filename2,..] filename是字符串,只包含文件不包含目录
//所有参数不允许缺省
```
## z-index
目前主体部分使用了 0-15,75,100
blockly使用 200 ,多行文本编辑器使用 300

File diff suppressed because one or more lines are too long

177
_server/blockly/LICENSE Normal file
View File

@ -0,0 +1,177 @@
Apache License
Version 2.0, January 2011
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

File diff suppressed because it is too large Load Diff

21
_server/blockly/NOTICE.md Normal file
View File

@ -0,0 +1,21 @@
# NOTICE
files
`blockly_compressed.js`
`blocks_compressed.js`
`javascript_compressed.js`
`zh-hans.js`
`media/*`
copyed from
https://github.com/google/blockly.git
### diff in blockly code
blocks_compressed.js
line 44 ~ 48
```javascript
// change by zhaouv @ logic_compare output : "Boolean" -> null
colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKYCONTROLS_IF_TOOLTIP_2}",helpUrl:"%{BKY_CONTROLS_IF_HELPURL}",extensions:["controls_if_tooltip"]},{type:"logic_compare",message0:"%1 %2 %3",args0:[{type:"input_value",name:"A"},{type:"field_dropdown",name:"OP",options:[["=","EQ"],["\u2260","NEQ"],["<","LT"],["\u2264","LTE"],[">","GT"],["\u2265","GTE"]]},{type:"input_value",name:"B"}],inputsInline:!0,output:null,colour:"%{BKY_LOGIC_HUE}",helpUrl:"%{BKY_LOGIC_COMPARE_HELPURL}",extensions:["logic_compare",
// change by zhaouv @ logic_operation output,check : "Boolean" -> null
// change by zhaouv @ logic_negate output,check : "Boolean" -> null
"logic_op_tooltip"]},{type:"logic_operation",message0:"%1 %2 %3",args0:[{type:"input_value",name:"A",check:null},{type:"field_dropdown",name:"OP",options:[["%{BKY_LOGIC_OPERATION_AND}","AND"],["%{BKY_LOGIC_OPERATION_OR}","OR"]]},{type:"input_value",name:"B",check:null}],inputsInline:!0,output:null,colour:"%{BKY_LOGIC_HUE}",helpUrl:"%{BKY_LOGIC_OPERATION_HELPURL}",extensions:["logic_op_tooltip"]},{type:"logic_negate",message0:"%{BKY_LOGIC_NEGATE_TITLE}",args0:[{type:"input_value",name:"BOOL",
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,159 @@
// Do not edit this file; automatically generated by build.py.
'use strict';
Blockly.Blocks.colour={};Blockly.Constants={};Blockly.Constants.Colour={};Blockly.Constants.Colour.HUE=20;Blockly.Blocks.colour.HUE=Blockly.Constants.Colour.HUE;
Blockly.defineBlocksWithJsonArray([{type:"colour_picker",message0:"%1",args0:[{type:"field_colour",name:"COLOUR",colour:"#ff0000"}],output:"Colour",colour:"%{BKY_COLOUR_HUE}",helpUrl:"%{BKY_COLOUR_PICKER_HELPURL}",tooltip:"%{BKY_COLOUR_PICKER_TOOLTIP}",extensions:["parent_tooltip_when_inline"]},{type:"colour_random",message0:"%{BKY_COLOUR_RANDOM_TITLE}",output:"Colour",colour:"%{BKY_COLOUR_HUE}",helpUrl:"%{BKY_COLOUR_RANDOM_HELPURL}",tooltip:"%{BKY_COLOUR_RANDOM_TOOLTIP}"},{type:"colour_rgb",message0:"%{BKY_COLOUR_RGB_TITLE} %{BKY_COLOUR_RGB_RED} %1 %{BKY_COLOUR_RGB_GREEN} %2 %{BKY_COLOUR_RGB_BLUE} %3",
args0:[{type:"input_value",name:"RED",check:"Number",align:"RIGHT"},{type:"input_value",name:"GREEN",check:"Number",align:"RIGHT"},{type:"input_value",name:"BLUE",check:"Number",align:"RIGHT"}],output:"Colour",colour:"%{BKY_COLOUR_HUE}",helpUrl:"%{BKY_COLOUR_RGB_HELPURL}",tooltip:"%{BKY_COLOUR_RGB_TOOLTIP}"},{type:"colour_blend",message0:"%{BKY_COLOUR_BLEND_TITLE} %{BKY_COLOUR_BLEND_COLOUR1} %1 %{BKY_COLOUR_BLEND_COLOUR2} %2 %{BKY_COLOUR_BLEND_RATIO} %3",args0:[{type:"input_value",name:"COLOUR1",
check:"Colour",align:"RIGHT"},{type:"input_value",name:"COLOUR2",check:"Colour",align:"RIGHT"},{type:"input_value",name:"RATIO",check:"Number",align:"RIGHT"}],output:"Colour",colour:"%{BKY_COLOUR_HUE}",helpUrl:"%{BKY_COLOUR_BLEND_HELPURL}",tooltip:"%{BKY_COLOUR_BLEND_TOOLTIP}"}]);Blockly.Blocks.lists={};Blockly.Constants.Lists={};Blockly.Constants.Lists.HUE=260;Blockly.Blocks.lists.HUE=Blockly.Constants.Lists.HUE;
Blockly.defineBlocksWithJsonArray([{type:"lists_create_empty",message0:"%{BKY_LISTS_CREATE_EMPTY_TITLE}",output:"Array",colour:"%{BKY_LISTS_HUE}",tooltip:"%{BKY_LISTS_CREATE_EMPTY_TOOLTIP}",helpUrl:"%{BKY_LISTS_CREATE_EMPTY_HELPURL}"},{type:"lists_repeat",message0:"%{BKY_LISTS_REPEAT_TITLE}",args0:[{type:"input_value",name:"ITEM"},{type:"input_value",name:"NUM",check:"Number"}],output:"Array",colour:"%{BKY_LISTS_HUE}",tooltip:"%{BKY_LISTS_REPEAT_TOOLTIP}",helpUrl:"%{BKY_LISTS_REPEAT_HELPURL}"},{type:"lists_reverse",
message0:"%{BKY_LISTS_REVERSE_MESSAGE0}",args0:[{type:"input_value",name:"LIST",check:"Array"}],output:"Array",inputsInline:!0,colour:"%{BKY_LISTS_HUE}",tooltip:"%{BKY_LISTS_REVERSE_TOOLTIP}",helpUrl:"%{BKY_LISTS_REVERSE_HELPURL}"},{type:"lists_isEmpty",message0:"%{BKY_LISTS_ISEMPTY_TITLE}",args0:[{type:"input_value",name:"VALUE",check:["String","Array"]}],output:"Boolean",colour:"%{BKY_LISTS_HUE}",tooltip:"%{BKY_LISTS_ISEMPTY_TOOLTIP}",helpUrl:"%{BKY_LISTS_ISEMPTY_HELPURL}"},{type:"lists_length",
message0:"%{BKY_LISTS_LENGTH_TITLE}",args0:[{type:"input_value",name:"VALUE",check:["String","Array"]}],output:"Number",colour:"%{BKY_LISTS_HUE}",tooltip:"%{BKY_LISTS_LENGTH_TOOLTIP}",helpUrl:"%{BKY_LISTS_LENGTH_HELPURL}"}]);
Blockly.Blocks.lists_create_with={init:function(){this.setHelpUrl(Blockly.Msg.LISTS_CREATE_WITH_HELPURL);this.setColour(Blockly.Blocks.lists.HUE);this.itemCount_=3;this.updateShape_();this.setOutput(!0,"Array");this.setMutator(new Blockly.Mutator(["lists_create_with_item"]));this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_TOOLTIP)},mutationToDom:function(){var a=document.createElement("mutation");a.setAttribute("items",this.itemCount_);return a},domToMutation:function(a){this.itemCount_=parseInt(a.getAttribute("items"),
10);this.updateShape_()},decompose:function(a){var b=a.newBlock("lists_create_with_container");b.initSvg();for(var c=b.getInput("STACK").connection,d=0;d<this.itemCount_;d++){var e=a.newBlock("lists_create_with_item");e.initSvg();c.connect(e.previousConnection);c=e.nextConnection}return b},compose:function(a){var b=a.getInputTargetBlock("STACK");for(a=[];b;)a.push(b.valueConnection_),b=b.nextConnection&&b.nextConnection.targetBlock();for(b=0;b<this.itemCount_;b++){var c=this.getInput("ADD"+b).connection.targetConnection;
c&&-1==a.indexOf(c)&&c.disconnect()}this.itemCount_=a.length;this.updateShape_();for(b=0;b<this.itemCount_;b++)Blockly.Mutator.reconnect(a[b],this,"ADD"+b)},saveConnections:function(a){a=a.getInputTargetBlock("STACK");for(var b=0;a;){var c=this.getInput("ADD"+b);a.valueConnection_=c&&c.connection.targetConnection;b++;a=a.nextConnection&&a.nextConnection.targetBlock()}},updateShape_:function(){this.itemCount_&&this.getInput("EMPTY")?this.removeInput("EMPTY"):this.itemCount_||this.getInput("EMPTY")||
this.appendDummyInput("EMPTY").appendField(Blockly.Msg.LISTS_CREATE_EMPTY_TITLE);for(var a=0;a<this.itemCount_;a++)if(!this.getInput("ADD"+a)){var b=this.appendValueInput("ADD"+a);0==a&&b.appendField(Blockly.Msg.LISTS_CREATE_WITH_INPUT_WITH)}for(;this.getInput("ADD"+a);)this.removeInput("ADD"+a),a++}};
Blockly.Blocks.lists_create_with_container={init:function(){this.setColour(Blockly.Blocks.lists.HUE);this.appendDummyInput().appendField(Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TITLE_ADD);this.appendStatementInput("STACK");this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TOOLTIP);this.contextMenu=!1}};
Blockly.Blocks.lists_create_with_item={init:function(){this.setColour(Blockly.Blocks.lists.HUE);this.appendDummyInput().appendField(Blockly.Msg.LISTS_CREATE_WITH_ITEM_TITLE);this.setPreviousStatement(!0);this.setNextStatement(!0);this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_ITEM_TOOLTIP);this.contextMenu=!1}};
Blockly.Blocks.lists_indexOf={init:function(){var a=[[Blockly.Msg.LISTS_INDEX_OF_FIRST,"FIRST"],[Blockly.Msg.LISTS_INDEX_OF_LAST,"LAST"]];this.setHelpUrl(Blockly.Msg.LISTS_INDEX_OF_HELPURL);this.setColour(Blockly.Blocks.lists.HUE);this.setOutput(!0,"Number");this.appendValueInput("VALUE").setCheck("Array").appendField(Blockly.Msg.LISTS_INDEX_OF_INPUT_IN_LIST);this.appendValueInput("FIND").appendField(new Blockly.FieldDropdown(a),"END");this.setInputsInline(!0);var b=this;this.setTooltip(function(){return Blockly.Msg.LISTS_INDEX_OF_TOOLTIP.replace("%1",
b.workspace.options.oneBasedIndex?"0":"-1")})}};
Blockly.Blocks.lists_getIndex={init:function(){var a=[[Blockly.Msg.LISTS_GET_INDEX_GET,"GET"],[Blockly.Msg.LISTS_GET_INDEX_GET_REMOVE,"GET_REMOVE"],[Blockly.Msg.LISTS_GET_INDEX_REMOVE,"REMOVE"]];this.WHERE_OPTIONS=[[Blockly.Msg.LISTS_GET_INDEX_FROM_START,"FROM_START"],[Blockly.Msg.LISTS_GET_INDEX_FROM_END,"FROM_END"],[Blockly.Msg.LISTS_GET_INDEX_FIRST,"FIRST"],[Blockly.Msg.LISTS_GET_INDEX_LAST,"LAST"],[Blockly.Msg.LISTS_GET_INDEX_RANDOM,"RANDOM"]];this.setHelpUrl(Blockly.Msg.LISTS_GET_INDEX_HELPURL);this.setColour(Blockly.Blocks.lists.HUE);
a=new Blockly.FieldDropdown(a,function(a){this.sourceBlock_.updateStatement_("REMOVE"==a)});this.appendValueInput("VALUE").setCheck("Array").appendField(Blockly.Msg.LISTS_GET_INDEX_INPUT_IN_LIST);this.appendDummyInput().appendField(a,"MODE").appendField("","SPACE");this.appendDummyInput("AT");Blockly.Msg.LISTS_GET_INDEX_TAIL&&this.appendDummyInput("TAIL").appendField(Blockly.Msg.LISTS_GET_INDEX_TAIL);this.setInputsInline(!0);this.setOutput(!0);this.updateAt_(!0);var b=this;this.setTooltip(function(){var a=
b.getFieldValue("MODE"),d=b.getFieldValue("WHERE"),e="";switch(a+" "+d){case "GET FROM_START":case "GET FROM_END":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FROM;break;case "GET FIRST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FIRST;break;case "GET LAST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_LAST;break;case "GET RANDOM":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_RANDOM;break;case "GET_REMOVE FROM_START":case "GET_REMOVE FROM_END":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM;break;case "GET_REMOVE FIRST":e=
Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST;break;case "GET_REMOVE LAST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST;break;case "GET_REMOVE RANDOM":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM;break;case "REMOVE FROM_START":case "REMOVE FROM_END":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM;break;case "REMOVE FIRST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST;break;case "REMOVE LAST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST;break;case "REMOVE RANDOM":e=
Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM}if("FROM_START"==d||"FROM_END"==d)e+=" "+("FROM_START"==d?Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP:Blockly.Msg.LISTS_INDEX_FROM_END_TOOLTIP).replace("%1",b.workspace.options.oneBasedIndex?"#1":"#0");return e})},mutationToDom:function(){var a=document.createElement("mutation");a.setAttribute("statement",!this.outputConnection);var b=this.getInput("AT").type==Blockly.INPUT_VALUE;a.setAttribute("at",b);return a},domToMutation:function(a){var b="true"==
a.getAttribute("statement");this.updateStatement_(b);a="false"!=a.getAttribute("at");this.updateAt_(a)},updateStatement_:function(a){a!=!this.outputConnection&&(this.unplug(!0,!0),a?(this.setOutput(!1),this.setPreviousStatement(!0),this.setNextStatement(!0)):(this.setPreviousStatement(!1),this.setNextStatement(!1),this.setOutput(!0)))},updateAt_:function(a){this.removeInput("AT");this.removeInput("ORDINAL",!0);a?(this.appendValueInput("AT").setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&this.appendDummyInput("ORDINAL").appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX)):
this.appendDummyInput("AT");var b=new Blockly.FieldDropdown(this.WHERE_OPTIONS,function(b){var c="FROM_START"==b||"FROM_END"==b;if(c!=a){var e=this.sourceBlock_;e.updateAt_(c);e.setFieldValue(b,"WHERE");return null}});this.getInput("AT").appendField(b,"WHERE");Blockly.Msg.LISTS_GET_INDEX_TAIL&&this.moveInputBefore("TAIL",null)}};
Blockly.Blocks.lists_setIndex={init:function(){var a=[[Blockly.Msg.LISTS_SET_INDEX_SET,"SET"],[Blockly.Msg.LISTS_SET_INDEX_INSERT,"INSERT"]];this.WHERE_OPTIONS=[[Blockly.Msg.LISTS_GET_INDEX_FROM_START,"FROM_START"],[Blockly.Msg.LISTS_GET_INDEX_FROM_END,"FROM_END"],[Blockly.Msg.LISTS_GET_INDEX_FIRST,"FIRST"],[Blockly.Msg.LISTS_GET_INDEX_LAST,"LAST"],[Blockly.Msg.LISTS_GET_INDEX_RANDOM,"RANDOM"]];this.setHelpUrl(Blockly.Msg.LISTS_SET_INDEX_HELPURL);this.setColour(Blockly.Blocks.lists.HUE);this.appendValueInput("LIST").setCheck("Array").appendField(Blockly.Msg.LISTS_SET_INDEX_INPUT_IN_LIST);
this.appendDummyInput().appendField(new Blockly.FieldDropdown(a),"MODE").appendField("","SPACE");this.appendDummyInput("AT");this.appendValueInput("TO").appendField(Blockly.Msg.LISTS_SET_INDEX_INPUT_TO);this.setInputsInline(!0);this.setPreviousStatement(!0);this.setNextStatement(!0);this.setTooltip(Blockly.Msg.LISTS_SET_INDEX_TOOLTIP);this.updateAt_(!0);var b=this;this.setTooltip(function(){var a=b.getFieldValue("MODE"),d=b.getFieldValue("WHERE"),e="";switch(a+" "+d){case "SET FROM_START":case "SET FROM_END":e=
Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FROM;break;case "SET FIRST":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FIRST;break;case "SET LAST":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_LAST;break;case "SET RANDOM":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_RANDOM;break;case "INSERT FROM_START":case "INSERT FROM_END":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FROM;break;case "INSERT FIRST":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST;break;case "INSERT LAST":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_LAST;
break;case "INSERT RANDOM":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM}if("FROM_START"==d||"FROM_END"==d)e+=" "+Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP.replace("%1",b.workspace.options.oneBasedIndex?"#1":"#0");return e})},mutationToDom:function(){var a=document.createElement("mutation"),b=this.getInput("AT").type==Blockly.INPUT_VALUE;a.setAttribute("at",b);return a},domToMutation:function(a){a="false"!=a.getAttribute("at");this.updateAt_(a)},updateAt_:function(a){this.removeInput("AT");
this.removeInput("ORDINAL",!0);a?(this.appendValueInput("AT").setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&this.appendDummyInput("ORDINAL").appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX)):this.appendDummyInput("AT");var b=new Blockly.FieldDropdown(this.WHERE_OPTIONS,function(b){var c="FROM_START"==b||"FROM_END"==b;if(c!=a){var e=this.sourceBlock_;e.updateAt_(c);e.setFieldValue(b,"WHERE");return null}});this.moveInputBefore("AT","TO");this.getInput("ORDINAL")&&this.moveInputBefore("ORDINAL",
"TO");this.getInput("AT").appendField(b,"WHERE")}};
Blockly.Blocks.lists_getSublist={init:function(){this.WHERE_OPTIONS_1=[[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_START,"FROM_START"],[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_END,"FROM_END"],[Blockly.Msg.LISTS_GET_SUBLIST_START_FIRST,"FIRST"]];this.WHERE_OPTIONS_2=[[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_START,"FROM_START"],[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_END,"FROM_END"],[Blockly.Msg.LISTS_GET_SUBLIST_END_LAST,"LAST"]];this.setHelpUrl(Blockly.Msg.LISTS_GET_SUBLIST_HELPURL);this.setColour(Blockly.Blocks.lists.HUE);
this.appendValueInput("LIST").setCheck("Array").appendField(Blockly.Msg.LISTS_GET_SUBLIST_INPUT_IN_LIST);this.appendDummyInput("AT1");this.appendDummyInput("AT2");Blockly.Msg.LISTS_GET_SUBLIST_TAIL&&this.appendDummyInput("TAIL").appendField(Blockly.Msg.LISTS_GET_SUBLIST_TAIL);this.setInputsInline(!0);this.setOutput(!0,"Array");this.updateAt_(1,!0);this.updateAt_(2,!0);this.setTooltip(Blockly.Msg.LISTS_GET_SUBLIST_TOOLTIP)},mutationToDom:function(){var a=document.createElement("mutation"),b=this.getInput("AT1").type==
Blockly.INPUT_VALUE;a.setAttribute("at1",b);b=this.getInput("AT2").type==Blockly.INPUT_VALUE;a.setAttribute("at2",b);return a},domToMutation:function(a){var b="true"==a.getAttribute("at1");a="true"==a.getAttribute("at2");this.updateAt_(1,b);this.updateAt_(2,a)},updateAt_:function(a,b){this.removeInput("AT"+a);this.removeInput("ORDINAL"+a,!0);b?(this.appendValueInput("AT"+a).setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&this.appendDummyInput("ORDINAL"+a).appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX)):
this.appendDummyInput("AT"+a);var c=new Blockly.FieldDropdown(this["WHERE_OPTIONS_"+a],function(c){var d="FROM_START"==c||"FROM_END"==c;if(d!=b){var f=this.sourceBlock_;f.updateAt_(a,d);f.setFieldValue(c,"WHERE"+a);return null}});this.getInput("AT"+a).appendField(c,"WHERE"+a);1==a&&(this.moveInputBefore("AT1","AT2"),this.getInput("ORDINAL1")&&this.moveInputBefore("ORDINAL1","AT2"));Blockly.Msg.LISTS_GET_SUBLIST_TAIL&&this.moveInputBefore("TAIL",null)}};
Blockly.Blocks.lists_sort={init:function(){this.jsonInit({message0:Blockly.Msg.LISTS_SORT_TITLE,args0:[{type:"field_dropdown",name:"TYPE",options:[[Blockly.Msg.LISTS_SORT_TYPE_NUMERIC,"NUMERIC"],[Blockly.Msg.LISTS_SORT_TYPE_TEXT,"TEXT"],[Blockly.Msg.LISTS_SORT_TYPE_IGNORECASE,"IGNORE_CASE"]]},{type:"field_dropdown",name:"DIRECTION",options:[[Blockly.Msg.LISTS_SORT_ORDER_ASCENDING,"1"],[Blockly.Msg.LISTS_SORT_ORDER_DESCENDING,"-1"]]},{type:"input_value",name:"LIST",check:"Array"}],output:"Array",colour:Blockly.Blocks.lists.HUE,
tooltip:Blockly.Msg.LISTS_SORT_TOOLTIP,helpUrl:Blockly.Msg.LISTS_SORT_HELPURL})}};
Blockly.Blocks.lists_split={init:function(){var a=this,b=new Blockly.FieldDropdown([[Blockly.Msg.LISTS_SPLIT_LIST_FROM_TEXT,"SPLIT"],[Blockly.Msg.LISTS_SPLIT_TEXT_FROM_LIST,"JOIN"]],function(b){a.updateType_(b)});this.setHelpUrl(Blockly.Msg.LISTS_SPLIT_HELPURL);this.setColour(Blockly.Blocks.lists.HUE);this.appendValueInput("INPUT").setCheck("String").appendField(b,"MODE");this.appendValueInput("DELIM").setCheck("String").appendField(Blockly.Msg.LISTS_SPLIT_WITH_DELIMITER);this.setInputsInline(!0);
this.setOutput(!0,"Array");this.setTooltip(function(){var b=a.getFieldValue("MODE");if("SPLIT"==b)return Blockly.Msg.LISTS_SPLIT_TOOLTIP_SPLIT;if("JOIN"==b)return Blockly.Msg.LISTS_SPLIT_TOOLTIP_JOIN;throw"Unknown mode: "+b;})},updateType_:function(a){"SPLIT"==a?(this.outputConnection.setCheck("Array"),this.getInput("INPUT").setCheck("String")):(this.outputConnection.setCheck("String"),this.getInput("INPUT").setCheck("Array"))},mutationToDom:function(){var a=document.createElement("mutation");a.setAttribute("mode",
this.getFieldValue("MODE"));return a},domToMutation:function(a){this.updateType_(a.getAttribute("mode"))}};Blockly.Blocks.logic={};Blockly.Constants.Logic={};Blockly.Constants.Logic.HUE=210;Blockly.Blocks.logic.HUE=Blockly.Constants.Logic.HUE;
Blockly.defineBlocksWithJsonArray([{type:"logic_boolean",message0:"%1",args0:[{type:"field_dropdown",name:"BOOL",options:[["%{BKY_LOGIC_BOOLEAN_TRUE}","TRUE"],["%{BKY_LOGIC_BOOLEAN_FALSE}","FALSE"]]}],output:"Boolean",colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKY_LOGIC_BOOLEAN_TOOLTIP}",helpUrl:"%{BKY_LOGIC_BOOLEAN_HELPURL}"},{type:"controls_if",message0:"%{BKY_CONTROLS_IF_MSG_IF} %1",args0:[{type:"input_value",name:"IF0",check:"Boolean"}],message1:"%{BKY_CONTROLS_IF_MSG_THEN} %1",args1:[{type:"input_statement",
name:"DO0"}],previousStatement:null,nextStatement:null,colour:"%{BKY_LOGIC_HUE}",helpUrl:"%{BKY_CONTROLS_IF_HELPURL}",mutator:"controls_if_mutator",extensions:["controls_if_tooltip"]},{type:"controls_ifelse",message0:"%{BKY_CONTROLS_IF_MSG_IF} %1",args0:[{type:"input_value",name:"IF0",check:"Boolean"}],message1:"%{BKY_CONTROLS_IF_MSG_THEN} %1",args1:[{type:"input_statement",name:"DO0"}],message2:"%{BKY_CONTROLS_IF_MSG_ELSE} %1",args2:[{type:"input_statement",name:"ELSE"}],previousStatement:null,nextStatement:null,
// change by zhaouv @ logic_compare output : "Boolean" -> null
colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKYCONTROLS_IF_TOOLTIP_2}",helpUrl:"%{BKY_CONTROLS_IF_HELPURL}",extensions:["controls_if_tooltip"]},{type:"logic_compare",message0:"%1 %2 %3",args0:[{type:"input_value",name:"A"},{type:"field_dropdown",name:"OP",options:[["=","EQ"],["\u2260","NEQ"],["<","LT"],["\u2264","LTE"],[">","GT"],["\u2265","GTE"]]},{type:"input_value",name:"B"}],inputsInline:!0,output:null,colour:"%{BKY_LOGIC_HUE}",helpUrl:"%{BKY_LOGIC_COMPARE_HELPURL}",extensions:["logic_compare",
// change by zhaouv @ logic_operation output,check : "Boolean" -> null
// change by zhaouv @ logic_negate output,check : "Boolean" -> null
"logic_op_tooltip"]},{type:"logic_operation",message0:"%1 %2 %3",args0:[{type:"input_value",name:"A",check:null},{type:"field_dropdown",name:"OP",options:[["%{BKY_LOGIC_OPERATION_AND}","AND"],["%{BKY_LOGIC_OPERATION_OR}","OR"]]},{type:"input_value",name:"B",check:null}],inputsInline:!0,output:null,colour:"%{BKY_LOGIC_HUE}",helpUrl:"%{BKY_LOGIC_OPERATION_HELPURL}",extensions:["logic_op_tooltip"]},{type:"logic_negate",message0:"%{BKY_LOGIC_NEGATE_TITLE}",args0:[{type:"input_value",name:"BOOL",
check:null}],output:null,colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKY_LOGIC_NEGATE_TOOLTIP}",helpUrl:"%{BKY_LOGIC_NEGATE_HELPURL}"},{type:"logic_null",message0:"%{BKY_LOGIC_NULL}",output:null,colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKY_LOGIC_NULL_TOOLTIP}",helpUrl:"%{BKY_LOGIC_NULL_HELPURL}"},{type:"logic_ternary",message0:"%{BKY_LOGIC_TERNARY_CONDITION} %1",args0:[{type:"input_value",name:"IF",check:"Boolean"}],message1:"%{BKY_LOGIC_TERNARY_IF_TRUE} %1",args1:[{type:"input_value",name:"THEN"}],
message2:"%{BKY_LOGIC_TERNARY_IF_FALSE} %1",args2:[{type:"input_value",name:"ELSE"}],output:null,colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKY_LOGIC_TERNARY_TOOLTIP}",helpUrl:"%{BKY_LOGIC_TERNARY_HELPURL}",extensions:["logic_ternary"]}]);
Blockly.defineBlocksWithJsonArray([{type:"controls_if_if",message0:"%{BKY_CONTROLS_IF_IF_TITLE_IF}",nextStatement:null,enableContextMenu:!1,colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKY_CONTROLS_IF_IF_TOOLTIP}"},{type:"controls_if_elseif",message0:"%{BKY_CONTROLS_IF_ELSEIF_TITLE_ELSEIF}",previousStatement:null,nextStatement:null,enableContextMenu:!1,colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKY_CONTROLS_IF_ELSEIF_TOOLTIP}"},{type:"controls_if_else",message0:"%{BKY_CONTROLS_IF_ELSE_TITLE_ELSE}",previousStatement:null,
enableContextMenu:!1,colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKY_CONTROLS_IF_ELSE_TOOLTIP}"}]);Blockly.Constants.Logic.TOOLTIPS_BY_OP={EQ:"%{BKY_LOGIC_COMPARE_TOOLTIP_EQ}",NEQ:"%{BKY_LOGIC_COMPARE_TOOLTIP_NEQ}",LT:"%{BKY_LOGIC_COMPARE_TOOLTIP_LT}",LTE:"%{BKY_LOGIC_COMPARE_TOOLTIP_LTE}",GT:"%{BKY_LOGIC_COMPARE_TOOLTIP_GT}",GTE:"%{BKY_LOGIC_COMPARE_TOOLTIP_GTE}",AND:"%{BKY_LOGIC_OPERATION_TOOLTIP_AND}",OR:"%{BKY_LOGIC_OPERATION_TOOLTIP_OR}"};
Blockly.Extensions.register("logic_op_tooltip",Blockly.Extensions.buildTooltipForDropdown("OP",Blockly.Constants.Logic.TOOLTIPS_BY_OP));
Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN={elseifCount_:0,elseCount_:0,mutationToDom:function(){if(!this.elseifCount_&&!this.elseCount_)return null;var a=document.createElement("mutation");this.elseifCount_&&a.setAttribute("elseif",this.elseifCount_);this.elseCount_&&a.setAttribute("else",1);return a},domToMutation:function(a){this.elseifCount_=parseInt(a.getAttribute("elseif"),10)||0;this.elseCount_=parseInt(a.getAttribute("else"),10)||0;this.updateShape_()},decompose:function(a){var b=a.newBlock("controls_if_if");
b.initSvg();for(var c=b.nextConnection,d=1;d<=this.elseifCount_;d++){var e=a.newBlock("controls_if_elseif");e.initSvg();c.connect(e.previousConnection);c=e.nextConnection}this.elseCount_&&(a=a.newBlock("controls_if_else"),a.initSvg(),c.connect(a.previousConnection));return b},compose:function(a){var b=a.nextConnection.targetBlock();this.elseCount_=this.elseifCount_=0;a=[null];for(var c=[null],d=null;b;){switch(b.type){case "controls_if_elseif":this.elseifCount_++;a.push(b.valueConnection_);c.push(b.statementConnection_);
break;case "controls_if_else":this.elseCount_++;d=b.statementConnection_;break;default:throw"Unknown block type.";}b=b.nextConnection&&b.nextConnection.targetBlock()}this.updateShape_();for(b=1;b<=this.elseifCount_;b++)Blockly.Mutator.reconnect(a[b],this,"IF"+b),Blockly.Mutator.reconnect(c[b],this,"DO"+b);Blockly.Mutator.reconnect(d,this,"ELSE")},saveConnections:function(a){a=a.nextConnection.targetBlock();for(var b=1;a;){switch(a.type){case "controls_if_elseif":var c=this.getInput("IF"+b),d=this.getInput("DO"+
b);a.valueConnection_=c&&c.connection.targetConnection;a.statementConnection_=d&&d.connection.targetConnection;b++;break;case "controls_if_else":d=this.getInput("ELSE");a.statementConnection_=d&&d.connection.targetConnection;break;default:throw"Unknown block type.";}a=a.nextConnection&&a.nextConnection.targetBlock()}},updateShape_:function(){this.getInput("ELSE")&&this.removeInput("ELSE");for(var a=1;this.getInput("IF"+a);)this.removeInput("IF"+a),this.removeInput("DO"+a),a++;for(a=1;a<=this.elseifCount_;a++)this.appendValueInput("IF"+
a).setCheck("Boolean").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF),this.appendStatementInput("DO"+a).appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN);this.elseCount_&&this.appendStatementInput("ELSE").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSE)}};Blockly.Extensions.registerMutator("controls_if_mutator",Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN,null,["controls_if_elseif","controls_if_else"]);
Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION=function(){this.setTooltip(function(){if(this.elseifCount_||this.elseCount_){if(!this.elseifCount_&&this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_2;if(this.elseifCount_&&!this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_3;if(this.elseifCount_&&this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_4}else return Blockly.Msg.CONTROLS_IF_TOOLTIP_1;return""}.bind(this))};Blockly.Extensions.register("controls_if_tooltip",Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION);
Blockly.Constants.Logic.fixLogicCompareRtlOpLabels=function(){var a={LT:"\u200f<\u200f",LTE:"\u200f\u2264\u200f",GT:"\u200f>\u200f",GTE:"\u200f\u2265\u200f"},b=this.getField("OP");if(b){b=b.getOptions();for(var c=0;c<b.length;++c){var d=b[c],e=a[d[1]];goog.isString(d[0])&&e&&(d[0]=e)}}};
Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN={prevBlocks_:[null,null],onchange:function(a){var b=this.getInputTargetBlock("A"),c=this.getInputTargetBlock("B");if(b&&c&&!b.outputConnection.checkType_(c.outputConnection)){Blockly.Events.setGroup(a.group);for(a=0;a<this.prevBlocks_.length;a++){var d=this.prevBlocks_[a];if(d===b||d===c)d.unplug(),d.bumpNeighbours_()}Blockly.Events.setGroup(!1)}this.prevBlocks_[0]=b;this.prevBlocks_[1]=c}};
Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION=function(){this.RTL&&Blockly.Constants.Logic.fixLogicCompareRtlOpLabels.apply(this);this.mixin(Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN)};Blockly.Extensions.register("logic_compare",Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION);
Blockly.Constants.Logic.LOGIC_TERNARY_ONCHANGE_MIXIN={prevParentConnection_:null,onchange:function(a){var b=this.getInputTargetBlock("THEN"),c=this.getInputTargetBlock("ELSE"),d=this.outputConnection.targetConnection;if((b||c)&&d)for(var e=0;2>e;e++){var f=1==e?b:c;f&&!f.outputConnection.checkType_(d)&&(Blockly.Events.setGroup(a.group),d===this.prevParentConnection_?(this.unplug(),d.getSourceBlock().bumpNeighbours_()):(f.unplug(),f.bumpNeighbours_()),Blockly.Events.setGroup(!1))}this.prevParentConnection_=
d}};Blockly.Extensions.registerMixin("logic_ternary",Blockly.Constants.Logic.LOGIC_TERNARY_ONCHANGE_MIXIN);Blockly.Blocks.loops={};Blockly.Constants.Loops={};Blockly.Constants.Loops.HUE=120;Blockly.Blocks.loops.HUE=Blockly.Constants.Loops.HUE;
Blockly.defineBlocksWithJsonArray([{type:"controls_repeat_ext",message0:"%{BKY_CONTROLS_REPEAT_TITLE}",args0:[{type:"input_value",name:"TIMES",check:"Number"}],message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",args1:[{type:"input_statement",name:"DO"}],previousStatement:null,nextStatement:null,colour:"%{BKY_LOOPS_HUE}",tooltip:"%{BKY_CONTROLS_REPEAT_TOOLTIP}",helpUrl:"%{BKY_CONTROLS_REPEAT_HELPURL}"},{type:"controls_repeat",message0:"%{BKY_CONTROLS_REPEAT_TITLE}",args0:[{type:"field_number",name:"TIMES",
value:10,min:0,precision:1}],message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",args1:[{type:"input_statement",name:"DO"}],previousStatement:null,nextStatement:null,colour:"%{BKY_LOOPS_HUE}",tooltip:"%{BKY_CONTROLS_REPEAT_TOOLTIP}",helpUrl:"%{BKY_CONTROLS_REPEAT_HELPURL}"},{type:"controls_whileUntil",message0:"%1 %2",args0:[{type:"field_dropdown",name:"MODE",options:[["%{BKY_CONTROLS_WHILEUNTIL_OPERATOR_WHILE}","WHILE"],["%{BKY_CONTROLS_WHILEUNTIL_OPERATOR_UNTIL}","UNTIL"]]},{type:"input_value",name:"BOOL",
check:"Boolean"}],message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",args1:[{type:"input_statement",name:"DO"}],previousStatement:null,nextStatement:null,colour:"%{BKY_LOOPS_HUE}",helpUrl:"%{BKY_CONTROLS_WHILEUNTIL_HELPURL}",extensions:["controls_whileUntil_tooltip"]},{type:"controls_for",message0:"%{BKY_CONTROLS_FOR_TITLE}",args0:[{type:"field_variable",name:"VAR",variable:null},{type:"input_value",name:"FROM",check:"Number",align:"RIGHT"},{type:"input_value",name:"TO",check:"Number",align:"RIGHT"},{type:"input_value",
name:"BY",check:"Number",align:"RIGHT"}],message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",args1:[{type:"input_statement",name:"DO"}],inputsInline:!0,previousStatement:null,nextStatement:null,colour:"%{BKY_LOOPS_HUE}",helpUrl:"%{BKY_CONTROLS_FOR_HELPURL}",extensions:["contextMenu_newGetVariableBlock","controls_for_tooltip"]},{type:"controls_forEach",message0:"%{BKY_CONTROLS_FOREACH_TITLE}",args0:[{type:"field_variable",name:"VAR",variable:null},{type:"input_value",name:"LIST",check:"Array"}],message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",
args1:[{type:"input_statement",name:"DO"}],previousStatement:null,nextStatement:null,colour:"%{BKY_LOOPS_HUE}",helpUrl:"%{BKY_CONTROLS_FOREACH_HELPURL}",extensions:["contextMenu_newGetVariableBlock","controls_forEach_tooltip"]},{type:"controls_flow_statements",message0:"%1",args0:[{type:"field_dropdown",name:"FLOW",options:[["%{BKY_CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK}","BREAK"],["%{BKY_CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE}","CONTINUE"]]}],previousStatement:null,colour:"%{BKY_LOOPS_HUE}",
helpUrl:"%{BKY_CONTROLS_FLOW_STATEMENTS_HELPURL}",extensions:["controls_flow_tooltip","controls_flow_in_loop_check"]}]);Blockly.Constants.Loops.WHILE_UNTIL_TOOLTIPS={WHILE:"%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_WHILE}",UNTIL:"%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL}"};Blockly.Extensions.register("controls_whileUntil_tooltip",Blockly.Extensions.buildTooltipForDropdown("MODE",Blockly.Constants.Loops.WHILE_UNTIL_TOOLTIPS));
Blockly.Constants.Loops.BREAK_CONTINUE_TOOLTIPS={BREAK:"%{BKY_CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK}",CONTINUE:"%{BKY_CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE}"};Blockly.Extensions.register("controls_flow_tooltip",Blockly.Extensions.buildTooltipForDropdown("FLOW",Blockly.Constants.Loops.BREAK_CONTINUE_TOOLTIPS));
Blockly.Constants.Loops.CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN={customContextMenu:function(a){var b=this.getFieldValue("VAR");if(!this.isCollapsed()&&null!=b){var c={enabled:!0};c.text=Blockly.Msg.VARIABLES_SET_CREATE_GET.replace("%1",b);b=goog.dom.createDom("field",null,b);b.setAttribute("name","VAR");b=goog.dom.createDom("block",null,b);b.setAttribute("type","variables_get");c.callback=Blockly.ContextMenu.callbackFactory(this,b);a.push(c)}}};
Blockly.Extensions.registerMixin("contextMenu_newGetVariableBlock",Blockly.Constants.Loops.CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN);Blockly.Extensions.register("controls_for_tooltip",Blockly.Extensions.buildTooltipWithFieldValue("%{BKY_CONTROLS_FOR_TOOLTIP}","VAR"));Blockly.Extensions.register("controls_forEach_tooltip",Blockly.Extensions.buildTooltipWithFieldValue("%{BKY_CONTROLS_FOREACH_TOOLTIP}","VAR"));
Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN={LOOP_TYPES:["controls_repeat","controls_repeat_ext","controls_forEach","controls_for","controls_whileUntil"],onchange:function(){if(this.workspace.isDragging&&!this.workspace.isDragging()){var a=!1,b=this;do{if(-1!=this.LOOP_TYPES.indexOf(b.type)){a=!0;break}b=b.getSurroundParent()}while(b);a?(this.setWarningText(null),this.isInFlyout||this.setDisabled(!1)):(this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING),this.isInFlyout||
this.getInheritedDisabled()||this.setDisabled(!0))}}};Blockly.Extensions.registerMixin("controls_flow_in_loop_check",Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN);Blockly.Blocks.math={};Blockly.Constants.Math={};Blockly.Constants.Math.HUE=230;Blockly.Blocks.math.HUE=Blockly.Constants.Math.HUE;
Blockly.defineBlocksWithJsonArray([{type:"math_number",message0:"%1",args0:[{type:"field_number",name:"NUM",value:0}],output:"Number",colour:"%{BKY_MATH_HUE}",helpUrl:"%{BKY_MATH_NUMBER_HELPURL}",tooltip:"%{BKY_MATH_NUMBER_TOOLTIP}",extensions:["parent_tooltip_when_inline"]},{type:"math_arithmetic",message0:"%1 %2 %3",args0:[{type:"input_value",name:"A",check:"Number"},{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_ADDITION_SYMBOL}","ADD"],["%{BKY_MATH_SUBTRACTION_SYMBOL}","MINUS"],["%{BKY_MATH_MULTIPLICATION_SYMBOL}",
"MULTIPLY"],["%{BKY_MATH_DIVISION_SYMBOL}","DIVIDE"],["%{BKY_MATH_POWER_SYMBOL}","POWER"]]},{type:"input_value",name:"B",check:"Number"}],inputsInline:!0,output:"Number",colour:"%{BKY_MATH_HUE}",helpUrl:"%{BKY_MATH_ARITHMETIC_HELPURL}",extensions:["math_op_tooltip"]},{type:"math_single",message0:"%1 %2",args0:[{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_SINGLE_OP_ROOT}","ROOT"],["%{BKY_MATH_SINGLE_OP_ABSOLUTE}","ABS"],["-","NEG"],["ln","LN"],["log10","LOG10"],["e^","EXP"],["10^","POW10"]]},
{type:"input_value",name:"NUM",check:"Number"}],output:"Number",colour:"%{BKY_MATH_HUE}",helpUrl:"%{BKY_MATH_SINGLE_HELPURL}",extensions:["math_op_tooltip"]},{type:"math_trig",message0:"%1 %2",args0:[{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_TRIG_SIN}","SIN"],["%{BKY_MATH_TRIG_COS}","COS"],["%{BKY_MATH_TRIG_TAN}","TAN"],["%{BKY_MATH_TRIG_ASIN}","ASIN"],["%{BKY_MATH_TRIG_ACOS}","ACOS"],["%{BKY_MATH_TRIG_ATAN}","ATAN"]]},{type:"input_value",name:"NUM",check:"Number"}],output:"Number",colour:"%{BKY_MATH_HUE}",
helpUrl:"%{BKY_MATH_TRIG_HELPURL}",extensions:["math_op_tooltip"]},{type:"math_constant",message0:"%1",args0:[{type:"field_dropdown",name:"CONSTANT",options:[["\u03c0","PI"],["e","E"],["\u03c6","GOLDEN_RATIO"],["sqrt(2)","SQRT2"],["sqrt(\u00bd)","SQRT1_2"],["\u221e","INFINITY"]]}],output:"Number",colour:"%{BKY_MATH_HUE}",tooltip:"%{BKY_MATH_CONSTANT_TOOLTIP}",helpUrl:"%{BKY_MATH_CONSTANT_HELPURL}"},{type:"math_number_property",message0:"%1 %2",args0:[{type:"input_value",name:"NUMBER_TO_CHECK",check:"Number"},
{type:"field_dropdown",name:"PROPERTY",options:[["%{BKY_MATH_IS_EVEN}","EVEN"],["%{BKY_MATH_IS_ODD}","ODD"],["%{BKY_MATH_IS_PRIME}","PRIME"],["%{BKY_MATH_IS_WHOLE}","WHOLE"],["%{BKY_MATH_IS_POSITIVE}","POSITIVE"],["%{BKY_MATH_IS_NEGATIVE}","NEGATIVE"],["%{BKY_MATH_IS_DIVISIBLE_BY}","DIVISIBLE_BY"]]}],inputsInline:!0,output:"Boolean",colour:"%{BKY_MATH_HUE}",tooltip:"%{BKY_MATH_IS_TOOLTIP}",mutator:"math_is_divisibleby_mutator"},{type:"math_change",message0:"%{BKY_MATH_CHANGE_TITLE}",args0:[{type:"field_variable",
name:"VAR",variable:"%{BKY_MATH_CHANGE_TITLE_ITEM}"},{type:"input_value",name:"DELTA",check:"Number"}],previousStatement:null,nextStatement:null,colour:"%{BKY_VARIABLES_HUE}",helpUrl:"%{BKY_MATH_CHANGE_HELPURL}",extensions:["math_change_tooltip"]},{type:"math_round",message0:"%1 %2",args0:[{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_ROUND_OPERATOR_ROUND}","ROUND"],["%{BKY_MATH_ROUND_OPERATOR_ROUNDUP}","ROUNDUP"],["%{BKY_MATH_ROUND_OPERATOR_ROUNDDOWN}","ROUNDDOWN"]]},{type:"input_value",
name:"NUM",check:"Number"}],output:"Number",colour:"%{BKY_MATH_HUE}",helpUrl:"%{BKY_MATH_ROUND_HELPURL}",tooltip:"%{BKY_MATH_ROUND_TOOLTIP}"},{type:"math_on_list",message0:"%1 %2",args0:[{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_ONLIST_OPERATOR_SUM}","SUM"],["%{BKY_MATH_ONLIST_OPERATOR_MIN}","MIN"],["%{BKY_MATH_ONLIST_OPERATOR_MAX}","MAX"],["%{BKY_MATH_ONLIST_OPERATOR_AVERAGE}","AVERAGE"],["%{BKY_MATH_ONLIST_OPERATOR_MEDIAN}","MEDIAN"],["%{BKY_MATH_ONLIST_OPERATOR_MODE}","MODE"],["%{BKY_MATH_ONLIST_OPERATOR_STD_DEV}",
"STD_DEV"],["%{BKY_MATH_ONLIST_OPERATOR_RANDOM}","RANDOM"]]},{type:"input_value",name:"LIST",check:"Array"}],output:"Number",colour:"%{BKY_MATH_HUE}",helpUrl:"%{BKY_MATH_ONLIST_HELPURL}",mutator:"math_modes_of_list_mutator",extensions:["math_op_tooltip"]},{type:"math_modulo",message0:"%{BKY_MATH_MODULO_TITLE}",args0:[{type:"input_value",name:"DIVIDEND",check:"Number"},{type:"input_value",name:"DIVISOR",check:"Number"}],inputsInline:!0,output:"Number",colour:"%{BKY_MATH_HUE}",tooltip:"%{BKY_MATH_MODULO_TOOLTIP}",
helpUrl:"%{BKY_MATH_MODULO_HELPURL}"},{type:"math_constrain",message0:"%{BKY_MATH_CONSTRAIN_TITLE}",args0:[{type:"input_value",name:"VALUE",check:"Number"},{type:"input_value",name:"LOW",check:"Number"},{type:"input_value",name:"HIGH",check:"Number"}],inputsInline:!0,output:"Number",colour:"%{BKY_MATH_HUE}",tooltip:"%{BKY_MATH_CONSTRAIN_TOOLTIP}",helpUrl:"%{BKY_MATH_CONSTRAIN_HELPURL}"},{type:"math_random_int",message0:"%{BKY_MATH_RANDOM_INT_TITLE}",args0:[{type:"input_value",name:"FROM",check:"Number"},
{type:"input_value",name:"TO",check:"Number"}],inputsInline:!0,output:"Number",colour:"%{BKY_MATH_HUE}",tooltip:"%{BKY_MATH_RANDOM_INT_TOOLTIP}",helpUrl:"%{BKY_MATH_RANDOM_INT_HELPURL}"},{type:"math_random_float",message0:"%{BKY_MATH_RANDOM_FLOAT_TITLE_RANDOM}",output:"Number",colour:"%{BKY_MATH_HUE}",tooltip:"%{BKY_MATH_RANDOM_FLOAT_TOOLTIP}",helpUrl:"%{BKY_MATH_RANDOM_FLOAT_HELPURL}"}]);
Blockly.Constants.Math.TOOLTIPS_BY_OP={ADD:"%{BKY_MATH_ARITHMETIC_TOOLTIP_ADD}",MINUS:"%{BKY_MATH_ARITHMETIC_TOOLTIP_MINUS}",MULTIPLY:"%{BKY_MATH_ARITHMETIC_TOOLTIP_MULTIPLY}",DIVIDE:"%{BKY_MATH_ARITHMETIC_TOOLTIP_DIVIDE}",POWER:"%{BKY_MATH_ARITHMETIC_TOOLTIP_POWER}",ROOT:"%{BKY_MATH_SINGLE_TOOLTIP_ROOT}",ABS:"%{BKY_MATH_SINGLE_TOOLTIP_ABS}",NEG:"%{BKY_MATH_SINGLE_TOOLTIP_NEG}",LN:"%{BKY_MATH_SINGLE_TOOLTIP_LN}",LOG10:"%{BKY_MATH_SINGLE_TOOLTIP_LOG10}",EXP:"%{BKY_MATH_SINGLE_TOOLTIP_EXP}",POW10:"%{BKY_MATH_SINGLE_TOOLTIP_POW10}",
SIN:"%{BKY_MATH_TRIG_TOOLTIP_SIN}",COS:"%{BKY_MATH_TRIG_TOOLTIP_COS}",TAN:"%{BKY_MATH_TRIG_TOOLTIP_TAN}",ASIN:"%{BKY_MATH_TRIG_TOOLTIP_ASIN}",ACOS:"%{BKY_MATH_TRIG_TOOLTIP_ACOS}",ATAN:"%{BKY_MATH_TRIG_TOOLTIP_ATAN}",SUM:"%{BKY_MATH_ONLIST_TOOLTIP_SUM}",MIN:"%{BKY_MATH_ONLIST_TOOLTIP_MIN}",MAX:"%{BKY_MATH_ONLIST_TOOLTIP_MAX}",AVERAGE:"%{BKY_MATH_ONLIST_TOOLTIP_AVERAGE}",MEDIAN:"%{BKY_MATH_ONLIST_TOOLTIP_MEDIAN}",MODE:"%{BKY_MATH_ONLIST_TOOLTIP_MODE}",STD_DEV:"%{BKY_MATH_ONLIST_TOOLTIP_STD_DEV}",RANDOM:"%{BKY_MATH_ONLIST_TOOLTIP_RANDOM}"};
Blockly.Extensions.register("math_op_tooltip",Blockly.Extensions.buildTooltipForDropdown("OP",Blockly.Constants.Math.TOOLTIPS_BY_OP));
Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN={mutationToDom:function(){var a=document.createElement("mutation"),b="DIVISIBLE_BY"==this.getFieldValue("PROPERTY");a.setAttribute("divisor_input",b);return a},domToMutation:function(a){a="true"==a.getAttribute("divisor_input");this.updateShape_(a)},updateShape_:function(a){var b=this.getInput("DIVISOR");a?b||this.appendValueInput("DIVISOR").setCheck("Number"):b&&this.removeInput("DIVISOR")}};
Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION=function(){this.getField("PROPERTY").setValidator(function(a){this.sourceBlock_.updateShape_("DIVISIBLE_BY"==a)})};Blockly.Extensions.registerMutator("math_is_divisibleby_mutator",Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN,Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION);Blockly.Constants.Math.CHANGE_TOOLTIP_EXTENSION=function(){this.setTooltip(function(){return Blockly.Msg.MATH_CHANGE_TOOLTIP.replace("%1",this.getFieldValue("VAR"))}.bind(this))};
Blockly.Extensions.register("math_change_tooltip",Blockly.Extensions.buildTooltipWithFieldValue("%{BKY_MATH_CHANGE_TOOLTIP}","VAR"));Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN={updateType_:function(a){"MODE"==a?this.outputConnection.setCheck("Array"):this.outputConnection.setCheck("Number")},mutationToDom:function(){var a=document.createElement("mutation");a.setAttribute("op",this.getFieldValue("OP"));return a},domToMutation:function(a){this.updateType_(a.getAttribute("op"))}};
Blockly.Constants.Math.LIST_MODES_MUTATOR_EXTENSION=function(){this.getField("OP").setValidator(function(a){this.updateType_(a)}.bind(this))};Blockly.Extensions.registerMutator("math_modes_of_list_mutator",Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN,Blockly.Constants.Math.LIST_MODES_MUTATOR_EXTENSION);Blockly.Blocks.procedures={};Blockly.Blocks.procedures.HUE=290;
Blockly.Blocks.procedures_defnoreturn={init:function(){var a=new Blockly.FieldTextInput("",Blockly.Procedures.rename);a.setSpellcheck(!1);this.appendDummyInput().appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE).appendField(a,"NAME").appendField("","PARAMS");this.setMutator(new Blockly.Mutator(["procedures_mutatorarg"]));(this.workspace.options.comments||this.workspace.options.parentWorkspace&&this.workspace.options.parentWorkspace.options.comments)&&Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT&&
this.setCommentText(Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT);this.setColour(Blockly.Blocks.procedures.HUE);this.setTooltip(Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP);this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL);this.arguments_=[];this.setStatements_(!0);this.statementConnection_=null},setStatements_:function(a){this.hasStatements_!==a&&(a?(this.appendStatementInput("STACK").appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_DO),this.getInput("RETURN")&&this.moveInputBefore("STACK",
"RETURN")):this.removeInput("STACK",!0),this.hasStatements_=a)},updateParams_:function(){for(var a=!1,b={},c=0;c<this.arguments_.length;c++){if(b["arg_"+this.arguments_[c].toLowerCase()]){a=!0;break}b["arg_"+this.arguments_[c].toLowerCase()]=!0}a?this.setWarningText(Blockly.Msg.PROCEDURES_DEF_DUPLICATE_WARNING):this.setWarningText(null);a="";this.arguments_.length&&(a=Blockly.Msg.PROCEDURES_BEFORE_PARAMS+" "+this.arguments_.join(", "));Blockly.Events.disable();try{this.setFieldValue(a,"PARAMS")}finally{Blockly.Events.enable()}},
mutationToDom:function(a){var b=document.createElement("mutation");a&&b.setAttribute("name",this.getFieldValue("NAME"));for(var c=0;c<this.arguments_.length;c++){var d=document.createElement("arg");d.setAttribute("name",this.arguments_[c]);a&&this.paramIds_&&d.setAttribute("paramId",this.paramIds_[c]);b.appendChild(d)}this.hasStatements_||b.setAttribute("statements","false");return b},domToMutation:function(a){this.arguments_=[];for(var b=0,c;c=a.childNodes[b];b++)"arg"==c.nodeName.toLowerCase()&&
this.arguments_.push(c.getAttribute("name"));this.updateParams_();Blockly.Procedures.mutateCallers(this);this.setStatements_("false"!==a.getAttribute("statements"))},decompose:function(a){var b=a.newBlock("procedures_mutatorcontainer");b.initSvg();this.getInput("RETURN")?b.setFieldValue(this.hasStatements_?"TRUE":"FALSE","STATEMENTS"):b.getInput("STATEMENT_INPUT").setVisible(!1);for(var c=b.getInput("STACK").connection,d=0;d<this.arguments_.length;d++){var e=a.newBlock("procedures_mutatorarg");e.initSvg();
e.setFieldValue(this.arguments_[d],"NAME");e.oldLocation=d;c.connect(e.previousConnection);c=e.nextConnection}Blockly.Procedures.mutateCallers(this);return b},compose:function(a){this.arguments_=[];this.paramIds_=[];for(var b=a.getInputTargetBlock("STACK");b;)this.arguments_.push(b.getFieldValue("NAME")),this.paramIds_.push(b.id),b=b.nextConnection&&b.nextConnection.targetBlock();this.updateParams_();Blockly.Procedures.mutateCallers(this);a=a.getFieldValue("STATEMENTS");if(null!==a&&(a="TRUE"==a,
this.hasStatements_!=a))if(a)this.setStatements_(!0),Blockly.Mutator.reconnect(this.statementConnection_,this,"STACK"),this.statementConnection_=null;else{a=this.getInput("STACK").connection;if(this.statementConnection_=a.targetConnection)a=a.targetBlock(),a.unplug(),a.bumpNeighbours_();this.setStatements_(!1)}},getProcedureDef:function(){return[this.getFieldValue("NAME"),this.arguments_,!1]},getVars:function(){return this.arguments_},renameVar:function(a,b){for(var c=!1,d=0;d<this.arguments_.length;d++)Blockly.Names.equals(a,
this.arguments_[d])&&(this.arguments_[d]=b,c=!0);if(c&&(this.updateParams_(),this.mutator.isVisible())){c=this.mutator.workspace_.getAllBlocks();d=0;for(var e;e=c[d];d++)"procedures_mutatorarg"==e.type&&Blockly.Names.equals(a,e.getFieldValue("NAME"))&&e.setFieldValue(b,"NAME")}},customContextMenu:function(a){var b={enabled:!0},c=this.getFieldValue("NAME");b.text=Blockly.Msg.PROCEDURES_CREATE_DO.replace("%1",c);var d=goog.dom.createDom("mutation");d.setAttribute("name",c);for(var e=0;e<this.arguments_.length;e++)c=
goog.dom.createDom("arg"),c.setAttribute("name",this.arguments_[e]),d.appendChild(c);d=goog.dom.createDom("block",null,d);d.setAttribute("type",this.callType_);b.callback=Blockly.ContextMenu.callbackFactory(this,d);a.push(b);if(!this.isCollapsed())for(e=0;e<this.arguments_.length;e++)b={enabled:!0},c=this.arguments_[e],b.text=Blockly.Msg.VARIABLES_SET_CREATE_GET.replace("%1",c),d=goog.dom.createDom("field",null,c),d.setAttribute("name","VAR"),d=goog.dom.createDom("block",null,d),d.setAttribute("type",
"variables_get"),b.callback=Blockly.ContextMenu.callbackFactory(this,d),a.push(b)},callType_:"procedures_callnoreturn"};
Blockly.Blocks.procedures_defreturn={init:function(){var a=new Blockly.FieldTextInput("",Blockly.Procedures.rename);a.setSpellcheck(!1);this.appendDummyInput().appendField(Blockly.Msg.PROCEDURES_DEFRETURN_TITLE).appendField(a,"NAME").appendField("","PARAMS");this.appendValueInput("RETURN").setAlign(Blockly.ALIGN_RIGHT).appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);this.setMutator(new Blockly.Mutator(["procedures_mutatorarg"]));(this.workspace.options.comments||this.workspace.options.parentWorkspace&&
this.workspace.options.parentWorkspace.options.comments)&&Blockly.Msg.PROCEDURES_DEFRETURN_COMMENT&&this.setCommentText(Blockly.Msg.PROCEDURES_DEFRETURN_COMMENT);this.setColour(Blockly.Blocks.procedures.HUE);this.setTooltip(Blockly.Msg.PROCEDURES_DEFRETURN_TOOLTIP);this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFRETURN_HELPURL);this.arguments_=[];this.setStatements_(!0);this.statementConnection_=null},setStatements_:Blockly.Blocks.procedures_defnoreturn.setStatements_,updateParams_:Blockly.Blocks.procedures_defnoreturn.updateParams_,
mutationToDom:Blockly.Blocks.procedures_defnoreturn.mutationToDom,domToMutation:Blockly.Blocks.procedures_defnoreturn.domToMutation,decompose:Blockly.Blocks.procedures_defnoreturn.decompose,compose:Blockly.Blocks.procedures_defnoreturn.compose,getProcedureDef:function(){return[this.getFieldValue("NAME"),this.arguments_,!0]},getVars:Blockly.Blocks.procedures_defnoreturn.getVars,renameVar:Blockly.Blocks.procedures_defnoreturn.renameVar,customContextMenu:Blockly.Blocks.procedures_defnoreturn.customContextMenu,
callType_:"procedures_callreturn"};Blockly.Blocks.procedures_mutatorcontainer={init:function(){this.appendDummyInput().appendField(Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TITLE);this.appendStatementInput("STACK");this.appendDummyInput("STATEMENT_INPUT").appendField(Blockly.Msg.PROCEDURES_ALLOW_STATEMENTS).appendField(new Blockly.FieldCheckbox("TRUE"),"STATEMENTS");this.setColour(Blockly.Blocks.procedures.HUE);this.setTooltip(Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TOOLTIP);this.contextMenu=!1}};
Blockly.Blocks.procedures_mutatorarg={init:function(){var a=new Blockly.FieldTextInput("x",this.validator_);this.appendDummyInput().appendField(Blockly.Msg.PROCEDURES_MUTATORARG_TITLE).appendField(a,"NAME");this.setPreviousStatement(!0);this.setNextStatement(!0);this.setColour(Blockly.Blocks.procedures.HUE);this.setTooltip(Blockly.Msg.PROCEDURES_MUTATORARG_TOOLTIP);this.contextMenu=!1;a.onFinishEditing_=this.createNewVar_;a.onFinishEditing_("x")},validator_:function(a){return(a=a.replace(/[\s\xa0]+/g,
" ").replace(/^ | $/g,""))||null},createNewVar_:function(a){var b=this.sourceBlock_;if(b&&b.workspace&&b.workspace.options&&b.workspace.options.parentWorkspace){b=b.workspace.options.parentWorkspace;var c=b.getVariable(a);c&&c.name!==a?b.renameVariableById(c.getId(),a):b.createVariable(a)}}};
Blockly.Blocks.procedures_callnoreturn={init:function(){this.appendDummyInput("TOPROW").appendField(this.id,"NAME");this.setPreviousStatement(!0);this.setNextStatement(!0);this.setColour(Blockly.Blocks.procedures.HUE);this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLNORETURN_HELPURL);this.arguments_=[];this.quarkConnections_={};this.quarkIds_=null},getProcedureCall:function(){return this.getFieldValue("NAME")},renameProcedure:function(a,b){Blockly.Names.equals(a,this.getProcedureCall())&&(this.setFieldValue(b,
"NAME"),this.setTooltip((this.outputConnection?Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP:Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP).replace("%1",b)))},setProcedureParameters_:function(a,b){var c=Blockly.Procedures.getDefinition(this.getProcedureCall(),this.workspace),d=c&&c.mutator&&c.mutator.isVisible();d||(this.quarkConnections_={},this.quarkIds_=null);if(b)if(goog.array.equals(this.arguments_,a))this.quarkIds_=b;else{if(b.length!=a.length)throw"Error: paramNames and paramIds must be the same length.";
this.setCollapsed(!1);this.quarkIds_||(this.quarkConnections_={},a.join("\n")==this.arguments_.join("\n")?this.quarkIds_=b:this.quarkIds_=[]);c=this.rendered;this.rendered=!1;for(var e=0;e<this.arguments_.length;e++){var f=this.getInput("ARG"+e);f&&(f=f.connection.targetConnection,this.quarkConnections_[this.quarkIds_[e]]=f,d&&f&&-1==b.indexOf(this.quarkIds_[e])&&(f.disconnect(),f.getSourceBlock().bumpNeighbours_()))}this.arguments_=[].concat(a);this.updateShape_();if(this.quarkIds_=b)for(e=0;e<this.arguments_.length;e++)d=
this.quarkIds_[e],d in this.quarkConnections_&&(f=this.quarkConnections_[d],Blockly.Mutator.reconnect(f,this,"ARG"+e)||delete this.quarkConnections_[d]);(this.rendered=c)&&this.render()}},updateShape_:function(){for(var a=0;a<this.arguments_.length;a++){var b=this.getField("ARGNAME"+a);if(b){Blockly.Events.disable();try{b.setValue(this.arguments_[a])}finally{Blockly.Events.enable()}}else b=new Blockly.FieldLabel(this.arguments_[a]),this.appendValueInput("ARG"+a).setAlign(Blockly.ALIGN_RIGHT).appendField(b,
"ARGNAME"+a).init()}for(;this.getInput("ARG"+a);)this.removeInput("ARG"+a),a++;if(a=this.getInput("TOPROW"))this.arguments_.length?this.getField("WITH")||(a.appendField(Blockly.Msg.PROCEDURES_CALL_BEFORE_PARAMS,"WITH"),a.init()):this.getField("WITH")&&a.removeField("WITH")},mutationToDom:function(){var a=document.createElement("mutation");a.setAttribute("name",this.getProcedureCall());for(var b=0;b<this.arguments_.length;b++){var c=document.createElement("arg");c.setAttribute("name",this.arguments_[b]);
a.appendChild(c)}return a},domToMutation:function(a){var b=a.getAttribute("name");this.renameProcedure(this.getProcedureCall(),b);b=[];for(var c=[],d=0,e;e=a.childNodes[d];d++)"arg"==e.nodeName.toLowerCase()&&(b.push(e.getAttribute("name")),c.push(e.getAttribute("paramId")));this.setProcedureParameters_(b,c)},renameVar:function(a,b){for(var c=0;c<this.arguments_.length;c++)Blockly.Names.equals(a,this.arguments_[c])&&(this.arguments_[c]=b,this.getField("ARGNAME"+c).setValue(b))},onchange:function(a){if(this.workspace&&
!this.workspace.isFlyout)if(a.type==Blockly.Events.BLOCK_CREATE&&-1!=a.ids.indexOf(this.id)){var b=this.getProcedureCall();b=Blockly.Procedures.getDefinition(b,this.workspace);!b||b.type==this.defType_&&JSON.stringify(b.arguments_)==JSON.stringify(this.arguments_)||(b=null);if(!b){Blockly.Events.setGroup(a.group);a=goog.dom.createDom("xml");b=goog.dom.createDom("block");b.setAttribute("type",this.defType_);var c=this.getRelativeToSurfaceXY(),d=c.y+2*Blockly.SNAP_RADIUS;b.setAttribute("x",c.x+Blockly.SNAP_RADIUS*
(this.RTL?-1:1));b.setAttribute("y",d);c=this.mutationToDom();b.appendChild(c);c=goog.dom.createDom("field");c.setAttribute("name","NAME");c.appendChild(document.createTextNode(this.getProcedureCall()));b.appendChild(c);a.appendChild(b);Blockly.Xml.domToWorkspace(a,this.workspace);Blockly.Events.setGroup(!1)}}else a.type==Blockly.Events.BLOCK_DELETE&&(b=this.getProcedureCall(),b=Blockly.Procedures.getDefinition(b,this.workspace),b||(Blockly.Events.setGroup(a.group),this.dispose(!0,!1),Blockly.Events.setGroup(!1)))},
customContextMenu:function(a){var b={enabled:!0};b.text=Blockly.Msg.PROCEDURES_HIGHLIGHT_DEF;var c=this.getProcedureCall(),d=this.workspace;b.callback=function(){var a=Blockly.Procedures.getDefinition(c,d);a&&a.select()};a.push(b)},defType_:"procedures_defnoreturn"};
Blockly.Blocks.procedures_callreturn={init:function(){this.appendDummyInput("TOPROW").appendField("","NAME");this.setOutput(!0);this.setColour(Blockly.Blocks.procedures.HUE);this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLRETURN_HELPURL);this.arguments_=[];this.quarkConnections_={};this.quarkIds_=null},getProcedureCall:Blockly.Blocks.procedures_callnoreturn.getProcedureCall,renameProcedure:Blockly.Blocks.procedures_callnoreturn.renameProcedure,setProcedureParameters_:Blockly.Blocks.procedures_callnoreturn.setProcedureParameters_,
updateShape_:Blockly.Blocks.procedures_callnoreturn.updateShape_,mutationToDom:Blockly.Blocks.procedures_callnoreturn.mutationToDom,domToMutation:Blockly.Blocks.procedures_callnoreturn.domToMutation,renameVar:Blockly.Blocks.procedures_callnoreturn.renameVar,onchange:Blockly.Blocks.procedures_callnoreturn.onchange,customContextMenu:Blockly.Blocks.procedures_callnoreturn.customContextMenu,defType_:"procedures_defreturn"};
Blockly.Blocks.procedures_ifreturn={init:function(){this.appendValueInput("CONDITION").setCheck("Boolean").appendField(Blockly.Msg.CONTROLS_IF_MSG_IF);this.appendValueInput("VALUE").appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);this.setInputsInline(!0);this.setPreviousStatement(!0);this.setNextStatement(!0);this.setColour(Blockly.Blocks.procedures.HUE);this.setTooltip(Blockly.Msg.PROCEDURES_IFRETURN_TOOLTIP);this.setHelpUrl(Blockly.Msg.PROCEDURES_IFRETURN_HELPURL);this.hasReturnValue_=!0},
mutationToDom:function(){var a=document.createElement("mutation");a.setAttribute("value",Number(this.hasReturnValue_));return a},domToMutation:function(a){this.hasReturnValue_=1==a.getAttribute("value");this.hasReturnValue_||(this.removeInput("VALUE"),this.appendDummyInput("VALUE").appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN))},onchange:function(){if(this.workspace.isDragging&&!this.workspace.isDragging()){var a=!1,b=this;do{if(-1!=this.FUNCTION_TYPES.indexOf(b.type)){a=!0;break}b=b.getSurroundParent()}while(b);
a?("procedures_defnoreturn"==b.type&&this.hasReturnValue_?(this.removeInput("VALUE"),this.appendDummyInput("VALUE").appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN),this.hasReturnValue_=!1):"procedures_defreturn"!=b.type||this.hasReturnValue_||(this.removeInput("VALUE"),this.appendValueInput("VALUE").appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN),this.hasReturnValue_=!0),this.setWarningText(null),this.isInFlyout||this.setDisabled(!1)):(this.setWarningText(Blockly.Msg.PROCEDURES_IFRETURN_WARNING),
this.isInFlyout||this.getInheritedDisabled()||this.setDisabled(!0))}},FUNCTION_TYPES:["procedures_defnoreturn","procedures_defreturn"]};Blockly.Blocks.texts={};Blockly.Constants.Text={};Blockly.Constants.Text.HUE=160;Blockly.Blocks.texts.HUE=Blockly.Constants.Text.HUE;
Blockly.defineBlocksWithJsonArray([{type:"text",message0:"%1",args0:[{type:"field_input",name:"TEXT",text:""}],output:"String",colour:"%{BKY_TEXTS_HUE}",helpUrl:"%{BKY_TEXT_TEXT_HELPURL}",tooltip:"%{BKY_TEXT_TEXT_TOOLTIP}",extensions:["text_quotes","parent_tooltip_when_inline"]},{type:"text_join",message0:"",output:"String",colour:"%{BKY_TEXTS_HUE}",helpUrl:"%{BKY_TEXT_JOIN_HELPURL}",tooltip:"%{BKY_TEXT_JOIN_TOOLTIP}",mutator:"text_join_mutator"},{type:"text_create_join_container",message0:"%{BKY_TEXT_CREATE_JOIN_TITLE_JOIN} %1 %2",
args0:[{type:"input_dummy"},{type:"input_statement",name:"STACK"}],colour:"%{BKY_TEXTS_HUE}",tooltip:"%{BKY_TEXT_CREATE_JOIN_TOOLTIP}",enableContextMenu:!1},{type:"text_create_join_item",message0:"%{BKY_TEXT_CREATE_JOIN_ITEM_TITLE_ITEM}",previousStatement:null,nextStatement:null,colour:"%{BKY_TEXTS_HUE}",tooltip:"{%BKY_TEXT_CREATE_JOIN_ITEM_TOOLTIP}",enableContextMenu:!1},{type:"text_append",message0:"%{BKY_TEXT_APPEND_TITLE}",args0:[{type:"field_variable",name:"VAR",variable:"%{BKY_TEXT_APPEND_VARIABLE}"},
{type:"input_value",name:"TEXT"}],previousStatement:null,nextStatement:null,colour:"%{BKY_TEXTS_HUE}",extensions:["text_append_tooltip"]},{type:"text_length",message0:"%{BKY_TEXT_LENGTH_TITLE}",args0:[{type:"input_value",name:"VALUE",check:["String","Array"]}],output:"Number",colour:"%{BKY_TEXTS_HUE}",tooltip:"%{BKY_TEXT_LENGTH_TOOLTIP}",helpUrl:"%{BKY_TEXT_LENGTH_HELPURL}"},{type:"text_isEmpty",message0:"%{BKY_TEXT_ISEMPTY_TITLE}",args0:[{type:"input_value",name:"VALUE",check:["String","Array"]}],
output:"Boolean",colour:"%{BKY_TEXTS_HUE}",tooltip:"%{BKY_TEXT_ISEMPTY_TOOLTIP}",helpUrl:"%{BKY_TEXT_ISEMPTY_HELPURL}"},{type:"text_indexOf",message0:"%{BKY_TEXT_INDEXOF_TITLE}",args0:[{type:"input_value",name:"VALUE",check:"String"},{type:"field_dropdown",name:"END",options:[["%{BKY_TEXT_INDEXOF_OPERATOR_FIRST}","FIRST"],["%{BKY_TEXT_INDEXOF_OPERATOR_LAST}","LAST"]]},{type:"input_value",name:"FIND",check:"String"}],output:"Number",colour:"%{BKY_TEXTS_HUE}",helpUrl:"%{BKY_TEXT_INDEXOF_HELPURL}",inputsInline:!0,
extensions:["text_indexOf_tooltip"]},{type:"text_charAt",message0:"%{BKY_TEXT_CHARAT_TITLE}",args0:[{type:"input_value",name:"VALUE",check:"String"},{type:"field_dropdown",name:"WHERE",options:[["%{BKY_TEXT_CHARAT_FROM_START}","FROM_START"],["%{BKY_TEXT_CHARAT_FROM_END}","FROM_END"],["%{BKY_TEXT_CHARAT_FIRST}","FIRST"],["%{BKY_TEXT_CHARAT_LAST}","LAST"],["%{BKY_TEXT_CHARAT_RANDOM}","RANDOM"]]}],output:"String",colour:"%{BKY_TEXTS_HUE}",helpUrl:"%{BKY_TEXT_CHARAT_HELPURL}",inputsInline:!0,mutator:"text_charAt_mutator"}]);
Blockly.Blocks.text_getSubstring={init:function(){this.WHERE_OPTIONS_1=[[Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_START,"FROM_START"],[Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_END,"FROM_END"],[Blockly.Msg.TEXT_GET_SUBSTRING_START_FIRST,"FIRST"]];this.WHERE_OPTIONS_2=[[Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_START,"FROM_START"],[Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_END,"FROM_END"],[Blockly.Msg.TEXT_GET_SUBSTRING_END_LAST,"LAST"]];this.setHelpUrl(Blockly.Msg.TEXT_GET_SUBSTRING_HELPURL);this.setColour(Blockly.Blocks.texts.HUE);
this.appendValueInput("STRING").setCheck("String").appendField(Blockly.Msg.TEXT_GET_SUBSTRING_INPUT_IN_TEXT);this.appendDummyInput("AT1");this.appendDummyInput("AT2");Blockly.Msg.TEXT_GET_SUBSTRING_TAIL&&this.appendDummyInput("TAIL").appendField(Blockly.Msg.TEXT_GET_SUBSTRING_TAIL);this.setInputsInline(!0);this.setOutput(!0,"String");this.updateAt_(1,!0);this.updateAt_(2,!0);this.setTooltip(Blockly.Msg.TEXT_GET_SUBSTRING_TOOLTIP)},mutationToDom:function(){var a=document.createElement("mutation"),
b=this.getInput("AT1").type==Blockly.INPUT_VALUE;a.setAttribute("at1",b);b=this.getInput("AT2").type==Blockly.INPUT_VALUE;a.setAttribute("at2",b);return a},domToMutation:function(a){var b="true"==a.getAttribute("at1");a="true"==a.getAttribute("at2");this.updateAt_(1,b);this.updateAt_(2,a)},updateAt_:function(a,b){this.removeInput("AT"+a);this.removeInput("ORDINAL"+a,!0);b?(this.appendValueInput("AT"+a).setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&this.appendDummyInput("ORDINAL"+a).appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX)):
this.appendDummyInput("AT"+a);2==a&&Blockly.Msg.TEXT_GET_SUBSTRING_TAIL&&(this.removeInput("TAIL",!0),this.appendDummyInput("TAIL").appendField(Blockly.Msg.TEXT_GET_SUBSTRING_TAIL));var c=new Blockly.FieldDropdown(this["WHERE_OPTIONS_"+a],function(c){var d="FROM_START"==c||"FROM_END"==c;if(d!=b){var f=this.sourceBlock_;f.updateAt_(a,d);f.setFieldValue(c,"WHERE"+a);return null}});this.getInput("AT"+a).appendField(c,"WHERE"+a);1==a&&this.moveInputBefore("AT1","AT2")}};
Blockly.Blocks.text_changeCase={init:function(){var a=[[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_UPPERCASE,"UPPERCASE"],[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_LOWERCASE,"LOWERCASE"],[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_TITLECASE,"TITLECASE"]];this.setHelpUrl(Blockly.Msg.TEXT_CHANGECASE_HELPURL);this.setColour(Blockly.Blocks.texts.HUE);this.appendValueInput("TEXT").setCheck("String").appendField(new Blockly.FieldDropdown(a),"CASE");this.setOutput(!0,"String");this.setTooltip(Blockly.Msg.TEXT_CHANGECASE_TOOLTIP)}};
Blockly.Blocks.text_trim={init:function(){var a=[[Blockly.Msg.TEXT_TRIM_OPERATOR_BOTH,"BOTH"],[Blockly.Msg.TEXT_TRIM_OPERATOR_LEFT,"LEFT"],[Blockly.Msg.TEXT_TRIM_OPERATOR_RIGHT,"RIGHT"]];this.setHelpUrl(Blockly.Msg.TEXT_TRIM_HELPURL);this.setColour(Blockly.Blocks.texts.HUE);this.appendValueInput("TEXT").setCheck("String").appendField(new Blockly.FieldDropdown(a),"MODE");this.setOutput(!0,"String");this.setTooltip(Blockly.Msg.TEXT_TRIM_TOOLTIP)}};
Blockly.Blocks.text_print={init:function(){this.jsonInit({message0:Blockly.Msg.TEXT_PRINT_TITLE,args0:[{type:"input_value",name:"TEXT"}],previousStatement:null,nextStatement:null,colour:Blockly.Blocks.texts.HUE,tooltip:Blockly.Msg.TEXT_PRINT_TOOLTIP,helpUrl:Blockly.Msg.TEXT_PRINT_HELPURL})}};
Blockly.Blocks.text_prompt_ext={init:function(){var a=[[Blockly.Msg.TEXT_PROMPT_TYPE_TEXT,"TEXT"],[Blockly.Msg.TEXT_PROMPT_TYPE_NUMBER,"NUMBER"]];this.setHelpUrl(Blockly.Msg.TEXT_PROMPT_HELPURL);this.setColour(Blockly.Blocks.texts.HUE);var b=this;a=new Blockly.FieldDropdown(a,function(a){b.updateType_(a)});this.appendValueInput("TEXT").appendField(a,"TYPE");this.setOutput(!0,"String");this.setTooltip(function(){return"TEXT"==b.getFieldValue("TYPE")?Blockly.Msg.TEXT_PROMPT_TOOLTIP_TEXT:Blockly.Msg.TEXT_PROMPT_TOOLTIP_NUMBER})},
updateType_:function(a){this.outputConnection.setCheck("NUMBER"==a?"Number":"String")},mutationToDom:function(){var a=document.createElement("mutation");a.setAttribute("type",this.getFieldValue("TYPE"));return a},domToMutation:function(a){this.updateType_(a.getAttribute("type"))}};
Blockly.Blocks.text_prompt={init:function(){this.mixin(Blockly.Constants.Text.QUOTE_IMAGE_MIXIN);var a=[[Blockly.Msg.TEXT_PROMPT_TYPE_TEXT,"TEXT"],[Blockly.Msg.TEXT_PROMPT_TYPE_NUMBER,"NUMBER"]],b=this;this.setHelpUrl(Blockly.Msg.TEXT_PROMPT_HELPURL);this.setColour(Blockly.Blocks.texts.HUE);a=new Blockly.FieldDropdown(a,function(a){b.updateType_(a)});this.appendDummyInput().appendField(a,"TYPE").appendField(this.newQuote_(!0)).appendField(new Blockly.FieldTextInput(""),"TEXT").appendField(this.newQuote_(!1));
this.setOutput(!0,"String");this.setTooltip(function(){return"TEXT"==b.getFieldValue("TYPE")?Blockly.Msg.TEXT_PROMPT_TOOLTIP_TEXT:Blockly.Msg.TEXT_PROMPT_TOOLTIP_NUMBER})},updateType_:Blockly.Blocks.text_prompt_ext.updateType_,mutationToDom:Blockly.Blocks.text_prompt_ext.mutationToDom,domToMutation:Blockly.Blocks.text_prompt_ext.domToMutation};
Blockly.Blocks.text_count={init:function(){this.jsonInit({message0:Blockly.Msg.TEXT_COUNT_MESSAGE0,args0:[{type:"input_value",name:"SUB",check:"String"},{type:"input_value",name:"TEXT",check:"String"}],output:"Number",inputsInline:!0,colour:Blockly.Blocks.texts.HUE,tooltip:Blockly.Msg.TEXT_COUNT_TOOLTIP,helpUrl:Blockly.Msg.TEXT_COUNT_HELPURL})}};
Blockly.Blocks.text_replace={init:function(){this.jsonInit({message0:Blockly.Msg.TEXT_REPLACE_MESSAGE0,args0:[{type:"input_value",name:"FROM",check:"String"},{type:"input_value",name:"TO",check:"String"},{type:"input_value",name:"TEXT",check:"String"}],output:"String",inputsInline:!0,colour:Blockly.Blocks.texts.HUE,tooltip:Blockly.Msg.TEXT_REPLACE_TOOLTIP,helpUrl:Blockly.Msg.TEXT_REPLACE_HELPURL})}};
Blockly.Blocks.text_reverse={init:function(){this.jsonInit({message0:Blockly.Msg.TEXT_REVERSE_MESSAGE0,args0:[{type:"input_value",name:"TEXT",check:"String"}],output:"String",inputsInline:!0,colour:Blockly.Blocks.texts.HUE,tooltip:Blockly.Msg.TEXT_REVERSE_TOOLTIP,helpUrl:Blockly.Msg.TEXT_REVERSE_HELPURL})}};
Blockly.Constants.Text.QUOTE_IMAGE_MIXIN={QUOTE_IMAGE_LEFT_DATAURI:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAQAAAAqJXdxAAAAn0lEQVQI1z3OMa5BURSF4f/cQhAKjUQhuQmFNwGJEUi0RKN5rU7FHKhpjEH3TEMtkdBSCY1EIv8r7nFX9e29V7EBAOvu7RPjwmWGH/VuF8CyN9/OAdvqIXYLvtRaNjx9mMTDyo+NjAN1HNcl9ZQ5oQMM3dgDUqDo1l8DzvwmtZN7mnD+PkmLa+4mhrxVA9fRowBWmVBhFy5gYEjKMfz9AylsaRRgGzvZAAAAAElFTkSuQmCC",QUOTE_IMAGE_RIGHT_DATAURI:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAQAAAAqJXdxAAAAqUlEQVQI1z3KvUpCcRiA8ef9E4JNHhI0aFEacm1o0BsI0Slx8wa8gLauoDnoBhq7DcfWhggONDmJJgqCPA7neJ7p934EOOKOnM8Q7PDElo/4x4lFb2DmuUjcUzS3URnGib9qaPNbuXvBO3sGPHJDRG6fGVdMSeWDP2q99FQdFrz26Gu5Tq7dFMzUvbXy8KXeAj57cOklgA+u1B5AoslLtGIHQMaCVnwDnADZIFIrXsoXrgAAAABJRU5ErkJggg==",
QUOTE_IMAGE_WIDTH:12,QUOTE_IMAGE_HEIGHT:12,quoteField_:function(a){for(var b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)if(a==e.name){c.insertFieldAt(d,this.newQuote_(!0));c.insertFieldAt(d+2,this.newQuote_(!1));return}console.warn('field named "'+a+'" not found in '+this.toDevString())},newQuote_:function(a){a=this.RTL?!a:a;return new Blockly.FieldImage(a?this.QUOTE_IMAGE_LEFT_DATAURI:this.QUOTE_IMAGE_RIGHT_DATAURI,this.QUOTE_IMAGE_WIDTH,this.QUOTE_IMAGE_HEIGHT,a?"\u201c":"\u201d")}};
Blockly.Constants.Text.TEXT_QUOTES_EXTENSION=function(){this.mixin(Blockly.Constants.Text.QUOTE_IMAGE_MIXIN);this.quoteField_("TEXT")};
Blockly.Constants.Text.TEXT_JOIN_MUTATOR_MIXIN={mutationToDom:function(){var a=document.createElement("mutation");a.setAttribute("items",this.itemCount_);return a},domToMutation:function(a){this.itemCount_=parseInt(a.getAttribute("items"),10);this.updateShape_()},decompose:function(a){var b=a.newBlock("text_create_join_container");b.initSvg();for(var c=b.getInput("STACK").connection,d=0;d<this.itemCount_;d++){var e=a.newBlock("text_create_join_item");e.initSvg();c.connect(e.previousConnection);c=
e.nextConnection}return b},compose:function(a){var b=a.getInputTargetBlock("STACK");for(a=[];b;)a.push(b.valueConnection_),b=b.nextConnection&&b.nextConnection.targetBlock();for(b=0;b<this.itemCount_;b++){var c=this.getInput("ADD"+b).connection.targetConnection;c&&-1==a.indexOf(c)&&c.disconnect()}this.itemCount_=a.length;this.updateShape_();for(b=0;b<this.itemCount_;b++)Blockly.Mutator.reconnect(a[b],this,"ADD"+b)},saveConnections:function(a){a=a.getInputTargetBlock("STACK");for(var b=0;a;){var c=
this.getInput("ADD"+b);a.valueConnection_=c&&c.connection.targetConnection;b++;a=a.nextConnection&&a.nextConnection.targetBlock()}},updateShape_:function(){this.itemCount_&&this.getInput("EMPTY")?this.removeInput("EMPTY"):this.itemCount_||this.getInput("EMPTY")||this.appendDummyInput("EMPTY").appendField(this.newQuote_(!0)).appendField(this.newQuote_(!1));for(var a=0;a<this.itemCount_;a++)if(!this.getInput("ADD"+a)){var b=this.appendValueInput("ADD"+a);0==a&&b.appendField(Blockly.Msg.TEXT_JOIN_TITLE_CREATEWITH)}for(;this.getInput("ADD"+
a);)this.removeInput("ADD"+a),a++}};Blockly.Constants.Text.TEXT_JOIN_EXTENSION=function(){this.mixin(Blockly.Constants.Text.QUOTE_IMAGE_MIXIN);this.itemCount_=2;this.updateShape_();this.setMutator(new Blockly.Mutator(["text_create_join_item"]))};Blockly.Constants.Text.TEXT_APPEND_TOOLTIP_EXTENSION=function(){var a=this;this.setTooltip(function(){return Blockly.Msg.TEXT_APPEND_TOOLTIP?Blockly.Msg.TEXT_APPEND_TOOLTIP.replace("%1",a.getFieldValue("VAR")):""})};
Blockly.Constants.Text.TEXT_INDEXOF_TOOLTIP_EXTENSION=function(){var a=this;this.setTooltip(function(){return Blockly.Msg.TEXT_INDEXOF_TOOLTIP.replace("%1",a.workspace.options.oneBasedIndex?"0":"-1")})};
Blockly.Constants.Text.TEXT_CHARAT_MUTATOR_MIXIN={mutationToDom:function(){var a=document.createElement("mutation");a.setAttribute("at",!!this.isAt_);return a},domToMutation:function(a){a="false"!=a.getAttribute("at");this.updateAt_(a)},updateAt_:function(a){this.removeInput("AT",!0);this.removeInput("ORDINAL",!0);a&&(this.appendValueInput("AT").setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&this.appendDummyInput("ORDINAL").appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX));Blockly.Msg.TEXT_CHARAT_TAIL&&
(this.removeInput("TAIL",!0),this.appendDummyInput("TAIL").appendField(Blockly.Msg.TEXT_CHARAT_TAIL));this.isAt_=a}};
Blockly.Constants.Text.TEXT_CHARAT_EXTENSION=function(){this.getField("WHERE").setValidator(function(a){var b="FROM_START"==a||"FROM_END"==a;if(b!=this.isAt_){var d=this.sourceBlock_;d.updateAt_(b);d.setFieldValue(a,"WHERE");return null}});this.updateAt_(!0);var a=this;this.setTooltip(function(){var b=a.getFieldValue("WHERE"),c=Blockly.Msg.TEXT_CHARAT_TOOLTIP;("FROM_START"==b||"FROM_END"==b)&&(b="FROM_START"==b?Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP:Blockly.Msg.LISTS_INDEX_FROM_END_TOOLTIP)&&
(c+=" "+b.replace("%1",a.workspace.options.oneBasedIndex?"#1":"#0"));return c})};Blockly.Extensions.register("text_indexOf_tooltip",Blockly.Constants.Text.TEXT_INDEXOF_TOOLTIP_EXTENSION);Blockly.Extensions.register("text_quotes",Blockly.Constants.Text.TEXT_QUOTES_EXTENSION);Blockly.Extensions.register("text_append_tooltip",Blockly.Constants.Text.TEXT_APPEND_TOOLTIP_EXTENSION);Blockly.Extensions.registerMutator("text_join_mutator",Blockly.Constants.Text.TEXT_JOIN_MUTATOR_MIXIN,Blockly.Constants.Text.TEXT_JOIN_EXTENSION);
Blockly.Extensions.registerMutator("text_charAt_mutator",Blockly.Constants.Text.TEXT_CHARAT_MUTATOR_MIXIN,Blockly.Constants.Text.TEXT_CHARAT_EXTENSION);Blockly.Blocks.variables={};Blockly.Constants.Variables={};Blockly.Constants.Variables.HUE=330;Blockly.Blocks.variables.HUE=Blockly.Constants.Variables.HUE;
Blockly.defineBlocksWithJsonArray([{type:"variables_get",message0:"%1",args0:[{type:"field_variable",name:"VAR",variable:"%{BKY_VARIABLES_DEFAULT_NAME}"}],output:null,colour:"%{BKY_VARIABLES_HUE}",helpUrl:"%{BKY_VARIABLES_GET_HELPURL}",tooltip:"%{BKY_VARIABLES_GET_TOOLTIP}",extensions:["contextMenu_variableSetterGetter"]},{type:"variables_set",message0:"%{BKY_VARIABLES_SET}",args0:[{type:"field_variable",name:"VAR",variable:"%{BKY_VARIABLES_DEFAULT_NAME}"},{type:"input_value",name:"VALUE"}],previousStatement:null,
nextStatement:null,colour:"%{BKY_VARIABLES_HUE}",tooltip:"%{BKY_VARIABLES_SET_TOOLTIP}",helpUrl:"%{BKY_VARIABLES_SET_HELPURL}",extensions:["contextMenu_variableSetterGetter"]}]);
Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN={customContextMenu:function(a){if("variables_get"==this.type)var b="variables_set",c=Blockly.Msg.VARIABLES_GET_CREATE_SET;else b="variables_get",c=Blockly.Msg.VARIABLES_SET_CREATE_GET;var d={enabled:0<this.workspace.remainingCapacity()},e=this.getFieldValue("VAR");d.text=c.replace("%1",e);c=goog.dom.createDom("field",null,e);c.setAttribute("name","VAR");c=goog.dom.createDom("block",null,c);c.setAttribute("type",b);d.callback=
Blockly.ContextMenu.callbackFactory(this,c);a.push(d)}};Blockly.Extensions.registerMixin("contextMenu_variableSetterGetter",Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN);

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="96px" height="124px">
<style type="text/css">
#background {
fill: none;
}
.arrows {
fill: #000;
stroke: none;
}
.selected>.arrows {
fill: #fff;
}
.checkmark {
fill: #000;
font-family: sans-serif;
font-size: 10pt;
text-anchor: middle;
}
.trash {
fill: #888;
}
.zoom {
fill: none;
stroke: #888;
stroke-width: 2;
stroke-linecap: round;
}
.zoom>.center {
fill: #888;
stroke-width: 0;
}
</style>
<rect id="background" width="96" height="124" x="0" y="0" />
<g>
<path class="arrows" d="M 13,1.5 13,14.5 1.74,8 z" />
<path class="arrows" d="M 17.5,3 30.5,3 24,14.26 z" />
<path class="arrows" d="M 35,1.5 35,14.5 46.26,8 z" />
</g>
<g class="selected" transform="translate(0, 16)">
<path class="arrows" d="M 13,1.5 13,14.5 1.74,8 z" />
<path class="arrows" d="M 17.5,3 30.5,3 24,14.26 z" />
<path class="arrows" d="M 35,1.5 35,14.5 46.26,8 z" />
</g>
<text class="checkmark" x="55.5" y="28">&#10003;</text>
<g class="trash">
<path d="M 2,41 v 6 h 42 v -6 h -10.5 l -3,-3 h -15 l -3,3 z" />
<rect width="36" height="20" x="5" y="50" />
<rect width="36" height="42" x="5" y="50" rx="4" ry="4" />
</g>
<g class="zoom">
<circle r="11.5" cx="16" cy="108" />
<circle r="4.3" cx="16" cy="108" class="center" />
<path d="m 28,108 h3" />
<path d="m 1,108 h3" />
<path d="m 16,120 v3" />
<path d="m 16,93 v3" />
</g>
<g class="zoom">
<circle r="15" cx="48" cy="108" />
<path d="m 48,101.6 v12.8" />
<path d="m 41.6,108 h12.8" />
</g>
<g class="zoom">
<circle r="15" cx="80" cy="108" />
<path d="m 73.6,108 h12.8" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

425
_server/blockly/zh-hans.js Normal file
View File

@ -0,0 +1,425 @@
// This file was automatically generated. Do not modify.
'use strict';
goog.provide('Blockly.Msg.zh.hans');
goog.require('Blockly.Msg');
/** @export */ Blockly.Msg.ADD_COMMENT = "添加注释";
/** @export */ Blockly.Msg.CANNOT_DELETE_VARIABLE_PROCEDURE = "不能删除变量“%1”因为它是功能“%2”定义的一部分";
/** @export */ Blockly.Msg.CHANGE_VALUE_TITLE = "更改值:";
/** @export */ Blockly.Msg.CLEAN_UP = "整理块";
/** @export */ Blockly.Msg.COLLAPSE_ALL = "折叠块";
/** @export */ Blockly.Msg.COLLAPSE_BLOCK = "折叠块";
/** @export */ Blockly.Msg.COLOUR_BLEND_COLOUR1 = "颜色1";
/** @export */ Blockly.Msg.COLOUR_BLEND_COLOUR2 = "颜色2";
/** @export */ Blockly.Msg.COLOUR_BLEND_HELPURL = "http://meyerweb.com/eric/tools/color-blend/"; // untranslated
/** @export */ Blockly.Msg.COLOUR_BLEND_RATIO = "比例";
/** @export */ Blockly.Msg.COLOUR_BLEND_TITLE = "混合";
/** @export */ Blockly.Msg.COLOUR_BLEND_TOOLTIP = "用一个给定的比率(0.0-1.0)混合两种颜色。";
/** @export */ Blockly.Msg.COLOUR_PICKER_HELPURL = "https://zh.wikipedia.org/wiki/颜色";
/** @export */ Blockly.Msg.COLOUR_PICKER_TOOLTIP = "从调色板中选择一种颜色。";
/** @export */ Blockly.Msg.COLOUR_RANDOM_HELPURL = "http://randomcolour.com"; // untranslated
/** @export */ Blockly.Msg.COLOUR_RANDOM_TITLE = "随机颜色";
/** @export */ Blockly.Msg.COLOUR_RANDOM_TOOLTIP = "随机选择一种颜色。";
/** @export */ Blockly.Msg.COLOUR_RGB_BLUE = "蓝色";
/** @export */ Blockly.Msg.COLOUR_RGB_GREEN = "绿色";
/** @export */ Blockly.Msg.COLOUR_RGB_HELPURL = "http://www.december.com/html/spec/colorper.html"; // untranslated
/** @export */ Blockly.Msg.COLOUR_RGB_RED = "红色";
/** @export */ Blockly.Msg.COLOUR_RGB_TITLE = "颜色";
/** @export */ Blockly.Msg.COLOUR_RGB_TOOLTIP = "通过指定红色、绿色和蓝色的量创建一种颜色。所有的值必须在0和100之间。";
/** @export */ Blockly.Msg.CONTROLS_FLOW_STATEMENTS_HELPURL = "https://github.com/google/blockly/wiki/Loops#loop-termination-blocks"; // untranslated
/** @export */ Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK = "中断循环";
/** @export */ Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE = "继续下一次循环";
/** @export */ Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK = "中断包含它的循环。";
/** @export */ Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE = "跳过这个循环的剩余部分,并继续下一次迭代。";
/** @export */ Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING = "警告:此块仅可用于在一个循环内。";
/** @export */ Blockly.Msg.CONTROLS_FOREACH_HELPURL = "https://github.com/google/blockly/wiki/Loops#for-each"; // untranslated
/** @export */ Blockly.Msg.CONTROLS_FOREACH_TITLE = "为每个项目 %1 在列表中 %2";
/** @export */ Blockly.Msg.CONTROLS_FOREACH_TOOLTIP = "遍历每个列表中的项目,将变量“%1”设定到该项中然后执行某些语句。";
/** @export */ Blockly.Msg.CONTROLS_FOR_HELPURL = "https://github.com/google/blockly/wiki/Loops#count-with"; // untranslated
/** @export */ Blockly.Msg.CONTROLS_FOR_TITLE = "使用 %1 从范围 %2 到 %3 每隔 %4";
/** @export */ Blockly.Msg.CONTROLS_FOR_TOOLTIP = "从起始数到结尾数中取出变量“%1”的值按指定的时间间隔执行指定的块。";
/** @export */ Blockly.Msg.CONTROLS_IF_ELSEIF_TOOLTIP = "在if语句块中增加一个条件。";
/** @export */ Blockly.Msg.CONTROLS_IF_ELSE_TOOLTIP = "添加一个最终的包括所有情况的节到if块中。";
/** @export */ Blockly.Msg.CONTROLS_IF_HELPURL = "https://github.com/google/blockly/wiki/IfElse"; // untranslated
/** @export */ Blockly.Msg.CONTROLS_IF_IF_TOOLTIP = "增加、删除或重新排列各节来重新配置“if”块。";
/** @export */ Blockly.Msg.CONTROLS_IF_MSG_ELSE = "否则";
/** @export */ Blockly.Msg.CONTROLS_IF_MSG_ELSEIF = "否则如果";
/** @export */ Blockly.Msg.CONTROLS_IF_MSG_IF = "如果";
/** @export */ Blockly.Msg.CONTROLS_IF_TOOLTIP_1 = "如果值为真,执行一些语句。";
/** @export */ Blockly.Msg.CONTROLS_IF_TOOLTIP_2 = "如果值为真,则执行第一块语句。否则,则执行第二块语句。";
/** @export */ Blockly.Msg.CONTROLS_IF_TOOLTIP_3 = "如果第一个值为真,则执行第一块的语句。否则,如果第二个值为真,则执行第二块的语句。";
/** @export */ Blockly.Msg.CONTROLS_IF_TOOLTIP_4 = "如果第一个值为真,则执行第一块对语句。否则,如果第二个值为真,则执行语句的第二块。如果没有值为真,则执行最后一块的语句。";
/** @export */ Blockly.Msg.CONTROLS_REPEAT_HELPURL = "https://zh.wikipedia.org/wiki/For循环";
/** @export */ Blockly.Msg.CONTROLS_REPEAT_INPUT_DO = "执行";
/** @export */ Blockly.Msg.CONTROLS_REPEAT_TITLE = "重复 %1 次";
/** @export */ Blockly.Msg.CONTROLS_REPEAT_TOOLTIP = "多次执行一些语句。";
/** @export */ Blockly.Msg.CONTROLS_WHILEUNTIL_HELPURL = "https://github.com/google/blockly/wiki/Loops#repeat"; // untranslated
/** @export */ Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_UNTIL = "重复直到";
/** @export */ Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_WHILE = "重复当";
/** @export */ Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL = "只要值为假,执行一些语句。";
/** @export */ Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_WHILE = "只要值为真,执行一些语句。";
/** @export */ Blockly.Msg.DELETE_ALL_BLOCKS = "删除所有%1块吗";
/** @export */ Blockly.Msg.DELETE_BLOCK = "删除块";
/** @export */ Blockly.Msg.DELETE_VARIABLE = "删除“%1”变量";
/** @export */ Blockly.Msg.DELETE_VARIABLE_CONFIRMATION = "删除“%2”变量的%1用途么";
/** @export */ Blockly.Msg.DELETE_X_BLOCKS = "删除 %1 块";
/** @export */ Blockly.Msg.DISABLE_BLOCK = "禁用块";
/** @export */ Blockly.Msg.DUPLICATE_BLOCK = "复制";
/** @export */ Blockly.Msg.ENABLE_BLOCK = "启用块";
/** @export */ Blockly.Msg.EXPAND_ALL = "展开块";
/** @export */ Blockly.Msg.EXPAND_BLOCK = "展开块";
/** @export */ Blockly.Msg.EXTERNAL_INPUTS = "外部输入";
/** @export */ Blockly.Msg.HELP = "帮助";
/** @export */ Blockly.Msg.INLINE_INPUTS = "单行输入";
/** @export */ Blockly.Msg.IOS_CANCEL = "取消";
/** @export */ Blockly.Msg.IOS_ERROR = "错误";
/** @export */ Blockly.Msg.IOS_OK = "确定";
/** @export */ Blockly.Msg.IOS_PROCEDURES_ADD_INPUT = "+添加输入";
/** @export */ Blockly.Msg.IOS_PROCEDURES_ALLOW_STATEMENTS = "允许声明";
/** @export */ Blockly.Msg.IOS_PROCEDURES_DUPLICATE_INPUTS_ERROR = "此功能有重复输入内容。";
/** @export */ Blockly.Msg.IOS_PROCEDURES_INPUTS = "输入";
/** @export */ Blockly.Msg.IOS_VARIABLES_ADD_BUTTON = "添加";
/** @export */ Blockly.Msg.IOS_VARIABLES_ADD_VARIABLE = "+添加变量";
/** @export */ Blockly.Msg.IOS_VARIABLES_DELETE_BUTTON = "删除";
/** @export */ Blockly.Msg.IOS_VARIABLES_EMPTY_NAME_ERROR = "您不能使用空变量名称。";
/** @export */ Blockly.Msg.IOS_VARIABLES_RENAME_BUTTON = "重命名";
/** @export */ Blockly.Msg.IOS_VARIABLES_VARIABLE_NAME = "变量名称";
/** @export */ Blockly.Msg.LISTS_CREATE_EMPTY_HELPURL = "https://github.com/google/blockly/wiki/Lists#create-empty-list";
/** @export */ Blockly.Msg.LISTS_CREATE_EMPTY_TITLE = "创建空列表";
/** @export */ Blockly.Msg.LISTS_CREATE_EMPTY_TOOLTIP = "返回一个列表,长度为 0不包含任何数据记录";
/** @export */ Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TITLE_ADD = "列表";
/** @export */ Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TOOLTIP = "增加、删除或重新排列各部分以此重新配置这个列表块。";
/** @export */ Blockly.Msg.LISTS_CREATE_WITH_HELPURL = "https://github.com/google/blockly/wiki/Lists#create-list-with";
/** @export */ Blockly.Msg.LISTS_CREATE_WITH_INPUT_WITH = "建立列表使用";
/** @export */ Blockly.Msg.LISTS_CREATE_WITH_ITEM_TOOLTIP = "将一个项添加到列表中。";
/** @export */ Blockly.Msg.LISTS_CREATE_WITH_TOOLTIP = "建立一个具有任意数量项目的列表。";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_FIRST = "第一";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_FROM_END = "倒数第#";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_FROM_START = "#";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_GET = "取得";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_GET_REMOVE = "取出并移除";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_LAST = "最后";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_RANDOM = "随机";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_REMOVE = "移除";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_TAIL = "空白";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FIRST = "返回列表中的第一个项目。";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FROM = "返回在列表中的指定位置的项。";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_LAST = "返回列表中的最后一项。";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_RANDOM = "随机返回列表中的一个项目。";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST = "移除并返回列表中的第一个项目。";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM = "移除并返回列表中的指定位置的项。";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST = "移除并返回列表中的最后一个项目。";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM = "移除并返回列表中的一个随机项目中。";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST = "移除列表中的第一项";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM = "移除在列表中的指定位置的项。";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST = "移除列表中的最后一项";
/** @export */ Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM = "删除列表中的一个随机的项。";
/** @export */ Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_END = "到倒数第#";
/** @export */ Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_START = "到#";
/** @export */ Blockly.Msg.LISTS_GET_SUBLIST_END_LAST = "到最后";
/** @export */ Blockly.Msg.LISTS_GET_SUBLIST_HELPURL = "https://github.com/google/blockly/wiki/Lists#getting-a-sublist"; // untranslated
/** @export */ Blockly.Msg.LISTS_GET_SUBLIST_START_FIRST = "从头获得子列表";
/** @export */ Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_END = "从倒数#取得子列表";
/** @export */ Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_START = "从#取得子列表";
/** @export */ Blockly.Msg.LISTS_GET_SUBLIST_TAIL = "空白";
/** @export */ Blockly.Msg.LISTS_GET_SUBLIST_TOOLTIP = "复制列表中指定的部分。";
/** @export */ Blockly.Msg.LISTS_INDEX_FROM_END_TOOLTIP = "%1是最后一项。";
/** @export */ Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP = "%1是第一个项目。";
/** @export */ Blockly.Msg.LISTS_INDEX_OF_FIRST = "找出第一个项出现";
/** @export */ Blockly.Msg.LISTS_INDEX_OF_HELPURL = "https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list"; // untranslated
/** @export */ Blockly.Msg.LISTS_INDEX_OF_LAST = "找出最后一个项出现";
/** @export */ Blockly.Msg.LISTS_INDEX_OF_TOOLTIP = "返回在列表中的第一/最后一个匹配项的索引值。如果找不到项目则返回%1。";
/** @export */ Blockly.Msg.LISTS_INLIST = "在列表中";
/** @export */ Blockly.Msg.LISTS_ISEMPTY_HELPURL = "https://github.com/google/blockly/wiki/Lists#is-empty"; // untranslated
/** @export */ Blockly.Msg.LISTS_ISEMPTY_TITLE = "%1是空的";
/** @export */ Blockly.Msg.LISTS_ISEMPTY_TOOLTIP = "如果改列表为空,则返回真。";
/** @export */ Blockly.Msg.LISTS_LENGTH_HELPURL = "https://github.com/google/blockly/wiki/Lists#length-of"; // untranslated
/** @export */ Blockly.Msg.LISTS_LENGTH_TITLE = "%1的长度";
/** @export */ Blockly.Msg.LISTS_LENGTH_TOOLTIP = "返回列表的长度。";
/** @export */ Blockly.Msg.LISTS_REPEAT_HELPURL = "https://github.com/google/blockly/wiki/Lists#create-list-with"; // untranslated
/** @export */ Blockly.Msg.LISTS_REPEAT_TITLE = "建立列表使用项 %1 重复 %2 次";
/** @export */ Blockly.Msg.LISTS_REPEAT_TOOLTIP = "建立包含指定重复次数的值的列表。";
/** @export */ Blockly.Msg.LISTS_REVERSE_HELPURL = "https://github.com/google/blockly/wiki/Lists#reversing-a-list";
/** @export */ Blockly.Msg.LISTS_REVERSE_MESSAGE0 = "倒转%1";
/** @export */ Blockly.Msg.LISTS_REVERSE_TOOLTIP = "倒转一个列表的拷贝。";
/** @export */ Blockly.Msg.LISTS_SET_INDEX_HELPURL = "https://github.com/google/blockly/wiki/Lists#in-list--set"; // untranslated
/** @export */ Blockly.Msg.LISTS_SET_INDEX_INPUT_TO = "为";
/** @export */ Blockly.Msg.LISTS_SET_INDEX_INSERT = "插入在";
/** @export */ Blockly.Msg.LISTS_SET_INDEX_SET = "设置";
/** @export */ Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST = "在列表的起始处添加该项。";
/** @export */ Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FROM = "插入在列表中指定位置的项。";
/** @export */ Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_LAST = "将该项追加到列表的末尾。";
/** @export */ Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM = "在列表中随机插入项。";
/** @export */ Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FIRST = "设置列表中的第一个项目。";
/** @export */ Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FROM = "设置在列表中指定位置的项。";
/** @export */ Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_LAST = "设置列表中的最后一项。";
/** @export */ Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_RANDOM = "设置列表中一个随机的项目。";
/** @export */ Blockly.Msg.LISTS_SORT_HELPURL = "https://github.com/google/blockly/wiki/Lists#sorting-a-list";
/** @export */ Blockly.Msg.LISTS_SORT_ORDER_ASCENDING = "升序";
/** @export */ Blockly.Msg.LISTS_SORT_ORDER_DESCENDING = "降序";
/** @export */ Blockly.Msg.LISTS_SORT_TITLE = "排序%1 %2 %3";
/** @export */ Blockly.Msg.LISTS_SORT_TOOLTIP = "排序一个列表的拷贝。";
/** @export */ Blockly.Msg.LISTS_SORT_TYPE_IGNORECASE = "按字母排序,忽略大小写";
/** @export */ Blockly.Msg.LISTS_SORT_TYPE_NUMERIC = "按数字排序";
/** @export */ Blockly.Msg.LISTS_SORT_TYPE_TEXT = "按字母排序";
/** @export */ Blockly.Msg.LISTS_SPLIT_HELPURL = "https://github.com/google/blockly/wiki/Lists#splitting-strings-and-joining-lists";
/** @export */ Blockly.Msg.LISTS_SPLIT_LIST_FROM_TEXT = "从文本制作列表";
/** @export */ Blockly.Msg.LISTS_SPLIT_TEXT_FROM_LIST = "从列表拆出文本";
/** @export */ Blockly.Msg.LISTS_SPLIT_TOOLTIP_JOIN = "加入文本列表至一个文本,由分隔符分隔。";
/** @export */ Blockly.Msg.LISTS_SPLIT_TOOLTIP_SPLIT = "拆分文本到文本列表,按每个分隔符拆分。";
/** @export */ Blockly.Msg.LISTS_SPLIT_WITH_DELIMITER = "用分隔符";
/** @export */ Blockly.Msg.LOGIC_BOOLEAN_FALSE = "假";
/** @export */ Blockly.Msg.LOGIC_BOOLEAN_HELPURL = "https://github.com/google/blockly/wiki/Logic#values"; // untranslated
/** @export */ Blockly.Msg.LOGIC_BOOLEAN_TOOLTIP = "返回真或假。";
/** @export */ Blockly.Msg.LOGIC_BOOLEAN_TRUE = "真";
/** @export */ Blockly.Msg.LOGIC_COMPARE_HELPURL = "https://zh.wikipedia.org/wiki/不等";
/** @export */ Blockly.Msg.LOGIC_COMPARE_TOOLTIP_EQ = "如果两个输入结果相等,则返回真。";
/** @export */ Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GT = "如果第一个输入结果比第二个大,则返回真。";
/** @export */ Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GTE = "如果第一个输入结果大于或等于第二个输入结果,则返回真。";
/** @export */ Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LT = "如果第一个输入结果比第二个小,则返回真。";
/** @export */ Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LTE = "如果第一个输入结果小于或等于第二个输入结果,则返回真。";
/** @export */ Blockly.Msg.LOGIC_COMPARE_TOOLTIP_NEQ = "如果两个输入结果不相等,则返回真。";
/** @export */ Blockly.Msg.LOGIC_NEGATE_HELPURL = "https://github.com/google/blockly/wiki/Logic#not";
/** @export */ Blockly.Msg.LOGIC_NEGATE_TITLE = "非%1";
/** @export */ Blockly.Msg.LOGIC_NEGATE_TOOLTIP = "如果输入结果为假,则返回真;如果输入结果为真,则返回假。";
/** @export */ Blockly.Msg.LOGIC_NULL = "空";
/** @export */ Blockly.Msg.LOGIC_NULL_HELPURL = "https://en.wikipedia.org/wiki/Nullable_type"; // untranslated
/** @export */ Blockly.Msg.LOGIC_NULL_TOOLTIP = "返回空值。";
/** @export */ Blockly.Msg.LOGIC_OPERATION_AND = "和";
/** @export */ Blockly.Msg.LOGIC_OPERATION_HELPURL = "https://github.com/google/blockly/wiki/Logic#logical-operations"; // untranslated
/** @export */ Blockly.Msg.LOGIC_OPERATION_OR = "或";
/** @export */ Blockly.Msg.LOGIC_OPERATION_TOOLTIP_AND = "如果两个输入结果都为真,则返回真。";
/** @export */ Blockly.Msg.LOGIC_OPERATION_TOOLTIP_OR = "如果至少有一个输入结果为真,则返回真。";
/** @export */ Blockly.Msg.LOGIC_TERNARY_CONDITION = "测试";
/** @export */ Blockly.Msg.LOGIC_TERNARY_HELPURL = "https://zh.wikipedia.org/wiki/条件运算符";
/** @export */ Blockly.Msg.LOGIC_TERNARY_IF_FALSE = "如果为假";
/** @export */ Blockly.Msg.LOGIC_TERNARY_IF_TRUE = "如果为真";
/** @export */ Blockly.Msg.LOGIC_TERNARY_TOOLTIP = "检查“test”中的条件。如果条件为真则返回“if true”的值否则则返回“if false”的值。";
/** @export */ Blockly.Msg.MATH_ADDITION_SYMBOL = "+"; // untranslated
/** @export */ Blockly.Msg.MATH_ARITHMETIC_HELPURL = "https://zh.wikipedia.org/wiki/算术";
/** @export */ Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD = "返回两个数字的和。";
/** @export */ Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE = "返回两个数字的商。";
/** @export */ Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS = "返回两个数字的区别。";
/** @export */ Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY = "返回两个数字的乘积。";
/** @export */ Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER = "返回第一个数的第二个数次幂。";
/** @export */ Blockly.Msg.MATH_CHANGE_HELPURL = "https://zh.wikipedia.org/wiki/加法";
/** @export */ Blockly.Msg.MATH_CHANGE_TITLE = "更改 %1 从 %2";
/** @export */ Blockly.Msg.MATH_CHANGE_TOOLTIP = "将一个数添加到变量“%1”。";
/** @export */ Blockly.Msg.MATH_CONSTANT_HELPURL = "https://zh.wikipedia.org/wiki/数学常数";
/** @export */ Blockly.Msg.MATH_CONSTANT_TOOLTIP = "返回一个常见常量:π (3.141…)、e (2.718…)、φ (1.618…)、平方根 (1.414…)、开平方根 (0.707…)或∞ (infinity)。";
/** @export */ Blockly.Msg.MATH_CONSTRAIN_HELPURL = "https://en.wikipedia.org/wiki/Clamping_(graphics)"; // untranslated
/** @export */ Blockly.Msg.MATH_CONSTRAIN_TITLE = "限制数字 %1 介于 (低) %2 到 (高) %3";
/** @export */ Blockly.Msg.MATH_CONSTRAIN_TOOLTIP = "限制数字介于两个指定的数字之间";
/** @export */ Blockly.Msg.MATH_DIVISION_SYMBOL = "÷"; // untranslated
/** @export */ Blockly.Msg.MATH_IS_DIVISIBLE_BY = "可被整除";
/** @export */ Blockly.Msg.MATH_IS_EVEN = "是偶数";
/** @export */ Blockly.Msg.MATH_IS_NEGATIVE = "为负";
/** @export */ Blockly.Msg.MATH_IS_ODD = "是奇数";
/** @export */ Blockly.Msg.MATH_IS_POSITIVE = "为正";
/** @export */ Blockly.Msg.MATH_IS_PRIME = "是质数";
/** @export */ Blockly.Msg.MATH_IS_TOOLTIP = "如果数字是偶数、奇数、非负整数、正数、负数或如果它可被某数字整除,则返回真或假。";
/** @export */ Blockly.Msg.MATH_IS_WHOLE = "为整数";
/** @export */ Blockly.Msg.MATH_MODULO_HELPURL = "https://zh.wikipedia.org/wiki/模除";
/** @export */ Blockly.Msg.MATH_MODULO_TITLE = "取余数自 %1 ÷ %2";
/** @export */ Blockly.Msg.MATH_MODULO_TOOLTIP = "返回这两个数字相除后的余数。";
/** @export */ Blockly.Msg.MATH_MULTIPLICATION_SYMBOL = "×"; // untranslated
/** @export */ Blockly.Msg.MATH_NUMBER_HELPURL = "https://zh.wikipedia.org/wiki/数";
/** @export */ Blockly.Msg.MATH_NUMBER_TOOLTIP = "一个数字。";
/** @export */ Blockly.Msg.MATH_ONLIST_HELPURL = ""; // untranslated
/** @export */ Blockly.Msg.MATH_ONLIST_OPERATOR_AVERAGE = "列表中的平均数";
/** @export */ Blockly.Msg.MATH_ONLIST_OPERATOR_MAX = "列表中的最大值";
/** @export */ Blockly.Msg.MATH_ONLIST_OPERATOR_MEDIAN = "列表中位数";
/** @export */ Blockly.Msg.MATH_ONLIST_OPERATOR_MIN = "列表中的最小值";
/** @export */ Blockly.Msg.MATH_ONLIST_OPERATOR_MODE = "列表模式";
/** @export */ Blockly.Msg.MATH_ONLIST_OPERATOR_RANDOM = "列表的随机项";
/** @export */ Blockly.Msg.MATH_ONLIST_OPERATOR_STD_DEV = "列表中的标准差";
/** @export */ Blockly.Msg.MATH_ONLIST_OPERATOR_SUM = "列表中的数的总和";
/** @export */ Blockly.Msg.MATH_ONLIST_TOOLTIP_AVERAGE = "返回列表中的数值的平均值。";
/** @export */ Blockly.Msg.MATH_ONLIST_TOOLTIP_MAX = "返回列表中最大数。";
/** @export */ Blockly.Msg.MATH_ONLIST_TOOLTIP_MEDIAN = "返回列表中的中位数。";
/** @export */ Blockly.Msg.MATH_ONLIST_TOOLTIP_MIN = "返回列表中最小数。";
/** @export */ Blockly.Msg.MATH_ONLIST_TOOLTIP_MODE = "返回列表中的最常见的项的列表。";
/** @export */ Blockly.Msg.MATH_ONLIST_TOOLTIP_RANDOM = "从列表中返回一个随机的元素。";
/** @export */ Blockly.Msg.MATH_ONLIST_TOOLTIP_STD_DEV = "返回列表的标准偏差。";
/** @export */ Blockly.Msg.MATH_ONLIST_TOOLTIP_SUM = "返回列表中的所有数字的和。";
/** @export */ Blockly.Msg.MATH_POWER_SYMBOL = "^"; // untranslated
/** @export */ Blockly.Msg.MATH_RANDOM_FLOAT_HELPURL = "https://zh.wikipedia.org/wiki/随机数生成器";
/** @export */ Blockly.Msg.MATH_RANDOM_FLOAT_TITLE_RANDOM = "随机分数";
/** @export */ Blockly.Msg.MATH_RANDOM_FLOAT_TOOLTIP = "返回介于包含0.0到1.0之间的随机数。";
/** @export */ Blockly.Msg.MATH_RANDOM_INT_HELPURL = "https://zh.wikipedia.org/wiki/随机数生成器";
/** @export */ Blockly.Msg.MATH_RANDOM_INT_TITLE = "从 %1 到 %2 之间的随机整数";
/** @export */ Blockly.Msg.MATH_RANDOM_INT_TOOLTIP = "返回两个指定的范围(含)之间的随机整数。";
/** @export */ Blockly.Msg.MATH_ROUND_HELPURL = "https://zh.wikipedia.org/wiki/数值修约";
/** @export */ Blockly.Msg.MATH_ROUND_OPERATOR_ROUND = "向下舍入";
/** @export */ Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDDOWN = "向下舍入";
/** @export */ Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDUP = "向上舍入";
/** @export */ Blockly.Msg.MATH_ROUND_TOOLTIP = "数字向上或向下舍入。";
/** @export */ Blockly.Msg.MATH_SINGLE_HELPURL = "https://zh.wikipedia.org/wiki/平方根";
/** @export */ Blockly.Msg.MATH_SINGLE_OP_ABSOLUTE = "绝对";
/** @export */ Blockly.Msg.MATH_SINGLE_OP_ROOT = "平方根";
/** @export */ Blockly.Msg.MATH_SINGLE_TOOLTIP_ABS = "返回一个数的绝对值。";
/** @export */ Blockly.Msg.MATH_SINGLE_TOOLTIP_EXP = "返回一个数的e次幂。";
/** @export */ Blockly.Msg.MATH_SINGLE_TOOLTIP_LN = "返回一个数的自然对数。";
/** @export */ Blockly.Msg.MATH_SINGLE_TOOLTIP_LOG10 = "返回一个数的对数。";
/** @export */ Blockly.Msg.MATH_SINGLE_TOOLTIP_NEG = "返回一个数的逻辑非。";
/** @export */ Blockly.Msg.MATH_SINGLE_TOOLTIP_POW10 = "返回一个数的10次幂。";
/** @export */ Blockly.Msg.MATH_SINGLE_TOOLTIP_ROOT = "返回一个数的平方根。";
/** @export */ Blockly.Msg.MATH_SUBTRACTION_SYMBOL = "-"; // untranslated
/** @export */ Blockly.Msg.MATH_TRIG_ACOS = "acos"; // untranslated
/** @export */ Blockly.Msg.MATH_TRIG_ASIN = "asin"; // untranslated
/** @export */ Blockly.Msg.MATH_TRIG_ATAN = "atan"; // untranslated
/** @export */ Blockly.Msg.MATH_TRIG_COS = "cos"; // untranslated
/** @export */ Blockly.Msg.MATH_TRIG_HELPURL = "https://zh.wikipedia.org/wiki/三角函数";
/** @export */ Blockly.Msg.MATH_TRIG_SIN = "sin"; // untranslated
/** @export */ Blockly.Msg.MATH_TRIG_TAN = "tan"; // untranslated
/** @export */ Blockly.Msg.MATH_TRIG_TOOLTIP_ACOS = "返回一个数的反余弦值。";
/** @export */ Blockly.Msg.MATH_TRIG_TOOLTIP_ASIN = "返回一个数的反正弦值。";
/** @export */ Blockly.Msg.MATH_TRIG_TOOLTIP_ATAN = "返回指定角度的反正切值。";
/** @export */ Blockly.Msg.MATH_TRIG_TOOLTIP_COS = "返回指定角度的余弦值(非弧度)。";
/** @export */ Blockly.Msg.MATH_TRIG_TOOLTIP_SIN = "返回指定角度的正弦值(非弧度)。";
/** @export */ Blockly.Msg.MATH_TRIG_TOOLTIP_TAN = "返回指定角度的正切值(非弧度)。";
/** @export */ Blockly.Msg.NEW_VARIABLE = "创建变量...";
/** @export */ Blockly.Msg.NEW_VARIABLE_TITLE = "新变量的名称:";
/** @export */ Blockly.Msg.ORDINAL_NUMBER_SUFFIX = "空白";
/** @export */ Blockly.Msg.PROCEDURES_ALLOW_STATEMENTS = "允许声明";
/** @export */ Blockly.Msg.PROCEDURES_BEFORE_PARAMS = "与:";
/** @export */ Blockly.Msg.PROCEDURES_CALLNORETURN_HELPURL = "https://zh.wikipedia.org/wiki/子程序";
/** @export */ Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP = "运行用户定义的函数“%1”。";
/** @export */ Blockly.Msg.PROCEDURES_CALLRETURN_HELPURL = "https://zh.wikipedia.org/wiki/子程序";
/** @export */ Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP = "运行用户定义的函数“%1”并使用它的输出值。";
/** @export */ Blockly.Msg.PROCEDURES_CALL_BEFORE_PARAMS = "与:";
/** @export */ Blockly.Msg.PROCEDURES_CREATE_DO = "创建“%1”";
/** @export */ Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT = "描述该功能...";
/** @export */ Blockly.Msg.PROCEDURES_DEFNORETURN_DO = "空白";
/** @export */ Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL = "https://zh.wikipedia.org/wiki/子程序";
/** @export */ Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE = "做点什么";
/** @export */ Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE = "至";
/** @export */ Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP = "创建一个不带输出值的函数。";
/** @export */ Blockly.Msg.PROCEDURES_DEFRETURN_HELPURL = "https://zh.wikipedia.org/wiki/子程序";
/** @export */ Blockly.Msg.PROCEDURES_DEFRETURN_RETURN = "返回";
/** @export */ Blockly.Msg.PROCEDURES_DEFRETURN_TOOLTIP = "创建一个有输出值的函数。";
/** @export */ Blockly.Msg.PROCEDURES_DEF_DUPLICATE_WARNING = "警告: 此函数具有重复参数。";
/** @export */ Blockly.Msg.PROCEDURES_HIGHLIGHT_DEF = "突出显示函数定义";
/** @export */ Blockly.Msg.PROCEDURES_IFRETURN_HELPURL = "http://c2.com/cgi/wiki?GuardClause";
/** @export */ Blockly.Msg.PROCEDURES_IFRETURN_TOOLTIP = "如果值为真,则返回第二个值。";
/** @export */ Blockly.Msg.PROCEDURES_IFRETURN_WARNING = "警告: 仅在定义函数内可使用此块。";
/** @export */ Blockly.Msg.PROCEDURES_MUTATORARG_TITLE = "输入名称:";
/** @export */ Blockly.Msg.PROCEDURES_MUTATORARG_TOOLTIP = "添加函数输入。";
/** @export */ Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TITLE = "输入";
/** @export */ Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TOOLTIP = "添加、删除或重新排此函数的输入。";
/** @export */ Blockly.Msg.REDO = "重做";
/** @export */ Blockly.Msg.REMOVE_COMMENT = "删除注释";
/** @export */ Blockly.Msg.RENAME_VARIABLE = "重命名变量...";
/** @export */ Blockly.Msg.RENAME_VARIABLE_TITLE = "将所有“%1”变量重命名为:";
/** @export */ Blockly.Msg.TEXT_APPEND_HELPURL = "https://github.com/google/blockly/wiki/Text#text-modification"; // untranslated
/** @export */ Blockly.Msg.TEXT_APPEND_TITLE = "至%1附加文本%2";
/** @export */ Blockly.Msg.TEXT_APPEND_TOOLTIP = "将一些文本追加到变量“%1”。";
/** @export */ Blockly.Msg.TEXT_CHANGECASE_HELPURL = "https://github.com/google/blockly/wiki/Text#adjusting-text-case"; // untranslated
/** @export */ Blockly.Msg.TEXT_CHANGECASE_OPERATOR_LOWERCASE = "转为小写";
/** @export */ Blockly.Msg.TEXT_CHANGECASE_OPERATOR_TITLECASE = "将首字母大写";
/** @export */ Blockly.Msg.TEXT_CHANGECASE_OPERATOR_UPPERCASE = "转为大写";
/** @export */ Blockly.Msg.TEXT_CHANGECASE_TOOLTIP = "在不同大小写下复制并返回这段文字。";
/** @export */ Blockly.Msg.TEXT_CHARAT_FIRST = "获得第一个字符";
/** @export */ Blockly.Msg.TEXT_CHARAT_FROM_END = "获得倒数第#个字符";
/** @export */ Blockly.Msg.TEXT_CHARAT_FROM_START = "获得字符#";
/** @export */ Blockly.Msg.TEXT_CHARAT_HELPURL = "https://github.com/google/blockly/wiki/Text#extracting-text"; // untranslated
/** @export */ Blockly.Msg.TEXT_CHARAT_LAST = "获得最后一个字符";
/** @export */ Blockly.Msg.TEXT_CHARAT_RANDOM = "获取随机的字母";
/** @export */ Blockly.Msg.TEXT_CHARAT_TAIL = "空白";
/** @export */ Blockly.Msg.TEXT_CHARAT_TITLE = "在文本%1 %2中";
/** @export */ Blockly.Msg.TEXT_CHARAT_TOOLTIP = "返回位于指定位置的字母。";
/** @export */ Blockly.Msg.TEXT_COUNT_HELPURL = "https://github.com/google/blockly/wiki/Text#counting-substrings";
/** @export */ Blockly.Msg.TEXT_COUNT_MESSAGE0 = "将%1计算在%2之内";
/** @export */ Blockly.Msg.TEXT_COUNT_TOOLTIP = "计算在一些其他文本中,部分文本重现了多少次。";
/** @export */ Blockly.Msg.TEXT_CREATE_JOIN_ITEM_TOOLTIP = "将一个项添加到文本中。";
/** @export */ Blockly.Msg.TEXT_CREATE_JOIN_TITLE_JOIN = "加入";
/** @export */ Blockly.Msg.TEXT_CREATE_JOIN_TOOLTIP = "添加、移除或重新排列各节来重新配置这个文本块。";
/** @export */ Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_END = "到倒数第#个字符";
/** @export */ Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_START = "到字符#";
/** @export */ Blockly.Msg.TEXT_GET_SUBSTRING_END_LAST = "到最后一个字符";
/** @export */ Blockly.Msg.TEXT_GET_SUBSTRING_HELPURL = "https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text"; // untranslated
/** @export */ Blockly.Msg.TEXT_GET_SUBSTRING_INPUT_IN_TEXT = "自文本";
/** @export */ Blockly.Msg.TEXT_GET_SUBSTRING_START_FIRST = "取得一段字串自第一个字符";
/** @export */ Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_END = "取得一段字串自倒数第#个字符";
/** @export */ Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_START = "取得一段字串自#";
/** @export */ Blockly.Msg.TEXT_GET_SUBSTRING_TAIL = "空白";
/** @export */ Blockly.Msg.TEXT_GET_SUBSTRING_TOOLTIP = "返回指定的部分文本。";
/** @export */ Blockly.Msg.TEXT_INDEXOF_HELPURL = "https://github.com/google/blockly/wiki/Text#finding-text"; // untranslated
/** @export */ Blockly.Msg.TEXT_INDEXOF_OPERATOR_FIRST = "寻找第一个出现的文本";
/** @export */ Blockly.Msg.TEXT_INDEXOF_OPERATOR_LAST = "寻找最后一个出现的文本";
/** @export */ Blockly.Msg.TEXT_INDEXOF_TITLE = "在文本%1 %2 %3中";
/** @export */ Blockly.Msg.TEXT_INDEXOF_TOOLTIP = "返回在第二个字串中的第一/最后一个匹配项的索引值。如果未找到则返回%1。";
/** @export */ Blockly.Msg.TEXT_ISEMPTY_HELPURL = "https://github.com/google/blockly/wiki/Text#checking-for-empty-text"; // untranslated
/** @export */ Blockly.Msg.TEXT_ISEMPTY_TITLE = "%1是空的";
/** @export */ Blockly.Msg.TEXT_ISEMPTY_TOOLTIP = "如果提供的文本为空,则返回真。";
/** @export */ Blockly.Msg.TEXT_JOIN_HELPURL = "https://github.com/google/blockly/wiki/Text#text-creation"; // untranslated
/** @export */ Blockly.Msg.TEXT_JOIN_TITLE_CREATEWITH = "建立字串使用";
/** @export */ Blockly.Msg.TEXT_JOIN_TOOLTIP = "通过串起任意数量的项以建立一段文字。";
/** @export */ Blockly.Msg.TEXT_LENGTH_HELPURL = "https://github.com/google/blockly/wiki/Text#text-modification"; // untranslated
/** @export */ Blockly.Msg.TEXT_LENGTH_TITLE = "%1的长度";
/** @export */ Blockly.Msg.TEXT_LENGTH_TOOLTIP = "返回提供文本的字母数(包括空格)。";
/** @export */ Blockly.Msg.TEXT_PRINT_HELPURL = "https://github.com/google/blockly/wiki/Text#printing-text"; // untranslated
/** @export */ Blockly.Msg.TEXT_PRINT_TITLE = "打印%1";
/** @export */ Blockly.Msg.TEXT_PRINT_TOOLTIP = "打印指定的文字、数字或其他值。";
/** @export */ Blockly.Msg.TEXT_PROMPT_HELPURL = "https://github.com/google/blockly/wiki/Text#getting-input-from-the-user"; // untranslated
/** @export */ Blockly.Msg.TEXT_PROMPT_TOOLTIP_NUMBER = "提示用户输入数字。";
/** @export */ Blockly.Msg.TEXT_PROMPT_TOOLTIP_TEXT = "提示用户输入一些文本。";
/** @export */ Blockly.Msg.TEXT_PROMPT_TYPE_NUMBER = "输入数字并显示提示消息";
/** @export */ Blockly.Msg.TEXT_PROMPT_TYPE_TEXT = "输入数字并显示提示消息";
/** @export */ Blockly.Msg.TEXT_REPLACE_HELPURL = "https://github.com/google/blockly/wiki/Text#replacing-substrings";
/** @export */ Blockly.Msg.TEXT_REPLACE_MESSAGE0 = "在%3中将%1替换为%2";
/** @export */ Blockly.Msg.TEXT_REPLACE_TOOLTIP = "在某些其他文本中,替换部分文本的所有事件。";
/** @export */ Blockly.Msg.TEXT_REVERSE_HELPURL = "https://github.com/google/blockly/wiki/Text#reversing-text";
/** @export */ Blockly.Msg.TEXT_REVERSE_MESSAGE0 = "倒转%1";
/** @export */ Blockly.Msg.TEXT_REVERSE_TOOLTIP = "倒转文本中字符的排序。";
/** @export */ Blockly.Msg.TEXT_TEXT_HELPURL = "https://zh.wikipedia.org/wiki/字符串";
/** @export */ Blockly.Msg.TEXT_TEXT_TOOLTIP = "一个字母、单词或一行文本。";
/** @export */ Blockly.Msg.TEXT_TRIM_HELPURL = "https://github.com/google/blockly/wiki/Text#trimming-removing-spaces"; // untranslated
/** @export */ Blockly.Msg.TEXT_TRIM_OPERATOR_BOTH = "消除两侧空格";
/** @export */ Blockly.Msg.TEXT_TRIM_OPERATOR_LEFT = "消除左侧空格";
/** @export */ Blockly.Msg.TEXT_TRIM_OPERATOR_RIGHT = "消除右侧空格";
/** @export */ Blockly.Msg.TEXT_TRIM_TOOLTIP = "复制这段文字的同时删除两端多余的空格。";
/** @export */ Blockly.Msg.TODAY = "今天";
/** @export */ Blockly.Msg.UNDO = "撤销";
/** @export */ Blockly.Msg.VARIABLES_DEFAULT_NAME = "项目";
/** @export */ Blockly.Msg.VARIABLES_GET_CREATE_SET = "创建“设定%1”";
/** @export */ Blockly.Msg.VARIABLES_GET_HELPURL = "https://github.com/google/blockly/wiki/Variables#get"; // untranslated
/** @export */ Blockly.Msg.VARIABLES_GET_TOOLTIP = "返回此变量的值。";
/** @export */ Blockly.Msg.VARIABLES_SET = "赋值 %1 到 %2";
/** @export */ Blockly.Msg.VARIABLES_SET_CREATE_GET = "创建“获得%1”";
/** @export */ Blockly.Msg.VARIABLES_SET_HELPURL = "https://github.com/google/blockly/wiki/Variables#set"; // untranslated
/** @export */ Blockly.Msg.VARIABLES_SET_TOOLTIP = "设置此变量,以使它和输入值相等。";
/** @export */ Blockly.Msg.VARIABLE_ALREADY_EXISTS = "已存在名为“%1”的变量。";
/** @export */ Blockly.Msg.VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE = "名叫“%1”的变量已存在但作为另一个变量类型“%2”存在。";
/** @export */ Blockly.Msg.PROCEDURES_DEFRETURN_TITLE = Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE;
/** @export */ Blockly.Msg.CONTROLS_IF_IF_TITLE_IF = Blockly.Msg.CONTROLS_IF_MSG_IF;
/** @export */ Blockly.Msg.CONTROLS_WHILEUNTIL_INPUT_DO = Blockly.Msg.CONTROLS_REPEAT_INPUT_DO;
/** @export */ Blockly.Msg.CONTROLS_IF_MSG_THEN = Blockly.Msg.CONTROLS_REPEAT_INPUT_DO;
/** @export */ Blockly.Msg.CONTROLS_IF_ELSE_TITLE_ELSE = Blockly.Msg.CONTROLS_IF_MSG_ELSE;
/** @export */ Blockly.Msg.PROCEDURES_DEFRETURN_PROCEDURE = Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE;
/** @export */ Blockly.Msg.LISTS_GET_SUBLIST_INPUT_IN_LIST = Blockly.Msg.LISTS_INLIST;
/** @export */ Blockly.Msg.LISTS_GET_INDEX_INPUT_IN_LIST = Blockly.Msg.LISTS_INLIST;
/** @export */ Blockly.Msg.MATH_CHANGE_TITLE_ITEM = Blockly.Msg.VARIABLES_DEFAULT_NAME;
/** @export */ Blockly.Msg.PROCEDURES_DEFRETURN_DO = Blockly.Msg.PROCEDURES_DEFNORETURN_DO;
/** @export */ Blockly.Msg.CONTROLS_IF_ELSEIF_TITLE_ELSEIF = Blockly.Msg.CONTROLS_IF_MSG_ELSEIF;
/** @export */ Blockly.Msg.LISTS_GET_INDEX_HELPURL = Blockly.Msg.LISTS_INDEX_OF_HELPURL;
/** @export */ Blockly.Msg.CONTROLS_FOREACH_INPUT_DO = Blockly.Msg.CONTROLS_REPEAT_INPUT_DO;
/** @export */ Blockly.Msg.LISTS_SET_INDEX_INPUT_IN_LIST = Blockly.Msg.LISTS_INLIST;
/** @export */ Blockly.Msg.CONTROLS_FOR_INPUT_DO = Blockly.Msg.CONTROLS_REPEAT_INPUT_DO;
/** @export */ Blockly.Msg.LISTS_CREATE_WITH_ITEM_TITLE = Blockly.Msg.VARIABLES_DEFAULT_NAME;
/** @export */ Blockly.Msg.TEXT_APPEND_VARIABLE = Blockly.Msg.VARIABLES_DEFAULT_NAME;
/** @export */ Blockly.Msg.TEXT_CREATE_JOIN_ITEM_TITLE_ITEM = Blockly.Msg.VARIABLES_DEFAULT_NAME;
/** @export */ Blockly.Msg.LISTS_INDEX_OF_INPUT_IN_LIST = Blockly.Msg.LISTS_INLIST;
/** @export */ Blockly.Msg.PROCEDURES_DEFRETURN_COMMENT = Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT;
/** @export */ Blockly.Msg.MATH_HUE = "230";
/** @export */ Blockly.Msg.LOOPS_HUE = "120";
/** @export */ Blockly.Msg.LISTS_HUE = "260";
/** @export */ Blockly.Msg.LOGIC_HUE = "210";
/** @export */ Blockly.Msg.VARIABLES_HUE = "330";
/** @export */ Blockly.Msg.TEXTS_HUE = "160";
/** @export */ Blockly.Msg.PROCEDURES_HUE = "290";
/** @export */ Blockly.Msg.COLOUR_HUE = "20";

View File

@ -184,10 +184,13 @@ body{
top: 5px;
overflow: auto;
}
.egameCanvas {
position: absolute;
}
.gameCanvas {
position: absolute;
}
#dataSelection{
#dataSelection , .appendSelection{
position: absolute;
/* top:0;
left:320px; */
@ -207,12 +210,14 @@ body{
color: #D50000;
font-weight: 700;
font-size: 14px;
line-height: 1.2em;
}
.infoText{
color: #2196F3;
}
.successText{
color: #00897B
color: #00897B;
line-height: 1.2em;
}
table, td {

166
_server/css/editor_mode.css Normal file
View File

@ -0,0 +1,166 @@
.leftTab {
border-radius: 2px;
box-sizing: border-box;
box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12);
}
.leftTab {
overflow: auto;
position: absolute;
height: 630px;
}
.leftTab > *{margin:2.5px 5px;}
.leftTab > :first-child{margin-top:5px;}
.leftTab > :last-child{margin-bottom:5px;}
.leftTab {
left: 5px;
top: 10px;
width: 435px;
}
#appendPicSelection span {
position: absolute;
font-size:11px;
-webkit-text-stroke: 1px red;
text-shadow: black 1px 0, black 0 1px, black -1px 0, black 0 -1px;
}
#left6 {
left: 5px;
/* top: 1930px; */
top: 5px;
z-index: 200;
position: fixed;
background-color: rgb(245, 245, 245);
width: 1335px;
height: 780px;
}
#left6 #blocklyDiv {
height: 480px;
width: 940px;
}
#left6 .CodeMirror {
border: 1px solid #eee;
height: 200px;
width: 1300px;
}
#left6 #codeArea {width: 99.5%; height: 15.4em;overflow:y;/* resize:none; */}
#left7 {
/* height: 440px; width: 375px;float:left; */
left: 5px;
top: 5px;
z-index: 200;
position: fixed;
background-color: rgb(245, 245, 245);
width: 1335px;
height: 780px;
}
#left7 .CodeMirror {
/* border-top: 1px solid black;
border-bottom: 1px solid black; */
border: 1px solid #eee;
height: 700px;
width: 940px;
}
.etable table,
.etable table td {
color: #000;
cursor: auto;
}
/* copy from github-css https://github.com/sindresorhus/github-markdown-css */
.etable table {
border-spacing: 0;
border-collapse: collapse;
}
.etable table {
margin-top: 0;
margin-bottom: 16px;
}
.etable table {
display: block;
width: 100%;
overflow: auto;
}
.etable table th {
font-weight: 600;
}
.etable table th,
.etable table td {
padding: 6px 13px;
border: 1px solid #dfe2e5;
}
.etable table tr {
background-color: #fff;
border-top: 1px solid #c6cbd1;
}
.etable table tr:nth-child(2n) {
background-color: #f6f8fa;
}
/* copy end --------------------------------------------- */
.etable tr {width:100%}
.etable tr > :nth-child(1) {width:20%}
.etable tr > :nth-child(2) {width:20%}
.etable tr > :nth-child(3) {width:60%}
.etable table {
overflow: visible;
}
.etable tr:not(:first-child) > :last-child:hover {
border: 1px solid rgb(87, 198, 232);
box-shadow: 0px 0px 3px rgb(87, 198, 232);
}
.etable tr:not(:first-child) > :nth-child(2):hover,
.etable tr:not(:first-child) > :nth-child(1):hover {
border: 1px solid rgb(87, 232, 198);
box-shadow: 0px 0px 3px rgb(87, 232, 198);
}
.etable tr:not(:first-child) > :last-child {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
position: relative;
}
div.etableInputDiv {
position: absolute;
padding: 5px 0 0 5px;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.etableInputDiv > * {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
background-color: rgba(255, 255, 255, 0);
border: none;
}
.etableInputDiv input {
}
.etableInputDiv select {
}
.etableInputDiv textarea {
resize: none;
}
.etableInputDiv textarea:hover {
margin: -5px;
}

547
_server/editor.js Normal file
View File

@ -0,0 +1,547 @@
function editor() {
this.version = "2.0";
this.material = {};
}
editor.prototype.init = function(callback){
var afterCoreReset = function(){
main.editor.disableGlobalAnimate=false;//允许GlobalAnimate
/* core.setHeroMoveTriggerInterval(); */
editor.reset(function(){
editor.drawMapBg();
var mapArray = core.maps.save(core.status.maps,core.status.floorId);
editor.map = mapArray.map(function(v){return v.map(function(v){return editor.ids[[editor.indexs[parseInt(v)][0]]]})});
editor.updateMap();
editor.currentFloorId=core.status.floorId;
editor.currentFloorData = core.floors[core.status.floorId];
if (Boolean(callback))callback();
});
}
var afterMainInit = function(){
core.floors=JSON.parse(JSON.stringify(core.floors,function(k,v){if(v instanceof Function){return v.toString()}else return v}));
core.data=JSON.parse(JSON.stringify(core.data,function(k,v){if(v instanceof Function){return v.toString()}else return v}));
data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d=JSON.parse(JSON.stringify(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d,function(k,v){if(v instanceof Function){return v.toString()}else return v}));
editor.main=main;
editor.core=core;
editor.fs=fs;
editor_file = editor_file(editor, function() {
editor.file=editor_file;
editor_mode = editor_mode(editor);
editor.mode=editor_mode;
editor.material.images=core.material.images;
editor.listen(); // 开始监听事件
core.resetStatus(core.firstData.hero, null, core.firstData.floorId, null, core.initStatus.maps);
core.changeFloor(core.status.floorId, null, core.firstData.hero.loc, null, function() {
afterCoreReset();
}, true);
core.events.setInitData(null);
});
}
afterMainInit();
}
editor.prototype.reset = function(callback){
editor.idsInit(core.maps, core.icons.icons); // 初始化图片素材信息
editor.drawInitData(core.icons.icons); // 初始化绘图
if(Boolean(callback))callback();
}
editor.prototype.idsInit = function(maps, icons){
editor.ids = [0];
editor.indexs = [];
var MAX_NUM = 400;
var getInfoById = function(id){
var block = maps.initBlock(0, 0, id);
if(hasOwnProp(block, 'event')){
return block;
}
}
var point = 0;
for(var i=0; i<MAX_NUM; i++){
var indexBlock = getInfoById(i);
editor.indexs[i] = [];
if(indexBlock){
var id = indexBlock.event.id;
var indexId = indexBlock.id;
var allCls = Object.keys(icons);
for(var j=0; j<allCls.length; j++){
if(id in icons[allCls[j]] ){
editor.ids.push({'idnum':indexId,'id':id,'images':allCls[j],'y':icons[allCls[j]][id]});
point++;
editor.indexs[i].push(point);
}
}
}
}
editor.indexs[0]=[0];
}
editor.prototype.drawInitData = function (icons) {
var ratio=1;
var images=editor.material.images;
var maxHeight=700;
var sumWidth=0;
editor.widthsX={};
// var imgNames = Object.keys(images); //还是固定顺序吧;
var imgNames = ["terrains", "animates", "enemys", "enemy48", "items", "npcs", "npc48", "autotile"];
for(var ii=0; ii<imgNames.length; ii++){
var img=imgNames[ii], tempy = 0;
if(img == 'autotile'){
var autotiles = images[img];
for(var im in autotiles){
tempy += autotiles[im].height;
}
editor.widthsX[img]=[img, sumWidth/32, (sumWidth+3*32)/32, tempy];
sumWidth += 3*32;
maxHeight = Math.max(maxHeight, tempy);
continue;
}
if(img == 'terrains'){
editor.widthsX[img]=[img, sumWidth/32, (sumWidth+images[img].width)/32, images[img].height+32]
sumWidth += images[img].width;
maxHeight = Math.max(maxHeight, images[img].height+32);
continue;
}
editor.widthsX[img]=[img, sumWidth/32, (sumWidth+images[img].width)/32, images[img].height];
sumWidth += images[img].width;
maxHeight = Math.max(maxHeight, images[img].height);
}
var fullWidth=~~(sumWidth*ratio);
var fullHeight=~~(maxHeight*ratio);
if (fullWidth > edata.width) edata.style.width = (edata.width = fullWidth)/ratio + 'px';
edata.style.height = (edata.height = fullHeight)/ratio + 'px';
var dc = edata.getContext('2d');
var nowx = 0;
var nowy = 0;
for(var ii=0; ii<imgNames.length; ii++){
var img=imgNames[ii];
if(img == 'terrains'){
dc.drawImage(images[img], nowx, 32);
nowx += images[img].width;
continue;
}
if(img == 'autotile'){
var autotiles = images[img];
for(var im in autotiles){
dc.drawImage(autotiles[im], nowx, nowy);
nowy += autotiles[im].height;
}
continue;
}
dc.drawImage(images[img], nowx, 0)
nowx += images[img].width;
}
bgSelect.bgs = Object.keys(icons.terrains);
//editor.drawMapBg();
//editor.mapInit();
}
editor.prototype.mapInit = function(){
var ec = document.getElementById('event').getContext('2d');
ec.clearRect(0, 0, 416, 416);
editor.map = [];
for(var y=0; y<13; y++){
editor.map[y] = [];
for(var x = 0; x<13; x++){
editor.map[y][x] = 0;
}
}
editor.currentFloorData.map=editor.map;
editor.currentFloorData.firstArrive=[];
editor.currentFloorData.events={};
editor.currentFloorData.changeFloor={};
editor.currentFloorData.afterBattle={};
editor.currentFloorData.afterGetItem={};
editor.currentFloorData.afterOpenDoor={};
editor.currentFloorData.cannotMove={};
}
editor.prototype.drawMapBg = function(img){
var bgc = bg.getContext('2d');
if (!core.isset(editor.bgY) || editor.bgY == 0){
editor.main.editor.drawMapBg();
return;
}
for (var ii = 0; ii < 13; ii++)
for (var jj = 0; jj < 13; jj++) {
bgc.clearRect(ii*32, jj*32, 32, 32);
bgc.drawImage(editor.material.images['terrains'], 0, 32*(editor.bgY||0), 32, 32, ii*32, jj*32, 32, 32);
}
if(img){
bgc.drawImage(img, 0, 0, 416, 416);
}
}
editor.prototype.updateMap = function(){
var blocks = main.editor.mapIntoBlocks(editor.map.map(function(v){return v.map(function(v){return v.idnum||v||0})}),{'events':{},'changeFloor':{}});
core.status.thisMap.blocks = blocks;
main.editor.updateMap();
var drawTile = function(ctx, x, y, tileInfo){ // 绘制一个普通块
//ctx.clearRect(x*32, y*32, 32, 32);
if(tileInfo == 0) return;
if(typeof(tileInfo) == typeof([][0]) || !hasOwnProp(tileInfo, 'idnum')) {//未定义块画红块
if(typeof(tileInfo) != typeof([][0]) && hasOwnProp(tileInfo, 'images')){
ctx.drawImage(editor.material.images[tileInfo.images], 0, tileInfo.y*32, 32, 32, x*32, y*32, 32, 32);
}
ctx.strokeStyle = 'red';
var OFFSET = 2;
ctx.lineWidth = OFFSET;
ctx.strokeRect(x*32+OFFSET, y*32+OFFSET, 32-OFFSET*2, 32-OFFSET*2);
ctx.font = "30px Verdana";
ctx.textAlign = 'center'
ctx.fillStyle = 'red';
ctx.fillText("?", x*32+16, y*32+27);
return;
}
//ctx.drawImage(editor.material.images[tileInfo.images], 0, tileInfo.y*32, 32, 32, x*32, y*32, 32, 32);
}
/*
// autotile的相关处理
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){ //index为autotile的图块索引1-48
var sx = 16*((index-1)%6), sy = 16*(~~((index-1)/6));
ctx.drawImage(autotileImg, sx, sy, 16, 16, dx, dy, 16, 16);
}
var isAutotile = function(info){
if(typeof(info)=='object' && hasOwnProp(info, 'images') && info.images=='autotile') return true;
return false;
}
var getAutotileAroundId = function(currId, x, y){ //与autotile当前idnum一致返回1否则返回0
if(x>=0 && y >=0 && x<13 && y<13 && isAutotile(editor.map[y][x]) && editor.map[y][x].idnum == currId)
return 1;
else if(x<0 || y<0 || x>12 || y>12) return 1; //边界外视为通用autotile这样好看些
else
return 0;
}
var checkAround = function(x, y){ // 得到周围四个32*32块周围每块都包含当前块的1/4不清楚的话画下图你就明白的数组索引
var currId = editor.map[y][x].idnum;
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 addIndexToAutotileInfo = 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]);
}
editor.map[y][x].blockIndex = indexArr;
}
var drawAutotile = function(ctx, x, y, info){ // 绘制一个autotile
ctx.clearRect(x*32, y*32, 32, 32);
//修正四个边角的固定搭配
if(info.blockIndex[0] == 13){
if(info.blockIndex[1] == 16) info.blockIndex[1] = 14;
if(info.blockIndex[2] == 31) info.blockIndex[2] = 19;
}
if(info.blockIndex[1] == 18){
if(info.blockIndex[0] == 15) info.blockIndex[0] = 17;
if(info.blockIndex[3] == 36) info.blockIndex[3] = 24;
}
if(info.blockIndex[2] == 43){
if(info.blockIndex[0] == 25) info.blockIndex[0] = 37;
if(info.blockIndex[3] == 46) info.blockIndex[3] = 44;
}
if(info.blockIndex[3] == 48){
if(info.blockIndex[1] == 30) info.blockIndex[1] = 42;
if(info.blockIndex[2] == 45) info.blockIndex[2] = 47;
}
for(var i=0; i<4; i++){
var index = info.blockIndex[i];
var dx = x*32 + 16*(i%2), dy = y*32 + 16*(~~(i/2));
drawBlockByIndex(ctx, dx, dy, editor.material.images[info.images][info.id], index);
}
}
*/
// 绘制地图 start
var eventCtx = document.getElementById('event').getContext("2d");
for(var y=0; y<13; y++)
for(var x=0; x<13; x++){
var tileInfo = editor.map[y][x];
if(false && isAutotile(tileInfo)){
addIndexToAutotileInfo(x, y);
drawAutotile(eventCtx, x, y, tileInfo);
}else drawTile(eventCtx, x, y, tileInfo);
}
// 绘制地图 end
}
editor.prototype.changeFloor = function(floorId,callback) {
editor.currentFloorData.map = editor.map.map(function(v){return v.map(function(v){return v.idnum||v||0})});
core.changeFloor(floorId, null, core.firstData.hero.loc, null, function(){
editor.drawMapBg();
var mapArray = core.maps.save(core.status.maps,core.status.floorId);
editor.map = mapArray.map(function(v){return v.map(function(v){return editor.ids[[editor.indexs[parseInt(v)][0]]]})});
editor.updateMap();
editor.currentFloorId=core.status.floorId;
editor.currentFloorData = core.floors[core.status.floorId];
editor_mode.floor();
if (core.isset(callback))callback();
});
}
editor.prototype.guid = function() {
return 'id_'+'xxxxxxxx_xxxx_4xxx_yxxx_xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}
editor.prototype.listen = function() {
var uc = eui.getContext('2d');
function fillPos(pos) {
uc.fillStyle = '#' + ~~(Math.random() * 8) + ~~(Math.random() * 8) + ~~(Math.random() * 8);
uc.fillRect(pos.x * 32 + 12, pos.y * 32 + 12, 8, 8);
}//在格子内画一个随机色块
function eToLoc(e) {
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
editor.loc = {
'x': scrollLeft+e.clientX - mid.offsetLeft-mapEdit.offsetLeft,
'y': scrollTop+e.clientY - mid.offsetTop-mapEdit.offsetTop,
'size': 32
};
return editor.loc; }//返回可用的组件内坐标
function locToPos(loc) {
editor.pos = { 'x': ~~(loc.x / loc.size), 'y': ~~(loc.y / loc.size) }
return editor.pos;
}
var holdingPath = 0;
var stepPostfix = null;//用于存放寻路检测的第一个点之后的后续移动
var mouseOutCheck = 2;
function clear1() {
if (mouseOutCheck > 1) {
mouseOutCheck--;
setTimeout(clear1, 1000);
return;
}
holdingPath = 0;
stepPostfix = [];
uc.clearRect(0, 0, 416, 416);
}//用于鼠标移出canvas时的自动清除状态
eui.onmousedown = function (e) {
if(!selectBox.isSelected) {
var loc = eToLoc(e);
var pos = locToPos(loc);
editor_mode.onmode('nextChange');
editor_mode.onmode('loc');
editor_mode.loc();
tip.whichShow = 1;
return;
}
holdingPath = 1;
mouseOutCheck = 2;
setTimeout(clear1);
e.stopPropagation();
uc.clearRect(0, 0, 416, 416);
var loc = eToLoc(e);
var pos = locToPos(loc);
stepPostfix = [];
stepPostfix.push(pos);
fillPos(pos);
}
eui.onmousemove = function (e) {
if(!selectBox.isSelected) {
// tip.whichShow = 1;
return;
}
if (holdingPath == 0) { return; }
mouseOutCheck = 2;
e.stopPropagation();
var loc = eToLoc(e);
var pos = locToPos(loc);
var pos0 = stepPostfix[stepPostfix.length - 1]
var directionDistance = [pos.y - pos0.y, pos0.x - pos.x, pos0.y - pos.y, pos.x - pos0.x]
var max = 0, index = 4;
for (var i = 0; i < 4; i++) {
if (directionDistance[i] > max) {
index = i;
max = directionDistance[i];
}
}
var 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;
stepPostfix.push(pos);
fillPos(pos);
}
}
eui.onmouseup = function (e) {
if(!selectBox.isSelected) {
tip.whichShow = 1;
return;
}
holdingPath = 0;
e.stopPropagation();
var loc = eToLoc(e);
if (stepPostfix.length) {
preMapData = JSON.parse(JSON.stringify(editor.map));
currDrawData.pos = JSON.parse(JSON.stringify(stepPostfix));
currDrawData.info = JSON.parse(JSON.stringify(editor.info));
reDo = null;
// console.log(stepPostfix);
for (var ii = 0; ii < stepPostfix.length; ii++)
editor.map[stepPostfix[ii].y][stepPostfix[ii].x] = editor.info;
// console.log(editor.map);
editor.updateMap();
holdingPath = 0;
stepPostfix = [];
uc.clearRect(0, 0, 416, 416);
}
}
var preMapData = {};
var currDrawData = {
pos: [],
info: {}
};
var reDo = null;
document.body.onkeydown = function(e) {
// 禁止快捷键的默认行为
if( e.ctrlKey && ( e.keyCode == 90 || e.keyCode == 89 ) )
e.preventDefault();
//Ctrl+z 撤销上一步undo
if(e.keyCode == 90 && e.ctrlKey && preMapData && currDrawData.pos.length){
editor.map = JSON.parse(JSON.stringify(preMapData));
editor.updateMap();
reDo = JSON.parse(JSON.stringify(currDrawData));
currDrawData = {pos: [],info: {}};
preMapData = null;
}
//Ctrl+y 重做一步redo
if(e.keyCode == 89 && e.ctrlKey && reDo && reDo.pos.length){
preMapData = JSON.parse(JSON.stringify(editor.map));
for(var j=0; j<reDo.pos.length;j++)
editor.map[reDo.pos[j].y][reDo.pos[j].x] = JSON.parse(JSON.stringify(reDo.info));
editor.updateMap();
currDrawData = JSON.parse(JSON.stringify(reDo));
reDo = null;
}
}
edata.onmousedown = function (e) {
e.stopPropagation();
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
var loc = {
'x': scrollLeft + e.clientX + iconLib.scrollLeft - right.offsetLeft-iconLib.offsetLeft,
'y': scrollTop + e.clientY + iconLib.scrollTop - right.offsetTop-iconLib.offsetTop,
'size': 32
};
editor.loc = loc;
var pos = locToPos(loc);
for (var spriter in editor.widthsX){
if(pos.x>=editor.widthsX[spriter][1] && pos.x<editor.widthsX[spriter][2]){
var ysize = spriter.indexOf('48')===-1?32:48;
loc.ysize = ysize;
pos.y = ~~(loc.y / loc.ysize);
pos.x=editor.widthsX[spriter][1];
pos.images = editor.widthsX[spriter][0];
var autotiles = editor.material.images['autotile'];
if(pos.images=='autotile'){
var imNames = Object.keys(autotiles);
if((pos.y+1)*ysize > editor.widthsX[spriter][3])
pos.y = ~~(editor.widthsX[spriter][3]/ysize)-4;
else{
for(var i=0; i<imNames.length; i++){
if(pos.y >= 4*i && pos.y < 4*(i+1)){
pos.images = imNames[i];
pos.y = 4*i;
}
}
}
}else if((pos.y+1)*ysize > editor.widthsX[spriter][3])
pos.y = ~~(editor.widthsX[spriter][3]/ysize)-1;
selectBox.isSelected = true;
// console.log(pos,editor.material.images[pos.images].height)
dataSelection.style.left = pos.x*32 +'px';
dataSelection.style.top = pos.y*ysize +'px';
dataSelection.style.height = ysize-6+'px';
if(pos.x==0&&pos.y==0){
// editor.info={idnum:0, id:'empty','images':'清除块', 'y':0};
editor.info=0;
}else{
if(hasOwnProp(autotiles, pos.images)) editor.info={'images':pos.images, 'y':0};
else if(pos.images == 'terrains') editor.info={'images':pos.images, 'y':pos.y-1};
else editor.info={'images':pos.images, 'y':pos.y};
for (var ii=0;ii<editor.ids.length;ii++){
if( ( editor.info.images==editor.ids[ii].images
&& editor.info.y==editor.ids[ii].y )
|| (hasOwnProp(autotiles, pos.images) && editor.info.images==editor.ids[ii].id
&& editor.info.y==editor.ids[ii].y)){
editor.info = editor.ids[ii];
break;
}
}
}
tip.infos = JSON.parse(JSON.stringify(editor.info));
editor_mode.onmode('nextChange');
editor_mode.onmode('emenyitem');
editor_mode.emenyitem();
}
}
}
}//绑定事件
/*
editor.loc
editor.pos
editor.info
始终是最后一次点击的结果
注意editor.info可能因为点击其他地方而被清空
*/
editor = new editor();

393
_server/editor_blockly.js Normal file
View File

@ -0,0 +1,393 @@
editor_blockly = function(){
var editor_blockly = {};
initscript=String.raw`
(function(){
var getCategory = function(name){
for(var node of document.getElementById('toolbox').children) {
if(node.getAttribute('name')==name) return node;
}
}
var toolboxObj = {
'entry':[
MotaActionFunctions.actionParser.parse([
"欢迎使用事件编辑器",
"本事件触发一次后会消失",
{"type": "hide", "time": 500},
],'event'),
MotaActionBlocks['changeFloor_m'].xmlText(),
MotaActionFunctions.actionParser.parse({"type": "choices", "choices": [
{"text": "攻击+\${point}", "action": [
{"type": "setValue", "name": "status:atk", "value": "status:atk+\${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}"},
]},
]},'point'),
MotaActionFunctions.actionParser.parse({
"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"}
]
},'shop'),
MotaActionBlocks['afterBattle_m'].xmlText(),
MotaActionBlocks['afterGetItem_m'].xmlText(),
MotaActionBlocks['afterOpenDoor_m'].xmlText(),
MotaActionBlocks['firstArrive_m'].xmlText(),
],
'statement':[
'<label text="显示文字"></label>',
MotaActionBlocks['text_0_s'].xmlText(),
MotaActionBlocks['text_1_s'].xmlText(),
MotaActionFunctions.actionParser.parseList({"type": "choices", "text": "是否跳过剧情", "choices": [
{"text": "是", "action": []},
{"text": "否", "action": [
{"type": "autoText", "text": "\\t[小妖精,fairy]双击方块进入多行编辑\\n用户无法跳过自动剧情文本,大段剧情文本请添加“是否跳过剧情”的提示\\n自动剧情文本\\n自动剧情文本\\n自动剧情文本", "time" :3000},
{"type": "autoText", "text": "(可以右键方块后点复制)", "time" :3000},
]},
]}),
MotaActionBlocks['setText_s'].xmlText(),
MotaActionBlocks['showImage_0_s'].xmlText(),
MotaActionBlocks['showImage_1_s'].xmlText(),
MotaActionBlocks['tip_s'].xmlText(),
MotaActionBlocks['openShop_s'].xmlText(),
MotaActionBlocks['win_s'].xmlText(),
MotaActionBlocks['lose_s'].xmlText(),
MotaActionBlocks['choices_s'].xmlText([
'选择剑或者盾','流浪者','man',MotaActionBlocks['choicesContext'].xmlText([
'剑',MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [3,3]}]),
MotaActionBlocks['choicesContext'].xmlText([
'盾',MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [9,3]}]),
])
])
]),
'<label text="数据相关"></label>',
MotaActionBlocks['setValue_s'].xmlText(),
MotaActionBlocks['input_s'].xmlText(),
MotaActionBlocks['update_s'].xmlText(),
MotaActionBlocks['moveHero_s'].xmlText(),
MotaActionBlocks['changeFloor_s'].xmlText(),
MotaActionBlocks['changePos_0_s'].xmlText(),
MotaActionBlocks['changePos_1_s'].xmlText(),
MotaActionBlocks['battle_s'].xmlText(),
MotaActionBlocks['openDoor_s'].xmlText(),
MotaActionBlocks['setBlock_s'].xmlText(),
'<label text="事件控制"></label>',
MotaActionBlocks['if_s'].xmlText(),
MotaActionBlocks['revisit_s'].xmlText(),
MotaActionBlocks['exit_s'].xmlText(),
MotaActionBlocks['show_s'].xmlText(),
MotaActionBlocks['hide_s'].xmlText(),
MotaActionBlocks['trigger_s'].xmlText(),
MotaActionBlocks['move_s'].xmlText(),
MotaActionBlocks['disableShop_s'].xmlText(),
'<label text="特效/声音"></label>',
MotaActionBlocks['sleep_s'].xmlText(),
MotaActionBlocks['animate_s'].xmlText(),
MotaActionBlocks['setFg_0_s'].xmlText(),
MotaActionBlocks['setFg_1_s'].xmlText(),
MotaActionBlocks['setWeather_s'].xmlText(),
MotaActionBlocks['playBgm_s'].xmlText(),
MotaActionBlocks['pauseBgm_s'].xmlText(),
MotaActionBlocks['resumeBgm_s'].xmlText(),
MotaActionBlocks['playSound_s'].xmlText(),
'<label text="其他"></label>',
MotaActionBlocks['function_s'].xmlText(),
],
'value':[
MotaActionBlocks['setValue_s'].xmlText(),
MotaActionBlocks['expression_arithmetic_0'].xmlText(),
MotaActionBlocks['negate_e'].xmlText(),
MotaActionBlocks['bool_e'].xmlText(),
MotaActionBlocks['idString_e'].xmlText(),
MotaActionBlocks['idString_1_e'].xmlText(),
MotaActionBlocks['idString_2_e'].xmlText(),
MotaActionBlocks['evalString_e'].xmlText(),
],
'template':[
'<label text="检测音乐如果没有开启则系统提示开启"></label>',
MotaActionFunctions.actionParser.parseList({"type": "if", "condition": "!core.musicStatus.bgmStatus",
"true": [
"\t[系统提示]你当前音乐处于关闭状态,本塔开音乐游戏效果更佳"
],
"false": []
}),
'<label text="战前剧情"></label>',
MotaActionFunctions.actionParser.parse({
"trigger": "action",
"displayDamage": true,
"data": [
' ... 战前剧情',
{"type": "battle", "id": "greenSlime"},
' ... 战后剧情;请注意上面的强制战斗不会使怪物消失',
'需要下一句来调用{"type": "hide"}来隐藏事件',
{"type": "hide"},
]
},'event'),
'<label text="打怪掉落道具"></label>',
MotaActionFunctions.actionParser.parse([
'怪物变成了黄钥匙(黄钥匙idnum是21)',
'打怪变成可对话的NPC: https://ckcz123.github.io/mota-js/#/event?id=%e6%89%93%e6%80%aa%e5%8f%98%e6%88%90%e5%8f%af%e5%af%b9%e8%af%9d%e7%9a%84npc%ef%bc%88%e6%80%aa%e7%89%a9-gtnpc%ef%bc%89',
{"type": "setBlock", "number": 21}
],'afterBattle'),
'<label text="打怪开门"></label>',
MotaActionFunctions.actionParser.parse([
{"type": "setValue", "name": "flag:__door_name__", "value": "flag:__door_name__+1"},
{"type": "if", "condition": "flag:__door_name__==2",
"true": [
{"type": "openDoor", "loc": [10,5]}
],
"false": []
},
],'afterBattle'),
'<label text="获得圣水后变成墙"></label>',
MotaActionFunctions.actionParser.parse({
"trigger": "action",
"noPass": true,
"data": [
{"type": "if", "condition": "flag:hasSuperPotion",
"true": [],
"false": [
{"type":"setValue", "name":"status:hp", "value":"status:hp*2"},
{"type":"setBlock", "number": 1},
{"type":"setValue", "name":"flag:hasSuperPotion", "value": "true"}
]
}
]
},'event'),
],
}
var toolboxgap = '<sep gap="5"></sep>'
//xml_text = MotaActionFunctions.actionParser.parse(obj,type||'event')
//MotaActionBlocks['idString_e'].xmlText()
for (var name in toolboxObj){
getCategory(name).innerHTML = toolboxObj[name].join(toolboxgap);
}
var workspace = Blockly.inject('blocklyDiv',{
media: '_server/blockly/media/',
toolbox: document.getElementById('toolbox'),
zoom:{
controls: true,
wheel: true,//false
startScale: 1.0,
maxScale: 3,
minScale: 0.3,
scaleSpeed: 1.08
},
trashcan: false,
});
var doubleClickCheck=[[0,'abc']];
function omitedcheckUpdateFunction(event) {
//console.log(event);
if(event.type==='ui'){
var newClick = [new Date().getTime(),event.blockId];
var lastClick = doubleClickCheck.shift();
doubleClickCheck.push(newClick);
if(newClick[0]-lastClick[0]<500){
if(newClick[1]===lastClick[1]){
editor_blockly.doubleClickBlock(newClick[1]);
}
}
}
try {
var code = Blockly.JavaScript.workspaceToCode(workspace);
codeAreaHL.setValue(code);
} catch (error) {
codeAreaHL.setValue(String(error));
if (error instanceof OmitedError){
var blockName = error.blockName;
var varName = error.varName;
var block = error.block;
}
console.log(error);
}
}
workspace.addChangeListener(omitedcheckUpdateFunction);
workspace.addChangeListener(Blockly.Events.disableOrphans);
editor_blockly.workspace = workspace;
MotaActionFunctions.workspace = function(){
return editor_blockly.workspace;
}
})();
`;
var input_='';
editor_blockly.runOne = function (){
//var printf = console.log;
//var printf = function(){};
var grammerFile = input_;
converter = new Converter().init();
converter.generBlocks(grammerFile);
//printf(converter.blocks);
converter.renderGrammerName();
//converter.generToolbox();
converter.generMainFile();
//printf(converter.mainFile.join(''));
console.log(converter);
var script = document.createElement('script');
//var initscript = document.getElementById('initscript').innerText;
script.innerHTML = converter.mainFile[5]+initscript;
document.body.appendChild(script);
}
var xhr=new XMLHttpRequest();
xhr.onreadystatechange = function (){
if(xhr.readyState!=4) return;
if(xhr.status!=200) {
alert("无法在file://下加载");
return;
}
input_=xhr.responseText;
editor_blockly.runOne();
}
xhr.open('GET','_server/blockly/MotaAction.g4',true);
xhr.send(null);
codeAreaHL = CodeMirror.fromTextArea(document.getElementById("codeArea"), {
lineNumbers: true,
matchBrackets: true,
lineWrapping: true,
continueComments: "Enter",
extraKeys: {"Ctrl-Q": "toggleComment"}
});
editor_blockly.showXML = function () {
var xml = Blockly.Xml.workspaceToDom(editor_blockly.workspace);
var xml_text = Blockly.Xml.domToPrettyText(xml);
console.log(xml_text);
var xml_text = Blockly.Xml.domToText(xml);
console.log(xml_text);
console.log(xml);
}
editor_blockly.runCode = function () {
// Generate JavaScript code and run it.
window.LoopTrap = 1000;
Blockly.JavaScript.INFINITE_LOOP_TRAP =
'if (--window.LoopTrap == 0) throw "Infinite loop.";\n';
var code = Blockly.JavaScript.workspaceToCode(editor_blockly.workspace);
Blockly.JavaScript.INFINITE_LOOP_TRAP = null;
try {
eval('obj=' + code);
console.log(obj);
} catch (e) {
alert(e);
}
}
editor_blockly.parse = function () {
MotaActionFunctions.parse(
eval('obj=' + codeAreaHL.getValue().replace(/[<>&]/g,function(c){return {'<':'&lt;','>':'&gt;','&':'&amp;'}[c];})),
document.getElementById('entryType').value
);
}
editor_blockly.id='';
editor_blockly.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');
var type = {
"['events']":'event',
"['changeFloor']":'changeFloor',
"['afterBattle']":'afterBattle',
"['afterGetItem']":'afterGetItem',
"['afterOpenDoor']":'afterOpenDoor',
//"['firstData']['shops']":'shop',
"--shop--未完成数组的处理":'shop',
"['firstArrive']":'firstArrive',
"['firstData']['startText']":'firstArrive',
"--point--未完成数据转移":'point',
}[field];
if(!type)return false;
editor_blockly.id=id_;
codeAreaHL.setValue(input.value);
document.getElementById('entryType').value = type;
editor_blockly.parse();
editor_blockly.show();
return true;
}
editor_blockly.show = function(){document.getElementById('left6').style='';}
editor_blockly.hide = function(){document.getElementById('left6').style='z-index:-1;opacity: 0;';}
editor_blockly.cancel = function(){
editor_blockly.id='';
editor_blockly.hide();
}
editor_blockly.confirm = function (){
if(!editor_blockly.id){
editor_blockly.id='';
return;
}
var setvalue = function(value){
var thisTr = document.getElementById(editor_blockly.id);
editor_blockly.id='';
var input = thisTr.children[2].children[0].children[0];
input.value = value;
editor_blockly.hide();
input.onchange();
}
if(codeAreaHL.getValue()===''){
setvalue('null');
return;
}
var code = Blockly.JavaScript.workspaceToCode(editor_blockly.workspace);
eval('var obj=' + code);
setvalue(JSON.stringify(obj));
}
editor_blockly.doubleClickBlock = function (blockId){
var b=editor_blockly.workspace.getBlockById(blockId);
//console.log(b);
var textStringDict = {
'text_0_s':'EvalString_0',
'text_1_s':'EvalString_2',
'autoText_s':'EvalString_2',
'choices_s':'EvalString_0',
'function_s':'RawEvalString_0',
}
var f=b?textStringDict[b.type]:null;
if(f){
var value = b.getFieldValue(f);
//多行编辑
editor_multi.multiLineEdit(value,b,f,function(newvalue,b,f){
if(textStringDict[b.type]!=='RawEvalString_0'){}
b.setFieldValue(newvalue.split('\n').join('\\n'),f);
});
}
}
return editor_blockly;
}
//editor_blockly=editor_blockly();

View File

@ -1,63 +1,608 @@
(function(){
editor_file = {};
editor_file.getFloorFileList = function(editor,callback){
if (isset(callback)) callback(['simple0.js','simple1.js','simple2.js'],null);
}
//callback(Array<String>,err:String)
editor_file.loadFloorFile = function(editor,filename,callback){
if (isset(callback)) callback('',null);
}
//callback(String,err:String)
editor_file.saveFloorFile = function(editor,callback){
if (isset(callback)) callback(null);
}
//callback(err:String)
editor_file.saveFloorFile = function(editor,saveAsFilename,callback){
if (isset(callback)) callback(null);
}
//callback(err:String)
editor_file.changeIdAndIdnum = function(editor,id,idnum,callback){
if (isset(callback)) callback(null);
}
//callback(err:String)
editor_file.editItem = function(editor,id,callback){
if (isset(callback)) callback('',null);
}
//callback(String,err:String)
editor_file.editEnemy = function(editor,id,callback){
if (isset(callback)) callback({'name': '初级巫师', 'hp': 100, 'atk': 120, 'def': 0, 'money': 16, 'experience': 0, 'special': 15, 'value': 100},null);
}
//callback(obj,err:String)
editor_file.editLoc = function(editor,x,y,input_value,callback){
if (isset(callback)) callback({"events":` [ // 守着道具的老人
"\t[老人,man]这些是本样板支持的所有的道具。\n\n道具分为三类items, constants, tools。\nitems 为即捡即用类道具,例如宝石、血瓶、剑盾等。\nconstants 为永久道具,例如怪物手册、楼层传送器、幸运金币等。\ntools 为消耗类道具,例如破墙镐、炸弹、中心对称飞行器等。\n\n后两类道具在工具栏中可以看到并使用。",
"\t[老人,man]有关道具效果定义在items.js中。\n目前大多数道具已有默认行为如有自定义的需求则需在items.js中修改代码。",
"\t[老人,man]constants 和 tools 各最多只允许12种多了会导致图标溢出。",
"\t[老人,man]拾取道具结束后可触发 afterGetItem 事件。\n\n有关事件的各种信息在下一层会有更为详细的说明。",
{"type": "hide", "time": 500} // 消失
],`,"changeFloor":"","afterBattle":"","afterGetItem":"","afterOpenDoor":""},null);
}
//callback(obj,err:String)
editor_file.editFloor = function(editor,input_value,callback){
if (isset(callback)) callback({"floorId": "sample0",
"title": "样板 0 层",
"name": "0",
"canFlyTo": true,
"canUseQuickShop": true,
"defaultGround": "ground",
"firstArrive":` [ // 第一次到该楼层触发的事件
"\t[样板提示]首次到达某层可以触发 firstArrive 事件该事件可类似于RMXP中的“自动执行脚本”。\n\n本事件支持一切的事件类型常常用来触发对话例如",
"\t[hero]我是谁?我从哪来?我又要到哪去?",
"\t[仙子,fairy]你问我...?我也不知道啊...",
"本层主要对道具、门、怪物等进行介绍,有关事件的各种信息在下一层会有更为详细的说明。",
],`},null);
}
//callback(obj,err:String)
var isset = function (val) {
if (val == undefined || val == null) {
return false;
}
return true
}
})();
editor_file = function(editor, callback){
var editor_file = {};
var commentjs={
'comment':'comment',
'data.comment':'dataComment',
'functions.comment':'functionsComment',
}
for(var key in commentjs){
(function(key){
var value = commentjs[key];
var script = document.createElement('script');
if (window.location.href.indexOf('_server')!==-1)
script.src = '../project/'+key+'.js';
else
script.src = 'project/'+key+'.js';
document.body.appendChild(script);
script.onload = function () {
editor_file[value]=eval(key.replace('.','_')+'_c456ea59_6018_45ef_8bcc_211a24c627dc');
var loaded = Boolean(callback);
for(var key_ in commentjs){loaded = loaded && editor_file[commentjs[key_]]}
if (loaded)callback();
}
})(key);
}
editor_file.getFloorFileList = function(callback){
if (!isset(callback)) {printe('未设置callback');throw('未设置callback')};
/* var fs = editor.fs;
fs.readdir('project/floors',function(err, data){
callback([data,err]);
}); */
callback([editor.core.floorIds,null]);
}
//callback([Array<String>,err:String])
editor_file.loadFloorFile = function(filename,callback){
//filename不含'/'不含'.js'
if (!isset(callback)) {printe('未设置callback');throw('未设置callback')};
/* var fs = editor.fs;
fs.readFile('project/floors/'+filename+'.js','utf-8',function(err, data){
if (err!=null){callback(err);return;}
data=data.split('=');
data=[data[0],data.slice(1).join('=')];
var varnameId = data[0].split('.').slice(-1)[0].trim();
var filenameId = filename.split('/').slice(-1)[0].split('\\').slice(-1)[0];
eval('b3917d1d_71c2_41f2_a8aa_481b215ffb99='+data[1]);
var floorData = b3917d1d_71c2_41f2_a8aa_481b215ffb99;
delete(b3917d1d_71c2_41f2_a8aa_481b215ffb99);
var floorId = floorData.floorId;
if (varnameId!=filenameId || filenameId!=floorId){
callback('文件名,第一行的变量名以及floorId不一致');
return;
}
editor.currentFloorId = floorId;
editor.currentFloorData = floorData;
callback(null)
}); */
editor.currentFloorId=editor.core.status.floorId;
editor.currentFloorData = editor.core.floors[editor.currentFloorId];
}
//callback(err:String)
editor_file.saveFloorFile = function(callback){
if (!isset(callback)) {printe('未设置callback');throw('未设置callback')};
/* if (!isset(editor.currentFloorId) || !isset(editor.currentFloorData)) {
callback('未选中文件或无数据');
} */
var filename = 'project/floors/' + editor.currentFloorId + '.js';
var datastr = ['main.floors.' , editor.currentFloorId , '=\n{'];
editor.currentFloorData.map = editor.map.map(function(v){return v.map(function(v){return v.idnum||v||0})});
for(var ii in editor.currentFloorData)
if (editor.currentFloorData.hasOwnProperty(ii)) {
if (ii=='map')
datastr=datastr.concat(['\n"',ii,'": [\n',formatMap(editor.currentFloorData[ii]),'\n],']);
else
datastr=datastr.concat(['\n"',ii,'": ',JSON.stringify(editor.currentFloorData[ii],null,4),',']);
}
datastr=datastr.concat(['\n}']);
datastr=datastr.join('');
fs.writeFile(filename,encode(datastr),'base64',function(err, data){
callback(err);
});
}
//callback(err:String)
editor_file.saveFloorFileAs = function(saveAsFilename,callback){
//saveAsFilename不含'/'不含'.js'
if (!isset(callback)) {printe('未设置callback');throw('未设置callback')};
if (!isset(editor.currentFloorData)) {
callback('无数据');
}
editor.currentFloorData.map = editor.map.map(function(v){return v.map(function(v){return v.idnum||v||0})});
editor.currentFloorData=JSON.parse(JSON.stringify(editor.currentFloorData));
editor.currentFloorData.floorId=saveAsFilename;
editor.currentFloorId=saveAsFilename;
editor_file.saveFloorFile(callback);
}
//callback(err:String)
////////////////////////////////////////////////////////////////////
editor_file.changeIdAndIdnum = function(id,idnum,info,callback){
if (!isset(callback)) {printe('未设置callback');throw('未设置callback')};
//检查maps中是否有重复的idnum或id
var change = -1;
for(var ii in editor.core.maps.blocksInfo){
if (ii==idnum) {
//暂时只允许创建新的不允许修改已有的
//if (info.idnum==idnum){change=ii;break;}//修改id
callback('idnum重复了');
return;
}
if (editor.core.maps.blocksInfo[ii].id==id) {
//if (info.id==id){change=ii;break;}//修改idnum
callback('id重复了');
return;
}
}
/*
if (change!=-1 && change!=idnum){//修改idnum
editor.core.maps.blocksInfo[idnum] = editor.core.maps.blocksInfo[change];
delete(editor.core.maps.blocksInfo[change]);
} else if (change==idnum) {//修改id
var oldid = editor.core.maps.blocksInfo[idnum].id;
editor.core.maps.blocksInfo[idnum].id = id;
for(var ii in editor.core.icons.icons){
if (ii.hasOwnProperty(oldid)){
ii[id]=ii[oldid];
delete(ii[oldid]);
}
}
} else {//创建新的
editor.core.maps.blocksInfo[idnum]={'cls': info.images, 'id':id};
editor.core.icons.icons[info.images][id]=info.y;
}
*/
var templist=[];
var tempcallback = function (err) {
templist.push(err);
if (templist.length ==2 ) {
if (templist[0]!=null || templist[1]!=null)
callback((templist[0]||'')+'\n'+(templist[1]||''));
//这里如果一个成功一个失败会出严重bug
else
callback(null);
}
}
saveSetting('maps',[["add","['"+idnum+"']",{'cls': info.images, 'id':id}]],tempcallback);
saveSetting('icons',[["add","['"+info.images+"']['"+id+"']",info.y]],tempcallback);
if(info.images==='items'){
saveSetting('items',[["change"/*其实应该是add*/,"['items']['"+id+"']",editor_file.comment.items_template]],function(err){if(err){printe(err);throw(err)}});
}
if(info.images==='enemys'){
saveSetting('enemys',[["change"/*其实应该是add*/,"['enemys']['"+id+"']",editor_file.comment.enemys_template]],function(err){if(err){printe(err);throw(err)}});
}
callback(null);
}
//callback(err:String)
editor_file.editItem = function(id,actionList,callback){
/*actionList:[
["change","['items']['name']","红宝石的新名字"],
["add","['items']['新的和name同级的属性']",123],
["change","['itemEffectTip']","',攻击力+'+editor.core.values.redJewel"],
]
[]时只查询不修改
*/
if (!isset(callback)) {printe('未设置callback');throw('未设置callback')};
if (isset(actionList) && actionList.length > 0){
actionList.forEach(function (value) {
var tempindex = value[1].indexOf(']')+1;
value[1] = [value[1].slice(0,tempindex),"['"+id+"']",value[1].slice(tempindex)].join('');
});
saveSetting('items',actionList,function (err) {
callback([
{'items':(function(){
var locObj=Object.assign({},editor.core.items.items[id]);
Object.keys(editor_file.comment.items.items).forEach(function(v){
if (!isset(editor.core.items.items[id][v]))
/* locObj[v]=editor.core.items.items[id][v];
else */
locObj[v]=null;
});
return locObj;
})(),
'itemEffect':editor.core.items.itemEffect[id],'itemEffectTip':editor.core.items.itemEffectTip[id]},
editor_file.comment.items,
err]);
});
} else {
callback([
{'items':(function(){
var locObj=Object.assign({},editor.core.items.items[id]);
Object.keys(editor_file.comment.items.items).forEach(function(v){
if (!isset(editor.core.items.items[id][v]))
/* locObj[v]=editor.core.items.items[id][v];
else */
locObj[v]=null;
});
return locObj;
})(),
'itemEffect':editor.core.items.itemEffect[id],'itemEffectTip':editor.core.items.itemEffectTip[id]},
editor_file.comment.items,
null]);
}
//只有items.cls是items的才有itemEffect和itemEffectTip,keys和constants和tools只有items
}
//callback([obj,commentObj,err:String])
editor_file.editEnemy = function(id,actionList,callback){
/*actionList:[
["change","['name']","初级巫师的新名字"],
["add","['新的和name同级的属性']",123],
["change","['bomb']",null],
]
[]时只查询不修改
*/
if (!isset(callback)) {printe('未设置callback');throw('未设置callback')};
if (isset(actionList) && actionList.length > 0){
actionList.forEach(function (value) {
value[1] = "['"+id+"']"+value[1];
});
saveSetting('enemys',actionList,function (err) {
callback([
(function(){
var locObj=Object.assign({},editor.core.enemys.enemys[id]);
Object.keys(editor_file.comment.enemys).forEach(function(v){
if (!isset(editor.core.enemys.enemys[id][v]))
/* locObj[v]=editor.core.enemys.enemys[id][v];
else */
locObj[v]=null;
});
return locObj;
})(),
editor_file.comment.enemys,
err]);
});
} else {
callback([
(function(){
var locObj=Object.assign({},editor.core.enemys.enemys[id]);
Object.keys(editor_file.comment.enemys).forEach(function(v){
if (!isset(editor.core.enemys.enemys[id][v]))
/* locObj[v]=editor.core.enemys.enemys[id][v];
else */
locObj[v]=null;
});
return locObj;
})(),
editor_file.comment.enemys,
null]);
}
}
//callback([obj,commentObj,err:String])
////////////////////////////////////////////////////////////////////
editor_file.editLoc = function(x,y,actionList,callback){
/*actionList:[
["change","['events']",["\t[老人,magician]领域、夹击。\n请注意领域怪需要设置value为伤害数值可参见样板中初级巫师的写法。"]],
["change","['afterBattle']",null],
]
[]时只查询不修改
*/
if (!isset(callback)) {printe('未设置callback');throw('未设置callback')};
if (isset(actionList) && actionList.length > 0){
actionList.forEach(function (value) {
value[1] = value[1]+"['"+x+","+y+"']";
});
saveSetting('floors',actionList,function (err) {
callback([
(function(){
var locObj={};
Object.keys(editor_file.comment.floors.loc).forEach(function(v){
if (isset(editor.currentFloorData[v][x+','+y]))
locObj[v]=editor.currentFloorData[v][x+','+y];
else
locObj[v]=null;
});
return locObj;
})(),
editor_file.comment.floors.loc,
err]);
});
} else {
callback([
(function(){
var locObj={};
Object.keys(editor_file.comment.floors.loc).forEach(function(v){
if (isset(editor.currentFloorData[v][x+','+y]))
locObj[v]=editor.currentFloorData[v][x+','+y];
else
locObj[v]=null;
});
return locObj;
})(),
editor_file.comment.floors.loc,
null]);
}
}
//callback([obj,commentObj,err:String])
////////////////////////////////////////////////////////////////////
editor_file.editFloor = function(actionList,callback){
/*actionList:[
["change","['title']",'样板 3 层'],
["change","['color']",null],
]
[]时只查询不修改
*/
if (!isset(callback)) {printe('未设置callback');throw('未设置callback')};
if (isset(actionList) && actionList.length > 0){
saveSetting('floors',actionList,function (err) {
callback([
(function(){
var locObj=Object.assign({},editor.currentFloorData);
Object.keys(editor_file.comment.floors.floor).forEach(function(v){
if (!isset(editor.currentFloorData[v]))
/* locObj[v]=editor.currentFloorData[v];
else */
locObj[v]=null;
});
Object.keys(editor_file.comment.floors.loc).forEach(function(v){
delete(locObj[v]);
});
delete(locObj.map);
return locObj;
})(),
editor_file.comment.floors.floor,
err]);
});
} else {
callback([
(function(){
var locObj=Object.assign({},editor.currentFloorData);
Object.keys(editor_file.comment.floors.floor).forEach(function(v){
if (!isset(editor.currentFloorData[v]))
/* locObj[v]=editor.currentFloorData[v];
else */
locObj[v]=null;
});
Object.keys(editor_file.comment.floors.loc).forEach(function(v){
delete(locObj[v]);
});
delete(locObj.map);
return locObj;
})(),
editor_file.comment.floors.floor,
null]);
}
}
//callback([obj,commentObj,err:String])
////////////////////////////////////////////////////////////////////
editor_file.editTower = function(actionList,callback){
/*actionList:[
["change","['firstData']['version']",'Ver 1.0.1 (Beta)'],
["change","['values']['lavaDamage']",200],
]
[]时只查询不修改
*/
if (!isset(callback)) {printe('未设置callback');throw('未设置callback')};
if (isset(actionList) && actionList.length > 0){
saveSetting('data',actionList,function (err) {
callback([
(function(){
var locObj=Object.assign({'main':{}},editor.core.data);
Object.keys(editor_file.dataComment.main).forEach(function(v){
if (isset(editor.main[v]))
locObj.main[v]=editor.main[v];
else
locObj[v]=null;
});
return locObj;
})(),
editor_file.dataComment,
err]);
});
} else {
callback([
(function(){
var locObj=Object.assign({'main':{}},editor.core.data);
Object.keys(editor_file.dataComment.main).forEach(function(v){
if (isset(editor.main[v]))
locObj.main[v]=editor.main[v];
else
locObj[v]=null;
});
return locObj;
})(),
editor_file.dataComment,
null]);
}
}
//callback([obj,commentObj,err:String])
////////////////////////////////////////////////////////////////////
var fmap = {};
var fjson = JSON.stringify(functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a,function(k,v){if(v instanceof Function){var id_ = editor.guid();fmap[id_]=v.toString();return id_;}else return v},4);
var fobj = JSON.parse(fjson);
editor_file.functionsMap = fmap;
editor_file.functionsJSON = fjson;
var buildlocobj = function(locObj){
for(var key in locObj){
if(typeof(locObj[key])!==typeof(''))buildlocobj(locObj[key]);
else locObj[key]=fmap[locObj[key]];
}
};
editor_file.editFunctions = function(actionList,callback){
/*actionList:[
["change","['events']['afterChangeLight']","function(x,y){console.log(x,y)}"],
["change","['ui']['drawAbout']","function(){...}"],
]
[]时只查询不修改
*/
if (!isset(callback)) {printe('未设置callback');throw('未设置callback')};
if (isset(actionList) && actionList.length > 0){
saveSetting('functions',actionList,function (err) {
callback([
(function(){
var locObj=JSON.parse(fjson);
buildlocobj(locObj);
return locObj;
})(),
editor_file.functionsComment,
err]);
});
} else {
callback([
(function(){
var locObj=JSON.parse(fjson);
buildlocobj(locObj);
return locObj;
})(),
editor_file.functionsComment,
null]);
}
}
//callback([obj,commentObj,err:String])
////////////////////////////////////////////////////////////////////
var isset = function (val) {
if (val == undefined || val == null) {
return false;
}
return true
}
var formatMap = function(mapArr){
//把13*13或者1*169数组格式化
var formatArrStr = '';
var arr = JSON.stringify(mapArr).replace(/\s+/g, '').split('],[');
for(var i =0; i<13; i++){
var a = [];
formatArrStr +=' [';
if(i==0||i==12) a = arr[i].split(/\D+/).join(' ').trim().split(' ');
else a = arr[i].split(/\D+/);
for(var k=0; k<13; k++){
var num = parseInt(a[k]);
formatArrStr += Array(Math.max(4-String(num).length,0)).join(' ')+num+(k==12?'':',');
}
formatArrStr += ']'+(i==12?'':',\n');
}
return formatArrStr;
}
var encode = function (str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode(parseInt(p1, 16))
}))
}
var saveSetting = function(file,actionList,callback) {
//console.log(file);
//console.log(actionList);
actionList.forEach(function (value) {
if (value[0]!='change' && file!='icons' && file!='maps') {printe('目前只支持change');throw('目前只支持change')};
});
if (file=='icons') {
actionList.forEach(function (value) {
if (value[0]!='add')return;
eval("icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1"+value[1]+'='+JSON.stringify(value[2]));
});
var datastr='icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1 = \n';
datastr+=JSON.stringify(icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1,null,4);
fs.writeFile('project/icons.js',encode(datastr),'base64',function(err, data){
callback(err);
});
return;
}
if (file=='maps') {
actionList.forEach(function (value) {
if (value[0]!='add')return;
eval("maps_90f36752_8815_4be8_b32b_d7fad1d0542e"+value[1]+'='+JSON.stringify(value[2]));
});
var datastr='maps_90f36752_8815_4be8_b32b_d7fad1d0542e = \n';
datastr+=JSON.stringify(maps_90f36752_8815_4be8_b32b_d7fad1d0542e,null,4);
fs.writeFile('project/maps.js',encode(datastr),'base64',function(err, data){
callback(err);
});
return;
}
if (file=='items') {
actionList.forEach(function (value) {
if (value[0]!='change')return;
eval("items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a"+value[1]+'='+JSON.stringify(value[2]));
});
var datastr='items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = \n';
datastr+=JSON.stringify(items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a,null,4);
fs.writeFile('project/items.js',encode(datastr),'base64',function(err, data){
callback(err);
});
return;
}
if (file=='enemys') {
actionList.forEach(function (value) {
if (value[0]!='change')return;
eval("enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80"+value[1]+'='+JSON.stringify(value[2]));
});
var datastr='enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 = \n';
var emap={};
var estr = JSON.stringify(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80,function(k,v){if(v.hp!=null){var id_ = editor.guid();emap[id_]=JSON.stringify(v);return id_;}else return v},4);
for(var id_ in emap){
estr = estr.replace('"'+id_+'"',emap[id_])
}
datastr+=estr;
fs.writeFile('project/enemys.js',encode(datastr),'base64',function(err, data){
callback(err);
});
return;
}
if (file=='data') {
actionList.forEach(function (value) {
if (value[0]!='change')return;
eval("data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d"+value[1]+'='+JSON.stringify(value[2]));
});
var datastr='data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = \n';
datastr+=JSON.stringify(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d,null,4);
fs.writeFile('project/data.js',encode(datastr),'base64',function(err, data){
callback(err);
});
return;
}
if (file=='functions') {
actionList.forEach(function (value) {
if (value[0]!='change')return;
eval("fmap[fobj"+value[1]+']='+JSON.stringify(value[2]));
});
var fraw = fjson;
for(var id_ in fmap){
fraw = fraw.replace('"'+id_+'"',fmap[id_])
}
var datastr='functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = \n';
datastr+=fraw;
fs.writeFile('project/functions.js',encode(datastr),'base64',function(err, data){
callback(err);
});
return;
}
if (file=='floors') {
actionList.forEach(function (value) {
if (value[0]!='change')return;
eval("editor.currentFloorData"+value[1]+'='+JSON.stringify(value[2]));
});
editor_file.saveFloorFile(callback);
return;
}
callback('出错了,要设置的文件名不识别');
}
/*
$select({\"values\":[\"keys\",\"items\",\"constants\",\"tools\"]})$end
$range(thiseval==~~thiseval &&thiseval>0)$end
$leaf(true)$end
$select({\"values\":[true]})$end
$select({\"values\":[false]})$end
$select({\"values\":[true,false]})$end
*/
/*
所有注释中的特殊指令
$range(evalstr:thiseval)$end
限制取值范围,要求修改后的eval(evalstr)为true
$leaf(evalstr:thiseval)$end
强制指定为叶节点,如果eval(evalstr)为true
//以下几个中选一个 [
$select(evalstr)$end
渲染成<select>,选项为数组eval(evalstr)['values']
$input(evalstr)$end
渲染成<input>
$textarea(evalstr)$end
渲染成<textarea>
默认选项为$textarea()$end
// ]
*/
return editor_file;
}
//editor_file = editor_file(editor);

511
_server/editor_mode.js Normal file
View File

@ -0,0 +1,511 @@
editor_mode = function(editor){
var core = editor.core;
function editor_mode(){
this.ids={
'loc':'left2',
'emenyitem':'left3',
'floor':'left4',
'tower':'left5',
'functions':'left8',
'map':'left',
'appendpic':'left1',
}
this._ids={}
this.dom={}
this.actionList=[];
this.mode='';
this.info={};
this.appendPic={};
}
editor_mode.prototype.init = function(callback){
if (Boolean(callback))callback();
}
editor_mode.prototype.init_dom_ids = function(callback){
Object.keys(editor_mode.ids).forEach(function(v){
editor_mode.dom[v]=document.getElementById(editor_mode.ids[v]);
editor_mode._ids[editor_mode.ids[v]]=v;
});
if (Boolean(callback))callback();
}
/////////////////////////////////////////////////////////////////////////////
editor_mode.prototype.objToTable = function(obj,commentObj){
var outstr=["\n<tr><td>条目</td><td>注释</td><td>值</td></tr>\n"];
var guids=[];
var checkIsLeaf = function(obj,commentObj,field){
var thiseval = eval('obj'+field);
if (thiseval == null || thiseval == undefined)return true;//null,undefined
if (typeof(thiseval) == typeof(''))return true;//字符串
if (Object.keys(thiseval).length == 0)return true;//数字,true,false,空数组,空对象
try {
var comment = eval('commentObj'+field);
if( comment.indexOf('$leaf') != -1){
evalstr = comment.split('$leaf')[1].split('$end')[0];
if(eval(evalstr) === true)return true;
}
} catch (error) {}
return false;
}
//深度优先遍历
var recursionParse = function(tfield) {
for(var ii in eval("obj"+tfield)){
var field = tfield+"['"+ii+"']";
var isleaf = checkIsLeaf(obj,commentObj,field);
if (isleaf) {
var leafnode = editor_mode.objToTr(obj,commentObj,field);
outstr.push(leafnode[0]);
guids.push(leafnode[1]);
} else {
outstr.push(["<tr><td>----</td><td>----</td><td>",field,"</td></tr>\n"].join(''));
recursionParse(field);
}
}
}
recursionParse("");
var checkRange = function(comment,thiseval){
if( comment.indexOf('$range') !== -1){
var evalstr = comment.split('$range')[1].split('$end')[0];
return eval(evalstr);
}
return true;
}
var listen = function(guids) {
guids.forEach(function(guid){
// tr>td[title=field]
// >td[title=comment]
// >td>div>input[value=thsieval]
var thisTr = document.getElementById(guid);
var input = thisTr.children[2].children[0].children[0];
var field = thisTr.children[0].getAttribute('title');
var comment = thisTr.children[1].getAttribute('title');
input.onchange = function(){
var node = thisTr.parentNode;
while (!editor_mode._ids.hasOwnProperty(node.getAttribute('id'))) {
node = node.parentNode;
}
editor_mode.onmode(editor_mode._ids[node.getAttribute('id')]);
var thiseval=null;
try{
thiseval = JSON.parse(input.value);
}catch(ee){
printe(field+' : '+ee);
throw ee;
}
if(checkRange(comment,thiseval)){
editor_mode.addAction(['change',field,thiseval]);
} else {
printe(field+' : 输入的值不合要求,请鼠标放置在注释上查看说明');
}
}
input.ondblclick = function(){
if(!editor_blockly.import(guid))
if(!editor_multi.import(guid)){}
}
});
}
return {"HTML":outstr.join(''),"guids":guids,"listen":listen};
}
editor_mode.prototype.objToTr = function(obj,commentObj,field){
var guid = editor.guid();
var thiseval = eval('obj'+field);
var comment = '';
try {
comment = eval('commentObj'+field);
} catch (error) {}
if(!comment)comment='';
var charlength=10;
var shortField = field.split("']").slice(-2)[0].split("['").slice(-1)[0];
shortField = (shortField.length<charlength?shortField:shortField.slice(0,charlength)+'...');
var commentHTMLescape=comment.split('').map(function(v){return '&#'+v.charCodeAt(0)+';'}).join('');
var shortCommentHTMLescape=(comment.length<charlength?commentHTMLescape:comment.slice(0,charlength).split('').map(function(v){return '&#'+v.charCodeAt(0)+';'}).join('')+'...');
var outstr=['<tr id="',guid,'"><td title="',field,'">',shortField,'</td>',
'<td title="',commentHTMLescape,'">',shortCommentHTMLescape,'</td>',
'<td><div class="etableInputDiv">',editor_mode.objToTd(thiseval,comment,field),'</div></td></tr>\n',
];
return [outstr.join(''),guid];
}
editor_mode.prototype.objToTd = function(thiseval,comment,field){
if( comment.indexOf('$select') != -1){
var evalstr = comment.split('$select')[1].split('$end')[0];
var values = eval(evalstr)['values'];
var outstr = ['<select>\n',"<option value='",JSON.stringify(thiseval),"'>",JSON.stringify(thiseval),'</option>\n'];
values.forEach(function(v){
outstr.push(["<option value='",JSON.stringify(v),"'>",JSON.stringify(v),'</option>\n'].join(''))
});
outstr.push('</select>');
return outstr.join('');
} else if( comment.indexOf('$input') != -1){
return ["<input spellcheck='false' value='",JSON.stringify(thiseval),"'/>\n"].join('');
} else {
//rows='",rows,"'
var num = 0;//editor_mode.indent(field);
return ["<textarea spellcheck='false' >",JSON.stringify(thiseval,null,num),'</textarea>\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(["<option value='",floor,"'>",floor,'</option>\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(["<option value='",image,"'>",image,'</option>\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;ii++){
appendPicSelection.children[ii].style='left:0;top:0;height:'+(ysize-6)+'px';
selectStr+='{"x":0,"y":0},'
}
editor_mode.appendPic.selectPos = eval('['+selectStr+']');
for(var jj=num;jj<4;jj++){
appendPicSelection.children[jj].style='display:none';
}
sprite.style.width = (sprite.width = img.width)/ratio + 'px';
sprite.style.height = (sprite.height = img.height+ysize)/ratio + 'px';
sprite.getContext('2d').drawImage(img, 0, 0);
}
selectAppend.onchange();
var selectFileBtn = document.getElementById('selectFileBtn');
selectFileBtn.onclick = function(){
var loadImage = function (content, callback) {
var image = new Image();
try {
image.src = content;
if (image.complete) {
callback(image);
return;
}
image.onload = function () {
callback(image);
}
}
catch (e) {
printe(e);
}
}
core.readFile(function(content){
loadImage(content,function(image){
editor_mode.appendPic.img = image;
editor_mode.appendPic.width = image.width;
editor_mode.appendPic.height = image.height;
var ysize = selectAppend.value.indexOf('48')===-1?32:48;
for(var ii=0;ii<3;ii++){
var newsprite = appendPicCanvas.children[ii];
newsprite.style.width = (newsprite.width = Math.floor(image.width/32)*32)/ratio + 'px';
newsprite.style.height = (newsprite.height = Math.floor(image.height/ysize)*ysize)/ratio + 'px';
}
//画灰白相间的格子
var bgc = bg.getContext('2d');
var colorA = ["#f8f8f8", "#cccccc"];
var colorIndex;
var sratio=4;
for (var ii = 0; ii < image.width/32*sratio; ii++){
colorIndex = 1-ii%2;
for (var jj = 0; jj < image.height/32*sratio; jj++) {
bgc.fillStyle = colorA[colorIndex];
colorIndex = 1 - colorIndex;
bgc.fillRect(ii * 32/sratio, jj * 32/sratio, 32/sratio, 32/sratio);
}
}
//把导入的图片画出
source.getContext('2d').drawImage(image, 0, 0);
//重置临时变量
selectAppend.onchange();
});
},null,'img');
return;
}
var left1 = document.getElementById('left1');
var eToLoc = function (e) {
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
var loc = {
'x': scrollLeft+e.clientX + appendPicCanvas.scrollLeft - left1.offsetLeft-appendPicCanvas.offsetLeft,
'y': scrollTop+e.clientY + appendPicCanvas.scrollTop - left1.offsetTop-appendPicCanvas.offsetTop,
'size': 32,
'ysize': selectAppend.value.indexOf('48')===-1?32:48
};
return loc;
}//返回可用的组件内坐标
var locToPos = function (loc) {
var pos = { 'x': ~~(loc.x / loc.size), 'y': ~~(loc.y / loc.ysize) ,'ysize': loc.ysize}
return pos;
}
picClick.onclick = function(e){
var loc = eToLoc(e);
var pos = locToPos(loc);
console.log(e,loc,pos);
var num = editor_mode.appendPic.num;
var ii = editor_mode.appendPic.index;
if(ii+1>=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);

104
_server/editor_multi.js Normal file
View File

@ -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();

View File

@ -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,

89
docs/V2.0.md Normal file
View File

@ -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素材的支持在这里将不再赘述请仔细阅读前面的几个文档进行了解。

View File

@ -3,4 +3,5 @@
- [元件说明](element)
- [事件](event)
- [个性化](personalization)
- [V2.0版本介绍](V2.0)
- [附录API列表](api)

View File

@ -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]** 快捷使用炸弹/圣锤

View File

@ -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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -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色调层用来控制当前楼层的画面色调
- uiUI层用来绘制一切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为一个数组,代表当前层所有作为背景素材的图片信息。
每一项为一个三元组分别为该背景素材的xy和图片名。其中x和y分别为横纵坐标在0-12之间图片名则必须在上面的this.pngs中定义过。
每一项为一个四元组分别为该背景素材的xy图片名和是否为前景。其中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的写111-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防减伤。也可以适当进行修改。

View File

@ -1,6 +1,6 @@
# 快速上手
?> 目前版本**v1.4.1**,上次更新时间:* {docsify-updated} *
?> 目前版本**v2.0**,上次更新时间:* {docsify-updated} *
在这一节中,将详细介绍做一部塔的流程。现在,让我们来做一部单层塔!
@ -12,9 +12,18 @@
- Chrome浏览器。其他浏览器可能会导致本地服务器产生闪退等现象。
- 一个很好的文本编辑器。推荐带有高亮染色、错误提示等效果。例如WebStormVSCode或者至少也要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

View File

@ -1,698 +1 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="_server/css/editor.css" rel="stylesheet">
</head>
<body>
<div class="main">
<div id="left">
<div id="arrEditor">
<table class="col" id='arrColMark'></table>
<table class="row" id='arrRowMark'></table>
<div id="editArea" v-cloak>
<textarea cols="10" rows="10" id="pout" v-model="mapArr"></textarea>
<p class="warnText" v-if="error">{{ errors[error-1] }}</p>
</div>
<div id="editTip" v-cloak>
<input class='btn' type="button" value="复制地图" v-on:click="copyMap"/>
</div>
</div>
<div id="objDataEditor">
</div>
<div id="eventEditor">
</div>
</div>
<div id="mid">
<table class="col" id='mapColMark'></table>
<table class="row" id='mapRowMark'></table>
<div class="map" id="mapEdit">
<canvas class='gameCanvas' id='bg' width='416' height='416' style='z-index:1'></canvas>
<canvas class='gameCanvas' id='eventLayer' width='416' height='416' style='z-index:2'></canvas>
<canvas class='gameCanvas' id='ui' width='416' height='416' style='z-index:100'></canvas>
</div>
<div class="tools">
<div id="tip" v-cloak >
<div v-if="isSelectedBlock" >
<p v-if="isClearBlock" class="infoText">当前选择为清除块,可擦除地图上块</p>
<div v-else>
<p v-if="hasId">图块编号:<span class="infoText">{{ infos['idnum'] }}</span></p>
<p v-if="hasId">图块ID<span class="infoText">{{ infos['id'] }}</span></p>
<p v-else class="warnText">该图块无对应的数字或ID存在请先前往icons.js和maps.js中进行定义</p>
<p>图块所在素材:<span class="infoText">{{ infos['images'] + (isAutotile ? '( '+infos['id']+' )' : '') }}</span></p>
<p>图块索引:<span class="infoText">{{ infos['y'] }}</span></p>
</div>
</div>
<div v-else>
<p v-if="whichShow" v-bind:class="[ (whichShow%2) ? 'warnText' : 'successText']">{{ mapMsg }}</p>
</div>
</div>
<input class='btn' id='clear' type="button" value="清除地图" v-on:click="clearMap"/>
<input class='btn' type="button" value="导出地图" id="exportM" v-on:click="exportMap"/>
<div id="bgSelect" v-cloak>
<span>当前地板: </span>
<select v-model="selectedBg">
<option disabled value="">请选择地板</option>
<option v-for="bg in bgs" v-bind:value="bg">
{{ bg }}
</option>
</select>
<div class="selectpng">
<input class='input' id='pin' v-model="imgname" placeholder="请输入自定义背景文件名"/>
<input class='btn' type="button" value="确定" v-on:click="updatebg"/>
</div>
</div>
</div>
</div>
<div id="right">
<div id="iconLib">
<canvas class='gameCanvas' id='data' width='416' height='416' style='z-index:0'></canvas>
<div id="selectBox">
<div id='dataSelection' v-show="isSelected" v-cloak></div>
</div>
</div>
</div>
</div>
<script>
// 生成定位编号
(function(){
var colNum = ' ';
for(var i=0; i<13; i++){
var tpl = '<td>'+i+'<div class="colBlock" style="left:'+(i*32+1)+'px;"></div></td>';
colNum += tpl;
}
arrColMark.innerHTML = '<tr>'+colNum+'</tr>';
mapColMark.innerHTML = '<tr>'+colNum+'</tr>';
var rowNum = ' ';
for(var i=0; i<13; i++){
var tpl = '<tr><td>'+i+'<div class="rowBlock" style="top:'+(i*32+1)+'px;"></div></td></tr>';
rowNum += tpl;
}
arrRowMark.innerHTML = rowNum;
mapRowMark.innerHTML = rowNum;
})();
</script>
<!-- =========================================================== -->
<script src='_server/vendor/vue.min.js'></script>
<script src='_server/vendor/polyfill.min.js'></script>
<!-- <script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script> -->
<script src='_server/fs.js'></script>
<!-- <script src='_server/editor_file.js'></script> -->
<script src='_server/vm.js'></script>
<script>
//所有全局量
__all__=['Vue','fs','printf','editor','main','core'];
__id__=['printOut','arrRowMark','mapRowMark','data','bg','dataSelection'];
__Vue__=['exportM','editArea','editTip','clear','tip','selectBox'];
var hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwnProp (obj, key) {
return hasOwnProperty.call(obj, key)
}
var main={'instance':{}};
var core={};
function editor() {
this.version = "1.3.2";
this.material = {};
}
// 重构这一堆回调
editor.prototype.init = function(){
var mapsjsUrl = 'libs/maps.js';
var iconsjsUrl = 'libs/icons.js';
var p1 = editor.loadjs(mapsjsUrl).then(function(){ // 加载maps.js
return new maps(); //实例化maps
});
var p2 = editor.loadjs(iconsjsUrl) // 加载icons.js
.then(function(){ // 实例化并获取icons
var ic = new icons();
ic.init();
return ic.getIcons();
});
var p3 = p2.then(function(icons){ // 加载所有图片
return editor.loadAllImgs(icons);
})
.catch(function(err){
console.log('发生错误!', err);
});
Promise.all([p1, p2, p3])
.then(function(results){
var maps = results[0], icons = results[1];
editor.idsInit(maps, icons); // 初始化图片素材信息
editor.drawInitData(icons); // 初始化绘图
editor.listen(); // 开始监听事件
})
}
editor.prototype.loadjs = function(url){
return new Promise(function(resolve, reject){
var script = document.createElement('script');
script.src = url + '?' + editor.version;
document.body.appendChild(script);
script.onload = function () {
resolve( console.log(url+"加载完成"));
}
script.onerror = function(){
reject(new Error('Load js error at '+url))
}
});
}
editor.prototype.loadImg = function(url){
return new Promise(function(resolve, reject){
var img = new Image();
img.src = url;
img.onload = function(){
resolve(img);
}
img.onerror = function(){
reject(new Error('Load image error at '+url));
}
})
}
editor.prototype.loadAllImgs = function(icons){
editor.material.images = {};
var imgs = Object.keys(icons);
var autotiles = null;
if(hasOwnProp(icons, 'hero')){ // hero 图片不加载
var index = imgs.indexOf('hero');
imgs.splice(index, 1);
}
if(hasOwnProp(icons, 'autotile')){
editor.material.images['autotile'] = {};
var index = imgs.indexOf('autotile');
imgs.splice(index, 1);
autotiles = Object.keys(icons.autotile);
imgs = imgs.concat(autotiles);
}
var p = imgs.map(function(im){
var url = 'images/'+im+'.png'
return editor.loadImg(url).then(function(image){
if(autotiles.indexOf(im) >= 0){
editor.material.images['autotile'][im] = image;
}else editor.material.images[im] = image;
}).catch(function(err){
console.log('发生错误!', err);
});
});
return Promise.all(p);
}
editor.prototype.idsInit = function(maps, icons){
editor.ids = [0];
editor.indexs = [];
var MAX_NUM = 400;
var getInfoById = function(id){
var block = maps.getBlock(0, 0, id);
if(hasOwnProp(block, 'event')){
return block;
}
}
var point = 0;
for(var i=0; i<MAX_NUM; i++){
var indexBlock = getInfoById(i);
editor.indexs[i] = [];
if(indexBlock){
var id = indexBlock.event.id;
var indexId = indexBlock.id;
var allCls = Object.keys(icons);
for(var j=0; j<allCls.length; j++){
if(id in icons[allCls[j]] ){
editor.ids.push({'idnum':indexId,'id':id,'images':allCls[j],'y':icons[allCls[j]][id]});
point++;
editor.indexs[i].push(point);
}
}
}
}
}
editor.prototype.drawInitData = function (icons) {
var ratio=1;
var images=editor.material.images;
var maxHeight=700;
var sumWidth=0;
editor.widthsX={};
// var imgNames = Object.keys(images); //还是固定顺序吧;
var imgNames = ["terrains", "animates", "enemys", "items", "npcs", "autotile"];
for(var ii=0; ii<imgNames.length; ii++){
var img=imgNames[ii], tempy = 0;
if(img == 'autotile'){
var autotiles = images[img];
for(var im in autotiles){
tempy += autotiles[im].height;
}
editor.widthsX[img]=[img, sumWidth/32, (sumWidth+3*32)/32, tempy];
sumWidth += 3*32;
maxHeight = Math.max(maxHeight, tempy);
continue;
}
if(img == 'terrains'){
editor.widthsX[img]=[img, sumWidth/32, (sumWidth+images[img].width)/32, images[img].height+32]
sumWidth += images[img].width;
maxHeight = Math.max(maxHeight, images[img].height+32);
continue;
}
editor.widthsX[img]=[img, sumWidth/32, (sumWidth+images[img].width)/32, images[img].height];
sumWidth += images[img].width;
maxHeight = Math.max(maxHeight, images[img].height);
}
var fullWidth=~~(sumWidth*ratio);
var fullHeight=~~(maxHeight*ratio);
if (fullWidth > data.width) data.style.width = (data.width = fullWidth)/ratio + 'px';
data.style.height = (data.height = fullHeight)/ratio + 'px';
var dc = data.getContext('2d');
var nowx = 0;
var nowy = 0;
for(var ii=0; ii<imgNames.length; ii++){
var img=imgNames[ii];
if(img == 'terrains'){
dc.drawImage(images[img], nowx, 32);
nowx += images[img].width;
continue;
}
if(img == 'autotile'){
var autotiles = images[img];
for(var im in autotiles){
dc.drawImage(autotiles[im], nowx, nowy);
nowy += autotiles[im].height;
}
continue;
}
dc.drawImage(images[img], nowx, 0)
nowx += images[img].width;
}
bgSelect.bgs = Object.keys(icons.terrains);
editor.drawMapBg();
editor.mapInit();
}
editor.prototype.mapInit = function(){
var ec = eventLayer.getContext('2d');
ec.clearRect(0, 0, 416, 416);
editor.map = [];
for(var y=0; y<13; y++){
editor.map[y] = [];
for(var x = 0; x<13; x++){
editor.map[y][x] = 0;
}
}
}
editor.prototype.drawMapBg = function(img){
var bgc = bg.getContext('2d');
for (var ii = 0; ii < 13; ii++)
for (var jj = 0; jj < 13; jj++) {
bgc.clearRect(ii*32, jj*32, 32, 32);
bgc.drawImage(editor.material.images['terrains'], 0, 32*(editor.bgY||0), 32, 32, ii*32, jj*32, 32, 32);
}
if(img){
bgc.drawImage(img, 0, 0, 416, 416);
}
}
editor.prototype.updateMap = function(){
var drawTile = function(ctx, x, y, tileInfo){ // 绘制一个普通块
ctx.clearRect(x*32, y*32, 32, 32);
if(tileInfo == 0) return;
if(typeof(tileInfo) == typeof([][0]) || !hasOwnProp(tileInfo, 'idnum')) {//未定义块画红块
if(typeof(tileInfo) != typeof([][0]) && hasOwnProp(tileInfo, 'images')){
ctx.drawImage(editor.material.images[tileInfo.images], 0, tileInfo.y*32, 32, 32, x*32, y*32, 32, 32);
}
ctx.strokeStyle = 'red';
var OFFSET = 2;
ctx.lineWidth = OFFSET;
ctx.strokeRect(x*32+OFFSET, y*32+OFFSET, 32-OFFSET*2, 32-OFFSET*2);
ctx.font = "30px Verdana";
ctx.textAlign = 'center'
ctx.fillStyle = 'red';
ctx.fillText("?", x*32+16, y*32+27);
return;
}
ctx.drawImage(editor.material.images[tileInfo.images], 0, tileInfo.y*32, 32, 32, x*32, y*32, 32, 32);
}
// autotile的相关处理
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){ //index为autotile的图块索引1-48
var sx = 16*((index-1)%6), sy = 16*(~~((index-1)/6));
ctx.drawImage(autotileImg, sx, sy, 16, 16, dx, dy, 16, 16);
}
var isAutotile = function(info){
if(typeof(info)=='object' && hasOwnProp(info, 'images') && info.images=='autotile') return true;
return false;
}
var getAutotileAroundId = function(currId, x, y){ //与autotile当前idnum一致返回1否则返回0
if(x>=0 && y >=0 && x<13 && y<13 && isAutotile(editor.map[y][x]) && editor.map[y][x].idnum == currId)
return 1;
else if(x<0 || y<0 || x>12 || y>12) return 1; //边界外视为通用autotile这样好看些
else
return 0;
}
var checkAround = function(x, y){ // 得到周围四个32*32块周围每块都包含当前块的1/4不清楚的话画下图你就明白的数组索引
var currId = editor.map[y][x].idnum;
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 addIndexToAutotileInfo = 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]);
}
editor.map[y][x].blockIndex = indexArr;
}
var drawAutotile = function(ctx, x, y, info){ // 绘制一个autotile
ctx.clearRect(x*32, y*32, 32, 32);
//修正四个边角的固定搭配
if(info.blockIndex[0] == 13){
if(info.blockIndex[1] == 16) info.blockIndex[1] = 14;
if(info.blockIndex[2] == 31) info.blockIndex[2] = 19;
}
if(info.blockIndex[1] == 18){
if(info.blockIndex[0] == 15) info.blockIndex[0] = 17;
if(info.blockIndex[3] == 36) info.blockIndex[3] = 24;
}
if(info.blockIndex[2] == 43){
if(info.blockIndex[0] == 25) info.blockIndex[0] = 37;
if(info.blockIndex[3] == 46) info.blockIndex[3] = 44;
}
if(info.blockIndex[3] == 48){
if(info.blockIndex[1] == 30) info.blockIndex[1] = 42;
if(info.blockIndex[2] == 45) info.blockIndex[2] = 47;
}
for(var i=0; i<4; i++){
var index = info.blockIndex[i];
var dx = x*32 + 16*(i%2), dy = y*32 + 16*(~~(i/2));
drawBlockByIndex(ctx, dx, dy, editor.material.images[info.images][info.id], index);
}
}
// 绘制地图 start
var eventCtx = eventLayer.getContext("2d");
for(var y=0; y<13; y++)
for(var x=0; x<13; x++){
var tileInfo = editor.map[y][x];
if(isAutotile(tileInfo)){
addIndexToAutotileInfo(x, y);
drawAutotile(eventCtx, x, y, tileInfo);
}else drawTile(eventCtx, x, y, tileInfo);
}
// 绘制地图 end
}
editor.prototype.listen = function() {
var uc = ui.getContext('2d');
function fillPos(pos) {
uc.fillStyle = '#' + ~~(Math.random() * 8) + ~~(Math.random() * 8) + ~~(Math.random() * 8);
uc.fillRect(pos.x * 32 + 12, pos.y * 32 + 12, 8, 8);
}//在格子内画一个随机色块
function eToLoc(e) {
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
editor.loc = {
'x': scrollLeft+e.clientX - mid.offsetLeft-mapEdit.offsetLeft,
'y': scrollTop+e.clientY - mid.offsetTop-mapEdit.offsetTop,
'size': 32
};
return editor.loc; }//返回可用的组件内坐标
function locToPos(loc) {
editor.pos = { 'x': ~~(loc.x / loc.size), 'y': ~~(loc.y / loc.size) }
return editor.pos;
}
var holdingPath = 0;
var stepPostfix = null;//用于存放寻路检测的第一个点之后的后续移动
var mouseOutCheck = 2;
function clear1() {
if (mouseOutCheck > 1) {
mouseOutCheck--;
setTimeout(clear1, 1000);
return;
}
holdingPath = 0;
stepPostfix = [];
uc.clearRect(0, 0, 416, 416);
}//用于鼠标移出canvas时的自动清除状态
ui.onmousedown = function (e) {
if(!selectBox.isSelected) {
tip.whichShow = 1;
return;
}
holdingPath = 1;
mouseOutCheck = 2;
setTimeout(clear1);
e.stopPropagation();
uc.clearRect(0, 0, 416, 416);
var loc = eToLoc(e);
var pos = locToPos(loc)
stepPostfix = [];
stepPostfix.push(pos);
fillPos(pos);
}
ui.onmousemove = function (e) {
if(!selectBox.isSelected) {
// tip.whichShow = 1;
return;
}
if (holdingPath == 0) { return; }
mouseOutCheck = 2;
e.stopPropagation();
var loc = eToLoc(e);
var pos = locToPos(loc);
var pos0 = stepPostfix[stepPostfix.length - 1]
var directionDistance = [pos.y - pos0.y, pos0.x - pos.x, pos0.y - pos.y, pos.x - pos0.x]
var max = 0, index = 4;
for (var i = 0; i < 4; i++) {
if (directionDistance[i] > max) {
index = i;
max = directionDistance[i];
}
}
var 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;
stepPostfix.push(pos);
fillPos(pos);
}
}
ui.onmouseup = function (e) {
if(!selectBox.isSelected) {
tip.whichShow = 1;
return;
}
holdingPath = 0;
e.stopPropagation();
var loc = eToLoc(e);
if (stepPostfix.length) {
preMapData = JSON.parse(JSON.stringify(editor.map));
currDrawData.pos = JSON.parse(JSON.stringify(stepPostfix));
currDrawData.info = JSON.parse(JSON.stringify(editor.info));
reDo = null;
// console.log(stepPostfix);
for (var ii = 0; ii < stepPostfix.length; ii++)
editor.map[stepPostfix[ii].y][stepPostfix[ii].x] = editor.info;
// console.log(editor.map);
editor.updateMap();
holdingPath = 0;
stepPostfix = [];
uc.clearRect(0, 0, 416, 416);
}
}
var preMapData = {};
var currDrawData = {
pos: [],
info: {}
};
var reDo = null;
document.body.onkeydown = function(e) {
// 禁止快捷键的默认行为
if( e.ctrlKey && ( e.keyCode == 90 || e.keyCode == 89 ) )
e.preventDefault();
//Ctrl+z 撤销上一步undo
if(e.keyCode == 90 && e.ctrlKey && preMapData && currDrawData.pos.length){
editor.map = JSON.parse(JSON.stringify(preMapData));
editor.updateMap();
reDo = JSON.parse(JSON.stringify(currDrawData));
currDrawData = {pos: [],info: {}};
preMapData = null;
}
//Ctrl+y 重做一步redo
if(e.keyCode == 89 && e.ctrlKey && reDo && reDo.pos.length){
preMapData = JSON.parse(JSON.stringify(editor.map));
for(var j=0; j<reDo.pos.length;j++)
editor.map[reDo.pos[j].y][reDo.pos[j].x] = JSON.parse(JSON.stringify(reDo.info));
editor.updateMap();
currDrawData = JSON.parse(JSON.stringify(reDo));
reDo = null;
}
}
data.onmousedown = function (e) {
e.stopPropagation();
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
var loc = {
'x': scrollLeft + e.clientX + iconLib.scrollLeft - right.offsetLeft-iconLib.offsetLeft,
'y': scrollTop + e.clientY + iconLib.scrollTop - right.offsetTop-iconLib.offsetTop,
'size': 32
};
editor.loc = loc;
var pos = locToPos(loc);
for (var spriter in editor.widthsX){
if(pos.x>=editor.widthsX[spriter][1] && pos.x<editor.widthsX[spriter][2]){
pos.x=editor.widthsX[spriter][1];
pos.images = editor.widthsX[spriter][0];
var autotiles = editor.material.images['autotile'];
if(pos.images=='autotile'){
var imNames = Object.keys(autotiles);
if((pos.y+1)*32 > editor.widthsX[spriter][3])
pos.y = ~~(editor.widthsX[spriter][3]/32)-4;
else{
for(var i=0; i<imNames.length; i++){
if(pos.y >= 4*i && pos.y < 4*(i+1)){
pos.images = imNames[i];
pos.y = 4*i;
}
}
}
}else if((pos.y+1)*32 > editor.widthsX[spriter][3])
pos.y = ~~(editor.widthsX[spriter][3]/32)-1;
selectBox.isSelected = true;
// console.log(pos,editor.material.images[pos.images].height)
dataSelection.style.left = pos.x*32 +'px';
dataSelection.style.top = pos.y*32 +'px';
if(pos.x==0&&pos.y==0){
// editor.info={idnum:0, id:'empty','images':'清除块', 'y':0};
editor.info=0;
}else{
if(hasOwnProp(autotiles, pos.images)) editor.info={'images':pos.images, 'y':0};
else if(pos.images == 'terrains') editor.info={'images':pos.images, 'y':pos.y-1};
else editor.info={'images':pos.images, 'y':pos.y};
for (var ii=0;ii<editor.ids.length;ii++){
if( ( editor.info.images==editor.ids[ii].images
&& editor.info.y==editor.ids[ii].y )
|| (hasOwnProp(autotiles, pos.images) && editor.info.images==editor.ids[ii].id
&& editor.info.y==editor.ids[ii].y)){
editor.info = editor.ids[ii];
break;
}
}
}
tip.infos = JSON.parse(JSON.stringify(editor.info));
}
}
}
document.body.onmousedown = function(e){
selectBox.isSelected = false;
editor.info = {};
}
iconLib.onmousedown = function(e){
e.stopPropagation();
}
}//绑定事件
editor.prototype.locInfo = function(){
}
/*
editor.updateMap
editor.loc
editor.pos
editor.info
始终是最后一次点击的结果
注意editor.info可能因为点击其他地方而被清空
*/
var editor = new editor();
editor.init();
editor.fs=fs;
// editor.file=editor_file;
</script>
<script>
// 文件相关操作
// var promisify = function (fn, receiver) {
// return function () {
// for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
// args[_key] = arguments[_key];
// }
// return new Promise(function (resolve, reject) {
// fn.apply(receiver, [].concat(args, [function (res, err) {
// return err ? reject(err) : resolve(res);
// }]));
// });
// };
// };
// var fns = Object.keys(editor.file);
// var promiseFns = {};
// fns.forEach(function(fn){
// promiseFns[fn] = promisify(editor.file[fn], editor.file)
// });
// editor.promiseFiles = Object.assign(promiseFns);
// editor.promiseFiles.getFloorFileList(editor)
// .then(function(filelist){
// editFile4map.filelist = filelist;
// })
// .catch(function(err){
// console.log(err);
// })
</script>
</body>
</html>
<html><body><script>window.location='editor.html'</script></body></html>

392
editor.html Normal file
View File

@ -0,0 +1,392 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href="_server/css/editor.css" rel="stylesheet">
<link href="_server/CodeMirror/codemirror.css" rel="stylesheet">
<link href="_server/css/editor_mode.css" rel="stylesheet">
</head>
<body>
<div class="main">
<div id="left" style="z-index:-1;opacity: 0;"><!-- map -->
<div id="arrEditor">
<table class="col" id='arrColMark'></table>
<table class="row" id='arrRowMark'></table>
<div id="editArea" v-cloak>
<textarea cols="10" rows="10" id="pout" v-model="mapArr"></textarea>
<p class="warnText" v-if="error">{{ errors[error-1] }}</p>
</div>
<div id="editTip" v-cloak>
<br>
<input type="button" value="当前地图另存为" id='saveFloorAs'/>
<input id='saveAsName' placeholder="输入新楼层id"/>
<input class='btn' type="button" value="复制地图" v-on:click="copyMap"/>
</div>
<div style="position: absolute;right: 10px;bottom:70px;">
<input class='btn' id='clear' type="button" value="清除地图" v-on:click="clearMap"/>
<input class='btn' type="button" value="导出地图" id="exportM" v-on:click="exportMap"/>
</div>
</div>
<div id="objDataEditor">
</div>
<div id="eventEditor">
</div>
</div>
<div id="left1" class='leftTab' style="z-index:-1;opacity: 0;"><div ><!-- appendpic -->
<h3>追加素材</h3>
<p>
<input id="selectFileBtn" type="button" value="导入文件到画板"/>
<select id="selectAppend"></select><!-- ["terrains", "animates", "enemys", "enemy48", "items", "npcs", "npc48"] -->
<input id="appendConfirm" type="button" value="追加"/>
</p>
<div id="appendPicCanvas" style="position:relative;overflow: auto;height:470px;">
<canvas style="position:absolute"></canvas><!-- 用于画出灰白相间背景 -->
<canvas style="position:absolute"></canvas><!-- 用于画出选中文件 -->
<canvas style="position:absolute;z-index:100"></canvas><!-- 用于响应鼠标点击 -->
<canvas style="position:absolute;display:none;"></canvas><!-- 画出追加后的sprite用于储存 -->
<div id="appendPicSelection">
<div class="appendSelection"><span style="top: 0; left: 2px;">1</span></div>
<div class="appendSelection"><span style="top: 0; left: 14px;">2</span></div>
<div class="appendSelection"><span style="top: 12px; left: 2px;">3</span></div>
<div class="appendSelection"><span style="top: 12px; left: 14px;">4</span></div>
</div>
</div>
</div></div>
<div id="left2" class='leftTab' style="z-index:-1;opacity: 0;"><div><!-- loc -->
<h3>地图选点&nbsp;&nbsp;<button onclick="editor.mode.onmode('save')">save</button></h3>
<p id='pos_a6771a78_a099_417c_828f_0a24851ebfce'>0,0</p>
<div class='etable'>
<table>
<tbody id='table_3d846fc4_7644_44d1_aa04_433d266a73df'>
<tr><td>条目</td><td>注释</td><td></td></tr>
</tbody>
</table>
</div>
</div></div>
<div id="left3" class='leftTab' style="z-index:-1;opacity: 0;"><div><!-- emenyitem -->
<h3>图块属性&nbsp;&nbsp;<button onclick="editor.mode.onmode('save')">save</button></h3>
<div id='newIdIdnum'><!-- id and idnum -->
<input placeholder="输入新id"/>
<input placeholder="输入新idnum"/>
<button>save</button>
</div>
<div><!-- enemy and item -->
<div class='etable'>
<table>
<tbody id='table_a3f03d4c_55b8_4ef6_b362_b345783acd72'>
<tr><td>条目</td><td>注释</td><td></td></tr>
</tbody>
</table>
</div>
</div>
</div></div>
<div id="left4" class='leftTab' style="z-index:-1;opacity: 0;"><div><!-- floor -->
<h3>楼层属性&nbsp;&nbsp;<button onclick="editor.mode.onmode('save')">save</button></h3>
<div class='etable'>
<table>
<tbody id='table_4a3b1b09_b2fb_4bdf_b9ab_9f4cdac14c74'>
<tr><td>条目</td><td>注释</td><td></td></tr>
</tbody>
</table>
</div>
</div></div>
<div id="left5" class='leftTab' style="z-index:-1;opacity: 0;"><div><!-- tower -->
<h3>全塔属性&nbsp;&nbsp;<button onclick="editor.mode.onmode('save')">save</button></h3>
<div class='etable'>
<table>
<tbody id='table_b6a03e4c_5968_4633_ac40_0dfdd2c9cde5'>
<tr><td>条目</td><td>注释</td><td></td></tr>
</tbody>
</table>
</div>
</div></div>
<div id="left6" class='leftTab' style="z-index:-1;opacity: 0;"><div><!-- eventsEditor -->
<h3>事件编辑器 &nbsp;&nbsp;
<button onclick="editor_blockly.showXML()">Show XML</button>
<button onclick="editor_blockly.runCode()">console.log(obj=code)</button>
<select id="entryType" disabled="disabled">
<option value="event">event</option>
<option value="changeFloor">changeFloor</option>
<option value="point">point</option>
<option value="shop">shop</option>
<option value="afterBattle">afterBattle</option>
<option value="afterGetItem">afterGetItem</option>
<option value="afterOpenDoor">afterOpenDoor</option>
<option value="firstArrive">firstArrive</option>
</select>
<button onclick="editor_blockly.parse()">parse</button>
<button onclick="editor_blockly.confirm()">confirm</button>
<button onclick="editor_blockly.cancel()">cancel</button>
<xml id="toolbox" style="display:none">
<category name="entry"></category>
<category name="statement"></category>
<category name="value"></category>
<category name="template"></category>
</xml>
</h3>
<div style="position: relative;">
<div id="blocklyDiv"></div>
<textarea id="codeArea" spellcheck="false"></textarea>
</div>
</div></div>
<div id="left7" style="z-index:-1;opacity: 0;"><div><!-- 多行文本编辑器 -->
<button onclick="editor_multi.confirm()">confirm</button>
<button onclick="editor_multi.cancel()">cancel</button>
<textarea id="multiLineCode" name="multiLineCode"></textarea>
</div></div>
<div id="left8" class='leftTab' style="z-index:-1;opacity: 0;"><div><!-- functions -->
<h3>脚本编辑&nbsp;&nbsp;<button onclick="editor.mode.onmode('save')">save</button></h3>
<div class='etable'>
<table>
<tbody id='table_e260a2be_5690_476a_b04e_dacddede78b3'>
<tr><td>条目</td><td>注释</td><td></td></tr>
</tbody>
</table>
</div>
</div></div>
<div id="mid">
<table class="col" id='mapColMark'></table>
<table class="row" id='mapRowMark'></table>
<div class="map" id="mapEdit">
<canvas class='gameCanvas' id='bg' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='event' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='event2' width='416' height='416'></canvas>
<canvas class='egameCanvas' id='eui' width='416' height='416' style='z-index:100'></canvas>
</div>
<div class="tools">
<div id="tip" v-cloak >
<div v-if="isSelectedBlock" >
<p v-if="isClearBlock" class="infoText">当前选择为清除块,可擦除地图上块</p>
<div v-else>
<p v-if="hasId">图块编号:<span class="infoText">{{ infos['idnum'] }}</span></p>
<p v-if="hasId">图块ID<span class="infoText">{{ infos['id'] }}</span></p>
<p v-else class="warnText">该图块无对应的数字或ID存在请先前往icons.js和maps.js中进行定义</p>
<p>图块所在素材:<span class="infoText">{{ infos['images'] + (isAutotile ? '( '+infos['id']+' )' : '') }}</span></p>
<p>图块索引:<span class="infoText">{{ infos['y'] }}</span></p>
</div>
</div>
<div v-else>
<p v-if="whichShow" v-bind:class="[ (whichShow%2) ? 'warnText' : 'successText']">{{ mapMsg }}</p>
</div>
</div>
<select id="editModeSelect">
<option value="map">地图编辑</option>
<option value="loc">地图选点</option>
<option value="emenyitem">图块属性</option>
<option value="floor">楼层属性</option>
<option value="tower">全塔属性</option>
<option value="functions">脚本编辑</option>
<option value="appendpic">追加素材</option>
</select>
<br><br><br><br>
<select id="selectFloor"></select>
<input type="button" value="保存地图" id='saveFloor'/>
<!-- -->
<div id="bgSelect" v-cloak style="display:none">
<span>当前地板: </span>
<select v-model="selectedBg">
<option disabled value="">请选择地板</option>
<option v-for="bg in bgs" v-bind:value="bg">
{{ bg }}
</option>
</select>
<div class="selectpng">
<input class='input' id='pin' v-model="imgname" placeholder="请输入自定义背景文件名"/>
<input class='btn' type="button" value="确定" v-on:click="updatebg"/>
</div>
</div>
<!-- -->
</div>
</div>
<div id="right">
<div id="iconLib">
<canvas class='egameCanvas' id='edata' width='416' height='416' style='z-index:0'></canvas>
<div id="selectBox">
<div id='dataSelection' v-show="isSelected" v-cloak></div>
</div>
</div>
</div>
</div>
<!-- <script>/* -->
<div id='gameGroup' style='display:none'>
<p id='mainTips'>请稍后...</p>
<div id='startPanel'>
<div id='startTop'>
<div id='startTopProgressBar'>
<div id='startTopProgress'></div>
</div>
<p id='startTopLoadTips'>资源即将开始加载</p>
</div>
<img id='startBackground'>
<p id='startLogo'></p>
<div id='startButtonGroup'>
<div id='startButtons'>
<span class='startButton' id='playGame'>开始游戏</span>
<span class='startButton' id='loadGame'>载入游戏</span>
<span class='startButton' id='replayGame'>录像回放</span>
</div>
<div id='levelChooseButtons'></div>
</div>
</div>
<div id='floorMsgGroup'>
<p id='logoLabel'></p>
<p id='versionLabel'></p>
<p id='floorNameLabel'></p>
</div>
<div id='statusBar' class="clearfix">
<div class="status" id="floorCol">
<img src='project/images/floor.png' id="img-floor">
<p class='statusLabel' id='floor'></p>
</div>
<div class="status" id="lvCol">
<img src='project/images/lv.png' id="img-lv">
<p class='statusLabel' id='lv'></p>
</div>
<div class="status" id='hpmaxCol'>
<img src='project/images/hpmax.png' id="img-hpmax">
<p class='statusLabel' id='hpmax'></p>
</div>
<div class="status">
<img src='project/images/hp.png' id="img-hp">
<p class='statusLabel' id='hp'></p>
</div>
<div class="status">
<img src='project/images/atk.png' id="img-atk">
<p class='statusLabel' id='atk'></p>
</div>
<div class="status">
<img src='project/images/def.png' id="img-def">
<p class='statusLabel' id='def'></p>
</div>
<div class="status" id="mdefCol">
<img src='project/images/mdef.png' id="img-mdef">
<p class='statusLabel' id='mdef'></p>
</div>
<div class="status" id="moneyCol">
<img src='project/images/money.png' id="img-money">
<p class='statusLabel' id='money'></p>
</div>
<div class="status" id="expCol">
<img src='project/images/experience.png' id="img-experience">
<p class='statusLabel' id='experience'></p>
</div>
<div class="status" id="upCol">
<img src='project/images/up.png' id="img-up">
<p class='statusLabel' id='up'></p>
</div>
<div class="status">
<span class='statusLabel' id='yellowKey' style="color:#FFCCAA"></span>
<span class='statusLabel' id='blueKey' style="color:#AAAADD"></span>
<span class='statusLabel' id='redKey' style="color:#FF8888"></span>
</div>
<div class="status" id="debuffCol">
<span class='statusLabel' id='poison' style="color: #AFFCA8;"></span>
<span class='statusLabel' id='weak' style="color: #FECCD0;"></span>
<span class='statusLabel' id='curse' style="color: #C2F4E7;"></span>
</div>
</div>
<div id="toolBar" class="clearfix">
<img src="project/images/book.png" class="tools" id='img-book'>
<img src="project/images/fly.png" class="tools" id='img-fly'>
<img src="project/images/toolbox.png" class="tools" id='img-toolbox'>
<img src="project/images/shop.png" class="tools" id='img-shop'>
<img src="project/images/save.png" class="tools" id='img-save'>
<img src="project/images/load.png" class="tools" id='img-load'>
<img src="project/images/settings.png" class="tools" id='img-settings'>
<p class="statusLabel tools" id="hard"></p>
</div>
<div id="curtain"></div>
<!-- <canvas class='gameCanvas' id='bg' width='416' height='416'></canvas> -->
<!-- <canvas class='gameCanvas' id='event' width='416' height='416'></canvas> -->
<canvas class='gameCanvas' id='hero' width='416' height='416'></canvas>
<!-- <canvas class='gameCanvas' id='event2' width='416' height='416'></canvas> -->
<canvas class='gameCanvas' id='fg' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='animate' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='weather' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='ui' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='data' width='416' height='416'>此浏览器不支持HTML5</canvas>
</div>
<!-- */</script> -->
<script>
// 生成定位编号
(function(){
var colNum = ' ';
for(var i=0; i<13; i++){
var tpl = '<td>'+i+'<div class="colBlock" style="left:'+(i*32+1)+'px;"></div></td>';
colNum += tpl;
}
arrColMark.innerHTML = '<tr>'+colNum+'</tr>';
mapColMark.innerHTML = '<tr>'+colNum+'</tr>';
var rowNum = ' ';
for(var i=0; i<13; i++){
var tpl = '<tr><td>'+i+'<div class="rowBlock" style="top:'+(i*32+1)+'px;"></div></td></tr>';
rowNum += tpl;
}
arrRowMark.innerHTML = rowNum;
mapRowMark.innerHTML = rowNum;
})();
</script>
<!-- =========================================================== -->
<script src='_server/vendor/vue.min.js'></script>
<!-- <script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script> -->
<script src='_server/vendor/polyfill.min.js'></script>
<script src='_server/fs.js'></script>
<script src='_server/editor_file.js'></script>
<script src='_server/editor_mode.js'></script>
<script src='_server/vm.js'></script>
<script id='mainScript' src='main.js'></script>
<script>
//所有全局量
__all__=['Vue','fs','editor_file','editor_mode','main','core','hasOwnProp','printf','printe','editor','converter','ActionParser','MotaActionFunctions','MotaActionBlocks'];
__id__=['editArea','arrRowMark','mapRowMark','data','bg','dataSelection','blocklyDiv','codeAreaHL','entryType'];
__Vue__=['exportM','editArea','editTip','clear','tip','selectBox'];
//var event = document.getElementById('event');
var hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwnProp (obj, key) {
return hasOwnProperty.call(obj, key)
}
</script>
<script src='_server/editor.js'></script>
<script>
main.init('editor', function() {
editor.init(function(){
editor.pos={x: 0, y: 0};
editor.mode.loc();
editor.info=editor.ids[editor.indexs[201]];
editor.mode.emenyitem();
editor.mode.floor();
editor.mode.tower();
editor.mode.functions();
editor.mode.showMode('floor');
editor.mode.listen();
editor_multi=editor_multi();
editor_blockly=editor_blockly();
});
});
//main.listen();
</script>
<!-- hightlight textarea -->
<script src='_server/editor_multi.js'></script>
<!-- blockly -->
<script src="_server/blockly/Converter.bundle.min.js"></script>
<script src="_server/blockly/blockly_compressed.js"></script>
<script src="_server/blockly/blocks_compressed.js"></script>
<script src="_server/blockly/javascript_compressed.js"></script>
<script src="_server/blockly/zh-hans.js"></script>
<script src='_server/editor_blockly.js'></script>
<script src="_server/CodeMirror/codeMirror.bundle.min.js"></script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -25,20 +25,15 @@
</div>
<p id='startTopLoadTips'>资源即将开始加载</p>
</div>
<img id='startBackground' src='images/bg.png'>
<!-- 标题界面可以改style的color使标题改变颜色 -->
<p id='startLogo' style="color: black"></p>
<img id='startBackground'>
<p id='startLogo'></p>
<div id='startButtonGroup'>
<div id='startButtons'>
<span class='startButton' id='playGame'>开始游戏</span>
<span class='startButton' id='loadGame'>载入游戏</span>
<span class='startButton' id='replayGame'>录像回放</span>
</div>
<div id='levelChooseButtons'>
<span class='startButton' id='easyLevel'>简单</span>
<span class='startButton' id='normalLevel'>普通</span>
<span class='startButton' id='hardLevel'>困难</span>
</div>
<div id='levelChooseButtons'></div>
</div>
</div>
<div id='floorMsgGroup'>
@ -48,39 +43,43 @@
</div>
<div id='statusBar' class="clearfix">
<div class="status" id="floorCol">
<img src='images/floor.png' id="img-floor">
<img src='project/images/floor.png' id="img-floor">
<p class='statusLabel' id='floor'></p>
</div>
<div class="status" id="lvCol">
<img src='images/lv.png' id="img-lv">
<img src='project/images/lv.png' id="img-lv">
<p class='statusLabel' id='lv'></p>
</div>
<div class="status" id='hpmaxCol'>
<img src='project/images/hpmax.png' id="img-hpmax">
<p class='statusLabel' id='hpmax'></p>
</div>
<div class="status">
<img src='images/hp.png' id="img-hp">
<img src='project/images/hp.png' id="img-hp">
<p class='statusLabel' id='hp'></p>
</div>
<div class="status">
<img src='images/atk.png' id="img-atk">
<img src='project/images/atk.png' id="img-atk">
<p class='statusLabel' id='atk'></p>
</div>
<div class="status">
<img src='images/def.png' id="img-def">
<img src='project/images/def.png' id="img-def">
<p class='statusLabel' id='def'></p>
</div>
<div class="status" id="mdefCol">
<img src='images/mdef.png' id="img-mdef">
<img src='project/images/mdef.png' id="img-mdef">
<p class='statusLabel' id='mdef'></p>
</div>
<div class="status" id="moneyCol">
<img src='images/money.png' id="img-money">
<img src='project/images/money.png' id="img-money">
<p class='statusLabel' id='money'></p>
</div>
<div class="status" id="expCol">
<img src='images/experience.png' id="img-experience">
<img src='project/images/experience.png' id="img-experience">
<p class='statusLabel' id='experience'></p>
</div>
<div class="status" id="upCol">
<img src='images/up.png' id="img-up">
<img src='project/images/up.png' id="img-up">
<p class='statusLabel' id='up'></p>
</div>
<div class="status">
@ -95,26 +94,28 @@
</div>
</div>
<div id="toolBar" class="clearfix">
<img src="images/book.png" class="tools" id='img-book'>
<img src="images/fly.png" class="tools" id='img-fly'>
<img src="images/toolbox.png" class="tools" id='img-toolbox'>
<img src="images/shop.png" class="tools" id='img-shop'>
<img src="images/save.png" class="tools" id='img-save'>
<img src="images/load.png" class="tools" id='img-load'>
<img src="images/settings.png" class="tools" id='img-settings'>
<img src="project/images/book.png" class="tools" id='img-book'>
<img src="project/images/fly.png" class="tools" id='img-fly'>
<img src="project/images/toolbox.png" class="tools" id='img-toolbox'>
<img src="project/images/shop.png" class="tools" id='img-shop'>
<img src="project/images/save.png" class="tools" id='img-save'>
<img src="project/images/load.png" class="tools" id='img-load'>
<img src="project/images/settings.png" class="tools" id='img-settings'>
<p class="statusLabel tools" id="hard"></p>
</div>
<div id="curtain"></div>
<canvas class='gameCanvas' id='bg' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='event' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='fg' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='hero' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='event2' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='fg' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='animate' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='weather' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='ui' width='416' height='416'></canvas>
<canvas class='gameCanvas' id='data' width='416' height='416'>此浏览器不支持HTML5</canvas>
</div>
<script id='mainScript' src='main.js'></script>
<script>main.init();main.listen();</script>
<script src='libs/thirdparty/mid.min.js'></script>
</body>
</html>

1967
libs/actions.js Normal file

File diff suppressed because it is too large Load Diff

2491
libs/control.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,186 +1,14 @@
function data() {
this.init();
}
data.prototype.init = function() {
this.firstData = {
"title": "魔塔样板", // 游戏名,将显示在标题页面以及切换楼层的界面中
"name": "template", // 游戏的唯一英文标识符。由英文、数字、下划线组成不能超过20个字符。
"version": "Ver 1.4.1", // 当前游戏版本;版本不一致的存档不能通用。
"floorId": "sample0", // 初始楼层ID
"hero": { // 勇士初始数据
"name": "阳光", // 勇士名;可以改成喜欢的
'lv': 1, // 初始等级,该项必须为正整数
"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": { // 游戏过程中的变量或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", // 商店唯一ID
"name": "贪婪之神", // 商店名称(标题)
"icon": "blueShop", // 商店图标在icons.js中的npc一项定义
"textInList": "1F金币商店", // 在快捷商店栏中显示的名称
"use": "money", // 商店所要使用的。只能是"money"或"experience"。
"need": "20+10*times*(times+1)", // 商店需要的金币/经验数值可以是一个表达式以times作为参数计算。
// 这里用到的times为该商店的已经的访问次数。首次访问该商店时times的值为0。
// 上面的例子是50层商店的计算公式。你也可以写任意其他的计算公式只要以times作为参数即可。
// 例如: "need": "25" 就是恒定需要25金币的商店 "need": "20+2*times" 就是第一次访问要20金币以后每次递增2金币的商店。
// 如果是对于每个选项有不同的计算公式,写 "need": "-1" 即可。可参见下面的经验商店。
"text": "勇敢的武士啊,给我${need}金币就可以:", // 显示的文字,需手动加换行符。可以使用${need}表示上面的need值。
"choices": [ // 商店的选项
{"text": "生命+800", "effect": "status:hp+=800"},
// 如果有多个effect以分号分开参见下面的经验商店
{"text": "攻击+4", "effect": "status:atk+=4"},
{"text": "防御+4", "effect": "status:def+=4"},
{"text": "魔防+10", "effect": "status:mdef+=10"}
// effect只能对status和item进行操作不能修改flag值。
// 必须是X+=Y的形式其中Y可以是一个表达式以status:xxx或item:xxx为参数
// 其他effect样例
// "item:yellowKey+=1" 黄钥匙+1
// "item:pickaxe+=3" 破墙镐+3
// "status:hp+=2*(status:atk+status:def)" 将生命提升攻防和的数值的两倍
]
},
{
"id": "expShop1", // 商店唯一ID
"name": "经验之神",
"icon": "pinkShop",
"textInList": "1F经验商店",
"use": "experience", // 该商店使用的是经验进行计算
"need": "-1", // 如果是对于每个选项所需要的数值不同,这里直接写-1然后下面选项里给定具体数值
"text": "勇敢的武士啊,给我若干经验就可以:",
"choices": [
// 在choices中写need可以针对每个选项都有不同的需求。
// 这里的need同样可以以times作为参数比如 "need": "100+20*times"
{"text": "等级+1", "need": "100", "effect": "status:lv+=1;status:hp+=1000;status:atk+=7;status:def+=7"},
// 多个effect直接以分号分开即可。如上面的意思是生命+1000攻击+7防御+7。
{"text": "攻击+5", "need": "30", "effect": "status:atk+=5"},
{"text": "防御+5", "need": "30", "effect": "status:def+=5"},
]
}
],
"levelUp": [ // 经验升级所需要的数值,是一个数组
{}, // 第一项为初始等级可以简单留空也可以写name
// 每一个里面可以含有三个参数 need, name, effect
// need为所需要的经验数值是一个正整数。请确保need所需的依次递增
// name为该等级的名称也可以省略代表使用系统默认值本项将显示在状态栏中
// effect为本次升级所执行的操作可由若干项组成由分号分开
// 其中每一项写法和上面的商店完全相同同样必须是X+=Y的形式Y是一个表达式同样可以使用status:xxx或item:xxx代表勇士的某项数值/道具个数
{"need": 20, "name": "第二级", "effect": "status:hp+=2*(status:atk+status:def);status:atk+=10;status:def+=10"}, // 先将生命提升攻防和的2倍再将攻击+10防御+10
// effect也允许写一个function代表本次升级将会执行的操作
{"need": 40, "effect": function () {
core.insertAction("恭喜升级!");
core.status.hero.hp *= 2;
core.status.hero.atk += 100;
core.status.hero.def += 100;
}},
// 依次往下写需要的数值即可
]
}
// 各种数值;一些数值可以在这里设置
this.values = {
/****** 角色相关 ******/
"HPMAX": 999999, // HP上限-1则无上限
"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, // 破甲的比例战斗前怪物附加角色防御的x%作为伤害)
'counterAttack': 0.1, // 反击的比例战斗时怪物每回合附加角色攻击的x%作为伤害,无视角色防御)
'purify': 3, // 净化的比例战斗前怪物附加勇士魔防的x倍作为伤害
'hatred': 2, // 仇恨属性中,每杀死一个怪物获得的仇恨值
/****** 系统相关 ******/
'animateSpeed': 500, // 动画时间
}
// 系统FLAG在游戏运行中中请不要修改它。
this.flags = {
/****** 状态栏相关 ******/
"enableFloor": true, // 是否在状态栏显示当前楼层
"enableLv": true, // 是否在状态栏显示当前等级
"enableMDef": true, // 是否在状态栏及战斗界面显示魔防(护盾)
"enableMoney": true, // 是否在状态栏、怪物手册及战斗界面显示金币
"enableExperience": true, // 是否在状态栏、怪物手册及战斗界面显示经验
"enableLevelUp": true, // 是否允许等级提升进阶如果上面enableExperience为false则此项恒视为false
"enableDebuff": true, // 是否涉及毒衰咒如果此项为false则不会在状态栏中显示毒衰咒的debuff
////// 上述的几个开关将直接影响状态栏的显示效果 //////
/****** 道具相关 ******/
"flyNearStair": true, // 是否需要在楼梯边使用传送器
"pickaxeFourDirections": true, // 使用破墙镐是否四个方向都破坏如果false则只破坏面前的墙壁
"bombFourDirections": true, // 使用炸弹是否四个方向都会炸如果false则只炸面前的怪物即和圣锤等价
"bigKeyIsBox": false, // 如果此项为true则视为钥匙盒红黄蓝钥匙+1若为false则视为大黄门钥匙
"equipment": false, // 剑和盾是否直接作为装备。如果此项为true则作为装备需要在道具栏使用否则将直接加属性。
"enableDeleteItem": true, // 是否允许删除(丢弃)道具
/****** 怪物相关 ******/
"enableNegativeDamage": true, // 是否支持负伤害(回血)
"hatredDecrease": true, // 是否在和仇恨怪战斗后减一半的仇恨值此项为false则和仇恨怪不会扣减仇恨值。
"betweenAttackCeil": false, // 夹击方式是向上取整还是向下取整。如果此项为true则为向上取整为false则为向下取整
/****** 系统相关 ******/
"startDirectly": false, // 点击“开始游戏”后是否立刻开始游戏而不显示难度选择界面
"canOpenBattleAnimate": true, // 是否允许用户开启战斗过程如果此项为false则下面两项均强制视为false
"showBattleAnimateConfirm": true, // 是否在游戏开始时提供“是否开启战斗动画”的选项
"battleAnimate": true, // 是否默认显示战斗动画;用户可以手动在菜单栏中开关
"displayEnemyDamage": true, // 是否地图怪物显伤;用户可以手动在菜单栏中开关
"displayExtraDamage": true, // 是否地图高级显伤(领域、夹击等);用户可以手动在菜单栏中开关
"enableGentleClick": true, // 是否允许轻触(获得面前物品)
"potionWhileRouting": false, // 寻路算法是否经过血瓶如果该项为false则寻路算法会自动尽量绕过血瓶
"enableViewMaps": true, // 是否支持在菜单栏中查看所有楼层的地图
"portalWithoutTrigger": true, // 是否支持穿透。所谓穿透,即当自动寻路经过楼梯时,不触发楼层转换事件而是穿过它。
"enableMoveDirectly": true, // 是否允许瞬间移动
}
this.firstData = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData;
this.values = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.values;
this.flags = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.flags;
//delete(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d);
}
data.prototype.getFirstData = function() {
return core.clone(this.firstData);
}
main.instance.data = new data();
}

View File

@ -1,72 +1,12 @@
function enemys() {
this.init();
}
////// 初始化 //////
enemys.prototype.init = function () {
// 怪物属性初始化定义:
this.enemys = {
'greenSlime': {'name': '绿头怪', 'hp': 100, 'atk': 120, 'def': 0, 'money': 1, 'experience': 1, 'special': [1,5,7,8]},
'redSlime': {'name': '红头怪', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'blackSlime': {'name': '青头怪', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'slimelord': {'name': '怪王', 'hp': 100, 'atk': 120, 'def': 0, 'money': 10, 'experience': 0, 'special': [1,9]},
'bat': {'name': '小蝙蝠', 'hp': 100, 'atk': 120, 'def': 0, 'money': 2, 'experience': 0, 'special': 1},
'bigBat': {'name': '大蝙蝠', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'redBat': {'name': '红蝙蝠', 'hp': 100, 'atk': 120, 'def': 0, 'money': 5, 'experience': 0, 'special': 4},
'vampire': {'name': '冥灵魔王', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'skeleton': {'name': '骷髅人', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'skeletonSoilder': {'name': '骷髅士兵', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'skeletonCaptain': {'name': '骷髅队长', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'ghostSkeleton': {'name': '冥队长', 'hp': 100, 'atk': 120, 'def': 0, 'money': 8, 'experience': 0, 'special': 7},
'zombie': {'name': '兽人', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'zombieKnight': {'name': '兽人武士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'rock': {'name': '石头人', 'hp': 100, 'atk': 120, 'def': 0, 'money': 4, 'experience': 0, 'special': 3},
'slimeMan': {'name': '影子战士', 'hp': 100, 'atk': 0, 'def': 0, 'money': 11, 'experience': 0, 'special': [10,21], 'atkValue': 2, 'defValue': 3}, // 退化怪可以在后面写atkValue和defValue表示退化的数值
'bluePriest': {'name': '初级法师', 'hp': 100, 'atk': 120, 'def': 0, 'money': 3, 'experience': 0, 'special': 2, 'point': 1}, // 'point'可以在打败怪物后进行加点,详见文档说明。
'redPriest': {'name': '高级法师', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'brownWizard': {'name': '初级巫师', 'hp': 100, 'atk': 120, 'def': 0, 'money': 16, 'experience': 0, 'special': 15, 'value': 100, 'range': 2}, // 领域怪需要加value表示领域伤害的数值range可选代表领域伤害的范围不加默认为1
'redWizard': {'name': '高级巫师', 'hp': 1000, 'atk': 1200, 'def': 0, 'money': 160, 'experience': 0, 'special': 15, 'value': 200, 'zoneSquare': true}, // zoneSquare可选代表是否九宫格伤害true为是九宫格伤害false或不设置为十字伤害
'yellowGuard': {'name': '初级卫兵', 'hp': 100, 'atk': 120, 'def': 0, 'money': 10, 'experience': 0, 'special': 0},
'blueGuard': {'name': '中级卫兵', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'redGuard': {'name': '高级卫兵', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'swordsman': {'name': '双手剑士', 'hp': 100, 'atk': 120, 'def': 0, 'money': 6, 'experience': 0, 'special': 5},
'soldier': {'name': '冥战士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'yellowKnight': {'name': '金骑士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'redKnight': {'name': '红骑士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'darkKnight': {'name': '黑骑士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'blackKing': {'name': '黑衣魔王', 'hp': 1000, 'atk': 500, 'def': 0, 'money': 1000, 'experience': 1000, 'special': 0, 'bomb': false}, // 加入 'bomb': false 代表该怪物不可被炸弹或圣锤炸掉
'yellowKing': {'name': '黄衣魔王', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'greenKing': {'name': '青衣武士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'blueKnight': {'name': '蓝骑士', 'hp': 100, 'atk': 120, 'def': 0, 'money': 9, 'experience': 0, 'special': 8},
'goldSlime': {'name': '黄头怪', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'poisonSkeleton': {'name': '紫骷髅', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'poisonBat': {'name': '紫蝙蝠', 'hp': 100, 'atk': 120, 'def': 0, 'money': 14, 'experience': 0, 'special': 13},
'steelRock': {'name': '铁面人', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'skeletonPriest': {'name': '骷髅法师', 'hp': 100, 'atk': 100, 'def': 0, 'money': 0, 'experience': 0, 'special': 18, 'value': 20},
'skeletonKing': {'name': '骷髅王', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'skeletonWizard': {'name': '骷髅巫师', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'redSkeletonCaption': {'name': '骷髅武士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'badHero': {'name': '迷失勇者', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'demon': {'name': '魔神武士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'demonPriest': {'name': '魔神法师', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'goldHornSlime': {'name': '金角怪', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'redKing': {'name': '红衣魔王', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'whiteKing': {'name': '白衣武士', 'hp': 100, 'atk': 120, 'def': 0, 'money': 17, 'experience': 0, 'special': 16},
'blackMagician': {'name': '黑暗大法师', 'hp': 100, 'atk': 120, 'def': 0, 'money': 12, 'experience': 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, 'special': 14},
'swordEmperor': {'name': '剑圣', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'whiteHornSlime': {'name': '尖角怪', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'badPrincess': {'name': '痛苦魔女', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'badFairy': {'name': '黑暗仙子', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'grayPriest': {'name': '中级法师', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'redSwordsman': {'name': '剑王', 'hp': 100, 'atk': 120, 'def': 0, 'money': 7, 'experience': 0, 'special': 6, 'n': 8}, // 多连击需要在后面指定n代表是几连击
'whiteGhost': {'name': '水银战士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'poisonZombie': {'name': '绿兽人', 'hp': 100, 'atk': 120, 'def': 0, 'money': 13, 'experience': 0, 'special': 12},
'magicDragon': {'name': '魔龙', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'octopus': {'name': '血影', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'darkFairy': {'name': '仙子', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
'greenKnight': {'name': '强盾骑士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
}
this.enemys = enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80;
//delete(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80);
}
////// 获得一个或所有怪物数据 //////
@ -119,6 +59,7 @@ enemys.prototype.getSpecialText = function (enemyId) {
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;
}
@ -159,9 +100,10 @@ enemys.prototype.getSpecialHint = function (enemy, special) {
case 20: return "无敌:勇士无法打败怪物,除非拥有十字架";
case 21: return "退化:战斗后勇士永久下降"+(enemy.atkValue||0)+"点攻击和"+(enemy.defValue||0)+"点防御";
case 22: return "固伤:战斗前,怪物对勇士造成"+(enemy.damage||0)+"点固定伤害,无视勇士魔防。";
case 23: return "重生:怪物被击败后,角色转换楼层则怪物将再次出现";
default: break;
}
return ""
return "";
}
////// 获得某个怪物的伤害 //////
@ -228,6 +170,10 @@ enemys.prototype.getDefDamage = function (monsterId) {
enemys.prototype.calDamage = function (monster, hero_hp, hero_atk, hero_def, hero_mdef) {
var mon_hp = monster.hp, mon_atk = monster.atk, mon_def = monster.def, mon_special = monster.special;
hero_hp=Math.max(0, hero_hp);
hero_atk=Math.max(0, hero_atk);
hero_def=Math.max(0, hero_def);
hero_mdef=Math.max(0, hero_mdef);
if (this.hasSpecial(mon_special, 20) && !core.hasItem("cross")) // 如果是无敌属性,且勇士未持有十字架
return 999999999; // 返回无限大
@ -300,19 +246,19 @@ enemys.prototype.getCurrentEnemys = function (floorId) {
var used = {};
var mapBlocks = core.status.maps[floorId].blocks;
for (var b = 0; b < mapBlocks.length; b++) {
if (core.isset(mapBlocks[b].event) && !(core.isset(mapBlocks[b].enable) && !mapBlocks[b].enable) && mapBlocks[b].event.cls == 'enemys') {
if (core.isset(mapBlocks[b].event) && !(core.isset(mapBlocks[b].enable) && !mapBlocks[b].enable)
&& mapBlocks[b].event.cls.indexOf('enemy')==0) {
var monsterId = mapBlocks[b].event.id;
if (core.isset(used[monsterId])) continue;
var monster = core.material.enemys[monsterId];
var mon_hp = monster.hp, mon_atk = monster.atk, mon_def = monster.def;
// 坚固
if (this.hasSpecial(monster.special, 3) && mon_def < core.status.hero.atk - 1)
mon_def = core.status.hero.atk - 1;
if (this.hasSpecial(monster.special, 10)) {
mon_atk=core.status.hero.atk;
mon_def=core.status.hero.def;
}
if (this.hasSpecial(monster.special, 3) && mon_def < core.status.hero.atk - 1)
mon_def = core.status.hero.atk - 1;
var specialText = core.enemys.getSpecialText(monsterId);
if (specialText.length>=3) specialText = "多属性...";
@ -345,6 +291,4 @@ enemys.prototype.getCurrentEnemys = function (floorId) {
return a.damage - b.damage;
});
return enemys;
}
main.instance.enemys = new enemys();
}

File diff suppressed because it is too large Load Diff

View File

@ -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();
}

View File

@ -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;
}

224
libs/loader.js Normal file
View File

@ -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;i<names.length;i++) {
this.loadImage(names[i], function (id, image) {
core.loader.setStartLoadTipText('正在加载图片 ' + id + "...");
toSave[id] = image;
items++;
core.loader.setStartProgressVal(items * (100 / names.length));
if (items == names.length) {
if (core.isset(callback)) callback();
}
})
}
}
loader.prototype.loadImage = function (imgName, callback) {
try {
var name=imgName;
if (name.indexOf(".")<0)
name=name+".png";
var image = new Image();
image.src = 'project/images/' + name + "?v=" + main.version;
if (image.complete) {
callback(imgName, image);
return;
}
image.onload = function () {
callback(imgName, image);
}
}
catch (e) {
console.log(e);
}
}
loader.prototype.loadAnimates = function () {
core.animates.forEach(function (t) {
core.http('GET', 'project/animates/' + t + ".animate", null, function (content) {
try {
content = JSON.parse(content);
var data = {};
data.ratio = content.ratio;
data.images = [];
data.images_rev = [];
content.bitmaps.forEach(function (t2) {
if (!core.isset(t2) || t2 == "") {
data.images.push(null);
}
else {
try {
var image = new Image();
image.src = t2;
data.images.push(image);
} catch (e) {
data.images.push(null);
}
}
})
data.frame = content.frame_max;
data.frames = [];
content.frames.forEach(function (t2) {
var info = [];
t2.forEach(function (t3) {
info.push({
'index': t3[0],
'x': t3[1],
'y': t3[2],
'zoom': t3[3],
'opacity': t3[4],
'mirror': t3[5] || 0,
'angle': t3[6] || 0,
})
})
data.frames.push(info);
})
core.material.animates[t] = data;
}
catch (e) {
console.log(e);
core.material.animates[t] = null;
}
}, function (e) {
console.log(e);
core.material.animates[t] = null;
}, "text/plain; charset=x-user-defined")
})
}
////// 加载音频 //////
loader.prototype.loadMusic = function () {
core.bgms.forEach(function (t) {
// 判断是不是mid
if (/^.*\.mid$/i.test(t)) {
if (core.musicStatus.audioContext!=null) {
core.material.bgms[t] = 'loading';
core.http('GET', 'project/sounds/'+t, null, function (data) {
try {
var ff = [];
var mx = data.length;
for (var z = 0; z < mx; z++)
ff[z] = String.fromCharCode(data.charCodeAt(z) & 255);
var shouldStart = core.material.bgms[t] == 'starting';
core.material.bgms[t] = AudioPlayer(core.musicStatus.audioContext, Replayer(MidiFile(ff.join("")), Synth(44100)), true);
if (shouldStart)
core.playBgm(t);
}
catch (e) {
console.log(e);
core.material.bgms[t] = null;
}
}, function (e) {
console.log(e);
core.material.bgms[t] = null;
}, "text/plain; charset=x-user-defined")
}
else {
core.material.bgms[t] = null;
}
}
else {
var music = new Audio();
music.preload = core.musicStatus.startDirectly?'auto':'none';
if (main.bgmRemote) music.src = 'https://gitee.com/ckcz123/h5music/raw/master/'+core.firstData.name+'/'+t;
else music.src = 'project/sounds/'+t;
music.loop = 'loop';
core.material.bgms[t] = music;
}
});
core.sounds.forEach(function (t) {
if (core.musicStatus.audioContext != null) {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'project/sounds/'+t, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) { //下载完成
try {
core.musicStatus.audioContext.decodeAudioData(this.response, function (buffer) {
core.material.sounds[t] = buffer;
}, function (e) {
console.log(e);
core.material.sounds[t] = null;
})
}
catch (ee) {
console.log(ee);
core.material.sounds[t] = null;
}
};
xhr.ontimeout = function(e) {
console.log(e);
core.material.sounds[t] = null;
}
xhr.onerror = function(e) {
console.log(e);
core.material.sounds[t] = null;
}
xhr.send();
}
else {
var music = new Audio();
music.src = 'project/sounds/'+t;
core.material.sounds[t] = music;
}
});
// 直接开始播放
if (core.musicStatus.startDirectly && core.bgms.length>0)
core.playBgm(core.bgms[0]);
}

View File

@ -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();
////// 勇士能否前往某方向 //////
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<blocks.length;n++) {
if (blocks[n].x==x && blocks[n].y==y && core.isset(blocks[n].event)) {
if (needEnable && core.isset(blocks[n].enable) && !blocks[n].enable) return null;
return {"index": n, "block": blocks[n]};
}
}
return null;
}
////// 显示移动某块的动画,达到{“type”:”move”}的效果 //////
maps.prototype.moveBlock = function(x,y,steps,time,immediateHide,callback) {
time = time || 500;
core.status.replay.animate=true;
core.clearMap('animate', 0, 0, 416, 416);
var block = core.getBlock(x,y,core.status.floorId,false);
if (block==null) {// 不存在
if (core.isset(callback)) callback();
return;
}
// 需要删除该块
core.removeBlock(x,y);
core.clearMap('ui', 0, 0, 416, 416);
core.setAlpha('ui', 1.0);
block=block.block;
var blockIcon = core.material.icons[block.event.cls][block.event.id];
var blockImage = core.material.images[block.event.cls];
var height = block.event.height || 32;
var opacityVal = 1;
core.setOpacity('animate', opacityVal);
core.canvas.animate.drawImage(blockImage, 0, blockIcon * height, 32, height, block.x * 32, block.y * 32 +32 - height, 32, height);
// 要运行的轨迹将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<e.value;i++) {
moveSteps.push(e.direction);
}
}
}
});
var nowX=32*x, nowY=32*y, step=0;
var scan = {
'up': {'x': 0, 'y': -1},
'left': {'x': -1, 'y': 0},
'down': {'x': 0, 'y': 1},
'right': {'x': 1, 'y': 0}
};
var animateValue = block.event.animate || 1;
var animateCurrent = 0;
var animateTime = 0;
var animate=window.setInterval(function() {
animateTime += time / 16 / core.status.replay.speed;
if (animateTime >= 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);
}

View File

@ -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; i<specialTexts.length;i++) {
if (specialTexts[i]!='') {
core.fillText('ui', specialTexts[i], left+right-margin-boxWidth/2, top+margin+32+44+20*(++j), '#FF6A6A', '15px Verdana');
core.fillText('ui', specialTexts[i], left+right-margin-boxWidth/2, top+margin+monsterHeight+44+20*(++j), '#FF6A6A', '15px Verdana');
}
}
@ -599,11 +888,11 @@ ui.prototype.drawBattleAnimate = function(monsterId, callback) {
// 怪物的
core.status.boxAnimateObjs = [];
core.status.boxAnimateObjs.push({
'bgx': left + right - margin - 40, 'bgy': top+margin, 'bgsize': boxWidth,
'image': core.material.images.enemys, 'x': left + right - margin - 40 + (boxWidth-32)/2, 'y': top + margin + (boxWidth-32)/2, 'icon': core.material.icons.enemys[monsterId]
});
'bgx': left+right-margin-40, 'bgy': top+margin, 'bgWidth': boxWidth, 'bgHeight': monsterHeight+boxWidth-32,
'x': left + right - margin - 40 + (boxWidth-32)/2, 'y': top + margin + (boxWidth-32)/2, 'height': monsterHeight,
'image': image, 'pos': monsterHeight*icon[monsterId], 'animate': animate
})
core.drawBoxAnimate();
var lineWidth = 80;
var left_start = left + margin + boxWidth + 10;
@ -694,11 +983,11 @@ ui.prototype.drawBattleAnimate = function(monsterId, callback) {
if (turn==0) {
// 勇士攻击
core.drawLine('data', left + right - margin - boxWidth + 6, top+margin+boxWidth-6,
core.drawLine('data', left + right - margin - boxWidth + 6, top+margin+monsterHeight+boxWidth-32-6,
left+right-margin-6, top+margin+6, '#FF0000', 4);
setTimeout(function() {
core.clearMap('data', left + right - margin - boxWidth, top+margin,
boxWidth, boxWidth);
boxWidth, boxWidth+monsterHeight-32);
}, 250);
if (hero_atk-mon_def>0)
@ -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"
]);
}
}

468
libs/utils.js Normal file
View File

@ -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;i<text.length;i++) {
if (text.charAt(i)=='\n') {
contents.push(text.substring(last, i));
last=i+1;
}
else if (text.charAt(i)=='\\' && text.charAt(i+1)=='n') {
contents.push(text.substring(last, i));
last=i+2;
}
else {
var toAdd = text.substring(last, i+1);
var width = core.canvas[canvas].measureText(toAdd).width;
if (width>maxLength) {
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;i<data.length;i++) {
for (var i in data) {
// copy.push(core.clone(data[i]));
copy[i] = core.clone(data[i]);
}
return copy;
}
// 函数
if (data instanceof Function) {
return data;
}
// object
if (data instanceof Object) {
var copy={};
for (var i in data) {
if (data.hasOwnProperty(i))
copy[i]=core.clone(data[i]);
}
return copy;
}
return data;
}
////// 格式化时间为字符串 //////
utils.prototype.formatDate = function(date) {
if (!core.isset(date)) return "";
return date.getFullYear()+"-"+core.setTwoDigits(date.getMonth()+1)+"-"+core.setTwoDigits(date.getDate())+" "
+core.setTwoDigits(date.getHours())+":"+core.setTwoDigits(date.getMinutes())+":"+core.setTwoDigits(date.getSeconds());
}
////// 格式化时间为最简字符串 //////
utils.prototype.formatDate2 = function (date) {
if (!core.isset(date)) return "";
return date.getFullYear()+core.setTwoDigits(date.getMonth()+1)+core.setTwoDigits(date.getDate())
+core.setTwoDigits(date.getHours())+core.setTwoDigits(date.getMinutes())+core.setTwoDigits(date.getSeconds());
}
////// 两位数显示 //////
utils.prototype.setTwoDigits = function (x) {
return parseInt(x)<10?"0"+x:x;
}
////// 数组转RGB //////
utils.prototype.arrayToRGB = function (color) {
var nowR = parseInt(color[0])||0, nowG = parseInt(color[1])||0, nowB = parseInt(color[2])||0;
if (nowR<0) nowR=0; if (nowB<0) nowB=0;if (nowG<0) nowG=0;
if (nowR>255) 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<route.length && !isNaN(route.charAt(index))) {
num+=route.charAt(index++);
}
if (num.length==0) num="1";
return core.isset(noparse)?num:parseInt(num);
}
var getString = function () {
var str="";
while (index<route.length && /\w/.test(route.charAt(index))) {
str+=route.charAt(index++);
}
index++;
return str;
}
while (index<route.length) {
var c=route.charAt(index++);
var nxt=(c=='I'||c=='F'||c=='S')?getString():getNumber();
switch (c) {
case "U": for (var i=0;i<nxt;i++) ans.push("up"); break;
case "D": for (var i=0;i<nxt;i++) ans.push("down"); break;
case "L": for (var i=0;i<nxt;i++) ans.push("left"); break;
case "R": for (var i=0;i<nxt;i++) ans.push("right"); break;
case "I": ans.push("item:"+nxt); break;
case "F": ans.push("fly:"+nxt); break;
case "C": ans.push("choices:"+nxt); break;
case "S": ans.push("shop:"+nxt+":"+getNumber(true)); break;
case "T": ans.push("turn"); break;
case "G": ans.push("getNext"); break;
case "P": ans.push("input:"+nxt); break;
case "N": ans.push("no"); break;
case "M": ++index; ans.push("move:"+nxt+":"+getNumber()); break;
case "K": ans.push("key:"+nxt); break;
}
}
return ans;
}
////// 判断某对象是否不为undefined也不会null //////
utils.prototype.isset = function (val) {
if (val == undefined || val == null || (typeof val=='number' && isNaN(val))) {
return false;
}
return true
}
////// 读取一个本地文件内容 //////
utils.prototype.readFile = function (success, error, readType) {
// 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;
}
if(!readType)core.platform.fileReader.readAsText(core.platform.fileInput.files[0]);
else core.platform.fileReader.readAsDataURL(core.platform.fileInput.files[0]);
core.platform.fileInput.value = '';
}
}
core.platform.successCallback = success;
core.platform.errorCallback = error;
core.platform.fileInput.click();
}
////// 下载文件到本地 //////
utils.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);
}
}
////// 复制一段内容到剪切板 //////
utils.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;
}
////// 动画显示某对象 //////
utils.prototype.show = function (obj, speed, callback) {
if (!core.isset(speed)) {
obj.style.display = 'block';
return;
}
obj.style.display = 'block';
if (main.mode!='play'){
obj.style.opacity = 1;
if (core.isset(callback)) {callback();}
return;
}
obj.style.opacity = 0;
var opacityVal = 0;
var showAnimate = window.setInterval(function () {
opacityVal += 0.03;
obj.style.opacity = opacityVal;
if (opacityVal > 1) {
clearInterval(showAnimate);
if (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();
}

167
main.js
View File

@ -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();

89
project/comment.js Normal file
View File

@ -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层用MT3hh表示隐藏等等 \n楼层唯一标识符需要和名字完全一致 \n这里不能更改floorId,请通过另存为来实现\n$range(false)$end",
"title": "楼层中文名 ",
"name": "显示在状态栏中的层数 ",
"canFlyTo": "该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器) \n$select({\"values\":[true,false]})$end",
"canUseQuickShop": "该层是否允许使用快捷商店 \n$select({\"values\":[true,false]})$end",
"defaultGround": "默认地面的图块IDterrains中 \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": {}
}, */
}

179
project/data.comment.js Normal file
View File

@ -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"
}
}

168
project/data.js Normal file
View File

@ -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,
}
}

67
project/enemys.js Normal file
View File

@ -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]},
}

View File

@ -1,17 +1,19 @@
// 这里需要改楼层名请和文件名及下面的floorId保持完全一致
// 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头
// 推荐用法第20层就用MT20第38层就用MT38地下6层就用MT_6用下划线代替负号隐藏3层用MT3hh表示隐藏等等
main.floors.MT0 = {
"floorId": "MT0", // 楼层唯一标识符,需要和名字完全一致
main.floors.MT0 =
{
"floorId": "MT0", // 这里需要改楼层名请和文件名及下面的floorId保持完全一致
// 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头
// 推荐用法第20层就用MT20第38层就用MT38地下6层就用MT_6用下划线代替负号隐藏3层用MT3hh表示隐藏等等
// 楼层唯一标识符,需要和名字完全一致
"title": "主塔 0 层", // 楼层中文名
"name": "0", // 显示在状态栏中的层数
"canFlyTo": true, // 该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器)
"canUseQuickShop": true, // 该层是否允许使用快捷商店
"defaultGround": "ground", // 默认地面的图块IDterrains中
"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建议使用地图生成器来生成
],

View File

@ -1,29 +1,31 @@
// 这里需要改楼层名请和文件名及下面的floorId保持完全一致
// 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头
// 推荐用法第20层就用MT20第38层就用MT38地下6层就用MT_6用下划线代替负号隐藏3层用MT3hh表示隐藏等等
main.floors.sample0 = {
"floorId": "sample0", // 楼层唯一标识符,需要和名字完全一致
main.floors.sample0 =
{
"floorId": "sample0", // 这里需要改楼层名请和文件名及下面的floorId保持完全一致
// 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头
// 推荐用法第20层就用MT20第38层就用MT38地下6层就用MT_6用下划线代替负号隐藏3层用MT3hh表示隐藏等等
// 楼层唯一标识符,需要和名字完全一致
"title": "样板 0 层", // 楼层中文名
"name": "0", // 显示在状态栏中的层数
"canFlyTo": true, // 该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器)
"canUseQuickShop": true, // 该层是否允许使用快捷商店
"defaultGround": "ground", // 默认地面的图块IDterrains中
"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指明目标点位置。

View File

@ -1,17 +1,19 @@
// 这里需要改楼层名请和文件名及下面的floorId保持完全一致
// 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头
// 推荐用法第20层就用MT20第38层就用MT38地下6层就用MT_6用下划线代替负号隐藏3层用MT3hh表示隐藏等等
main.floors.sample1 = {
"floorId": "sample1", // 楼层唯一标识符,需要和名字完全一致
main.floors.sample1 =
{
"floorId": "sample1", // 这里需要改楼层名请和文件名及下面的floorId保持完全一致
// 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头
// 推荐用法第20层就用MT20第38层就用MT38地下6层就用MT_6用下划线代替负号隐藏3层用MT3hh表示隐藏等等
// 楼层唯一标识符,需要和名字完全一致
"title": "样板 1 层", // 楼层中文名
"name": "1", // 显示在状态栏中的层数
"canFlyTo": true, // 该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器)
"canUseQuickShop": true, // 该层是否允许使用快捷商店
"defaultGround": "grass", // 默认地面的图块IDterrains中
"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位置。

View File

@ -1,17 +1,19 @@
// 这里需要改楼层名请和文件名及下面的floorId保持完全一致
// 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头
// 推荐用法第20层就用MT20第38层就用MT38地下6层就用MT_6用下划线代替负号隐藏3层用MT3hh表示隐藏等等
main.floors.sample2 = {
"floorId": "sample2", // 楼层唯一标识符,需要和名字完全一致
main.floors.sample2 =
{
"floorId": "sample2", // 这里需要改楼层名请和文件名及下面的floorId保持完全一致
// 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头
// 推荐用法第20层就用MT20第38层就用MT38地下6层就用MT_6用下划线代替负号隐藏3层用MT3hh表示隐藏等等
// 楼层唯一标识符,需要和名字完全一致
"title": "主塔 40 层", // 楼层中文名
"name": "40", // 显示在状态栏中的层数
"canFlyTo": false, // 该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器)
"canUseQuickShop": true, // 该层是否允许使用快捷商店
"defaultGround": "snowGround", // 默认地面的图块IDterrains中
"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],

View File

@ -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" : "绘制“关于”界面"
}
}

301
project/functions.js Normal file
View File

@ -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<core.status.thisMap.blocks.length;i++) {
var block=core.status.thisMap.blocks[i];
if (core.isset(block.event) && block.event.id=='box') return false;
}
return true;
}
if (noBoxLeft()) {
// 可以通过if语句来进行开门操作
/*
if (core.status.floorId=='xxx') { // 在某个楼层
core.insertAction([ // 插入一条事件
{"type": "openDoor", "loc": [x,y]} // 开门
])
}
*/
}
},
////// 使用炸弹/圣锤后的事件 //////
"afterUseBomb" : function () {
// 使用炸弹/圣锤后的事件
// 这是一个使用炸弹也能开门的例子
/*
if (core.status.floorId=='xxx' && core.terrainExists(x0,y0,'specialDoor') // 某个楼层,该机关门存在
&& !core.enemyExists(x1,y1) && !core.enemyExists(x2,y2)) // 且守门的怪物都不存在
{
core.insertAction([ // 插入事件
{"type": "openDoor", "loc": [x0,y0]} // 开门
])
}
*/
},
////// 即将存档前可以执行的操作 //////
"beforeSaveData" : function(data) {
// 即将存档前可以执行的操作
},
////// 读档事件后,载入事件前,可以执行的操作 //////
"afterLoadData" : function(data) {
// 读档事件后,载入事件前,可以执行的操作
}
},
"ui":{
////// 绘制“关于”界面 //////
"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像素即可
}
}
}

234
project/icons.js Normal file
View File

@ -0,0 +1,234 @@
icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1 =
{
'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
},
'npc48': {
'npc0': 0,
'npc1': 1,
'npc2': 2,
'npc3': 3,
'npc4': 4,
},
'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,
},
'enemy48': {
'angel': 0,
'elemental': 1,
'steelGuard': 2,
'evilBat': 3,
},
'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,
}
}

BIN
project/images/animates.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 207 B

After

Width:  |  Height:  |  Size: 207 B

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
project/images/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 464 B

After

Width:  |  Height:  |  Size: 464 B

View File

Before

Width:  |  Height:  |  Size: 276 B

After

Width:  |  Height:  |  Size: 276 B

BIN
project/images/enemy48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

Before

Width:  |  Height:  |  Size: 508 B

After

Width:  |  Height:  |  Size: 508 B

View File

Before

Width:  |  Height:  |  Size: 995 B

After

Width:  |  Height:  |  Size: 995 B

View File

Before

Width:  |  Height:  |  Size: 854 B

After

Width:  |  Height:  |  Size: 854 B

Some files were not shown because too many files have changed in this diff Show More