diff --git a/B站视频教程.url b/B站视频教程.url new file mode 100644 index 00000000..036a8a64 --- /dev/null +++ b/B站视频教程.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,2 +[InternetShortcut] +IDList= +URL=https://www.bilibili.com/video/av32781473/ \ No newline at end of file diff --git a/HTML5魔塔样板使用指南.url b/HTML5魔塔样板使用说明文档.url similarity index 64% rename from HTML5魔塔样板使用指南.url rename to HTML5魔塔样板使用说明文档.url index 823d8f8d..021c516b 100644 --- a/HTML5魔塔样板使用指南.url +++ b/HTML5魔塔样板使用说明文档.url @@ -2,4 +2,4 @@ Prop3=19,2 [InternetShortcut] IDList= -URL=https://ckcz123.github.io/mota-js/ +URL=https://h5mota.com/games/template/docs/ \ No newline at end of file diff --git a/README.md b/README.md index 406abacc..45d52676 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,23 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏! ## 更新说明 +### 2018.11.21 V2.5.1 + +* [x] 新增事件type:insert,可以插入另一个地点的事件执行(公共事件) +* [x] 可以使用\r来控制剧情文本部分文字的颜色 +* [x] 新增事件type:switch,多重分歧 +* [x] 绘制前景/背景层时淡化其他图层 +* [x] 追加素材的自动调整(如白底、不规范的素材) +* [x] 浏览地图时:左上角/V开启显伤;右上角/Z查看当前层大地图 +* [x] 允许在受到领域夹击等伤害后禁用快捷商店 +* [x] 升级的扣除模式,即不显示经验值,只显示升级的所需剩余值 +* [x] 装备增加可装备条件判定 +* [x] 选项界面可以使用1-9快速选择 +* [x] 未开启状态的快捷商店用灰色显示 +* [x] 修复不能在背景/前景层绘图的Bug +* [x] 手机端的地图编辑器也能有报错信息了 +* [x] 部分其他细节优化 + ### 2018.10.31 V2.5 * [x] 添加绘图模式支持;可以用户手动绘图和保存 diff --git a/V2.0版本简易造塔流程(For新人).txt b/V2.0版本简易造塔流程(For新人).txt deleted file mode 100644 index 042e6517..00000000 --- a/V2.0版本简易造塔流程(For新人).txt +++ /dev/null @@ -1,78 +0,0 @@ -这只是一个最简单的造塔流程,更为详细的还是请参见视频或教程文档。 - -1. 打开启动服务,地图编辑器。 - -2. 切换到MT0层,然后开始绘制地图。可以在上面放置墙、门、道具或怪物等。 -如果提示“该素材未被定义”,请参见第7点。 -如果要从RMXP中复刻已有的塔的地图,请参见第11点。 - -3. 切换到楼层属性,一项一项仔细进行楼层属性的编辑,如楼层名,firstArrive等等。 -将鼠标移动到表格的中间可以查看详细信息。 -firstArrive为初次到达楼层的事件,可以双击进行事件的编辑。有关事件请详见文档。 - -3. 输入怪物数据:点击右边怪物,然后左边写怪物的攻防血等数值。 -将鼠标移动到表格的中间可以查看详细信息。 -如果是特殊属性怪物直接写特殊编号,多个特殊属性可以用 [1,2] 来表示。 - -4. 在中间的下拉框切换全塔属性,一项一项仔细进行根据需求编辑。 -请注意"name"一项必须修改为“字母、数字、下划线组成的字符串”,否则会出现串档问题。 -startText(初始剧情)、shops(全局商店)、levelUp(升级)等都是可以双击方框进行编辑的。 -有关全局商店和升级等信息详见 教程文档 - 事件 - -5. 给地图添加事件;可以给地图上的NPC增加事件,或者战斗/开门事件等。 -点击地图上的某个点,在左边进行编辑。 -event -- 该点的自定义事件(例如NPC,商店,等等) -changeFloor -- 该点的楼层传送事件(楼梯/传送门) -afterBattle -- 该点战斗后触发的战后事件 -afterOpenDoor -- 该点开门后触发的事件 -afterGetItem -- 该点获得道具后触发的事件 -等等。 -有关事件详细内容请参见 文档 - 事件。 - -6. 新建楼层:切换到地图编辑,然后在框内输入新楼层的floorId,点击新建地图即可保存。 -创建的floorId必须是字母、数字和下划线组成,且不能以数字开头。 -不能为空白,不能和任何已有楼层的floorId重复。 -保存成功后刷新页面。 - -删除楼层同理,不过请注意删除的会是当前的楼层而不是框中的内容。 - -7. 关于素材未被定义的问题:如果点击某个怪物或NPC提示该素材未被定义,请在左边进行素材的注册。 -输入该素材的唯一ID(不能和其他素材的ID重复),和素材的唯一数字(1000以内,不能和其他的数字重复), -保存并刷新,即注册成功。 - -8. 添加新素材:请打开启动服务的便捷PS工具,然后左边读取你要添加到的图片(比如怪物是enemys.png,道具是items.png), -右边读取你要导入的怪物素材,通过复制粘贴进行导入,再保存,刷新页面后按照第7点来进行素材的注册。 - -9. 道具的自定义效果:如果需要自定义道具效果,请仿照其他的几个道具来写,更多信息详见文档。 - -10. 报错处理:有时候刷新后可能页面变成空白,即无法正确加载。 -出现这种问题的原因往往是手动错误编辑了文件、新建楼层使用了不合法的floorId(比如中文或数字)、楼层floorId定义重复,等等。 - -出现这种问题,(在Chrome浏览器中)请按Ctrl+Shift+I打开控制台,找到Console查看报错。 -一般都会具体到哪个楼层文件出错。 - -解决方式:哪个楼层文件出错,请使用VSCode等打开project目录下的data.js文件,并将出错的那个楼层定义删除。 - -举例,比如我在新建地图中写了 “水潭边” 这样一个楼层名(中文),然后新建并保存,刷新会出错。 -此时,打开控制台(Ctrl+Shift+I的Console),并查看报错,发现是该楼层错误。 -那么打开data.js文件,并将 "floorIds": [..., "水潭边"] 这里对它的楼层定义删除,再刷新即可。 - -11. 从RMXP中导入已有的塔的地图。 -如果你想复刻老塔,则需使用启动服务的地图生成器。 -请确保老地图中的所有使用素材(地面/墙壁/门/道具/怪物等等)都已经被注册过(参见第7点)。 - -打开windows自带的截图工具,并对地图进行截图。 -截图时请注意:必须截刚好13x13范围大小的地图,尽量对其边缘进行截取。 -如果不是13x13的范围大小,可能会导致地图生成器无响应。 -截图完毕后,请复制到剪切板,然后在地图生成器中点加载图片。等1-2秒,就可以看到截图被识别。 -点“复制地图”,然后在地图编辑器中切换到“地图编辑”,并粘贴到左边的框内,即可。 -如果存在个别识别问题,可以对这个别素材再进行重新绘制。 - -如果出现大量识别问题,比如基本全是错的,则代表你的截图方式有问题。 -由于地图生成器的识别以左上角的图块为基准来找寻截图偏移量,请确保左上角一定要是一个能被很好识别的图块。 -建议:在RM的图层第三层,左上角放一个岩浆,再进行截图(保证截图的13x13的左上角是岩浆,从而可以确保定位), -识别后再复制到地图编辑器中进行绘制。 - --------------------------------- - -HTML5魔塔交流群:539113091,如果有问题请加群提问。 diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index add43d86..92c52eb2 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -192,6 +192,7 @@ action | show_s | hide_s | trigger_s + | insert_s | revisit_s | exit_s | setBlock_s @@ -238,6 +239,7 @@ action | win_s | lose_s | if_s + | switch_s | while_s | break_s | continue_s @@ -480,6 +482,20 @@ var code = '{"type": "trigger", "loc": ['+PosString_0+','+PosString_1+']},\n'; return code; */; +insert_s + : '插入事件' 'x' PosString ',' 'y' PosString '楼层' IdString? Newline + + +/* insert_s +tooltip : insert: 立即插入另一个地点的事件执行,当前事件不会中断,事件坐标不会改变 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=insert%ef%bc%9a%e6%8f%92%e5%85%a5%e5%8f%a6%e4%b8%80%e4%b8%aa%e5%9c%b0%e7%82%b9%e7%9a%84%e4%ba%8b%e4%bb%b6 +default : ["0","0",""] +colour : this.eventColor +IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); +var code = '{"type": "insert", "loc": ['+PosString_0+','+PosString_1+']'+IdString_0+'},\n'; +return code; +*/; + revisit_s : '重启当前事件' Newline @@ -1236,6 +1252,33 @@ var code = ['{"type": "if", "condition": "',expression_0,'",\n', return code; */; +switch_s + : '多重分歧 条件判定' ':' expression BGNL? Newline switchCase+ BEND Newline + + +/* switch_s +tooltip : switch: 多重条件分歧 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=switch%EF%BC%9A%E5%A4%9A%E9%87%8D%E6%9D%A1%E4%BB%B6%E5%88%86%E6%AD%A7 +default : ["判别值"] +colour : this.eventColor +var code = ['{"type": "switch", "condition": "',expression_0,'", "caseList": [\n', + switchCase_0, +'], },\n'].join(''); +return code; +*/; + +switchCase + : '如果是' expression '的场合' BGNL? Newline action+ + + +/* switchCase +tooltip : 选项的选择 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=switch%EF%BC%9A%E5%A4%9A%E9%87%8D%E6%9D%A1%E4%BB%B6%E5%88%86%E6%AD%A7 +colour : this.subColor +var code = '{"case": "'+expression_0+'", "action": [\n'+action_0+']},\n'; +return code; +*/; + choices_s : '选项' ':' EvalString? BGNL? '标题' EvalString? '图像' IdString? BGNL? Newline choicesContext+ BEND Newline @@ -1938,6 +1981,10 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['trigger_s'].xmlText([ data.loc[0],data.loc[1],this.next]); break; + case "insert": // 强制插入另一个点的事件在当前事件列表执行,当前坐标和楼层不会改变 + this.next = MotaActionBlocks['insert_s'].xmlText([ + data.loc[0],data.loc[1],data.floorId||'',this.next]); + break; case "playSound": this.next = MotaActionBlocks['playSound_s'].xmlText([ data.name,this.next]); @@ -1983,6 +2030,15 @@ ActionParser.prototype.parseAction = function() { this.insertActionList(data["false"]), this.next]); break; + case "switch": // 多重条件分歧 + var case_caseList = null; + for(var ii=data.caseList.length-1,caseNow;caseNow=data.caseList[ii];ii--) { + case_caseList=MotaActionBlocks['switchCase'].xmlText([ + this.isset(caseNow.case)?MotaActionBlocks['evalString_e'].xmlText([caseNow.case]):"值",this.insertActionList(caseNow.action),case_caseList]); + } + this.next = MotaActionBlocks['switch_s'].xmlText([ + MotaActionBlocks['evalString_e'].xmlText([data.condition]),case_caseList,this.next]); + break; case "choices": // 提供选项 var text_choices = null; for(var ii=data.choices.length-1,choice;choice=data.choices[ii];ii--) { diff --git a/_server/comment.js b/_server/comment.js index 0cfcfce0..7477667b 100644 --- a/_server/comment.js +++ b/_server/comment.js @@ -49,28 +49,35 @@ comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_type": "textarea", "_string": true, "_lint": true, - "_data": "cls为items的即捡即用类物品的效果。" + "_data": "即捡即用类物品的效果,仅对cls为items有效。" }, "itemEffectTip": { "_leaf": true, "_type": "textarea", "_string": true, "_lint": true, - "_data": "cls为items的即捡即用类物品,在获得时左上角额外显示的文字。" + "_data": "即捡即用类物品在获得时提示的文字,仅对cls为items有效。" }, "useItemEffect": { "_leaf": true, "_type": "textarea", "_string": true, "_lint": true, - "_data": "cls为tools或constants时的使用物品效果。" + "_data": "道具效果,仅对cls为tools或constants有效。" }, "canUseItemEffect": { "_leaf": true, "_type": "textarea", "_string": true, "_lint": true, - "_data": "cls为tools或constants时对当前能否使用该物品的判断。" + "_data": "当前能否使用该道具,仅对cls为tools或constants有效。" + }, + "canEquip":{ + "_leaf": true, + "_type": "textarea", + "_string": true, + "_lint": true, + "_data": "当前能否装备某个装备,仅对cls为equips有效。\n与canUseItemEffect不同,这里null代表可以装备。" } } }, @@ -119,54 +126,54 @@ comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_leaf": true, "_type": "textarea", "_range": "thiseval==null || thiseval instanceof Array || (thiseval==~~thiseval && thiseval>=0)", - "_data": "特殊属性\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:重生,24:激光\n\n多个属性例如用[1,4,11]表示先攻2连击吸血\n模仿怪的攻防设为0就好" + "_data": "特殊属性\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:重生,24:激光,25:光环\n\n多个属性例如用[1,4,11]表示先攻2连击吸血" }, "value": { "_leaf": true, "_type": "textarea", - "_data": "特殊属性的数值\n领域怪需要加value表示领域伤害的数值\n吸血怪需要在后面添加value代表吸血比例" + "_data": "特殊属性的数值\n如:领域/阻激/激光怪的伤害值;吸血怪的吸血比例;光环怪增加生命的比例" }, "zoneSquare": { "_leaf": true, "_type": "checkbox", "_bool": "bool", - "_data": "领域怪zoneSquare代表是否九宫格伤害" + "_data": "领域怪是否九宫格伤害" }, "range": { "_leaf": true, "_type": "textarea", "_range": "(thiseval==~~thiseval && thiseval>0)||thiseval==null", - "_data": "range可选,代表领域伤害的范围;不加默认为1" + "_data": "领域伤害的范围;不加默认为1" }, "notBomb": { "_leaf": true, "_type": "checkbox", "_bool": "bool", - "_data": "加入 \"notBomb\": true 代表该怪物不可被炸弹或圣锤炸掉" + "_data": "该怪物不可被炸" }, "n": { "_leaf": true, "_type": "textarea", "_range": "(thiseval==~~thiseval && thiseval>0)||thiseval==null", - "_data": "多连击需要在后面指定n代表是几连击" + "_data": "多连击的连击数" }, "add": { "_leaf": true, "_type": "checkbox", "_bool": "bool", - "_data": "代表吸血后是否加到自身" + "_data": "吸血后是否加到自身;光环是否叠加" }, "atkValue": { "_leaf": true, "_type": "textarea", "_range": "thiseval==~~thiseval||thiseval==null", - "_data": "退化时勇士下降的攻击力点数" + "_data": "退化时勇士下降的攻击力点数;光环怪增加攻击的比例" }, "defValue": { "_leaf": true, "_type": "textarea", "_range": "thiseval==~~thiseval||thiseval==null", - "_data": "退化时勇士下降的防御力点数" + "_data": "退化时勇士下降的防御力点数;光环怪增加防御的比例" }, "damage": { "_leaf": true, diff --git a/_server/data.comment.js b/_server/data.comment.js index af1c0b4b..6d277522 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -424,6 +424,12 @@ data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_bool": "bool", "_data": "是否允许等级提升(进阶);如果上面enableExperience为false,则此项恒视为false" }, + "levelUpLeftMode": { + "_leaf": true, + "_type": "checkbox", + "_bool": "bool", + "_data": "进阶使用扣除模式,即在状态栏显示距离下个等级所需要的经验值;只有enableExperience和enableLevelUp均开启时才有效。" + }, "enableKeys": { "_leaf": true, "_type": "checkbox", @@ -612,6 +618,12 @@ data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_bool": "bool", "_data": "是否允许查看未开启状态的快捷商店内容;如果此项为真,则对于未开启状态的商店允许查看其内容(但不能购买)" }, + "disableShopOnDamage": { + "_leaf": true, + "_type": "checkbox", + "_bool": "bool", + "_data": "是否在经过领域/夹击/路障等伤害后禁用快捷商店。" + } } } } diff --git a/_server/editor.js b/_server/editor.js index 63ca9f47..7b418d1d 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -3,6 +3,30 @@ function editor() { this.brushMod = "line";//["line","rectangle","tileset"] this.layerMod = "map";//["fgmap","map","bgmap"] this.isMobile = false; + + window.onerror = function (msg, url, lineNo, columnNo, error) { + var string = msg.toLowerCase(); + var substring = "script error"; + var message; + if (string.indexOf(substring) > -1){ + message = 'Script Error: See Browser Console for Detail'; + } else { + message = [ + 'Message: ' + msg, + 'URL: ' + url, + 'Line: ' + lineNo, + 'Column: ' + columnNo, + 'Error object: ' + JSON.stringify(error) + ].join(' - '); + // alert(message); + } + try { + printe(message) + } catch (e) { + alert(message); + } + return false; + }; } /* @@ -1079,19 +1103,33 @@ editor.prototype.listen = function () { editor.brushMod=brushMod3.value; } + var bgc = document.getElementById('bg'), fgc = document.getElementById('fg'), + evc = document.getElementById('event'), ev2c = document.getElementById('event2'); + var layerMod=document.getElementById('layerMod'); layerMod.onchange=function(){ editor.layerMod=layerMod.value; + [bgc,fgc,evc,ev2c].forEach(function (x) { + x.style.opacity = 1; + }); } var layerMod2=document.getElementById('layerMod2'); if(layerMod2)layerMod2.onchange=function(){ editor.layerMod=layerMod2.value; + [fgc,evc,ev2c].forEach(function (x) { + x.style.opacity = 0.3; + }); + bgc.style.opacity = 1; } var layerMod3=document.getElementById('layerMod3'); if(layerMod3)layerMod3.onchange=function(){ editor.layerMod=layerMod3.value; + [bgc,evc,ev2c].forEach(function (x) { + x.style.opacity = 0.3; + }); + fgc.style.opacity = 1; } var viewportButtons=document.getElementById('viewportButtons'); diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 1c4b538b..1c1c2f21 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -108,6 +108,11 @@ editor_blockly = function () { ], '事件控制':[ MotaActionBlocks['if_s'].xmlText(), + MotaActionFunctions.actionParser.parseList({"type": "switch", "condition": "判别值", "caseList": [ + {"action": [{"type": "comment", "text": "当判别值是值的场合执行此事件"}]}, + {"action": []}, + {"case": "default", "action": [{"type": "comment", "text": "当没有符合的值的场合执行default事件"}]}, + ]}), MotaActionBlocks['while_s'].xmlText(), MotaActionBlocks['break_s'].xmlText(), MotaActionBlocks['continue_s'].xmlText(), @@ -121,6 +126,7 @@ editor_blockly = function () { MotaActionBlocks['hideBgFgMap_s'].xmlText(), MotaActionBlocks['setBgFgBlock_s'].xmlText(), MotaActionBlocks['trigger_s'].xmlText(), + MotaActionBlocks['insert_s'].xmlText(), MotaActionBlocks['move_s'].xmlText(), MotaActionBlocks['jump_s'].xmlText(), MotaActionBlocks['disableShop_s'].xmlText(), @@ -415,7 +421,7 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ var type = args.type; if (!type) return false; editor_blockly.id = id_; - codeAreaHL.setValue(input.value); + codeAreaHL.setValue(input.value.replace(/\\r/g,'\\\\r')); document.getElementById('entryType').value = type; editor_blockly.parse(); editor_blockly.show(); diff --git a/_server/editor_mode.js b/_server/editor_mode.js index cc0022cc..3dd40ece 100644 --- a/_server/editor_mode.js +++ b/_server/editor_mode.js @@ -556,6 +556,90 @@ editor_mode = function (editor) { } selectAppend.onchange(); + var getPixel=function(imgData, x, y) { + var offset = (x + y * imgData.width) * 4; + var r = imgData.data[offset+0]; + var g = imgData.data[offset+1]; + var b = imgData.data[offset+2]; + var a = imgData.data[offset+3]; + return [r,g,b,a]; + } + var setPixel=function(imgData, x, y, rgba) { + var offset = (x + y * imgData.width) * 4; + imgData.data[offset+0]=rgba[0]; + imgData.data[offset+1]=rgba[1]; + imgData.data[offset+2]=rgba[2]; + imgData.data[offset+3]=rgba[3]; + } + + var autoAdjust = function (image, callback) { + var changed = false; + + // Step 1: 检测白底 + var tempCanvas = document.createElement('canvas').getContext('2d'); + tempCanvas.canvas.width = image.width; + tempCanvas.canvas.height = image.height; + tempCanvas.mozImageSmoothingEnabled = false; + tempCanvas.webkitImageSmoothingEnabled = false; + tempCanvas.msImageSmoothingEnabled = false; + tempCanvas.imageSmoothingEnabled = false; + tempCanvas.drawImage(image, 0, 0); + var imgData = tempCanvas.getImageData(0, 0, image.width, image.height); + var trans = 0, white = 0; + for (var i=0;itrans*10 && confirm("看起来这张图片是以白色为底色,是否自动调整为透明底色?")) { + for (var i=0;i 目前版本**v2.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.1**,上次更新时间:* {docsify-updated} * 目前样板已经更新到V2.0版本以上,本章将对V2.0的一些内容进行介绍。 diff --git a/docs/api.md b/docs/api.md index 03a5d666..17d3b1df 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,6 +1,6 @@ # 附录: API列表 -?> 目前版本**v2.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.1**,上次更新时间:* {docsify-updated} * **这里只列出所有可能会被造塔者用到的常用API,更多的有关内容请在代码内进行查询。** diff --git a/docs/element.md b/docs/element.md index 087937c0..1d9becba 100644 --- a/docs/element.md +++ b/docs/element.md @@ -1,6 +1,6 @@ # 元件说明 -?> 目前版本**v2.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.1**,上次更新时间:* {docsify-updated} * 在本章中,将对样板里的各个元件进行说明。各个元件主要包括道具、门、怪物、楼梯等等。 @@ -262,6 +262,17 @@ floorId指定的是目标楼层的唯一标识符(ID)。 **从2.1.1开始,楼层属性中提供了`upFloor`和`downFloor`两项。如果设置此项(比如`"upFloor": [2,3]`),则写stair:upFloor或者楼传器的落点将用此点来替换楼梯位置(即类似于RM中的上箭头)。** +## 剧情文本控制 + +在写剧情文本时,可以: + +- 使用`\t[...]`来给文字加上标题和图标。如`\t[老人,man]`。 +- 使用`\b[...]`来制作对话框效果,如`\b[up,3,2]`。 +- 使用`\r[...]`来动态修改局部文本的颜色,如`\r[red]`。 +- 使用`${}`来计算一个表达式的值,如`${status:atk+status:def}`。 + +详细信息请参见[剧情文本控制](event#text:显示一段文字(剧情))中的说明。 + ## 大地图 从V2.4开始,H5魔塔开始支持大地图。 diff --git a/docs/event.md b/docs/event.md index 915ca3a8..12b2aacb 100644 --- a/docs/event.md +++ b/docs/event.md @@ -1,6 +1,6 @@ # 事件 -?> 目前版本**v2.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.1**,上次更新时间:* {docsify-updated} * 本章内将对样板所支持的事件进行介绍。 @@ -237,6 +237,15 @@ !> `\t[...]`必须在`\b[...]`前面!不然两者都无法正常显示。 +还可以使用`\r[...]`来调整剧情文本的颜色。 + +``` js +"x,y": [ // 实际执行的事件列表 + "这句话是默认颜色,\r[red]将颜色变成红色,\r[blue]将颜色变成蓝色", + "\r[#FF00FF]还可以使用RGB值来控制颜色,\r如果不加中括号则回到默认颜色", + "\t[hero]\b[up,hero]啊啊啊,别过来,\r[red]别过来!!!\n\r你到底是什么东西!" +] +``` 另外值得一提的是,我们是可以在文字中计算一个表达式的值的。只需要将表达式用 `${ }`整个括起来就可以。 @@ -468,6 +477,32 @@ NPC对话事件结束后如果需要NPC消失也需要调用 `{"type": "hide"}` 例如上面这个例子,下面的文字将不会再被显示,而是直接跳转到`"3,6"`对应的事件列表从头执行。 +### insert:插入另一个地点的事件 + +`{"type":"insert"}` 会插入另一个地点的事件执行。 + +其基本写法如下: + +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "insert", "loc": [3,6]}, // 插入[3,6]点的事件并执行 + {"type": "insert", "loc": [10,10], "floorId": "MT1"}, // 插入MT1层[10,10]点的事件并执行 + "上面的插入事件执行完毕后会接着继续执行后面的事件" +] +``` + +loc是必须的,代表另一个地点的坐标。 + +floorId可选,代表另一个地点所在的楼层;如果不写则默认为当前层。 + +和`type:trigger`不同的是,**`type:trigger`是立刻将当前事件结束(剩下所有内容都忽略),然后重新启动另一个地点的action事件。** + +但是`type:insert`不会结束当前事件,而是直接将另一个地点的事件列表“插入”到当前事件列表中执行。 + +**这个过程中,当前事件不会被结束,当前的楼层和事件坐标不会发生改变。** 插入的事件执行完毕后,会继续执行接下来的内容。 + +我们某个事件写在某个角落的墙上然后远程调用,从而达到“公共事件”的效果。 + ### revisit:立即重启当前事件 revisit和trigger完全相同,只不过是立刻触发的还是本地点的事件 @@ -1190,6 +1225,70 @@ text为提示文字,可以在这里给输入提示文字。这里同样可以 - if可以不断进行嵌套,一层套一层;如成立的场合再进行另一个if判断等。 - if语句内的内容执行完毕后将接着其后面的语句继续执行。 + +### switch:多重条件分歧 + +使用`{"type": "switch"}`可以比较判别值和不同分支的条件,根据判断结果选择不同的分支执行。 + +其大致写法如下: + +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "switch", "condition": "...", // 计算某个表达式 + "caseList": [ + {"case": "a", "action": [// 若表达式的值等于a则执行该处事件 + + ], + {"case": "b", "action": [// 若表达式的值等于b则执行该处事件 + + ], + {"case": "default", "action": [ // 没有条件成立则执行该处里的事件 + + ] + ] + }, +] +``` + +我们可以在condition中给出一个表达式(能将`status:xxx`, `item:xxx`, `flag:xxx`来作为参数),并计算它的值 + +如果某条件中的值与其相等,则将执行其对应的列表事件内容。 + +如果没有符合的值,则将执行`default`中的列表事件内容。 + +例如下面这个例子,将检查当前游戏难度并赠送不同属性。 + +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "switch", "condition": "flag:hard", // 判断当前游戏难度 + "caseList": [ + {"case": "0", "action": [// 若表达式的值等于0则执行该处事件 + "当前为简单难度,赠送100点攻防!", + {"type": "setValue", "name": "status:atk", "value": "status:atk+100"}, + {"type": "setValue", "name": "status:def", "value": "status:def+100"}, + ], + {"case": "1", "action": [// 若表达式的值等于1则执行该处事件 + "当前为普通难度,赠送50点攻防!", + {"type": "setValue", "name": "status:atk", "value": "status:atk+50"}, + {"type": "setValue", "name": "status:def", "value": "status:def+50"}, + ], + {"case": "default", "action": [ // 其他难度下不赠送属性 + + ] + ] + }, +] +``` + +需要额外注意的几点: + +- 各个条件分支的判断是顺序执行的,因此若多个分支的条件都满足,将只执行最靠前的分支,同理,请不要在`default`分支后添加分支,这些分支将不可能被执行。 +- `default`分支并不是必要的,如果删除,则在没有满足条件的分支时将不执行任何事件。 +- 即使某个场合不执行事件,对应的action数组也需要存在,不过简单的留空就好。 +- switch可以不断进行嵌套,一层套一层;如某条件成立的场合再进行另一个switch判断等。 +- switch语句内的内容执行完毕后将接着其后面的语句继续执行。 + + ### choices:给用户提供选项 choices是一个很麻烦的事件,它将弹出一个列表供用户进行选择。 diff --git a/docs/index.md b/docs/index.md index 842078dd..492288f6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,6 @@ # HTML5 魔塔样板说明文档 -?> 目前版本**v2.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.1**,上次更新时间:* {docsify-updated} * 众所周知,魔塔的趋势是向移动端发展,贴吧中也常常能见到“求手机魔塔”的帖子。然而现有的工具中,NekoRPG有着比较大的局限性,游戏感较差,更是完全没法在iOS上运行。而一些APP的魔塔虽然可用,但是必须要下载安装,对于Android和iOS还必须开发不同的版本,非常麻烦。 diff --git a/docs/personalization.md b/docs/personalization.md index 5d4211f3..2fbf4cd4 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -1,6 +1,6 @@ # 个性化 -?> 目前版本**v2.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.1**,上次更新时间:* {docsify-updated} * 有时候只靠样板本身可能是不够的。我们需要一些个性化、自定义的素材,道具效果,怪物属性,等等。 @@ -521,6 +521,15 @@ case 89: // 使用该按键的keyCode,比如Y键就是89 ## 公共事件 +从2.5.1开始,H5提供了`{"type":"insert"}`事件,完美支持了公共事件的写法。 + +我们只需要将需要的公共事件放在某个角落的墙上(或者甚至单独弄一层专门摆放公共事件),并使用“插入事件”,即可进行调用。 + +具体详见[插入另一个地点的事件](event#insert:插入另一个地点的事件)。 + +当然,继续使用**插件**的写法也是可以的。具体参见“脚本编辑 - 插件编写”。 + + ## 自定义状态栏(新增显示项) 在V2.2以后,我们可以自定义状态栏背景图(全塔属性 - statusLeftBackground)等等。 -但是,如果我们还想新增其他项目的显示,比如技能塔所需要的魔力值(气息),该怎么办? +但是,如果我们还想新增其他项目的显示,比如攻速或者暴击,该怎么办? 需要进行如下几个操作: -1. 定义图标ID;比如魔力我就定义mana,气息可以简单的定义qixi;你也可以定义其他的ID,但是不能和已有的重复。这里以mana为例。 +1. 定义ID;比如攻速我就定义speed,暴击可以简单的定义baoji;你也可以定义其他的ID,但是不能和已有的重复。这里以speed为例。 2. 在index.html的statusBar中(44行起),进行该状态栏项的定义。仿照其他几项,插在其应当显示的位置,注意替换掉相应的ID。 ``` html -
- -

+
+ +

``` -3. 在editor.html中的statusBar(317行起),仿照第二点同样添加;这一项如果不进行则会地图编辑器报错。editor-mobile.html同理。 -4. 使用便捷PS工具,打开icons.png,新增一行并将魔力的图标P上去;记下其索引比如24(从0开始数)。 +3. 在editor.html中的statusBar(323行起),仿照第二点同样添加;这一项如果不进行则会地图编辑器报错。editor-mobile.html同理。 +4. 使用便捷PS工具,打开icons.png,新增一行并将魔力的图标P上去;记下其索引比如30(从0开始数)。 5. 在main.js的this.statusBar中增加图片、图标和内容的定义。 ``` js this.statusBar = { 'images': { // ...其他略 - 'mana': document.getElementById("img-mana"), // 图片的定义 + 'speed': document.getElementById("img-speed"), // 图片的定义 }, 'icons': { // ...其他略 - 'mana': 24, // 图标的定义,这里对应的是icons.png中的索引 + 'speed': 24, // 图标的定义,这里对应的是icons.png中的索引 }, // ...其他略 - 'mana': document.getElementById('mana'), // 显示内容(数据)的定义 + 'speed': document.getElementById('speed'), // 显示内容(数据)的定义 } ``` 6. 显示内容的设置。在脚本编辑的updateStatusBar函数,可以对该状态栏显示内容进行设置,下面是几个例子。 ``` js -core.statusBar.mana.innerHTML = core.getFlag('mana', 0); // 设置其显示内容为flag:mana值。 -core.statusBar.mana.innerHTML = core.getFlag('mana', 0) + '/' + core.getFlag('manaMax', 0); // 显示内容将类似 "32/60" 这样。 -core.statusBar.mana.style.fontStyle = 'normal'; // 这一行会取消斜体。如果是汉字(比如技能名)的话,斜体起来会非常难看,可以通过这一句取消。 +// 设置其显示内容为status:speed值;需要在project/data.js中firstData的hero那里新增初始值`"speed": 0`。 +core.statusBar.speed.innerHTML = core.getStatus('speed'); +// 设置其显示内容为flag:speed值,无需额外进行定义。 +core.statusBar.speed.innerHTML = core.getFlag('speed', 0); ``` ---> - ## 技能塔的支持 其实,在HTML5上制作技能塔是完全可行的。 diff --git a/docs/start.md b/docs/start.md index ac2bc064..ec55095d 100644 --- a/docs/start.md +++ b/docs/start.md @@ -1,6 +1,6 @@ # 快速上手 -?> 目前版本**v2.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.1**,上次更新时间:* {docsify-updated} * 在这一节中,将详细介绍做一部塔的流程。现在,让我们来做一部单层塔! diff --git a/libs/actions.js b/libs/actions.js index d43972f8..6275251b 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -767,6 +767,12 @@ actions.prototype.clickAction = function (x,y) { ////// 自定义事件时,按下某个键的操作 ////// actions.prototype.keyDownAction = function (keycode) { + // 视为无效 + var startTime = core.status.event.data.startTime||0; + if (startTime>0 && new Date().getTime()-startTime<250) + return; + core.status.event.data.startTime = 0; + if (core.status.event.data.type=='choices') { var data = core.status.event.data.current; var choices = data.choices; @@ -809,6 +815,15 @@ actions.prototype.keyUpAction = function (keycode) { core.insertAction(choices[core.status.event.selection].action); core.doAction(); } + // 数字键快速选择 + if (keycode>=49 && keycode<=57) { + var index = keycode-49; + if (index=2 && x<=10 && y<=1 && mh>13) { core.ui.drawMaps(index, cx, cy-1); @@ -1002,6 +1027,11 @@ actions.prototype.keyUpViewMaps = function (keycode) { core.ui.drawMaps(core.status.event.data); return; } + if (keycode==90) { + core.status.event.data.all = !core.status.event.data.all; + core.ui.drawMaps(core.status.event.data); + return; + } if (keycode==77) { core.status.event.data.paint = !core.status.event.data.paint; core.ui.drawMaps(core.status.event.data); @@ -1122,6 +1152,14 @@ actions.prototype.keyUpShop = function (keycode) { var topIndex = 6 - parseInt(choices.length / 2); this.clickShop(6, topIndex+core.status.event.selection); } + // 数字键快速选择 + if (keycode>=49 && keycode<=57) { + var index = keycode-49; + if (index<=choices.length) { + var topIndex = 6 - parseInt(choices.length / 2); + this.clickShop(6, topIndex+index); + } + } return; } @@ -1169,6 +1207,13 @@ actions.prototype.keyUpQuickShop = function (keycode) { var topIndex = 6 - parseInt(keys.length / 2); this.clickQuickShop(6, topIndex+core.status.event.selection); } + if (keycode>=49 && keycode<=57) { + var index = keycode-49; + if (index<=keys.length) { + var topIndex = 6 - parseInt(keys.length / 2); + this.clickQuickShop(6, topIndex+index); + } + } return; } @@ -1774,10 +1819,16 @@ actions.prototype.clickSwitchs = function (x,y) { core.ui.drawSwitchs(); break; case 8: - window.open(core.platform.isPC?"editor.html":"editor-mobile.html", "_blank"); + if (core.platform.isPC) + window.open("editor.html", "_blank"); + else + window.location.href = "editor-mobile.html"; break; case 9: - window.open(core.firstData.name+".zip", "_blank"); + if (core.platform.isPC) + window.open(core.firstData.name+".zip"); + else + window.location.href = core.firstData.name+".zip"; break; case 10: core.status.event.selection=0; @@ -1811,6 +1862,14 @@ actions.prototype.keyUpSwitchs = function (keycode) { var topIndex = 6 - parseInt((choices.length - 1) / 2); this.clickSwitchs(6, topIndex+core.status.event.selection); } + // 数字键快速选择 + if (keycode>=49 && keycode<=57) { + var index = keycode-49; + if (index=49 && keycode<=57) { + var index = keycode-49; + if (index=49 && keycode<=57) { + var index = keycode-49; + if (index=49 && keycode<=57) { + var index = keycode-49; + if (index=49 && keycode<=57) { + var index = keycode-49; + if (index=49 && keycode<=57) { + var index = keycode-49; + if (index=49 && keycode<=57) { + var index = keycode-49; + if (index0) { core.playSound('zone.mp3'); core.drawAnimate("zone", x, y); + + // 禁用快捷商店 + if (core.flags.disableShopOnDamage) { + for (var shopId in core.status.shops) { + core.status.shops[shopId].visited = false; + } + } + } core.status.hero.statistics.extraDamage += damage; @@ -1511,7 +1519,9 @@ control.prototype.updateDamage = function (floorId, canvas) { core.clearMap('damage'); } - // if (!core.isset(core.status.thisMap) || !core.isset(core.status.thisMap.blocks)) return; + // 正在开始游戏中 + if (core.status.isStarting) return; + // 更新显伤 var mapBlocks = core.status.maps[floorId].blocks; // 没有怪物手册 @@ -1526,15 +1536,9 @@ control.prototype.updateDamage = function (floorId, canvas) { if (core.isset(mapBlocks[b].event) && mapBlocks[b].event.cls.indexOf('enemy')==0 && !mapBlocks[b].disable) { - // 非系统默认的战斗事件(被覆盖) - if (mapBlocks[b].event.trigger != 'battle') { - // 判断显伤 - var event = core.floors[floorId].events[x+","+y]; - if (core.isset(event) && !(event instanceof Array)) { - if (event.displayDamage === false) - continue; - } - } + // 判定是否显伤 + if (mapBlocks[b].event.displayDamage === false) + continue; var id = mapBlocks[b].event.id; @@ -1590,7 +1594,7 @@ control.prototype.updateDamage = function (floorId, canvas) { } } // 如果是领域&夹击 - if (core.flags.displayExtraDamage) { + if (core.flags.displayExtraDamage && core.isset((core.status.checkBlock||{}).damage)) { canvas.textAlign = 'center'; // 临时改变 @@ -1913,7 +1917,7 @@ control.prototype.replay = function () { core.status.event.data = {"toolsPage":Math.floor(index/12)+1, "constantsPage":1, "selectId":null}; index = index%12; } - else if (index=constants.indexOf(itemId)>=0) { + else if ((index=constants.indexOf(itemId))>=0) { core.status.event.data = {"toolsPage":1, "constantsPage":Math.floor(index/12)+1, "selectId":null}; index = index%12+12; } @@ -2246,7 +2250,7 @@ control.prototype.doSL = function (id, type) { if (data.version != core.firstData.version) { // core.drawTip("存档版本不匹配"); if (confirm("存档版本不匹配!\n你想回放此存档的录像吗?\n可以随时停止录像播放以继续游戏。")) { - core.startGame(data.hard, data.hero.flags.seed, core.decodeRoute(data.route)); + core.startGame(data.hard, data.hero.flags.__seed__, core.decodeRoute(data.route)); } return; } @@ -2285,7 +2289,7 @@ control.prototype.doSL = function (id, type) { return; } var route = core.subarray(core.status.route, core.decodeRoute(data.route)); - if (!core.isset(route) || data.hero.flags.seed!=core.getFlag('seed')) { + if (!core.isset(route) || data.hero.flags.__seed__!=core.getFlag('__seed__')) { core.drawTip("无法从此存档回放录像"); return; } @@ -2778,6 +2782,7 @@ control.prototype.resize = function(clientWidth, clientHeight) { if (!core.flags.enableMoney) count--; if (!core.flags.enableExperience) count--; if (!core.flags.enableLevelUp) count--; + if (core.flags.levelUpLeftMode) count--; if (!core.flags.enableDebuff) count--; if (!core.flags.enableKeys) count--; if (!core.flags.enablePZF) count--; @@ -2785,6 +2790,8 @@ control.prototype.resize = function(clientWidth, clientHeight) { if (!core.flags.enableMana) count--; if (!core.flags.enableSkill) count--; + if (count>12) alert("当前状态栏数目("+count+")大于12,请调整到不超过12以避免手机端出现显示问题。"); + var statusLineHeight = BASE_LINEHEIGHT * 9 / count; var statusLineFontSize = DEFAULT_FONT_SIZE; if (count>9) statusLineFontSize = statusLineFontSize * 9 / count; @@ -3084,7 +3091,7 @@ control.prototype.resize = function(clientWidth, clientHeight) { { id: 'expCol', rules: { - display: core.flags.enableExperience ? 'block': 'none' + display: core.flags.enableExperience && !core.flags.levelUpLeftMode ? 'block': 'none' } }, { diff --git a/libs/core.js b/libs/core.js index 35186832..de889da3 100644 --- a/libs/core.js +++ b/libs/core.js @@ -148,7 +148,7 @@ function core() { }, 'textAttribute': { 'position': "center", - "offset": 20, + "offset": 0, "title": [255,215,0,1], "background": [0,0,0,0.85], "text": [255,255,255,1], @@ -183,6 +183,8 @@ core.prototype.init = function (coreData, callback) { if (!core.flags.enableExperience) core.flags.enableLevelUp = false; + if (!core.flags.enableLevelUp) + core.flags.levelUpLeftMode = false; if (!core.flags.canOpenBattleAnimate) { core.flags.showBattleAnimateConfirm = false; core.flags.battleAnimate = false; @@ -201,6 +203,11 @@ core.prototype.init = function (coreData, callback) { document.getElementById("startLogo").innerHTML = core.firstData.title; core.material.items = core.clone(core.items.getItems()); core.material.enemys = core.clone(core.enemys.getEnemys()); + if (main.mode == 'play') { + for (var enemyId in core.material.enemys) { + core.material.enemys[enemyId].id = enemyId; + } + } core.material.icons = core.icons.getIcons(); core.material.events = core.events.getEvents(); diff --git a/libs/enemys.js b/libs/enemys.js index c6350103..7f87fc4e 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -260,22 +260,17 @@ enemys.prototype.getCurrentEnemys = function (floorId) { var critical = this.nextCriticals(enemyId); if (critical.length>0) critical=critical[0]; - enemys.push({ - 'id': enemyId, - 'name': enemy.name, - 'hp': enemyInfo.hp, - 'atk': enemyInfo.atk, - 'def': enemyInfo.def, - 'money': enemyInfo.money||0, - 'experience': enemyInfo.experience||0, - 'point': enemyInfo.point||0, // 加点 - 'special': specialText, - 'damage': this.getDamage(enemyId,null,null,floorId), - 'critical': critical[0], - 'criticalDamage': critical[1], - 'defDamage': this.getDefDamage(enemyId,1,null,null,floorId) - }); - + var e = core.clone(enemy); + for (var x in enemyInfo) { + e[x] = enemyInfo[x]; + } + e.id = enemyId; + e.specialText = specialText; + e.damage = this.getDamage(enemyId, null, null, floorId); + e.critical = critical[0]; + e.criticalDamage = critical[1]; + e.defDamage = this.getDefDamage(enemyId,1,null,null,floorId); + enemys.push(e); used[enemyId] = true; } } diff --git a/libs/events.js b/libs/events.js index 220b6ba8..72d6eacd 100644 --- a/libs/events.js +++ b/libs/events.js @@ -88,8 +88,8 @@ events.prototype.startGame = function (hard, seed, route, callback) { core.status.isStarting = true; if (core.isset(seed)) { - core.setFlag('seed', seed); - core.setFlag('rand', seed); + core.setFlag('__seed__', seed); + core.setFlag('__rand__', seed); } else core.utils.__init_seed(); @@ -195,7 +195,7 @@ events.prototype.gameOver = function (ending, fromReplay, norank) { 'name': core.firstData.name, 'version': core.firstData.version, 'hard': core.status.hard, - 'seed': core.getFlag('seed'), + 'seed': core.getFlag('__seed__'), 'route': core.encodeRoute(core.status.route) } core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5route", JSON.stringify(obj)); @@ -238,7 +238,7 @@ events.prototype.gameOver = function (ending, fromReplay, norank) { formData.append('experience', core.status.hero.experience); formData.append('steps', core.status.hero.steps); formData.append('norank', norank||0); - formData.append('seed', core.getFlag('seed')); + formData.append('seed', core.getFlag('__seed__')); formData.append('totalTime', Math.floor(core.status.hero.statistics.totalTime/1000)); formData.append('route', core.encodeRoute(core.status.route)); formData.append('base64', 1); @@ -316,7 +316,7 @@ events.prototype.doEvents = function (list, x, y, callback) { core.status.event = {'id': 'action', 'data': { 'list': [ {"todo": core.clone(list), "total": core.clone(list), "condition": "false"} - ], 'x': x, 'y': y, 'callback': callback + ], 'x': x, 'y': y, 'callback': callback, 'startTime': new Date().getTime() }} // 停止勇士 @@ -702,12 +702,12 @@ events.prototype.doAction = function() { case "setFg": // 颜色渐变 if (data.async) { core.setFg(data.color, data.time); - core.setFlag('color', data.color||null); + core.setFlag('__color__', data.color||null); this.doAction(); } else { core.setFg(data.color, data.time, function() { - core.setFlag('color', data.color||null); + core.setFlag('__color__', data.color||null); core.events.doAction(); }); } @@ -715,8 +715,8 @@ events.prototype.doAction = function() { case "setWeather": // 更改天气 core.setWeather(data.name, data.level); if (core.isset(data.name)) - core.setFlag('weather', [data.name, data.level]); - else core.setFlag('weather', null); + core.setFlag('__weather__', [data.name, data.level]); + else core.setFlag('__weather__', null); this.doAction(); break; case "openDoor": // 开一个门,包括暗墙 @@ -774,6 +774,15 @@ events.prototype.doAction = function() { this.doAction(); break; } + case "insert": + { + var toX=core.calValue(data.loc[0]), toY=core.calValue(data.loc[1]); + var floorId = data.floorId || core.status.floorId; + var event = core.floors[floorId].events[toX+","+toY]; + if (core.isset(event)) core.insertAction(event); + this.doAction(); + break; + } case "playSound": if (!core.status.replay.replaying) core.playSound(data.name); @@ -810,7 +819,7 @@ events.prototype.doAction = function() { var value=core.calValue(data.value); // 属性 if (data.name.indexOf("status:")==0) { - value=parseFloat(value); + // value=parseFloat(value); core.setStatus(data.name.substring(7), value); } // 道具 @@ -907,6 +916,16 @@ events.prototype.doAction = function() { core.events.insertAction(data["false"]) this.doAction(); break; + case "switch": // 条件选择 + var key = core.calValue(data.condition) + for (var i = 0; i < data.caseList.length; i++) { + if (data.caseList[i].case=="default" || core.calValue(data.caseList[i].case) == key) { + core.events.insertAction(data.caseList[i].action); + break; + } + } + this.doAction(); + break; case "choices": // 提供选项 if (core.status.replay.replaying) { if (core.status.replay.toReplay.length==0) { // 回放完毕 @@ -1326,7 +1345,7 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback } // 不存在事件时,更改画面色调 - var color = core.getFlag('color', null); + var color = core.getFlag('__color__', null); if (!core.isset(color) && core.isset(core.status.maps[floorId].color)) { color = core.status.maps[floorId].color; } @@ -1346,7 +1365,7 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback } // 更改天气 - var weather = core.getFlag('weather', null); + var weather = core.getFlag('__weather__', null); if (!core.isset(weather) && core.isset(core.status.maps[floorId].weather)) { weather = core.status.maps[floorId].weather; } @@ -1631,8 +1650,8 @@ events.prototype.openShop = function(shopId, needVisited) { var choice = shop.choices[i]; var text = choice.text; if (core.isset(choice.need)) - text += "("+eval(choice.need)+use+")" - choices.push(text); + text += "("+eval(choice.need)+use+")"; + choices.push({"text": text, "color":shop.visited?null:"#999999"}); } choices.push("离开"); core.ui.drawChoices(content, choices); @@ -1902,7 +1921,7 @@ events.prototype.uploadCurrent = function (username) { formData.append('money', core.status.hero.money); formData.append('experience', core.status.hero.experience); formData.append('steps', core.status.hero.steps); - formData.append('seed', core.getFlag('seed')); + formData.append('seed', core.getFlag('__seed__')); formData.append('totalTime', Math.floor(core.status.hero.statistics.totalTime/1000)); formData.append('route', core.encodeRoute(core.status.route)); formData.append('deler', 'current'); diff --git a/libs/items.js b/libs/items.js index a576179e..bf20d5bb 100644 --- a/libs/items.js +++ b/libs/items.js @@ -9,6 +9,10 @@ items.prototype.init = function () { this.itemEffectTip = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.itemEffectTip; this.useItemEffect = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.useItemEffect; this.canUseItemEffect = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.canUseItemEffect; + if (!core.isset(items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.canEquip)) + items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.canEquip = {}; + this.canEquip = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.canEquip; + //delete(items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a); } @@ -162,13 +166,21 @@ items.prototype.loadEquip = function (equipId, callback) { if (!core.isset(core.status.hero.equipment)) core.status.hero.equipment = []; - core.playSound('equip.mp3'); - var loadEquip = core.material.items[equipId]; if (!core.isset(loadEquip)) { if (core.isset(callback)) callback(); return; } + + var can = this.canEquip[equipId]; + if (core.isset(can) && !eval(can)) { + core.drawTip("当前不可换上"+loadEquip.name); + if (core.isset(callback)) callback(); + return; + } + + core.playSound('equip.mp3'); + var loadEquipType = loadEquip.equip.type; var unloadEquipId = core.status.hero.equipment[loadEquipType]; @@ -285,9 +297,19 @@ items.prototype.quickLoadEquip = function (index) { for (var i=0;i0) { var block = core.maps.initBlock(x, y, arr[y][x]); if (core.isset(block.event)) { @@ -454,9 +440,16 @@ maps.prototype.drawMap = function (mapName, callback) { core.removeGlobalAnimate(null, null, true); var drawBg = function(){ + var width = core.floors[mapName].width || 13; + var height = core.floors[mapName].height || 13; - core.maps.drawBgFgMap(mapName, core.canvas.bg, "bg"); - core.maps.drawBgFgMap(mapName, core.canvas.fg, "fg"); + var groundId = (core.status.maps||core.floors)[mapName].defaultGround || "ground"; + var blockIcon = core.material.icons.terrains[groundId]; + for (var x = 0; x < width; x++) { + for (var y = 0; y < height; y++) { + core.canvas.bg.drawImage(core.material.images.terrains, 0, blockIcon * 32, 32, 32, x * 32, y * 32, 32, 32); + } + } var images = []; if (core.isset(core.status.maps[mapName].images)) { @@ -466,6 +459,7 @@ maps.prototype.drawMap = function (mapName, callback) { } } images.forEach(function (t) { + if (typeof t == 'string') t = [0,0,t]; var dx=parseInt(t[0]), dy=parseInt(t[1]), p=t[2]; if (core.isset(dx) && core.isset(dy) && !core.hasFlag("floorimg_"+mapName+"_"+dx+"_"+dy) && @@ -496,7 +490,10 @@ maps.prototype.drawMap = function (mapName, callback) { 32*dx, 32*dy + image.height - 32, image.width, 32); } } - }) + }); + + core.maps.drawBgFgMap(mapName, core.canvas.bg, "bg"); + core.maps.drawBgFgMap(mapName, core.canvas.fg, "fg"); } if (main.mode=='editor'){ diff --git a/libs/ui.js b/libs/ui.js index 80292eef..a9ad53e9 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -283,6 +283,64 @@ ui.prototype.drawText = function (contents, callback) { // core.drawTextBox(content); } +ui.prototype.getTitleAndIcon = function (content) { + var id=null, name=null, image=null, icon=null, iconHeight=32, animate=null; + + var getInfo = function (v) { + ["enemy48", "enemys", "npc48", "npcs"].forEach(function (x) { + if (core.isset(core.material.icons[x][v])) { + image = core.material.images[x]; + icon = core.material.icons[x][v]; + if (x.indexOf("48")>=0) { + iconHeight = 48; + animate = 4; + } + else { + iconHeight = 32; + animate = 2; + } + } + }); + }; + + if (content.indexOf("\t[")==0 || content.indexOf("\\t[")==0) { + var index = content.indexOf("]"); + if (index>=0) { + var str=content.substring(2, index); + if (content.indexOf("\\t[")==0) str=content.substring(3, index); + content=content.substring(index+1); + var ss=str.split(","); + if (ss.length==1) { + id=ss[0]; + if (id=='hero') name = core.status.hero.name; + else if (core.isset(core.material.enemys[id])) { + name = core.material.enemys[id].name; + getInfo(id); + } + else { + name=id; + id='npc'; + } + } + else { + name=ss[0]; + id = 'npc'; + if (ss[1]=='hero') id = 'hero'; + else getInfo(ss[1]); + } + } + } + return { + "content": content, + "id": id, + "name": name, + "image": image, + "icon": icon, + "iconHeight": iconHeight, + "animate": animate + }; +} + ////// 绘制一个对话框 ////// ui.prototype.drawTextBox = function(content, showAll) { @@ -294,78 +352,9 @@ ui.prototype.drawTextBox = function(content, showAll) { core.status.event.interval = null; // 获得name, image, icon - 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) { - var str=content.substring(2, index); - if (content.indexOf("\\t[")==0) str=content.substring(3, index); - content=content.substring(index+1); - var ss=str.split(","); - if (ss.length==1) { - // id - id=ss[0]; - if (id=='hero') { - name = core.status.hero.name; - } - else { - if (core.isset(core.material.enemys[id])) { - name = core.material.enemys[id].name; - - 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; - id='npc'; - image=null; - icon=null; - } - } - } - else { - name=ss[0]; - id = 'npc'; - if (ss[1]=='hero') { - id = 'hero'; - } - else 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 if (core.isset(core.material.icons.npcs[ss[1]])){ - image = core.material.images.npcs; - icon = core.material.icons.npcs[ss[1]]; - iconHeight = 32; - animate=2; - } - else if (core.isset(core.material.icons.enemy48[ss[1]])) { - image = core.material.images.enemy48; - icon = core.material.icons.enemy48[ss[1]]; - iconHeight = 48; - animate=4; - } - else if (core.isset(core.material.icons.enemys[ss[1]])) { - image = core.material.images.enemys; - icon = core.material.icons.enemys[ss[1]]; - iconHeight = 32; - animate=2; - } - } - } - } + var info = this.getTitleAndIcon(content); + content = info.content; + var id=info.id, name=info.name, image=info.image, icon=info.icon, iconHeight=info.iconHeight, animate=info.animate; // 获得位置信息 @@ -415,16 +404,17 @@ ui.prototype.drawTextBox = function(content, showAll) { // var contents = content.split('\n'); // var contents = core.splitLines('ui', content, ); - var left=10, right=416-2*left; + var left=7, right=416-2*left; var content_left = left + 25; if (id=='hero' || core.isset(icon)) content_left=left+63; var validWidth = right-(content_left-left)-13; var font = textfont + 'px Verdana'; if (textAttribute.bold) font = "bold "+font; - var contents = core.splitLines("ui", content, validWidth, font); + var realContent = content.replace(/(\r|\\r)(\[.*?])?/g, ""); - var height = 20 + (textfont+5)*(contents.length+1) + (id=='hero'?core.material.icons.hero.height-10:core.isset(name)?iconHeight-10:0); + var height = 20 + (textfont+5)*(core.splitLines("ui", realContent, validWidth, font).length+1) + + (id=='hero'?core.material.icons.hero.height-10:core.isset(name)?iconHeight-10:0); var xoffset = 6, yoffset = 22; @@ -434,20 +424,16 @@ ui.prototype.drawTextBox = function(content, showAll) { top = parseInt((416 - height) / 2); } else if (position=='up') { - if (px==null || py==null) { + if (px==null || py==null) top = 5 + offset; - } - else { + else top = 32 * py - height - ydelta - yoffset; - } } else if (position=='down') { - if (px==null || py==null) { + if (px==null || py==null) top = 416 - height - 5 - offset; - } - else { + else top = 32 * py + 32 + yoffset; - } } // var left = 97, top = 64, right = 416 - 2 * left, bottom = 416 - 2 * top; @@ -459,11 +445,10 @@ ui.prototype.drawTextBox = function(content, showAll) { core.setFillStyle('ui', core.arrayToRGB(textAttribute.background)); core.setStrokeStyle('ui', borderColor); - core.fillRect('ui', left, top, right, height); core.strokeRect('ui', left - 1, top - 1, right + 1, height + 1, borderColor, 2); - var xoffset = 9; + var xoffset = 10; // draw triangle if (position=='up' && core.isset(px) && core.isset(py)) { @@ -534,32 +519,66 @@ ui.prototype.drawTextBox = function(content, showAll) { } } + var defaultColor = core.arrayToRGB(textAttribute.text); + var offsetx = content_left, offsety = content_top; + core.setFont('ui', font); + core.setAlpha('ui', textAttribute.text[3]); + core.setFillStyle('ui', defaultColor); + var index = 0, currcolor = defaultColor, changed = false; - var drawContent = function (content) { - - core.clearMap("ui", content_left, content_top - 18, validWidth, top + height - content_top + 10); - core.setAlpha('ui', textAttribute.background[3]); - core.setFillStyle('ui', core.arrayToRGB(textAttribute.background)); - core.fillRect("ui", content_left, content_top - 18, validWidth, top + height - content_top + 11); - - core.setAlpha('ui', textAttribute.text[3]); - core.setFillStyle('ui', core.arrayToRGB(textAttribute.text)); - var contents = core.splitLines("ui", content, validWidth, font); - - for (var i=0;i= content.length) return false; + if (changed) { + core.setFillStyle('ui', currcolor); + changed = false; } - } + // get next character + var char = content.charAt(index++); + // \n, \\n + if (char == '\n' || (char=='\\' && content.charAt(index)=='n')) { + offsetx = content_left; + offsety += textfont+5; + if (char=='\\') index++; + return drawNext(); + } + // \r, \\r + if (char == '\r' || (char=='\\' && content.charAt(index)=='r')) { + if (char == '\\') index++; + changed = true; + // 检查是不是 [] + var index2; + if (content.charAt(index) == '[' && ((index2=content.indexOf(']', index))>=0)) { + // 变色 + var str = content.substring(index+1, index2); + if (str=="") currcolor = defaultColor; + else currcolor = str; + index = index2+1; + } + else currcolor = defaultColor; + return drawNext(); + } + // 检查是不是自动换行 + var charwidth = core.canvas.ui.measureText(char).width; + if (offsetx + charwidth > content_left + validWidth) { + index--; + offsetx = content_left; + offsety += textfont+5; + return drawNext(); + } + // 输出 + core.fillText('ui', char, offsetx, offsety); + offsetx += charwidth; + return true; + }; if (showAll || textAttribute.time<=0 || core.status.event.id!='action') { - drawContent(content); + while (drawNext()); } else { - var index=0; core.status.event.interval = setInterval(function () { - drawContent(content.substring(0, ++index)); - if (index==content.length) { + changed = true; + if (!drawNext()) { clearInterval(core.status.event.interval); core.status.event.interval = null; } @@ -604,82 +623,13 @@ ui.prototype.drawChoices = function(content, choices) { if (core.isset(content)) { // 获得name, image, icon - if (content.indexOf("\t[")==0 || content.indexOf("\\t[")==0) { - var index = content.indexOf("]"); - if (index>=0) { - var str=content.substring(2, index); - if (content.indexOf("\\t[")==0) str=content.substring(3, index); - content=content.substring(index+1); - var ss=str.split(","); - if (ss.length==1) { - // id - id=ss[0]; - if (id=='hero') { - name = core.status.hero.name; - } - else { - if (core.isset(core.material.enemys[id])) { - name = core.material.enemys[id].name; - - 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; - id='npc'; - image=null; - icon=null; - } - } - } - else { - name=ss[0]; - id = 'npc'; - if (ss[1]=='hero') { - id = 'hero'; - } - else 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 if (core.isset(core.material.icons.npcs[ss[1]])){ - image = core.material.images.npcs; - icon = core.material.icons.npcs[ss[1]]; - iconHeight = 32; - animate=2; - } - else if (core.isset(core.material.icons.enemy48[ss[1]])) { - image = core.material.images.enemy48; - icon = core.material.icons.enemy48[ss[1]]; - iconHeight = 48; - animate=4; - } - else if (core.isset(core.material.icons.enemys[ss[1]])) { - image = core.material.images.enemys; - icon = core.material.icons.enemys[ss[1]]; - iconHeight = 32; - animate=2; - } - } - } - } - content = core.replaceText(content); - + // 获得name, image, icon + var info = this.getTitleAndIcon(content); + content = core.replaceText(info.content); + id=info.id; name=info.name; image=info.image; + icon=info.icon; iconHeight=info.iconHeight; animate=info.animate; if (id=='hero' || core.isset(icon)) content_left = left+60; - contents = core.splitLines('ui', content, width-(content_left-left)-10, 'bold 15px Verdana'); // content部分高度 @@ -746,7 +696,8 @@ ui.prototype.drawChoices = function(content, choices) { // 选项 core.canvas.ui.textAlign = "center"; for (var i = 0; i < choices.length; i++) { - core.fillText('ui', core.replaceText(choices[i].text || choices[i]), 208, choice_top + 32 * i, "#FFFFFF", "bold 17px Verdana"); + core.setFillStyle('ui', choices[i].color || "#FFFFFF"); + core.fillText('ui', core.replaceText(choices[i].text || choices[i]), 208, choice_top + 32 * i, null, "bold 17px Verdana"); } if (choices.length>0) { @@ -846,7 +797,9 @@ ui.prototype.drawQuickShop = function () { core.status.event.id = 'selectShop'; var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) {return shopList[shopId].visited || !shopList[shopId].mustEnable}); - var choices = keys.map(function (shopId) {return shopList[shopId].textInList}); + var choices = keys.map(function (shopId) { + return {"text": shopList[shopId].textInList, "color": shopList[shopId].visited?null:"#999999"}; + }); choices.push("返回游戏"); this.drawChoices(null, choices); @@ -1340,25 +1293,25 @@ ui.prototype.drawBook = function (index) { // 数据 core.canvas.ui.textAlign = "center"; - if (enemy.special=='') { + if (enemy.specialText=='') { core.fillText('ui', enemy.name, 115, 62 * i + 47, '#DDDDDD', 'bold 17px Verdana'); } else { core.fillText('ui', enemy.name, 115, 62 * i + 40, '#DDDDDD', 'bold 17px Verdana'); - core.fillText('ui', enemy.special, 115, 62 * i + 62, '#FF6A6A', 'bold 15px Verdana'); + core.fillText('ui', enemy.specialText, 115, 62 * i + 62, '#FF6A6A', 'bold 15px Verdana'); } core.canvas.ui.textAlign = "left"; core.fillText('ui', '生命', 165, 62 * i + 32, '#DDDDDD', '13px Verdana'); - core.fillText('ui', core.formatBigNumber(enemy.hp), 195, 62 * i + 32, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.hp||0), 195, 62 * i + 32, '#DDDDDD', 'bold 13px Verdana'); core.fillText('ui', '攻击', 255, 62 * i + 32, '#DDDDDD', '13px Verdana'); - core.fillText('ui', core.formatBigNumber(enemy.atk), 285, 62 * i + 32, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.atk||0), 285, 62 * i + 32, '#DDDDDD', 'bold 13px Verdana'); core.fillText('ui', '防御', 335, 62 * i + 32, '#DDDDDD', '13px Verdana'); - core.fillText('ui', core.formatBigNumber(enemy.def), 365, 62 * i + 32, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.def||0), 365, 62 * i + 32, '#DDDDDD', 'bold 13px Verdana'); var expOffset = 165, line_cnt=0; if (core.flags.enableMoney) { core.fillText('ui', '金币', 165, 62 * i + 50, '#DDDDDD', '13px Verdana'); - core.fillText('ui', core.formatBigNumber(enemy.money), 195, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.money||0), 195, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); expOffset = 255; line_cnt++; } @@ -1367,7 +1320,7 @@ ui.prototype.drawBook = function (index) { if (core.flags.enableAddPoint) { core.canvas.ui.textAlign = "left"; core.fillText('ui', '加点', expOffset, 62 * i + 50, '#DDDDDD', '13px Verdana'); - core.fillText('ui', core.formatBigNumber(enemy.point), expOffset + 30, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.point||0), expOffset + 30, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); expOffset = 255; line_cnt++; } @@ -1375,7 +1328,7 @@ ui.prototype.drawBook = function (index) { 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', core.formatBigNumber(enemy.experience), expOffset + 30, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.experience||0), expOffset + 30, 62 * i + 50, '#DDDDDD', 'bold 13px Verdana'); line_cnt++; } @@ -1396,14 +1349,14 @@ ui.prototype.drawBook = function (index) { if (damage<=0) color = '#00FF00'; damage = core.formatBigNumber(damage); - if (core.enemys.hasSpecial(core.material.enemys[enemy.id], 19)) + if (core.enemys.hasSpecial(enemy, 19)) damage += "+"; - if (core.enemys.hasSpecial(core.material.enemys[enemy.id], 21)) + if (core.enemys.hasSpecial(enemy, 21)) damage += "-"; - if (core.enemys.hasSpecial(core.material.enemys[enemy.id], 11)) + if (core.enemys.hasSpecial(enemy, 11)) damage += "^"; } - if (core.material.enemys[enemy.id].notBomb) + if (enemy.notBomb) damage += "[b]"; core.fillText('ui', damage, damageOffset, 62 * i + 50, color, 'bold 13px Verdana'); @@ -1411,11 +1364,11 @@ ui.prototype.drawBook = function (index) { core.canvas.ui.textAlign = "left"; core.fillText('ui', '临界', 165, 62 * i + 68, '#DDDDDD', '13px Verdana'); - core.fillText('ui', core.formatBigNumber(enemy.critical), 195, 62 * i + 68, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.critical||0), 195, 62 * i + 68, '#DDDDDD', 'bold 13px Verdana'); core.fillText('ui', '减伤', 255, 62 * i + 68, '#DDDDDD', '13px Verdana'); - core.fillText('ui', core.formatBigNumber(enemy.criticalDamage), 285, 62 * i + 68, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.criticalDamage||0), 285, 62 * i + 68, '#DDDDDD', 'bold 13px Verdana'); core.fillText('ui', '1防', 335, 62 * i + 68, '#DDDDDD', '13px Verdana'); - core.fillText('ui', core.formatBigNumber(enemy.defDamage), 365, 62 * i + 68, '#DDDDDD', 'bold 13px Verdana'); + core.fillText('ui', core.formatBigNumber(enemy.defDamage||0), 365, 62 * i + 68, '#DDDDDD', 'bold 13px Verdana'); if (index == start+i) { core.strokeRect('ui', 10, 62 * i + 13, 416-10*2, 62, '#FFD700'); @@ -1436,8 +1389,7 @@ ui.prototype.drawBookDetail = function (index) { if (index<0) index=0; if (index>=enemys.length) index=enemys.length-1; - var enemyId=enemys[index].id; - var enemy = core.material.enemys[enemyId]; + var enemy = enemys[index], enemyId = enemy.id; var hints=core.enemys.getSpecialHint(enemy); if (hints.length==0) @@ -1619,6 +1571,13 @@ ui.prototype.drawMaps = function (index, x, y) { core.fillText('ui', "上移地图 [W]", 208, 38, '#FFD700', '20px Arial'); core.fillText('ui', "下移地图 [S]", 208, 390); + core.strokeRect('ui', 2, 2, 28, 28); + core.fillText('ui', 'V', 16, 24); + core.strokeRect('ui', 2, 416-30, 28, 28); + core.fillText('ui', 'M', 16, 408); + core.strokeRect('ui', 416-30, 2, 28, 28); + core.fillText('ui', 'Z', 400, 24); + var top = 150; core.fillText('ui', "左", 32, top); core.fillText('ui', "移", 32, top+32); @@ -1636,6 +1595,7 @@ ui.prototype.drawMaps = function (index, x, y) { core.fillText('ui', "退出 [ESC / ENTER]", 208, 208+8); core.fillText('ui', "[X] 可查看怪物手册", 285, 208+40, null, '13px Arial'); + return; } @@ -1643,8 +1603,10 @@ ui.prototype.drawMaps = function (index, x, y) { core.setOpacity('animate', 1); var damage = (core.status.event.data||{}).damage, paint = (core.status.event.data||{}).paint; + var all = (core.status.event.data||{}).all; if (core.isset(index.damage)) damage=index.damage; if (core.isset(index.paint)) paint=index.paint; + if (core.isset(index.all)) all=index.all; if (core.isset(index.index)) { x=index.x; @@ -1662,7 +1624,7 @@ ui.prototype.drawMaps = function (index, x, y) { if (y<6) y=6; if (y>mh-7) y=mh-7; - core.status.event.data = {"index": index, "x": x, "y": y, "damage": damage, "paint": paint}; + core.status.event.data = {"index": index, "x": x, "y": y, "damage": damage, "paint": paint, "all": all}; clearTimeout(core.interval.tipAnimate); core.clearMap('ui'); @@ -1684,7 +1646,7 @@ ui.prototype.drawMaps = function (index, x, y) { core.setFont('data', '16px Arial'); var text = core.status.maps[floorId].title; - if (mw>13 || mh>13) text+=" ["+(x-6)+","+(y-6)+"]"; + if (!all && (mw>13 || mh>13)) text+=" ["+(x-6)+","+(y-6)+"]"; var textX = 16, textY = 18, width = textX + core.canvas.data.measureText(text).width + 16, height = 42; core.fillRect('data', 5, 5, width, height, '#000'); core.setOpacity('data', 0.4); @@ -2113,8 +2075,13 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, cente tempCanvas.canvas.height = tempHeight; tempCanvas.clearRect(0, 0, tempWidth, tempHeight); - // background map - core.maps.drawBgFgMap(floorId, tempCanvas, "bg"); + var groundId = (core.status.maps||core.floors)[floorId].defaultGround || "ground"; + var blockIcon = core.material.icons.terrains[groundId]; + for (var i = 0; i < mw; i++) { + for (var j = 0; j < mh; j++) { + tempCanvas.drawImage(core.material.images.terrains, 0, blockIcon * 32, 32, 32, i * 32, j * 32, 32, 32); + } + } // background image var images = []; @@ -2125,6 +2092,7 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, cente } } images.forEach(function (t) { + if (typeof t == 'string') t = [0,0,t]; var dx=parseInt(t[0]), dy=parseInt(t[1]), p=t[2]; if (core.isset(dx) && core.isset(dy) && !core.hasFlag("floorimg_"+floorId+"_"+dx+"_"+dy) && @@ -2137,6 +2105,10 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, cente 32 * dx, 32 * dy + image.height - 32, image.width, 32); } }) + + // background map + core.maps.drawBgFgMap(floorId, tempCanvas, "bg"); + // draw block var mapArray = core.maps.getMapArray(blocks,mw,mh); for (var b in blocks) { @@ -2172,8 +2144,6 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, cente var height = core.material.images.images[heroIcon].height/4; tempCanvas.drawImage(core.material.images.images[heroIcon], icon.stop * 32, icon.loc * height, 32, height, 32*heroLoc.x, 32*heroLoc.y+32-height, 32, height); } - // foreground map - core.maps.drawBgFgMap(floorId, tempCanvas, "fg"); // draw fg images.forEach(function (t) { @@ -2190,6 +2160,9 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, cente } }) + // foreground map + core.maps.drawBgFgMap(floorId, tempCanvas, "fg"); + // draw damage if (core.status.event.id=='viewMaps' && (core.status.event.data||{}).damage) core.control.updateDamage(floorId, tempCanvas); @@ -2199,9 +2172,28 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, cente if (!core.isset(centerX)) centerX=parseInt(mw/2); if (!core.isset(centerY)) centerY=parseInt(mh/2); - var offsetX = core.clamp(centerX-6, 0, mw-13), offsetY = core.clamp(centerY-6, 0, mh-13); - // offsetX~offsetX+12; offsetY~offsetY+12 - core.canvas[canvas].drawImage(tempCanvas.canvas, offsetX*32, offsetY*32, 416, 416, x, y, size, size); + // 如果是浏览地图的全模式 + if (core.status.event.id=='viewMaps' && (core.status.event.data||{}).all) { + if (tempWidth<=tempHeight) { + var realHeight = 416, realWidth = realHeight * tempWidth / tempHeight; + var side = (416 - realWidth) / 2; + core.fillRect(canvas, 0, 0, side, realHeight, '#000000'); + core.fillRect(canvas, 416-side, 0, side, realHeight); + core.canvas[canvas].drawImage(tempCanvas.canvas, 0, 0, tempWidth, tempHeight, side, 0, realWidth, realHeight); + } + else { + var realWidth = 416, realHeight = realWidth * tempHeight / tempWidth; + var side = (416 - realHeight) / 2; + core.fillRect(canvas, 0, 0, realWidth, side, '#000000'); + core.fillRect(canvas, 0, 416-side, realWidth, side); + core.canvas[canvas].drawImage(tempCanvas.canvas, 0, 0, tempWidth, tempHeight, 0, side, realWidth, realHeight); + } + } + else { + var offsetX = core.clamp(centerX-6, 0, mw-13), offsetY = core.clamp(centerY-6, 0, mh-13); + // offsetX~offsetX+12; offsetY~offsetY+12 + core.canvas[canvas].drawImage(tempCanvas.canvas, offsetX*32, offsetY*32, 416, 416, x, y, size, size); + } } ui.prototype.drawKeyBoard = function () { diff --git a/libs/utils.js b/libs/utils.js index 24c1eaf9..ecf5178c 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -4,16 +4,41 @@ utils.js 工具类 */ function utils() { - + this.init(); } utils.prototype.init = function () { + // 定义Object.assign + if (typeof Object.assign != "function") { + Object.assign = function(target, varArgs) { // .length of function is 2 + if (target == null) { // TypeError if undefined or null + throw new TypeError('Cannot convert undefined or null to object'); + } + + var to = Object(target); + + for (var index = 1; index < arguments.length; index++) { + var nextSource = arguments[index]; + + if (nextSource != null) { // Skip over if undefined or null + for (var nextKey in nextSource) { + // Avoid bugs when hasOwnProperty is shadowed + if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { + to[nextKey] = nextSource[nextKey]; + } + } + } + } + return to; + }; + } + } ////// 将文字中的${和}(表达式)进行替换 ////// utils.prototype.replaceText = function (text) { - return text.replace(/\${([^}]+)}/g, function (word, value) { + return text.replace(/\${(.*?)}/g, function (word, value) { return core.calValue(value); }); } @@ -486,8 +511,8 @@ utils.prototype.__init_seed = function () { rand = this.__next_rand(rand); rand = this.__next_rand(rand); rand = this.__next_rand(rand); - core.setFlag('seed', rand); - core.setFlag('rand', rand); + core.setFlag('__seed__', rand); + core.setFlag('__rand__', rand); } utils.prototype.__next_rand = function (_rand) { @@ -497,9 +522,9 @@ utils.prototype.__next_rand = function (_rand) { } utils.prototype.rand = function (num) { - var rand = core.getFlag('rand'); + var rand = core.getFlag('__rand__'); rand = this.__next_rand(rand); - core.setFlag('rand', rand); + core.setFlag('__rand__', rand); var ans = rand/2147483647; if (core.isset(num) && num>0) return Math.floor(ans*num); @@ -800,12 +825,12 @@ utils.prototype.decodeCanvas = function (arr, width, height) { } utils.prototype.consoleOpened = function () { + if (window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized) + return true; var threshold = 160; - var widthThreshold = window.outerWidth - window.innerWidth > threshold; - var heightThreshold = window.outerHeight - window.innerHeight > threshold; - return !(heightThreshold && widthThreshold) && - ((window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized) - || widthThreshold || heightThreshold); + var zoom = Math.min(window.outerWidth/window.innerWidth, window.outerHeight/window.innerHeight); + return window.outerWidth - zoom*window.innerWidth > threshold + || window.outerHeight - zoom*window.innerHeight > threshold; } utils.prototype.hashCode = function (obj) { diff --git a/main.js b/main.js index 45ccd438..cdbcdc75 100644 --- a/main.js +++ b/main.js @@ -2,7 +2,7 @@ function main() { //------------------------ 用户修改内容 ------------------------// - this.version = "2.5"; // 游戏版本号;如果更改了游戏内容建议修改此version以免造成缓存问题。 + this.version = "2.5.1"; // 游戏版本号;如果更改了游戏内容建议修改此version以免造成缓存问题。 this.useCompress = false; // 是否使用压缩文件 // 当你即将发布你的塔时,请使用“JS代码压缩工具”将所有js代码进行压缩,然后将这里的useCompress改为true。 @@ -420,15 +420,6 @@ main.statusBar.image.fly.onclick = function () { return; } - // 浏览地图时 - if (main.core.isPlaying() && (core.status.event||{}).id=='viewMaps') { - if (core.isset(core.status.event.data)) { - core.status.event.data.paint = !core.status.event.data.paint; - core.ui.drawMaps(core.status.event.data); - } - return; - } - if (main.core.isPlaying()) { if (!main.core.flags.equipboxButton) { main.core.useFly(true); diff --git a/project/data.js b/project/data.js index 22b396ea..e8c3c64b 100644 --- a/project/data.js +++ b/project/data.js @@ -68,7 +68,7 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "firstData": { "title": "魔塔样板", "name": "template", - "version": "Ver 2.5", + "version": "Ver 2.5.1", "floorId": "sample0", "hero": { "name": "阳光", @@ -203,6 +203,7 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "enableMoney": true, "enableExperience": false, "enableLevelUp": false, + "levelUpLeftMode": false, "enableKeys": true, "enablePZF": false, "enableDebuff": false, @@ -232,6 +233,7 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "portalWithoutTrigger": true, "canGoDeadZone": false, "enableMoveDirectly": true, - "enableDisabledShop": true + "enableDisabledShop": true, + "disableShopOnDamage": false } } \ No newline at end of file diff --git a/project/floors/sample1.js b/project/floors/sample1.js index 87bbb9b2..659098a7 100644 --- a/project/floors/sample1.js +++ b/project/floors/sample1.js @@ -1,340 +1,787 @@ -main.floors.sample1 = +main.floors.sample1= { - "floorId": "sample1", // 这里需要改楼层名,请和文件名及下面的floorId保持完全一致 - // 楼层唯一标识符仅能由字母、数字、下划线组成,且不能由数字开头 - // 推荐用法:第20层就用MT20,第38层就用MT38,地下6层就用MT_6(用下划线代替负号),隐藏3层用MT3h(h表示隐藏),等等 - // 楼层唯一标识符,需要和名字完全一致 - "title": "样板 1 层", // 楼层中文名 - "name": "1", // 显示在状态栏中的层数 - "canFlyTo": true, // 该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器) - "canUseQuickShop": true, // 该层是否允许使用快捷商店 - "defaultGround": "grass", // 默认地面的图块ID(terrains中) - "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], - [152,152,152,152,121,152,152,152, 0, 0,229, 0, 0], - [ 43, 33, 44,151, 0, 0, 0,152,165,161, 0,163,165], - [ 21, 22, 21,151, 0, 0, 0,152,166,165, 0,165,166], - [151,245,151,151, 0, 87, 0,152,152,152, 85,153,153], - [ 0,246, 0,151, 0, 0, 0,152,152,221, 0,221,153], - [246, 0,246,151, 0, 0, 0,121, 85, 0, 0, 0,153], - [151,246,151,151, 0,153,153,153,153,153,153,153,153], - [ 0, 0, 0, 0, 0, 0, 0,164, 0, 0,163, 0, 0], - [ 1, 1, 1, 1, 0, 20, 0, 0, 0,162, 0,161, 0], - [ 1, 0,123, 1, 0, 20,124, 0,121, 0,122, 0,126], - [ 1, 0, 0, 1, 88, 20, 86, 0, 0, 0, 0, 0, 0] +"floorId": "sample1", +"title": "样板 1 层", +"name": "1", +"canFlyTo": true, +"canUseQuickShop": true, +"defaultGround": "grass", +"images": [ + [ + 0, + 0, + "bg.jpg", + false + ] +], +"weather": [ + "snow", + 6 +], +"item_ratio": 1, +"map": [ + [ 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], + [152,152,152,152,121,152,152,152, 0, 0,229, 0, 0], + [ 43, 33, 44,151, 0, 0, 0,152,165,161, 0,163,165], + [ 21, 22, 21,151, 0, 0, 0,152,166,165, 0,165,166], + [151,245,151,151, 0, 87, 0,152,152,152, 85,153,153], + [ 0,246, 0,151, 0, 0, 0,152,152,221, 0,221,153], + [246, 0,246,151, 0, 0, 0,121, 85, 0, 0, 0,153], + [151,246,151,151, 0,153,153,153,153,153,153,153,153], + [ 0, 0, 0, 0, 0, 0, 0,164, 0, 0,163, 0, 0], + [ 1, 1, 1, 1, 0, 20, 0, 0, 0,162, 0,161, 0], + [ 1, 0,123, 1, 0, 20,124, 0,121, 0,122, 0,126], + [ 1, 0, 0, 1, 88, 20, 86, 0, 0, 0, 0, 0,122] +], +"firstArrive": [], +"events": { + "4,10": [ + "\t[样板提示]本层楼将会对各类事件进行介绍。", + "左边是一个仿50层的陷阱做法,上方是商店、快捷商店的使用方法,右上是一个典型的杀怪开门的例子,右下是各类可能的NPC事件。", + "本样板目前支持的事件列表大致有:\ntext: 显示一段文字(比如你现在正在看到的)\ntip: 左上角显示提示\nshow: 使一个事件有效(可见、可被交互)\nhide: 使一个事件失效(不可见、不可被交互)\ntrigger: 触发另一个地点的事件\nanimate: 显示动画\nbattle: 强制和某怪物战斗\nopenDoor: 无需钥匙开门(例如机关门、暗墙)", + "openShop: 打开一个全局商店\ndisableShop: 禁用一个全局商店\nchangeFloor: 传送勇士到某层某位置\nchangePos: 传送勇士到当层某位置;转向\nshowImage: 显示图片\nsetFg: 更改画面色调\nsetWeather: 更改天气\nmove: 移动事件效果\nmoveHero: 移动勇士效果\nplayBgm: 播放某个背景音乐\npauseBgm: 暂停背景音乐\nresumeBgm: 恢复背景音乐的播放\nplaySound: 播放某个音频", + "if: 条件判断\nchoices: 提供选项\nsetValue: 设置勇士属性道具,或某个变量/flag\nupdate: 更新状态栏和地图显伤\nwin: 获得胜利(游戏通关)\nlose: 游戏失败\nsleep: 等待多少毫秒\nexit: 立刻结束当前事件\nrevisit: 立刻结束事件并重新触发\nfunction: 自定义JS脚本\n\n更多支持的事件还在编写中,欢迎您宝贵的意见。", + "有关各事件的样例,可参见本层一些NPC的写法。\n所有事件样例本层都有介绍。\n\n一个自定义事件处理完后,需要调用{\"type\": \"hide\"}该事件才不会再次出现。", + { + "type": "hide" + } ], - "firstArrive": [ // 第一次到该楼层触发的事件 - + "1,5": { + "enable": false, + "data": [] + }, + "1,6": { + "enable": false, + "data": [] + }, + "0,7": { + "enable": false, + "data": [] + }, + "2,7": { + "enable": false, + "data": [] + }, + "1,8": { + "enable": false, + "data": [] + }, + "1,7": [ + { + "type": "show", + "loc": [ + 1, + 5 + ], + "time": 1500 + }, + { + "type": "sleep", + "time": 500 + }, + "\t[redKing]欢迎来到魔塔,你是第一百位挑战者。\n若你能打败我所有的手下,我就与你一对一的决斗。\n现在你必须接受我的安排。", + { + "type": "show", + "loc": [ + [ + 1, + 6 + ], + [ + 0, + 7 + ], + [ + 1, + 8 + ], + [ + 2, + 7 + ] + ], + "time": 500 + }, + "\t[hero]什么?", + { + "type": "playSound", + "name": "attack.mp3" + }, + { + "type": "setValue", + "name": "status:atk", + "value": "status:atk/10" + }, + { + "type": "setValue", + "name": "status:def", + "value": "status:def/10" + }, + { + "type": "hide", + "loc": [ + [ + 1, + 6 + ], + [ + 0, + 7 + ], + [ + 2, + 7 + ], + [ + 1, + 8 + ] + ] + }, + { + "type": "hide", + "loc": [ + 1, + 5 + ], + "time": 500 + }, + { + "type": "hide" + }, + { + "type": "setFg", + "color": [ + 0, + 0, + 0 + ], + "time": 1250 + }, + { + "type": "sleep", + "time": 700 + }, + { + "type": "changeFloor", + "floorId": "sample1", + "loc": [ + 1, + 11 + ], + "direction": "right", + "time": 1000 + }, + { + "type": "trigger", + "loc": [ + 2, + 11 + ] + } ], - "events": { // 该楼的所有可能事件列表 - - "4,10": [ // 走到中间时的提示 - "\t[样板提示]本层楼将会对各类事件进行介绍。", - "左边是一个仿50层的陷阱做法,上方是商店、快捷商店的使用方法,右上是一个典型的杀怪开门的例子,右下是各类可能的NPC事件。", - "本样板目前支持的事件列表大致有:\ntext: 显示一段文字(比如你现在正在看到的)\ntip: 左上角显示提示\nshow: 使一个事件有效(可见、可被交互)\nhide: 使一个事件失效(不可见、不可被交互)\ntrigger: 触发另一个地点的事件\nanimate: 显示动画\nbattle: 强制和某怪物战斗\nopenDoor: 无需钥匙开门(例如机关门、暗墙)", - "openShop: 打开一个全局商店\ndisableShop: 禁用一个全局商店\nchangeFloor: 传送勇士到某层某位置\nchangePos: 传送勇士到当层某位置;转向\nshowImage: 显示图片\nsetFg: 更改画面色调\nsetWeather: 更改天气\nmove: 移动事件效果\nmoveHero: 移动勇士效果\nplayBgm: 播放某个背景音乐\npauseBgm: 暂停背景音乐\nresumeBgm: 恢复背景音乐的播放\nplaySound: 播放某个音频", - "if: 条件判断\nchoices: 提供选项\nsetValue: 设置勇士属性道具,或某个变量/flag\nupdate: 更新状态栏和地图显伤\nwin: 获得胜利(游戏通关)\nlose: 游戏失败\nsleep: 等待多少毫秒\nexit: 立刻结束当前事件\nrevisit: 立刻结束事件并重新触发\nfunction: 自定义JS脚本\n\n更多支持的事件还在编写中,欢迎您宝贵的意见。", - "有关各事件的样例,可参见本层一些NPC的写法。\n所有事件样例本层都有介绍。\n\n一个自定义事件处理完后,需要调用{\"type\": \"hide\"}该事件才不会再次出现。", - {"type": "hide"} - ], - - /****** 左边仿50F陷阱事件 ******/ - "1,5": {"enable": false}, // 这几个是白衣武士等怪物,起始时需要隐藏起来 - "1,6": {"enable": false}, - "0,7": {"enable": false}, - "2,7": {"enable": false}, - "1,8": {"enable": false}, - "1,7": [ // 走到白衣武士中间,触发陷阱事件 - {"type": "show", "loc": [1,5], "time": 1500}, // 显示红衣魔王,动画效果1500ms - {"type": "sleep", "time": 500}, // 等待500ms - "\t[redKing]欢迎来到魔塔,你是第一百位挑战者。\n若你能打败我所有的手下,我就与你一对一的决斗。\n现在你必须接受我的安排。", - {"type": "show", "loc": [[1,6],[0,7],[1,8],[2,7]], "time": 500}, // 显示四个白衣武士,每个动画效果500ms - "\t[hero]什么?", - {"type": "playSound", "name": "attack.mp3"}, // 播放战斗音频 - {"type": "setValue", "name": "status:atk", "value": "status:atk/10"}, // 勇士的攻防变成原来的十分之一 - {"type": "setValue", "name": "status:def", "value": "status:def/10"}, - {"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": "sleep", "time": 700}, - {"type": "changeFloor", "floorId": "sample1", "loc": [1,11], "direction": "right", "time": 1000}, // 楼层切换。changeFloor必须指定floorId和loc。 - // 备注:这里也可以下面的这种写法: - // {"type": "changePos", "loc": [1,11]} - // 使用这种写法将不会有“楼层切换动画”,而是直接让勇士到达本层的loc位置。 - {"type": "trigger", "loc": [2,11]} // 立刻直接触发另一个事件(也就是下面的小偷事件);当前事件会被立刻结束 - ], - "2,11": [ // 小偷事件 - "\t[杰克,thief]喂!醒醒!快醒醒!", - {"type": "setFg", "time": 1500}, // 渐变回来 - "\t[hero]额,我这是在什么地方?", - "\t[杰克,thief]你被魔王抓了起来扔进了监狱,和我关在了一起,但是幸运的是我在昨天刚刚挖好一条越狱的暗道!", - {"type": "openDoor", "loc": [3,11]}, // 开门或墙必须指定门/墙的名称,否则不会执行 - {"type": "sleep", "time": 300}, // 等待300ms - "\t[杰克,thief]我先走了,祝你好运!", - {"type": "move", "time": 750, "steps": [ // 动画移动效果,time为每步事件(毫秒),steps是个数组指定了移动的方位 - {"direction": "right", "value": 2}, // 向右移动两步,再向下移动一步,并消失 - "down" // 如果该方向只移动一步,可以直接这样简写。 这种写法等价于: {"direction":"down","value":1} - ]}, - // 调用move事件后,hide事件也会被自动调用,因此无需再手动调用 {"type":"hide"} 来隐藏本事件了 - "上面是个move事件,可以对NPC等进行移动。\n详见样板中小偷事件的写法。", - "\t[hero]怎么跑的这么快..." - ], - - /****** 上方商店事件相关 ******/ - "4,2": [ // 商店门前的老人 - "\t[老人,man]本塔的商店有两类,全局商店和非全局商店。\n\n所谓非全局商店,就类似于右下角那个卖钥匙的老人一样,一定要碰到才能触发事件。\n\n而全局商店,则能在快捷商店中直接使用。", - "\t[老人,man]要注册一个全局商店,你需要在 data.js 中,找到 shops,并在内添加你的商店信息。", - "\t[老人,man]商店信息添加后,可以在需要的事件处调用{\"type\": \"openShop\"}来打开你添加的全局商店。", - "\t[老人,man]在上面的例子里,左边是一个仿50层的金币商店,右边是一个仿24层的经验商店。\n\n商店被访问后即可在快捷商店中进行使用。", - "\t[老人,man]如果你需要在某层暂时禁用快捷商店,可以在data.js中设置cannotUseQuickShop。\n如果需要永久禁用商店,请使用{\"type\":\"disableShop\"}", - {"type": "hide", "time": 500} - ], - "1,0": [ // 金币商店 - // 打开商店前,你也可以添加自己的剧情 - // 例如,通过if来事件来判断是不是第一次访问商店,是的则显示一段文字(类似宿命的华音那样) - {"type": "openShop", "id": "moneyShop1"} // 这里的id要和data.js中你定义的商店ID完全一致 - // 调用openShop事件后,所有当前事件都会被结束(同exit事件),然后打开一个全局商店 - ], - "5,0": [ // 经验商店 - {"type": "openShop", "id": "expShop1"} - ], - - - - /****** 右边陷阱、战斗相关 ******/ - "7,7": [ // 门口老人的提示 - "\t[老人,man]这是一个典型的杀怪开门、强制战斗事件。", - {"type": "hide"} // 不显示动画,直接消失 - ], - "8,7": {"enable": false}, // 门口的机关门,初始时是禁用状态 - "9,7": [ // 当你刚进去后,触发机关门 - {"type": "show", "loc": [8,7]}, // 显示机关门 - {"type": "hide"} // 该事件消失 - ], - // 注意:初级卫兵打死后的开门事件是在 afterBattle 中调用 - "10,4": [ // 开门后走进去的事件:强制战斗 - "\t[blackKing]你终于还是来了。", - "\t[hero]放开我们的公主!", - "\t[blackKing]如果我不愿意呢?", - "\t[hero]无需多说,拔剑吧!", - {"type": "battle", "id": "blackKing"}, // 强制战斗 - // 如果战斗失败直接死亡,不会继续触发接下来的剧情。 - {"type": "hide", "loc": [10,2]}, // 战斗后需要手动使怪物消失;战斗后不会引发afterBattle事件。 - {"type": "openDoor", "loc": [8,7]}, // 开门口的机关门 - "\t[blackKing]没想到你已经变得这么强大了... 算你厉害。\n公主就交给你了,请好好对她。", - {"type": "hide"} // 隐藏本事件 - ], - "10,0": [ // 公主事件 - "\t[hero]公主,我来救你了~", - "\t[公主,princess]快救我出去!我受够这里了!", - "\t[hero]公主别怕,我们走吧~", - {"type": "win", "reason": "救出公主"} // 获得胜利。此事件将显示获胜界面,并结束游戏。 - // 该事件将直接调用events.js中的win()函数;如需修改获胜界面内容可前往修改。 - // 下面这个是失败事件,同样会直接调用events.js中的lose()函数;如需修改失败界面内容可以前往修改。 - // {"type": "lose", "reason": "救了假公主"} - ], - - - - /****** 右下各种NPC事件相关 ******/ - "6,12": {"enable":false}, // 仙子下面的铁门,初始时是禁用的 - "6,11": [ // 仙子事件 - "\t[仙子,fairy]通过调用 {\"type\": \"show\"} 可以使隐藏的事件显示出来。\n比如我下面这个机关门。", - {"type": "show", "loc": [6,12]}, // 使隐藏的铁门显示出来 - "\t[仙子,fairy]通过调用 {\"type\": \"openDoor\"} 可以无需钥匙打开一扇门或暗墙。", - {"type": "openDoor", "loc": [6,12]}, // 开门 - "\t[仙子,fairy]同时,也可以对其它层进行操作,比如楼下的机关门,现在已经为你打开了。", - {"type": "openDoor", "loc": [11,10], "floorId": "sample0"}, // 打开其它层的门,需要指定floorId - "\t[仙子,fairy]如果 show 或 hide 指定了 time 参数,则以动画效果显示,指定的参数作为消失时间(毫秒)来计算。", - "\t[仙子,fairy]现在到楼下来找我吧~", - {"type": "show", "loc": [12,10], "floorId": "sample0"}, // 显示其它层的事件,需要指定其floorId - {"type": "hide", "time": 500} - ], - "8,11": [ // 老人事件,勇士状态的显示与变化 - {"type": "setValue", "name": "flag:man_times", "value": "flag:man_times+1"}, // 设置这个老人的访问次数 - "\t[老人,man]在文字中使用${' ${ '}和 } 可以计算并显示一个表达式的结果。\n", - "\t[老人,man]例如:\n你的当前攻击力是${status:atk},防御力是${status:def}。\n攻防和的十倍是${10*(status:atk+status:def)},攻防之积是${status:atk*status:def}。\n你有${item:yellowKey}把黄钥匙,${item:blueKey}把蓝钥匙,${item:redKey}把红钥匙。\n你有${item:pickaxe}个破,${item:bomb}个炸,${item:centerFly}个飞。\n这是你第${flag:man_times}次和我对话。", - "\t[老人,man]同时,你也可以通过{\"type\": \"setValue\"}来设置一个勇士的属性、道具,或某个Flag。", - "\t[老人,man]例如:\n现在我将让你的攻防提升50%,再将攻防和的十倍加到生命值上。", - {"type": "setValue", "name": "status:atk", "value": "status:atk*1.5"}, // 攻击提升50%;注意不要加${} - {"type": "setValue", "name": "status:def", "value": "status:def*1.5"}, // 防御提升50%;注意不要加${} - {"type": "setValue", "name": "status:hp", "value": "status:hp+10*(status:atk+status:def)"}, //生命提升攻防和的十倍 - "\t[老人,man]再送你500金币,1000经验,1破2炸3飞!", - {"type": "setValue", "name": "status:money", "value": "status:money+500"}, - {"type": "setValue", "name": "status:experience", "value": "status:experience+1000"}, - {"type": "setValue", "name": "item:pickaxe", "value": "item:pickaxe+1"}, // 1破 - {"type": "setValue", "name": "item:bomb", "value": "item:bomb+2"}, // 2炸 - {"type": "setValue", "name": "item:centerFly", "value": "item:centerFly+3"}, // 3飞 - "\t[老人,man]status:xxx 代表勇士的某个属性。\n其中xxx可取hp, atk, def, mdef, money,experience这几项。\n\nitem:xxx 代表勇士的某个道具的个数。\nxxx为道具ID,具体可参见items.js中的定义。\n\nflag:xxx 代表某个自定义Flag或变量。\nxxx为Flag/变量名,可以自行定义,由字母、数字和下划线组成。\n未定义过而直接取用的Flag默认值为false。", - // 如果老人不消失,则不要调用 {"type": "hide"} - "\t[老人,man]你现在可以重新和我进行对话,进一步看到属性值的改变。" - ], - "10,11": [ // 商人事件,if语句和choices语句的写法 - // 这部分逻辑相对比较长,细心看,很容易看懂的。 - {"type": "if", "condition": "flag:woman_times==0", // 条件判断:是否从未访问过此商人。 - "true": [ // 如果从未访问过该商人,显示一段文字 - "\t[老人,woman]这是个很复杂的例子,它将教会你如何使用if 语句进行条件判断,以及 choices 提供选项来供用户进行选择。", - "\t[老人,woman]第一次访问我将显示这段文字;从第二次开始将会向你出售钥匙。\n钥匙价格将随着访问次数递增。\n当合计出售了七把钥匙后,将送你一把大黄门钥匙,并消失不再出现。", - "\t[老人,woman]这部分的逻辑比较长,请细心看样板的写法,是很容易看懂并理解的。" - // 第一次访问结束 - ], - "false": [ // 如果已经访问过该商人 - {"type": "if", "condition": "flag:woman_times==8", // 条件判断:是否已经出售七把钥匙 - "true": [ // 如果已经出售过七把钥匙,则直接结束 - "\t[老人,woman]你购买的钥匙已经够多了,再继续卖给你的话我会有危险的。", - "\t[老人,woman]看在你贡献给我这么多钱的份上,送你一把大黄门钥匙吧,希望你能好好用它。", - {"type": "setValue", "name": "item:bigKey", "value": "item:bigKey+1"}, // 获得一把大黄门钥匙 - "\t[老人,woman]我先走了,拜拜~", - {"type":"hide", "time": 500}, // 消失 - {"type":"exit"} // 立刻结束当前事件。下面的 setValue 和 revisit 都不会再执行。 - ], - "false": [ // 否则,显示选择页面 - {"type": "choices", "text": "\t[老人,woman]少年,你需要钥匙吗?\n我这里有大把的!", // 显示一个选择页面 - "choices": [ // 提供四个选项:黄钥匙、蓝钥匙、红钥匙、离开。前三个选项显示需要的金额 - {"text": "黄钥匙(${9+flag:woman_times}金币)", "action": [ // 第一个选项,黄钥匙 - // 选择该选项的执行内容 - // 条件判断:钱够不够 - {"type": "if", "condition": "status:money>=9+flag:woman_times", + "2,11": [ + "\t[杰克,thief]喂!醒醒!快醒醒!", + { + "type": "setFg", + "time": 1500 + }, + "\t[hero]额,我这是在什么地方?", + "\t[杰克,thief]你被魔王抓了起来扔进了监狱,和我关在了一起,但是幸运的是我在昨天刚刚挖好一条越狱的暗道!", + { + "type": "openDoor", + "loc": [ + 3, + 11 + ] + }, + { + "type": "sleep", + "time": 300 + }, + "\t[杰克,thief]我先走了,祝你好运!", + { + "type": "move", + "time": 750, + "steps": [ + { + "direction": "right", + "value": 2 + }, + "down" + ] + }, + "上面是个move事件,可以对NPC等进行移动。\n详见样板中小偷事件的写法。", + "\t[hero]怎么跑的这么快..." + ], + "4,2": [ + "\t[老人,man]本塔的商店有两类,全局商店和非全局商店。\n\n所谓非全局商店,就类似于右下角那个卖钥匙的老人一样,一定要碰到才能触发事件。\n\n而全局商店,则能在快捷商店中直接使用。", + "\t[老人,man]要注册一个全局商店,你需要在 data.js 中,找到 shops,并在内添加你的商店信息。", + "\t[老人,man]商店信息添加后,可以在需要的事件处调用{\"type\": \"openShop\"}来打开你添加的全局商店。", + "\t[老人,man]在上面的例子里,左边是一个仿50层的金币商店,右边是一个仿24层的经验商店。\n\n商店被访问后即可在快捷商店中进行使用。", + "\t[老人,man]如果你需要在某层暂时禁用快捷商店,可以在data.js中设置cannotUseQuickShop。\n如果需要永久禁用商店,请使用{\"type\":\"disableShop\"}", + { + "type": "hide", + "time": 500 + } + ], + "1,0": [ + { + "type": "openShop", + "id": "moneyShop1" + } + ], + "5,0": [ + { + "type": "openShop", + "id": "expShop1" + } + ], + "7,7": [ + "\t[老人,man]这是一个典型的杀怪开门、强制战斗事件。", + { + "type": "hide" + } + ], + "8,7": { + "enable": false, + "data": [] + }, + "9,7": [ + { + "type": "show", + "loc": [ + 8, + 7 + ] + }, + { + "type": "hide" + } + ], + "10,4": [ + "\t[blackKing]你终于还是来了。", + "\t[hero]放开我们的公主!", + "\t[blackKing]如果我不愿意呢?", + "\t[hero]无需多说,拔剑吧!", + { + "type": "battle", + "id": "blackKing" + }, + { + "type": "hide", + "loc": [ + 10, + 2 + ] + }, + { + "type": "openDoor", + "loc": [ + 8, + 7 + ] + }, + "\t[blackKing]没想到你已经变得这么强大了... 算你厉害。\n公主就交给你了,请好好对她。", + { + "type": "hide" + } + ], + "10,0": [ + "\t[hero]公主,我来救你了~", + "\t[公主,princess]快救我出去!我受够这里了!", + "\t[hero]公主别怕,我们走吧~", + { + "type": "win", + "reason": "救出公主" + } + ], + "6,12": { + "enable": false, + "data": [] + }, + "6,11": [ + "\t[仙子,fairy]通过调用 {\"type\": \"show\"} 可以使隐藏的事件显示出来。\n比如我下面这个机关门。", + { + "type": "show", + "loc": [ + 6, + 12 + ] + }, + "\t[仙子,fairy]通过调用 {\"type\": \"openDoor\"} 可以无需钥匙打开一扇门或暗墙。", + { + "type": "openDoor", + "loc": [ + 6, + 12 + ] + }, + "\t[仙子,fairy]同时,也可以对其它层进行操作,比如楼下的机关门,现在已经为你打开了。", + { + "type": "openDoor", + "loc": [ + 11, + 10 + ], + "floorId": "sample0" + }, + "\t[仙子,fairy]如果 show 或 hide 指定了 time 参数,则以动画效果显示,指定的参数作为消失时间(毫秒)来计算。", + "\t[仙子,fairy]现在到楼下来找我吧~", + { + "type": "show", + "loc": [ + 12, + 10 + ], + "floorId": "sample0" + }, + { + "type": "hide", + "time": 500 + } + ], + "8,11": [ + { + "type": "setValue", + "name": "flag:man_times", + "value": "flag:man_times+1" + }, + "\t[老人,man]在文字中使用${' ${ '}和 } 可以计算并显示一个表达式的结果。\n", + "\t[老人,man]例如:\n你的当前攻击力是${status:atk},防御力是${status:def}。\n攻防和的十倍是${10*(status:atk+status:def)},攻防之积是${status:atk*status:def}。\n你有${item:yellowKey}把黄钥匙,${item:blueKey}把蓝钥匙,${item:redKey}把红钥匙。\n你有${item:pickaxe}个破,${item:bomb}个炸,${item:centerFly}个飞。\n这是你第${flag:man_times}次和我对话。", + "\t[老人,man]同时,你也可以通过{\"type\": \"setValue\"}来设置一个勇士的属性、道具,或某个Flag。", + "\t[老人,man]例如:\n现在我将让你的攻防提升50%,再将攻防和的十倍加到生命值上。", + { + "type": "setValue", + "name": "status:atk", + "value": "status:atk*1.5" + }, + { + "type": "setValue", + "name": "status:def", + "value": "status:def*1.5" + }, + { + "type": "setValue", + "name": "status:hp", + "value": "status:hp+10*(status:atk+status:def)" + }, + "\t[老人,man]再送你500金币,1000经验,1破2炸3飞!", + { + "type": "setValue", + "name": "status:money", + "value": "status:money+500" + }, + { + "type": "setValue", + "name": "status:experience", + "value": "status:experience+1000" + }, + { + "type": "setValue", + "name": "item:pickaxe", + "value": "item:pickaxe+1" + }, + { + "type": "setValue", + "name": "item:bomb", + "value": "item:bomb+2" + }, + { + "type": "setValue", + "name": "item:centerFly", + "value": "item:centerFly+3" + }, + "\t[老人,man]status:xxx 代表勇士的某个属性。\n其中xxx可取hp, atk, def, mdef, money,experience这几项。\n\nitem:xxx 代表勇士的某个道具的个数。\nxxx为道具ID,具体可参见items.js中的定义。\n\nflag:xxx 代表某个自定义Flag或变量。\nxxx为Flag/变量名,可以自行定义,由字母、数字和下划线组成。\n未定义过而直接取用的Flag默认值为false。", + "\t[老人,man]你现在可以重新和我进行对话,进一步看到属性值的改变。" + ], + "10,11": [ + { + "type": "if", + "condition": "flag:woman_times==0", + "true": [ + "\t[老人,woman]这是个很复杂的例子,它将教会你如何使用if 语句进行条件判断,以及 choices 提供选项来供用户进行选择。", + "\t[老人,woman]第一次访问我将显示这段文字;从第二次开始将会向你出售钥匙。\n钥匙价格将随着访问次数递增。\n当合计出售了七把钥匙后,将送你一把大黄门钥匙,并消失不再出现。", + "\t[老人,woman]这部分的逻辑比较长,请细心看样板的写法,是很容易看懂并理解的。" + ], + "false": [ + { + "type": "if", + "condition": "flag:woman_times==8", + "true": [ + "\t[老人,woman]你购买的钥匙已经够多了,再继续卖给你的话我会有危险的。", + "\t[老人,woman]看在你贡献给我这么多钱的份上,送你一把大黄门钥匙吧,希望你能好好用它。", + { + "type": "setValue", + "name": "item:bigKey", + "value": "item:bigKey+1" + }, + "\t[老人,woman]我先走了,拜拜~", + { + "type": "hide", + "time": 500 + }, + { + "type": "exit" + } + ], + "false": [ + { + "type": "choices", + "text": "\t[老人,woman]少年,你需要钥匙吗?\n我这里有大把的!", + "choices": [ + { + "text": "黄钥匙(${9+flag:woman_times}金币)", + "action": [ + { + "type": "if", + "condition": "status:money>=9+flag:woman_times", "true": [ - {"type": "setValue", "name": "status:money", "value": "status:money-(9+flag:woman_times)"}, // 扣减金钱 - {"type": "setValue", "name": "item:yellowKey", "value": "item:yellowKey+1"}, // 增加黄钥匙 - // 然后会继续执行下面的setValue来增加商人访问次数 + { + "type": "setValue", + "name": "status:money", + "value": "status:money-(9+flag:woman_times)" + }, + { + "type": "setValue", + "name": "item:yellowKey", + "value": "item:yellowKey+1" + } ], "false": [ "\t[老人,woman]你的金钱不足!", - {"type": "revisit"} // 直接重新访问;不执行下面的setValue来增加访问次数 + { + "type": "revisit" + } ] } - ]}, - {"text": "蓝钥匙(${18+2*flag:woman_times}金币)", "action": [ // 第二个选项:蓝钥匙 - // 逻辑和上面黄钥匙完全相同,不赘述 - {"type": "if", "condition": "status:money>=18+2*flag:woman_times", + ] + }, + { + "text": "蓝钥匙(${18+2*flag:woman_times}金币)", + "action": [ + { + "type": "if", + "condition": "status:money>=18+2*flag:woman_times", "true": [ - {"type": "setValue", "name": "status:money", "value": "status:money-(18+2*flag:woman_times)"}, - {"type": "setValue", "name": "item:blueKey", "value": "item:blueKey+1"}, + { + "type": "setValue", + "name": "status:money", + "value": "status:money-(18+2*flag:woman_times)" + }, + { + "type": "setValue", + "name": "item:blueKey", + "value": "item:blueKey+1" + } ], "false": [ "\t[老人,woman]你的金钱不足!", - {"type": "revisit"} + { + "type": "revisit" + } ] } - ]}, - {"text": "红钥匙(${36+4*flag:woman_times}金币)", "action": [ // 第三个选项:红钥匙 - // 逻辑和上面黄钥匙完全相同,不赘述 - {"type": "if", "condition": "status:money>=36+4*flag:woman_times", + ] + }, + { + "text": "红钥匙(${36+4*flag:woman_times}金币)", + "action": [ + { + "type": "if", + "condition": "status:money>=36+4*flag:woman_times", "true": [ - {"type": "setValue", "name": "status:money", "value": "status:money-(36+4*flag:woman_times)"}, - {"type": "setValue", "name": "item:redKey", "value": "item:redKey+1"}, + { + "type": "setValue", + "name": "status:money", + "value": "status:money-(36+4*flag:woman_times)" + }, + { + "type": "setValue", + "name": "item:redKey", + "value": "item:redKey+1" + } ], "false": [ "\t[老人,woman]你的金钱不足!", - {"type": "revisit"} + { + "type": "revisit" + } ] } - ]}, - {"text": "离开", "action": [ // 第四个选项:离开 - {"type": "exit"} // 立刻结束当前事件 - ]} - ] - } - ] - } - ] - }, - {"type": "setValue", "name": "flag:woman_times", "value": "flag:woman_times+1"}, // 增加该商人的访问次数。 - {"type": "revisit"} // 立即重新开始这个事件 - ], - "12,11": [ // 自定义事件的老人 - "\t[老人,womanMagician]使用 {\"type\":\"function\"} 可以写自定义的JS脚本。\n本塔支持的所有主要API会在doc文档内给出。", - "\t[老人,womanMagician]例如这个例子:即将弹出一个输入窗口,然后会将你的输入结果直接加到你的攻击力上。", - /* - {"type": "function", "function": function() { // 自己写JS脚本并执行 - - // 注意一下prompt对于录像是如何处理的 - var value; - if (core.status.replay.replaying) { - var action = core.status.replay.toReplay.shift(); - if (action.indexOf("input:")==0 ) { - value=parseInt(action.substring(6)); - } - else { - core.stopReplay(); - core.drawTip("录像文件出错"); - return; - } + ] + }, + { + "text": "离开", + "action": [ + { + "type": "exit" + } + ] + } + ] + } + ] } - else { - value = prompt("请输入你要加攻击力的数值:"); + ] + }, + { + "type": "setValue", + "name": "flag:woman_times", + "value": "flag:woman_times+1" + }, + { + "type": "revisit" + } + ], + "12,11": [ + "\t[老人,womanMagician]使用 {\"type\":\"function\"} 可以写自定义的JS脚本。\n本塔支持的所有主要API会在doc文档内给出。", + "\t[老人,womanMagician]例如这个例子:即将弹出一个输入窗口,然后会将你的输入结果直接加到你的攻击力上。", + { + "type": "input", + "text": "请输入你要加攻击力的数值:" + }, + { + "type": "if", + "condition": "flag:input>0", + "true": [ + { + "type": "setValue", + "name": "status:atk", + "value": "status:atk+flag:input" + }, + { + "type": "tip", + "text": "操作成功,攻击+${flag:input}" + }, + "操作成功,攻击+${flag:input}" + ], + "false": [] + }, + "\t[老人,womanMagician]具体可参见样板中本事件的写法。" + ], + "10,12": null, + "12,12": [ + { + "type": "switch", + "condition": "flag:woman_times", + "caseList": [ + { + "case": "0", + "action": [ + "\t[老人,woman]现在使用switch改写这个例子" + ] + }, + { + "case": "8", + "action": [ + "\t[老人,woman]你购买的钥匙已经够多了,再继续卖给你的话我会有危险的。", + "\t[老人,woman]看在你贡献给我这么多钱的份上,送你一把大黄门钥匙吧,希望你能好好用它。", + { + "type": "setValue", + "name": "item:bigKey", + "value": "item:bigKey+1" + }, + "\t[老人,woman]我先走了,拜拜~", + { + "type": "hide", + "time": 500 + }, + { + "type": "exit" + } + ] + }, + { + "case": "default", + "action": [ + { + "type": "comment", + "text": "当没有符合的值的场合执行此事件" + }, + { + "type": "choices", + "text": "\t[老人,woman]少年,你需要钥匙吗?\n我这里有大把的!", + "choices": [ + { + "text": "黄钥匙(${9+flag:woman_times}金币)", + "action": [ + { + "type": "if", + "condition": "status:money>=9+flag:woman_times", + "true": [ + { + "type": "setValue", + "name": "status:money", + "value": "status:money-(9+flag:woman_times)" + }, + { + "type": "setValue", + "name": "item:yellowKey", + "value": "item:yellowKey+1" + } + ], + "false": [ + "\t[老人,woman]你的金钱不足!", + { + "type": "revisit" + } + ] + } + ] + }, + { + "text": "蓝钥匙(${18+2*flag:woman_times}金币)", + "action": [ + { + "type": "if", + "condition": "status:money>=18+2*flag:woman_times", + "true": [ + { + "type": "setValue", + "name": "status:money", + "value": "status:money-(18+2*flag:woman_times)" + }, + { + "type": "setValue", + "name": "item:blueKey", + "value": "item:blueKey+1" + } + ], + "false": [ + "\t[老人,woman]你的金钱不足!", + { + "type": "revisit" + } + ] + } + ] + }, + { + "text": "红钥匙(${36+4*flag:woman_times}金币)", + "action": [ + { + "type": "if", + "condition": "status:money>=36+4*flag:woman_times", + "true": [ + { + "type": "setValue", + "name": "status:money", + "value": "status:money-(36+4*flag:woman_times)" + }, + { + "type": "setValue", + "name": "item:redKey", + "value": "item:redKey+1" + } + ], + "false": [ + "\t[老人,woman]你的金钱不足!", + { + "type": "revisit" + } + ] + } + ] + }, + { + "text": "离开", + "action": [ + { + "type": "exit" + } + ] + } + ] + } + ] } - value = parseInt(value)||0; - core.status.route.push("input:"+value); - - if (value>0) { // 检查 - core.setStatus("atk", core.getStatus("atk")+value); - // core.updateStatusBar(); // 和下面的 {"type": "update"} 等价,立即更新状态栏和地图显伤 - core.drawTip("操作成功,攻击+"+value); // 左上角气泡提示 - core.events.insertAction([ // 往当前事件列表前插入两条事件 - {"type": "update"}, // 更新状态栏和地图显伤 - "操作成功,攻击+"+value // 对话框提示 - ]); - } - }}, - */ - {"type": "input", "text": "请输入你要加攻击力的数值:"}, - {"type": "if", "condition": "flag:input>0", - "true": [ - {"type": "setValue", "name": "status:atk", "value": "status:atk+flag:input"}, - {"type": "tip", "text": "操作成功,攻击+${flag:input}"}, - "操作成功,攻击+${flag:input}" - ], - "false": [ - - ] - }, - "\t[老人,womanMagician]具体可参见样板中本事件的写法。" + ] + }, + { + "type": "setValue", + "name": "flag:woman_times", + "value": "flag:woman_times+1" + }, + { + "type": "revisit" + } + ] +}, +"changeFloor": { + "4,12": { + "floorId": "sample0", + "loc": [ + 6, + 0 ] }, - "changeFloor": { // 楼层转换事件;该事件不能和上面的events有冲突(同位置点),否则会被覆盖 - "4,12": {"floorId": "sample0", "loc": [6,0]}, // 由于楼下有多个上楼梯,所以需指定位置而不是简单地写"stair": "upFloor" - "5,5": {"floorId": "sample2", "stair": "downFloor", "direction": "up"} + "5,5": { + "floorId": "sample2", + "stair": "downFloor", + "direction": "up" }, - "afterBattle": { // 战斗后可能触发的事件列表 - "9,6": [ // 初级卫兵1 - {"type": "setValue", "name": "flag:door", "value": "flag:door+1"}, // 将"door"这个自定义flag加一 - {"type": "if", "condition": "flag:door==2", // 一个条件判断事件,条件是"door"这个flag值等于2 - "true": [ // 如果条件成立:打开机关门 - {"type": "openDoor", "loc": [10,5]} - ], - "false": [] // 如果条件不成立则无事件触发 - }, - ], - "11,6": [ // 初级卫兵2;注意由于打怪顺序问题,可能都得写一遍。 - {"type": "setValue", "name": "flag:door", "value": "flag:door+1"}, // 将"door"这个自定义flag加一 - {"type": "if", "condition": "flag:door==2", // 一个条件判断事件,条件是"door"这个flag值等于2 - "true": [ // 如果条件成立:打开机关门 - {"type": "openDoor", "loc": [10,5]} - ], - "false": [] // 如果条件不成立则无事件触发 - }, - ], - }, - "afterGetItem": { // 获得道具后可能触发的事件列表 + "10,12": null +}, +"afterBattle": { + "9,6": [ + { + "type": "setValue", + "name": "flag:door", + "value": "flag:door+1" + }, + { + "type": "if", + "condition": "flag:door==2", + "true": [ + { + "type": "openDoor", + "loc": [ + 10, + 5 + ] + } + ], + "false": [] + } + ], + "11,6": [ + { + "type": "setValue", + "name": "flag:door", + "value": "flag:door+1" + }, + { + "type": "if", + "condition": "flag:door==2", + "true": [ + { + "type": "openDoor", + "loc": [ + 10, + 5 + ] + } + ], + "false": [] + } + ], + "10,12": null +}, +"afterGetItem": { + "10,12": null +}, +"afterOpenDoor": { + "10,12": null +}, +"cannotMove": { + "10,12": null +}, +"bgmap": [ - }, - "afterOpenDoor": { // 开完门后可能触发的事件列表 - - }, - "cannotMove": { // 每个图块不可通行的方向 - // 可以在这里定义每个点不能前往哪个方向,例如悬崖边不能跳下去 - // "x,y": ["up", "left"], // (x,y)点不能往上和左走 - - }, -} +], +"fgmap": [ +], +} \ No newline at end of file diff --git a/project/functions.js b/project/functions.js index 59ad43f7..ca618442 100644 --- a/project/functions.js +++ b/project/functions.js @@ -817,7 +817,11 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 进阶 if (core.flags.enableLevelUp && core.status.hero.lv