diff --git a/README.md b/README.md index 4ea48018..7f6628d2 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,21 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏! ## 更新说明 -### 2018.7.9 V2.3.3 +### 2018.7.21 V2.3.3 + +HTML5魔塔样板V2.3.3 + +* [x] 将怪物特殊属性定义和伤害计算函数移动到脚本编辑中 +* [x] 地图编辑器可以使用矩形方式绘制地图 +* [x] 瞬间移动可以指定存在事件的点(如怪物、门、楼梯等) +* [x] 事件:画面震动 +* [x] 事件:更新怪物数据 +* [x] 移动事件和跳跃事件增加“不消失”选项 +* [x] 修改默认bgm +* [x] 修复读档开启战斗动画等Bug +* [x] 大量细节优化 + +### 2018.7.9 V2.3.2 * [x] 适配手机端的造塔页面 * [x] 启动服务的多开版本 diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index ab728be1..c35e3b0d 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -193,6 +193,7 @@ action | setBlock_s | setHeroIcon_s | update_s + | updateEnemys_s | sleep_s | wait_s | battle_s @@ -205,6 +206,7 @@ action | follow_s | unfollow_s | animate_s + | viberate_s | showImage_0_s | showImage_1_s | animateImage_0_s @@ -496,6 +498,18 @@ var code = '{"type": "update"},\n'; return code; */; +updateEnemys_s + : '更新怪物数据' Newline + + +/* updateEnemys_s +tooltip : updateEnemys: 立刻更新怪物数据 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=updateEnemys%ef%bc%9a%e6%9b%b4%e6%96%b0%e6%80%aa%e7%89%a9%e6%95%b0%e6%8d%ae +colour : this.dataColor +var code = '{"type": "updateEnemys"},\n'; +return code; +*/; + sleep_s : '等待' Int '毫秒' Newline @@ -639,6 +653,20 @@ var code = '{"type": "unfollow"' + EvalString_0 + '},\n'; return code; */; +viberate_s + : '画面震动' '时间' Int Newline + + +/* viberate_s +tooltip : viberate: 画面震动 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=viberate%ef%bc%9a%e7%94%bb%e9%9d%a2%e9%9c%87%e5%8a%a8 +default : [2000] +colour : this.soundColor +Int_0 = Int_0 ?(', "time": '+Int_0):''; +var code = '{"type": "viberate"' + Int_0 + '},\n'; +return code; +*/; + animate_s : '显示动画' IdString '位置' EvalString? Newline @@ -806,20 +834,20 @@ return code; */; move_s - : '移动事件' 'x' PosString? ',' 'y' PosString? '动画时间' Int? '消失时无动画时间' Bool BGNL? StepString Newline + : '移动事件' 'x' PosString? ',' 'y' PosString? '动画时间' Int? '不消失' Bool BGNL? StepString Newline /* move_s tooltip : move: 让某个NPC/怪物移动,位置可不填代表当前事件 helpUrl : https://ckcz123.github.io/mota-js/#/event?id=move%EF%BC%9A%E8%AE%A9%E6%9F%90%E4%B8%AAnpc%E6%80%AA%E7%89%A9%E7%A7%BB%E5%8A%A8 -default : ["","",500,null,"上右3下2左上左2"] +default : ["","",500,false,"上右3下2左上左2"] colour : this.eventColor var floorstr = ''; if (PosString_0 && PosString_1) { floorstr = ', "loc": ['+PosString_0+','+PosString_1+']'; } Int_0 = Int_0 ?(', "time": '+Int_0):''; -var code = '{"type": "move"'+floorstr+''+Int_0+', "steps": '+JSON.stringify(StepString_0)+', "immediateHide": '+Bool_0+'},\n'; +var code = '{"type": "move"'+floorstr+''+Int_0+', "steps": '+JSON.stringify(StepString_0)+', "keep": '+Bool_0+'},\n'; return code; */; @@ -838,13 +866,13 @@ return code; */; jump_s - : '跳跃事件' '起始 x' PosString? ',' 'y' PosString? '终止 x' PosString? ',' 'y' PosString? BGNL? '动画时间' Int? '消失时无动画时间' Bool Newline + : '跳跃事件' '起始 x' PosString? ',' 'y' PosString? '终止 x' PosString? ',' 'y' PosString? '动画时间' Int? '不消失' Bool Newline /* jump_s tooltip : jump: 让某个NPC/怪物跳跃 helpUrl : https://ckcz123.github.io/mota-js/#/event?id=jump%EF%BC%9A%E8%AE%A9%E6%9F%90%E4%B8%AANPC%2F%E6%80%AA%E7%89%A9%E8%B7%B3%E8%B7%83 -default : ["","","","",500,null] +default : ["","","","",500,true] colour : this.eventColor var floorstr = ''; if (PosString_0 && PosString_1) { @@ -854,7 +882,7 @@ if (PosString_2 && PosString_3) { floorstr += ', "to": ['+PosString_2+','+PosString_3+']'; } Int_0 = Int_0 ?(', "time": '+Int_0):''; -var code = '{"type": "jump"'+floorstr+''+Int_0+', "immediateHide": '+Bool_0+'},\n'; +var code = '{"type": "jump"'+floorstr+''+Int_0+', "keep": '+Bool_0+'},\n'; return code; */; @@ -1222,7 +1250,7 @@ Floor_List /*Floor_List ['floorId',':before',':next']*/; Stair_List - : '坐标'|'上楼'|'下楼' + : '坐标'|'上楼梯'|'下楼梯' /*Stair_List ['loc','upFloor','downFloor']*/; SetTextPosition_List @@ -1513,7 +1541,7 @@ ActionParser.prototype.parseAction = function() { case "move": // 移动事件 data.loc=data.loc||['','']; this.next = MotaActionBlocks['move_s'].xmlText([ - data.loc[0],data.loc[1],data.time||0,data.immediateHide,this.StepString(data.steps),this.next]); + data.loc[0],data.loc[1],data.time||0,data.keep,this.StepString(data.steps),this.next]); break; case "moveHero": this.next = MotaActionBlocks['moveHero_s'].xmlText([ @@ -1523,7 +1551,7 @@ ActionParser.prototype.parseAction = function() { data.from=data.from||['','']; data.to=data.to||['','']; this.next = MotaActionBlocks['jump_s'].xmlText([ - data.from[0],data.from[1],data.to[0],data.to[1],data.time||0,data.immediateHide,this.next]); + data.from[0],data.from[1],data.to[0],data.to[1],data.time||0,data.keep,this.next]); break; case "jumpHero": // 跳跃勇士 data.loc=data.loc||['',''] @@ -1556,6 +1584,9 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['animate_s'].xmlText([ data.name,animate_loc,this.next]); break; + case "viberate": // 画面震动 + this.next = MotaActionBlocks['viberate_s'].xmlText([data.time||0, this.next]); + break; case "showImage": // 显示图片 if(this.isset(data.name)){ this.next = MotaActionBlocks['showImage_0_s'].xmlText([ @@ -1702,6 +1733,10 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['update_s'].xmlText([ this.next]); break; + case "updateEnemys": + this.next = MotaActionBlocks['updateEnemys_s'].xmlText([ + this.next]); + break; case "sleep": // 等待多少毫秒 this.next = MotaActionBlocks['sleep_s'].xmlText([ data.time,this.next]); diff --git a/_server/data.comment.js b/_server/data.comment.js index 83bcb8a9..74cd5fea 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -495,6 +495,12 @@ data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_bool": "bool", "_data": "夹击方式是向上取整还是向下取整。如果此项为true则为向上取整,为false则为向下取整" }, + "useLoop": { + "_leaf": true, + "_type": "checkbox", + "_bool": "bool", + "_data": "是否循环计算临界;如果此项为true则使用循环法(而不是回合数计算法)来算临界" + }, "startDirectly": { "_leaf": true, "_type": "checkbox", diff --git a/_server/editor.js b/_server/editor.js index 0e0cb653..b76134b0 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -1,6 +1,7 @@ function editor() { this.version = "2.0"; this.material = {}; + this.brushMod = "line";//["line","rectangle"] } editor.prototype.init = function (callback) { @@ -503,6 +504,20 @@ editor.prototype.listen = function () { e.stopPropagation(); if (stepPostfix && stepPostfix.length) { preMapData = JSON.parse(JSON.stringify(editor.map)); + if(editor.brushMod==='rectangle'){ + var x0=stepPostfix[0].x; + var y0=stepPostfix[0].y; + var x1=stepPostfix[stepPostfix.length-1].x; + var y1=stepPostfix[stepPostfix.length-1].y; + if(x0>x1){x0^=x1;x1^=x0;x0^=x1;}//swap + if(y0>y1){y0^=y1;y1^=y0;y0^=y1;}//swap + stepPostfix=[]; + for(var ii=x0;ii<=x1;ii++){ + for(var jj=y0;jj<=y1;jj++){ + stepPostfix.push({x:ii,y:jj}) + } + } + } currDrawData.pos = JSON.parse(JSON.stringify(stepPostfix)); currDrawData.info = JSON.parse(JSON.stringify(editor.info)); reDo = null; @@ -839,6 +854,16 @@ editor.prototype.listen = function () { }); } + var brushMod=document.getElementById('brushMod'); + brushMod.onchange=function(){ + editor.brushMod=brushMod.value; + } + + var brushMod2=document.getElementById('brushMod2'); + if(brushMod2)brushMod2.onchange=function(){ + editor.brushMod=brushMod2.value; + } + }//绑定事件 /* diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index dfbe4314..b35decf8 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -87,6 +87,7 @@ editor_blockly = function () { MotaActionBlocks['setValue_s'].xmlText(), MotaActionBlocks['input_s'].xmlText(), MotaActionBlocks['update_s'].xmlText(), + MotaActionBlocks['updateEnemys_s'].xmlText(), MotaActionBlocks['moveHero_s'].xmlText(), MotaActionBlocks['jumpHero_s'].xmlText(), MotaActionBlocks['changeFloor_s'].xmlText(), @@ -115,6 +116,7 @@ editor_blockly = function () { '', MotaActionBlocks['sleep_s'].xmlText(), MotaActionBlocks['wait_s'].xmlText(), + MotaActionBlocks['viberate_s'].xmlText(), MotaActionBlocks['animate_s'].xmlText(), MotaActionBlocks['setFg_0_s'].xmlText(), MotaActionBlocks['setFg_1_s'].xmlText(), diff --git a/_server/functions.comment.js b/_server/functions.comment.js index dd9466e7..0b2901ae 100644 --- a/_server/functions.comment.js +++ b/_server/functions.comment.js @@ -87,6 +87,30 @@ functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = } } }, + "enemys": { + "_leaf": false, + "_type": "object", + "_data": { + "getSpecials": { + "_leaf": true, + "_type": "textarea", + "_lint": true, + "_data": "怪物特殊属性的定义(获得怪物的特殊属性)" + }, + "getDamageInfo": { + "_leaf": true, + "_type": "textarea", + "_lint": true, + "_data": "获得战斗伤害信息(实际伤害计算函数)" + }, + "updateEnemys": { + "_leaf": true, + "_type": "textarea", + "_lint": true, + "_data": "更新怪物数据,可以在这里对怪物属性和数据进行动态更新" + } + } + }, "ui": { "_leaf": false, "_type": "object", diff --git a/_server/vm.js b/_server/vm.js index 4e70722b..312507fa 100644 --- a/_server/vm.js +++ b/_server/vm.js @@ -24,7 +24,7 @@ document.body.onmousedown = function (e) { } }); - if (clickpath.indexOf('edit') === -1 && clickpath.indexOf('tip') === -1) { + if (clickpath.indexOf('edit') === -1 && clickpath.indexOf('tip') === -1 && clickpath.indexOf('brushMod') === -1 && clickpath.indexOf('brushMod2') === -1) { if (clickpath.indexOf('eui') === -1) { if (selectBox.isSelected) { editor_mode.onmode(''); diff --git a/docs/api.md b/docs/api.md index e2a9fd86..eaa6f276 100644 --- a/docs/api.md +++ b/docs/api.md @@ -338,7 +338,7 @@ core.enemys.getDamageInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef) core.enemys.calDamage(enemy, hero_hp, hero_atk, hero_def, hero_mdef) -计算战斗伤害;实际返回的是上面getDamageInfo中伤害的数值。 +获得在某个勇士属性下怪物伤害;实际返回的是上面getDamageInfo中伤害的数值。 core.enemys.getCurrentEnemys(floorId) diff --git a/docs/event.md b/docs/event.md index 1bf94a19..6f159aaa 100644 --- a/docs/event.md +++ b/docs/event.md @@ -509,6 +509,12 @@ name是可选的,代表目标行走图的文件名。 如果你需要刷新状态栏和地图显伤,只需要简单地调用 `{"type": "update"}` 即可。 +### updateEnemys:更新怪物数据 + +使用 `{"type": "updateEnemys"}` 可以动态修改怪物数据。 + +详见[怪物数据的动态修改](#怪物数据的动态修改)。 + ### sleep:等待多少毫秒 等价于RMXP中的"等待x帧",不过是以毫秒来计算。 @@ -649,6 +655,10 @@ name为可选的,是要取消跟随的行走图文件名。 如果name省略,则会取消所有的跟随效果。 +### viberate:画面震动 + +使用 `{"type": "viberate", "time": 2000}` 可以造成画面震动效果,后面time可以指定震动时间。 + ### animate:显示动画 我们可以使用 `{"type": "animate"}` 来显示一段动画。 @@ -806,7 +816,7 @@ level为天气的强度等级,在1-10之间。1级为最弱,10级为最强 {"type": "move", "time": 750, "loc": [x,y], "steps": [// 动画效果,time为移动速度(比如这里每750ms一步),loc为位置可选,steps为移动数组 {"direction": "right", "value": 2},// 这里steps 的效果为向右移动2步,在向下移动一步并消失 "down" // 如果该方向上只移动一步则可以这样简写,效果等价于上面value为1 - ], "immediateHide": true }, //immediateHide可选,制定为true则立刻消失,否则渐变消失 + ], "keep": true }, // keep可选,如果为true则不消失,否则渐变消失 ] ``` @@ -818,13 +828,13 @@ steps为一个数组,其每一项为一个 `{"direction" : xxx, "value": n}` 如果只移动一步可以直接简单的写方向字符串(`up/left/down/right`)。 -immediateHide为一个可选项,代表该事件移动完毕后是否立刻消失。如果该项指定了并为true,则移动完毕后直接消失,否则以动画效果消失。 +keep为一个可选项,代表该事件移动完毕后是否消失。如果该项指定了并为true,则移动完毕后将不消失,否则以动画效果消失。 值得注意的是,当调用move事件时,实际上是使事件脱离了原始地点。为了避免冲突,规定:move事件会自动调用该点的hide事件。 换句话说,当move事件被调用后,该点本身的事件将被禁用。 -move完毕后移动的NPC/怪物一定会消失,只不过可以通过immediateHide决定是否立刻消失还是以time作为时间来动画效果消失。 +如果指定了`"keep": true`,则相当于会在目标地点触发一个`setBlock`事件;如需能继续对话交互请在目标地点再写事件。 如果想让move后的NPC/怪物仍然可以被交互,需采用如下的写法: @@ -832,11 +842,9 @@ move完毕后移动的NPC/怪物一定会消失,只不过可以通过immediate "4,3": [ // [4,3]是一个NPC,比如小偷 {"type": "move", "time": 750, "steps": [ // 向上移动两格,每步750毫秒 {"direction": "up", "value": 2}, - ], "immediateHide": true}, // 移动完毕立刻消失 - {"type": "show", "loc": [4,1]} // 指定[4,1]点的NPC立刻生效(显示) - {"type": "trigger", "loc": [4,1]} // 立刻触发[4,1]点的事件 + ], "keep": true}, // 移动完毕后不消失 ], -"4,1": { // [4,1]也是这个NPC,而且是向上移动两个的位置 +"4,1": { // [4,1]为目标地点 "enable": false, // 初始时需要是禁用状态,被show调用后将显示出来 "data": [ "\t[杰克,thief]这样看起来就好像移动过去后也可以被交互。" @@ -873,7 +881,7 @@ move完毕后移动的NPC/怪物一定会消失,只不过可以通过immediate ``` js "x,y": [ // 实际执行的事件列表 - {"type": "jump", "from": [3,6], "to": [2,1], "time": 750, "immediateHide": true}, + {"type": "jump", "from": [3,6], "to": [2,1], "time": 750, "keep": true}, ] ``` @@ -883,13 +891,9 @@ to为要跳跃到的坐标。可以省略,如果省略则跳跃到当前坐标 time选项必须指定,为全程跳跃所需要用到的时间。 -immediateHide为一个可选项,同上代表该跳跃完毕后是否立刻消失。如果该项指定了并为true,则跳跃完毕后直接消失,否则以动画效果消失。 +keep为一个可选项,同上代表该跳跃完毕后是否不消失。如果该项指定了并为true,则跳跃完毕后不会消失,否则以动画效果消失。 -值得注意的是,当调用jump事件时,实际上是使事件脱离了原始地点。 - -为了避免冲突,同move事件一样规定:jump事件会自动调用该点的hide事件。 - -如果是本地跳跃,需要在跳跃完毕后再启用事件。 +如果指定了`"keep": true`,则相当于会在目标地点触发一个`setBlock`事件;如需能继续对话交互请在目标地点再写事件。 ### jumpHero:跳跃勇士 @@ -1591,25 +1595,33 @@ core.insertAction([ 而在我们的存档中,是不会对怪物数据进行存储的,只会存各个变量和Flag,因此我们需要在读档后根据变量或Flag来调整怪物数据。 -我们可以在脚本编辑中的`afterLoadData`进行处理。 +我们可以在脚本编辑中的`updateEnemys`进行处理。 ``` js ////// 读档事件后,载入事件前,可以执行的操作 ////// -"afterLoadData" : function(data) { - // 读档事件后,载入事件前,可以执行的操作 - if (core.hasFlag("fengyin")) { // 如果存在封印(flag为真) - core.material.enemys.blackKing.hp/=10; // 将怪物的血量变成原来的十分之一 - // ... - } - // 同样难度分歧可以类似写 if (core.getFlag('hard', 0)==3) {... +"updateEnemys" : function () { + // 更新怪物数据,可以在这里对怪物属性和数据进行动态更新,详见文档——事件——怪物数据的动态修改 + // 比如下面这个例子,如果flag:xxx为真,则将绿头怪的攻击设为100,红头怪的金币设为20 + // 推荐写变化后的具体数值,以免多次变化导致冲突 + /* + // 如果flag:xxx为真;你也可以写其他判断语句比如core.hasItem(...)等等 + if (core.hasFlag('xxx')) { + core.material.enemys.greenSlime.atk = 100; + core.material.enemys.redSlime.money = 20; + } + */ + // 别忘了在事件中调用“更新怪物数据”事件! } +``` -// 在封印时,可以调用setValue将该flag置为真,然后调用自定义脚本 core.afterLoadData() 即可。 +当我们获得一个道具(或者触发某个事件等)后,需要在事件中调用“更新怪物数据”事件。 + +``` js +// 调用`updateEnemys`(更新怪物数据)事件就可以触发了 "x,y": [ - {"type": "setValue", "name": "flag:fengyin", "value": "true"}, // 封印 - {"type": "function", "function": function() { // 手动调用自定义JS脚本 core.afterLoadData() - core.afterLoadData(); - }} + "将flag:xxx置为真,就可以让怪物数据发生改变!", + {"type": "setValue", "name": "flag:xxx", "value": "true"}, // 将flag:xxx置为真 + {"type": "updateEnemys"} // 更新怪物数据;此时绿头怪攻击就会变成100了 ] ``` diff --git a/editor-mobile.html b/editor-mobile.html index 954e81e1..21c1a885 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -244,6 +244,7 @@ +