diff --git a/_docs/element.md b/_docs/element.md
index 3e123c60..c5fcc4be 100644
--- a/_docs/element.md
+++ b/_docs/element.md
@@ -326,9 +326,12 @@ floorId指定的是目标楼层的唯一标识符(ID)。
- 使用`\r[...]`来动态修改局部文本的颜色,如`\r[red]`。
- 使用`${}`来计算一个表达式的值,如`${status:atk+status:def}`。
- 使用`\f[...]`来同时插入一张立绘图,如`\f[1.png,100,200]`。
+- 使用`\\i[...]`来在对话框中绘制一个图标,如`\\i[fly]`。
从V2.5.2开始,也允许绘制一张头像图在对话框中,只要通过`\t[1.png]`或`\t[标题,1.png]`的写法。
+**使用`\\i[...]`绘制图标请注意:在事件块中,允许只写一个反斜杠`\i`,系统会自动转义成`\\i`;但是在脚本中必须两个反斜杠都写上!**
+
详细信息请参见[剧情文本控制](event#text:显示一段文字(剧情))中的说明。
从V2.5.2开始,可以用一张WindowSkin图片作为对话框的背景皮肤。
diff --git a/_docs/event.md b/_docs/event.md
index 01c0f726..a84cc3d8 100644
--- a/_docs/event.md
+++ b/_docs/event.md
@@ -267,6 +267,21 @@
]
```
+从V2.5.5以后,也可以使用`\\i[...]`来在对话框中绘制一个图标。
+
+这里可以使用一个合法ID(32x48图块除外),或使用一个系统图标(`core.statusBar.icons`中的内容)。
+
+``` js
+"x,y": [ // 实际执行的事件列表
+ "\t[勇士]\b[up,hero]这是一个飞行器\\i[fly],这是一个破墙镐\\i[pickaxe]",
+ "\t[hero]也可以使用系统图标,比如这是存档\\i[save],这是工具栏\\i[toolbox]",
+]
+```
+
+**可以在控制台中输入`core.statusBar.icons`以查看所有的系统图标定义。**
+
+!> 注意,在事件块中,允许只写一个反斜杠`\i`,系统会自动转义成`\\i`;但是在脚本中必须两个反斜杠都写上!
+
另外值得一提的是,我们是可以在文字中计算一个表达式的值的。只需要将表达式用 `${ }`整个括起来就可以。
``` js
@@ -425,6 +440,23 @@ value是一个表达式,将通过这个表达式计算出的结果赋值给nam
另外注意一点的是,如果hp被设置成了0或以下,将触发lose事件,直接死亡。
+### setValue2:增减勇士的某个属性、道具个数,或某个变量/Flag的值
+
+和`{"type": "setValue"}`的写法完全相同,不过此项是可以直接将值加减到原始数值上。
+
+即下面的写法是等价的:
+
+``` js
+"x,y": [ // 实际执行的事件列表
+ {"type": "setValue", "name": "status:atk", "value": "status:atk+10" } // 攻击提高10点
+ {"type": "setValue2", "name": "status:atk", "value": "10" } // 和上面写法等价
+ {"type": "setValue", "name": "item:yellowKey", "value": "item:yellowKey-3" } // 黄钥匙个数-3
+ {"type": "setValue2", "name": "item:yellowKey", "value": "-3" } // 和上面写法等价
+ {"type": "setValue", "name": "flag:door2", "value": "flag:door2+1" } // 将变量door值+1
+ {"type": "setValue2", "name": "flag:door2", "value": "01" } // 和上面写法等价
+]
+```
+
### setFloor:设置楼层属性
使用`{"type":"setFloor"}`可以设置某层楼的楼层属性。
diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4
index d87bd35e..fafa1bb7 100644
--- a/_server/blockly/MotaAction.g4
+++ b/_server/blockly/MotaAction.g4
@@ -229,6 +229,7 @@ action
| setText_s
| tip_s
| setValue_s
+ | setValue2_s
| setFloor_s
| setGlobalAttribute_s
| setGlobalValue_s
@@ -465,6 +466,18 @@ var code = '{"type": "setValue", "name": "'+idString_e_0+'", "value": "'+express
return code;
*/;
+setValue2_s
+ : '数值增减' ':' '名称' idString_e '+=' expression Newline
+
+
+/* setValue2_s
+tooltip : setValue2:增减勇士的某个属性、道具个数, 或某个变量/Flag的值
+helpUrl : https://h5mota.com/games/template/docs/#/event?id=setValue2%ef%bc%9a%e5%a2%9e%e5%87%8f%e5%8b%87%e5%a3%ab%e7%9a%84%e6%9f%90%e4%b8%aa%e5%b1%9e%e6%80%a7%e3%80%81%e9%81%93%e5%85%b7%e4%b8%aa%e6%95%b0%ef%bc%8c%e6%88%96%e6%9f%90%e4%b8%aa%e5%8f%98%e9%87%8f%2fFlag%e7%9a%84%e5%80%bc
+colour : this.dataColor
+var code = '{"type": "setValue2", "name": "'+idString_e_0+'", "value": "'+expression_0+'"},\n';
+return code;
+*/;
+
setFloor_s
: '设置楼层属性' ':' Floor_Meta_List '楼层名' IdString? '值' EvalString Newline
@@ -1528,13 +1541,13 @@ return code;
*/;
choicesContext
- : '子选项' EvalString '颜色' EvalString? Colour BGNL? Newline action+
+ : '子选项' EvalString '图标' IdString? '颜色' EvalString? Colour BGNL? Newline action+
/* choicesContext
tooltip : 选项的选择
helpUrl : https://h5mota.com/games/template/docs/#/event?id=choices%EF%BC%9A%E7%BB%99%E7%94%A8%E6%88%B7%E6%8F%90%E4%BE%9B%E9%80%89%E9%A1%B9
-default : ["提示文字:红钥匙",""]
+default : ["提示文字:红钥匙","",""]
colour : this.subColor
if (EvalString_1) {
var colorRe = /^(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(,0(\.\d+)?|,1)?$/;
@@ -1543,7 +1556,8 @@ if (EvalString_1) {
else
EvalString_1 = ', "color": "'+EvalString_1+'"';
}
-var code = '{"text": "'+EvalString_0+'"'+EvalString_1+', "action": [\n'+action_0+']},\n';
+IdString_0 = IdString_0?(', "icon": "'+IdString_0+'"'):'';
+var code = '{"text": "'+EvalString_0+'"'+IdString_0+EvalString_1+', "action": [\n'+action_0+']},\n';
return code;
*/;
@@ -2364,6 +2378,13 @@ ActionParser.prototype.parseAction = function() {
MotaActionBlocks['evalString_e'].xmlText([data.value]),
this.next]);
break;
+ case "setValue2":
+ this.next = MotaActionBlocks['setValue2_s'].xmlText([
+ // MotaActionBlocks['idString_e'].xmlText([data.name]),
+ this.tryToUseEvFlag_e('idString_e', [data.name]),
+ MotaActionBlocks['evalString_e'].xmlText([data.value]),
+ this.next]);
+ break;
case "setFloor":
this.next = MotaActionBlocks['setFloor_s'].xmlText([
data.name, data.floorId||null, data.value, this.next]);
@@ -2411,7 +2432,7 @@ ActionParser.prototype.parseAction = function() {
var text_choices = null;
for(var ii=data.choices.length-1,choice;choice=data.choices[ii];ii--) {
text_choices=MotaActionBlocks['choicesContext'].xmlText([
- choice.text,choice.color,'rgba('+choice.color+')',this.insertActionList(choice.action),text_choices]);
+ choice.text,choice.icon,choice.color,'rgba('+choice.color+')',this.insertActionList(choice.action),text_choices]);
}
this.next = MotaActionBlocks['choices_s'].xmlText([
this.isset(data.text)?this.EvalString(data.text):null,'','',text_choices,this.next]);
diff --git a/_server/data.comment.js b/_server/data.comment.js
index 8f157bcf..76c87a1f 100644
--- a/_server/data.comment.js
+++ b/_server/data.comment.js
@@ -16,26 +16,31 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"images": {
"_leaf": true,
"_type": "textarea",
+ "_range": "editor.mode.checkUnique(thiseval)",
"_data": "在此存放所有可能使用的图片(tilesets除外) \n图片可以被作为背景图(的一部分),也可以直接用自定义事件进行显示。 \n 图片名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 \n 建议对于较大的图片,在网上使用在线的“图片压缩工具(http://compresspng.com/zh/)”来进行压缩,以节省流量 \n 依次向后添加"
},
"tilesets": {
"_leaf": true,
"_type": "textarea",
+ "_range": "editor.mode.checkUnique(thiseval)",
"_data": "在此存放额外素材的图片名, \n可以自定导入任意张素材图片,无需PS,无需注册,即可直接在游戏中使用 \n 形式如[\"1.png\", \"2.png\"] ,将需要的素材图片放在images目录下 \n 素材的宽高必须都是32的倍数,且图片上的总图块数不超过1000(即最多有1000个32*32的图块在该图片上)"
},
"animates": {
"_leaf": true,
"_type": "textarea",
+ "_range": "editor.mode.checkUnique(thiseval)",
"_data": "在此存放所有可能使用的动画,必须是animate格式,在这里不写后缀名 \n动画必须放在animates目录下;文件名不能使用中文,不能带空格或特殊字符 \n \"jianji\", \"thunder\" \n 根据需求自行添加"
},
"bgms": {
"_leaf": true,
"_type": "textarea",
+ "_range": "editor.mode.checkUnique(thiseval)",
"_data": "在此存放所有的bgm,和文件名一致。 \n音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好"
},
"sounds": {
"_leaf": true,
"_type": "textarea",
+ "_range": "editor.mode.checkUnique(thiseval)",
"_data": "在此存放所有的SE,和文件名一致 \n音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好"
},
"startBackground": {
@@ -131,17 +136,20 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"title": {
"_leaf": true,
"_type": "textarea",
+ "_string": true,
"_data": "游戏名,将显示在标题页面以及切换楼层的界面中"
},
"name": {
"_leaf": true,
"_type": "textarea",
+ "_string": true,
"_range": "/^[a-zA-Z0-9_]{1,30}$/.test(thiseval)",
"_data": "游戏的唯一英文标识符。由英文、数字、下划线组成,不能超过30个字符。\n此项必须修改,其将直接影响到存档的定位!"
},
"version": {
"_leaf": true,
"_type": "textarea",
+ "_string": true,
"_data": "当前游戏版本;版本不一致的存档不能通用。"
},
"floorId": {
@@ -160,6 +168,7 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"name": {
"_leaf": true,
"_type": "textarea",
+ "_string": true,
"_data": "勇士名;可以改成喜欢的"
},
"lv": {
@@ -211,6 +220,7 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"equipment": {
"_leaf": true,
"_type": "textarea",
+ "_range": "thiseval instanceof Array",
"_data": "初始装上的装备,此处建议请直接留空数组"
},
"items": {
@@ -220,21 +230,25 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"keys": {
"_leaf": true,
"_type": "textarea",
+ "_range": "thiseval instanceof Object && !(thiseval instanceof Array)",
"_data": "初始三种钥匙个数"
},
"constants": {
"_leaf": true,
"_type": "textarea",
+ "_range": "thiseval instanceof Object && !(thiseval instanceof Array)",
"_data": "初始永久道具个数,例如初始送手册可以写 {\"book\": 1}"
},
"tools": {
"_leaf": true,
"_type": "textarea",
+ "_range": "thiseval instanceof Object && !(thiseval instanceof Array)",
"_data": "初始消耗道具个数,例如初始有两破可以写 {\"pickaxe\": 2}"
},
"equips": {
"_leaf": true,
"_type": "textarea",
+ "_range": "thiseval instanceof Object && !(thiseval instanceof Array)",
"_data": "初始装备个数,例如初始送铁剑可以写 {\"sword1\": 1}"
}
}
@@ -242,6 +256,7 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"flyRange": {
"_leaf": true,
"_type": "textarea",
+ "_range": "thiseval instanceof Array",
"_data": "初始可飞的楼层;一般留空数组即可"
},
"loc": {
@@ -276,6 +291,7 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"flags": {
"_leaf": true,
"_type": "textarea",
+ "_range": "thiseval instanceof Object && !(thiseval instanceof Array)",
"_data": "游戏过程中的变量或flags"
},
"steps": {
diff --git a/_server/editor.js b/_server/editor.js
index 006a4df2..5a9f3539 100644
--- a/_server/editor.js
+++ b/_server/editor.js
@@ -1230,16 +1230,15 @@ editor.prototype.listen = function () {
});
}
- var clearLoc = document.getElementById('clearLoc');
- clearLoc.onmousedown = function(e){
+ var _clearPoint = function (clearPoint) {
editor.hideMidMenu();
- e.stopPropagation();
editor.preMapData = null;
reDo = null;
editor.info = 0;
editor_mode.onmode('');
var now = editor.pos;
- editor.map[now.y][now.x]=editor.info;
+ if (clearPoint)
+ editor.map[now.y][now.x]=editor.info;
editor.updateMap();
fields.forEach(function(v){
delete editor.currentFloorData[v][now.x+','+now.y];
@@ -1249,11 +1248,23 @@ editor.prototype.listen = function () {
printe(err);
throw(err)
}
- ;printf('清空此点及事件成功');
+ ;printf(clearPoint?'清空该点和事件成功':'只清空该点事件成功');
editor.drawPosSelection();
});
}
+ var clearEvent = document.getElementById('clearEvent');
+ clearEvent.onmousedown = function (e) {
+ e.stopPropagation();
+ _clearPoint(false);
+ }
+
+ var clearLoc = document.getElementById('clearLoc');
+ clearLoc.onmousedown = function(e){
+ e.stopPropagation();
+ _clearPoint(true);
+ }
+
var brushMod=document.getElementById('brushMod');
brushMod.onchange=function(){
editor.brushMod=brushMod.value;
diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js
index b624e7c4..e1db7827 100644
--- a/_server/editor_blockly.js
+++ b/_server/editor_blockly.js
@@ -64,9 +64,9 @@ editor_blockly = function () {
MotaActionBlocks['lose_s'].xmlText(),
MotaActionBlocks['choices_s'].xmlText([
'选择剑或者盾','流浪者','man',MotaActionBlocks['choicesContext'].xmlText([
- '剑','',null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [3,3]}]),
+ '剑','','',null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [3,3]}]),
MotaActionBlocks['choicesContext'].xmlText([
- '盾','',null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [9,3]}]),
+ '盾','','',null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [9,3]}]),
])
])
]),
@@ -75,6 +75,9 @@ editor_blockly = function () {
MotaActionBlocks['setValue_s'].xmlText([
MotaActionBlocks['idString_1_e'].xmlText(['status','hp'])
]),
+ MotaActionBlocks['setValue2_s'].xmlText([
+ MotaActionBlocks['idString_1_e'].xmlText(['status','hp'])
+ ]),
MotaActionBlocks['setFloor_s'].xmlText(),
MotaActionBlocks['setGlobalAttribute_s'].xmlText(),
MotaActionBlocks['setGlobalValue_s'].xmlText(),
@@ -154,6 +157,9 @@ editor_blockly = function () {
MotaActionBlocks['setValue_s'].xmlText([
MotaActionBlocks['idString_1_e'].xmlText(['status','hp'])
]),
+ MotaActionBlocks['setValue2_s'].xmlText([
+ MotaActionBlocks['idString_1_e'].xmlText(['status','hp'])
+ ]),
MotaActionBlocks['expression_arithmetic_0'].xmlText(),
MotaActionBlocks['evFlag_e'].xmlText(),
MotaActionBlocks['negate_e'].xmlText(),
@@ -178,8 +184,8 @@ editor_blockly = function () {
{"text": "黄钥匙(\${9+flag:shop_times}金币)", "color": [255,255,0,1], "action": [
{"type": "if", "condition": "status:money>=9+flag:shop_times",
"true": [
- {"type": "setValue", "name": "status:money", "value": "status:money-(9+flag:shop_times)"},
- {"type": "setValue", "name": "item:yellowKey", "value": "item:yellowKey+1"},
+ {"type": "setValue2", "name": "status:money", "value": "-(9+flag:shop_times)"},
+ {"type": "setValue2", "name": "item:yellowKey", "value": "1"},
],
"false": [
"\t[老人,man]你的金钱不足!",
@@ -194,7 +200,7 @@ editor_blockly = function () {
]}
]
},
- {"type": "setValue", "name": "flag:shop_times", "value": "flag:shop_times+1"},
+ {"type": "setValue2", "name": "flag:shop_times", "value": "1"},
{"type": "revisit"}
], 'event'),
'',
@@ -217,7 +223,7 @@ editor_blockly = function () {
],'afterBattle'),
'',
MotaActionFunctions.actionParser.parse([
- {"type": "setValue", "name": "flag:__door__", "value": "flag:__door__+1"},
+ {"type": "setValue2", "name": "flag:__door__", "value": "1"},
{"type": "if", "condition": "flag:__door__==2",
"true": [
{"type": "openDoor", "loc": [10,5]}
@@ -339,7 +345,7 @@ function omitedcheckUpdateFunction(event) {
}
}
try {
- var code = Blockly.JavaScript.workspaceToCode(workspace);
+ var code = Blockly.JavaScript.workspaceToCode(workspace).replace(/\\i/g, '\\\\i');
codeAreaHL.setValue(code);
} catch (error) {
codeAreaHL.setValue(String(error));
@@ -481,7 +487,8 @@ function omitedcheckUpdateFunction(event) {
MotaActionFunctions.parse(
eval('obj=' + codeAreaHL.getValue().replace(/[<>&]/g, function (c) {
return {'<': '<', '>': '>', '&': '&'}[c];
- }).replace(/\\r/g, '\\\\r').replace(/\\f/g, '\\\\f')),
+ }).replace(/\\r/g, '\\\\r').replace(/\\f/g, '\\\\f')
+ .replace(/\\i/,'\\\\i')),
document.getElementById('entryType').value
);
}
@@ -555,6 +562,7 @@ function omitedcheckUpdateFunction(event) {
return;
}
var code = Blockly.JavaScript.workspaceToCode(editor_blockly.workspace);
+ code = code.replace(/\\i/g, '\\\\i');
eval('var obj=' + code);
setvalue(JSON.stringify(obj));
}
diff --git a/_server/editor_mode.js b/_server/editor_mode.js
index 40ad2801..15950e8e 100644
--- a/_server/editor_mode.js
+++ b/_server/editor_mode.js
@@ -1166,7 +1166,21 @@ editor_mode = function (editor) {
if(editor.isMobile)editor.showdataarea(false);
}
+ editor_mode.checkUnique = function (thiseval) {
+ if (!(thiseval instanceof Array)) return false;
+ var map = {};
+ for (var i = 0; i