From c9fe2f6177640e77eb31ae7f36fe56bb6714d5ef Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 4 Dec 2018 13:23:02 +0800 Subject: [PATCH 01/81] Remove starttime --- libs/actions.js | 6 ------ libs/events.js | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index 5b8a3ede..d4f024a3 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -780,12 +780,6 @@ 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; diff --git a/libs/events.js b/libs/events.js index a1a3184a..6bdecb9a 100644 --- a/libs/events.js +++ b/libs/events.js @@ -344,7 +344,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, 'startTime': new Date().getTime() + ], 'x': x, 'y': y, 'callback': callback }} // 停止勇士 From 68c8ef12bca7cc12bb7be3599906a7c296a02a56 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 4 Dec 2018 15:50:13 +0800 Subject: [PATCH 02/81] saveIndex2 -> saveIndex --- libs/actions.js | 8 ++++---- libs/control.js | 8 ++++---- libs/items.js | 34 +++++++++++++++++++++++++--------- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index d4f024a3..ceee4f34 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -2243,14 +2243,14 @@ actions.prototype.clickStorageRemove = function (x, y) { core.ui.closePanel(); core.drawText("\t[操作成功]你的所有存档已被清空。"); core.status.saveIndex = 1; - core.setLocalStorage('saveIndex2', 1); + core.removeLocalStorage('saveIndex'); }); } else { localStorage.clear(); core.drawText("\t[操作成功]你的所有存档已被清空。"); core.status.saveIndex = 1; - core.setLocalStorage('saveIndex2', 1); + core.removeLocalStorage('saveIndex'); } break; case 1: @@ -2264,7 +2264,7 @@ actions.prototype.clickStorageRemove = function (x, y) { core.ui.closePanel(); core.drawText("\t[操作成功]当前塔的存档已被清空。"); core.status.saveIndex = 1; - core.setLocalStorage('saveIndex2', 1); + core.removeLocalStorage('saveIndex'); }); } else { @@ -2275,7 +2275,7 @@ actions.prototype.clickStorageRemove = function (x, y) { core.removeLocalStorage("autoSave"); core.drawText("\t[操作成功]当前塔的存档已被清空。"); core.status.saveIndex = 1; - core.setLocalStorage('saveIndex2', 1); + core.removeLocalStorage('saveIndex'); } break; case 2: diff --git a/libs/control.js b/libs/control.js index 56bdff04..c380fb3b 100644 --- a/libs/control.js +++ b/libs/control.js @@ -350,7 +350,7 @@ control.prototype.resetStatus = function(hero, hard, floorId, route, maps, value if (core.isset(route)) core.status.route = route; // 保存的Index - core.status.saveIndex = core.getLocalStorage('saveIndex2', 1); + core.status.saveIndex = core.getLocalStorage('saveIndex', 1); if (core.isset(values)) core.values = core.clone(values); @@ -2199,7 +2199,7 @@ control.prototype.save = function(need) { control.prototype.load = function (need) { if (core.isset(core.status.replay)&&core.status.replay.replaying) return; - var saveIndex = core.getLocalStorage('saveIndex2', 1); + var saveIndex = core.getLocalStorage('saveIndex', 1); var page=parseInt((saveIndex-1)/5), offset=saveIndex-5*page; // 游戏开始前读档 @@ -2251,7 +2251,7 @@ control.prototype.doSL = function (id, type) { core.drawTip('存档成功!'); if (id!="autoSave") { core.status.saveIndex=id; - core.setLocalStorage('saveIndex2', core.status.saveIndex); + core.setLocalStorage('saveIndex', core.status.saveIndex); } }, function(err) { console.info(err); @@ -2288,7 +2288,7 @@ control.prototype.doSL = function (id, type) { core.drawTip("读档成功"); if (id!="autoSave") { core.status.saveIndex=id; - core.setLocalStorage('saveIndex2', core.status.saveIndex); + core.setLocalStorage('saveIndex', core.status.saveIndex); } }); }, function(err) { diff --git a/libs/items.js b/libs/items.js index ea6fcd59..49860bda 100644 --- a/libs/items.js +++ b/libs/items.js @@ -72,7 +72,12 @@ items.prototype.useItem = function (itemId, callback) { var itemCls = core.material.items[itemId].cls; if (itemId in this.useItemEffect) { - eval(this.useItemEffect[itemId]); + try { + eval(this.useItemEffect[itemId]); + } + catch (e) { + console.log(e); + } } // 记录路线 if (itemId!='book' && itemId!='fly') { @@ -96,7 +101,12 @@ items.prototype.canUseItem = function (itemId) { if (!core.hasItem(itemId)) return false; if (itemId in this.canUseItemEffect) { - return eval(this.canUseItemEffect[itemId]); + try { + return eval(this.canUseItemEffect[itemId]); + } + catch (e) { + console.log(e); + } } return false; @@ -121,7 +131,7 @@ items.prototype.hasEquip = function (itemId) { if (!core.isset(itemId)) return null; if (!core.isset((core.material.items[itemId]||{}).equip)) return null; - return itemId == this.getEquip(core.material.items[itemId].equip.type); + return this.getEquip(core.material.items[itemId].equip.type) == itemId; } ////// 获得某个装备类型的当前装备 ////// @@ -132,14 +142,13 @@ items.prototype.getEquip = function (equipType) { ////// 设置某个物品的个数 ////// items.prototype.setItem = function (itemId, itemNum) { itemNum = itemNum || 0; - if (itemNum<=0) itemNum = 0; var itemCls = core.material.items[itemId].cls; if (itemCls == 'items') return; if (!core.isset(core.status.hero.items[itemCls])) { core.status.hero.items[itemCls] = {}; } core.status.hero.items[itemCls][itemId] = itemNum; - if (itemCls!='keys' && itemNum==0) { + if (itemCls!='keys' && itemNum<=0) { delete core.status.hero.items[itemCls][itemId]; } } @@ -189,10 +198,17 @@ items.prototype.loadEquip = function (equipId, callback) { } var can = this.canEquip[equipId]; - if (core.isset(can) && !eval(can)) { - core.drawTip("当前不可换上"+loadEquip.name); - if (core.isset(callback)) callback(); - return; + if (core.isset(can)) { + try { + if (!eval(can)) { + core.drawTip("当前不可换上"+loadEquip.name); + if (core.isset(callback)) callback(); + return; + } + } + catch (e) { + console.log(e); + } } core.playSound('equip.mp3'); From 84e7087f42aaeea2393a2f7320e8ad5e8b784123 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 4 Dec 2018 15:54:55 +0800 Subject: [PATCH 03/81] items number --- libs/items.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/libs/items.js b/libs/items.js index 49860bda..1453b562 100644 --- a/libs/items.js +++ b/libs/items.js @@ -87,7 +87,7 @@ items.prototype.useItem = function (itemId, callback) { // 道具使用完毕:删除 if (itemCls=='tools') core.status.hero.items[itemCls][itemId]--; - if (core.status.hero.items[itemCls][itemId]==0) + if (core.status.hero.items[itemCls][itemId]<=0) delete core.status.hero.items[itemCls][itemId]; core.updateStatusBar(); @@ -117,7 +117,7 @@ items.prototype.itemCount = function (itemId) { if (!core.isset(itemId) || !core.isset(core.material.items[itemId])) return 0; var itemCls = core.material.items[itemId].cls; if (itemCls=="items") return 0; - return core.isset(core.status.hero.items[itemCls][itemId]) ? core.status.hero.items[itemCls][itemId] : 0; + return core.status.hero.items[itemCls][itemId]||0; } ////// 是否存在某个物品 ////// @@ -148,9 +148,11 @@ items.prototype.setItem = function (itemId, itemNum) { core.status.hero.items[itemCls] = {}; } core.status.hero.items[itemCls][itemId] = itemNum; - if (itemCls!='keys' && itemNum<=0) { - delete core.status.hero.items[itemCls][itemId]; + if (core.status.hero.items[itemCls][itemId] <= 0) { + if (itemCls!='keys') delete core.status.hero.items[itemCls][itemId]; + else core.status.hero.items[itemCls][itemId] = 0; } + core.updateStatusBar(); } ////// 删除某个物品 ////// @@ -159,8 +161,9 @@ items.prototype.removeItem = function (itemId, itemNum) { if (!core.hasItem(itemId)) return false; var itemCls = core.material.items[itemId].cls; core.status.hero.items[itemCls][itemId]-=itemNum; - if (itemCls!='keys' && core.status.hero.items[itemCls][itemId]<=0) { - delete core.status.hero.items[itemCls][itemId]; + if (core.status.hero.items[itemCls][itemId] <= 0) { + if (itemCls!='keys') delete core.status.hero.items[itemCls][itemId]; + else core.status.hero.items[itemCls][itemId] = 0; } core.updateStatusBar(); return true; @@ -168,7 +171,7 @@ items.prototype.removeItem = function (itemId, itemNum) { ////// 增加某个物品的个数 ////// items.prototype.addItem = function (itemId, itemNum) { - itemNum=itemNum||1; + itemNum = itemNum || 1; var itemData = core.material.items[itemId]; var itemCls = itemData.cls; if (itemCls == 'items') return; @@ -180,9 +183,14 @@ items.prototype.addItem = function (itemId, itemNum) { core.status.hero.items[itemCls][itemId] = 0; } core.status.hero.items[itemCls][itemId] += itemNum; + if (core.status.hero.items[itemCls][itemId] <= 0) { + if (itemCls!='keys') delete core.status.hero.items[itemCls][itemId]; + else core.status.hero.items[itemCls][itemId] = 0; + } // 永久道具只能有一个 if (itemCls == 'constants' && core.status.hero.items[itemCls][itemId]>1) core.status.hero.items[itemCls][itemId] = 1; + core.updateStatusBar(); } From 4db79dec3fe19edc9600c3256e07295eeb640a2a Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 4 Dec 2018 18:16:19 +0800 Subject: [PATCH 04/81] Equipment percentage for each --- _server/data.comment.js | 14 ---------- docs/element.md | 26 +++++------------- libs/enemys.js | 13 ++++----- libs/items.js | 26 ++++++++++-------- libs/ui.js | 61 +++++++++++++++++++++++------------------ project/data.js | 1 - project/functions.js | 23 ++++++---------- 7 files changed, 70 insertions(+), 94 deletions(-) diff --git a/_server/data.comment.js b/_server/data.comment.js index 300a5fc0..7370b25f 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -522,20 +522,6 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_bool": "bool", "_data": "状态栏的装备按钮。若此项为true则将状态栏中的楼层转换器按钮换为装备栏按钮" }, - "equipPercentage": { - "_leaf": true, - "_type": "checkbox", - "_bool": "bool", - "_data": "装备增加百分比属性。如果此项为true,则装备属性全部按照百分比进行计算,比如\"atk\": 20意味着攻击增加20%。\n如果多个装备百分比增加同一个属性的,按加算处理。(即一个10%一个20%总共是30%而不是32%)" - }, - /* - "enableDeleteItem": { - "_leaf": true, - "_type": "checkbox", - "_bool": "bool", - "_data": "是否允许删除(丢弃)道具" - }, - */ "enableAddPoint": { "_leaf": true, "_type": "checkbox", diff --git a/docs/element.md b/docs/element.md index 254f8ad9..5a7189a3 100644 --- a/docs/element.md +++ b/docs/element.md @@ -47,8 +47,9 @@ 如果要将一个道具设置为装备,首先需要将其`cls`设为`equips`。 然后在图块属性的`equip`一项中设置装备的具体属性。该项写法如下: + ``` js -{"type": 0, "atk": 0, "def": 0, "mdef":0, "animate": "hand"} +{"type": 0, "atk": 0, "def": 0, "mdef":0, "animate": "hand", "percentage": true} ``` type为该装备的类型,必填,和上面装备栏一一对应。例如,0就是武器,2就是首饰等等。 @@ -57,35 +58,22 @@ atk/def/mdef为该装备分别增加的攻防魔防数值(支持负数); animate为该装备的攻击动画,仅对type为0时有效。具体可参见[动画和天气系统](#动画和天气系统)。 +percentage为该装备是否按比例增加属性。 + 下面是几个写法例子。 ``` js {"type": 0, "atk": 10} // 装备类型是武器,效果是攻击+10,使用默认的攻击动画 {"type": 0, "atk": 40, "animate": "sword"} // 装备类型为武器,效果是攻击+10,攻击动画是sword -{"type": 1, "def": 40} // 装备类型是防具,效果是防御+40 +{"type": 1, "def": 40, "percentage": true} // 装备类型是防具,效果是防御提升40% {"type": 1, "def": 100, "mdef": 100} // 装备类型是防具,效果是防御和魔防各+100 {"type": 3, "atk": -20, "def": 50, "mdef": 50} // 装备类型是魔杖,效果是攻击-20,防御和魔防各+50 -``` - -### 装备按比例增加属性 - -从V2.4.2开始,装备可以选择按照比例来增加属性。 - -在全塔属性中有个`equipPercentage`开关,如果将其打开,则会所有值都按照比例计算。(也就是类似Buff一样) - -例如,上面的例子就变成了: - -``` js -{"type": 0, "atk": 10} // 装备类型是武器,效果是攻击提升10%,使用默认的攻击动画 -{"type": 0, "atk": 40, "animate": "sword"} // 装备类型为武器,效果是攻击提升40%,攻击动画是sword -{"type": 1, "def": 40} // 装备类型是防具,效果是防御提升40% -{"type": 1, "def": 100, "mdef": 100} // 装备类型是防具,效果是防御和魔防各提升100% -{"type": 3, "atk": -20, "def": 50, "mdef": 50} // 装备类型是魔杖,效果是攻击下降20%,防御和魔防各提升50% +{"type": 2, "atk": -20, "def": 50, "mdef": 50, "percentage": true} // 装备类型是魔杖,效果是攻击下降20%,防御和魔防各提升50% ``` 所有取值全部向下取整。 -值得注意的是:多装备增加同一属性使用加法计算;也就是比如武器增加30%攻击,防具增加10%攻击,最终合起来增加的是40%而不是43%的属性。 +值得注意的是,如果多个装备同时按比例增加属性,使用加法计算。比如武器增加30%攻击,防具增加10%攻击,最终合起来增加的是40%而不是43%的属性。 ### 检测是否存在装备 diff --git a/libs/enemys.js b/libs/enemys.js index c6dd1311..a3097af3 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -164,9 +164,7 @@ enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId) { for (var t = turn-1;t>=1;t--) { var nextAtk = Math.ceil(mon_hp/t) + mon_def; // 装备提升比例的计算临界 - if (core.flags.equipPercentage) { - nextAtk = Math.ceil(nextAtk / core.getFlag('equip_atk_buff', 1)); - } + nextAtk = Math.ceil(nextAtk / core.getFlag('equip_atk_buff', 1)); if (nextAtk<=hero_atk) break; if (nextAtk!=pre) { var nextInfo = this.getDamageInfo(enemy, core.status.hero.hp, nextAtk, core.status.hero.def, core.status.hero.mdef, x, y, floorId); @@ -257,11 +255,10 @@ enemys.prototype.getCurrentEnemys = function (floorId) { var mon_hp = enemy.hp, mon_atk = enemy.atk, mon_def = enemy.def; var hero_atk = core.status.hero.atk, hero_def = core.status.hero.def, hero_mdef = core.status.hero.mdef; - if (core.flags.equipPercentage) { - hero_atk = Math.floor(core.getFlag('equip_atk_buff',1)*hero_atk); - hero_def = Math.floor(core.getFlag('equip_def_buff',1)*hero_def); - hero_mdef = Math.floor(core.getFlag('equip_mdef_buff',1)*hero_mdef); - } + hero_atk = Math.floor(core.getFlag('equip_atk_buff',1)*hero_atk); + hero_def = Math.floor(core.getFlag('equip_def_buff',1)*hero_def); + hero_mdef = Math.floor(core.getFlag('equip_mdef_buff',1)*hero_mdef); + var enemyInfo = this.getEnemyInfo(enemy, core.status.hero.hp, hero_atk, hero_def, hero_mdef, null, null, floorId); var specialText = core.enemys.getSpecialText(enemyId); diff --git a/libs/items.js b/libs/items.js index 1453b562..fcba3daa 100644 --- a/libs/items.js +++ b/libs/items.js @@ -199,8 +199,8 @@ items.prototype.loadEquip = function (equipId, callback) { if (!core.isset(core.status.hero.equipment)) core.status.hero.equipment = []; - var loadEquip = core.material.items[equipId]; - if (!core.isset(loadEquip)) { + var loadEquip = core.material.items[equipId]||{}; + if (!core.isset(loadEquip.equip)) { if (core.isset(callback)) callback(); return; } @@ -223,11 +223,21 @@ items.prototype.loadEquip = function (equipId, callback) { var loadEquipType = loadEquip.equip.type; var unloadEquipId = core.status.hero.equipment[loadEquipType]; + var unloadEquip = core.material.items[unloadEquipId] || {}; + + // ------ 如果当前装备和目标装备的模式不同(一个百分比一个数值),则需要先脱再穿 ------ // + if (core.isset(unloadEquip.equip) && (unloadEquip.equip.percentage||false) != (loadEquip.equip.percentage||false)) { + this.unloadEquip(loadEquipType); + this.loadEquip(equipId); + if (core.isset(callback)) callback(); + return; + } + // 下面保证了两者的模式是相同的 // 比较能力值 var result = core.compareEquipment(equipId,unloadEquipId); - if (core.flags.equipPercentage) { + if (loadEquip.equip.percentage) { core.setFlag('equip_atk_buff', core.getFlag('equip_atk_buff',1)+result.atk/100); core.setFlag('equip_def_buff', core.getFlag('equip_def_buff',1)+result.def/100); core.setFlag('equip_mdef_buff', core.getFlag('equip_mdef_buff',1)+result.mdef/100); @@ -242,9 +252,6 @@ items.prototype.loadEquip = function (equipId, callback) { core.status.hero.equipment[loadEquipType] = equipId; core.updateStatusBar(); - // 记录路线 - // core.status.route.push("equip:"+equipId); - // 装备更换完毕:删除换上的装备 core.removeItem(equipId); @@ -269,10 +276,10 @@ items.prototype.unloadEquip = function (equipType, callback) { if (core.isset(callback)) callback(); return; } - var unloadEquip = core.material.items[unloadEquipId]; + var unloadEquip = core.material.items[unloadEquipId] || {}; // 处理能力值改变 - if (core.flags.equipPercentage) { + if (unloadEquip.equip.percentage) { core.setFlag('equip_atk_buff', core.getFlag('equip_atk_buff',1)-(unloadEquip.equip.atk||0)/100); core.setFlag('equip_def_buff', core.getFlag('equip_def_buff',1)-(unloadEquip.equip.def||0)/100); core.setFlag('equip_mdef_buff', core.getFlag('equip_mdef_buff',1)-(unloadEquip.equip.mdef||0)/100); @@ -287,9 +294,6 @@ items.prototype.unloadEquip = function (equipType, callback) { core.status.hero.equipment[equipType] = null; core.updateStatusBar(); - - // 记录路线 - // core.status.route.push("unEquip:"+equipType); // 装备更换完毕:增加卸下的装备 core.addItem(unloadEquipId, 1); diff --git a/libs/ui.js b/libs/ui.js index 635d0221..c6067779 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -966,11 +966,9 @@ ui.prototype.drawBattleAnimate = function(monsterId, callback) { hero_def=Math.max(0, hero_def); hero_mdef=Math.max(0, hero_mdef); - if (core.flags.equipPercentage) { - hero_atk = Math.floor(core.getFlag('equip_atk_buff',1)*hero_atk); - hero_def = Math.floor(core.getFlag('equip_def_buff',1)*hero_def); - hero_mdef = Math.floor(core.getFlag('equip_mdef_buff',1)*hero_mdef); - } + hero_atk = Math.floor(core.getFlag('equip_atk_buff',1)*hero_atk); + hero_def = Math.floor(core.getFlag('equip_def_buff',1)*hero_def); + hero_mdef = Math.floor(core.getFlag('equip_mdef_buff',1)*hero_mdef); var enemy = core.material.enemys[monsterId]; var enemyInfo = core.enemys.getEnemyInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef); @@ -2034,30 +2032,41 @@ ui.prototype.drawEquipbox = function(index) { // 比较属性 if (lines.length==1) { - var compare; + var compare, differentMode = false; if (index<12) compare = core.compareEquipment(null, selectId); else { - compare = core.compareEquipment(selectId, equipEquipment[equip.equip.type]); - } - var drawOffset = 10; - - [['攻击','atk'], ['防御','def'], ['魔防','mdef']].forEach(function (t) { - var title = t[0], name = t[1]; - if (!core.isset(compare[name]) || compare[name]==0) return; - var color = '#00FF00'; - if (compare[name]<0) color = '#FF0000'; - var nowValue = core.getStatus(name), newValue = nowValue + compare[name]; - if (core.flags.equipPercentage) { - var nowBuff = core.getFlag('equip_'+name+"_buff",1), newBuff = nowBuff+compare[name]/100; - nowValue = Math.floor(nowBuff*core.getStatus(name)); - newValue = Math.floor(newBuff*core.getStatus(name)); + var last = core.material.items[equipEquipment[equipType]]||{}; + // 检查是不是数值模式和比例模式之间的切换 + if (core.isset(last.equip) && (last.equip.percentage||false) != (equip.equip.percentage||false)) { + differentMode = true; } - var content = title + ' ' + nowValue + '->'; - core.fillText('ui', content, drawOffset, 89, '#CCCCCC', 'bold 14px '+globalFont); - drawOffset += core.canvas.ui.measureText(content).width; - core.fillText('ui', newValue, drawOffset, 89, color); - drawOffset += core.canvas.ui.measureText(newValue).width + 15; - }) + else { + compare = core.compareEquipment(selectId, equipEquipment[equipType]); + } + } + if (differentMode) { + core.fillText('ui', '<数值和比例模式之间的切换不显示属性变化>', 10, 89, '#CCCCCC', '14px '+globalFont); + } + else { + var drawOffset = 10; + [['攻击','atk'], ['防御','def'], ['魔防','mdef']].forEach(function (t) { + var title = t[0], name = t[1]; + if (!core.isset(compare[name]) || compare[name]==0) return; + var color = '#00FF00'; + if (compare[name]<0) color = '#FF0000'; + var nowValue = core.getStatus(name), newValue = nowValue + compare[name]; + if (equip.equip.percentage) { + var nowBuff = core.getFlag('equip_'+name+"_buff",1), newBuff = nowBuff+compare[name]/100; + nowValue = Math.floor(nowBuff*core.getStatus(name)); + newValue = Math.floor(newBuff*core.getStatus(name)); + } + var content = title + ' ' + nowValue + '->'; + core.fillText('ui', content, drawOffset, 89, '#CCCCCC', 'bold 14px '+globalFont); + drawOffset += core.canvas.ui.measureText(content).width; + core.fillText('ui', newValue, drawOffset, 89, color); + drawOffset += core.canvas.ui.measureText(newValue).width + 15; + }) + } } else { var leftText = text.substring(lines[0].length); diff --git a/project/data.js b/project/data.js index 9b4ac12e..41c36ba7 100644 --- a/project/data.js +++ b/project/data.js @@ -362,7 +362,6 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "bigKeyIsBox": false, "equipment": false, "equipboxButton": false, - "equipPercentage": false, "enableAddPoint": false, "enableNegativeDamage": false, "hatredDecrease": true, diff --git a/project/functions.js b/project/functions.js index ef3be11d..62ad87d6 100644 --- a/project/functions.js +++ b/project/functions.js @@ -484,12 +484,10 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = hero_def=Math.max(0, hero_def); hero_mdef=Math.max(0, hero_mdef); - // 装备按比例增加属性 - if (core.flags.equipPercentage) { - hero_atk = Math.floor(core.getFlag('equip_atk_buff',1)*hero_atk); - hero_def = Math.floor(core.getFlag('equip_def_buff',1)*hero_def); - hero_mdef = Math.floor(core.getFlag('equip_mdef_buff',1)*hero_mdef); - } + // 计算装备按比例增加属性后的数值 + hero_atk = Math.floor(core.getFlag('equip_atk_buff',1)*hero_atk); + hero_def = Math.floor(core.getFlag('equip_def_buff',1)*hero_def); + hero_mdef = Math.floor(core.getFlag('equip_mdef_buff',1)*hero_mdef); // 怪物的各项数据 // 对坚固模仿等处理扔到了脚本编辑-getEnemyInfo之中 @@ -809,16 +807,11 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 向下取整 if (core.isset(core.status.hero[item])) core.status.hero[item] = Math.floor(core.status.hero[item]); - // 大数据格式化 - core.statusBar[item].innerHTML = core.formatBigNumber(core.getStatus(item)); + // 装备按比例增加属性 + var value = Math.floor(core.getStatus(item)*core.getFlag('equip_'+item+'_buff',1)); + // 大数据格式化; + core.statusBar[item].innerHTML = core.formatBigNumber(value); }); - - // 装备按比例增加属性 - if (core.flags.equipPercentage) { - core.statusBar.atk.innerHTML = core.formatBigNumber(Math.floor(core.getFlag('equip_atk_buff',1)*core.getStatus('atk'))); - core.statusBar.def.innerHTML = core.formatBigNumber(Math.floor(core.getFlag('equip_def_buff',1)*core.getStatus('def'))); - core.statusBar.mdef.innerHTML = core.formatBigNumber(Math.floor(core.getFlag('equip_mdef_buff',1)*core.getStatus('mdef'))); - } // 设置魔力值 if (core.flags.enableMana) { From 105d73e0af8f874dad78f19a05819d9113546bc1 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 4 Dec 2018 18:57:02 +0800 Subject: [PATCH 05/81] non-null in location --- .gitignore | 2 +- _server/editor.js | 9 ++++++--- _server/editor_file.js | 6 +++++- project/maps.js | 4 +++- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 928ab591..cd2cdffd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ .vscode -*ce5eec52_2fa1_447b_8dad_764e267a7fab* .DS_Store +MTBuilder.app # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 diff --git a/_server/editor.js b/_server/editor.js index 3da2558c..6a125e2e 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -1009,6 +1009,7 @@ editor.prototype.listen = function () { editor.updateMap(); fields.forEach(function(v){ editor.currentFloorData[v][now.x+','+now.y]=editor.currentFloorData[v][last.x+','+last.y] + if (!core.isset(editor.currentFloorData[v][now.x+','+now.y])) delete editor.currentFloorData[v][now.x+','+now.y]; }) editor.file.saveFloorFile(function (err) { if (err) { @@ -1053,8 +1054,10 @@ editor.prototype.listen = function () { fields.forEach(function(v){ var temp_atsfcytaf=editor.currentFloorData[v][now.x+','+now.y]; - editor.currentFloorData[v][now.x+','+now.y]=editor.currentFloorData[v][last.x+','+last.y]; - editor.currentFloorData[v][last.x+','+last.y]=temp_atsfcytaf + if (!core.isset(editor.currentFloorData[v][last.x+','+last.y])) delete editor.currentFloorData[v][now.x+','+now.y]; + else editor.currentFloorData[v][now.x+','+now.y]=editor.currentFloorData[v][last.x+','+last.y]; + if (!core.isset(temp_atsfcytaf)) delete editor.currentFloorData[v][last.x+','+last.y]; + else editor.currentFloorData[v][last.x+','+last.y]=temp_atsfcytaf }) editor.file.saveFloorFile(function (err) { if (err) { @@ -1078,7 +1081,7 @@ editor.prototype.listen = function () { editor.map[now.y][now.x]=editor.info; editor.updateMap(); fields.forEach(function(v){ - editor.currentFloorData[v][now.x+','+now.y]=null; + delete editor.currentFloorData[v][now.x+','+now.y]; }) editor.file.saveFloorFile(function (err) { if (err) { diff --git a/_server/editor_file.js b/_server/editor_file.js index 3e938917..8178712c 100644 --- a/_server/editor_file.js +++ b/_server/editor_file.js @@ -901,7 +901,11 @@ editor_file = function (editor, callback) { } if (file == 'floors') { actionList.forEach(function (value) { - eval("editor.currentFloorData" + value[1] + '=' + JSON.stringify(value[2])); + // 检测null/undefined + if (core.isset(value[2])) + eval("editor.currentFloorData" + value[1] + '=' + JSON.stringify(value[2])); + else + eval("delete editor.currentFloorData"+value[1]); }); editor_file.saveFloorFile(callback); return; diff --git a/project/maps.js b/project/maps.js index d39bbf77..8056a76c 100644 --- a/project/maps.js +++ b/project/maps.js @@ -79,7 +79,9 @@ var maps_90f36752_8815_4be8_b32b_d7fad1d0542e = '65':{'cls': 'items', 'id': 'hammer'}, // 圣锤 '68':{'cls': 'items', 'id': 'lifeWand'}, // 生命魔杖 '69':{'cls': 'items', 'id': 'jumpShoes'}, // 生命魔杖 - '70':{'cls': 'items', 'id': 'skill1'}, // 技能:二倍斩 + '70':{'cls': 'items', 'id': 'sword0'}, + '71':{'cls': 'items', 'id': 'shield0'}, + '72':{'cls': 'items', 'id': 'skill1'}, // 技能:二倍斩 ////////////////////////// 门、楼梯、传送点部分 ////////////////////////// From fd909336732af6b367f28a735ddd88ad6f4163c0 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 4 Dec 2018 18:58:39 +0800 Subject: [PATCH 06/81] non-null in location --- _server/editor.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/_server/editor.js b/_server/editor.js index 6a125e2e..89049bbd 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -1009,7 +1009,6 @@ editor.prototype.listen = function () { editor.updateMap(); fields.forEach(function(v){ editor.currentFloorData[v][now.x+','+now.y]=editor.currentFloorData[v][last.x+','+last.y] - if (!core.isset(editor.currentFloorData[v][now.x+','+now.y])) delete editor.currentFloorData[v][now.x+','+now.y]; }) editor.file.saveFloorFile(function (err) { if (err) { @@ -1054,10 +1053,8 @@ editor.prototype.listen = function () { fields.forEach(function(v){ var temp_atsfcytaf=editor.currentFloorData[v][now.x+','+now.y]; - if (!core.isset(editor.currentFloorData[v][last.x+','+last.y])) delete editor.currentFloorData[v][now.x+','+now.y]; - else editor.currentFloorData[v][now.x+','+now.y]=editor.currentFloorData[v][last.x+','+last.y]; - if (!core.isset(temp_atsfcytaf)) delete editor.currentFloorData[v][last.x+','+last.y]; - else editor.currentFloorData[v][last.x+','+last.y]=temp_atsfcytaf + editor.currentFloorData[v][now.x+','+now.y]=editor.currentFloorData[v][last.x+','+last.y]; + editor.currentFloorData[v][last.x+','+last.y]=temp_atsfcytaf; }) editor.file.saveFloorFile(function (err) { if (err) { From ca05e48846a22df66f107559abef874164543631 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 4 Dec 2018 20:50:25 +0800 Subject: [PATCH 07/81] dblclick & highlight pos & WASD move --- _server/editor.js | 34 ++++++++++++++++++++++++++++++---- _server/editor_mode.js | 6 ++++-- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/_server/editor.js b/_server/editor.js index 89049bbd..6c92568c 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -275,6 +275,14 @@ editor.prototype.drawEventBlock = function () { } } +editor.prototype.drawPosSelection = function () { + this.drawEventBlock(); + var fg=document.getElementById('efg').getContext('2d'); + fg.strokeStyle = 'rgba(255,255,255,0.7)'; + fg.lineWidth = 4; + fg.strokeRect(32*editor.pos.x - core.bigmap.offsetX + 4, 32*editor.pos.y - core.bigmap.offsetY + 4, 24, 24); +} + editor.prototype.updateMap = function () { var blocks = main.editor.mapIntoBlocks(editor.map.map(function (v) { return v.map(function (v) { @@ -327,7 +335,7 @@ editor.prototype.moveViewport=function(x,y){ core.bigmap.offsetY = core.clamp(core.bigmap.offsetY+32*y, 0, 32*core.bigmap.height-416); core.control.updateViewport(); editor.buildMark(); - editor.drawEventBlock(); + editor.drawPosSelection(); } /////////// 通用 /////////// @@ -631,6 +639,15 @@ editor.prototype.listen = function () { eui.oncontextmenu=function(e){e.preventDefault()} + eui.ondblclick = function(e) { + // 双击地图可以选中素材 + var loc = eToLoc(e); + var pos = locToPos(loc,true); + var thisevent = editor.map[pos.y][pos.x]; + editor.setSelectBoxFromInfo(thisevent); + return; + } + eui.onmousedown = function (e) { if (e.button==2){ var loc = eToLoc(e); @@ -863,6 +880,15 @@ editor.prototype.listen = function () { printf('已保存该快捷图块, ctrl + '+(e.keyCode-48)+' 使用.') core.setLocalStorage('shortcut',shortcut); } + // wasd平移大地图 + if (e.keyCode==87) + editor.moveViewport(0,-1) + else if (e.keyCode==65) + editor.moveViewport(-1,0) + else if (e.keyCode==83) + editor.moveViewport(0,1); + else if (e.keyCode==68) + editor.moveViewport(1,0); } var dataSelection = document.getElementById('dataSelection'); @@ -1016,7 +1042,7 @@ editor.prototype.listen = function () { throw(err) } ;printf('复制事件成功'); - editor.drawEventBlock(); + editor.drawPosSelection(); }); } @@ -1062,7 +1088,7 @@ editor.prototype.listen = function () { throw(err) } ;printf('两位置的事件已互换'); - editor.drawEventBlock(); + editor.drawPosSelection(); }); } @@ -1086,7 +1112,7 @@ editor.prototype.listen = function () { throw(err) } ;printf('清空此点及事件成功'); - editor.drawEventBlock(); + editor.drawPosSelection(); }); } diff --git a/_server/editor_mode.js b/_server/editor_mode.js index 3dd40ece..94e65bee 100644 --- a/_server/editor_mode.js +++ b/_server/editor_mode.js @@ -206,7 +206,7 @@ editor_mode = function (editor) { throw(objs_.slice(-1)[0]) } ;printf('修改成功'); - editor.drawEventBlock(); + editor.drawPosSelection(); }); break; case 'enemyitem': @@ -286,6 +286,8 @@ editor_mode = function (editor) { editor_mode.dom[name].style = 'z-index:-1;opacity: 0;'; } editor_mode.dom[mode].style = ''; + // clear + editor.drawEventBlock(); if (editor_mode[mode]) editor_mode[mode](); document.getElementById('editModeSelect').value = mode; var tips = tip_in_showMode; @@ -307,7 +309,7 @@ editor_mode = function (editor) { var tableinfo = editor_mode.objToTable_(objs[0], objs[1]); document.getElementById('table_3d846fc4_7644_44d1_aa04_433d266a73df').innerHTML = tableinfo.HTML; tableinfo.listen(tableinfo.guids); - + editor.drawPosSelection(); if (Boolean(callback)) callback(); } From 7429ac3248792c1f8e463615d4c9f300aaa8165e Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 4 Dec 2018 20:56:39 +0800 Subject: [PATCH 08/81] hard label: break-line --- styles.css | 1 + 1 file changed, 1 insertion(+) diff --git a/styles.css b/styles.css index a1505d1e..4e3d174b 100644 --- a/styles.css +++ b/styles.css @@ -220,6 +220,7 @@ p#hard { font: bold normal 1.1em "Arial Black"; text-align: center; margin: 0 6px 6px 0; + word-break: keep-all; } span#poison, span#weak, span#curse, span#pickaxe, span#bomb, span#fly { From 9634e2c167c6cbe0126f5b4545eb05a7753727a3 Mon Sep 17 00:00:00 2001 From: oc Date: Wed, 5 Dec 2018 14:51:35 +0800 Subject: [PATCH 09/81] Hero move effect --- libs/control.js | 13 +++++++++++-- libs/core.js | 2 ++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/libs/control.js b/libs/control.js index c380fb3b..0c15502b 100644 --- a/libs/control.js +++ b/libs/control.js @@ -59,6 +59,7 @@ control.prototype.setRequestAnimationFrame = function () { core.animateFrame.boxTime = core.animateFrame.boxTime||timestamp; core.animateFrame.animateTime = core.animateFrame.animateTime||timestamp; core.animateFrame.moveTime = core.animateFrame.moveTime||timestamp; + core.animateFrame.lastLegTime = core.animateFrame.lastLegTime||timestamp; core.animateFrame.weather.time = core.animateFrame.weather.time||timestamp; // move time @@ -122,15 +123,23 @@ control.prototype.setRequestAnimationFrame = function () { } // Hero move - if (timestamp-core.animateFrame.moveTime>16 && core.isset(core.status.heroMoving) && core.status.heroMoving>0) { + if (core.isPlaying() && core.status.heroMoving>0) { var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'), direction = core.getHeroLoc('direction'); + + // 200ms换腿? + if (timestamp - core.animateFrame.moveTime > (core.values.moveSpeed||100)) { + core.animateFrame.leftLeg = !core.animateFrame.leftLeg; + core.animateFrame.moveTime = timestamp; + } + core.drawHero(direction, x, y, core.animateFrame.leftLeg?'leftFoot':'rightFoot', 4*core.status.heroMoving); + /* if (core.status.heroMoving<=4) { core.drawHero(direction, x, y, 'leftFoot', 4*core.status.heroMoving); } else if (core.status.heroMoving<=8) { core.drawHero(direction, x, y, 'rightFoot', 4*core.status.heroMoving); } - core.animateFrame.moveTime = timestamp; + */ } // weather diff --git a/libs/core.js b/libs/core.js index f6cfe375..6d01ebb9 100644 --- a/libs/core.js +++ b/libs/core.js @@ -34,6 +34,8 @@ function core() { 'boxTime': null, 'animateTime': null, 'moveTime': null, + 'lastLegTime': null, + 'leftLeg': true, 'speed': null, 'weather': { 'time': null, From a6a76715434a65aa0a4cffd18043b0926912ee1e Mon Sep 17 00:00:00 2001 From: oc Date: Wed, 5 Dec 2018 14:54:47 +0800 Subject: [PATCH 10/81] Space -> tab --- project/functions.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/project/functions.js b/project/functions.js index 62ad87d6..98fbcb24 100644 --- a/project/functions.js +++ b/project/functions.js @@ -677,7 +677,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = break; case 80: // P:查看评论 window.open("/score.php?name="+core.firstData.name+"&num=10", "_blank"); - break; + break; case 49: // 快捷键1: 破 if (core.hasItem('pickaxe')) { if (core.canUseItem('pickaxe')) { @@ -834,9 +834,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (core.flags.enableLevelUp && core.status.hero.lv Date: Wed, 5 Dec 2018 16:48:33 +0800 Subject: [PATCH 11/81] Async function --- _server/blockly/MotaAction.g4 | 9 +++++---- docs/event.md | 2 ++ libs/events.js | 17 +++++++++++------ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index c4c827c9..ad12ff1a 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -1490,15 +1490,16 @@ return code; function_s - : '自定义JS脚本' BGNL? Newline RawEvalString Newline BEND Newline + : '自定义JS脚本' '不自动执行下一个事件' Bool BGNL? Newline RawEvalString Newline BEND Newline /* function_s tooltip : 可双击多行编辑,请勿使用异步代码。常见API参见文档附录。 helpUrl : https://h5mota.com/games/template/docs/#/event?id=function%EF%BC%9A%E8%87%AA%E5%AE%9A%E4%B9%89js%E8%84%9A%E6%9C%AC -default : ["alert(core.getStatus(\"atk\"));"] +default : [false,"alert(core.getStatus(\"atk\"));"] colour : this.dataColor -var code = '{"type": "function", "function": "function(){\\n'+JSON.stringify(RawEvalString_0).slice(1,-1).split('\\\\n').join('\\n')+'\\n}"},\n'; +Bool_0 = Bool_0?', "async": true':''; +var code = '{"type": "function"'+Bool_0+', "function": "function(){\\n'+JSON.stringify(RawEvalString_0).slice(1,-1).split('\\\\n').join('\\n')+'\\n}"},\n'; return code; */; @@ -2225,7 +2226,7 @@ ActionParser.prototype.parseAction = function() { var func = data["function"]; func=func.split('{').slice(1).join('{').split('}').slice(0,-1).join('}').trim().split('\n').join('\\n'); this.next = MotaActionBlocks['function_s'].xmlText([ - func,this.next]); + data.async||false,func,this.next]); break; case "update": this.next = MotaActionBlocks['update_s'].xmlText([ diff --git a/docs/event.md b/docs/event.md index 7720332f..f2cb169f 100644 --- a/docs/event.md +++ b/docs/event.md @@ -1610,6 +1610,8 @@ core.insertAction([ // 请勿直接调用 core.changeFloor(toFloor, ...),这个代码是异步的,会导致事件处理和录像出问题! ``` +!> 从V2.5.3开始,提供了一个"不自动执行下一个事件"的选项(`"async": true`)。如果设置了此项,那么在该部分代码执行完毕后,不会立刻执行下一个事件。你需要在脚本中手动调用`core.events.doAction()`来执行下一个事件。可以通过此项来实现一些异步的代码,即在异步函数的回调中再执行下一个事件。使用此选项请谨慎,最好向开发者寻求咨询。 + ## 同一个点的多事件处理 我们可以发现,就目前而且,每个点的事件是和该点进行绑定,并以该点坐标作为唯一索引来查询。 diff --git a/libs/events.js b/libs/events.js index 6bdecb9a..6a3657ba 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1053,14 +1053,19 @@ events.prototype.doAction = function() { case "function": { var func = data["function"]; - if (core.isset(func)) { - if ((typeof func == "string") && func.indexOf("function")==0) { - eval('('+func+')()'); + try { + if (core.isset(func)) { + if ((typeof func == "string") && func.indexOf("function")==0) { + eval('('+func+')()'); + } + else if (func instanceof Function) + func(); } - else if (func instanceof Function) - func(); + } catch (e) { + console.log(e); } - this.doAction(); + if (!data.async) + this.doAction(); break; } case "update": From 75bff6bcd6c838e7753731a9f96d3071c542fa7b Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Thu, 6 Dec 2018 16:22:16 +0800 Subject: [PATCH 12/81] Fix Editor ChangeFloor Bug --- _server/data.comment.js | 2 +- libs/events.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/_server/data.comment.js b/_server/data.comment.js index 7370b25f..7e7e136a 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -388,7 +388,7 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "animateSpeed": { "_leaf": true, "_type": "textarea", - "_data": "动画时间,一般300比较合适" + "_data": "全局动画时间,即怪物振动频率,一般300比较合适" } } }, diff --git a/libs/events.js b/libs/events.js index 6a3657ba..ac17281e 100644 --- a/libs/events.js +++ b/libs/events.js @@ -171,6 +171,8 @@ events.prototype.startGame = function (hard, seed, route, callback) { } + if (main.mode!='play') return; + if (core.flags.startUsingCanvas) { core.dom.startPanel.style.display = 'none'; start(); From 519b88275824afb79e9c0c9c3ff8c766eb7350f2 Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 6 Dec 2018 23:29:49 +0800 Subject: [PATCH 13/81] statusCanvas --- _server/data.comment.js | 12 +++ _server/functions.comment.js | 6 ++ editor-mobile.html | 11 ++- editor.html | 11 ++- index.html | 11 ++- libs/control.js | 181 ++++++++++++++--------------------- main.js | 6 +- project/data.js | 2 + project/functions.js | 22 +++++ 9 files changed, 141 insertions(+), 121 deletions(-) diff --git a/_server/data.comment.js b/_server/data.comment.js index 7e7e136a..ab8ddd6e 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -564,6 +564,18 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_bool": "bool", "_data": "点击“开始游戏”后是否立刻开始游戏而不显示难度选择界面" }, + "statusCanvas": { + "_leaf": true, + "_type": "checkbox", + "_bool": "bool", + "_data": "是否状态栏canvas化,即手动自定义绘制状态栏。\n如果此项开启,则可在脚本编辑的drawStatusBar中自定义绘制菜单栏。" + }, + "statusCanvasRowsOnMobile": { + "_leaf": true, + "_type": "textarea", + "_range": "thiseval==null || (thiseval>0 && thiseval<=4)", + "_data": "竖屏模式下,顶端状态栏canvas化后的行数。\n此项将决定竖屏的状态栏高度,如果设置则不小于1且不大于4。\n仅在statusCanvas开启时才有效" + }, "canOpenBattleAnimate": { "_leaf": true, "_type": "checkbox", diff --git a/_server/functions.comment.js b/_server/functions.comment.js index d7fb4499..ae97a7cd 100644 --- a/_server/functions.comment.js +++ b/_server/functions.comment.js @@ -169,6 +169,12 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_leaf": false, "_type": "object", "_data": { + "drawStatusBar": { + "_leaf": true, + "_type": "textarea", + "_lint": true, + "_data": "自定义绘制状态栏。\n当状态栏canvas化开启时,可以在这里对状态栏进行自定义绘制。\n仅当statusCanvas开启时有效。" + }, "drawStatistics": { "_leaf": true, "_type": "textarea", diff --git a/editor-mobile.html b/editor-mobile.html index 89b98714..c3396905 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -353,7 +353,7 @@

-
+

@@ -361,11 +361,11 @@

-
+

-
+

@@ -377,7 +377,7 @@

-
+

@@ -404,6 +404,9 @@
+ + +
diff --git a/editor.html b/editor.html index b5f76989..54cdb46e 100644 --- a/editor.html +++ b/editor.html @@ -339,7 +339,7 @@

-
+

@@ -347,11 +347,11 @@

-
+

-
+

@@ -363,7 +363,7 @@

-
+

@@ -390,6 +390,9 @@
+ + +
diff --git a/index.html b/index.html index 4e65f98a..8fe217e5 100644 --- a/index.html +++ b/index.html @@ -58,7 +58,7 @@

-
+

@@ -66,11 +66,11 @@

-
+

-
+

@@ -82,7 +82,7 @@

-
+

@@ -109,6 +109,9 @@
+ + +
diff --git a/libs/control.js b/libs/control.js index 0c15502b..c413b999 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2907,6 +2907,36 @@ control.prototype.setToolbarButton = function (useButton) { } } +control.prototype.needDraw = function(id) { + if (!core.isset(id)) { + var toDraw = [], status = core.dom.status; + for (var i = 0; i12) alert("当前状态栏数目("+count+")大于12,请调整到不超过12以避免手机端出现显示问题。"); + if (!statusCanvas && count>12) alert("当前状态栏数目("+count+")大于12,请调整到不超过12以避免手机端出现显示问题。"); + var col = Math.ceil(count / 3); + if (statusCanvas) col = statusCanvasRows; var statusLineHeight = BASE_LINEHEIGHT * 9 / count; var statusLineFontSize = DEFAULT_FONT_SIZE; @@ -2988,9 +3009,6 @@ control.prototype.resize = function(clientWidth, clientHeight) { core.domStyle.screenMode = 'vertical'; //显示快捷商店图标 shopDisplay = 'block'; - //判断应该显示几行 - // var col = core.flags.enableMDef || core.flags.enableExperience || core.flags.enableDebuff ? 3 : 2; - var col = parseInt((count-1)/3)+1; var tempTopBarH = scale * (BASE_LINEHEIGHT * col + SPACE * 2) + 6; var tempBotBarH = scale * (BASE_LINEHEIGHT + SPACE * 4) + 6; @@ -2998,6 +3016,8 @@ control.prototype.resize = function(clientWidth, clientHeight) { gameGroupHeight = tempWidth + tempTopBarH + tempBotBarH; gameGroupWidth = tempWidth + statusCanvasWidth = canvasWidth; + statusCanvasHeight = tempTopBarH; canvasTop = tempTopBarH; // canvasLeft = 0; toolBarWidth = statusBarWidth = canvasWidth; @@ -3031,6 +3051,8 @@ control.prototype.resize = function(clientWidth, clientHeight) { toolBarWidth = statusBarWidth = DEFAULT_BAR_WIDTH * scale; statusBarHeight = gameGroupHeight - SPACE; statusBarBorder = '3px '+borderColor+' solid'; + statusCanvasWidth = toolBarWidth + SPACE; + statusCanvasHeight = statusBarHeight; statusBackground = (core.status.globalAttribute||core.initStatus.globalAttribute).statusLeftBackground; statusHeight = scale*statusLineHeight * .8; @@ -3065,6 +3087,8 @@ control.prototype.resize = function(clientWidth, clientHeight) { // statusBarHeight = statusLineHeight * count + SPACE * 2; //一共有9行 statusBackground = (core.status.globalAttribute||core.initStatus.globalAttribute).statusLeftBackground; statusBarHeight = gameGroupHeight - SPACE; + statusCanvasWidth = toolBarWidth + SPACE; + statusCanvasHeight = statusBarHeight; statusHeight = statusLineHeight * .8; statusLabelsLH = .8 * statusLineHeight; @@ -3100,6 +3124,14 @@ control.prototype.resize = function(clientWidth, clientHeight) { height: (canvasWidth - SPACE*2) + unit, } }, + { + id: 'statusCanvas', + rules: { + width: (statusCanvasWidth - SPACE*2) + unit, + height: (statusCanvasHeight - SPACE) + unit, + display: statusCanvas?'block':'none' + } + }, { id: 'gif', rules: { @@ -3114,15 +3146,6 @@ control.prototype.resize = function(clientWidth, clientHeight) { height:(canvasWidth - SPACE*2) + unit, } }, - /* - { - id: 'curtain', - rules: { - width: (canvasWidth - SPACE*2) + unit, - height:(canvasWidth - SPACE*2) + unit, - } - }, - */ { id: 'gameDraw', rules: { @@ -3166,7 +3189,8 @@ control.prototype.resize = function(clientWidth, clientHeight) { width: '100%', maxWidth: statusMaxWidth + unit, height: statusHeight + unit, - margin: margin/2 + unit + margin: margin/2 + unit, + display: !statusCanvas?'block':'none' } }, { @@ -3212,84 +3236,6 @@ control.prototype.resize = function(clientWidth, clientHeight) { display: shopDisplay && core.domStyle.showStatusBar } }, - { - id: 'floorCol', - rules: { - display: core.flags.enableFloor ? 'block': 'none' - } - }, - { - id: 'nameCol', - rules: { - display: core.flags.enableName ? 'block': 'none' - } - }, - { - id: 'lvCol', - rules: { - display: core.flags.enableLv ? 'block': 'none' - } - }, - { - id: 'hpmaxCol', - rules: { - display: core.flags.enableHPMax ? 'block': 'none' - } - }, - { - id: 'manaCol', - rules: { - display: core.flags.enableMana ? 'block': 'none' - } - }, - { - id: 'mdefCol', - rules: { - display: core.flags.enableMDef ? 'block': 'none' - } - }, - { - id: 'moneyCol', - rules: { - display: core.flags.enableMoney ? 'block': 'none' - } - }, - { - id: 'expCol', - rules: { - display: core.flags.enableExperience && !core.flags.levelUpLeftMode ? 'block': 'none' - } - }, - { - id: 'upCol', - rules: { - display: core.flags.enableLevelUp ? 'block': 'none' - } - }, - { - id: 'skillCol', - rules: { - display: core.flags.enableSkill ? 'block': 'none' - } - }, - { - id: 'keyCol', - rules: { - display: !core.isset(core.flags.enableKeys)||core.flags.enableKeys?'block':'none' - } - }, - { - id: 'pzfCol', - rules: { - display: core.flags.enablePZF?'block':'none' - } - }, - { - 'id': 'debuffCol', - rules: { - display: core.flags.enableDebuff ? 'block': 'none' - } - }, { id: 'hard', rules: { @@ -3298,8 +3244,27 @@ control.prototype.resize = function(clientWidth, clientHeight) { } }, ] + for (var i = 0; i < core.dom.status.length; ++i) { + var id = core.dom.status[i].id; + core.domStyle.styles.push({ + id: id, + rules: { + display: toDraw.indexOf(id.substring(0, id.length-3))>=0 && !statusCanvas ? "block": "none" + } + }); + } + core.domRenderer(); this.setToolbarButton(); + + if (core.domStyle.screenMode == 'vertical') { + core.dom.statusCanvas.width = 416; + core.dom.statusCanvas.height = col * BASE_LINEHEIGHT + SPACE + 6; + } + else { + core.dom.statusCanvas.width = 129; + core.dom.statusCanvas.height = 416; + } } ////// 渲染DOM ////// diff --git a/main.js b/main.js index 2ff39470..0ea10df4 100644 --- a/main.js +++ b/main.js @@ -55,16 +55,20 @@ function main() { 'nameCol': document.getElementById('nameCol'), 'lvCol': document.getElementById('lvCol'), 'hpmaxCol': document.getElementById('hpmaxCol'), + 'hpCol': document.getElementById('hpCol'), 'manaCol': document.getElementById('manaCol'), + 'atkCol': document.getElementById('atkCol'), + 'defCol': document.getElementById('defCol'), 'mdefCol': document.getElementById('mdefCol'), 'moneyCol': document.getElementById('moneyCol'), - 'expCol': document.getElementById('expCol'), + 'experienceCol': document.getElementById('experienceCol'), 'upCol': document.getElementById('upCol'), 'keyCol': document.getElementById('keyCol'), 'pzfCol': document.getElementById('pzfCol'), 'debuffCol': document.getElementById('debuffCol'), 'skillCol': document.getElementById('skillCol'), 'hard': document.getElementById('hard'), + 'statusCanvas': document.getElementById('statusCanvas') }; this.mode = 'play'; this.loadList = [ diff --git a/project/data.js b/project/data.js index 41c36ba7..c4a85d72 100644 --- a/project/data.js +++ b/project/data.js @@ -369,6 +369,8 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "useLoop": false, "startUsingCanvas": false, "startDirectly": false, + "statusCanvas": false, + "statusCanvasRowsOnMobile": 3, "canOpenBattleAnimate": true, "showBattleAnimateConfirm": false, "battleAnimate": false, diff --git a/project/functions.js b/project/functions.js index 98fbcb24..c1011e77 100644 --- a/project/functions.js +++ b/project/functions.js @@ -998,6 +998,28 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } }, "ui": { + "drawStatusBar": function () { + // 如果是非状态栏canvas化,直接返回 + if (!core.flags.statusCanvas) return; + var canvas = core.dom.statusCanvas, ctx = canvas.getContext('2d'); + // 清空状态栏 + ctx.clearRect(0, 0, canvas.width, canvas.height); + // 如果是隐藏状态栏模式,直接返回 + if (!core.domStyle.showStatusBar) return; + + // 动态计算要绘制的项目 + var toDraw = core.control.needDraw(); + console.log(toDraw); + + // 开始绘制;横竖屏分别绘制 + if (core.domStyle.screenMode != 'vertical') { + console.log("横屏"); + } + else { + console.log("竖屏"); + } + +}, "drawStatistics": function () { // 浏览地图时参与的统计项目 From 15b71dc60c8d8edbc2d4068bd887843b0a9b0aab Mon Sep 17 00:00:00 2001 From: oc Date: Fri, 7 Dec 2018 01:08:01 +0800 Subject: [PATCH 14/81] Auto adjust for pure black --- _server/editor_mode.js | 18 ++++++++++++++++-- 常用工具/便捷PS工具.exe | Bin 25600 -> 26112 bytes 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/_server/editor_mode.js b/_server/editor_mode.js index 94e65bee..12b6aba8 100644 --- a/_server/editor_mode.js +++ b/_server/editor_mode.js @@ -587,15 +587,16 @@ editor_mode = function (editor) { tempCanvas.imageSmoothingEnabled = false; tempCanvas.drawImage(image, 0, 0); var imgData = tempCanvas.getImageData(0, 0, image.width, image.height); - var trans = 0, white = 0; + var trans = 0, white = 0, black=0; for (var i=0;itrans*10 && confirm("看起来这张图片是以白色为底色,是否自动调整为透明底色?")) { + if (white>black && white>trans*10 && confirm("看起来这张图片是以纯白为底色,是否自动调整为透明底色?")) { for (var i=0;iwhite && black>trans*10 && confirm("看起来这张图片是以纯黑为底色,是否自动调整为透明底色?")) { + for (var i=0;i} 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 uR;#~=o6!A6_A5) Date: Fri, 7 Dec 2018 01:15:44 +0800 Subject: [PATCH 15/81] statusCanvas --- _server/editor_mode.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/_server/editor_mode.js b/_server/editor_mode.js index 12b6aba8..031dd8b9 100644 --- a/_server/editor_mode.js +++ b/_server/editor_mode.js @@ -665,10 +665,6 @@ editor_mode = function (editor) { callback(image); } image.src = content; - if (image.complete) { - callback(image); - return; - } } catch (e) { printe(e); From 83b5ef106f17885f43d221db2970039c4388168a Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Fri, 7 Dec 2018 13:36:42 +0800 Subject: [PATCH 16/81] floorChangeTime --- _server/blockly/MotaAction.g4 | 18 +++++++++--------- _server/data.comment.js | 5 +++++ _server/editor.js | 14 ++++++++++++-- libs/events.js | 5 +++-- libs/loader.js | 2 +- libs/utils.js | 20 +++++++------------- project/data.js | 3 ++- 7 files changed, 39 insertions(+), 28 deletions(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index ad12ff1a..5db2748e 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -1675,8 +1675,8 @@ Global_Attribute_List /*Global_Attribute_List ['font','statusLeftBackground','statusTopBackground', 'toolsBackground', 'borderColor', 'statusBarColor', 'hardLabelColor', 'floorChangingBackground', 'floorChangingTextColor']*/; Global_Value_List - : '血网伤害'|'中毒伤害'|'衰弱效果'|'红宝石效果'|'蓝宝石效果'|'绿宝石效果'|'红血瓶效果'|'蓝血瓶效果'|'黄血瓶效果'|'绿血瓶效果'|'破甲比例'|'反击比例'|'净化比例'|'仇恨增加值'|'行走速度'|'动画时间' - /*Global_Value_List ['lavaDamage','poisonDamage','weakValue', 'redJewel', 'blueJewel', 'greenJewel', 'redPotion', 'bluePotion', 'yellowPotion', 'greenPotion', 'breakArmor', 'counterAttack', 'purify', 'hatred', 'moveSpeed', 'animateSpeed']*/; + : '血网伤害'|'中毒伤害'|'衰弱效果'|'红宝石效果'|'蓝宝石效果'|'绿宝石效果'|'红血瓶效果'|'蓝血瓶效果'|'黄血瓶效果'|'绿血瓶效果'|'破甲比例'|'反击比例'|'净化比例'|'仇恨增加值'|'行走速度'|'动画时间'|'楼层切换时间' + /*Global_Value_List ['lavaDamage','poisonDamage','weakValue', 'redJewel', 'blueJewel', 'greenJewel', 'redPotion', 'bluePotion', 'yellowPotion', 'greenPotion', 'breakArmor', 'counterAttack', 'purify', 'hatred', 'moveSpeed', 'animateSpeed', 'floorChangeTime']*/; Bool: 'TRUE' | 'FALSE' @@ -1904,7 +1904,7 @@ ActionParser.prototype.parseAction = function() { case "autoText": // 自动剧情文本 data.time=this.isset(data.time)?data.time:MotaActionBlocks['autoText_s'].fieldDefault[3]; this.next = MotaActionBlocks['autoText_s'].xmlText([ - '','','',data.time,this.EvalString(data.text),this.next]); + '','','',data.time||0,this.EvalString(data.text),this.next]); break; case "comment": // 注释 this.next = MotaActionBlocks['comment_s'].xmlText([data.text,this.next]); @@ -1916,7 +1916,7 @@ ActionParser.prototype.parseAction = function() { if (!/^\w+\.png$/.test(data.background)) data.background=setTextfunc(data.background); this.next = MotaActionBlocks['setText_s'].xmlText([ - data.position,data.offset,data.title,data.text,data.background,data.bold,data.titlefont,data.textfont,data.time,this.next]); + data.position,data.offset,data.title,data.text,data.background,data.bold,data.titlefont,data.textfont,data.time||0,this.next]); break; case "tip": this.next = MotaActionBlocks['tip_s'].xmlText([ @@ -2069,10 +2069,10 @@ ActionParser.prototype.parseAction = function() { case "animateImage": // 显示图片 if(data.action == 'show'){ this.next = MotaActionBlocks['animateImage_0_s'].xmlText([ - data.name,data.loc[0],data.loc[1],data.time,data.keep||false,data.async||false,this.next]); + data.name,data.loc[0],data.loc[1],data.time||0,data.keep||false,data.async||false,this.next]); } else if (data.action == 'hide') { this.next = MotaActionBlocks['animateImage_1_s'].xmlText([ - data.name,data.loc[0],data.loc[1],data.time,data.keep||false,data.async||false,this.next]); + data.name,data.loc[0],data.loc[1],data.time||0,data.keep||false,data.async||false,this.next]); } break; case "showGif": // 显示动图 @@ -2086,7 +2086,7 @@ ActionParser.prototype.parseAction = function() { break; case "moveImage": // 移动图片 this.next = MotaActionBlocks['moveImage_0_s'].xmlText([ - data.name, data.from[0], data.from[1], data.to[0], data.to[1], data.time, data.keep||false, data.async||false, this.next + data.name, data.from[0], data.from[1], data.to[0], data.to[1], data.time||0, data.keep||false, data.async||false, this.next ]); break; case "setFg": // 颜色渐变 @@ -2147,7 +2147,7 @@ ActionParser.prototype.parseAction = function() { break case "setVolume": this.next = MotaActionBlocks['setVolume_s'].xmlText([ - data.value, data.time, data.async||false, this.next]); + data.value, data.time||0, data.async||false, this.next]); break case "setValue": this.next = MotaActionBlocks['setValue_s'].xmlText([ @@ -2246,7 +2246,7 @@ ActionParser.prototype.parseAction = function() { break; case "sleep": // 等待多少毫秒 this.next = MotaActionBlocks['sleep_s'].xmlText([ - data.time,this.next]); + data.time||0,this.next]); break; case "wait": // 等待用户操作 this.next = MotaActionBlocks['wait_s'].xmlText([ diff --git a/_server/data.comment.js b/_server/data.comment.js index 7e7e136a..16a36c24 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -389,6 +389,11 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_leaf": true, "_type": "textarea", "_data": "全局动画时间,即怪物振动频率,一般300比较合适" + }, + "floorChangeTime": { + "_leaf": true, + "_type": "textarea", + "_data": "默认楼层切换时间" } } }, diff --git a/_server/editor.js b/_server/editor.js index 6c92568c..f83e68b4 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -197,7 +197,12 @@ editor.prototype.fetchMapFromCore = function(){ var mapArray = core.maps.save(core.status.maps, core.status.floorId); editor.map = mapArray.map(function (v) { return v.map(function (v) { - return editor.ids[[editor.indexs[parseInt(v)][0]]] + var x = parseInt(v), y = editor.indexs[x]; + if (!core.isset(y)) { + printe("素材数字"+x+"未定义。是不是忘了注册,或者接档时没有覆盖icons.js和maps.js?"); + y = [0]; + } + return editor.ids[y[0]] }) }); editor.currentFloorId = core.status.floorId; @@ -210,7 +215,12 @@ editor.prototype.fetchMapFromCore = function(){ } editor[name]=mapArray.map(function (v) { return v.map(function (v) { - return editor.ids[[editor.indexs[parseInt(v)][0]]] + var x = parseInt(v), y = editor.indexs[x]; + if (!core.isset(y)) { + printe("素材数字"+x+"未定义。是不是忘了注册,或者接档时没有覆盖icons.js和maps.js?"); + y = [0]; + } + return editor.ids[y[0]] }) }); } diff --git a/libs/events.js b/libs/events.js index ac17281e..eaf94f69 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1391,10 +1391,11 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback if (index=100) && !core.status.replay.replaying; + var displayAnimate = time>=100 && !core.status.replay.replaying; - time = time || 800; time /= 20; core.lockControl(); core.stopHero(); diff --git a/libs/loader.js b/libs/loader.js index d5a4d3d3..5ff3c386 100644 --- a/libs/loader.js +++ b/libs/loader.js @@ -238,7 +238,7 @@ loader.prototype.loadMusic = function () { console.log(ee); core.material.sounds[t] = null; } - }, function () { + }, function (e) { console.log(e); core.material.sounds[t] = null; }, null, 'arraybuffer'); diff --git a/libs/utils.js b/libs/utils.js index aad199fb..1e554205 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -735,14 +735,10 @@ utils.prototype.copy = function (data) { ////// 动画显示某对象 ////// utils.prototype.show = function (obj, speed, callback) { - if (!core.isset(speed)) { - obj.style.display = 'block'; - return; - } obj.style.display = 'block'; - if (main.mode!='play'){ + if (!core.isset(speed) && main.mode!='play') { obj.style.opacity = 1; - if (core.isset(callback)) {callback();} + if (core.isset(callback)) callback(); return; } obj.style.opacity = 0; @@ -761,15 +757,13 @@ utils.prototype.show = function (obj, speed, callback) { ////// 动画使某对象消失 ////// utils.prototype.hide = function (obj, speed, callback) { - if (!core.isset(speed)) { - obj.style.display = 'none'; - return; - } - if (main.mode!='play'){ - obj.style.display = 'none'; - if (core.isset(callback)) {callback();} + obj.style.display = 'none'; + if (!core.isset(speed) || main.mode!='play'){ + obj.style.opacity = 0; + if (core.isset(callback)) callback(); return; } + obj.style.opacity = 1; var opacityVal = 1; var hideAnimate = window.setInterval(function () { opacityVal -= 0.03; diff --git a/project/data.js b/project/data.js index 41c36ba7..0743a04c 100644 --- a/project/data.js +++ b/project/data.js @@ -338,7 +338,8 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "purify": 3, "hatred": 2, "moveSpeed": 100, - "animateSpeed": 300 + "animateSpeed": 300, + "floorChangeTime": 800, }, "flags": { "enableFloor": true, From 2929a68de8256cedbba9242fb6066de03f5b5e3c Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Fri, 7 Dec 2018 13:41:43 +0800 Subject: [PATCH 17/81] getNextItem on 7 --- project/functions.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/project/functions.js b/project/functions.js index 98fbcb24..20b5b209 100644 --- a/project/functions.js +++ b/project/functions.js @@ -724,6 +724,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } } break; + case 55: // 快捷键7:绑定为轻按,方便手机版操作 + core.getNextItem(); + break; case 118: // F7:开启debug模式 core.debug(); break; From eba4aafbfd2f0a629f8315f95818d61278671d77 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Fri, 7 Dec 2018 15:52:30 +0800 Subject: [PATCH 18/81] Adjust to 2.5 lines --- libs/core.js | 4 ++-- libs/ui.js | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/libs/core.js b/libs/core.js index 6d01ebb9..3131844c 100644 --- a/libs/core.js +++ b/libs/core.js @@ -759,8 +759,8 @@ core.prototype.animateBlock = function (loc,type,time,callback) { } ////// 将某个块从禁用变成启用状态 ////// -core.prototype.showBlock = function(x, y, floodId) { - core.maps.showBlock(x,y,floodId); +core.prototype.showBlock = function(x, y, floorId) { + core.maps.showBlock(x,y,floorId); } ////// 将某个块从启用变成禁用状态,但是并不删除它 ////// diff --git a/libs/ui.js b/libs/ui.js index c6067779..5eb60157 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -403,6 +403,9 @@ ui.prototype.calTextBoxWidth = function (canvas, content, min_width, max_width) // 如果不存在手动换行,则二分自动换行 if (allLines.length == 1) { + var w = core.canvas[canvas].measureText(allLines[0]).width; + return core.clamp(w / 2.4, min_width, max_width); + /* var prefer_lines = 3; var start = Math.floor(min_width), end = Math.floor(max_width); while (start < end) { @@ -413,6 +416,7 @@ ui.prototype.calTextBoxWidth = function (canvas, content, min_width, max_width) start = mid + 1; } return mid; + */ } // 存在手动换行:以最长的为准 else { From 3155dcbfc5d3361227188a490669c9fc297cb912 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Fri, 7 Dec 2018 16:08:21 +0800 Subject: [PATCH 19/81] Auto adjust textbox width --- docs/element.md | 2 +- libs/ui.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/element.md b/docs/element.md index 5a7189a3..e3388285 100644 --- a/docs/element.md +++ b/docs/element.md @@ -318,7 +318,7 @@ floorId指定的是目标楼层的唯一标识符(ID)。 另外一点是,V2.5.2以后,对话框`\b`可以根据文字长度来自动控制文本框宽度,其基本控制原理如下: - 如果用户存在手动换行`\n`,则选取**最长的一段话**作为文本框宽度。 -- 如果用户不存在手动换行,则会将文本框宽度调整为**尽量刚好达到三行**的最佳宽度。 +- 如果用户不存在手动换行,则会将文本框宽度调整为X行半的最佳宽度。 - 文本框宽度存在上下界,最终宽度一定会控制在该范围内。 该自动调整仅对`\b`的对话框效果有效。非对话框仍然会绘制整个界面的宽度。 diff --git a/libs/ui.js b/libs/ui.js index 5eb60157..1be9ee61 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -404,7 +404,9 @@ ui.prototype.calTextBoxWidth = function (canvas, content, min_width, max_width) // 如果不存在手动换行,则二分自动换行 if (allLines.length == 1) { var w = core.canvas[canvas].measureText(allLines[0]).width; - return core.clamp(w / 2.4, min_width, max_width); + if (w Date: Fri, 7 Dec 2018 21:36:33 +0800 Subject: [PATCH 20/81] setGlobalAttribute --- libs/events.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libs/events.js b/libs/events.js index ac17281e..8b47da2d 100644 --- a/libs/events.js +++ b/libs/events.js @@ -918,6 +918,11 @@ events.prototype.doAction = function() { this.doAction(); break; case "setGlobalAttribute": + if (typeof data.value == 'string') { + if ((data.value.charAt(0)=='"' && data.value.charAt(data.value.length-1)=='"') + || (data.value.charAt(0)=="'" && data.value.charAt(data.value.length-1)=="'")) + data.value = data.value.substring(1, data.value.length-1); + } core.status.globalAttribute[data.name] = data.value; core.control.updateGlobalAttribute(data.name); core.setFlag('globalAttribute', core.status.globalAttribute); From ae720ee4771ad8f90bd7195da99f982fbbe0e636 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 8 Dec 2018 00:03:31 +0800 Subject: [PATCH 21/81] Fog --- _server/blockly/MotaAction.g4 | 4 +-- _server/comment.js | 2 +- docs/element.md | 2 +- docs/event.md | 2 ++ libs/control.js | 45 +++++++++++++++++++++++++++++++++- libs/core.js | 4 +++ libs/events.js | 1 + libs/utils.js | 3 +-- project/images/fog.png | Bin 0 -> 38503 bytes 9 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 project/images/fog.png diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 5db2748e..399a4c1b 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -1651,8 +1651,8 @@ Arithmetic_List ; Weather_List - : '无'|'雨'|'雪' - /*Weather_List ['','rain','snow']*/; + : '无'|'雨'|'雪'|'雾' + /*Weather_List ['','rain','snow','fog']*/; B_0_List : '不改变'|'不可通行'|'可以通行' diff --git a/_server/comment.js b/_server/comment.js index 2b7fcc33..9577712f 100644 --- a/_server/comment.js +++ b/_server/comment.js @@ -376,7 +376,7 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "weather": { "_leaf": true, "_type": "textarea", - "_data": "该层的默认天气。本项可忽略表示晴天,如果写则第一项为\"rain\"或\"snow\"代表雨雪,第二项为1-10之间的数代表强度。\n如[\"rain\", 8]代表8级雨天。" + "_data": "该层的默认天气。本项可忽略表示晴天,如果写则第一项为\"rain\",\"snow\"或\"fog\"代表雨雪雾,第二项为1-10之间的数代表强度。\n如[\"rain\", 8]代表8级雨天。" }, "bgm": { "_leaf": true, diff --git a/docs/element.md b/docs/element.md index e3388285..7ef586d3 100644 --- a/docs/element.md +++ b/docs/element.md @@ -361,7 +361,7 @@ floorId指定的是目标楼层的唯一标识符(ID)。 在每层楼的剧本文件里存在一个weather选项,表示该层楼的默认天气。 ``` js -// 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain"或"snow"代表雨雪,第二项为1-10之间的数代表强度。 +// 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain","snow"或"fog"代表雨雪雾,第二项为1-10之间的数代表强度。 "weather": ["snow",5] ``` diff --git a/docs/event.md b/docs/event.md index f2cb169f..69e2214a 100644 --- a/docs/event.md +++ b/docs/event.md @@ -1035,6 +1035,8 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 name为天气选项。目前只支持`rain`和`snow`,即雨天和雪天。 +从V2.5.3开始,也支持雾天`fog`。 + level为天气的强度等级,在1-10之间。1级为最弱,10级为最强。 如果想改回晴天则直接不加任何参数。 diff --git a/libs/control.js b/libs/control.js index 0c15502b..a0a655bc 100644 --- a/libs/control.js +++ b/libs/control.js @@ -212,6 +212,37 @@ control.prototype.setRequestAnimationFrame = function () { core.canvas.weather.fill(); + } + else if (core.animateFrame.weather.type == 'fog' && core.animateFrame.weather.level > 0) { + core.clearMap('weather'); + if (core.animateFrame.weather.fog) { + var w = 416, h = 416; + core.setAlpha('weather', 0.5); + core.animateFrame.weather.nodes.forEach(function (p) { + core.canvas.weather.drawImage(core.animateFrame.weather.fog, p.x - ox, p.y - oy, w, h); + + p.x += p.xs; + p.y += p.ys; + if (p.x > core.bigmap.width*32 - w/2) { + p.x = core.bigmap.width*32 - w/2 - 1; + p.xs = -p.xs; + } + if (p.x < -w/2) { + p.x = -w/2+1; + p.xs = -p.xs; + } + if (p.y > core.bigmap.height*32 - h/2) { + p.y = core.bigmap.height*32 - h/2 - 1; + p.ys = -p.ys; + } + if (p.y < -h/2) { + p.y = -h/2+1; + p.ys = -p.ys; + } + }) + core.setAlpha('weather',1); + } + } core.animateFrame.weather.time = timestamp; @@ -1438,7 +1469,7 @@ control.prototype.snipe = function (snipes) { control.prototype.setWeather = function (type, level) { // 非雨雪 - if (type!='rain' && type!='snow') { + if (type!='rain' && type!='snow' && type!='fog') { core.clearMap('weather') core.animateFrame.weather.type = null; core.animateFrame.weather.level = 0; @@ -1485,6 +1516,18 @@ control.prototype.setWeather = function (type, level) { }) } } + else if (type=='fog') { + if (core.animateFrame.weather.fog) { + for (var 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 iU0ti|u&;x3=l(xhYAFfkNF0d(0000 Date: Sat, 8 Dec 2018 01:35:44 +0800 Subject: [PATCH 22/81] StatusBar Canvas --- libs/actions.js | 17 ++++++------- libs/control.js | 21 +++++++++------- libs/core.js | 7 ++++++ libs/ui.js | 6 +++++ project/functions.js | 58 +++++++++++++++++++++++++++++++++++++------- 5 files changed, 81 insertions(+), 28 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index ceee4f34..55212e0b 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -432,16 +432,13 @@ actions.prototype.getClickLoc = function (x, y) { var size = 32; size = size * core.domStyle.scale; - switch (core.domStyle.screenMode) {// 这里的3是指statusBar和游戏画布之间的白线宽度 - case 'vertical': - statusBar.x = 0; - statusBar.y = core.dom.statusBar.offsetHeight + 3; - break; - case 'horizontal': - case 'bigScreen': - statusBar.x = core.dom.statusBar.offsetWidth + 3; - statusBar.y = 0; - break; + if (core.domStyle.isVertical) { + statusBar.x = 0; + statusBar.y = core.dom.statusBar.offsetHeight + 3; + } + else { + statusBar.x = core.dom.statusBar.offsetWidth + 3; + statusBar.y = 0; } var left = core.dom.gameGroup.offsetLeft + statusBar.x; diff --git a/libs/control.js b/libs/control.js index f533e065..d3f25f7d 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2877,31 +2877,30 @@ control.prototype.updateGlobalAttribute = function (name) { if (!core.isset(attribute)) return; switch (name) { case 'statusLeftBackground': - if (core.domStyle.screenMode == 'horizontal' || core.domStyle.screenMode == 'bigScreen') { + if (!core.domStyle.isVertical) { core.dom.statusBar.style.background = attribute[name]; } break; case 'statusTopBackground': - if (core.domStyle.screenMode == 'vertical') { + if (core.domStyle.isVertical) { core.dom.statusBar.style.background = attribute[name]; } break; case 'toolsBackground': - if (core.domStyle.screenMode == 'vertical') { + if (core.domStyle.isVertical) { core.dom.toolBar.style.background = attribute[name]; } break; case 'borderColor': { var border = '3px ' + attribute[name] + ' solid'; - var isVertical = core.domStyle.screenMode == 'vertical'; core.dom.statusBar.style.borderTop = border; core.dom.statusBar.style.borderLeft = border; - core.dom.statusBar.style.borderRight = isVertical?'':border; + core.dom.statusBar.style.borderRight = core.domStyle.isVertical?'':border; core.dom.gameDraw.style.border = border; core.dom.toolBar.style.borderBottom = border; core.dom.toolBar.style.borderLeft = border; - core.dom.toolBar.style.borderRight = isVertical?'':border; + core.dom.toolBar.style.borderRight = core.domStyle.isVertical?'':border; break; } case 'statusBarColor': @@ -2928,7 +2927,7 @@ control.prototype.setToolbarButton = function (useButton) { if (!core.domStyle.showStatusBar) return; if (!core.isset(useButton)) useButton = core.domStyle.toolbarBtn; - if (core.domStyle.screenMode != 'vertical') useButton = false; + if (!core.domStyle.isVertical) useButton = false; core.domStyle.toolbarBtn = useButton; if (useButton) { @@ -2946,7 +2945,7 @@ control.prototype.setToolbarButton = function (useButton) { ["book","fly","toolbox","shop","save","load","settings"].forEach(function (t) { core.statusBar.image[t].style.display = 'block'; }); - core.statusBar.image.shop.style.display = core.domStyle.screenMode != 'vertical' ? "none":"block"; + core.statusBar.image.shop.style.display = core.domStyle.isVertical ? "block":"none"; } } @@ -3050,6 +3049,7 @@ control.prototype.resize = function(clientWidth, clientHeight) { var tempWidth = DEFAULT_CANVAS_WIDTH * scale; if(!isHorizontal){ //竖屏 core.domStyle.screenMode = 'vertical'; + core.domStyle.isVertical = true; //显示快捷商店图标 shopDisplay = 'block'; @@ -3086,6 +3086,7 @@ control.prototype.resize = function(clientWidth, clientHeight) { toolbarFontSize = DEFAULT_FONT_SIZE * scale; }else { //横屏 core.domStyle.screenMode = 'horizontal'; + core.domStyle.isVertical = false; shopDisplay = 'none'; gameGroupWidth = tempWidth + DEFAULT_BAR_WIDTH * scale; gameGroupHeight = tempWidth; @@ -3118,6 +3119,7 @@ control.prototype.resize = function(clientWidth, clientHeight) { }else { //大屏设备 pc端 core.domStyle.scale = 1; core.domStyle.screenMode = 'bigScreen'; + core.domStyle.isVertical = false; shopDisplay = 'none'; gameGroupWidth = DEFAULT_CANVAS_WIDTH + DEFAULT_BAR_WIDTH; @@ -3300,7 +3302,7 @@ control.prototype.resize = function(clientWidth, clientHeight) { core.domRenderer(); this.setToolbarButton(); - if (core.domStyle.screenMode == 'vertical') { + if (core.domStyle.isVertical) { core.dom.statusCanvas.width = 416; core.dom.statusCanvas.height = col * BASE_LINEHEIGHT + SPACE + 6; } @@ -3308,6 +3310,7 @@ control.prototype.resize = function(clientWidth, clientHeight) { core.dom.statusCanvas.width = 129; core.dom.statusCanvas.height = 416; } + this.updateStatusBar(); } ////// 渲染DOM ////// diff --git a/libs/core.js b/libs/core.js index 6a602754..1882bf8b 100644 --- a/libs/core.js +++ b/libs/core.js @@ -77,6 +77,8 @@ function core() { this.domStyle = { styles: [], scale: 1.0, + screenMode: null, + isVertical: false, toolbarBtn: false, showStatusBar: true, } @@ -1386,6 +1388,11 @@ core.prototype.updateStatusBar = function () { core.control.updateStatusBar(); } +////// 绘制状态栏 ////// +core.prototype.drawStatusBar = function () { + core.ui.drawStatusBar(); +} + ////// 屏幕分辨率改变后重新自适应 ////// core.prototype.resize = function(clientWidth, clientHeight) { core.control.resize(clientWidth, clientHeight); diff --git a/libs/ui.js b/libs/ui.js index 1be9ee61..27ba3e00 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2394,6 +2394,12 @@ ui.prototype.drawKeyBoard = function () { core.fillText("ui", "返回游戏", 416-80, offset-3, '#FFFFFF', 'bold 15px '+globalFont); } +////// 绘制状态栏 ///// +ui.prototype.drawStatusBar = function () { + if (this.uidata.drawStatusBar) + this.uidata.drawStatusBar(); +} + ////// 绘制“数据统计”界面 ////// ui.prototype.drawStatistics = function () { diff --git a/project/functions.js b/project/functions.js index 26c747fb..4309b9d1 100644 --- a/project/functions.js +++ b/project/functions.js @@ -863,6 +863,8 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 难度 core.statusBar.hard.innerHTML = core.status.hard; + // 状态栏绘制 + core.drawStatusBar(); // 更新阻激夹域的伤害值 core.updateCheckBlock(); @@ -1010,18 +1012,56 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 如果是隐藏状态栏模式,直接返回 if (!core.domStyle.showStatusBar) return; - // 动态计算要绘制的项目 - var toDraw = core.control.needDraw(); - console.log(toDraw); + // 作为样板,只绘制楼层、生命、攻击、防御、魔防、金币、钥匙这七个内容 + // 需要其他的请自行进行修改;横竖屏都需要进行适配绘制。 + // (可以使用Chrome浏览器开控制台来模拟手机上的竖屏模式的显示效果,具体方式自行百度) + // 横屏模式下的画布大小是 129*416 + // 竖屏模式下的画布大小是 416*(32*rows+9) 其中rows为状态栏行数,即全塔属性中statusCanvasRowsOnMobile值 + // 可以使用 core.domStyle.isVertical 来判定当前是否是竖屏模式 - // 开始绘制;横竖屏分别绘制 - if (core.domStyle.screenMode != 'vertical') { - console.log("横屏"); - } - else { - console.log("竖屏"); + ctx.fillStyle = core.status.globalAttribute.statusBarColor || core.initStatus.globalAttribute.statusBarColor; + ctx.font = 'italic bold 18px Verdana'; + + // 距离左侧边框6像素,上侧边框9像素,行距约为39像素 + var leftOffset = 6, topOffset = 9, lineHeight = 39; + if (core.domStyle.isVertical) { // 竖屏模式,行高32像素 + leftOffset = 6; topOffset = 6; lineHeight = 32; } + var toDraw = ["floor", "hp", "atk", "def", "mdef", "money"]; + for (var index = 0; index < toDraw.length; index++) { + // 绘制下一个数据 + var name = toDraw[index]; + // 图片大小25x25 + ctx.drawImage(core.statusBar.icons[name], leftOffset, topOffset, 25, 25); + // 文字内容 + var text = (core.statusBar[name]||{}).innerText || " "; + // 斜体判定:如果不是纯数字,斜体会非常难看,需要取消 + if (!/^\d*$/.test(text)) ctx.font = 'bold 18px Verdana'; + // 绘制文字 + ctx.fillText(text, leftOffset + 36, topOffset + 20); + ctx.font = 'italic bold 18px Verdana'; + // 计算下一个绘制的坐标 + if (core.domStyle.isVertical) { + // 竖屏模式 + if (index % 3 != 2) leftOffset += 131; + else { + leftOffset = 6; + topOffset += lineHeight; + } + } + else { + // 横屏模式 + topOffset += lineHeight; + } + } + // 绘制三色钥匙 + ctx.fillStyle = '#FFCCAA'; + ctx.fillText(core.statusBar.yellowKey.innerText, leftOffset + 5, topOffset + 20); + ctx.fillStyle = '#AAAADD'; + ctx.fillText(core.statusBar.blueKey.innerText, leftOffset + 40, topOffset + 20); + ctx.fillStyle = '#FF8888'; + ctx.fillText(core.statusBar.redKey.innerText, leftOffset + 75, topOffset + 20); }, "drawStatistics": function () { // 浏览地图时参与的统计项目 From 3e1220c3507e5eaadc75bb3a1110767fa7efe722 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 8 Dec 2018 20:16:26 +0800 Subject: [PATCH 23/81] weakValue --- libs/events.js | 15 ++++++++------- project/functions.js | 15 ++++++++------- project/items.js | 11 ++++++----- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/libs/events.js b/libs/events.js index d2c55581..0a9c0e1d 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1884,13 +1884,14 @@ events.prototype.passNet = function (data) { if (data.event.id=='weakNet') { // 衰网 if (core.hasFlag('weak')) return; core.setFlag('weak', true); - var weakValue = core.values.weakValue; - var weakAtk = weakValue>=1?weakValue:Math.floor(weakValue*core.status.hero.atk); - var weakDef = weakValue>=1?weakValue:Math.floor(weakValue*core.status.hero.def); - core.setFlag('weakAtk', weakAtk); - core.setFlag('weakDef', weakDef); - core.status.hero.atk-=weakAtk; - core.status.hero.def-=weakDef; + if (core.values.weakValue>=1) { // >=1:直接扣数值 + core.status.hero.atk -= core.values.weakValue; + core.status.hero.def -= core.values.weakValue; + } + else { // <1:扣比例 + core.setFlag("equip_atk_buff", core.getFlag("equip_atk_buff", 1) + core.values.weakValue - 1); + core.setFlag("equip_def_buff", core.getFlag("equip_def_buff", 1) + core.values.weakValue - 1); + } } if (data.event.id=='curseNet') { // 咒网 if (core.hasFlag('curse')) return; diff --git a/project/functions.js b/project/functions.js index 20b5b209..5e677c96 100644 --- a/project/functions.js +++ b/project/functions.js @@ -179,13 +179,14 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 衰弱 if (core.enemys.hasSpecial(special, 13) && !core.hasFlag('weak')) { core.setFlag('weak', true); - var weakValue = core.values.weakValue; - var weakAtk = weakValue>=1?weakValue:Math.floor(weakValue*core.status.hero.atk); - var weakDef = weakValue>=1?weakValue:Math.floor(weakValue*core.status.hero.def); - core.setFlag('weakAtk', weakAtk); - core.setFlag('weakDef', weakDef); - core.status.hero.atk-=weakAtk; - core.status.hero.def-=weakDef; + if (core.values.weakValue>=1) { // >=1:直接扣数值 + core.status.hero.atk -= core.values.weakValue; + core.status.hero.def -= core.values.weakValue; + } + else { // <1:扣比例 + core.setFlag("equip_atk_buff", core.getFlag("equip_atk_buff", 1) + core.values.weakValue - 1); + core.setFlag("equip_def_buff", core.getFlag("equip_def_buff", 1) + core.values.weakValue - 1); + } } // 诅咒 if (core.enemys.hasSpecial(special, 14) && !core.hasFlag('curse')) { diff --git a/project/items.js b/project/items.js index 4c648cfe..4f925f40 100644 --- a/project/items.js +++ b/project/items.js @@ -1,4 +1,4 @@ -var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = +var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = { "items": { "yellowKey": { @@ -301,7 +301,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "constants", "name": "技能:二倍斩", "text": "可以打开或关闭主动技能二倍斩", - "hideInReplay": true + "hideInReplay": true } }, "itemEffect": { @@ -368,9 +368,9 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "upFly": "var loc = {'direction': core.status.hero.loc.direction, 'x': core.status.event.data.x, 'y': core.status.event.data.y};\ncore.changeFloor(core.status.event.data.id, null, loc, null, function (){\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\tcore.replay();\n});", "downFly": "var loc = {'direction': core.status.hero.loc.direction, 'x': core.status.event.data.x, 'y': core.status.event.data.y};\ncore.changeFloor(core.status.event.data.id, null, loc, null, function (){\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\tcore.replay();\n});", "poisonWine": "core.removeFlag('poison');", - "weakWine": "core.removeFlag('weak');\ncore.status.hero.atk += core.getFlag('weakAtk', core.values.weakValue);\ncore.status.hero.def += core.getFlag('weakDef', core.values.weakValue);", + "weakWine": "core.removeFlag('weak');\nif (core.values.weakValue>=1) { // >=1:直接扣数值\n\tcore.status.hero.atk += core.values.weakValue;\n\tcore.status.hero.def += core.values.weakValue;\n}\nelse { // <1:扣比例\n\tcore.setFlag(\"equip_atk_buff\", core.getFlag(\"equip_atk_buff\", 1) - core.values.weakValue + 1);\n\tcore.setFlag(\"equip_def_buff\", core.getFlag(\"equip_def_buff\", 1) - core.values.weakValue + 1);\n}", "curseWine": "core.removeFlag('curse');", - "superWine": "core.removeFlag('poison');\nif (core.hasFlag('weak')) {\n\tcore.removeFlag('weak');\n\tcore.status.hero.atk += core.getFlag('weakAtk', core.values.weakValue);\n\tcore.status.hero.def += core.getFlag('weakDef', core.values.weakValue);\n}\ncore.removeFlag('curse');", + "superWine": "core.removeFlag('poison');\nif (core.hasFlag('weak')) {\n\tcore.removeFlag('weak');\n\tif (core.values.weakValue>=1) { // >=1:直接扣数值\n\t\tcore.status.hero.atk += core.values.weakValue;\n\t\tcore.status.hero.def += core.values.weakValue;\n\t}\n\telse { // <1:扣比例\n\t\tcore.setFlag(\"equip_atk_buff\", core.getFlag(\"equip_atk_buff\", 1) - core.values.weakValue + 1);\n\t\tcore.setFlag(\"equip_def_buff\", core.getFlag(\"equip_def_buff\", 1) - core.values.weakValue + 1);\n\t}\n}\ncore.removeFlag('curse');", "lifeWand": "core.insertAction([\n\t{\"type\": \"input\", \"text\": \"请输入生命魔杖使用次数:(0-${item:lifeWand})\"},\n\t{\"type\": \"if\", \"condition\": \"flag:input<=item:lifeWand\",\n\t\t\"true\": [\n\t\t\t{\"type\": \"setValue\", \"name\": \"item:lifeWand\", \"value\": \"item:lifeWand-flag:input\"},\n\t\t\t{\"type\": \"setValue\", \"name\": \"status:hp\", \"value\": \"status:hp+flag:input*100\"},\n\t\t\t\"成功使用${flag:input}次生命魔杖,恢复${flag:input*100}点生命。\"\n\t\t],\n\t\t\"false\": [\"输入不合法!\"]\n\t},\n]);\ncore.addItem('lifeWand', 1);", "jumpShoes": "core.insertAction({\"type\":\"jumpHero\",\"loc\":[core.nextX(2),core.nextY(2)]});", "redPotion": "core.status.hero.hp += core.values.redPotion", @@ -411,5 +411,6 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "greenJewel": "true", "yellowJewel": "true", "skill1": "true" - } + }, + "canEquip": {} } \ No newline at end of file From 962cc005c67ff2743e4b310b6fb9c962a8f28703 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 8 Dec 2018 20:19:06 +0800 Subject: [PATCH 24/81] weakValue --- libs/events.js | 4 ++-- project/functions.js | 4 ++-- project/items.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/events.js b/libs/events.js index 0a9c0e1d..048e3118 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1889,8 +1889,8 @@ events.prototype.passNet = function (data) { core.status.hero.def -= core.values.weakValue; } else { // <1:扣比例 - core.setFlag("equip_atk_buff", core.getFlag("equip_atk_buff", 1) + core.values.weakValue - 1); - core.setFlag("equip_def_buff", core.getFlag("equip_def_buff", 1) + core.values.weakValue - 1); + core.setFlag("equip_atk_buff", core.getFlag("equip_atk_buff", 1) - core.values.weakValue); + core.setFlag("equip_def_buff", core.getFlag("equip_def_buff", 1) - core.values.weakValue); } } if (data.event.id=='curseNet') { // 咒网 diff --git a/project/functions.js b/project/functions.js index 5e677c96..5e21f9d1 100644 --- a/project/functions.js +++ b/project/functions.js @@ -184,8 +184,8 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.status.hero.def -= core.values.weakValue; } else { // <1:扣比例 - core.setFlag("equip_atk_buff", core.getFlag("equip_atk_buff", 1) + core.values.weakValue - 1); - core.setFlag("equip_def_buff", core.getFlag("equip_def_buff", 1) + core.values.weakValue - 1); + core.setFlag("equip_atk_buff", core.getFlag("equip_atk_buff", 1) - core.values.weakValue); + core.setFlag("equip_def_buff", core.getFlag("equip_def_buff", 1) - core.values.weakValue); } } // 诅咒 diff --git a/project/items.js b/project/items.js index 4f925f40..8b25809c 100644 --- a/project/items.js +++ b/project/items.js @@ -368,9 +368,9 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "upFly": "var loc = {'direction': core.status.hero.loc.direction, 'x': core.status.event.data.x, 'y': core.status.event.data.y};\ncore.changeFloor(core.status.event.data.id, null, loc, null, function (){\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\tcore.replay();\n});", "downFly": "var loc = {'direction': core.status.hero.loc.direction, 'x': core.status.event.data.x, 'y': core.status.event.data.y};\ncore.changeFloor(core.status.event.data.id, null, loc, null, function (){\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\tcore.replay();\n});", "poisonWine": "core.removeFlag('poison');", - "weakWine": "core.removeFlag('weak');\nif (core.values.weakValue>=1) { // >=1:直接扣数值\n\tcore.status.hero.atk += core.values.weakValue;\n\tcore.status.hero.def += core.values.weakValue;\n}\nelse { // <1:扣比例\n\tcore.setFlag(\"equip_atk_buff\", core.getFlag(\"equip_atk_buff\", 1) - core.values.weakValue + 1);\n\tcore.setFlag(\"equip_def_buff\", core.getFlag(\"equip_def_buff\", 1) - core.values.weakValue + 1);\n}", + "weakWine": "core.removeFlag('weak');\nif (core.values.weakValue>=1) { // >=1:直接扣数值\n\tcore.status.hero.atk += core.values.weakValue;\n\tcore.status.hero.def += core.values.weakValue;\n}\nelse { // <1:扣比例\n\tcore.setFlag(\"equip_atk_buff\", core.getFlag(\"equip_atk_buff\", 1) + core.values.weakValue);\n\tcore.setFlag(\"equip_def_buff\", core.getFlag(\"equip_def_buff\", 1) + core.values.weakValue);\n}", "curseWine": "core.removeFlag('curse');", - "superWine": "core.removeFlag('poison');\nif (core.hasFlag('weak')) {\n\tcore.removeFlag('weak');\n\tif (core.values.weakValue>=1) { // >=1:直接扣数值\n\t\tcore.status.hero.atk += core.values.weakValue;\n\t\tcore.status.hero.def += core.values.weakValue;\n\t}\n\telse { // <1:扣比例\n\t\tcore.setFlag(\"equip_atk_buff\", core.getFlag(\"equip_atk_buff\", 1) - core.values.weakValue + 1);\n\t\tcore.setFlag(\"equip_def_buff\", core.getFlag(\"equip_def_buff\", 1) - core.values.weakValue + 1);\n\t}\n}\ncore.removeFlag('curse');", + "superWine": "core.removeFlag('poison');\nif (core.hasFlag('weak')) {\n\tcore.removeFlag('weak');\n\tif (core.values.weakValue>=1) { // >=1:直接扣数值\n\t\tcore.status.hero.atk += core.values.weakValue;\n\t\tcore.status.hero.def += core.values.weakValue;\n\t}\n\telse { // <1:扣比例\n\t\tcore.setFlag(\"equip_atk_buff\", core.getFlag(\"equip_atk_buff\", 1) + core.values.weakValue);\n\t\tcore.setFlag(\"equip_def_buff\", core.getFlag(\"equip_def_buff\", 1) + core.values.weakValue);\n\t}\n}\ncore.removeFlag('curse');", "lifeWand": "core.insertAction([\n\t{\"type\": \"input\", \"text\": \"请输入生命魔杖使用次数:(0-${item:lifeWand})\"},\n\t{\"type\": \"if\", \"condition\": \"flag:input<=item:lifeWand\",\n\t\t\"true\": [\n\t\t\t{\"type\": \"setValue\", \"name\": \"item:lifeWand\", \"value\": \"item:lifeWand-flag:input\"},\n\t\t\t{\"type\": \"setValue\", \"name\": \"status:hp\", \"value\": \"status:hp+flag:input*100\"},\n\t\t\t\"成功使用${flag:input}次生命魔杖,恢复${flag:input*100}点生命。\"\n\t\t],\n\t\t\"false\": [\"输入不合法!\"]\n\t},\n]);\ncore.addItem('lifeWand', 1);", "jumpShoes": "core.insertAction({\"type\":\"jumpHero\",\"loc\":[core.nextX(2),core.nextY(2)]});", "redPotion": "core.status.hero.hp += core.values.redPotion", From 7d9c111479b991d9274efc5f518b653eb3de0c44 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 8 Dec 2018 21:06:30 +0800 Subject: [PATCH 25/81] fog onerror --- libs/core.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/core.js b/libs/core.js index 6a602754..21972a8d 100644 --- a/libs/core.js +++ b/libs/core.js @@ -331,6 +331,9 @@ core.prototype.init = function (coreData, callback) { core.material.ground.src = "project/images/ground.png"; core.animateFrame.weather.fog = new Image(); + core.animateFrame.weather.fog.onerror = function () { + core.animateFrame.weather.fog = null; + } core.animateFrame.weather.fog.src = "project/images/fog.png"; core.bigmap.tempCanvas = document.createElement('canvas').getContext('2d'); From 58ba6b57b0cabb64158449197c79fd77c7b25fbd Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 8 Dec 2018 23:58:04 +0800 Subject: [PATCH 26/81] onload --- libs/loader.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/libs/loader.js b/libs/loader.js index 5ff3c386..ff24e929 100644 --- a/libs/loader.js +++ b/libs/loader.js @@ -106,14 +106,10 @@ loader.prototype.loadImage = function (imgName, callback) { if (name.indexOf(".")<0) name=name+".png"; var image = new Image(); - image.src = 'project/images/' + name + "?v=" + main.version; - if (image.complete) { - callback(imgName, image); - return; - } image.onload = function () { callback(imgName, image); } + image.src = 'project/images/' + name + "?v=" + main.version; } catch (e) { console.log(e); From 09f130e049cdd4e4b3372172684182a79894dc1b Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Sun, 9 Dec 2018 18:28:02 +0800 Subject: [PATCH 27/81] scrollText --- _server/blockly/MotaAction.g4 | 20 ++++++++++++- _server/editor_blockly.js | 2 ++ docs/event.md | 28 ++++++++++++++++-- libs/control.js | 7 +++-- libs/events.js | 17 +++++++++++ libs/ui.js | 56 +++++++++++++++++++++++++++++++++++ 6 files changed, 123 insertions(+), 7 deletions(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 399a4c1b..09bde8b4 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -222,6 +222,7 @@ action | text_1_s | comment_s | autoText_s + | scrollText_s | setText_s | tip_s | setValue_s @@ -365,6 +366,19 @@ var code = '{"type": "autoText", "text": "'+title+EvalString_1+EvalString_2+'", return code; */; +scrollText_s + : '滚动剧情文本:' '时间' Int '不等待执行完毕' Bool? BGNL? EvalString Newline + + +/* scrollText_s +tooltip : scrollText:滚动剧情文本,将从下到上进行滚动显示。 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=scrollText%ef%bc%9a%e6%bb%9a%e5%8a%a8%e5%89%a7%e6%83%85%e6%96%87%e6%9c%ac +default : [5000,false,"时间是总时间,可以使用setText事件来控制字体、颜色、大小、偏移量等"] +Bool_0 = Bool_0?', "async": true':''; +var code = '{"type": "scrollText", "text": "'+EvalString_0+'"'+Bool_0+', "time" :'+Int_0+'},\n'; +return code; +*/; + setText_s : '设置剧情文本的属性' '位置' SetTextPosition_List '偏移像素' EvalString? BGNL? '标题颜色' EvalString? '正文颜色' EvalString? '背景色' EvalString? '粗体' B_1_List BGNL? '标题字体大小' EvalString? '正文字体大小' EvalString? '打字间隔' EvalString? Newline @@ -1906,8 +1920,12 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['autoText_s'].xmlText([ '','','',data.time||0,this.EvalString(data.text),this.next]); break; + case "scrollText": + this.next = MotaActionBlocks['scrollText_s'].xmlText([ + data.time, data.async||false, this.EvalString(data.text), this.next]); + break; case "comment": // 注释 - this.next = MotaActionBlocks['comment_s'].xmlText([data.text,this.next]); + this.next = MotaActionBlocks['comment_s'].xmlText([this.EvalString(data.text),this.next]); break; case "setText": // 设置剧情文本的属性 var setTextfunc = function(a){return a?JSON.stringify(a).slice(1,-1):null;} diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index c16c0a12..864fb7fd 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -60,6 +60,7 @@ editor_blockly = function () { MotaActionBlocks['text_1_s'].xmlText(), MotaActionBlocks['comment_s'].xmlText(), MotaActionBlocks['autoText_s'].xmlText(), + MotaActionBlocks['scrollText_s'].xmlText(), MotaActionBlocks['setText_s'].xmlText(), MotaActionBlocks['showImage_0_s'].xmlText(), MotaActionBlocks['animateImage_0_s'].xmlText(), @@ -492,6 +493,7 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ 'text_0_s': 'EvalString_0', 'text_1_s': 'EvalString_2', 'autoText_s': 'EvalString_2', + 'scrollText_s': 'EvalString_0', 'comment_s': 'EvalString_0', 'choices_s': 'EvalString_0', 'function_s': 'RawEvalString_0', diff --git a/docs/event.md b/docs/event.md index 69e2214a..328c1900 100644 --- a/docs/event.md +++ b/docs/event.md @@ -316,15 +316,35 @@ time为可选项,代表该自动文本的时间。可以不指定,不指定 !> 由于用户无法跳过自动剧情文本,因此对于大段剧情文本请自行添加“是否跳过剧情”的提示,否则可能会非常不友好。 +### scrollText:滚动剧情文本 + +使用`{"type": "scrollText"}`可以使用滚动剧情文本,即将一段文字从屏幕最下方滚动到屏幕最上方。 + +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "scrollText", "text": "第一排\n第二牌\n\n空行后的一排", "time": 5000, "async": true}, +] +``` + +text为正文文本内容。可以使用`${ }`来计算表达式的值,且使用`\n`手动换行。系统不会对滚动剧情文本进行自动换行。 + +time为可选项,代表总的滚动时间。默认为5000毫秒。 + +async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。 + +可以使用下面的[设置剧情文本的属性](event#setText:设置剧情文本的属性)来对文字颜色、文字大小、粗体、距离左边的偏移量进行设置。 + +!> 滚动剧情文本会绘制在UI层(和对话框冲突)!如果是异步处理请注意不要和对话框混用。 + ### setText:设置剧情文本的属性 使用`{"type": "setText"}`可以设置剧情文本的各项属性。 ``` js "x,y": [ // 实际执行的事件列表 - {"type": "setText", "title": [255,0,0], "text": [255,255,0], "background": [0,0,255,0.3]}, - {"type": "setText", "position": "up", "bold": true, "titlefont": 26, "textfont": 17, "time": 70}, - "这段话将显示在上方,标题为红色,正文为黄色粗体,背景为透明度0.3的蓝色,标题26px,正文17px,70毫秒速度打字机效果", + {"type": "setText", "title": [255,0,0], "text": [255,255,0], "background": [0,0,255,0.3], "time": 70}, + {"type": "setText", "position": "up", "offset": 15, "bold": true, "titlefont": 26, "textfont": 17}, + "这段话将显示在上方(距离顶端15像素),标题为红色,正文为黄色粗体,背景为透明度0.3的蓝色,标题26px,正文17px,70毫秒速度打字机效果", {"type": "setText", "background": "winskin.png"} // 还可以一张使用WindowSkin作为皮肤。 ] ``` @@ -339,6 +359,8 @@ V2.5.2以后,background也可以为一个WindowSkin的文件名。详见[剧 position为可选项,表示设置文字显示位置。只能为up(上),center(中)和down(下)三者。 默认值: `center` +offset为可选项,如果设置则为代表距离如果显示位置是上/下的话,距离顶端/底端的像素值。也作为滚动剧情文本时距离左边的像素值。 + bold为可选项,如果设置则为true或false,表示正文是否使用粗体。 默认值:`false` titlefont为可选项,表示标题字体大小(px为单位)。默认值:`22` diff --git a/libs/control.js b/libs/control.js index d3f25f7d..f3ae58b9 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2686,7 +2686,7 @@ control.prototype.pauseBgm = function () { core.musicStatus.isPlaying = false; } catch (e) { - console.log("无法暂停BGM "+bgm); + console.log("无法暂停BGM"); console.log(e); } } @@ -2714,7 +2714,7 @@ control.prototype.resumeBgm = function () { } } catch (e) { - console.log("无法恢复BGM "+bgm); + console.log("无法恢复BGM"); console.log(e); } } @@ -3310,7 +3310,8 @@ control.prototype.resize = function(clientWidth, clientHeight) { core.dom.statusCanvas.width = 129; core.dom.statusCanvas.height = 416; } - this.updateStatusBar(); + if (core.isPlaying()) + core.updateStatusBar(); } ////// 渲染DOM ////// diff --git a/libs/events.js b/libs/events.js index 048e3118..e8166ec8 100644 --- a/libs/events.js +++ b/libs/events.js @@ -422,6 +422,23 @@ events.prototype.doAction = function() { }, data.time || 3000); } break; + case "scrollText": // 滚动剧情文本 + if (core.status.replay.replaying) + core.events.doAction(); + else { + var content = core.replaceText(data.text); + var time = data.time || 5000; + if (data.async) { + core.ui.drawScrollText(content, time); + core.events.doAction(); + } + else { + core.ui.drawScrollText(content, time, function() { + core.events.doAction(); + }); + } + } + break; case "comment": this.doAction(); break; diff --git a/libs/ui.js b/libs/ui.js index 27ba3e00..a620dfb6 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -721,6 +721,62 @@ ui.prototype.drawTextBox = function(content, showAll) { } +////// 绘制滚动字幕 ////// +ui.prototype.drawScrollText = function (content, time, callback) { + + content = content || ""; + time = time || 5000; + + clearInterval(core.status.event.interval); + core.status.event.interval = null; + + // 获得颜色的盒子等信息 + var textAttribute = core.status.textAttribute || core.initStatus.textAttribute; + var textfont = textAttribute.textfont || 16; + var offset = textAttribute.offset || 15; + var textColor = core.arrayToRGBA(textAttribute.text); + + var font = textfont+"px "+core.status.globalAttribute.font; + if (textAttribute.bold) font = "bold "+font; + var contents = core.splitLines('ui', content), lines = contents.length; + + // 计算总高度,按1.2倍行距计算 + var width = 416, height = textfont * 1.4 * lines; + var tempCanvas = core.bigmap.tempCanvas; + tempCanvas.canvas.width = width; + tempCanvas.canvas.height = height; + tempCanvas.clearRect(0, 0, width, height); + tempCanvas.font = font; + tempCanvas.fillStyle = textColor; + + // 全部绘制 + var currH = textfont; + for (var i = 0; i < lines; ++i) { + var text = contents[i]; + tempCanvas.fillText(text, offset, currH); + currH += 1.4 * textfont; + } + + // 开始绘制到UI上 + core.clearMap('ui'); + var per_pixel = 1, per_time = time * per_pixel / (416+height); + var currH = 416; + core.canvas.ui.drawImage(tempCanvas.canvas, 0, currH); + var animate = setInterval(function () { + core.clearMap('ui'); + currH -= per_pixel; + if (currH < -height) { + delete core.animateFrame.asyncId[animate]; + clearInterval(animate); + if (core.isset(callback)) callback(); + return; + } + core.canvas.ui.drawImage(tempCanvas.canvas, 0, currH); + }, per_time); + + core.animateFrame.asyncId[animate] = true; +} + ////// 绘制一个选项界面 ////// ui.prototype.drawChoices = function(content, choices) { From 52a04029b759bf0db3a24c80b1d53195e3625440 Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 9 Dec 2018 22:10:02 +0800 Subject: [PATCH 28/81] 2.5.3 --- docs/V2.0.md | 2 +- docs/api.md | 2 +- docs/element.md | 2 +- docs/event.md | 2 +- docs/index.md | 2 +- docs/personalization.md | 2 +- docs/start.md | 2 +- main.js | 2 +- project/data.js | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/V2.0.md b/docs/V2.0.md index 908ca193..9c44dfa1 100644 --- a/docs/V2.0.md +++ b/docs/V2.0.md @@ -1,6 +1,6 @@ # V2.0版本介绍 -?> 目前版本**v2.5.2**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.3**,上次更新时间:* {docsify-updated} * 目前样板已经更新到V2.0版本以上,本章将对V2.0的一些内容进行介绍。 diff --git a/docs/api.md b/docs/api.md index c1f9bc74..559f810a 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,6 +1,6 @@ # 附录: API列表 -?> 目前版本**v2.5.2**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.3**,上次更新时间:* {docsify-updated} * **这里只列出所有可能会被造塔者用到的常用API,更多的有关内容请在代码内进行查询。** diff --git a/docs/element.md b/docs/element.md index 7ef586d3..807cacf4 100644 --- a/docs/element.md +++ b/docs/element.md @@ -1,6 +1,6 @@ # 元件说明 -?> 目前版本**v2.5.2**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.3**,上次更新时间:* {docsify-updated} * 在本章中,将对样板里的各个元件进行说明。各个元件主要包括道具、门、怪物、楼梯等等。 diff --git a/docs/event.md b/docs/event.md index 328c1900..f691e69a 100644 --- a/docs/event.md +++ b/docs/event.md @@ -1,6 +1,6 @@ # 事件 -?> 目前版本**v2.5.2**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.3**,上次更新时间:* {docsify-updated} * 本章内将对样板所支持的事件进行介绍。 diff --git a/docs/index.md b/docs/index.md index f46c24e5..1689ac40 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,6 @@ # HTML5 魔塔样板说明文档 -?> 目前版本**v2.5.2**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.3**,上次更新时间:* {docsify-updated} * 众所周知,魔塔的趋势是向移动端发展,贴吧中也常常能见到“求手机魔塔”的帖子。然而现有的工具中,NekoRPG有着比较大的局限性,游戏感较差,更是完全没法在iOS上运行。而一些APP的魔塔虽然可用,但是必须要下载安装,对于Android和iOS还必须开发不同的版本,非常麻烦。 diff --git a/docs/personalization.md b/docs/personalization.md index 153ee029..330ea050 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -1,6 +1,6 @@ # 个性化 -?> 目前版本**v2.5.2**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.3**,上次更新时间:* {docsify-updated} * 有时候只靠样板本身可能是不够的。我们需要一些个性化、自定义的素材,道具效果,怪物属性,等等。 diff --git a/docs/start.md b/docs/start.md index 27a6b3c8..1b4bcd71 100644 --- a/docs/start.md +++ b/docs/start.md @@ -1,6 +1,6 @@ # 快速上手 -?> 目前版本**v2.5.2**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.3**,上次更新时间:* {docsify-updated} * 在这一节中,将详细介绍做一部塔的流程。现在,让我们来做一部单层塔! diff --git a/main.js b/main.js index 0ea10df4..107ac52b 100644 --- a/main.js +++ b/main.js @@ -2,7 +2,7 @@ function main() { //------------------------ 用户修改内容 ------------------------// - this.version = "2.5.2"; // 游戏版本号;如果更改了游戏内容建议修改此version以免造成缓存问题。 + this.version = "2.5.3"; // 游戏版本号;如果更改了游戏内容建议修改此version以免造成缓存问题。 this.useCompress = false; // 是否使用压缩文件 // 当你即将发布你的塔时,请使用“JS代码压缩工具”将所有js代码进行压缩,然后将这里的useCompress改为true。 diff --git a/project/data.js b/project/data.js index 9498941c..592286c9 100644 --- a/project/data.js +++ b/project/data.js @@ -70,7 +70,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "firstData": { "title": "魔塔样板", "name": "template", - "version": "Ver 2.5.2", + "version": "Ver 2.5.3", "floorId": "sample0", "hero": { "name": "阳光", From f891cb1f3b4e4b442c7d2279697bd553d73c6546 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 10 Dec 2018 01:50:24 +0800 Subject: [PATCH 29/81] keyUp in replay --- libs/actions.js | 6 +++--- libs/control.js | 2 +- libs/core.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index 55212e0b..e4421355 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -192,12 +192,12 @@ actions.prototype.keyDown = function(keyCode) { } ////// 根据放开键的code来执行一系列操作 ////// -actions.prototype.keyUp = function(keyCode, altKey) { - if (core.isset(core.status.replay)&&core.status.replay.replaying +actions.prototype.keyUp = function(keyCode, altKey, fromReplay) { + if (!fromReplay && core.isset(core.status.replay)&&core.status.replay.replaying &&core.status.event.id!='save'&&(core.status.event.id||"").indexOf('book')!=0&&core.status.event.id!='viewMaps') return; if (core.status.lockControl) { - core.status.holdingKeys = []; + core.status.holdingKeys = [];g // 全键盘操作部分 if (core.status.event.id == 'text' && (keyCode==13 || keyCode==32 || keyCode==67)) { core.drawText(); diff --git a/libs/control.js b/libs/control.js index f3ae58b9..f29c0361 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2130,7 +2130,7 @@ control.prototype.replay = function () { } } else if (action.indexOf('key:')==0) { - core.actions.keyUp(parseInt(action.substring(4)), true); + core.actions.keyUp(parseInt(action.substring(4)), false, true); core.replay(); return; } diff --git a/libs/core.js b/libs/core.js index 901b664c..b77b0288 100644 --- a/libs/core.js +++ b/libs/core.js @@ -428,8 +428,8 @@ core.prototype.keyDown = function(keyCode) { } ////// 根据放开键的code来执行一系列操作 ////// -core.prototype.keyUp = function(keyCode, altKey) { - return core.actions.keyUp(keyCode, altKey); +core.prototype.keyUp = function(keyCode, altKey, fromReplay) { + return core.actions.keyUp(keyCode, altKey, fromReplay); } ////// 点击(触摸)事件按下时 ////// From 96500c5dabc40f5831bfce11d0c708a528f4b099 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 10 Dec 2018 01:51:51 +0800 Subject: [PATCH 30/81] keyUp in replay --- libs/actions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/actions.js b/libs/actions.js index e4421355..e51b297d 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -197,7 +197,7 @@ actions.prototype.keyUp = function(keyCode, altKey, fromReplay) { &&core.status.event.id!='save'&&(core.status.event.id||"").indexOf('book')!=0&&core.status.event.id!='viewMaps') return; if (core.status.lockControl) { - core.status.holdingKeys = [];g + core.status.holdingKeys = []; // 全键盘操作部分 if (core.status.event.id == 'text' && (keyCode==13 || keyCode==32 || keyCode==67)) { core.drawText(); From 3eecce4812b42d01e5c10077b47131e6c3a57af5 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 10 Dec 2018 10:20:43 +0800 Subject: [PATCH 31/81] Update docs --- docs/personalization.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/personalization.md b/docs/personalization.md index 330ea050..98cfa110 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -8,17 +8,17 @@ HTML5魔塔是使用画布(canvas)来绘制,存在若干个图层,它们之间有一个覆盖关系,后面的图层将覆盖前面的图层。 -所有图层从低往高依次如下: +所有图层从低往高依次如下:(加[B]的代表该层是大地图) -- bg:背景层;绘制背景图层素材bgmap,和背景贴图 -- event:事件层;所有事件(道具、墙壁、NPC、怪物等)都绘制在这一层进行处理 +- bg[B]:背景层;绘制背景图层素材bgmap,和背景贴图 +- event[B]:事件层;所有事件(道具、墙壁、NPC、怪物等)都绘制在这一层进行处理 - hero:勇士层;主要用来绘制勇士 -- event2:事件2层;本层主要用来绘制48x32的图片素材的上半部分(避免和勇士错位) -- fg:前景层;绘制前景图层素材fgmap,和前景贴图 -- damage:显伤层;主要用来绘制怪物显伤和领域显伤 -- animate:动画层;主要用来绘制动画。showImage事件绘制的图片也是在这一层。 -- weather:天气层;主要用来绘制天气(雨/雪) -- route:路线层;主要用来绘制勇士的行走路线图,也用来绘制图块的淡入/淡出效果,图块的移动等。 +- event2[B]:事件2层;本层主要用来绘制48x32的图片素材的上半部分(避免和勇士错位) +- fg[B]:前景层;绘制前景图层素材fgmap,和前景贴图 +- damage[B]:显伤层;主要用来绘制怪物显伤和领域显伤 +- animate:动画层;主要用来绘制动画。 +- weather:天气层;主要用来绘制天气(雨/雪/雾) +- route[B]:路线层;主要用来绘制勇士的行走路线图,也用来绘制图块的淡入/淡出效果,图块的移动等。 - curtain:色调层;用来控制当前楼层的画面色调 - image:图片层;主要用来绘制显示图片;该层之所以在curtain层上是为了可以在全黑时贴大头像图 - ui:UI层;用来绘制一切UI窗口,如剧情文本、怪物手册、楼传器、系统菜单等等 From fbacf6fe96aa0e28fc847c39c699a9eac8124bc9 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 10 Dec 2018 10:28:47 +0800 Subject: [PATCH 32/81] Update docs --- docs/personalization.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/personalization.md b/docs/personalization.md index 98cfa110..a3816fc6 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -10,15 +10,15 @@ HTML5魔塔是使用画布(canvas)来绘制,存在若干个图层,它们 所有图层从低往高依次如下:(加[B]的代表该层是大地图) -- bg[B]:背景层;绘制背景图层素材bgmap,和背景贴图 -- event[B]:事件层;所有事件(道具、墙壁、NPC、怪物等)都绘制在这一层进行处理 +- bg**[B]**:背景层;绘制背景图层素材bgmap,和背景贴图 +- event**[B]**:事件层;所有事件(道具、墙壁、NPC、怪物等)都绘制在这一层进行处理 - hero:勇士层;主要用来绘制勇士 -- event2[B]:事件2层;本层主要用来绘制48x32的图片素材的上半部分(避免和勇士错位) -- fg[B]:前景层;绘制前景图层素材fgmap,和前景贴图 -- damage[B]:显伤层;主要用来绘制怪物显伤和领域显伤 +- event2**[B]**:事件2层;本层主要用来绘制48x32的图片素材的上半部分(避免和勇士错位) +- fg**[B]**:前景层;绘制前景图层素材fgmap,和前景贴图 +- damage**[B]**:显伤层;主要用来绘制怪物显伤和领域显伤 - animate:动画层;主要用来绘制动画。 - weather:天气层;主要用来绘制天气(雨/雪/雾) -- route[B]:路线层;主要用来绘制勇士的行走路线图,也用来绘制图块的淡入/淡出效果,图块的移动等。 +- route**[B]**:路线层;主要用来绘制勇士的行走路线图,也用来绘制图块的淡入/淡出效果,图块的移动等。 - curtain:色调层;用来控制当前楼层的画面色调 - image:图片层;主要用来绘制显示图片;该层之所以在curtain层上是为了可以在全黑时贴大头像图 - ui:UI层;用来绘制一切UI窗口,如剧情文本、怪物手册、楼传器、系统菜单等等 @@ -351,10 +351,11 @@ function (enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) { ``` js // 写在获得道具后事件 [ - {"type": "setValue", "name": "no_zone", "value": "true"}, // 免疫领域 - {"type": "setValue", "name": "no_snipe", "value": "true"}, // 免疫阻击 - {"type": "setValue", "name": "no_laser", "value": "true"}, // 免疫激光 - {"type": "setValue", "name": "no_betweenAttack", "value": "true"}, // 免疫夹击 + // 设置不同的flag可以分别无视对应的阻激夹域效果 + {"type": "setValue", "name": "flag:no_zone", "value": "true"}, // 免疫领域 + {"type": "setValue", "name": "flag:no_snipe", "value": "true"}, // 免疫阻击 + {"type": "setValue", "name": "flag:no_laser", "value": "true"}, // 免疫激光 + {"type": "setValue", "name": "flag:no_betweenAttack", "value": "true"}, // 免疫夹击 ] ``` 4. 如果有更高的需求,例如想让吸血效果变成一半,则还是在上面这些地方进行对应的修改即可。 @@ -620,7 +621,7 @@ this.statusBar = { }, 'icons': { // ...其他略 - 'speed': 24, // 图标的定义,这里对应的是icons.png中的索引 + 'speed': 37, // 图标的定义,这里对应的是icons.png中的索引 }, // ...其他略 'speed': document.getElementById('speed'), // 显示内容(数据)的定义 From 553db5d1dae8bbee3843e3bd5b9542c80ad5c069 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 10 Dec 2018 23:49:42 +0800 Subject: [PATCH 33/81] checkLvUp --- libs/events.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/events.js b/libs/events.js index e8166ec8..6f37b4d3 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1827,8 +1827,9 @@ events.prototype.checkLvUp = function () { if (core.status.hero.experience>=need) { // 升级 core.status.hero.lv++; - core.insertAction(core.firstData.levelUp[core.status.hero.lv-1].action); - this.checkLvUp(); + core.insertAction(core.firstData.levelUp[core.status.hero.lv-1].action, null, null, function() { + core.events.checkLvUp(); + }); } } From a6260d9edd3ae21695d826a7ef970d4818666fb4 Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 11 Dec 2018 01:44:01 +0800 Subject: [PATCH 34/81] clear exp in levelUp --- _server/blockly/MotaAction.g4 | 9 +++++---- libs/events.js | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 09bde8b4..5f44aef1 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -50,15 +50,16 @@ return code; */; levelCase - : '需求' expression '称号' EvalString? BGNL? Newline action+ + : '需求' expression '称号' EvalString? '是否扣除经验' Bool BGNL? Newline action+ /* levelCase tooltip : 升级设定 helpUrl : https://h5mota.com/games/template/docs/#/event?id=%e7%bb%8f%e9%aa%8c%e5%8d%87%e7%ba%a7%ef%bc%88%e8%bf%9b%e9%98%b6%2f%e5%a2%83%e7%95%8c%e5%a1%94%ef%bc%89 -default : [0,"",null] +default : [0,"",false,null] colour : this.subColor -var code = '{"need": "'+expression_0+'", "title": "'+EvalString_0+'", "action": [\n'+action_0+']},\n'; +Bool_0 = Bool_0?', "clear": true':''; +var code = '{"need": "'+expression_0+'", "title": "'+EvalString_0+'"'+Bool_0+', "action": [\n'+action_0+']},\n'; return code; */; @@ -1832,7 +1833,7 @@ ActionParser.prototype.parse = function (obj,type) { var text_choices = null; for(var ii=obj.length-1,choice;choice=obj[ii];ii--) { text_choices=MotaActionBlocks['levelCase'].xmlText([ - MotaActionBlocks['evalString_e'].xmlText([choice.need]),choice.title,this.parseList(choice.action),text_choices]); + MotaActionBlocks['evalString_e'].xmlText([choice.need]),choice.title,choice.clear||false,this.parseList(choice.action),text_choices]); } return MotaActionBlocks['level_m'].xmlText([text_choices]); diff --git a/libs/events.js b/libs/events.js index 6f37b4d3..97fb8201 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1822,14 +1822,15 @@ events.prototype.checkLvUp = function () { if (!core.flags.enableLevelUp || !core.isset(core.firstData.levelUp) || core.status.hero.lv>=core.firstData.levelUp.length) return; // 计算下一个所需要的数值 - var need=core.calValue((core.firstData.levelUp[core.status.hero.lv]||{}).need); + var next = (core.firstData.levelUp[core.status.hero.lv]||{}); + var need = core.calValue(next.need); if (!core.isset(need)) return; if (core.status.hero.experience>=need) { // 升级 core.status.hero.lv++; - core.insertAction(core.firstData.levelUp[core.status.hero.lv-1].action, null, null, function() { - core.events.checkLvUp(); - }); + if (next.clear) core.status.hero.experience -= need; + core.insertAction(next.action); + this.checkLvUp(); } } From f297fc58f7fe42e75ac0e20d0c418576f09793da Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 11 Dec 2018 16:09:45 +0800 Subject: [PATCH 35/81] Fix vertical border color --- libs/control.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/control.js b/libs/control.js index f29c0361..3be65956 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2896,11 +2896,11 @@ control.prototype.updateGlobalAttribute = function (name) { var border = '3px ' + attribute[name] + ' solid'; core.dom.statusBar.style.borderTop = border; core.dom.statusBar.style.borderLeft = border; - core.dom.statusBar.style.borderRight = core.domStyle.isVertical?'':border; + core.dom.statusBar.style.borderRight = core.domStyle.isVertical?border:''; core.dom.gameDraw.style.border = border; core.dom.toolBar.style.borderBottom = border; core.dom.toolBar.style.borderLeft = border; - core.dom.toolBar.style.borderRight = core.domStyle.isVertical?'':border; + core.dom.toolBar.style.borderRight = core.domStyle.isVertical?border:''; break; } case 'statusBarColor': From 0fc267be14cfade5ed0ff5cf78839e3cdfa4a166 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 11 Dec 2018 16:17:08 +0800 Subject: [PATCH 36/81] Update icons.png --- project/images/icons.png | Bin 25694 -> 25438 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/project/images/icons.png b/project/images/icons.png index c5a383c617a6b21df8fb0b916fc229b5579c1da3..ec1e2d4587c5bcea53f3151908601b303ec80e66 100644 GIT binary patch literal 25438 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 literal 25694 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 Ws&$Lm2>(wI1Q|(1i3)K;|Nj9$A)18% From 93dceaa7b8cee68825a4c945ff79618de05fd54c Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 11 Dec 2018 16:47:21 +0800 Subject: [PATCH 37/81] resetMap & fix autotileObjs in load --- docs/api.md | 6 +++++- libs/maps.js | 19 +++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/docs/api.md b/docs/api.md index 559f810a..7ea7b61c 100644 --- a/docs/api.md +++ b/docs/api.md @@ -135,11 +135,15 @@ core.changeFloor('MT5', null, {'x': 3, 'y': 6}, 0) 无动画切换到MT5层的(3 core.resetMap() -重置当前楼层地图。 +重置当前楼层地图和楼层属性。 当我们修改某一层地图后,进游戏读档,会发现修改的内容并没有被更新上去。 这是因为,H5的存档是会存下来每一个楼层的地图的,读档会从档里面获得地图信息。 此时,如果我们在某一层地图执行 core.resetMap() ,则可以立刻从剧本中读取并重置当前楼层地图。 已经被修改过的内容也会相应出现。 +此函数参数有三种形式: + - 不加任何参数,表示重置当前层:core.resetMap() + - 加上一个floorId,表示重置某一层:core.resetMap("MT1") + - 使用一个数组,表示重置若干层:core.resetMap(["MT1", "MT2", "MT3"]) R diff --git a/libs/maps.js b/libs/maps.js index 2c9c5f83..4d8ac72d 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -476,7 +476,7 @@ maps.prototype.drawBgFgMap = function (floorId, canvas, name, animate) { } } } - core.status.autotileAnimateObjs[name+"map"] = core.clone(arr); + if (animate) core.status.autotileAnimateObjs[name+"map"] = core.clone(arr); } ////// 绘制某张地图 ////// @@ -1449,13 +1449,12 @@ maps.prototype.setBgFgMap = function (type, name, loc, floorId, callback) { maps.prototype.resetMap = function(floorId) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return; - core.status.maps[floorId] = this.loadFloor(floorId); - if (floorId==core.status.floorId) { - this.drawMap(floorId, function () { - core.drawTip("地图重置成功"); - }) - } - else { - core.drawTip(floorId+"地图重置成功"); - } + if (typeof floorId == 'string') floorId = [floorId]; + var needRefresh = false; + floorId.forEach(function (t) { + core.status.maps[t] = core.maps.loadFloor(t); + if (t == core.status.floorId) needRefresh = true; + }); + if (needRefresh) this.drawMap(core.status.floorId); + core.drawTip("地图重置成功"); } \ No newline at end of file From 25cdc2324dab20d05557eb8940320f9e2587e466 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 11 Dec 2018 17:21:23 +0800 Subject: [PATCH 38/81] blockly Int_0 --- _server/blockly/MotaAction.g4 | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 5f44aef1..edd7d58e 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -524,7 +524,7 @@ if (EvalString_0 && EvalString_1) { floorstr = ', "loc": ['+EvalString_0.join(',')+']'; } IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); -Int_0 = Int_0 ?(', "time": '+Int_0):''; +Int_0 = Int_0!=='' ?(', "time": '+Int_0):''; Bool_0 = Bool_0 ?', "async": true':''; var code = '{"type": "show"'+floorstr+IdString_0+''+Int_0+Bool_0+'},\n'; return code; @@ -557,7 +557,7 @@ if (EvalString_0 && EvalString_1) { floorstr = ', "loc": ['+EvalString_0.join(',')+']'; } IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); -Int_0 = Int_0 ?(', "time": '+Int_0):''; +Int_0 = Int_0!=='' ?(', "time": '+Int_0):''; Bool_0 = Bool_0 ?', "async": true':''; var code = '{"type": "hide"'+floorstr+IdString_0+''+Int_0+Bool_0+'},\n'; return code; @@ -1131,10 +1131,10 @@ var limit = function(v,min,max) { return v; } Number_0 = limit(Number_0,0,255); -Number_1 = limit(Number_1,0,255); +Number_1 = limit(Number_1,0,255);A Number_2 = limit(Number_2,0,255); Number_3 = limit(Number_3,0,1); -Int_0 = Int_0 ?(', "time": '+Int_0):''; +Int_0 = Int_0!=='' ?(', "time": '+Int_0):''; var async = Bool_0?', "async": true':''; var code = '{"type": "setFg", "color": ['+Number_0+','+Number_1+','+Number_2+','+Number_3+']'+Int_0 +async+'},\n'; return code; @@ -1149,7 +1149,7 @@ tooltip : setFg: 恢复画面色调,动画时间可不填 helpUrl : https://h5mota.com/games/template/docs/#/event?id=setfg%EF%BC%9A%E6%9B%B4%E6%94%B9%E7%94%BB%E9%9D%A2%E8%89%B2%E8%B0%83 default : [500,false] colour : this.soundColor -Int_0 = Int_0 ?(', "time": '+Int_0):''; +Int_0 = Int_0!=='' ?(', "time": '+Int_0):''; var async = Bool_0?', "async": true':''; var code = '{"type": "setFg"'+Int_0 +async+'},\n'; return code; @@ -1183,7 +1183,7 @@ var floorstr = ''; if (PosString_0 && PosString_1) { floorstr = ', "loc": ['+PosString_0+','+PosString_1+']'; } -Int_0 = Int_0 ?(', "time": '+Int_0):''; +Int_0 = Int_0!=='' ?(', "time": '+Int_0):''; Bool_0 = Bool_0?', "keep": true':''; Bool_1 = Bool_1?', "async": true':''; var code = '{"type": "move"'+floorstr+Int_0+Bool_0+Bool_1+', "steps": '+JSON.stringify(StepString_0)+'},\n'; @@ -1199,7 +1199,7 @@ tooltip : moveHero:移动勇士,用这种方式移动勇士的过程中将无 helpUrl : https://h5mota.com/games/template/docs/#/event?id=movehero%EF%BC%9A%E7%A7%BB%E5%8A%A8%E5%8B%87%E5%A3%AB default : [500,false,"上右3下2左上左2"] colour : this.dataColor -Int_0 = Int_0 ?(', "time": '+Int_0):''; +Int_0 = Int_0!=='' ?(', "time": '+Int_0):''; Bool_0 = Bool_0?', "async": true':''; var code = '{"type": "moveHero"'+Int_0+Bool_0+', "steps": '+JSON.stringify(StepString_0)+'},\n'; return code; @@ -1221,7 +1221,7 @@ if (PosString_0 && PosString_1) { if (PosString_2 && PosString_3) { floorstr += ', "to": ['+PosString_2+','+PosString_3+']'; } -Int_0 = Int_0 ?(', "time": '+Int_0):''; +Int_0 = Int_0!=='' ?(', "time": '+Int_0):''; Bool_0 = Bool_0?', "keep": true':''; Bool_1 = Bool_1?', "async": true':''; var code = '{"type": "jump"'+floorstr+''+Int_0+Bool_0+Bool_1+'},\n'; @@ -1241,7 +1241,7 @@ var floorstr = ''; if (PosString_0 && PosString_1) { floorstr = ', "loc": ['+PosString_0+','+PosString_1+']'; } -Int_0 = Int_0 ?(', "time": '+Int_0):''; +Int_0 = Int_0!=='' ?(', "time": '+Int_0):''; Bool_0 = Bool_0?', "async": true':''; var code = '{"type": "jumpHero"'+floorstr+Int_0+Bool_0+'},\n'; return code; @@ -1306,7 +1306,7 @@ tooltip : setVolume: 设置音量 helpUrl : https://h5mota.com/games/template/docs/#/event?id=setvolume%EF%BC%9A%E8%AE%BE%E7%BD%AE%E9%9F%B3%E9%87%8F default : [90, 500, false] colour : this.soundColor -Int_1 = Int_1?(', "time": '+Int_1):"" +Int_1 = Int_1!==''?(', "time": '+Int_1):"" var async = Bool_0?', "async": true':''; var code = '{"type": "setVolume", "value": '+Int_0+Int_1+async+'},\n'; return code; @@ -1917,9 +1917,8 @@ ActionParser.prototype.parseAction = function() { this.EvalString(data.text),this.next]); break; case "autoText": // 自动剧情文本 - data.time=this.isset(data.time)?data.time:MotaActionBlocks['autoText_s'].fieldDefault[3]; this.next = MotaActionBlocks['autoText_s'].xmlText([ - '','','',data.time||0,this.EvalString(data.text),this.next]); + '','','',data.time,this.EvalString(data.text),this.next]); break; case "scrollText": this.next = MotaActionBlocks['scrollText_s'].xmlText([ From 2a855900555b217f7dae937a7155ded7ad6b7a59 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 11 Dec 2018 17:22:22 +0800 Subject: [PATCH 39/81] blockly Int_0 --- _server/blockly/MotaAction.g4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index edd7d58e..5b681deb 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -1131,7 +1131,7 @@ var limit = function(v,min,max) { return v; } Number_0 = limit(Number_0,0,255); -Number_1 = limit(Number_1,0,255);A +Number_1 = limit(Number_1,0,255); Number_2 = limit(Number_2,0,255); Number_3 = limit(Number_3,0,1); Int_0 = Int_0!=='' ?(', "time": '+Int_0):''; From 64a0f0a6aaec62d24906b4e76cdbaad8e6160164 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 11 Dec 2018 18:52:51 +0800 Subject: [PATCH 40/81] Fix item & core.status.event.data --- libs/items.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libs/items.js b/libs/items.js index fcba3daa..f8a7bfc1 100644 --- a/libs/items.js +++ b/libs/items.js @@ -91,6 +91,7 @@ items.prototype.useItem = function (itemId, callback) { delete core.status.hero.items[itemCls][itemId]; core.updateStatusBar(); + core.status.event.data = null; if (core.isset(callback)) callback(); } @@ -100,16 +101,18 @@ items.prototype.canUseItem = function (itemId) { // 没有道具 if (!core.hasItem(itemId)) return false; + var able = false; if (itemId in this.canUseItemEffect) { try { - return eval(this.canUseItemEffect[itemId]); + able = eval(this.canUseItemEffect[itemId]); } catch (e) { console.log(e); } } + if (!able) core.status.event.data = null; - return false; + return able; } ////// 获得某个物品的个数 ////// From 0d587ac712b2d6d152ca810222b92a2bae8e89e2 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 11 Dec 2018 19:44:00 +0800 Subject: [PATCH 41/81] reset status bar on restart --- libs/control.js | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/control.js b/libs/control.js index 3be65956..64db5a3d 100644 --- a/libs/control.js +++ b/libs/control.js @@ -397,6 +397,7 @@ control.prototype.resetStatus = function(hero, hard, floorId, route, maps, value else core.values = core.clone(core.data.values); core.events.initGame(); + this.updateGlobalAttribute(Object.keys(core.status.globalAttribute)); core.status.played = true; } From b646c1cb3e080014bbb68665d9d0437aa2118fd4 Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 11 Dec 2018 23:28:00 +0800 Subject: [PATCH 42/81] firstArrive before eachArrive --- _server/comment.js | 2 +- libs/events.js | 2 +- project/functions.js | 11 +++++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/_server/comment.js b/_server/comment.js index 9577712f..c38b6cd9 100644 --- a/_server/comment.js +++ b/_server/comment.js @@ -334,7 +334,7 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_leaf": true, "_type": "event", "_event": "eachArrive", - "_data": "每次到该楼层触发的事件,可以双击进入事件编辑器;该事件会比firstArrive先执行。" + "_data": "每次到该楼层触发的事件,可以双击进入事件编辑器;该事件会在firstArrive执行后再执行。" }, "parallelDo": { "_leaf": true, diff --git a/libs/events.js b/libs/events.js index 97fb8201..7588fbaa 100644 --- a/libs/events.js +++ b/libs/events.js @@ -117,7 +117,7 @@ events.prototype.startGame = function (hard, seed, route, callback) { core.changeFloor(core.firstData.floorId, null, nowLoc, null, function() { if (core.isset(callback)) callback(); - }, true); + }); setTimeout(function () { // Upload diff --git a/project/functions.js b/project/functions.js index d2ffbc3e..21852685 100644 --- a/project/functions.js +++ b/project/functions.js @@ -87,16 +87,19 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = "afterChangeFloor": function (floorId, fromLoad) { // 转换楼层结束的事件 // floorId是切换到的楼层;fromLoad若为true则代表是从读档行为造成的楼层切换 + + // 每次抵达楼层时执行的事件 + if (!fromLoad) { + core.insertAction(core.floors[floorId].eachArrive); + } + + // 首次抵达楼层时执行的事件(后插入,先执行) var visited = core.getFlag("__visited__", []); if (visited.indexOf(floorId)===-1) { core.insertAction(core.floors[floorId].firstArrive); visited.push(floorId); core.setFlag("__visited__", visited); } - // 每次抵达楼层时执行的事件 - if (!fromLoad) { - core.insertAction(core.floors[floorId].eachArrive); - } }, "addPoint": function (enemy) { // 加点事件 From 7671a925862473a527e23a64d2425dda78ad98d1 Mon Sep 17 00:00:00 2001 From: oc Date: Wed, 12 Dec 2018 12:41:57 +0800 Subject: [PATCH 43/81] formatBigNumber --- docs/api.md | 2 +- libs/control.js | 8 ++++---- libs/core.js | 4 ++-- libs/ui.js | 8 ++++---- libs/utils.js | 18 +++++++++++++----- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/docs/api.md b/docs/api.md index 7ea7b61c..bba4bba2 100644 --- a/docs/api.md +++ b/docs/api.md @@ -504,7 +504,7 @@ core.utils.decodeBase64(str) Base64解密字符串 -core.utils.formatBigNumber(x) +core.utils.formatBigNumber(x, onMap) 大数据的格式化 diff --git a/libs/control.js b/libs/control.js index 64db5a3d..399f0adf 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1374,7 +1374,7 @@ control.prototype.snipe = function (snipes) { else if (damage < core.status.hero.hp) color = '#FF7F00'; else color = '#FF0000'; - damage = core.formatBigNumber(damage); + damage = core.formatBigNumber(damage, true); if (core.enemys.hasSpecial(core.material.enemys[block.event.id], 19)) damage += "+"; if (core.enemys.hasSpecial(core.material.enemys[block.event.id], 21)) @@ -1623,7 +1623,7 @@ control.prototype.updateDamage = function (floorId, canvas) { else if (damage < hero_hp * 2 / 3) color = '#FFFF00'; else if (damage < hero_hp) color = '#FF7F00'; else color = '#FF0000'; - damage = core.formatBigNumber(damage); + damage = core.formatBigNumber(damage, true); if (core.enemys.hasSpecial(core.material.enemys[id], 19)) damage += "+"; if (core.enemys.hasSpecial(core.material.enemys[id], 21)) @@ -1646,7 +1646,7 @@ control.prototype.updateDamage = function (floorId, canvas) { if (core.flags.displayCritical) { var critical = core.enemys.nextCriticals(id); if (critical.length>0) critical=critical[0]; - critical = core.formatBigNumber(critical[0]); + critical = core.formatBigNumber(critical[0], true); if (critical == '???') critical = '?'; canvas.fillStyle = '#000000'; canvas.fillText(critical, 32 * x + 2, 32 * (y + 1) - 2 - 10); @@ -1678,7 +1678,7 @@ control.prototype.updateDamage = function (floorId, canvas) { for (var y=0;y0) { - damage = core.formatBigNumber(damage); + damage = core.formatBigNumber(damage, true); canvas.fillStyle = '#000000'; canvas.fillText(damage, 32 * x + 17, 32 * (y + 1) - 13); canvas.fillText(damage, 32 * x + 15, 32 * (y + 1) - 15); diff --git a/libs/core.js b/libs/core.js index b77b0288..b25d05ba 100644 --- a/libs/core.js +++ b/libs/core.js @@ -1037,8 +1037,8 @@ core.prototype.formatDate2 = function (date) { } ////// 格式化大数 ////// -core.prototype.formatBigNumber = function (x) { - return core.utils.formatBigNumber(x); +core.prototype.formatBigNumber = function (x, onMap) { + return core.utils.formatBigNumber(x, onMap); } ////// 两位数显示 ////// diff --git a/libs/ui.js b/libs/ui.js index a620dfb6..0f60f6db 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2225,8 +2225,8 @@ ui.prototype.drawSLPanel = function(index, refresh) { core.strokeRect('ui', (2*i+1)*u-size/2, 45, size, size, i==offset?strokeColor:'#FFFFFF', i==offset?6:2); if (core.isset(data) && core.isset(data.floorId)) { core.ui.drawThumbnail(data.floorId, 'ui', core.maps.load(data.maps, data.floorId).blocks, (2*i+1)*u-size/2, 45, size, data.hero.loc.x, data.hero.loc.y, data.hero.loc, data.hero.flags.heroIcon||"hero.png"); - var v = core.formatBigNumber(data.hero.hp)+"/"+core.formatBigNumber(data.hero.atk)+"/"+core.formatBigNumber(data.hero.def); - var v2 = "/"+core.formatBigNumber(data.hero.mdef); + var v = core.formatBigNumber(data.hero.hp,true)+"/"+core.formatBigNumber(data.hero.atk,true)+"/"+core.formatBigNumber(data.hero.def,true); + var v2 = "/"+core.formatBigNumber(data.hero.mdef,true); if (v.length+v2.length<=21) v+=v2; core.fillText('ui', v, (2*i+1)*u, 60+size, '#FFD700', '10px '+globalFont); core.fillText('ui', core.formatDate(new Date(data.time)), (2*i+1)*u, 73+size, data.hero.flags.consoleOpened?'#FF6A6A':'#FFFFFF'); @@ -2241,8 +2241,8 @@ ui.prototype.drawSLPanel = function(index, refresh) { core.strokeRect('ui', (2*i-5)*u-size/2, 233, size, size, i==offset?strokeColor:'#FFFFFF', i==offset?6:2); if (core.isset(data) && core.isset(data.floorId)) { core.ui.drawThumbnail(data.floorId, 'ui', core.maps.load(data.maps, data.floorId).blocks, (2*i-5)*u-size/2, 233, size, data.hero.loc.x, data.hero.loc.y, data.hero.loc, data.hero.flags.heroIcon||"hero.png"); - var v = core.formatBigNumber(data.hero.hp)+"/"+core.formatBigNumber(data.hero.atk)+"/"+core.formatBigNumber(data.hero.def); - var v2 = "/"+core.formatBigNumber(data.hero.mdef); + var v = core.formatBigNumber(data.hero.hp,true)+"/"+core.formatBigNumber(data.hero.atk,true)+"/"+core.formatBigNumber(data.hero.def,true); + var v2 = "/"+core.formatBigNumber(data.hero.mdef,true); if (v.length+v2.length<=21) v+=v2; core.fillText('ui', v, (2*i-5)*u, 248+size, '#FFD700', '10px '+globalFont); core.fillText('ui', core.formatDate(new Date(data.time)), (2*i-5)*u, 261+size, data.hero.flags.consoleOpened?'#FF6A6A':'#FFFFFF', '10px '+globalFont); diff --git a/libs/utils.js b/libs/utils.js index b5dcdd2e..e7ba2f23 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -297,14 +297,14 @@ utils.prototype.setTwoDigits = function (x) { return parseInt(x)<10?"0"+x:x; } -utils.prototype.formatBigNumber = function (x) { +utils.prototype.formatBigNumber = function (x, onMap) { x = Math.floor(parseFloat(x)); if (!core.isset(x)) return '???'; var c = x<0?"-":""; x = Math.abs(x); - if (x<=999999) return c + x; + if (x<=99999 || (!onMap && x<=999999)) return c + x; var all = [ {"val": 1e20, "c": "g"}, @@ -316,9 +316,17 @@ utils.prototype.formatBigNumber = function (x) { for (var i=0;i=10*one.val) { - var v = x/one.val; - return c + v.toFixed(Math.max(0, Math.floor(4-Math.log10(v+1)))) + one.c; + if (onMap) { + if (x>=one.val) { + var v = x/one.val; + return c + v.toFixed(Math.max(0, Math.floor(3-Math.log10(v+1)))) + one.c; + } + } + else { + if (x>=10*one.val) { + var v = x/one.val; + return c + v.toFixed(Math.max(0, Math.floor(4-Math.log10(v+1)))) + one.c; + } } } From ccb89e422fcb70da9eac8dd9d486a26d10b5eb5a Mon Sep 17 00:00:00 2001 From: oc Date: Wed, 12 Dec 2018 16:19:42 +0800 Subject: [PATCH 44/81] setInterval time & load statusBar --- libs/control.js | 19 +++++++++---------- libs/events.js | 20 ++++++++++---------- libs/maps.js | 9 +++++---- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/libs/control.js b/libs/control.js index 399f0adf..dc23bb33 100644 --- a/libs/control.js +++ b/libs/control.js @@ -354,9 +354,6 @@ control.prototype.resetStatus = function(hero, hard, floorId, route, maps, value // 清除游戏数据 core.clearStatus(); - // 显示状态栏 - core.control.triggerStatusBar("show"); - // 初始化status core.status = core.clone(core.initStatus); // 初始化maps @@ -398,6 +395,7 @@ control.prototype.resetStatus = function(hero, hard, floorId, route, maps, value core.events.initGame(); this.updateGlobalAttribute(Object.keys(core.status.globalAttribute)); + this.triggerStatusBar(core.getFlag('hideStatusBar', false)?'hide':'show'); core.status.played = true; } @@ -1556,15 +1554,15 @@ control.prototype.setFg = function(color, time, callback) { return; } - var step=0; - // core.status.replay.animate=true; + var per_time = 10, step=0, steps = parseInt(time / per_time); + var changeAnimate = setInterval(function() { step++; - var nowA = fromColor[3]+(color[3]-fromColor[3])*step/25; - var nowR = parseInt(fromColor[0]+(color[0]-fromColor[0])*step/25); - var nowG = parseInt(fromColor[1]+(color[1]-fromColor[1])*step/25); - var nowB = parseInt(fromColor[2]+(color[2]-fromColor[2])*step/25); + var nowA = fromColor[3]+(color[3]-fromColor[3])*step/steps; + var nowR = parseInt(fromColor[0]+(color[0]-fromColor[0])*step/steps); + var nowG = parseInt(fromColor[1]+(color[1]-fromColor[1])*step/steps); + var nowB = parseInt(fromColor[2]+(color[2]-fromColor[2])*step/steps); core.clearMap('curtain'); core.fillRect('curtain', 0, 0, 416, 416, core.arrayToRGBA([nowR,nowG,nowB,nowA])); @@ -1575,7 +1573,7 @@ control.prototype.setFg = function(color, time, callback) { // core.status.replay.animate=false; if (core.isset(callback)) callback(); } - }, time/25/core.status.replay.speed); + }, per_time); core.animateFrame.asyncId[changeAnimate] = true; } @@ -2832,6 +2830,7 @@ control.prototype.triggerStatusBar = function (name) { var statusItems = core.dom.status; var toolItems = core.dom.tools; core.domStyle.showStatusBar = name == 'show'; + core.setFlag('hideStatusBar', core.domStyle.showStatusBar?null:true); if (!core.domStyle.showStatusBar) { for (var i = 0; i < statusItems.length; ++i) statusItems[i].style.opacity = 0; diff --git a/libs/events.js b/libs/events.js index 7588fbaa..f17e8529 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1575,10 +1575,11 @@ events.prototype.animateImage = function (type, image, loc, time, keep, callback core.canvas.data.drawImage(image, x, y); core.setAlpha('data', 1); - // core.status.replay.animate=true; + var per_time = 10, steps = parseInt(time / per_time), delta = 1 / steps; + var animate = setInterval(function () { - if (type=='show') alpha += 0.1; - else alpha -= 0.1; + if (type=='show') alpha += delta; + else alpha -= delta; core.clearMap('data', x, y, image.width, image.height); if (alpha >=1 || alpha<=0) { delete core.animateFrame.asyncId[animate]; @@ -1593,7 +1594,7 @@ events.prototype.animateImage = function (type, image, loc, time, keep, callback core.canvas.data.drawImage(image, x, y); core.setAlpha('data', 1); } - }, time / 10); + }, per_time); core.animateFrame.asyncId[animate] = true; } @@ -1653,21 +1654,20 @@ events.prototype.setVolume = function (value, time, callback) { if (core.isset(callback)) callback(); return; } - // core.status.replay.animate=true; + var currVolume = core.musicStatus.volume; - var step = 0; + var per_time = 10, step = 0, steps = parseInt(time / per_time); var fade = setInterval(function () { step++; - var nowVolume = currVolume+(value-currVolume)*step/32; + var nowVolume = currVolume+(value-currVolume)*step/steps; set(nowVolume); - if (step>=32) { + if (step>=steps) { delete core.animateFrame.asyncId[fade]; clearInterval(fade); - // core.status.replay.animate=false; if (core.isset(callback)) callback(); } - }, time / 32); + }, per_time); core.animateFrame.asyncId[fade] = true; } diff --git a/libs/maps.js b/libs/maps.js index 4d8ac72d..12865f76 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -1091,9 +1091,10 @@ maps.prototype.animateBlock = function (loc,type,time,callback) { core.setAlpha('route', alpha); draw(); - var animate = window.setInterval(function () { - if (type=='show') alpha += 0.1; - else alpha -= 0.1; + var per_time = 10, steps = parseInt(time / per_time), delta = 1 / steps; + var animate = setInterval(function () { + if (type=='show') alpha += delta; + else alpha -= delta; clear(); if (alpha >=1 || alpha<=0) { delete core.animateFrame.asyncId[animate]; @@ -1115,7 +1116,7 @@ maps.prototype.animateBlock = function (loc,type,time,callback) { core.setAlpha('route', alpha); draw(); } - }, time / 10 / core.status.replay.speed); + }, per_time); core.animateFrame.asyncId[animate] = true; } From e5a7c9e10c3f2ecdd91906a38dbdcb7c4ae822e6 Mon Sep 17 00:00:00 2001 From: oc Date: Wed, 12 Dec 2018 16:37:16 +0800 Subject: [PATCH 45/81] setInterval time & load statusBar --- libs/control.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/control.js b/libs/control.js index dc23bb33..beaeb8cc 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1566,7 +1566,7 @@ control.prototype.setFg = function(color, time, callback) { core.clearMap('curtain'); core.fillRect('curtain', 0, 0, 416, 416, core.arrayToRGBA([nowR,nowG,nowB,nowA])); - if (step>=25) { + if (step>=steps) { delete core.animateFrame.asyncId[changeAnimate]; clearInterval(changeAnimate); core.status.curtainColor = color; From 3d2e0c06bb500f7eccff8619e3120d5aa3ec19e4 Mon Sep 17 00:00:00 2001 From: oc Date: Wed, 12 Dec 2018 23:07:38 +0800 Subject: [PATCH 46/81] Fix Ctrl+Z --- _server/editor.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/_server/editor.js b/_server/editor.js index f83e68b4..c9622e6f 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -235,6 +235,7 @@ editor.prototype.changeFloor = function (floorId, callback) { }); editor.currentFloorData[name]=mapArray; } + editor.preMapData = null; core.changeFloor(floorId, null, {"x": 0, "y": 0, "direction": "up"}, null, function () { core.bigmap.offsetX=0; core.bigmap.offsetY=0; @@ -728,7 +729,7 @@ editor.prototype.listen = function () { holdingPath = 0; e.stopPropagation(); if (stepPostfix && stepPostfix.length) { - preMapData = JSON.parse(JSON.stringify({map:editor.map,fgmap:editor.fgmap,bgmap:editor.bgmap})); + editor.preMapData = JSON.parse(JSON.stringify({map:editor.map,fgmap:editor.fgmap,bgmap:editor.bgmap})); if(editor.brushMod!=='line'){ var x0=stepPostfix[0].x; var y0=stepPostfix[0].y; @@ -822,7 +823,7 @@ editor.prototype.listen = function () { } } - var preMapData = {}; + editor.preMapData = null; var currDrawData = { pos: [], info: {} @@ -836,18 +837,18 @@ editor.prototype.listen = function () { if (e.altKey && [48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1) e.preventDefault(); //Ctrl+z 撤销上一步undo - if (e.keyCode == 90 && e.ctrlKey && preMapData && currDrawData.pos.length && selectBox.isSelected) { - editor.map = JSON.parse(JSON.stringify(preMapData.map)); - editor.fgmap = JSON.parse(JSON.stringify(preMapData.fgmap)); - editor.bgmap = JSON.parse(JSON.stringify(preMapData.bgmap)); + if (e.keyCode == 90 && e.ctrlKey && editor.preMapData && currDrawData.pos.length && selectBox.isSelected) { + editor.map = JSON.parse(JSON.stringify(editor.preMapData.map)); + editor.fgmap = JSON.parse(JSON.stringify(editor.preMapData.fgmap)); + editor.bgmap = JSON.parse(JSON.stringify(editor.preMapData.bgmap)); editor.updateMap(); reDo = JSON.parse(JSON.stringify(currDrawData)); currDrawData = {pos: [], info: {}}; - preMapData = null; + editor.preMapData = null; } //Ctrl+y 重做一步redo if (e.keyCode == 89 && e.ctrlKey && reDo && reDo.pos.length && selectBox.isSelected) { - preMapData = JSON.parse(JSON.stringify({map:editor.map,fgmap:editor.fgmap,bgmap:editor.bgmap})); + editor.preMapData = JSON.parse(JSON.stringify({map:editor.map,fgmap:editor.fgmap,bgmap:editor.bgmap})); for (var j = 0; j < reDo.pos.length; j++) editor.map[reDo.pos[j].y][reDo.pos[j].x] = JSON.parse(JSON.stringify(reDo.info)); @@ -1027,7 +1028,7 @@ editor.prototype.listen = function () { copyLoc.onmousedown = function(e){ editor.hideMidMenu(); e.stopPropagation(); - preMapData = null; + editor.preMapData = null; reDo = null; editor_mode.onmode(''); var now = editor.pos; @@ -1060,7 +1061,7 @@ editor.prototype.listen = function () { moveLoc.onmousedown = function(e){ editor.hideMidMenu(); e.stopPropagation(); - preMapData = null; + editor.preMapData = null; reDo = null; var thisevent = editor.map[editor.pos.y][editor.pos.x]; if(thisevent==0){ @@ -1106,7 +1107,7 @@ editor.prototype.listen = function () { clearLoc.onmousedown = function(e){ editor.hideMidMenu(); e.stopPropagation(); - preMapData = null; + editor.preMapData = null; reDo = null; editor.info = 0; editor_mode.onmode(''); From edb3f031361e008b42cca3c5ab00ca998dfab6bd Mon Sep 17 00:00:00 2001 From: oc Date: Wed, 12 Dec 2018 23:21:28 +0800 Subject: [PATCH 47/81] draw confirm box with winskin --- libs/ui.js | 50 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/libs/ui.js b/libs/ui.js index 0f60f6db..b3ea38ed 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -927,9 +927,17 @@ ui.prototype.drawConfirmBox = function (text, yesCallback, noCallback) { if (!core.isset(core.status.event.selection) || core.status.event.selection>1) core.status.event.selection=1; if (core.status.event.selection<0) core.status.event.selection=0; - core.clearMap('ui'); - core.setAlpha('ui', 1); - core.setFillStyle('ui', core.material.groundPattern); + var background = core.status.textAttribute.background; + var isWindowSkin = false; + if (typeof background == 'string') { + background = core.material.images.images[background]; + if (core.isset(background) && background.width==192 && background.height==128) isWindowSkin = true; + else background = core.initStatus.textAttribute.background; + } + if (!isWindowSkin) background = core.arrayToRGBA(background); + var borderColor = core.status.globalAttribute.borderColor; + var textColor = core.arrayToRGBA(core.status.textAttribute.text); + var globalFont = core.status.globalAttribute.font; core.setFont('ui', "bold 19px "+globalFont); @@ -942,29 +950,35 @@ ui.prototype.drawConfirmBox = function (text, yesCallback, noCallback) { var left = Math.min(208 - 40 - parseInt(max_length / 2), 100); var top = 140 - (lines-1)*30; - var right = 416 - 2 * left, bottom = 416 - 140 - top; + var right = 416 - left, bottom = 416 - 140, width = right - left, height = bottom - top; - var borderColor = core.status.globalAttribute.borderColor; + core.clearMap('ui'); + if (isWindowSkin) { + core.setAlpha('ui', 0.85); + this.drawWindowSkin(background,'ui',left,top,width,height); + } + else { + core.fillRect('ui', left, top, width, height, background); + core.strokeRect('ui', left - 1, top - 1, width + 1, height + 1, borderColor, 2); + } + core.setAlpha('ui', 1); - if (core.isPlaying()) - core.fillRect('ui', left, top, right, bottom, core.material.groundPattern); - if (core.isPlaying()) - core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, borderColor, 2); core.canvas.ui.textAlign = "center"; for (var i in contents) { - core.fillText('ui', contents[i], 208, top + 50 + i*30, "#FFFFFF"); + core.fillText('ui', contents[i], 208, top + 50 + i*30, textColor); } - core.fillText('ui', "确定", 208 - 38, top + bottom - 35, "#FFFFFF", "bold 17px "+globalFont); - core.fillText('ui', "取消", 208 + 38, top + bottom - 35); + core.fillText('ui', "确定", 208 - 38, bottom - 35, null, "bold 17px "+globalFont); + core.fillText('ui', "取消", 208 + 38, bottom - 35); var len=core.canvas.ui.measureText("确定").width; - if (core.status.event.selection==0) { - core.strokeRect('ui', 208-38-parseInt(len/2)-5, top+bottom-35-20, len+10, 28, "#FFD700", 2); - } - if (core.status.event.selection==1) { - core.strokeRect('ui', 208+38-parseInt(len/2)-5, top+bottom-35-20, len+10, 28, "#FFD700", 2); - } + + var strokeLeft = 208 + (76*core.status.event.selection-38) - parseInt(len/2) - 5; + + if (isWindowSkin) + this.drawWindowSelector(background, 'ui', strokeLeft, bottom-35-20, len+10, 28); + else + core.strokeRect('ui', strokeLeft, bottom-35-20, len+10, 28, "#FFD700", 2); } From 21abbf933f4fb5c6faa7e4cfafb3cf243bd30e24 Mon Sep 17 00:00:00 2001 From: oc Date: Wed, 12 Dec 2018 23:27:07 +0800 Subject: [PATCH 48/81] Move view project & download to gameInfo --- libs/actions.js | 32 ++++++++++++++++---------------- libs/ui.js | 4 +--- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index e51b297d..fe5a6750 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1821,19 +1821,6 @@ actions.prototype.clickSwitchs = function (x,y) { core.ui.drawSwitchs(); break; case 8: - if (core.platform.isPC) - window.open("editor.html", "_blank"); - else if (confirm("即将离开本塔,跳转至本塔工程页面,确认?")) { - window.location.href = "editor-mobile.html"; - } - break; - case 9: - 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; core.ui.drawSettings(); break; @@ -2414,6 +2401,13 @@ actions.prototype.clickGameInfo = function (x, y) { core.ui.drawStatistics(); break; case 1: + if (core.platform.isPC) + window.open("editor.html", "_blank"); + else if (confirm("即将离开本塔,跳转至本塔工程页面,确认?")) { + window.location.href = "editor-mobile.html"; + } + break; + case 2: if (core.platform.isPC) { window.open("/score.php?name="+core.firstData.name+"&num=10", "_blank"); } @@ -2423,13 +2417,19 @@ actions.prototype.clickGameInfo = function (x, y) { } } break; - case 2: + case 3: core.ui.drawHelp(); break; - case 3: + case 4: core.ui.drawAbout(); break; - case 4: + case 5: + if (core.platform.isPC) + window.open(core.firstData.name+".zip"); + else + window.location.href = core.firstData.name+".zip"; + break; + case 6: core.status.event.selection=5; core.ui.drawSettings(); break; diff --git a/libs/ui.js b/libs/ui.js index b3ea38ed..ec7c1dec 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -995,8 +995,6 @@ ui.prototype.drawSwitchs = function() { "领域显伤: "+(core.flags.displayExtraDamage ? "[ON]" : "[OFF]"), "新版存档: "+(core.platform.useLocalForage ? "[ON]":"[OFF]"), "单击瞬移: "+(core.getFlag('clickMove', true) ? "[ON]":"[OFF]"), - "查看工程", - "下载离线版本", "返回主菜单" ]; this.drawChoices(null, choices); @@ -1401,7 +1399,7 @@ ui.prototype.drawReplay = function () { ui.prototype.drawGameInfo = function () { core.status.event.id = 'gameInfo'; this.drawChoices(null, [ - "数据统计", "查看评论", "操作帮助", "关于本塔", "返回上级菜单" + "数据统计", "查看工程", "查看评论", "操作帮助", "关于本塔","下载离线版本", "返回主菜单" ]); } From 682873673b6170e02b69cf686bd64bcc74543943 Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Wed, 12 Dec 2018 18:27:34 -0500 Subject: [PATCH 49/81] lastusedblocks --- _server/editor_blockly.js | 50 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 864fb7fd..4d4af6a0 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -4,12 +4,13 @@ editor_blockly = function () { initscript = String.raw` (function(){ - var getCategory = function(name){ + var getCategory = function(name,custom){ for(var node of document.getElementById('toolbox').children) { if(node.getAttribute('name')==name) return node; } var node = document.createElement('category'); node.setAttribute('name',name); + if(custom)node.setAttribute('custom',custom); document.getElementById('toolbox').appendChild(node); return node; } @@ -243,15 +244,19 @@ editor_blockly = function () { } ] },'event'), - ], + '最近使用':[ + '', + ] } var toolboxgap = '' //xml_text = MotaActionFunctions.actionParser.parse(obj,type||'event') //MotaActionBlocks['idString_e'].xmlText() for (var name in toolboxObj){ - getCategory(name).innerHTML = toolboxObj[name].join(toolboxgap); + var custom = null; + if(name=='最近使用')custom='searchBlockCategory'; + getCategory(name,custom).innerHTML = toolboxObj[name].join(toolboxgap); } var blocklyArea = document.getElementById('blocklyArea'); @@ -269,6 +274,24 @@ var workspace = Blockly.inject(blocklyDiv,{ }, trashcan: false, }); + +editor_blockly.searchBlockCategoryCallback = function(workspace) { + //var colourList = ['#4286f4', '#ef0447']; + var xmlList = []; + if (Blockly.Blocks['colour_picker']) { + for (var i = 0; i < editor_blockly.lastUsedType.length; i++) { + var blockText = '' + + MotaActionBlocks[editor_blockly.lastUsedType[i]].xmlText() + + ''; + var block = Blockly.Xml.textToDom(blockText).firstChild; + xmlList.push(block); + } + } + return xmlList; +}; + +workspace.registerToolboxCategoryCallback( + 'searchBlockCategory', editor_blockly.searchBlockCategoryCallback); var onresize = function(e) { blocklyDiv.style.width = blocklyArea.offsetWidth + 'px'; @@ -291,6 +314,12 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ var doubleClickCheck=[[0,'abc']]; function omitedcheckUpdateFunction(event) { + console.log(event) + console.log(event.type) + + if(event.type==='ui'||event.type==='move'){ + editor_blockly.addIntoLastUsedType(event.blockId); + } if(event.type==='ui'){ var newClick = [new Date().getTime(),event.blockId]; var lastClick = doubleClickCheck.shift(); @@ -511,6 +540,21 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ } } + editor_blockly.lastUsedType=['comment_s']//初始空着比较难看 + editor_blockly.lastUsedTypeNum=15 + + editor_blockly.addIntoLastUsedType=function(blockId){ + var b = editor_blockly.workspace.getBlockById(blockId); + if(!b)return; + var blockType = b.type; + if(!blockType || ['pass_s','emptyshop'].indexOf(blockType)!==-1)return; + if(editor_blockly.lastUsedType.indexOf(blockType)!==-1){ + editor_blockly.lastUsedType.splice(editor_blockly.lastUsedType.indexOf(blockType),1) + } + editor_blockly.lastUsedType.unshift(blockType) + editor_blockly.lastUsedType=editor_blockly.lastUsedType.slice(0,editor_blockly.lastUsedTypeNum) + } + return editor_blockly; } //editor_blockly=editor_blockly(); \ No newline at end of file From 556dd15dc2bf36c6461ac3b5187a829c1122eb50 Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Wed, 12 Dec 2018 18:31:59 -0500 Subject: [PATCH 50/81] delete console.log(...) --- _server/editor_blockly.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 4d4af6a0..c8ff17ff 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -276,7 +276,6 @@ var workspace = Blockly.inject(blocklyDiv,{ }); editor_blockly.searchBlockCategoryCallback = function(workspace) { - //var colourList = ['#4286f4', '#ef0447']; var xmlList = []; if (Blockly.Blocks['colour_picker']) { for (var i = 0; i < editor_blockly.lastUsedType.length; i++) { @@ -314,9 +313,6 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ var doubleClickCheck=[[0,'abc']]; function omitedcheckUpdateFunction(event) { - console.log(event) - console.log(event.type) - if(event.type==='ui'||event.type==='move'){ editor_blockly.addIntoLastUsedType(event.blockId); } From 560c6136f7de463c183c6ee5ddd027316f4c5385 Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Wed, 12 Dec 2018 18:33:57 -0500 Subject: [PATCH 51/81] fix --- _server/editor_blockly.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index c8ff17ff..dd449a91 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -277,14 +277,12 @@ var workspace = Blockly.inject(blocklyDiv,{ editor_blockly.searchBlockCategoryCallback = function(workspace) { var xmlList = []; - if (Blockly.Blocks['colour_picker']) { - for (var i = 0; i < editor_blockly.lastUsedType.length; i++) { - var blockText = '' + - MotaActionBlocks[editor_blockly.lastUsedType[i]].xmlText() + - ''; - var block = Blockly.Xml.textToDom(blockText).firstChild; - xmlList.push(block); - } + for (var i = 0; i < editor_blockly.lastUsedType.length; i++) { + var blockText = '' + + MotaActionBlocks[editor_blockly.lastUsedType[i]].xmlText() + + ''; + var block = Blockly.Xml.textToDom(blockText).firstChild; + xmlList.push(block); } return xmlList; }; From 5669197fbceeb5e885bbf75eddd3f7222a4df7b5 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Thu, 13 Dec 2018 15:10:55 +0800 Subject: [PATCH 52/81] Last Used Items --- _server/editor_blockly.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index dd449a91..12959257 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -282,6 +282,7 @@ editor_blockly.searchBlockCategoryCallback = function(workspace) { MotaActionBlocks[editor_blockly.lastUsedType[i]].xmlText() + ''; var block = Blockly.Xml.textToDom(blockText).firstChild; + block.setAttribute("gap", 5); xmlList.push(block); } return xmlList; @@ -311,7 +312,7 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ var doubleClickCheck=[[0,'abc']]; function omitedcheckUpdateFunction(event) { - if(event.type==='ui'||event.type==='move'){ + if(event.type==='move'){ editor_blockly.addIntoLastUsedType(event.blockId); } if(event.type==='ui'){ @@ -535,18 +536,18 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ } editor_blockly.lastUsedType=['comment_s']//初始空着比较难看 - editor_blockly.lastUsedTypeNum=15 + editor_blockly.lastUsedTypeNum=15; - editor_blockly.addIntoLastUsedType=function(blockId){ + editor_blockly.addIntoLastUsedType=function(blockId) { var b = editor_blockly.workspace.getBlockById(blockId); if(!b)return; var blockType = b.type; - if(!blockType || ['pass_s','emptyshop'].indexOf(blockType)!==-1)return; - if(editor_blockly.lastUsedType.indexOf(blockType)!==-1){ - editor_blockly.lastUsedType.splice(editor_blockly.lastUsedType.indexOf(blockType),1) - } - editor_blockly.lastUsedType.unshift(blockType) - editor_blockly.lastUsedType=editor_blockly.lastUsedType.slice(0,editor_blockly.lastUsedTypeNum) + if(!blockType || blockType.indexOf("_s")!==blockType.length-2 || blockType==='pass_s')return; + console.log(b); + editor_blockly.lastUsedType = editor_blockly.lastUsedType.filter(function (v) {return v!==blockType;}); + if (editor_blockly.lastUsedType.length >= editor_blockly.lastUsedTypeNum) + editor_blockly.lastUsedType.pop(); + editor_blockly.lastUsedType.unshift(blockType); } return editor_blockly; From ecdea0785675f0ab60b51cba05aeaf0e75905cfc Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Thu, 13 Dec 2018 15:26:01 +0800 Subject: [PATCH 53/81] Frequently & Last Used Blocks --- _server/editor_blockly.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 12959257..a966619f 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -245,7 +245,7 @@ editor_blockly = function () { ] },'event'), ], - '最近使用':[ + '最近使用事件':[ '', ] } @@ -255,7 +255,7 @@ editor_blockly = function () { for (var name in toolboxObj){ var custom = null; - if(name=='最近使用')custom='searchBlockCategory'; + if(name=='最近使用事件')custom='searchBlockCategory'; getCategory(name,custom).innerHTML = toolboxObj[name].join(toolboxgap); } @@ -535,7 +535,22 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ } } - editor_blockly.lastUsedType=['comment_s']//初始空着比较难看 + editor_blockly.lastUsedType=[ + 'text_0_s', + 'comment_s', + 'show_s', + 'hide_s', + 'setValue_s', + 'if_s', + 'battle_s', + 'openDoor_s', + 'choices_s', + 'setText_s', + 'exit_s', + 'revisit_s', + 'sleep_s', + 'setBlock_s' + ]; // 最常用的15个图块 editor_blockly.lastUsedTypeNum=15; editor_blockly.addIntoLastUsedType=function(blockId) { From e4d985c8b6963621d6f0cbd669297950aa350be8 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Thu, 13 Dec 2018 17:22:56 +0800 Subject: [PATCH 54/81] Fix paint bugs --- libs/utils.js | 12 +++++++----- project/functions.js | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/libs/utils.js b/libs/utils.js index e7ba2f23..45313e71 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -813,6 +813,12 @@ utils.prototype.encodeCanvas = function (ctx) { ////// 解析arr数组,并绘制到tempCanvas上 ////// utils.prototype.decodeCanvas = function (arr, width, height) { + // 清空tempCanvas + var tempCanvas = core.bigmap.tempCanvas; + tempCanvas.canvas.width=width; + tempCanvas.canvas.height=height; + tempCanvas.clearRect(0, 0, width, height); + if (!core.isset(arr)) return null; // to byte array var curr = 0, list = []; @@ -820,11 +826,6 @@ utils.prototype.decodeCanvas = function (arr, width, height) { for (var i=0;i threshold diff --git a/project/functions.js b/project/functions.js index 21852685..0d47e471 100644 --- a/project/functions.js +++ b/project/functions.js @@ -1040,8 +1040,8 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = ctx.drawImage(core.statusBar.icons[name], leftOffset, topOffset, 25, 25); // 文字内容 var text = (core.statusBar[name]||{}).innerText || " "; - // 斜体判定:如果不是纯数字,斜体会非常难看,需要取消 - if (!/^\d*$/.test(text)) ctx.font = 'bold 18px Verdana'; + // 斜体判定:如果不是纯数字和字母,斜体会非常难看,需要取消 + if (!/^[-+_.a-zA-Z0-9]*$/.test(text)) ctx.font = 'bold 18px Verdana'; // 绘制文字 ctx.fillText(text, leftOffset + 36, topOffset + 20); ctx.font = 'italic bold 18px Verdana'; From efacefbc587ee507ba8618e0f4d0f4d7579628e5 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Thu, 13 Dec 2018 18:32:05 +0800 Subject: [PATCH 55/81] Fix showImage with flag --- libs/events.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/events.js b/libs/events.js index f17e8529..9998e01f 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1548,7 +1548,7 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback ////// 绘制图片 ////// events.prototype.showImage = function (name, x, y) { if (core.isset(name) && core.isset(x) && core.isset(y) && core.isset(core.material.images.images[name])) { - core.canvas.image.drawImage(core.material.images.images[name], x, y); + core.canvas.image.drawImage(core.material.images.images[name], core.calValue(x), core.calValue(y)); } else core.clearMap('image'); } From 07bcfafe270a3097bebb1848e35101d297512c0a Mon Sep 17 00:00:00 2001 From: tocque <364004564@qq.com> Date: Thu, 13 Dec 2018 20:02:03 +0900 Subject: [PATCH 56/81] dynamic canvas --- _server/blockly/MotaAction.g4 | 122 +++++++--------- _server/editor_blockly.js | 9 +- docs/event.md | 65 +++++---- index.html | 2 +- libs/actions.js | 2 + libs/control.js | 23 ++- libs/core.js | 33 +++++ libs/events.js | 258 +++++++++++++++++++++------------- libs/maps.js | 62 ++++++-- libs/ui.js | 150 ++++++++++++++++---- main.js | 4 +- project/data.js | 24 +++- styles.css | 34 ++--- 13 files changed, 529 insertions(+), 259 deletions(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 09bde8b4..89175f71 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -260,13 +260,12 @@ action | unfollow_s | animate_s | vibrate_s - | showImage_0_s - | showImage_1_s - | animateImage_0_s - | animateImage_1_s + | showImage_s + | hideImage_s + | showTextImage_s + | animateImage_s | showGif_0_s | showGif_1_s - | moveImage_0_s | setFg_0_s | setFg_1_s | setWeather_s @@ -1019,58 +1018,49 @@ var code = '{"type": "animate", "name": "'+IdString_0+'"'+EvalString_0+async+'}, return code; */; -showImage_0_s - : '显示图片' EvalString '起点像素位置' 'x' PosString 'y' PosString Newline +showImage_s + : '显示图片' '图片编号' Int '图片' EvalString '起点像素位置' 'x' PosString 'y' PosString BGNL + '放大率 : x' Int '% y' Int '% 透明度' Int '时间' Int '不等待执行完毕' Bool Newline -/* showImage_0_s +/* showImage_s tooltip : showImage:显示图片 helpUrl : https://h5mota.com/games/template/docs/#/event?id=showimage%EF%BC%9A%E6%98%BE%E7%A4%BA%E5%9B%BE%E7%89%87 -default : ["bg.jpg","0","0"] +default : [1,"bg.jpg","0","0",100,100,100,0,false] colour : this.printColor -var code = '{"type": "showImage", "name": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+']},\n'; +if(Int_3<0 || Int_3>100) throw new Error('透明度的值在0~100之间'); +var async = Bool_0?', "async": true':''; +var code = '{"type": "showImage", "code": '+Int_0+', "image": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "dw": '+Int_1+', "dh": '+Int_2+', "opacity": '+Int_3+', "time": '+Int_4+async+'},\n'; return code; */; -showImage_1_s - : '清除所有图片' Newline +showTextImage_s + : '显示图片化文本' '图片编号' Int '文本' EvalString BGNL + '起点像素位置' 'x' PosString 'y' PosString '透明度' Int '时间' Int '不等待执行完毕' Bool Newline -/* showImage_1_s -tooltip : showImage:清除所有显示的图片 +/* showTextImage_s +tooltip : showTextImage:显示图片化文本 helpUrl : https://h5mota.com/games/template/docs/#/event?id=showimage%EF%BC%9A%E6%98%BE%E7%A4%BA%E5%9B%BE%E7%89%87 colour : this.printColor -var code = '{"type": "showImage"},\n'; +default : [1,"可以使用setText事件来控制字体、颜色、大小、偏移量等","0","0",100,0,false] +if(Int_1<0 || Int_1>100) throw new Error('透明度的值在0~100之间'); +var async = Bool_0?', "async": true':''; +var code = '{"type": "showTextImage", "code": '+Int_0+', "text": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "opacity": '+Int_1+', "time": '+Int_2+async+'},\n'; return code; */; -animateImage_0_s - : '图片淡入' EvalString '起点像素位置' 'x' PosString 'y' PosString '动画时间' Int '保留图片' Bool '不等待执行完毕' Bool Newline +hideImage_s + : '清除图片' '图片编号' Int '时间' Int '不等待执行完毕' Bool Newline -/* animateImage_0_s -tooltip : animageImage:图片淡入 -helpUrl : https://h5mota.com/games/template/docs/#/event?id=animateimage%EF%BC%9A%E5%9B%BE%E7%89%87%E6%B7%A1%E5%85%A5%E6%B7%A1%E5%87%BA -default : ["bg.jpg","0","0",500,true,false] +/* hideImage_s +tooltip : hideImage:清除图片 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=showimage%EF%BC%9A%E6%98%BE%E7%A4%BA%E5%9B%BE%E7%89%87 colour : this.printColor -var keep = Bool_0?', "keep": true':''; -var async = Bool_1?', "async": true':''; -var code = '{"type": "animateImage", "action": "show", "name": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "time": '+Int_0+keep+async+'},\n'; -return code; -*/; - -animateImage_1_s - : '图片淡出' EvalString '起点像素位置' 'x' PosString 'y' PosString '动画时间' Int '清除图片' Bool '不等待执行完毕' Bool Newline - - -/* animateImage_1_s -tooltip : animageImage:图片淡出 -helpUrl : https://h5mota.com/games/template/docs/#/event?id=animateimage%EF%BC%9A%E5%9B%BE%E7%89%87%E6%B7%A1%E5%85%A5%E6%B7%A1%E5%87%BA -default : ["bg.jpg","0","0",500,true,false] -colour : this.printColor -var keep = Bool_0?', "keep": true':''; -var async = Bool_1?', "async": true':''; -var code = '{"type": "animateImage", "action": "hide", "name": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "time": '+Int_0+keep+async+'},\n'; +default : [1,0,false] +var async = Bool_0?', "async": true':''; +var code = '{"type": "hideImage", "code": '+Int_0+', "time": '+Int_1+async+'},\n'; return code; */; @@ -1099,19 +1089,22 @@ var code = '{"type": "showGif"},\n'; return code; */; -moveImage_0_s - : '图片移动' EvalString '起点像素位置' 'x' PosString 'y' PosString BGNL - '终点像素位置' 'x' PosString 'y' PosString '移动时间' Int '保留图片' Bool '不等待执行完毕' Bool Newline +animateImage_s + : '图片移动' '编号' Int '终点像素位置' 'x' PosString? 'y' PosString? BGNL + '透明度' PosString? '移动时间' Int '不等待执行完毕' Bool Newline -/* moveImage_0_s -tooltip : moveImage:图片移动 +/* animateImage_s +tooltip : animateImage:图片移动 helpUrl : https://h5mota.com/games/template/docs/#/event?id=moveimage%EF%BC%9A%E5%9B%BE%E7%89%87%E7%A7%BB%E5%8A%A8 -default : ["bg.jpg","0","0","0","0",500,true,false] +default : [1,"0","0",100,500,false] colour : this.printColor -var keep = Bool_0?', "keep": true':''; -var async = Bool_1?', "async": true':''; -var code = '{"type": "moveImage", "name": "'+EvalString_0+'", "from": ['+PosString_0+','+PosString_1+'], "to": ['+PosString_2+','+PosString_3+'], "time": '+Int_0+keep+async+'},\n'; +var toloc = ''; +if (PosString_0 && PosString_1) + toloc = ', "to": ['+PosString_0+','+PosString_1+']' +PosString_2 = (PosString_2) ? (', "opacity": '+PosString_2):''; +var async = Bool_0?', "async": true':''; +var code = '{"type": "animateImage", "code": '+Int_0+toloc+PosString_2+',"time": '+Int_1+async+'},\n'; return code; */; @@ -2076,22 +2069,20 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['vibrate_s'].xmlText([data.time||0, data.async||false, this.next]); break; case "showImage": // 显示图片 - if(this.isset(data.name)){ - this.next = MotaActionBlocks['showImage_0_s'].xmlText([ - data.name,data.loc[0],data.loc[1],this.next]); - } else { - this.next = MotaActionBlocks['showImage_1_s'].xmlText([ - this.next]); - } + this.next = MotaActionBlocks['showImage_s'].xmlText([ + data.code,data.image,data.loc[0],data.loc[1],data.dw||100,data.dw||100,data.opacity||100,data.time||0,data.async||false,this.next]); break; - case "animateImage": // 显示图片 - if(data.action == 'show'){ - this.next = MotaActionBlocks['animateImage_0_s'].xmlText([ - data.name,data.loc[0],data.loc[1],data.time||0,data.keep||false,data.async||false,this.next]); - } else if (data.action == 'hide') { - this.next = MotaActionBlocks['animateImage_1_s'].xmlText([ - data.name,data.loc[0],data.loc[1],data.time||0,data.keep||false,data.async||false,this.next]); - } + case "hideImage": // 清除图片 + this.next = MotaActionBlocks['hideImage_s'].xmlText([ + data.code,data.time||0,data.async||false,this.next]); + break; + case "showTextImage": // 显示图片化文本 + this.next = MotaActionBlocks['showTextImage_s'].xmlText([ + data.code,this.EvalString(data.text),data.loc[0],data.loc[1],data.opacity||100,data.time||0,data.async||false,this.next]); + break; + case "animateImage": // 移动图片 + this.next = MotaActionBlocks['animateImage_s'].xmlText([ + data.code, data.to[0], data.to[1], data.opacity, data.time||0, data.async||false, this.next]); break; case "showGif": // 显示动图 if(this.isset(data.name)){ @@ -2102,11 +2093,6 @@ ActionParser.prototype.parseAction = function() { this.next]); } break; - case "moveImage": // 移动图片 - this.next = MotaActionBlocks['moveImage_0_s'].xmlText([ - data.name, data.from[0], data.from[1], data.to[0], data.to[1], data.time||0, data.keep||false, data.async||false, this.next - ]); - break; case "setFg": // 颜色渐变 if(this.isset(data.color)){ var alpha = data.color[3]; diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 864fb7fd..dcabfcf4 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -62,13 +62,12 @@ editor_blockly = function () { MotaActionBlocks['autoText_s'].xmlText(), MotaActionBlocks['scrollText_s'].xmlText(), MotaActionBlocks['setText_s'].xmlText(), - MotaActionBlocks['showImage_0_s'].xmlText(), - MotaActionBlocks['animateImage_0_s'].xmlText(), - MotaActionBlocks['animateImage_1_s'].xmlText(), - MotaActionBlocks['showImage_1_s'].xmlText(), + MotaActionBlocks['showImage_s'].xmlText(), + MotaActionBlocks['hideImage_s'].xmlText(), + MotaActionBlocks['showTextImage_s'].xmlText(), + MotaActionBlocks['animateImage_s'].xmlText(), MotaActionBlocks['showGif_0_s'].xmlText(), MotaActionBlocks['showGif_1_s'].xmlText(), - MotaActionBlocks['moveImage_0_s'].xmlText(), MotaActionBlocks['tip_s'].xmlText(), MotaActionBlocks['win_s'].xmlText(), MotaActionBlocks['lose_s'].xmlText(), diff --git a/docs/event.md b/docs/event.md index 328c1900..9f09a82e 100644 --- a/docs/event.md +++ b/docs/event.md @@ -939,48 +939,58 @@ loc可忽略,如果忽略则显示为事件当前点。 ``` js "x,y": [ // 实际执行的事件列表 - {"type": "showImage", "name": "bg.jpg", "loc": [231,297]}, // 在(231,297)显示bg.jpg - {"type": "showImage", "name": "1.png", "loc": [109,167]}, // 在(109,167)显示1.png - {"type": "showImage"} // 如果不指定name则清除所有图片。 + {"type": "showImage", "code": 1, "image": "bg.jpg", "loc": [231,297], "dw": 100, "dy" : 100, "opacity": 100, "time" : 0}, // 在(231,297)显示bg.jpg + {"type": "showImage", "code": 12, "image": "1.png", "loc": [209,267], "dw": 100, "dy" : 100, "opacity": 50, "time" : 1000}, // 在(209,267)渐变显示1.png,渐变时间为1000毫秒,完成时透明度为0.5,这张图片将遮盖上一张 + {"type": "showImage", "code": 8, "image": "hero.png", "loc": [349,367], "dw": 50, "dy" : 50, "opacity": 100, "time" : 0}, // 在(209,267)渐变显示hero.png,大小为原图片的一半,渐变时间为1000毫秒,这张图片将被上一张遮盖 ] ``` -name为图片名。**请确保图片在data.js中的images中被定义过。** +code为图片编号,如果两张图片重叠,编号较大的显示在上。建议编号取1~50之间的数。 + +image为图片名。**请确保图片在data.js中的images中被定义过。** loc为图片左上角坐标,以像素为单位进行计算。 -如果不指定name则清除所有显示的图片。 +dw和dh为图片的横向、纵向放大率,默认值为100,即不进行缩放。 -调用show/hide/move/animate等几个事件同样会清除所有显示的图片。 +opacity为图片透明度,默认值为100,即不透明。 -### animateImage:图片淡入淡出 +time为渐变时间,默认值为0,即不渐变直接显示。 -我们还可以使用 `{"type": "animateImage"}` 来造成显示图片的淡入淡出效果。 +### showTextImage:显示图片 + +我们可以使用 `{"type": "showTextImage"}` 以图片的方式显示文本。 ``` js "x,y": [ // 实际执行的事件列表 - {"type": "animateImage", "action": "show", "name": "bg.jpg", "loc": [231,297], "time": 500, "keep": true}, // 在(231,297)淡入bg.jpg,动画时间500ms - {"type": "animateImage", "action": "hide", "name": "1.png", "loc": [109,167], "time": 300, "async": true}, // 在(109,167)淡出1.png,动画时间300ms,异步执行 + {"type": "showTextImage", "code": 1, "text": "第一排\n第二排\n\n空行后的一排", "loc": [231,297], "opacity": 1, "time" : 0}, // 在(231,297)显示"第一排\n第二排\n\n空行后的一排" ] ``` -action为淡入还是淡出,`show`为淡入,`hide`会淡出。 +code为图片编号,如果两张图片重叠,编号较大的显示在上。建议编号取1~50之间的数。 -name为图片名。**请确保图片在data.js中的images中被定义过。** +text为要显示的文本。默认行宽为416。 loc为图片左上角坐标,以像素为单位进行计算。 -time为淡入淡出的时间,如果是0则忽略此项。 +opacity为图片透明度。 -keep可选,如果为true则在淡入图片后立刻调用showImage以保留图片,在淡出图片前先清除再动画。 +time为渐变时间,默认值为0,即不渐变直接显示。 -async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。 +### hideImage:清除图片 -如果多张图片的淡入淡出可以采用以下方式(仅供参考): +我们可以使用 `{"type": "hideImage"}` 来清除一张图片。 -假设我现在已经有了`1.jpg`显示在屏幕上: -- 淡入显示`2.png`:调用`animateImage`淡入图片,然后立刻调用`showImage`显示图片。 -- 淡出`1.png`:清除所有图片,`showImage`显示`2.png`,然后调用`animateImage`淡出`1.jpg` +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "hideImage", "code": 1, "time" : 0}, // 使1号图片消失 + {"type": "hideImage", "code": 12, "time" : 1000}, // 使12号图片渐变消失,时间为1000毫秒 +] +``` + +time为渐变时间,默认值为0,即不渐变直接消除。 + +code为显示图片时输入的图片编号。 ### showGif:显示动图 @@ -999,26 +1009,27 @@ loc为动图左上角坐标,以像素为单位进行计算。 如果不指定name则清除所有显示的动图。 -### moveImage:图片移动 +### animateImage:图片移动 -我们可以使用 `{"type": "moveImage"}` 来造成图片移动效果。 +我们可以使用 `{"type": "animateImage"}` 来造成图片移动,淡入淡出等效果。 ``` js "x,y": [ // 实际执行的事件列表 - {"type": "moveImage", "name": "bg.jpg", "from": [231,297], "to": [22,333], "time": 500, "keep": true, "async": true}, + {"type": "animateImage", "code": 1, "to": [22,333], "opacity": 1, "time": 1000}, + // 将1号图片移动到(22,333),动画时间为1000ms + {"type": "animateImage", "code": 12, "opacity": 0.5, "time": 500}, // 将二号图片的透明度变为0.5,动画时间500ms + {"type": "animateImage", "code": 1, "to": [109,167], "opacity": 0, "time": 300, "async": true}, // 将1号图片移动到(109,167),透明度设为0(不可见),动画时间300ms,异步执行 ] ``` -name为图片名。**请确保图片在data.js中的images中被定义过。** +image为图片名。**请确保图片在data.js中的images中被定义过。** -from为起点图片左上角坐标,以像素为单位进行计算。 +to为终点图片左上角坐标,以像素为单位进行计算,不填写则视为当前图片位置。 -to为终点图片左上角坐标,以像素为单位进行计算。 +opacity为完成时图片透明度,移动过程中逐渐变化。 time为总移动的时间。 -keep可选,如果为true则在移动结束后立刻调用showImage以保留图片。 - async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。 ### setFg:更改画面色调 diff --git a/index.html b/index.html index 8fe217e5..c31e434a 100644 --- a/index.html +++ b/index.html @@ -143,9 +143,9 @@ - 此浏览器不支持HTML5 +
diff --git a/libs/actions.js b/libs/actions.js index 55212e0b..499e551f 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1893,9 +1893,11 @@ actions.prototype.clickSettings = function (x,y) { core.ui.drawKeyBoard(); break; case 2: + core.clearLastEvent(); core.ui.drawMaps(); break; case 3: + core.clearLastEvent(); core.ui.drawPaint(); break; case 4: diff --git a/libs/control.js b/libs/control.js index f3ae58b9..9edbda74 100644 --- a/libs/control.js +++ b/libs/control.js @@ -57,6 +57,7 @@ control.prototype.setRequestAnimationFrame = function () { core.animateFrame.globalTime = core.animateFrame.globalTime||timestamp; core.animateFrame.boxTime = core.animateFrame.boxTime||timestamp; + core.animateFrame.selectorTime = core.animateFrame.selectorTime||timestamp; core.animateFrame.animateTime = core.animateFrame.animateTime||timestamp; core.animateFrame.moveTime = core.animateFrame.moveTime||timestamp; core.animateFrame.lastLegTime = core.animateFrame.lastLegTime||timestamp; @@ -110,6 +111,19 @@ control.prototype.setRequestAnimationFrame = function () { core.animateFrame.boxTime = timestamp; } + // selectorTime + if (timestamp-core.animateFrame.selectorTime>20 && core.isset(core.dymCanvas.selector)) { + var opac = parseFloat(core.dymCanvas.selector.canvas.style.opacity); + if (core.getFlag("seleUp", true)) + opac += 0.02; + else + opac -= 0.02; + if (opac > 0.9 || opac < 0.6) + core.setFlag("seleUp", !core.getFlag("seleUp", true)) + core.setOpacity("selector", opac); + core.animateFrame.selectorTime = timestamp; + } + // Animate if (timestamp-core.animateFrame.animateTime>50 && core.isset(core.status.animateObjs) && core.status.animateObjs.length>0) { core.clearMap('animate'); @@ -3356,5 +3370,12 @@ control.prototype.domRenderer = function(){ core.canvas[cn].canvas.style.height = core.bigmap.height*32*core.domStyle.scale + "px"; }); } - + // 动态canvas + for (var i = 0; i < core.dymCanvas._list.length; i++) { + var spirit = core.dymCanvas._list[i]; + core.dymCanvas[spirit.id].canvas.style.width = core.dymCanvas[spirit.id].canvas.width * core.domStyle.scale + "px"; + core.dymCanvas[spirit.id].canvas.style.height = core.dymCanvas[spirit.id].canvas.height * core.domStyle.scale + "px"; + core.dymCanvas[spirit.id].canvas.style.left = spirit.style.left * core.domStyle.scale + "px"; + core.dymCanvas[spirit.id].canvas.style.top = spirit.style.top * core.domStyle.scale + "px" + } } \ No newline at end of file diff --git a/libs/core.js b/libs/core.js index 901b664c..3c332ee8 100644 --- a/libs/core.js +++ b/libs/core.js @@ -188,6 +188,9 @@ function core() { 'animateObjs': [], }; this.status = {}; + this.dymCanvas = { + "_list": [] + }; } /////////// 系统事件相关 /////////// @@ -688,6 +691,31 @@ core.prototype.setFillStyle = function (map, style) { core.ui.setFillStyle(map, style); } +////// canvas创建 ////// +core.prototype.createCanvas = function (name, x, y, width, height, z) { + core.ui.createCanvas(name, x, y, width, height, z); +} + +////// canvas查找 ////// +core.prototype.findCanvas = function (name) { + return core.ui.findCanvas(name); +} + +////// canvas重定位 ////// +core.prototype.relocateCanvas = function (name, x, y) { + core.ui.relocateCanvas(name, x, y); +} + +////// canvas重置 ////// +core.prototype.resizeCanvas = function (name, width, height) { + core.ui.resizeCanvas(name, width, height); +} + +////// canvas删除 ////// +core.prototype.deleteCanvas = function (name) { + core.ui.deleteCanvas(name); +} + core.prototype.drawBlock = function (block, animate, dx, dy) { core.maps.drawBlock(block, animate, dx, dy); } @@ -1092,6 +1120,11 @@ core.prototype.closePanel = function () { core.ui.closePanel(); } +////// 一般清除事件 ////// +core.prototype.clearLastEvent = function () { + core.ui.clearLastEvent(); +} + ////// 更改播放状态 ////// core.prototype.triggerReplay = function () { core.control.triggerReplay(); diff --git a/libs/events.js b/libs/events.js index e8166ec8..0548fe7c 100644 --- a/libs/events.js +++ b/libs/events.js @@ -363,8 +363,7 @@ events.prototype.doAction = function() { clearInterval(core.status.event.interval); core.status.event.interval = null; - core.clearMap('ui'); - core.setAlpha('ui', 1.0); + core.clearLastEvent(); // 事件处理完毕 if (core.status.event.data.list.length==0) { @@ -720,29 +719,50 @@ events.prototype.doAction = function() { this.doAction(); break; case "showImage": // 显示图片 - if (!core.isset(data.loc)) data.loc=[]; - core.events.showImage(data.name, data.loc[0], data.loc[1]); - this.doAction(); - break; - case "animateImage": // 淡入淡出图片 - if (core.status.replay.replaying) { // 正在播放录像 + if (!core.isset(data.loc)) data.loc=[0, 0]; + if (core.status.replay.replaying) { + data.time = 0; + } + var image = core.material.images.images[data.image]; + if (data.async || data.time == 0) { + core.events.showImage(data.code, image, data.loc[0], data.loc[1], data.dw, data.dh, data.opacity, data.time); this.doAction(); } else { - if (core.isset(data.loc) && core.isset(core.material.images.images[data.name]) && (data.action=="show" || data.action=="hide")) { - if (data.async) { - core.events.animateImage(data.action, core.material.images.images[data.name], data.loc, data.time, data.keep); - this.doAction(); - } - else { - core.events.animateImage(data.action, core.material.images.images[data.name], data.loc, data.time, data.keep, function() { - core.events.doAction(); - }); - } - } - else { - this.doAction(); - } + core.events.showImage(data.code, image, data.loc[0], data.loc[1], data.dw, data.dh, data.opacity, data.time, function () { + core.events.doAction(); + }); + } + break; + case "showTextImage": // 显示图片化文本 + if (!core.isset(data.loc)) data.loc=[0, 0]; + if (core.status.replay.replaying) { + data.time = 0; + } + var content = core.replaceText(data.text); + var image = core.events.textImage(content); + if (data.async || data.time == 0) { + core.events.showImage(data.code, image, data.loc[0], data.loc[1], 100, 100, data.opacity, data.time); + this.doAction(); + } + else { + core.events.showImage(data.code, image, data.loc[0], data.loc[1], 100, 100, data.opacity, data.time, function() { + core.events.doAction(); + }); + } + break; + case "hideImage": // 隐藏图片 + if (core.status.replay.replaying) { + data.time = 0; + } + if (data.async || data.time == 0) { + core.events.hideImage(data.code, data.time); + this.doAction(); + } + else { + core.events.hideImage(data.code, data.time, function () { + core.events.doAction(); + }); } break; case "showGif": // 显示动图 @@ -761,24 +781,19 @@ events.prototype.doAction = function() { } this.doAction(); break; - case "moveImage": // 图片移动 + case "animateImage": // 图片移动 if (core.status.replay.replaying) { // 正在播放录像 this.doAction(); } else { - if (core.isset(data.from) && core.isset(data.to) && core.isset(core.material.images.images[data.name])) { - if (data.async) { - core.events.moveImage(core.material.images.images[data.name], data.from, data.to, data.time, data.keep); - this.doAction(); - } - else { - core.events.moveImage(core.material.images.images[data.name], data.from, data.to, data.time, data.keep, function() { - core.events.doAction(); - }); - } + if (data.async) { + core.events.animateImage(data.code, data.to, data.opacity, data.time); + this.doAction(); } else { - this.doAction(); + core.events.animateImage(data.code, data.to, data.opacity, data.time, function() { + core.events.doAction(); + }); } } break; @@ -1545,91 +1560,146 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback }, 25); } -////// 绘制图片 ////// -events.prototype.showImage = function (name, x, y) { - if (core.isset(name) && core.isset(x) && core.isset(y) && core.isset(core.material.images.images[name])) { - core.canvas.image.drawImage(core.material.images.images[name], x, y); +////// 显示图片 ////// +events.prototype.showImage = function (code, image, x, y, dw, dh, opacityVal, time, callback) { + dw /= 100, dh /= 100, opacityVal /= 100; + var zIndex = code + 100; + var name = "image"+ zIndex; + if (core.findCanvas(name) != -1) { + core.relocateCanvas(name, x, y); + core.resizeCanvas(name, image.width * dw, image.height * dh); + core.dymCanvas[name].style.zIndex = zIndex; + } + else + core.createCanvas(name, x, y, image.width * dw, image.height * dh, zIndex); + core.dymCanvas[name].drawImage(image, 0, 0, image.width * dw, image.height * dh); + if (time == 0) + core.setOpacity(name, opacityVal); + else { + clearInterval(core.interval.tipAnimate); + var opac = 0; + core.setOpacity(name, 0); + var animate = setInterval(function () { + opac += opacityVal/20; + core.setOpacity(name, opac); + if (opac >= opacityVal) { + delete core.animateFrame.asyncId[animate]; + clearInterval(animate); + core.setOpacity(name, opacityVal); + if (core.isset(callback)) callback(); + } + }, time/20); + + core.animateFrame.asyncId[animate] = true; } - else core.clearMap('image'); } -////// 图片淡入/淡出 ////// -events.prototype.animateImage = function (type, image, loc, time, keep, callback) { - time = time||0; - if ((type!='show' && type!='hide') || time<=0) { - if (core.isset(callback)) callback(); +////// 隐藏图片 ////// +events.prototype.hideImage = function (code, time, callback) { + var name = "image"+ (code+100); + if (!core.isset(core.dymCanvas[name])) { + console.log(code+"号图片不存在") return; } + if (time == 0) + core.deleteCanvas(name); + else { + clearInterval(core.interval.tipAnimate); + var opacityVal = parseFloat(core.dymCanvas[name].canvas.style.opacity); + var opac = opacityVal; + var animate = setInterval(function () { + opac -= opacityVal/20; + core.setOpacity(name, opac); + if (opac < 0) { + delete core.animateFrame.asyncId[animate]; + clearInterval(animate); + core.deleteCanvas(name); + if (core.isset(callback)) callback(); + } + }, time/20); - clearInterval(core.interval.tipAnimate); - - var alpha = 0; - if (type == 'hide') alpha = 1; - - var x = core.calValue(loc[0]), y = core.calValue(loc[1]); - - if (type == 'hide' && keep) { - core.clearMap('image', x, y, image.width, image.height); + core.animateFrame.asyncId[animate] = true; } - core.setAlpha('data', alpha); - core.canvas.data.drawImage(image, x, y); - core.setAlpha('data', 1); +} - // core.status.replay.animate=true; - var animate = setInterval(function () { - if (type=='show') alpha += 0.1; - else alpha -= 0.1; - core.clearMap('data', x, y, image.width, image.height); - if (alpha >=1 || alpha<=0) { - delete core.animateFrame.asyncId[animate]; - clearInterval(animate); - if (type == 'show' && keep) - core.canvas.image.drawImage(image, x, y); - core.setAlpha('data', 1); - if (core.isset(callback)) callback(); - } - else { - core.setAlpha('data', alpha); - core.canvas.data.drawImage(image, x, y); - core.setAlpha('data', 1); - } - }, time / 10); +////// 文本图片化 ////// +events.prototype.textImage = function (content) { + content = content || ""; - core.animateFrame.asyncId[animate] = true; + // 获得颜色的盒子等信息 + var textAttribute = core.status.textAttribute || core.initStatus.textAttribute; + var textfont = textAttribute.textfont || 16; + var offset = textAttribute.offset || 15; + var textColor = core.arrayToRGBA(textAttribute.text); + + var font = textfont+"px "+core.status.globalAttribute.font; + if (textAttribute.bold) font = "bold "+font; + var contents = core.splitLines('ui', content), lines = contents.length; + + // 计算总高度,按1.2倍行距计算 + var width = 416, height = textfont * 1.4 * lines; + var tempCanvas = core.bigmap.tempCanvas; + tempCanvas.canvas.width = width; + tempCanvas.canvas.height = height; + tempCanvas.clearRect(0, 0, width, height); + tempCanvas.font = font; + tempCanvas.fillStyle = textColor; + + // 全部绘制 + var currH = textfont; + for (var i = 0; i < lines; ++i) { + var text = contents[i]; + tempCanvas.fillText(text, offset, currH); + currH += 1.4 * textfont; + } + + return tempCanvas.canvas; } ////// 移动图片 ////// -events.prototype.moveImage = function (image, from, to, time, keep, callback) { +events.prototype.animateImage = function (code, to, opacityVal, time, callback) { time = time || 1000; clearInterval(core.interval.tipAnimate); - core.setAlpha('data', 1); - - var width = image.width, height = image.height; // core.status.replay.animate=true; - var fromX = core.calValue(from[0]), fromY = core.calValue(from[1]), - toX = core.calValue(to[0]), toY = core.calValue(to[1]); + var name = "image"+ (code+100), index = core.findCanvas(name); + if (index == -1) { + console.log(code+"号图片不存在") + return; + } + var fromX = core.dymCanvas._list[index].style.left, + fromY = core.dymCanvas._list[index].style.top, + preX = fromX, preY = fromY; + if (core.isset(to)) + var toX = core.calValue(to[0]), toY = core.calValue(to[1]); + else + var toX = fromX, toY = fromY; - if (keep) core.clearMap('image', fromX, fromY, width, height); - - var step = 0, preX = fromX, preY = fromY; + var step = 0; var per_time = 10, steps = parseInt(time / per_time); - var drawImage = function () { + var preOpac = parseFloat(core.dymCanvas[name].canvas.style.opacity), opacStep; + if (core.isset(opacityVal)) { + opacityVal /= 100; + opacStep = (opacityVal - preOpac) / steps; + } + else + opacStep = 0; + + var moveStep = function () { + preOpac += opacStep; + core.setOpacity(name, preOpac); preX = parseInt(fromX + (toX-fromX)*step/steps); preY = parseInt(fromY + (toY-fromY)*step/steps); - core.canvas.data.drawImage(image, preX, preY); + core.relocateCanvas(name, preX, preY); } - - drawImage(); var animate = setInterval(function () { - core.clearMap('data', preX, preY, width, height); step++; - if (step <= steps) - drawImage(); - else { + moveStep(); + if (step > steps) { + if (core.isset(opacityVal)) + core.setOpacity(name, opacityVal); delete core.animateFrame.asyncId[animate]; clearInterval(animate); - if (keep) core.canvas.image.drawImage(image, toX, toY); if (core.isset(callback)) callback(); } }, per_time); diff --git a/libs/maps.js b/libs/maps.js index 2c9c5f83..87977043 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -811,10 +811,10 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { faceIds = block.event.faceIds||{}; } - var alpha = 1; - core.setAlpha('route', alpha); - core.canvas.route.drawImage(image, bx * 32, by * height, 32, height, block.x * 32, block.y * 32 +32 - height, 32, height); - + var alpha = 1, name = 'move'+x+'_'+y; + core.createCanvas(name, block.x, block.y * 32 +32 - height, 32, height, 45); + core.dymCanvas[name].textAlign = 'left'; + core.dymCanvas[name].drawImage(image, bx * 32, by * height, 32, height, 0, 0, 32, height); // 要运行的轨迹:将steps展开 var moveSteps=[]; steps.forEach(function (e) { @@ -861,22 +861,23 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { if (moveSteps.length==0) { if (keep) alpha=0; else alpha -= 0.06; - core.clearMap('route', nowX, nowY-height+32, 32, height); if (alpha<=0) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); + core.deleteCanvas(name); // 不消失 if (keep) { core.setBlock(id, nowX/32, nowY/32); core.showBlock(nowX/32, nowY/32); } - core.setAlpha('route',1); + else { + if (block.event.cls == 'enemys' || block.event.cls == 'enemy48') + core.clearMap('damage', nowX, nowY, 32, 32); + } if (core.isset(callback)) callback(); } else { - core.setAlpha('route', alpha); - core.canvas.route.drawImage(image, animateCurrent * 32, by * height, 32, height, nowX, nowY-height+32, 32, height); - core.setAlpha('route', 1); + core.dymCanvas[name].canvas.style.opacity = alpha; } } else { @@ -892,12 +893,49 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { } } - core.clearMap('route', nowX, nowY-height+32, 32, height); step++; nowX+=scan[direction].x*2; nowY+=scan[direction].y*2; - // 绘制 - core.canvas.route.drawImage(image, animateCurrent * 32, by * height, 32, height, nowX, nowY-height+32, 32, height); + // 移动 + core.relocateCanvas(name, nowX, nowY-height+32); + core.dymCanvas[name].drawImage(image, animateCurrent * 32, by * height, 32, height, 0, 0, 32, height); + // 显伤绘制 + if ((block.event.cls == 'enemys' || block.event.cls == 'enemy48') && core.hasItem('book')) { + // 鉴于移动过程中可能的主角状态改变,每次重新计算 + var damage = core.enemys.getDamage(block.event.id, x, y); + var color = '#000000'; + + if (damage == null) { + damage = "???"; + color = '#FF0000'; + } + else { + if (damage <= 0) color = '#00FF00'; + else if (damage < core.status.hero.hp / 3) color = '#FFFFFF'; + else if (damage < core.status.hero.hp * 2 / 3) color = '#FFFF00'; + else if (damage < core.status.hero.hp) color = '#FF7F00'; + else color = '#FF0000'; + + damage = core.formatBigNumber(damage); + if (core.enemys.hasSpecial(core.material.enemys[block.event.id], 19)) + damage += "+"; + if (core.enemys.hasSpecial(core.material.enemys[block.event.id], 21)) + damage += "-"; + if (core.enemys.hasSpecial(core.material.enemys[block.event.id], 11)) + damage += "^"; + } + // 清空上一次 + core.clearMap('damage', nowX-2*scan[direction].x, nowY-2*scan[direction].y, 32, 32); + + core.setFillStyle('damage', '#000000'); + core.canvas.damage.fillText(damage, nowX + 5, nowY + 30); + core.canvas.damage.fillText(damage, nowX + 3, nowY + 30); + core.canvas.damage.fillText(damage, nowX + 5, nowY + 32); + core.canvas.damage.fillText(damage, nowX + 3, nowY + 32); + + core.setFillStyle('damage', color); + core.canvas.damage.fillText(damage, nowX + 4, nowY + 31); + } if (step==16) { // 该移动完毕,继续 step=0; diff --git a/libs/ui.js b/libs/ui.js index a620dfb6..3a08b4e7 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -151,7 +151,14 @@ ui.prototype.setOpacity = function (map, opacity) { core.canvas[m].canvas.style.opacity = opacity; } } - else core.canvas[map].canvas.style.opacity = opacity; + else if (core.isset(core.canvas[map])) { + core.canvas[map].canvas.style.opacity = opacity; + } + else if (core.isset(core.dymCanvas[map])) { + core.dymCanvas[map].canvas.style.opacity = opacity; + } + else + console.log("未找到"+map); } ////// 设置某个canvas的绘制属性(如颜色等) ////// @@ -161,9 +168,14 @@ ui.prototype.setFillStyle = function (map, style) { core.canvas[m].fillStyle = style; } } - else { + else if (core.isset(core.canvas[map])) { core.canvas[map].fillStyle = style; } + else if (core.isset(core.dymCanvas[map])) { + core.dymCanvas[map].fillStyle = style; +} + else + console.log("未找到"+map); } @@ -174,8 +186,7 @@ ui.prototype.setFillStyle = function (map, style) { ui.prototype.closePanel = function () { core.status.boxAnimateObjs = []; clearInterval(core.status.event.interval); - core.clearMap('ui'); - core.setAlpha('ui', 1.0); + core.clearLastEvent(); core.unLockControl(); core.status.event.data = null; core.status.event.id = null; @@ -184,6 +195,14 @@ ui.prototype.closePanel = function () { core.status.event.interval = null; } +////// 一般清除事件 ////// +ui.prototype.clearLastEvent = function () { + if (core.isset(core.dymCanvas.selector)) + core.deleteCanvas("selector"); + core.clearMap('ui'); + core.setAlpha('ui', 1); +} + ////// 左上角绘制一段提示 ////// ui.prototype.drawTip = function (text, itemIcon) { var textX, textY, width, height, hide = false, alpha = 0; @@ -351,21 +370,28 @@ ui.prototype.getTitleAndIcon = function (content) { } // 绘制选择光标 -ui.prototype.drawWindowSelector = function(background,canvas,x,y,w,h) { - var dstImage = core.canvas[canvas]; - +ui.prototype.drawWindowSelector = function(background,x,y,w,h) { + if (core.isset(core.dymCanvas.selector)) { + core.relocateCanvas("selector", x, y); + core.resizeCanvas("selector", w, h); + } + else { + core.ui.createCanvas("selector", x, y, w, h, 165); + } + core.setOpacity("selector", 0.8); + var dstImage = core.dymCanvas.selector; // back - dstImage.drawImage(background,130,66,28,28,x+2,y+2,w-4,h-4); + dstImage.drawImage(background, 130, 66, 28, 28, 2, 2,w-4,h-4); // corner - dstImage.drawImage(background,128,64,2,2,x,y,2,2); - dstImage.drawImage(background,158,64,2,2,x+w-2,y,2,2); - dstImage.drawImage(background,128,94,2,2,x,y+h-2,2,2); - dstImage.drawImage(background,158,94,2,2,x+w-2,y+h-2,2,2); + dstImage.drawImage(background, 128, 64, 2, 2, 0, 0, 2, 2); + dstImage.drawImage(background, 158, 64, 2, 2,w-2, 0, 2, 2); + dstImage.drawImage(background, 128, 94, 2, 2, 0,h-2, 2, 2); + dstImage.drawImage(background, 158, 94, 2, 2,w-2,h-2, 2, 2); // border - dstImage.drawImage(background,130,64,28,2,x+2,y,w-4,2); - dstImage.drawImage(background,130,94,28,2,x+2,y+h-2,w-4,2); - dstImage.drawImage(background,128,66,2,28,x,y+2,2,h-4); - dstImage.drawImage(background,158,66,2,28,x+w-2,y+2,2,h-4); + dstImage.drawImage(background, 130, 64, 28, 2, 2, 0,w-4, 2); + dstImage.drawImage(background, 130, 94, 28, 2, 2,h-2,w-4, 2); + dstImage.drawImage(background, 128, 66, 2, 28, 0, 2, 2,h-4); + dstImage.drawImage(background, 158, 66, 2, 28,w-2, 2, 2,h-4); } // 绘制皮肤 @@ -502,7 +528,7 @@ ui.prototype.drawTextBox = function(content, showAll) { content = core.replaceText(content); core.status.boxAnimateObjs = []; - core.clearMap('ui'); + core.clearLastEvent(); // drawImage content = content.replace(/(\f|\\f)\[(.*?)]/g, function (text, sympol, str) { @@ -909,7 +935,7 @@ ui.prototype.drawChoices = function(content, choices) { while (core.status.event.selection>=choices.length) core.status.event.selection-=choices.length; var len = core.canvas.ui.measureText(core.replaceText(choices[core.status.event.selection].text || choices[core.status.event.selection])).width; if (isWindowSkin) - this.drawWindowSelector(background, 'ui' ,208-len/2-5, choice_top + 32 * core.status.event.selection - 20, len+10, 28); + this.drawWindowSelector(background, 208-len/2-5, choice_top + 32 * core.status.event.selection - 20, len+10, 28); else core.strokeRect('ui', 208-len/2-5, choice_top + 32 * core.status.event.selection - 20, len+10, 28, "#FFD700", 2); } @@ -927,8 +953,7 @@ ui.prototype.drawConfirmBox = function (text, yesCallback, noCallback) { if (!core.isset(core.status.event.selection) || core.status.event.selection>1) core.status.event.selection=1; if (core.status.event.selection<0) core.status.event.selection=0; - core.clearMap('ui'); - core.setAlpha('ui', 1); + core.clearLastEvent(); core.setFillStyle('ui', core.material.groundPattern); var globalFont = core.status.globalAttribute.font; core.setFont('ui', "bold 19px "+globalFont); @@ -1322,8 +1347,7 @@ ui.prototype.drawWaiting = function(text) { core.lockControl(); core.status.event.id = 'waiting'; - core.clearMap('ui'); - core.setAlpha('ui', 1); + core.clearLastEvent(); core.setFillStyle('ui', core.material.groundPattern); var globalFont = core.status.globalAttribute.font; @@ -1444,8 +1468,7 @@ ui.prototype.drawBook = function (index) { clearInterval(core.interval.tipAnimate); core.clearMap('data'); - core.clearMap('ui'); - core.setAlpha('ui', 1); + core.clearLastEvent(); core.setFillStyle('ui', core.material.groundPattern); core.fillRect('ui', 0, 0, 416, 416); @@ -1759,8 +1782,7 @@ ui.prototype.drawMaps = function (index, x, y) { if (!core.isset(index)) { core.status.event.data = null; - core.clearMap('ui'); - core.setAlpha('ui', 1); + core.clearLastEvent(); core.clearMap('animate'); core.fillRect('animate', 0, 0, 416, 416, 'rgba(0,0,0,0.4)'); @@ -2414,7 +2436,7 @@ ui.prototype.drawKeyBoard = function () { core.lockControl(); core.status.event.id = 'keyBoard'; - core.clearMap('ui'); + core.clearLastEvent(); var left = 16, top = 48, right = 416 - 2 * left, bottom = 416 - 2 * top; core.fillRect('ui', left, top, right, bottom, core.material.groundPattern); @@ -2664,7 +2686,7 @@ ui.prototype.drawPaint = function () { core.status.event.id = 'paint'; core.status.event.data = {"x": null, "y": null, "erase": false}; - core.clearMap('ui'); + core.clearLastEvent(); core.clearMap('route'); core.setAlpha('route', 1); @@ -2718,3 +2740,75 @@ ui.prototype.drawHelp = function () { ]); } +////// 动态canvas ////// + +////// canvas创建 ////// +ui.prototype.createCanvas = function (name, x, y, width, height, z) { + var newCanvas = document.createElement("CANVAS"); + newCanvas.id = name; + newCanvas.style.display = 'block'; + newCanvas.width = width; + newCanvas.height = height; + newCanvas.style.width = width * core.domStyle.scale + 'px'; + newCanvas.style.height = height * core.domStyle.scale + 'px'; + newCanvas.style.left = x * core.domStyle.scale + 'px'; + newCanvas.style.top = y * core.domStyle.scale + 'px'; + newCanvas.style.zIndex = z; + newCanvas.style.position = 'absolute'; + core.dymCanvas[name] = newCanvas.getContext('2d'); + core.dom.dymCanvas.appendChild(newCanvas); + core.dymCanvas._list.push({ + "id": name, + "style": { + "left": x, + "top": y, + } + }); +} + +////// canvas查找 ////// +ui.prototype.findCanvas = function (name) { + var index = 0; + while (index < core.dymCanvas._list.length && core.dymCanvas._list[index].id != name) index++; + if (index == core.dymCanvas._list.length) { + return -1; + } + return index; +} + +////// canvas重定位 ////// +ui.prototype.relocateCanvas = function (name, x, y) { + var index = core.findCanvas(name); + if (core.isset(x)) { + core.dymCanvas[name].canvas.style.left = x * core.domStyle.scale + 'px'; + core.dymCanvas._list[index].style.left = x; + } + if (core.isset(y)) { + core.dymCanvas[name].canvas.style.top = y * core.domStyle.scale + 'px'; + core.dymCanvas._list[index].style.top = y; + } +} + +////// canvas重置 ////// +ui.prototype.resizeCanvas = function (name, width, height) { + var dstCanvas = core.dymCanvas[name].canvas; + if (core.isset(width)) { + dstCanvas.width = width; + dstCanvas.style.width = width * core.domStyle.scale + 'px'; + } + if (core.isset(height)) { + dstCanvas.height = height; + dstCanvas.style.height = height * core.domStyle.scale + 'px'; + } +} +////// canvas删除 ////// +ui.prototype.deleteCanvas = function (name) { + var index = core.findCanvas(name); + if (index == -1) { + console.error("未找到"+name); + } + var obj = core.dom.dymCanvas.removeChild(core.dom.dymCanvas.childNodes[index]); + obj = null; + core.dymCanvas[name] = null; + core.dymCanvas._list.splice(index,1); +} diff --git a/main.js b/main.js index 0ea10df4..80ea5f7d 100644 --- a/main.js +++ b/main.js @@ -68,7 +68,9 @@ function main() { 'debuffCol': document.getElementById('debuffCol'), 'skillCol': document.getElementById('skillCol'), 'hard': document.getElementById('hard'), - 'statusCanvas': document.getElementById('statusCanvas') + 'statusCanvas': document.getElementById('statusCanvas'), + 'dymCanvas': document.getElementById('dymCanvas'), + 'dym': document.getElementsByClassName('dym'), }; this.mode = 'play'; this.loadList = [ diff --git a/project/data.js b/project/data.js index 9498941c..e65bf7bd 100644 --- a/project/data.js +++ b/project/data.js @@ -110,11 +110,16 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = }, { "type": "showImage", - "name": "bg.jpg", + "code": 1, + "image": "bg.jpg", "loc": [ 0, 0 - ] + ], + "dw": 100, + "dh": 100, + "opacity": 100, + "time": 0 }, { "type": "comment", @@ -163,7 +168,9 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = ] }, { - "type": "showImage" + "type": "hideImage", + "code": 1, + "time": 0 }, { "type": "comment", @@ -179,7 +186,9 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "function": "function(){\ncore.control.checkBgm()\n}" }, { - "type": "showImage" + "type": "hideImage", + "code": 1, + "time": 0 }, { "type": "comment", @@ -202,6 +211,11 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "type": "function", "function": "function(){\ncore.control.checkBgm()\n}" }, + { + "type": "hideImage", + "code": 1, + "time": 0 + }, { "type": "comment", "text": "这段代码会结束事件,选择录像文件,播放录像或重新开始" @@ -339,7 +353,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "hatred": 2, "moveSpeed": 100, "animateSpeed": 300, - "floorChangeTime": 800, + "floorChangeTime": 800 }, "flags": { "enableFloor": true, diff --git a/styles.css b/styles.css index 4e3d174b..6a967fd3 100644 --- a/styles.css +++ b/styles.css @@ -21,7 +21,7 @@ position: fixed; top: 10px; left: 10px; - z-index: 320; + z-index: 370; } #startPanel { @@ -32,7 +32,7 @@ left: 0; background-color: #fff; overflow: hidden; - z-index: 250; + z-index: 300; } #startTop { @@ -42,7 +42,7 @@ top: 0; left: 0; background-color: #000; - z-index: 300; + z-index: 350; } #startTopProgressBar { @@ -77,12 +77,12 @@ height: 100%; width: auto; transform:translate(-50%,-50%); - z-index: 210; + z-index: 260; } #startLogo { position: absolute; - z-index: 240; + z-index: 290; left: 0; right: 0; margin-left: auto; @@ -95,7 +95,7 @@ #startTitle { position: absolute; - z-index: 230; + z-index: 280; } #startButtonGroup { @@ -106,7 +106,7 @@ background-color: #000; opacity: 0.85; display: none; - z-index: 260; + z-index: 310; bottom: 0; margin-bottom: 7%; } @@ -142,7 +142,7 @@ display: none; color: #fff; background-color: #000; - z-index: 180; + z-index: 230; } #logoLabel { @@ -170,7 +170,7 @@ -moz-box-sizing: border-box; -webkit-box-sizing: border-box; background: url(project/images/ground.png) repeat; - z-index: 135; + z-index: 185; display: none; } #statusBar .status{ @@ -200,7 +200,7 @@ #toolBar { position: absolute; background: url(project/images/ground.png) repeat; - z-index: 160; + z-index: 210; box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -255,7 +255,7 @@ p#name { position: absolute; background: #000000; overflow: hidden; - z-index: 135; + z-index: 185; } #bg { @@ -298,16 +298,16 @@ p#name { z-index: 100; } -#image { - z-index: 105; -} - #ui { - z-index: 110; + z-index: 160; } #data { - z-index: 120; + z-index: 170; +} + +#dymCanvas { + position: absolute; } .clearfix:before, From 71f03ffbfe687af03210f74c6ddaa76f3d9e9d47 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Thu, 13 Dec 2018 20:41:20 +0800 Subject: [PATCH 57/81] Search --- _server/css/editor.css | 18 +++++++++++ _server/editor_blockly.js | 63 ++++++++++++++++++++++++++++++++++++--- editor.html | 4 +++ 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/_server/css/editor.css b/_server/css/editor.css index 928a0964..c5837379 100644 --- a/_server/css/editor.css +++ b/_server/css/editor.css @@ -392,3 +392,21 @@ table.row td { [v-cloak] { display: none !important; } + +#blockSearch { + width: 100px; + background-color: #E9EBF2; + border-radius: 10px; + outline: none; + padding-left: 20px; + height: 14px; +} + +.searchLogo { + width: 15px; + height: 15px; + position: absolute; + left: 6px; + top: 7px; + background-image:url('data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJmdWxsIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpldj0iaHR0cDovL3d3dy53My5vcmcvMjAwMS94bWwtZXZlbnRzIj4KPGc%2BCgk8cG9seWdvbiBmaWxsPSIjNjY2IiBwb2ludHM9IjkuMjA3LDYuMTI2IDcuNzkzLDcuNTQxIDExLjc5MywxMS41NDEgMTMuMjA3LDEwLjEyNiIgLz4KCTxwYXRoIGZpbGw9IiM2NjYiIGQ9Ik01LjkxNywyYzEuNjA4LDAsMi45MTcsMS4zMDgsMi45MTcsMi45MTdTNy41MjUsNy44MzMsNS45MTcsNy44MzNTMyw2LjUyNSwzLDQuOTE3UzQuMzA4LDIsNS45MTcsMgoJCSBNNS45MTcsMEMzLjIwMSwwLDEsMi4yMDEsMSw0LjkxN3MyLjIwMSw0LjkxNyw0LjkxNyw0LjkxN3M0LjkxNy0yLjIwMSw0LjkxNy00LjkxN0MxMC44MzMsMi4yMDEsOC42MzIsMCw1LjkxNywwTDUuOTE3LDB6IiAvPgo8L2c%2BCjwvc3ZnPgo%3D'); +} \ No newline at end of file diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index a966619f..1d12d9ad 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -277,9 +277,10 @@ var workspace = Blockly.inject(blocklyDiv,{ editor_blockly.searchBlockCategoryCallback = function(workspace) { var xmlList = []; - for (var i = 0; i < editor_blockly.lastUsedType.length; i++) { + var labels = editor_blockly.searchBlock(); + for (var i = 0; i < labels.length; i++) { var blockText = '' + - MotaActionBlocks[editor_blockly.lastUsedType[i]].xmlText() + + MotaActionBlocks[labels[i]].xmlText() + ''; var block = Blockly.Xml.textToDom(blockText).firstChild; block.setAttribute("gap", 5); @@ -310,8 +311,8 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ workspace.setScale(workspace.scale); } - var doubleClickCheck=[[0,'abc']]; - function omitedcheckUpdateFunction(event) { +var doubleClickCheck=[[0,'abc']]; +function omitedcheckUpdateFunction(event) { if(event.type==='move'){ editor_blockly.addIntoLastUsedType(event.blockId); } @@ -565,6 +566,60 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ editor_blockly.lastUsedType.unshift(blockType); } + // Index from 1 - 9 + editor_blockly.openToolbox = function(index) { + var element = document.getElementById(':'+index); + if (element == null || element.getAttribute("aria-selected")=="true") return; + element.click(); + } + editor_blockly.reopenToolbox = function(index) { + var element = document.getElementById(':'+index); + if (element == null) return; + if (element.getAttribute("aria-selected")=="true") element.click(); + element.click(); + } + + editor_blockly.closeToolbox = function() { + for (var i=1; i<=10; i++) { + var element = document.getElementById(':'+i); + if (element && element.getAttribute("aria-selected")=="true") { + element.click(); + return; + } + } + } + + var searchInput = document.getElementById("blockSearch"); + searchInput.onfocus = function () { + editor_blockly.reopenToolbox(9); + } + + searchInput.oninput = function () { + editor_blockly.reopenToolbox(9); + } + + editor_blockly.searchBlock = function (value) { + if (value == null) value = searchInput.value; + value = value.toLowerCase(); + if (value == '') return editor_blockly.lastUsedType; + var results = []; + for (var name in MotaActionBlocks) { + if (typeof name !== 'string' || name.indexOf("_s") !== name.length-2) continue; + var block = MotaActionBlocks[name]; + if(block && block.json) { + if ((block.json.type||"").toLowerCase().indexOf(value)>=0 + || (block.json.message0||"").toLowerCase().indexOf(value)>=0 + || (block.json.tooltip||"").toLowerCase().indexOf(value)>=0) { + results.push(name); + if (results.length>=editor_blockly.lastUsedTypeNum) + break; + } + } + } + + return results.length == 0 ? editor_blockly.lastUsedType : results; + } + return editor_blockly; } //editor_blockly=editor_blockly(); \ No newline at end of file diff --git a/editor.html b/editor.html index 54cdb46e..ce6bf5c2 100644 --- a/editor.html +++ b/editor.html @@ -178,6 +178,10 @@ +
+ + +
From 8d31055c5255657505935d201a7afed55168001f Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 13 Dec 2018 22:43:28 +0800 Subject: [PATCH 58/81] Search Blockly --- _server/css/editor.css | 4 ++-- _server/editor_blockly.js | 27 +++++++++++++++++---------- editor-mobile.html | 5 +++++ editor.html | 2 +- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/_server/css/editor.css b/_server/css/editor.css index c5837379..ebd4b009 100644 --- a/_server/css/editor.css +++ b/_server/css/editor.css @@ -393,7 +393,7 @@ table.row td { display: none !important; } -#blockSearch { +#searchBlock { width: 100px; background-color: #E9EBF2; border-radius: 10px; @@ -407,6 +407,6 @@ table.row td { height: 15px; position: absolute; left: 6px; - top: 7px; + top: 6px; background-image:url('data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJmdWxsIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpldj0iaHR0cDovL3d3dy53My5vcmcvMjAwMS94bWwtZXZlbnRzIj4KPGc%2BCgk8cG9seWdvbiBmaWxsPSIjNjY2IiBwb2ludHM9IjkuMjA3LDYuMTI2IDcuNzkzLDcuNTQxIDExLjc5MywxMS41NDEgMTMuMjA3LDEwLjEyNiIgLz4KCTxwYXRoIGZpbGw9IiM2NjYiIGQ9Ik01LjkxNywyYzEuNjA4LDAsMi45MTcsMS4zMDgsMi45MTcsMi45MTdTNy41MjUsNy44MzMsNS45MTcsNy44MzNTMyw2LjUyNSwzLDQuOTE3UzQuMzA4LDIsNS45MTcsMgoJCSBNNS45MTcsMEMzLjIwMSwwLDEsMi4yMDEsMSw0LjkxN3MyLjIwMSw0LjkxNyw0LjkxNyw0LjkxN3M0LjkxNy0yLjIwMSw0LjkxNy00LjkxN0MxMC44MzMsMi4yMDEsOC42MzIsMCw1LjkxNywwTDUuOTE3LDB6IiAvPgo8L2c%2BCjwvc3ZnPgo%3D'); } \ No newline at end of file diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 1d12d9ad..928c4803 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -313,7 +313,7 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ var doubleClickCheck=[[0,'abc']]; function omitedcheckUpdateFunction(event) { - if(event.type==='move'){ + if(event.type==='create'){ editor_blockly.addIntoLastUsedType(event.blockId); } if(event.type==='ui'){ @@ -559,27 +559,32 @@ function omitedcheckUpdateFunction(event) { if(!b)return; var blockType = b.type; if(!blockType || blockType.indexOf("_s")!==blockType.length-2 || blockType==='pass_s')return; - console.log(b); editor_blockly.lastUsedType = editor_blockly.lastUsedType.filter(function (v) {return v!==blockType;}); if (editor_blockly.lastUsedType.length >= editor_blockly.lastUsedTypeNum) editor_blockly.lastUsedType.pop(); editor_blockly.lastUsedType.unshift(blockType); + + document.getElementById("searchBlock").value=''; } // Index from 1 - 9 editor_blockly.openToolbox = function(index) { - var element = document.getElementById(':'+index); - if (element == null || element.getAttribute("aria-selected")=="true") return; - element.click(); + // var element = document.getElementById(':'+index); + // if (element == null || element.getAttribute("aria-selected")=="true") return; + // element.click(); + editor_blockly.workspace.toolbox_.tree_.setSelectedItem(editor_blockly.workspace.toolbox_.tree_.children_[index-1]); } editor_blockly.reopenToolbox = function(index) { - var element = document.getElementById(':'+index); - if (element == null) return; - if (element.getAttribute("aria-selected")=="true") element.click(); - element.click(); + // var element = document.getElementById(':'+index); + // if (element == null) return; + // if (element.getAttribute("aria-selected")=="true") element.click(); + // element.click(); + editor_blockly.workspace.toolbox_.tree_.setSelectedItem(editor_blockly.workspace.toolbox_.tree_.children_[index-1]); + editor_blockly.workspace.getFlyout_().show(editor_blockly.workspace.toolbox_.tree_.children_[index-1].blocks); } editor_blockly.closeToolbox = function() { + /* for (var i=1; i<=10; i++) { var element = document.getElementById(':'+i); if (element && element.getAttribute("aria-selected")=="true") { @@ -587,9 +592,11 @@ function omitedcheckUpdateFunction(event) { return; } } + */ + editor_blockly.workspace.toolbox_.clearSelection(); } - var searchInput = document.getElementById("blockSearch"); + var searchInput = document.getElementById("searchBlock"); searchInput.onfocus = function () { editor_blockly.reopenToolbox(9); } diff --git a/editor-mobile.html b/editor-mobile.html index c3396905..fedd1cb1 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -179,6 +179,11 @@ + +
+ + +
diff --git a/editor.html b/editor.html index ce6bf5c2..df51ae2e 100644 --- a/editor.html +++ b/editor.html @@ -180,7 +180,7 @@
- +
From 7be7d3706fa8ecbf7d3b8815d32ae7da0fed7cef Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 13 Dec 2018 23:01:41 +0800 Subject: [PATCH 59/81] Loop Critical for Big Number --- libs/enemys.js | 4 +++- libs/ui.js | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libs/enemys.js b/libs/enemys.js index a3097af3..bc1563b5 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -179,7 +179,9 @@ enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId) { } else { // 暴力for循环法 pre = info.damage; - for (var atk=hero_atk+1;atk<=mon_hp+mon_def;atk++) { + var per_add = Math.ceil(hero_atk / 5000); + if (per_add<0) per_add = 1; + for (var atk=hero_atk+per_add;atk<=mon_hp+mon_def;atk+=per_add) { var nextInfo = this.getDamageInfo(enemy, core.status.hero.hp, atk, core.status.hero.def, core.status.hero.mdef, x, y, floorId); if (nextInfo==null) break; if (pre>nextInfo.damage) { diff --git a/libs/ui.js b/libs/ui.js index ec7c1dec..15f0bd0e 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1645,7 +1645,7 @@ ui.prototype.drawBookDetail = function (index) { u.push(t); } }); - hints.push(JSON.stringify(u.map(function (v) {return v[0]+":"+v[1];}))); + hints.push(JSON.stringify(u.map(function (v) {return core.formatBigNumber(v[0])+":"+core.formatBigNumber(v[1]);}))); } } @@ -1679,7 +1679,7 @@ ui.prototype.drawBookDetail = function (index) { hints.push(""); var criticals = core.enemys.nextCriticals(enemyId, 10).map(function (v) { - return v[0]+":"+v[1]; + return core.formatBigNumber(v[0])+":"+core.formatBigNumber(v[1]); }); while (criticals[0]=='0:0') criticals.shift(); hints.push("临界表:"+JSON.stringify(criticals)) From e8559f3e2d07a54a2575c2b9caeef8b2cbde9dd0 Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 13 Dec 2018 23:50:01 +0800 Subject: [PATCH 60/81] noGlobalAnimate --- _server/blockly/MotaAction.g4 | 11 ++++++----- _server/comment.js | 2 +- _server/editor.js | 9 ++++++++- libs/maps.js | 6 +++++- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 5b681deb..37dca134 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -5,22 +5,23 @@ grammar MotaAction; //事件 事件编辑器入口之一 event_m - : '事件' BGNL? Newline '覆盖触发器' Bool '启用' Bool '通行状态' B_0_List '显伤' Bool BGNL? Newline action+ BEND + : '事件' BGNL? Newline '覆盖触发器' Bool '启用' Bool '通行状态' B_0_List '动画' Bool '显伤' Bool BGNL? Newline action+ BEND /* event_m tooltip : 编辑魔塔的事件 helpUrl : https://h5mota.com/games/template/docs/#/event -default : [false,null,null,null] +default : [false,null,null,null,null] B_0_List_0=eval(B_0_List_0); var code = { 'trigger': Bool_0?'action':null, 'enable': Bool_1, 'noPass': B_0_List_0, - 'displayDamage': Bool_2, + 'animate': Bool_2, + 'displayDamage': Bool_3, 'data': 'data_asdfefw' } -if (!Bool_0 && Bool_1 && (B_0_List_0===null) && Bool_2) code = 'data_asdfefw'; +if (!Bool_0 && Bool_1 && (B_0_List_0===null) && Bool_2 && Bool_3) code = 'data_asdfefw'; code=JSON.stringify(code,null,2).split('"data_asdfefw"').join('[\n'+action_0+']\n'); return code; */; @@ -1803,7 +1804,7 @@ ActionParser.prototype.parse = function (obj,type) { if(typeof(obj)===typeof('')) obj={'data':[obj]}; if(obj instanceof Array) obj={'data':obj}; return MotaActionBlocks['event_m'].xmlText([ - obj.trigger==='action',obj.enable,obj.noPass,obj.displayDamage,this.parseList(obj.data) + obj.trigger==='action',obj.enable,obj.noPass,obj.animate,obj.displayDamage,this.parseList(obj.data) ]); case 'changeFloor': diff --git a/_server/comment.js b/_server/comment.js index c38b6cd9..41aa00ef 100644 --- a/_server/comment.js +++ b/_server/comment.js @@ -261,7 +261,7 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_leaf": true, "_type": "textarea", "_range": "thiseval==null||(thiseval instanceof Array)", - "_data": "该图块的不可入方向\n可以在这里定义不能从哪个方向访问该图块,可以达到悬崖之类的效果\n例如 [\"down\", \"right\"] 代表不能从下或右访问此图块\n此值对背景层、事件层、前景层上的图块均有效" + "_data": "该图块的不可入方向\n可以在这里定义不能朝哪个方向进入该图块,可以达到悬崖之类的效果\n例如 [\"down\"] 代表不能从该图块的上方点朝向下进入此图块\n此值对背景层、事件层、前景层上的图块均有效" }, "faceIds": { "_leaf": true, diff --git a/_server/editor.js b/_server/editor.js index c9622e6f..f90a9b6f 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -295,11 +295,18 @@ editor.prototype.drawPosSelection = function () { } editor.prototype.updateMap = function () { + var evs = {}; + if (editor.currentFloorData && editor.currentFloorData.events) { + for (var loc in editor.currentFloorData.events) { + if (editor.currentFloorData.events[loc].animate == false) + evs[loc] = {"animate": false}; + } + } var blocks = main.editor.mapIntoBlocks(editor.map.map(function (v) { return v.map(function (v) { return v.idnum || v || 0 }) - }), {'events': {}, 'changeFloor': {}}, editor.currentFloorId); + }), {'events': evs, 'changeFloor': {}}, editor.currentFloorId); core.status.thisMap.blocks = blocks; main.editor.updateMap(); diff --git a/libs/maps.js b/libs/maps.js index 12865f76..1eff4460 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -146,9 +146,13 @@ maps.prototype.addEvent = function (block, x, y, event) { if (!core.isset(block.disable) && core.isset(event.enable)) { block.disable=!event.enable; } + // 覆盖animate + if (event.animate === false) { + block.event.animate = 1; + } // 覆盖所有属性 for (var key in event) { - if (key!="enable" && core.isset(event[key])) { + if (key!="enable" && key!="animate" && core.isset(event[key])) { block.event[key]=core.clone(event[key]); } } From f20d2e3c69acb08bfabeaa4aa518e8fac19b42bf Mon Sep 17 00:00:00 2001 From: oc Date: Fri, 14 Dec 2018 00:23:13 +0800 Subject: [PATCH 61/81] Fix battle check --- project/functions.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/project/functions.js b/project/functions.js index 0d47e471..a9fd87ac 100644 --- a/project/functions.js +++ b/project/functions.js @@ -526,9 +526,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = init_damage += vampire_damage; } - // 检查是否破防;否则直接返回不可战斗 - if (hero_atk <= mon_def) return null; - // 每回合怪物对勇士造成的战斗伤害 var per_damage = mon_atk - hero_def; // 魔攻:战斗伤害就是怪物攻击力 @@ -558,6 +555,10 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 勇士每回合对怪物造成的伤害 var hero_per_damage = hero_atk - mon_def; + + // 如果没有破防,则不可战斗 + if (hero_per_damage <= 0) return null; + // 勇士的攻击回合数;为怪物生命除以每回合伤害向上取整 var turn = Math.ceil(mon_hp / hero_per_damage); // 最终伤害:初始伤害 + 怪物对勇士造成的伤害 + 反击伤害 From 861a44ae20b098489d6ef6881d16543c20d7b61e Mon Sep 17 00:00:00 2001 From: oc Date: Fri, 14 Dec 2018 00:26:29 +0800 Subject: [PATCH 62/81] Fix battle check --- project/functions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/functions.js b/project/functions.js index a9fd87ac..9e06e527 100644 --- a/project/functions.js +++ b/project/functions.js @@ -554,7 +554,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = init_damage += Math.floor(core.values.purify * hero_mdef); // 勇士每回合对怪物造成的伤害 - var hero_per_damage = hero_atk - mon_def; + var hero_per_damage = Math.max(hero_atk - mon_def, 0); // 如果没有破防,则不可战斗 if (hero_per_damage <= 0) return null; From f838ef399748c5d9befd521f35e6de90cea24951 Mon Sep 17 00:00:00 2001 From: oc Date: Fri, 14 Dec 2018 10:19:41 +0800 Subject: [PATCH 63/81] Fix Bugs --- _server/editor.js | 2 +- libs/ui.js | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/_server/editor.js b/_server/editor.js index f90a9b6f..77b802e1 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -298,7 +298,7 @@ editor.prototype.updateMap = function () { var evs = {}; if (editor.currentFloorData && editor.currentFloorData.events) { for (var loc in editor.currentFloorData.events) { - if (editor.currentFloorData.events[loc].animate == false) + if ((editor.currentFloorData.events[loc]||{}).animate == false) evs[loc] = {"animate": false}; } } diff --git a/libs/ui.js b/libs/ui.js index 0ca964c4..d658802a 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -562,14 +562,10 @@ ui.prototype.drawTextBox = function(content, showAll) { validWidth = this.calTextBoxWidth('ui', realContent, min_width, max_width); width = validWidth + leftSpace + rightSpace; // left必须在7~416-7-width区间内,以保证left>=7,right<=416-7 - left = core.clamp(32*px+16-width/2, 7, 416-7-width); - - left -= core.bigmap.offsetX; - + left = core.clamp(32*px+16-width/2-core.bigmap.offsetX, 7, 416-7-width); right = left + width; } - var content_left = left + leftSpace; var height = 30 + (textfont+5)*core.splitLines("ui", realContent, validWidth, font).length; if (core.isset(name)) height += titlefont + 5; From 68dc1b6b1be3853f51eff2cffc19ea129e579efa Mon Sep 17 00:00:00 2001 From: oc Date: Fri, 14 Dec 2018 10:33:59 +0800 Subject: [PATCH 64/81] Fix Bugs --- libs/events.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libs/events.js b/libs/events.js index 922a8e27..2cbd8ee6 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1136,13 +1136,9 @@ events.prototype.doAction = function() { } break; case "sleep": // 等待多少毫秒 - if (core.status.replay.replaying) + setTimeout(function() { core.events.doAction(); - else { - setTimeout(function () { - core.events.doAction(); - }, data.time); - } + }, core.status.replay.replaying?20:data.time); break; case "wait": if (core.status.replay.replaying) { From eeab671f4e9611d629099c26aa6ae47f143aa6b8 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Fri, 14 Dec 2018 11:49:00 +0800 Subject: [PATCH 65/81] cannotMoveDirectly in floor --- _server/blockly/MotaAction.g4 | 4 ++-- _server/comment.js | 6 ++++++ _server/editor_file.js | 1 + docs/event.md | 2 +- libs/maps.js | 5 ++++- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 37dca134..501d8ef6 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -1683,8 +1683,8 @@ Bg_Fg_List /*Bg_Fg_List ['bg','fg']*/; Floor_Meta_List - : '楼层中文名'|'状态栏名称'|'能否使用楼传'|'能否打开快捷商店'|'是否不可浏览地图'|'默认地面ID'|'楼层贴图'|'宝石血瓶效果'|'上楼点坐标'|'下楼点坐标'|'背景音乐'|'画面色调'|'天气和强度'|'是否地下层' - /*Floor_Meta_List ['title','name','canFlyTo', 'canUseQuickShop', 'cannotViewMap', 'defaultGround', 'images', 'item_ratio', 'upFloor', 'downFloor', 'bgm', 'color', 'weather', 'underGround']*/; + : '楼层中文名'|'状态栏名称'|'能否使用楼传'|'能否打开快捷商店'|'是否不可浏览地图'|'是否不可瞬间移动'|'默认地面ID'|'楼层贴图'|'宝石血瓶效果'|'上楼点坐标'|'下楼点坐标'|'背景音乐'|'画面色调'|'天气和强度'|'是否地下层' + /*Floor_Meta_List ['title','name','canFlyTo', 'canUseQuickShop', 'cannotViewMap', 'cannotMoveDirectly', 'defaultGround', 'images', 'item_ratio', 'upFloor', 'downFloor', 'bgm', 'color', 'weather', 'underGround']*/; Global_Attribute_List : '全局字体'|'横屏左侧状态栏背景'|'竖屏上方状态栏背景'|'竖屏下方道具栏背景'|'边框颜色'|'状态栏文字色'|'难度显示文字色'|'楼层转换背景'|'楼层转换文字色' diff --git a/_server/comment.js b/_server/comment.js index 41aa00ef..b44cc428 100644 --- a/_server/comment.js +++ b/_server/comment.js @@ -324,6 +324,12 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_bool": "bool", "_data": "该层是否不允许被浏览地图看到;如果勾上则浏览地图会跳过该层" }, + "cannotMoveDirectly": { + "_leaf": true, + "_type": "checkbox", + "_bool": "bool", + "_data": "该层是否不允许瞬间移动;如果勾上则不可在此层进行瞬移" + }, "firstArrive": { "_leaf": true, "_type": "event", diff --git a/_server/editor_file.js b/_server/editor_file.js index 8178712c..3d2b80ca 100644 --- a/_server/editor_file.js +++ b/_server/editor_file.js @@ -147,6 +147,7 @@ editor_file = function (editor, callback) { canFlyTo: saveStatus?currData.canFlyTo:true, canUseQuickShop: saveStatus?currData.canUseQuickShop:true, cannotViewMap: saveStatus?currData.cannotViewMap:false, + cannotMoveDirectly: saveStatus?currData.cannotMoveDirectly:false, images: [], item_ratio: saveStatus?currData.item_ratio:1, defaultGround: saveStatus?currData.defaultGround:"ground", diff --git a/docs/event.md b/docs/event.md index f691e69a..2dd6f6c4 100644 --- a/docs/event.md +++ b/docs/event.md @@ -441,7 +441,7 @@ value是一个表达式,将通过这个表达式计算出的结果赋值给nam ] ``` -name为必填项,代表要修改的楼层属性。其和楼层属性中一一对应,目前只能为`"title", "name", "canFlyTo", "canUseQuickShop", "cannotViewMap", "color", "weather", +name为必填项,代表要修改的楼层属性。其和楼层属性中一一对应,目前只能为`"title", "name", "canFlyTo", "canUseQuickShop", "cannotViewMap", "cannotMoveDirectly", "color", "weather", "defaultGround", "images", "item_ratio", "upFloor", "bgm", "downFloor", "underGround"`。 floorId为可选项,代表要修改的楼层ID;可以省略代表当前楼层。 diff --git a/libs/maps.js b/libs/maps.js index 1eff4460..958dcaf7 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -18,7 +18,7 @@ maps.prototype.loadFloor = function (floorId, map) { map = {"map": map}; } var content = {}; - ["floorId", "title", "name", "canFlyTo", "canUseQuickShop", "cannotViewMap", "color", "weather", + ["floorId", "title", "name", "canFlyTo", "canUseQuickShop", "cannotViewMap", "cannotMoveDirectly", "color", "weather", "defaultGround", "images", "item_ratio", "upFloor", "bgm", "downFloor", "underGround"].forEach(function (e) { if (core.isset(map[e])) content[e] = core.clone(map[e]); else content[e] = core.clone(floor[e]); @@ -321,6 +321,9 @@ maps.prototype.canMoveDirectly = function (destX,destY) { // 不可瞬间移动请返回-1 if (!core.flags.enableMoveDirectly) return -1; + // 检查该楼层是否不可瞬间移动 + if (core.status.thisMap.cannotMoveDirectly) return -1; + // 中毒状态:不能 if (core.hasFlag('poison')) return -1; From 65f9fcb612b33a0c28664b3b9df9299b2a5e2cbf Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Fri, 14 Dec 2018 20:52:55 +0800 Subject: [PATCH 66/81] Dynamic canvas --- _server/blockly/MotaAction.g4 | 63 +++++++++++---------- _server/editor_blockly.js | 7 ++- docs/event.md | 45 ++++++++------- editor-mobile.html | 2 +- editor.html | 2 +- libs/control.js | 101 ++++++---------------------------- libs/core.js | 6 ++ libs/enemys.js | 32 +++++++++++ libs/events.js | 65 ++++++++++++---------- libs/items.js | 2 +- libs/maps.js | 68 ++++++++--------------- libs/ui.js | 20 +++++-- main.js | 1 - 13 files changed, 197 insertions(+), 217 deletions(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 06b76d77..7d4929f3 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -265,7 +265,7 @@ action | showImage_s | hideImage_s | showTextImage_s - | animateImage_s + | moveImage_s | showGif_0_s | showGif_1_s | setFg_0_s @@ -1021,34 +1021,34 @@ return code; */; showImage_s - : '显示图片' '图片编号' Int '图片' EvalString '起点像素位置' 'x' PosString 'y' PosString BGNL - '放大率 : x' Int '% y' Int '% 透明度' Int '时间' Int '不等待执行完毕' Bool Newline + : '显示图片' '图片编号' Int '图片' EvalString '起点像素位置' 'x' PosString 'y' PosString BGNL? + '放大率 : x' Int '% y' Int '% 不透明度' Number '时间' Int '不等待执行完毕' Bool Newline /* showImage_s tooltip : showImage:显示图片 -helpUrl : https://h5mota.com/games/template/docs/#/event?id=showimage%EF%BC%9A%E6%98%BE%E7%A4%BA%E5%9B%BE%E7%89%87 -default : [1,"bg.jpg","0","0",100,100,100,0,false] +helpUrl : https://h5mota.com/games/template/docs/#/event?id=showImage%ef%bc%9a%e6%98%be%e7%a4%ba%e5%9b%be%e7%89%87 +default : [1,"bg.jpg","0","0",100,100,1,0,false] colour : this.printColor -if(Int_3<0 || Int_3>100) throw new Error('透明度的值在0~100之间'); +if(Int_0<=0 || Int_0>50) throw new Error('图片编号在1~50之间'); var async = Bool_0?', "async": true':''; -var code = '{"type": "showImage", "code": '+Int_0+', "image": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "dw": '+Int_1+', "dh": '+Int_2+', "opacity": '+Int_3+', "time": '+Int_4+async+'},\n'; +var code = '{"type": "showImage", "code": '+Int_0+', "image": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "dw": '+Int_1+', "dh": '+Int_2+', "opacity": '+Number_0+', "time": '+Int_3+async+'},\n'; return code; */; showTextImage_s - : '显示图片化文本' '图片编号' Int '文本' EvalString BGNL - '起点像素位置' 'x' PosString 'y' PosString '透明度' Int '时间' Int '不等待执行完毕' Bool Newline + : '显示图片化文本' '文本内容' EvalString BGNL? + '图片编号' Int '起点像素位置' 'x' PosString 'y' PosString '不透明度' Number '时间' Int '不等待执行完毕' Bool Newline /* showTextImage_s tooltip : showTextImage:显示图片化文本 -helpUrl : https://h5mota.com/games/template/docs/#/event?id=showimage%EF%BC%9A%E6%98%BE%E7%A4%BA%E5%9B%BE%E7%89%87 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=showTextImage%ef%bc%9a%e6%98%be%e7%a4%ba%e6%96%87%e6%9c%ac%e5%8c%96%e5%9b%be%e7%89%87 colour : this.printColor -default : [1,"可以使用setText事件来控制字体、颜色、大小、偏移量等","0","0",100,0,false] -if(Int_1<0 || Int_1>100) throw new Error('透明度的值在0~100之间'); +default : ["可以使用setText事件来控制字体、颜色、大小、偏移量等",1,"0","0",1,0,false] +if(Int_0<=0 || Int_0>50) throw new Error('图片编号在1~50之间'); var async = Bool_0?', "async": true':''; -var code = '{"type": "showTextImage", "code": '+Int_0+', "text": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "opacity": '+Int_1+', "time": '+Int_2+async+'},\n'; +var code = '{"type": "showTextImage", "code": '+Int_0+', "text": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "opacity": '+Number_0+', "time": '+Int_1+async+'},\n'; return code; */; @@ -1058,9 +1058,10 @@ hideImage_s /* hideImage_s tooltip : hideImage:清除图片 -helpUrl : https://h5mota.com/games/template/docs/#/event?id=showimage%EF%BC%9A%E6%98%BE%E7%A4%BA%E5%9B%BE%E7%89%87 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=hideImage%ef%bc%9a%e6%b8%85%e9%99%a4%e5%9b%be%e7%89%87 colour : this.printColor default : [1,0,false] +if(Int_0<=0 || Int_0>50) throw new Error('图片编号在1~50之间'); var async = Bool_0?', "async": true':''; var code = '{"type": "hideImage", "code": '+Int_0+', "time": '+Int_1+async+'},\n'; return code; @@ -1091,22 +1092,23 @@ var code = '{"type": "showGif"},\n'; return code; */; -animateImage_s - : '图片移动' '编号' Int '终点像素位置' 'x' PosString? 'y' PosString? BGNL - '透明度' PosString? '移动时间' Int '不等待执行完毕' Bool Newline +moveImage_s + : '图片移动' '图片编号' Int '终点像素位置' 'x' PosString? 'y' PosString? BGNL? + '不透明度' EvalString? '移动时间' Int '不等待执行完毕' Bool Newline -/* animateImage_s -tooltip : animateImage:图片移动 -helpUrl : https://h5mota.com/games/template/docs/#/event?id=moveimage%EF%BC%9A%E5%9B%BE%E7%89%87%E7%A7%BB%E5%8A%A8 -default : [1,"0","0",100,500,false] +/* moveImage_s +tooltip : moveImage:图片移动 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=moveImage%ef%bc%9a%e5%9b%be%e7%89%87%e7%a7%bb%e5%8a%a8 +default : [1,'','','',500,false] colour : this.printColor +if(Int_0<=0 || Int_0>50) throw new Error('图片编号在1~50之间'); var toloc = ''; if (PosString_0 && PosString_1) - toloc = ', "to": ['+PosString_0+','+PosString_1+']' -PosString_2 = (PosString_2) ? (', "opacity": '+PosString_2):''; + toloc = ', "to": ['+PosString_0+','+PosString_1+']'; +EvalString_0 = (EvalString_0!=='') ? (', "opacity": '+EvalString_0):''; var async = Bool_0?', "async": true':''; -var code = '{"type": "animateImage", "code": '+Int_0+toloc+PosString_2+',"time": '+Int_1+async+'},\n'; +var code = '{"type": "moveImage", "code": '+Int_0+toloc+EvalString_0+',"time": '+Int_1+async+'},\n'; return code; */; @@ -2070,19 +2072,22 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['vibrate_s'].xmlText([data.time||0, data.async||false, this.next]); break; case "showImage": // 显示图片 + data.loc=data.loc||['',''] this.next = MotaActionBlocks['showImage_s'].xmlText([ - data.code,data.image,data.loc[0],data.loc[1],data.dw||100,data.dw||100,data.opacity||100,data.time||0,data.async||false,this.next]); + data.code,data.image,data.loc[0],data.loc[1],data.dw,data.dh,data.opacity,data.time||0,data.async||false,this.next]); break; case "hideImage": // 清除图片 this.next = MotaActionBlocks['hideImage_s'].xmlText([ data.code,data.time||0,data.async||false,this.next]); break; case "showTextImage": // 显示图片化文本 + data.loc=data.loc||['',''] this.next = MotaActionBlocks['showTextImage_s'].xmlText([ - data.code,this.EvalString(data.text),data.loc[0],data.loc[1],data.opacity||100,data.time||0,data.async||false,this.next]); + this.EvalString(data.text),data.code,data.loc[0],data.loc[1],data.opacity,data.time||0,data.async||false,this.next]); break; - case "animateImage": // 移动图片 - this.next = MotaActionBlocks['animateImage_s'].xmlText([ + case "moveImage": // 移动图片 + data.to=data.to||['',''] + this.next = MotaActionBlocks['moveImage_s'].xmlText([ data.code, data.to[0], data.to[1], data.opacity, data.time||0, data.async||false, this.next]); break; case "showGif": // 显示动图 @@ -2341,7 +2346,7 @@ MotaActionFunctions.IdString_pre = function(IdString){ MotaActionFunctions.PosString_pre = function(PosString){ if (!PosString || /^-?\d+$/.test(PosString)) return PosString; - if (!(/^flag:[0-9a-zA-Z_][0-9a-zA-Z_\-:]*$/.test(PosString)))throw new Error(PosString+'中包含了0-9 a-z A-Z _ - :之外的字符,或者是没有以flag: 开头'); + if (!(/^flag:[0-9a-zA-Z_][0-9a-zA-Z_:]*$/.test(PosString)))throw new Error(PosString+'中包含了0-9 a-z A-Z _ :之外的字符,或者是没有以flag: 开头'); return '"'+PosString+'"'; } diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 981a2746..15c48840 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -66,7 +66,7 @@ editor_blockly = function () { MotaActionBlocks['showImage_s'].xmlText(), MotaActionBlocks['hideImage_s'].xmlText(), MotaActionBlocks['showTextImage_s'].xmlText(), - MotaActionBlocks['animateImage_s'].xmlText(), + MotaActionBlocks['moveImage_s'].xmlText(), MotaActionBlocks['showGif_0_s'].xmlText(), MotaActionBlocks['showGif_1_s'].xmlText(), MotaActionBlocks['tip_s'].xmlText(), @@ -432,7 +432,7 @@ function omitedcheckUpdateFunction(event) { MotaActionFunctions.parse( eval('obj=' + codeAreaHL.getValue().replace(/[<>&]/g, function (c) { return {'<': '<', '>': '>', '&': '&'}[c]; - })), + }).replace(/\\r/g, '\\\\r').replace(/\\f/g, '\\\\f')), document.getElementById('entryType').value ); } @@ -447,7 +447,7 @@ function omitedcheckUpdateFunction(event) { var type = args.type; if (!type) return false; editor_blockly.id = id_; - codeAreaHL.setValue(input.value.replace(/\\r/g,'\\\\r').replace(/\\f/,'\\\\f')); + codeAreaHL.setValue(input.value); document.getElementById('entryType').value = type; editor_blockly.parse(); editor_blockly.show(); @@ -520,6 +520,7 @@ function omitedcheckUpdateFunction(event) { 'scrollText_s': 'EvalString_0', 'comment_s': 'EvalString_0', 'choices_s': 'EvalString_0', + 'showTextImage_s': 'EvalString_0', 'function_s': 'RawEvalString_0', 'shopsub': 'EvalString_3', } diff --git a/docs/event.md b/docs/event.md index d1e6d83f..90f38b1d 100644 --- a/docs/event.md +++ b/docs/event.md @@ -923,7 +923,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 ] ``` -name为动画名,**请确保动画在main.js中的this.animates中被定义过。** +name为动画名,**请确保动画在全塔属性中的animates中被定义过。** loc为动画的位置,可以是`[x,y]`表示在(x,y)点显示,也可以是字符串`"hero"`表示在勇士点显示。 @@ -939,25 +939,27 @@ loc可忽略,如果忽略则显示为事件当前点。 ``` js "x,y": [ // 实际执行的事件列表 - {"type": "showImage", "code": 1, "image": "bg.jpg", "loc": [231,297], "dw": 100, "dy" : 100, "opacity": 100, "time" : 0}, // 在(231,297)显示bg.jpg - {"type": "showImage", "code": 12, "image": "1.png", "loc": [209,267], "dw": 100, "dy" : 100, "opacity": 50, "time" : 1000}, // 在(209,267)渐变显示1.png,渐变时间为1000毫秒,完成时透明度为0.5,这张图片将遮盖上一张 - {"type": "showImage", "code": 8, "image": "hero.png", "loc": [349,367], "dw": 50, "dy" : 50, "opacity": 100, "time" : 0}, // 在(209,267)渐变显示hero.png,大小为原图片的一半,渐变时间为1000毫秒,这张图片将被上一张遮盖 + {"type": "showImage", "code": 1, "image": "bg.jpg", "loc": [231,297], "dw": 100, "dy" : 100, "opacity": 1, "time" : 0}, // 在(231,297)显示bg.jpg + {"type": "showImage", "code": 12, "image": "1.png", "loc": [209,267], "dw": 100, "dy" : 100, "opacity": 0.5, "time" : 1000}, // 在(209,267)渐变显示1.png,渐变时间为1000毫秒,完成时不透明度为0.5,这张图片将遮盖上一张 + {"type": "showImage", "code": 8, "image": "hero.png", "loc": [349,367], "dw": 50, "dy" : 50, "opacity": 1, "time" : 500, "async": true}, // 在(209,267)渐变显示hero.png,大小为原图片的一半,渐变时间为500毫秒,异步执行;这张图片将被上一张遮盖 ] ``` -code为图片编号,如果两张图片重叠,编号较大的显示在上。建议编号取1~50之间的数。 +code为图片编号,如果两张图片重叠,编号较大会覆盖编号较小的。该值需要在1~50之间。 -image为图片名。**请确保图片在data.js中的images中被定义过。** +image为图片名。**请确保图片在全塔属性中的images中被定义过。** loc为图片左上角坐标,以像素为单位进行计算。 dw和dh为图片的横向、纵向放大率,默认值为100,即不进行缩放。 -opacity为图片透明度,默认值为100,即不透明。 +opacity为图片不透明度,在0~1之间,默认值为1,即不透明。 time为渐变时间,默认值为0,即不渐变直接显示。 -### showTextImage:显示图片 +async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。 + +### showTextImage:显示文本化图片 我们可以使用 `{"type": "showTextImage"}` 以图片的方式显示文本。 @@ -967,16 +969,20 @@ time为渐变时间,默认值为0,即不渐变直接显示。 ] ``` -code为图片编号,如果两张图片重叠,编号较大的显示在上。建议编号取1~50之间的数。 +code为图片编号,如果两张图片重叠,编号较大会覆盖编号较小的。该值需要在1~50之间。 text为要显示的文本。默认行宽为416。 loc为图片左上角坐标,以像素为单位进行计算。 -opacity为图片透明度。 +opacity为图片不透明度,在0~1之间,默认值为1,即不透明。 time为渐变时间,默认值为0,即不渐变直接显示。 +async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。 + +文本通过图片的方式显示后,即视为一张正常图片,可以被清除或者移动。 + ### hideImage:清除图片 我们可以使用 `{"type": "hideImage"}` 来清除一张图片。 @@ -992,6 +998,8 @@ time为渐变时间,默认值为0,即不渐变直接消除。 code为显示图片时输入的图片编号。 +async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。 + ### showGif:显示动图 我们可以使用 `{"type": "showGif"}` 来显示一张图片。 @@ -1003,30 +1011,29 @@ code为显示图片时输入的图片编号。 ] ``` -name为图片名。**请确保图片在data.js中的images中被定义过。** +name为图片名。**请确保图片在全塔属性中的images中被定义过。** loc为动图左上角坐标,以像素为单位进行计算。 如果不指定name则清除所有显示的动图。 -### animateImage:图片移动 +### moveImage:图片移动 -我们可以使用 `{"type": "animateImage"}` 来造成图片移动,淡入淡出等效果。 +我们可以使用 `{"type": "moveImage"}` 来造成图片移动,淡入淡出等效果。 ``` js "x,y": [ // 实际执行的事件列表 - {"type": "animateImage", "code": 1, "to": [22,333], "opacity": 1, "time": 1000}, - // 将1号图片移动到(22,333),动画时间为1000ms - {"type": "animateImage", "code": 12, "opacity": 0.5, "time": 500}, // 将二号图片的透明度变为0.5,动画时间500ms - {"type": "animateImage", "code": 1, "to": [109,167], "opacity": 0, "time": 300, "async": true}, // 将1号图片移动到(109,167),透明度设为0(不可见),动画时间300ms,异步执行 + {"type": "moveImage", "code": 1, "to": [22,333], "opacity": 1, "time": 1000}, // 将1号图片移动到(22,333),动画时间为1000ms + {"type": "moveImage", "code": 12, "opacity": 0.5, "time": 500}, // 将二号图片的透明度变为0.5,动画时间500ms + {"type": "moveImage", "code": 1, "to": [109,167], "opacity": 0, "time": 300, "async": true}, // 将1号图片移动到(109,167),透明度设为0(不可见),动画时间300ms,异步执行 ] ``` -image为图片名。**请确保图片在data.js中的images中被定义过。** +code为图片编号。该值需要在1~50之间。 to为终点图片左上角坐标,以像素为单位进行计算,不填写则视为当前图片位置。 -opacity为完成时图片透明度,移动过程中逐渐变化。 +opacity为完成时图片不透明度,移动过程中逐渐变化。在0~1之间。 time为总移动的时间。 diff --git a/editor-mobile.html b/editor-mobile.html index fedd1cb1..41818ed2 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -443,9 +443,9 @@ - 此浏览器不支持HTML5 +
diff --git a/editor.html b/editor.html index df51ae2e..0838ffcb 100644 --- a/editor.html +++ b/editor.html @@ -428,9 +428,9 @@ - 此浏览器不支持HTML5 +
diff --git a/libs/control.js b/libs/control.js index 7f786c75..0a6b4883 100644 --- a/libs/control.js +++ b/libs/control.js @@ -113,14 +113,14 @@ control.prototype.setRequestAnimationFrame = function () { // selectorTime if (timestamp-core.animateFrame.selectorTime>20 && core.isset(core.dymCanvas.selector)) { - var opac = parseFloat(core.dymCanvas.selector.canvas.style.opacity); - if (core.getFlag("seleUp", true)) - opac += 0.02; + var opacity = parseFloat(core.dymCanvas.selector.canvas.style.opacity); + if (core.animateFrame.selectorUp) + opacity += 0.02; else - opac -= 0.02; - if (opac > 0.9 || opac < 0.6) - core.setFlag("seleUp", !core.getFlag("seleUp", true)) - core.setOpacity("selector", opac); + opacity -= 0.02; + if (opacity > 0.95 || opacity < 0.55) + core.animateFrame.selectorUp = !core.animateFrame.selectorUp; + core.setOpacity("selector", opacity); core.animateFrame.selectorTime = timestamp; } @@ -129,10 +129,10 @@ control.prototype.setRequestAnimationFrame = function () { core.clearMap('animate'); core.status.animateObjs = core.status.animateObjs.filter(function (obj) { return obj.index < obj.animate.frames.length; - }) + }); core.status.animateObjs.forEach(function (obj) { core.maps.drawAnimateFrame(obj.animate, obj.centerX, obj.centerY, obj.index++); - }) + }); core.animateFrame.animateTime = timestamp; } @@ -1372,28 +1372,8 @@ control.prototype.snipe = function (snipes) { snipe.blockImage = core.material.images[cls]; snipe.height = height; - var damage = core.enemys.getDamage(block.event.id, x, y); - var color = '#000000'; - - if (damage == null) { - damage = "???"; - color = '#FF0000'; - } - else { - if (damage <= 0) color = '#00FF00'; - else if (damage < core.status.hero.hp / 3) color = '#FFFFFF'; - else if (damage < core.status.hero.hp * 2 / 3) color = '#FFFF00'; - else if (damage < core.status.hero.hp) color = '#FF7F00'; - else color = '#FF0000'; - - damage = core.formatBigNumber(damage, true); - if (core.enemys.hasSpecial(core.material.enemys[block.event.id], 19)) - damage += "+"; - if (core.enemys.hasSpecial(core.material.enemys[block.event.id], 21)) - damage += "-"; - if (core.enemys.hasSpecial(core.material.enemys[block.event.id], 11)) - damage += "^"; - } + var damageString = core.enemys.getDamageString(block.event.id, x, y); + var damage = damageString.damage, color = damageString.color; snipe.damage = damage; snipe.color = color; @@ -1454,14 +1434,7 @@ control.prototype.snipe = function (snipes) { if (core.hasItem('book')) { // drawDamage - core.setFillStyle('damage', '#000000'); - core.canvas.damage.fillText(snipe.damage, nowX + 2, nowY + 30); - core.canvas.damage.fillText(snipe.damage, nowX, nowY + 30); - core.canvas.damage.fillText(snipe.damage, nowX + 2, nowY + 32); - core.canvas.damage.fillText(snipe.damage, nowX, nowY + 32); - - core.setFillStyle('damage', snipe.color); - core.canvas.damage.fillText(snipe.damage, nowX + 1, nowY + 31); + core.fillBoldText(core.canvas.damage, snipe.damage, snipe.color, nowX+1, nowY+31); } }) @@ -1622,36 +1595,9 @@ control.prototype.updateDamage = function (floorId, canvas) { var id = mapBlocks[b].event.id; if (core.flags.displayEnemyDamage) { - var damage = core.enemys.getDamage(id, x, y); - var color = '#000000'; - - if (damage == null) { - damage = "???"; - color = '#FF0000'; - } - else { - if (damage <= 0) color = '#00FF00'; - else if (damage < hero_hp / 3) color = '#FFFFFF'; - else if (damage < hero_hp * 2 / 3) color = '#FFFF00'; - else if (damage < hero_hp) color = '#FF7F00'; - else color = '#FF0000'; - damage = core.formatBigNumber(damage, true); - if (core.enemys.hasSpecial(core.material.enemys[id], 19)) - damage += "+"; - if (core.enemys.hasSpecial(core.material.enemys[id], 21)) - damage += "-"; - if (core.enemys.hasSpecial(core.material.enemys[id], 11)) - damage += "^"; - } - - canvas.fillStyle = '#000000'; - canvas.fillText(damage, 32 * x + 2, 32 * (y + 1) - 2); - canvas.fillText(damage, 32 * x, 32 * (y + 1) - 2); - canvas.fillText(damage, 32 * x + 2, 32 * (y + 1)); - canvas.fillText(damage, 32 * x, 32 * (y + 1)); - - canvas.fillStyle = color; - canvas.fillText(damage, 32 * x + 1, 32 * (y + 1) - 1); + var damageString = core.enemys.getDamageString(id, x, y); + var damage = damageString.damage, color = damageString.color; + core.fillBoldText(canvas, damage, color, 32*x+1, 32*(y+1)-1); } // 临界显伤 @@ -1660,13 +1606,7 @@ control.prototype.updateDamage = function (floorId, canvas) { if (critical.length>0) critical=critical[0]; critical = core.formatBigNumber(critical[0], true); if (critical == '???') critical = '?'; - canvas.fillStyle = '#000000'; - canvas.fillText(critical, 32 * x + 2, 32 * (y + 1) - 2 - 10); - canvas.fillText(critical, 32 * x, 32 * (y + 1) - 2 - 10); - canvas.fillText(critical, 32 * x + 2, 32 * (y + 1) - 10); - canvas.fillText(critical, 32 * x, 32 * (y + 1) - 10); - canvas.fillStyle = '#FFFFFF'; - canvas.fillText(critical, 32 * x + 1, 32 * (y + 1) - 1 - 10); + core.fillBoldText(canvas, critical, '#FFFFFF', 32*x+1, 32*(y+1)-11); } } @@ -1691,14 +1631,7 @@ control.prototype.updateDamage = function (floorId, canvas) { var damage = core.status.checkBlock.damage[x+core.bigmap.width*y]; if (damage>0) { damage = core.formatBigNumber(damage, true); - canvas.fillStyle = '#000000'; - canvas.fillText(damage, 32 * x + 17, 32 * (y + 1) - 13); - canvas.fillText(damage, 32 * x + 15, 32 * (y + 1) - 15); - canvas.fillText(damage, 32 * x + 17, 32 * (y + 1) - 15); - canvas.fillText(damage, 32 * x + 15, 32 * (y + 1) - 13); - - canvas.fillStyle = '#FF7F00'; - canvas.fillText(damage, 32 * x + 16, 32 * (y + 1) - 14); + core.fillBoldText(canvas, damage, "#FF7F00", 32*x+16, 32*(y+1)-14); } } } diff --git a/libs/core.js b/libs/core.js index 6b5f1a8a..76dc3052 100644 --- a/libs/core.js +++ b/libs/core.js @@ -32,6 +32,8 @@ function core() { 'globalAnimate': false, 'globalTime': null, 'boxTime': null, + 'selectorTime': null, + 'selectorUp': true, 'animateTime': null, 'moveTime': null, 'lastLegTime': null, @@ -890,6 +892,10 @@ core.prototype.updateDamage = function () { core.control.updateDamage(); } +core.prototype.fillBoldText = function (canvas, text, color, x, y, font) { + core.ui.fillBoldText(canvas, text, color, x, y, font); +} + ////// 测试是否拥有某个特殊属性 ////// core.prototype.hasSpecial = function (special, test) { return core.enemys.hasSpecial(special, test); diff --git a/libs/enemys.js b/libs/enemys.js index bc1563b5..b6fb9027 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -127,6 +127,38 @@ enemys.prototype.getExtraDamage = function (enemy) { return extra_damage; } +enemys.prototype.getDamageString = function (enemy, x, y) { + if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; + var damage = core.enemys.getDamage(enemy, x, y); + + var color = '#000000'; + + if (damage == null) { + damage = "???"; + color = '#FF0000'; + } + else { + if (damage <= 0) color = '#00FF00'; + else if (damage < core.status.hero.hp / 3) color = '#FFFFFF'; + else if (damage < core.status.hero.hp * 2 / 3) color = '#FFFF00'; + else if (damage < core.status.hero.hp) color = '#FF7F00'; + else color = '#FF0000'; + + damage = core.formatBigNumber(damage, true); + if (core.enemys.hasSpecial(enemy, 19)) + damage += "+"; + if (core.enemys.hasSpecial(enemy, 21)) + damage += "-"; + if (core.enemys.hasSpecial(enemy, 11)) + damage += "^"; + } + + return { + "damage": damage, + "color": color + }; +} + ////// 接下来N个临界值和临界减伤计算 ////// enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; diff --git a/libs/events.js b/libs/events.js index 2cbd8ee6..9d380fee 100644 --- a/libs/events.js +++ b/libs/events.js @@ -212,8 +212,7 @@ events.prototype.gameOver = function (ending, fromReplay, norank) { // 清空图片和天气 core.clearMap('animate'); - core.clearMap('image'); - core.clearMap('weather') + core.clearMap('weather'); core.dom.gif2.innerHTML = ""; core.animateFrame.weather.type = null; core.animateFrame.weather.level = 0; @@ -724,6 +723,10 @@ events.prototype.doAction = function() { data.time = 0; } var image = core.material.images.images[data.image]; + if (!core.isset(image)) { + this.doAction(); + break; + } if (data.async || data.time == 0) { core.events.showImage(data.code, image, data.loc[0], data.loc[1], data.dw, data.dh, data.opacity, data.time); this.doAction(); @@ -781,17 +784,17 @@ events.prototype.doAction = function() { } this.doAction(); break; - case "animateImage": // 图片移动 + case "moveImage": // 图片移动 if (core.status.replay.replaying) { // 正在播放录像 this.doAction(); } else { if (data.async) { - core.events.animateImage(data.code, data.to, data.opacity, data.time); + core.events.moveImage(data.code, data.to, data.opacity, data.time); this.doAction(); } else { - core.events.animateImage(data.code, data.to, data.opacity, data.time, function() { + core.events.moveImage(data.code, data.to, data.opacity, data.time, function() { core.events.doAction(); }); } @@ -1558,8 +1561,12 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback ////// 显示图片 ////// events.prototype.showImage = function (code, image, x, y, dw, dh, opacityVal, time, callback) { - dw /= 100, dh /= 100, opacityVal /= 100; + dw /= 100; + dh /= 100; + x = core.calValue(x) || 0; + y = core.calValue(y) || 0; var zIndex = code + 100; + time = time || 0; var name = "image"+ zIndex; if (core.findCanvas(name) != -1) { core.relocateCanvas(name, x, y); @@ -1568,23 +1575,24 @@ events.prototype.showImage = function (code, image, x, y, dw, dh, opacityVal, ti } else core.createCanvas(name, x, y, image.width * dw, image.height * dh, zIndex); + core.dymCanvas[name].drawImage(image, 0, 0, image.width * dw, image.height * dh); if (time == 0) core.setOpacity(name, opacityVal); else { - clearInterval(core.interval.tipAnimate); - var opac = 0; + var per_time = 10, steps = parseInt(time / per_time), per_add = opacityVal / steps; + var opacity = 0; core.setOpacity(name, 0); var animate = setInterval(function () { - opac += opacityVal/20; - core.setOpacity(name, opac); - if (opac >= opacityVal) { + opacity += per_add; + core.setOpacity(name, opacity); + if (opacity >= opacityVal) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); core.setOpacity(name, opacityVal); if (core.isset(callback)) callback(); } - }, time/20); + }, per_time); core.animateFrame.asyncId[animate] = true; } @@ -1592,27 +1600,28 @@ events.prototype.showImage = function (code, image, x, y, dw, dh, opacityVal, ti ////// 隐藏图片 ////// events.prototype.hideImage = function (code, time, callback) { + time = time || 0; var name = "image"+ (code+100); if (!core.isset(core.dymCanvas[name])) { console.log(code+"号图片不存在") + if (core.isset(callback)) callback(); return; } if (time == 0) core.deleteCanvas(name); else { - clearInterval(core.interval.tipAnimate); var opacityVal = parseFloat(core.dymCanvas[name].canvas.style.opacity); - var opac = opacityVal; + var per_time = 10, steps = parseInt(time / per_time), per_add = opacityVal / steps; var animate = setInterval(function () { - opac -= opacityVal/20; - core.setOpacity(name, opac); - if (opac < 0) { + opacityVal -= per_add; + core.setOpacity(name, opacityVal); + if (opacityVal < 0) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); core.deleteCanvas(name); if (core.isset(callback)) callback(); } - }, time/20); + }, per_time); core.animateFrame.asyncId[animate] = true; } @@ -1632,7 +1641,7 @@ events.prototype.textImage = function (content) { if (textAttribute.bold) font = "bold "+font; var contents = core.splitLines('ui', content), lines = contents.length; - // 计算总高度,按1.2倍行距计算 + // 计算总高度,按1.4倍行距计算 var width = 416, height = textfont * 1.4 * lines; var tempCanvas = core.bigmap.tempCanvas; tempCanvas.canvas.width = width; @@ -1653,29 +1662,29 @@ events.prototype.textImage = function (content) { } ////// 移动图片 ////// -events.prototype.animateImage = function (code, to, opacityVal, time, callback) { +events.prototype.moveImage = function (code, to, opacityVal, time, callback) { time = time || 1000; - clearInterval(core.interval.tipAnimate); - // core.status.replay.animate=true; var name = "image"+ (code+100), index = core.findCanvas(name); if (index == -1) { console.log(code+"号图片不存在") + if (core.isset(callback)) callback(); return; } var fromX = core.dymCanvas._list[index].style.left, fromY = core.dymCanvas._list[index].style.top, - preX = fromX, preY = fromY; - if (core.isset(to)) - var toX = core.calValue(to[0]), toY = core.calValue(to[1]); - else - var toX = fromX, toY = fromY; + preX = fromX, preY = fromY, toX = fromX, toY = fromY; + + if (core.isset(to)) { + toX = core.calValue(to[0]) || toX; + toY = core.calValue(to[1]) || toY; + } var step = 0; var per_time = 10, steps = parseInt(time / per_time); var preOpac = parseFloat(core.dymCanvas[name].canvas.style.opacity), opacStep; if (core.isset(opacityVal)) { - opacityVal /= 100; + opacityVal = core.calValue(opacityVal); opacStep = (opacityVal - preOpac) / steps; } else diff --git a/libs/items.js b/libs/items.js index f8a7bfc1..d7c5a7ff 100644 --- a/libs/items.js +++ b/libs/items.js @@ -91,7 +91,7 @@ items.prototype.useItem = function (itemId, callback) { delete core.status.hero.items[itemCls][itemId]; core.updateStatusBar(); - core.status.event.data = null; + if (!core.isset(core.status.event.id)) core.status.event.data = null; if (core.isset(callback)) callback(); } diff --git a/libs/maps.js b/libs/maps.js index 8f4b0d80..67082943 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -817,11 +817,6 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { by = core.material.icons[block.event.cls][block.event.id]; faceIds = block.event.faceIds||{}; } - - var alpha = 1, name = 'move'+x+'_'+y; - core.createCanvas(name, block.x, block.y * 32 +32 - height, 32, height, 45); - core.dymCanvas[name].textAlign = 'left'; - core.dymCanvas[name].drawImage(image, bx * 32, by * height, 32, height, 0, 0, 32, height); // 要运行的轨迹:将steps展开 var moveSteps=[]; steps.forEach(function (e) { @@ -850,8 +845,31 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { var animateValue = block.event.animate || 1; var animateCurrent = 0; + if (block.event.cls=='tileset') { + animateCurrent = bx; + } var animateTime = 0; + var alpha = 1, name = 'move'+x+'_'+y; + core.createCanvas(name, block.x - core.bigmap.offsetX, block.y * 32 +32 - height - core.bigmap.offsetY, 32, height, 45); + core.dymCanvas[name].textAlign = 'left'; + + // 显伤 + var damage = null, damageColor = null; + if ((block.event.cls == 'enemys' || block.event.cls == 'enemy48') && core.hasItem('book')) { + var damageString = core.enemys.getDamageString(block.event.id, x, y); + damage = damageString.damage; damageColor = damageString.color; + } + + var draw = function() { + core.dymCanvas[name].clearRect(0, 0, 32, height); + core.dymCanvas[name].drawImage(image, animateCurrent*32, by*height, 32, height, 0, 0, 32, height); + // 绘制显伤 + if (damage != null) + core.fillBoldText(core.dymCanvas[name], damage, damageColor, 1, height-1); + }; + draw(); + var animate=window.setInterval(function() { animateTime += time / 16 / core.status.replay.speed; @@ -899,50 +917,12 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { by = tby; } } - step++; nowX+=scan[direction].x*2; nowY+=scan[direction].y*2; // 移动 core.relocateCanvas(name, nowX, nowY-height+32); - core.dymCanvas[name].drawImage(image, animateCurrent * 32, by * height, 32, height, 0, 0, 32, height); - // 显伤绘制 - if ((block.event.cls == 'enemys' || block.event.cls == 'enemy48') && core.hasItem('book')) { - // 鉴于移动过程中可能的主角状态改变,每次重新计算 - var damage = core.enemys.getDamage(block.event.id, x, y); - var color = '#000000'; - - if (damage == null) { - damage = "???"; - color = '#FF0000'; - } - else { - if (damage <= 0) color = '#00FF00'; - else if (damage < core.status.hero.hp / 3) color = '#FFFFFF'; - else if (damage < core.status.hero.hp * 2 / 3) color = '#FFFF00'; - else if (damage < core.status.hero.hp) color = '#FF7F00'; - else color = '#FF0000'; - - damage = core.formatBigNumber(damage); - if (core.enemys.hasSpecial(core.material.enemys[block.event.id], 19)) - damage += "+"; - if (core.enemys.hasSpecial(core.material.enemys[block.event.id], 21)) - damage += "-"; - if (core.enemys.hasSpecial(core.material.enemys[block.event.id], 11)) - damage += "^"; - } - // 清空上一次 - core.clearMap('damage', nowX-2*scan[direction].x, nowY-2*scan[direction].y, 32, 32); - - core.setFillStyle('damage', '#000000'); - core.canvas.damage.fillText(damage, nowX + 5, nowY + 30); - core.canvas.damage.fillText(damage, nowX + 3, nowY + 30); - core.canvas.damage.fillText(damage, nowX + 5, nowY + 32); - core.canvas.damage.fillText(damage, nowX + 3, nowY + 32); - - core.setFillStyle('damage', color); - core.canvas.damage.fillText(damage, nowX + 4, nowY + 31); - } + draw(); if (step==16) { // 该移动完毕,继续 step=0; diff --git a/libs/ui.js b/libs/ui.js index d658802a..cb545683 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -43,6 +43,18 @@ ui.prototype.fillText = function (map, text, x, y, style, font) { core.canvas[map].fillText(text, x, y); } +////// 在某个canvas上绘制粗体 ////// +ui.prototype.fillBoldText = function (canvas, text, color, x, y, font) { + if (core.isset(font)) canvas.font = font; + canvas.fillStyle = '#000000'; + canvas.fillText(text, x-1, y-1); + canvas.fillText(text, x-1, y+1); + canvas.fillText(text, x+1, y-1); + canvas.fillText(text, x+1, y+1); + canvas.fillStyle = color; + canvas.fillText(text, x, y); +} + ////// 在某个canvas上绘制一个矩形 ////// ui.prototype.fillRect = function (map, x, y, width, height, style) { if (core.isset(style)) { @@ -762,7 +774,7 @@ ui.prototype.drawScrollText = function (content, time, callback) { if (textAttribute.bold) font = "bold "+font; var contents = core.splitLines('ui', content), lines = contents.length; - // 计算总高度,按1.2倍行距计算 + // 计算总高度,按1.4倍行距计算 var width = 416, height = textfont * 1.4 * lines; var tempCanvas = core.bigmap.tempCanvas; tempCanvas.canvas.width = width; @@ -1477,9 +1489,6 @@ ui.prototype.drawCursor = function () { ui.prototype.drawBook = function (index) { var enemys = core.enemys.getCurrentEnemys(core.floorIds[(core.status.event.selection||{}).index]); - clearInterval(core.interval.tipAnimate); - core.clearMap('data'); - core.clearLastEvent(); core.setFillStyle('ui', core.material.groundPattern); core.fillRect('ui', 0, 0, 416, 416); @@ -1577,8 +1586,8 @@ ui.prototype.drawBook = function (index) { if (line_cnt==2) damageOffset=361; core.canvas.ui.textAlign = "center"; - var damage = enemy.damage; + var damage = enemy.damage; var color = '#FFFF00'; if (damage == null) { damage = '无法战斗'; @@ -1598,7 +1607,6 @@ ui.prototype.drawBook = function (index) { } if (enemy.notBomb) damage += "[b]"; - core.fillText('ui', damage, damageOffset, 62 * i + 50, color, 'bold 13px '+globalFont); core.canvas.ui.textAlign = "left"; diff --git a/main.js b/main.js index a697bccd..bb6be1bb 100644 --- a/main.js +++ b/main.js @@ -70,7 +70,6 @@ function main() { 'hard': document.getElementById('hard'), 'statusCanvas': document.getElementById('statusCanvas'), 'dymCanvas': document.getElementById('dymCanvas'), - 'dym': document.getElementsByClassName('dym'), }; this.mode = 'play'; this.loadList = [ From 340cbe73a00b32ecd397fd14cb133bfaa259afc7 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Fri, 14 Dec 2018 21:05:20 +0800 Subject: [PATCH 67/81] Dynamic canvas --- libs/ui.js | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/libs/ui.js b/libs/ui.js index cb545683..33351c7d 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -962,7 +962,6 @@ ui.prototype.drawConfirmBox = function (text, yesCallback, noCallback) { if (core.status.event.selection<0) core.status.event.selection=0; core.clearLastEvent(); - core.setFillStyle('ui', core.material.groundPattern); var background = core.status.textAttribute.background; var isWindowSkin = false; @@ -1013,7 +1012,7 @@ ui.prototype.drawConfirmBox = function (text, yesCallback, noCallback) { var strokeLeft = 208 + (76*core.status.event.selection-38) - parseInt(len/2) - 5; if (isWindowSkin) - this.drawWindowSelector(background, 'ui', strokeLeft, bottom-35-20, len+10, 28); + this.drawWindowSelector(background, strokeLeft, bottom-35-20, len+10, 28); else core.strokeRect('ui', strokeLeft, bottom-35-20, len+10, 28, "#FFD700", 2); @@ -2764,7 +2763,7 @@ ui.prototype.drawHelp = function () { ////// canvas创建 ////// ui.prototype.createCanvas = function (name, x, y, width, height, z) { - var newCanvas = document.createElement("CANVAS"); + var newCanvas = document.createElement("canvas"); newCanvas.id = name; newCanvas.style.display = 'block'; newCanvas.width = width; @@ -2788,17 +2787,17 @@ ui.prototype.createCanvas = function (name, x, y, width, height, z) { ////// canvas查找 ////// ui.prototype.findCanvas = function (name) { - var index = 0; - while (index < core.dymCanvas._list.length && core.dymCanvas._list[index].id != name) index++; - if (index == core.dymCanvas._list.length) { - return -1; + for (var index = 0; index < core.dymCanvas._list.length; index++) { + if (core.dymCanvas._list[index].id == name) + return index; } - return index; + return -1; } ////// canvas重定位 ////// ui.prototype.relocateCanvas = function (name, x, y) { var index = core.findCanvas(name); + if (index < 0) return; if (core.isset(x)) { core.dymCanvas[name].canvas.style.left = x * core.domStyle.scale + 'px'; core.dymCanvas._list[index].style.left = x; @@ -2824,11 +2823,8 @@ ui.prototype.resizeCanvas = function (name, width, height) { ////// canvas删除 ////// ui.prototype.deleteCanvas = function (name) { var index = core.findCanvas(name); - if (index == -1) { - console.error("未找到"+name); - } - var obj = core.dom.dymCanvas.removeChild(core.dom.dymCanvas.childNodes[index]); - obj = null; + if (index == -1) return; + core.dom.dymCanvas.removeChild(core.dom.dymCanvas.childNodes[index]); core.dymCanvas[name] = null; core.dymCanvas._list.splice(index,1); } From 86fbd7ae54f1dd39337290a183695905ec365f38 Mon Sep 17 00:00:00 2001 From: oc Date: Fri, 14 Dec 2018 23:23:47 +0800 Subject: [PATCH 68/81] moveOneStep in functions --- _server/data.comment.js | 6 ++++++ _server/functions.comment.js | 6 ++++++ libs/actions.js | 7 +++++++ libs/control.js | 16 +++------------- libs/events.js | 2 ++ libs/ui.js | 6 +++++- libs/utils.js | 2 +- project/data.js | 3 ++- project/functions.js | 18 ++++++++++++++++++ 9 files changed, 50 insertions(+), 16 deletions(-) diff --git a/_server/data.comment.js b/_server/data.comment.js index ec0d4f11..788dd247 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -658,6 +658,12 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_type": "checkbox", "_bool": "bool", "_data": "是否在经过领域/夹击/路障等伤害后禁用快捷商店。" + }, + "checkConsole": { + "_leaf": true, + "_type": "checkbox", + "_bool": "bool", + "_data": "是否检查控制台的开启情况。" } } } diff --git a/_server/functions.comment.js b/_server/functions.comment.js index ae97a7cd..9b8c79dd 100644 --- a/_server/functions.comment.js +++ b/_server/functions.comment.js @@ -162,6 +162,12 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_type": "textarea", "_lint": true, "_data": "阻激夹域的伤害值计算" + }, + "moveOneStep": { + "_leaf": true, + "_type": "textarea", + "_lint": true, + "_data": "勇士每走一步的操作" } } }, diff --git a/libs/actions.js b/libs/actions.js index 917774c5..d50443b8 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -655,6 +655,13 @@ actions.prototype.longClick = function (x, y, fromEvent) { core.doAction(); return true; } + // 长按楼传器的箭头可以快速翻页 + if (core.status.event.id=='fly') { + if ((x==10 || x==11) && (y==5 || y==9)) { + this.clickFly(x, y); + return true; + } + } } else if (!fromEvent) { core.waitHeroToStop(function () { diff --git a/libs/control.js b/libs/control.js index 0a6b4883..c623a804 100644 --- a/libs/control.js +++ b/libs/control.js @@ -387,6 +387,8 @@ control.prototype.resetStatus = function(hero, hard, floorId, route, maps, value 'currTime': 0, 'hp': 0, "battle": 0, + 'money': 0, + 'experience': 0, 'battleDamage': 0, 'poisonDamage': 0, 'extraDamage': 0, @@ -1036,19 +1038,7 @@ control.prototype.jumpHero = function (ex, ey, time, callback) { ////// 每移动一格后执行的事件 ////// control.prototype.moveOneStep = function() { - core.status.hero.steps++; - // 中毒状态 - if (core.hasFlag('poison')) { - core.status.hero.statistics.poisonDamage += core.values.poisonDamage; - core.status.hero.hp -= core.values.poisonDamage; - if (core.status.hero.hp<=0) { - core.status.hero.hp=0; - core.updateStatusBar(); - core.events.lose(); - return; - } - core.updateStatusBar(); - } + return this.controldata.moveOneStep(); } ////// 停止勇士的一切行动,等待勇士行动结束后,再执行callback ////// diff --git a/libs/events.js b/libs/events.js index 9d380fee..030ea2e7 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1203,6 +1203,8 @@ events.prototype.doAction = function() { ////// 往当前事件列表之前添加一个或多个事件 ////// events.prototype.insertAction = function (action, x, y, callback) { + if (core.hasFlag("__statistics__")) return; + if (core.status.event.id != 'action') { this.doEvents(action, x, y, callback); } diff --git a/libs/ui.js b/libs/ui.js index 33351c7d..d632b299 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2566,6 +2566,8 @@ ui.prototype.drawStatistics = function () { var temp = core.clone(core.status.hero); + core.setFlag("__statistics__", true); + if (core.isset(total.count[id])) { var hp=0, atk=0, def=0, mdef=0; @@ -2573,6 +2575,7 @@ ui.prototype.drawStatistics = function () { var ratio = floor.item_ratio||1; if (core.isset(core.items.itemEffect[id])) { try { + // 需要检查是否是测试状态... eval(core.items.itemEffect[id]); } catch (e) {} @@ -2673,7 +2676,8 @@ ui.prototype.drawStatistics = function () { +",总游戏时长"+formatTime(statistics.totalTime) +"。\n瞬间移动次数:"+statistics.moveDirectly+",共计少走"+statistics.ignoreSteps+"步。" +"\n\n总计通过血瓶恢复生命值为"+core.formatBigNumber(statistics.hp)+"点。\n\n" - +"总计打死了"+statistics.battle+"个怪物,受到的伤害为"+core.formatBigNumber(statistics.battleDamage+statistics.poisonDamage+statistics.extraDamage) + +"总计打死了"+statistics.battle+"个怪物,得到了"+core.formatBigNumber(statistics.money)+"金币,"+core.formatBigNumber(statistics.experience)+"点经验。\n\n" + +"受到的总伤害为"+core.formatBigNumber(statistics.battleDamage+statistics.poisonDamage+statistics.extraDamage) +",其中战斗伤害"+core.formatBigNumber(statistics.battleDamage)+"点" +(core.flags.enableDebuff?(",中毒伤害"+core.formatBigNumber(statistics.poisonDamage)+"点"):"") +",领域/夹击/阻击/血网伤害"+core.formatBigNumber(statistics.extraDamage)+"点。", diff --git a/libs/utils.js b/libs/utils.js index 45313e71..8cb58dce 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -839,9 +839,9 @@ utils.prototype.decodeCanvas = function (arr, width, height) { } utils.prototype.consoleOpened = function () { + if (!core.flags.checkConsole) return false; if (window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized) return true; - if (!core.platform.isPC) return false; var threshold = 160; var zoom = Math.min(window.outerWidth/window.innerWidth, window.outerHeight/window.innerHeight); return window.outerWidth - zoom*window.innerWidth > threshold diff --git a/project/data.js b/project/data.js index 75900628..a1c7d4d8 100644 --- a/project/data.js +++ b/project/data.js @@ -398,6 +398,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "canGoDeadZone": false, "enableMoveDirectly": true, "enableDisabledShop": true, - "disableShopOnDamage": false + "disableShopOnDamage": false, + "checkConsole": false } } \ No newline at end of file diff --git a/project/functions.js b/project/functions.js index 9e06e527..8bde3593 100644 --- a/project/functions.js +++ b/project/functions.js @@ -158,9 +158,11 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (core.hasItem('coin')) money *= 2; if (core.hasFlag('curse')) money=0; core.status.hero.money += money; + core.status.hero.statistics.money += money; var experience =enemy.experience; if (core.hasFlag('curse')) experience=0; core.status.hero.experience += experience; + core.status.hero.statistics.experience += experience; var hint = "打败 " + enemy.name; if (core.flags.enableMoney) hint += ",金币+" + money; @@ -1005,6 +1007,22 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } } } +}, + "moveOneStep": function () { + // 勇士每走一步后执行的操作 + core.status.hero.steps++; + // 中毒状态:扣血 + if (core.hasFlag('poison')) { + core.status.hero.statistics.poisonDamage += core.values.poisonDamage; + core.status.hero.hp -= core.values.poisonDamage; + if (core.status.hero.hp<=0) { + core.status.hero.hp=0; + core.updateStatusBar(); + core.events.lose(); + return; + } + core.updateStatusBar(); + } } }, "ui": { From e3f4f9dc68e7f2d87d6fe95b5de4a52e4b8e4014 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 15 Dec 2018 12:02:54 +0800 Subject: [PATCH 69/81] showToolbox & force autoSave --- _server/blockly/MotaAction.g4 | 8 ++++--- docs/event.md | 2 +- libs/control.js | 40 +++++++++++++++++++++++++---------- libs/events.js | 2 +- libs/ui.js | 3 +-- project/functions.js | 2 +- 6 files changed, 38 insertions(+), 19 deletions(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 7d4929f3..f8910a0b 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -813,14 +813,16 @@ return code; */; hideStatusBar_s - : '隐藏状态栏' Newline + : '隐藏状态栏' '不隐藏竖屏工具栏' Bool Newline /* hideStatusBar_s tooltip : hideStatusBar: 隐藏状态栏 helpUrl : https://h5mota.com/games/template/docs/#/event?id=hideStatusBar%ef%bc%9a%e9%9a%90%e8%97%8f%e7%8a%b6%e6%80%81%e6%a0%8f colour : this.soundColor -var code = '{"type": "hideStatusBar"},\n'; +default : [false] +Bool_0 = Bool_0?', "toolbox": true':''; +var code = '{"type": "hideStatusBar"'+Bool_0+'},\n'; return code; */; @@ -2248,7 +2250,7 @@ ActionParser.prototype.parseAction = function() { break; case "hideStatusBar": this.next = MotaActionBlocks['hideStatusBar_s'].xmlText([ - this.next]); + this.toolbox||false,this.next]); break; case "updateEnemys": this.next = MotaActionBlocks['updateEnemys_s'].xmlText([ diff --git a/docs/event.md b/docs/event.md index 90f38b1d..0ccdc36c 100644 --- a/docs/event.md +++ b/docs/event.md @@ -750,7 +750,7 @@ name是可选的,代表目标行走图的文件名。 使用`{"type": "hideStatusBar"}`可以隐藏状态栏。读档或重新开始游戏时,状态栏会重新显示。 -隐藏状态栏的状态下,将无法点击工具栏里面的按钮(如存读档怪物手册等)。建议仅在事件中使用,事件结束前显示。 +可以添加`"toolbox": true`来不隐藏竖屏模式下的工具栏。 ### showStatusBar:显示状态栏 diff --git a/libs/control.js b/libs/control.js index c623a804..0430ba83 100644 --- a/libs/control.js +++ b/libs/control.js @@ -411,7 +411,7 @@ control.prototype.resetStatus = function(hero, hard, floorId, route, maps, value core.events.initGame(); this.updateGlobalAttribute(Object.keys(core.status.globalAttribute)); - this.triggerStatusBar(core.getFlag('hideStatusBar', false)?'hide':'show'); + this.triggerStatusBar(core.getFlag('hideStatusBar', false)?'hide':'show', core.getFlag("showToolbox")); core.status.played = true; } @@ -2214,17 +2214,23 @@ control.prototype.openSettings = function (need) { ////// 自动存档 ////// control.prototype.autosave = function (removeLast) { - if (core.status.event.id!=null) - return; + var addLast = true; + if (core.status.event.id!=null) { + // 检查是否是强制自动存档 + if (core.status.event.id=='action' && core.hasFlag("forceSave")) addLast = false; + else return; + } var x=null; if (removeLast) x=core.status.route.pop(); - // 加入当前方向 - core.status.route.push("turn:"+core.getHeroLoc('direction')); - core.setLocalForage("autoSave", core.saveData()) - core.status.route.pop(); + if (addLast) + core.status.route.push("turn:"+core.getHeroLoc('direction')); + core.setLocalForage("autoSave", core.saveData()); + if (addLast) + core.status.route.pop(); if (removeLast && core.isset(x)) core.status.route.push(x); + core.removeFlag("forceSave"); } ////// 实际进行存读档事件 ////// @@ -2762,17 +2768,20 @@ control.prototype.updateStatusBar = function () { } } -control.prototype.triggerStatusBar = function (name) { +control.prototype.triggerStatusBar = function (name, showToolbox) { if (name!='hide') name='show'; var statusItems = core.dom.status; var toolItems = core.dom.tools; core.domStyle.showStatusBar = name == 'show'; core.setFlag('hideStatusBar', core.domStyle.showStatusBar?null:true); + core.setFlag('showToolbox', showToolbox); if (!core.domStyle.showStatusBar) { for (var i = 0; i < statusItems.length; ++i) statusItems[i].style.opacity = 0; - for (var i = 0; i < toolItems.length; ++i) - toolItems[i].style.display = 'none'; + if (!core.domStyle.isVertical || !showToolbox) { + for (var i = 0; i < toolItems.length; ++i) + toolItems[i].style.display = 'none'; + } } else { for (var i = 0; i < statusItems.length; ++i) @@ -2861,7 +2870,16 @@ control.prototype.updateGlobalAttribute = function (name) { ////// 改变工具栏为按钮1-7 ////// control.prototype.setToolbarButton = function (useButton) { - if (!core.domStyle.showStatusBar) return; + if (!core.domStyle.showStatusBar) { + // 隐藏状态栏时检查竖屏 + if (!core.domStyle.isVertical) { + for (var i = 0; i < core.dom.tools.length; ++i) + core.dom.tools[i].style.display = 'none'; + return; + } + if (!core.hasFlag('showToolbox')) return; + else core.dom.tools.hard.style.display = 'block'; + } if (!core.isset(useButton)) useButton = core.domStyle.toolbarBtn; if (!core.domStyle.isVertical) useButton = false; diff --git a/libs/events.js b/libs/events.js index 030ea2e7..7f0df862 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1119,7 +1119,7 @@ events.prototype.doAction = function() { this.doAction(); break; case "hideStatusBar": - core.control.triggerStatusBar("hide"); + core.control.triggerStatusBar("hide", data.toolbox); this.doAction(); break; case "updateEnemys": diff --git a/libs/ui.js b/libs/ui.js index d632b299..e747cb6d 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2493,8 +2493,7 @@ ui.prototype.drawKeyBoard = function () { ////// 绘制状态栏 ///// ui.prototype.drawStatusBar = function () { - if (this.uidata.drawStatusBar) - this.uidata.drawStatusBar(); + this.uidata.drawStatusBar(); } ////// 绘制“数据统计”界面 ////// diff --git a/project/functions.js b/project/functions.js index 8bde3593..807b8b2d 100644 --- a/project/functions.js +++ b/project/functions.js @@ -89,7 +89,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // floorId是切换到的楼层;fromLoad若为true则代表是从读档行为造成的楼层切换 // 每次抵达楼层时执行的事件 - if (!fromLoad) { + if (!fromLoad || core.hasFlag("forceSave")) { core.insertAction(core.floors[floorId].eachArrive); } From 9b843081493cb3cccad2e37c12cdf704c01f76f4 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 15 Dec 2018 12:04:48 +0800 Subject: [PATCH 70/81] showToolbox in hideMode --- _server/blockly/MotaAction.g4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index f8910a0b..3fb29c71 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -2250,7 +2250,7 @@ ActionParser.prototype.parseAction = function() { break; case "hideStatusBar": this.next = MotaActionBlocks['hideStatusBar_s'].xmlText([ - this.toolbox||false,this.next]); + data.toolbox||false,this.next]); break; case "updateEnemys": this.next = MotaActionBlocks['updateEnemys_s'].xmlText([ From 430c7650ce100676b2efd2a7de38d485143b9e07 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Sun, 16 Dec 2018 13:24:54 +0800 Subject: [PATCH 71/81] setVolume & useLoop --- _server/data.comment.js | 6 ++++++ libs/control.js | 6 ++++++ libs/enemys.js | 2 +- libs/events.js | 9 ++++----- libs/maps.js | 3 +++ project/data.js | 1 + project/functions.js | 9 +++++++-- 7 files changed, 28 insertions(+), 8 deletions(-) diff --git a/_server/data.comment.js b/_server/data.comment.js index ec0d4f11..4ec5c34d 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -557,6 +557,12 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_bool": "bool", "_data": "是否循环计算临界;如果此项为true则使用循环法(而不是回合数计算法)来算临界" }, + "loopStep": { + "_leaf": true, + "_type": "textbox", + "_range": "thiseval==null || thiseval>0", + "_data": "循环计算临界时,每次攻击增加量为原始攻击的多少分之一。\n例如,5000就代表循环中每次攻击增加量是原始攻击的1/5000(向上取整)。\n默认值5000。" + }, "startUsingCanvas": { "_leaf": true, "_type": "checkbox", diff --git a/libs/control.js b/libs/control.js index beaeb8cc..bb0f3fc7 100644 --- a/libs/control.js +++ b/libs/control.js @@ -275,6 +275,9 @@ control.prototype.showStartAnimate = function (noAnimate, callback) { core.clearMap('all'); core.clearMap('curtain'); + // 重置音量 + core.events.setVolume(1, 0); + if (core.flags.startUsingCanvas) { core.dom.startTop.style.display = 'none'; core.dom.startButtonGroup.style.display = 'block'; @@ -2535,6 +2538,9 @@ control.prototype.loadData = function (data, callback) { core.control.updateGlobalAttribute(Object.keys(toAttribute)); } + // 重置音量 + core.events.setVolume(core.getFlag("__volume__", 1), 0); + // load icons var icon = core.getFlag("heroIcon", "hero.png"); if (core.isset(core.material.images.images[icon])) { diff --git a/libs/enemys.js b/libs/enemys.js index bc1563b5..4724ed0a 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -179,7 +179,7 @@ enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId) { } else { // 暴力for循环法 pre = info.damage; - var per_add = Math.ceil(hero_atk / 5000); + var per_add = Math.ceil(hero_atk / (core.flags.loopStep||5000)); if (per_add<0) per_add = 1; for (var atk=hero_atk+per_add;atk<=mon_hp+mon_def;atk+=per_add) { var nextInfo = this.getDamageInfo(enemy, core.status.hero.hp, atk, core.status.hero.def, core.status.hero.mdef, x, y, floorId); diff --git a/libs/events.js b/libs/events.js index 9998e01f..28e68bf6 100644 --- a/libs/events.js +++ b/libs/events.js @@ -884,15 +884,14 @@ events.prototype.doAction = function() { this.doAction(); break case "setVolume": - data.value = parseInt(data.value||0); - if (data.value<0) data.value=0; - if (data.value>100) data.value=100; + data.value = core.clamp(parseInt(data.value)/100, 0, 1); + core.setFlag("__volume__", data.value); if (data.async) { - this.setVolume(data.value/100, data.time); + this.setVolume(data.value, data.time); this.doAction(); } else { - this.setVolume(data.value/100, data.time, function() { + this.setVolume(data.value, data.time, function() { core.events.doAction(); }); } diff --git a/libs/maps.js b/libs/maps.js index 958dcaf7..00849c2e 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -324,6 +324,9 @@ maps.prototype.canMoveDirectly = function (destX,destY) { // 检查该楼层是否不可瞬间移动 if (core.status.thisMap.cannotMoveDirectly) return -1; + // flag:cannotMoveDirectly为true:不能 + if (core.hasFlag('cannotMoveDirectly')) return -1; + // 中毒状态:不能 if (core.hasFlag('poison')) return -1; diff --git a/project/data.js b/project/data.js index 592286c9..497b81c6 100644 --- a/project/data.js +++ b/project/data.js @@ -368,6 +368,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "hatredDecrease": true, "betweenAttackCeil": false, "useLoop": false, + "loopStep": 5000, "startUsingCanvas": false, "startDirectly": false, "statusCanvas": false, diff --git a/project/functions.js b/project/functions.js index 9e06e527..b280be05 100644 --- a/project/functions.js +++ b/project/functions.js @@ -428,8 +428,12 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (this.hasSpecial(mon_special, 3) && mon_def < hero_atk - 1) { mon_def = hero_atk - 1; } - - // 光环效果 + + // V2.5.3备注: + // 这一部分是检查光环代码的,需要对整个地图上的图块进行遍历,可能会造成不必要的性能的损耗,尤其是循环计算临界会变得非常慢。 + // 因此默认注释掉此段代码以加快游戏运行速度。 + // 如果游戏中有光环怪物存在,取消注释(或按需根据floorId加判定)即可。 + /* // 检查当前楼层所有光环怪物(数字25) var hp_delta = 0, atk_delta = 0, def_delta = 0, cnt = 0; // 遍历每个图块 @@ -453,6 +457,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = mon_hp *= (1+hp_delta/100); mon_atk *= (1+atk_delta/100); mon_def *= (1+def_delta/100); + */ // TODO:可以在这里新增其他的怪物数据变化 // 比如仿攻(怪物攻击不低于勇士攻击): From 920b3c4045cd47ad3c652926edd86bb04c722cd2 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Sun, 16 Dec 2018 14:03:23 +0800 Subject: [PATCH 72/81] system flags --- docs/personalization.md | 51 ++++++++++++++++++----------------------- project/functions.js | 14 +++++++---- 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/docs/personalization.md b/docs/personalization.md index a3816fc6..22271bbe 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -855,38 +855,31 @@ if (core.flags.enableSkill) { 3. 在脚本编辑 - setInitData中加上`core.plugin.initHeros()`来初始化新勇士。(写在`core.events.afterLoadData()`后,反大括号之前。) 4. 如果需要切换角色(包括事件、道具或者快捷键等),可以直接调用自定义JS脚本:`core.plugin.changeHero();`进行切换。也可以指定参数调用`core.plugin.changeHero(1)`来切换到某个具体的勇士上。 -## 根据难度分歧来自定义地图 +## 系统使用的flag变量 -遗憾的是,所有地图数据必须在剧本的map中指定,换句话说,我们无法在游戏进行中动态修改地图,比如为简单难度增加一个血瓶。 +众所周知,自定义flag变量都可以任意定义并取用(未定义直接取用的flag默认值为0)。 -幸运的是,我们可以采用如下方式进行难度分歧,为用户简单难度下增加额外的血瓶或宝石。 +下面是一些可能会被系统设置或取用的flag变量: -``` js -"firstArrive": [ // 第一次到该楼层触发的事件 - {"type": "if", "condition": "flag:hard!=3", // 判断是否困难难度 - "true": [ // 不为困难,则为普通或简单难度 - {"type": "show", "loc": [3,6]} // 显示血瓶 - {"type": "if", "condition": "flag:hard==1", // 判断是否是简单难度 - "true": [ - {"type": "show", "loc": [3,7]} // 简单难度则显示宝石 - ], - "false": [] // 普通难度则只显示血瓶 - }, - ], - "false": [] // 困难难度,不进行任何操作 - }, -], -"events": { - "3,6": {"enable": false} // 比如[3,6]点是一个血瓶,初始不可见 - "3,7": {"enable": false} // 比如[3,7]点是一个宝石,初始不可见 -} -``` - -如上所示,我们在地图上设置一个额外的血瓶和宝石,并初始时设为禁用状态。 - -当第一次到达该楼层时,进行一次判断;如果不为困难难度,则将血瓶显示出来;再判断是否为简单难度,如果是则再把宝石显示出来。 - -通过对`flag:hard`进行判断的方式,我们也可以达成“对于不同的难度有着不同的地图效果”。 +- **`flag:hard`**: 当前的难度标志;此flag变量在setInitData中被定义,可以直接取用来判定当前难度分歧。上传成绩时将根据此flag来对不同难度进行排序。 +- **`flag:posion`**, **`flag:weak`**, **`flag:curse`**: 中毒、衰弱、诅咒状态。 +- **`flag:no_zone`**, **`flag:no_snipe`**, **`flag:no_laser`**, **`flag:no_betweenAttack`**: 是否分别免疫领域、阻击、激光、夹击效果。 +- **`flag:hatred`**: 当前的仇恨数值。 +- **`flag:commonTimes`**: 全局商店共用次数时的访问次数。 +- **`flag:input`**: 接受用户输入的事件后,存放用户输入的结果。 +- **`flag:type`**, **`flag:keycode`**, **`flag:x`**, **`flag:y`**: 等待用户操作后,用户的操作类型,按键keycode或点击坐标。 +- **`flag:skill`**, **`flag:skillName`**: 开启的技能编号和技能名。 +- **`flag:heroIcon`**: 当前的勇士行走图名称。 +- **`flag:saveEquips`**: 快速换装时保存的套装。 +- **`flag:__visited__`**: 当前访问过的楼层。 +- **`flag:equip_atk_buff`**, **`flag:equip_def_buff`**, **`flag:equip_mdef_buff`**: 当前攻防魔防的实际计算比例加成。 +- **`flag:forceSave`**: 是否允许事件中强制自动存档。如果将此项置为true并调用core.autosave()即可在事件中强制自动存档,读档时会自动执行该楼层的`eachArrive`事件。 +- **`flag:__color__`**, **`flag:__weather__`**, **`flag:__volume__`**: 当前的画面色调、天气和音量。 +- **`flag:textAttribute`**, **`flag:globalAttribute`**: 当前的剧情文本属性,当前的全局属性。 +- **`flag:cannotMoveDirectly`**, **`flag:clickMove`**: 当前是否不允许瞬间移动,当前用户是否开启了单击瞬移。 +- **`flag:hideStatusBar`**, **`flag:showToolbox`**: 是否隐藏状态栏,是否显示工具栏。 +- **`flag:debug`**, **`flag:consoleOpened`**: 当前是否开启了调试模式,是否开启了控制台。 +- **`flag:__seed__`**, **`flag:__rand__`**: 伪随机数生成种子和当前的状态 ========================================================================================== diff --git a/project/functions.js b/project/functions.js index bdc26d20..09ed1cdd 100644 --- a/project/functions.js +++ b/project/functions.js @@ -1028,6 +1028,11 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } core.updateStatusBar(); } + // 备注:瞬间移动不会执行该函数。如果要控制能否瞬间移动有三种方法: + // 1. 将全塔属性中的cannotMoveDirectly这个开关勾上,即可在全塔中全程禁止使用瞬移。 + // 2, 将楼层属性中的cannotMoveDirectly这个开关勾上,即禁止在该层楼使用瞬移。 + // 3. 将flag:cannotMoveDirectly置为true,即可使用flag控制在某段剧情范围内禁止瞬移。 + } }, "ui": { @@ -1201,21 +1206,20 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // core.plugin.drawLight([255,255,0,0.2], [[25,11,46,0.1]]); // 全图为不透明度0.2的黄色,其中在(25,11)点存在一个半径为46的灯光效果,灯光中心不透明度0.1。 // core.plugin.drawLight(0.9, [[25,11,46],[105,121,88],[301,221,106]]); // 存在三个灯光效果,分别是中心(25,11)半径46,中心(105,121)半径88,中心(301,221)半径106。 // core.plugin.drawLight([0,0,255,0.3], [[25,11,46],[105,121,88,0.2]], 0.4); // 存在两个灯光效果,它们在内圈40%范围内保持全亮,且40%后才开始衰减。 - // 【注意事项】 - // 此函数会和更改画面色调发生冲突,请只选择一个使用。 this.drawLight = function (color, lights, lightDec) { - // 清空色调层 + // 清空色调层;也可以修改成其它层比如animate层,或者用自己创建的canvas var ctx = core.canvas.curtain; ctx.mozImageSmoothingEnabled = false; ctx.webkitImageSmoothingEnabled = false; ctx.msImageSmoothingEnabled = false; ctx.imageSmoothingEnabled = false; - core.clearMap('curtain'); + ctx.clearRect(0, 0, 416, 416); // 绘制色调层,默认不透明度 if (!core.isset(color)) color = 0.9; if (typeof color == "number") color = [0,0,0,color]; - core.fillRect('curtain', 0, 0, 416, 416, core.arrayToRGBA(color)); + ctx.fillStyle = core.arrayToRGBA(color); + ctx.fillRect(0, 0, 416, 416); // 绘制每个灯光效果 if (!core.isset(lights) || lights.length==0) return; From ba0b499365a92bc893f99cba45e13c56d9ccad56 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 17 Dec 2018 00:00:17 +0800 Subject: [PATCH 73/81] shop times & checkLvUp & drawWaiting & achievements --- docs/event.md | 6 ++-- docs/personalization.md | 61 ++++++++++++++++++++++++++++++++++++++++- libs/actions.js | 6 ++-- libs/control.js | 8 ++++-- libs/core.js | 12 ++++---- libs/events.js | 43 +++++++++++++++++------------ libs/ui.js | 28 +++++++++++++++---- libs/utils.js | 6 ++-- 8 files changed, 129 insertions(+), 41 deletions(-) diff --git a/docs/event.md b/docs/event.md index 0ccdc36c..061b97e6 100644 --- a/docs/event.md +++ b/docs/event.md @@ -1869,8 +1869,8 @@ if (core.getFlag("door",0)==2) { {"text": "攻击+4", "effect": "status:atk+=4"}, {"text": "防御+4", "effect": "status:def+=4"}, {"text": "魔防+10", "effect": "status:mdef+=10"} - // effect只能对status和item进行操作,不能修改flag值。 - // 必须是X+=Y的形式,其中Y可以是一个表达式,以status:xxx或item:xxx为参数 + // effect可以对status,item和flag进行操作。 + // 必须是X+=Y的形式,其中Y可以是一个表达式,以status:xxx, item:xxx或flag:xxx为参数 // 其他effect样例: // "item:yellowKey+=1" 黄钥匙+1 // "item:pickaxe+=3" 破墙镐+3 @@ -1912,7 +1912,7 @@ if (core.getFlag("door",0)==2) { - text 为商店所说的话。可以用${need}表示需要的数值。 - choices 为商店的各个选项,是一个list,每一项是一个选项 - text为显示文字。请注意这里不支持 ${} 的表达式计算。 - - effect 为该选项的效果;effect只能对status或items进行操作,且必须是 `status:xxx+=yyy` 或 `item:xxx+=yyy`的形式。即中间必须是+=符号。 + - effect 为该选项的效果;effect必须是 `status:xxx+=yyy`, `item:xxx+=yyy`或`flag:xxx+=yyy`的形式。即中间必须是+=符号。 - 如有多个effect(例如升级全属性提升),使用分号分开,参见经验商店的写法。 像这样定义了全局商店后,即可在快捷栏中看到。 diff --git a/docs/personalization.md b/docs/personalization.md index 22271bbe..f88c49a2 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -779,6 +779,65 @@ if (core.flags.enableSkill) { 通过上述这几种方式,我们就能成功的让H5支持技能啦! +## 成就系统 + +我们还可以给HTML5魔塔增加成就系统。注意到成就是和游戏相关,因此需要使用getLocalStorage而不是getFlag判定。 + +可将下面的代码粘贴到脚本编辑 - 插件编写中。 + +``` js +// 所有成就项的定义 +this.achievements = [ + // 每行一个,分别定义flag、名称、描述、是否存在提示、成就点数 + {"flag": "a1", "name": "成就1", "text": "成就1的达成描述", "hint": false, "point": 1}, + // 可以继续往后新增其他的。 +]; + +// 达成成就;如 core.plugin.achieve("a1") 即达成a1对应的成就 +this.achieve = function (flag) { + // 获得已达成的成就;如果跟存档而不是跟游戏则改成getFlag + var achieved = core.getLocalStorage("achievements", []); + var point = core.getLocalStorage("achievePoint", 0); + // 已经获得该成就 + if (achieved.indexOf(flag)>=0) return; + // 尝试达成成就;找到对应的成就项 + this.achievements.forEach(function (one) { + if (one.flag == flag) { + // 执行达成成就的操作;也可以自行在上面加上达成成就后的事件 + core.insertAction("\t[达成成就:"+one.name+"]"+one.text); + point += one.point || 0; + } + }); + achieved.push(flag); + // 存入localStorage中;如果跟存档走则使用setFlag + core.setLocalStorage("achievements", achieved); + core.setLocalStorage("achievePoint", point); +} + +// 获得所有成就说明;这里简单使用两个insertAction,你也可以修改成自己的实现 +// 简单一点的可以使用insertAction+剧情文本;稍微复杂一点的可以使用图片化文本等;更复杂的可以自绘UI。 +this.getAchievements = function () { + var achieved = core.getLocalStorage("achievements", []); + var yes = [], no = []; + // 对所有成就进行遍历 + this.achievements.forEach(function (one) { + // 检测是否达成 + if (achieved.indexOf(one.flag)>=0) { + yes.push(one.name+":"+one.text); + } + else { + no.push(one.name+":"+(one.hint?one.text:"达成条件请自行探索")); + } + }); + core.insertAction([ + "\t[已达成的成就]"+(yes.length==0?"暂无":yes.join("\n")), + "\t[尚未达成的成就]"+(no.length==0?"暂无":no.join("\n")) + ]); +} +``` + + + ## 多角色的支持 其实,我们的样板还能支持多角色的制作。比如《黑·白·间》之类的塔也是完全可以刻的。 @@ -787,7 +846,7 @@ if (core.flags.enableSkill) { 1. 每个角色弄一张行走图。相关信息参见[自定义事件:setHeroIcon](event#setHeroIcon:更改角色行走图)。 2. [覆盖楼传事件](#覆盖楼传事件),这样可以通过点工具栏的楼层传送按钮来切换角色。当然你也完全可以自己写一个道具,或[自定义快捷键](#自定义快捷键)来进行绑定。 -3. 将下述代码直接贴入脚本编辑 - 插件编写中。(写在`var _useEquipment = ...`之前。) +3. 将下述代码直接贴入脚本编辑 - 插件编写中。 ``` js // 所有需要保存的内容;这些保存的内容不会多角色共用,在切换时会进行恢复。 // 你也可以自行新增或删除,比如不共用金币则可以加上"money"的初始化,不共用道具则可以加上"items"的初始化, diff --git a/libs/actions.js b/libs/actions.js index d50443b8..f41f52dc 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1080,13 +1080,13 @@ actions.prototype.clickShop = function(x,y) { core.status.event.selection=y-topIndex; var money = core.getStatus('money'), experience = core.getStatus('experience'); - var times = shop.times, need = eval(shop.need); + var times = shop.times, need = core.calValue(shop.need, null, times); var use = shop.use; var use_text = use=='money'?"金币":"经验"; var choice = choices[y-topIndex]; if (core.isset(choice.need)) - need = eval(choice.need); + need = core.calValue(choice.need, null, times); if (need > eval(use)) { core.drawTip("你的"+use_text+"不足"); @@ -1101,7 +1101,7 @@ actions.prototype.clickShop = function(x,y) { // 更新属性 choice.effect.split(";").forEach(function (t) { - core.doEffect(t); + core.doEffect(t, need, times); }); core.updateStatusBar(); shop.times++; diff --git a/libs/control.js b/libs/control.js index 3d8f41f2..25bcd17b 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1639,11 +1639,11 @@ control.prototype.updateDamage = function (floorId, canvas) { } ////// 执行一个表达式的effect操作 ////// -control.prototype.doEffect = function (effect) { +control.prototype.doEffect = function (effect, need, times) { effect.split(";").forEach(function (expression) { var arr = expression.split("+="); if (arr.length!=2) return; - var name=arr[0], value=core.calValue(arr[1]); + var name=arr[0], value=core.calValue(arr[1], need, times); if (name.indexOf("status:")==0) { var status=name.substring(7); core.setStatus(status, core.getStatus(status)+value); @@ -1652,6 +1652,10 @@ control.prototype.doEffect = function (effect) { var itemId=name.substring(5); core.setItem(itemId, core.itemCount(itemId)+value); } + else if (name.indexOf("flag:")==0) { + var flag=name.substring(5); + core.setFlag(flag, core.getFlag(flag, 0)+value); + } }); } diff --git a/libs/core.js b/libs/core.js index 76dc3052..5c9871d1 100644 --- a/libs/core.js +++ b/libs/core.js @@ -999,18 +999,18 @@ core.prototype.drawText = function (contents, callback) { /////////// 系统机制 /////////// ////// 将文字中的${和}(表达式)进行替换 ////// -core.prototype.replaceText = function (text) { - return core.utils.replaceText(text); +core.prototype.replaceText = function (text, need, times) { + return core.utils.replaceText(text, need, times); } ////// 计算表达式的值 ////// -core.prototype.calValue = function (value) { - return core.utils.calValue(value); +core.prototype.calValue = function (value, need, times) { + return core.utils.calValue(value, need, times); } ////// 执行一个表达式的effect操作 ////// -core.prototype.doEffect = function (expression) { - core.control.doEffect(expression); +core.prototype.doEffect = function (expression, need, times) { + core.control.doEffect(expression, need, times); } ////// 字符串自动换行的分割 ////// diff --git a/libs/events.js b/libs/events.js index 6ca2dfdd..518a5c25 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1849,20 +1849,18 @@ events.prototype.openShop = function(shopId, needVisited) { // 拼词 var content = "\t["+shop.name+","+shop.icon+"]"; - var times = shop.times, need=eval(shop.need); + var times = shop.times, need=core.calValue(shop.need, null, times); - content = content + shop.text.replace(/\${([^}]+)}/g, function (word, value) { - return eval(value); - }); + content += core.replaceText(shop.text, need, times); var use = shop.use=='experience'?'经验':'金币'; var choices = []; for (var i=0;i=core.firstData.levelUp.length) return; - // 计算下一个所需要的数值 - var next = (core.firstData.levelUp[core.status.hero.lv]||{}); - var need = core.calValue(next.need); - if (!core.isset(need)) return; - if (core.status.hero.experience>=need) { - // 升级 - core.status.hero.lv++; - if (next.clear) core.status.hero.experience -= need; - core.insertAction(next.action); - this.checkLvUp(); + var check = function () { + if (!core.flags.enableLevelUp || !core.isset(core.firstData.levelUp) + || core.status.hero.lv>=core.firstData.levelUp.length) return null; + // 计算下一个所需要的数值 + var next = (core.firstData.levelUp[core.status.hero.lv]||{}); + var need = core.calValue(next.need); + if (!core.isset(need)) return null; + if (core.status.hero.experience>=need) { + // 升级 + core.status.hero.lv++; + if (next.clear) core.status.hero.experience -= need; + return next.action||[]; + } + return null; } + var actions = []; + while (true) { + var next = check(); + if (next == null) break; + actions = actions.concat(next); + } + if (actions.length>0) core.insertAction(actions); } ////// 尝试使用道具 ////// diff --git a/libs/ui.js b/libs/ui.js index e747cb6d..dc030742 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1371,20 +1371,38 @@ ui.prototype.drawWaiting = function(text) { core.status.event.id = 'waiting'; core.clearLastEvent(); - core.setFillStyle('ui', core.material.groundPattern); + + var background = core.status.textAttribute.background; + var isWindowSkin = false; + if (typeof background == 'string') { + background = core.material.images.images[background]; + if (core.isset(background) && background.width==192 && background.height==128) isWindowSkin = true; + else background = core.initStatus.textAttribute.background; + } + if (!isWindowSkin) background = core.arrayToRGBA(background); + var borderColor = core.status.globalAttribute.borderColor; + var textColor = core.arrayToRGBA(core.status.textAttribute.text); var globalFont = core.status.globalAttribute.font; - core.setFont('ui', 'bold 17px '+globalFont); + core.setFont('ui', "bold 19px "+globalFont); var text_length = core.canvas.ui.measureText(text).width; var right = Math.max(text_length+50, 220); var left = 208-parseInt(right/2), top = 208 - 32 - 16, bottom = 416 - 2 * top; - core.fillRect('ui', left, top, right, bottom); - core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, '#FFFFFF', 2); + core.clearMap('ui'); + if (isWindowSkin) { + core.setAlpha('ui', 0.85); + this.drawWindowSkin(background,'ui',left,top,right,bottom); + } + else { + core.fillRect('ui', left, top, right, bottom, background); + core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, borderColor, 2); + } + core.setAlpha('ui', 1); core.canvas.ui.textAlign = "center"; - core.fillText('ui', text, 208, top + 56, '#FFFFFF'); + core.fillText('ui', text, 208, top + 56, textColor); } diff --git a/libs/utils.js b/libs/utils.js index 8cb58dce..5a356344 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -39,14 +39,14 @@ utils.prototype.init = function () { } ////// 将文字中的${和}(表达式)进行替换 ////// -utils.prototype.replaceText = function (text) { +utils.prototype.replaceText = function (text, need, times) { return text.replace(/\${(.*?)}/g, function (word, value) { - return core.calValue(value); + return core.calValue(value, need, times); }); } ////// 计算表达式的值 ////// -utils.prototype.calValue = function (value) { +utils.prototype.calValue = function (value, need, times) { if (!core.isset(value)) return value; if (typeof value == 'number') { return value; From 82490f352be392b93ca0e1fe52131ddfcae59adb Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 17 Dec 2018 00:31:43 +0800 Subject: [PATCH 74/81] Cache bgms --- _server/blockly/MotaAction.g4 | 36 ++++++++++++++++++++++++++++++ _server/editor_blockly.js | 2 ++ docs/element.md | 8 +++++++ docs/event.md | 14 ++++++++++++ libs/control.js | 2 ++ libs/core.js | 12 ++++++++++ libs/events.js | 8 +++++++ libs/loader.js | 42 ++++++++++++++++++++++++++++++----- 8 files changed, 118 insertions(+), 6 deletions(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 3fb29c71..c99e1695 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -278,6 +278,8 @@ action | playBgm_s | pauseBgm_s | resumeBgm_s + | loadBgm_s + | freeBgm_s | playSound_s | setVolume_s | win_s @@ -1282,6 +1284,32 @@ var code = '{"type": "resumeBgm"},\n'; return code; */; +loadBgm_s + : '预加载背景音乐' EvalString Newline + + +/* loadBgm_s +tooltip : loadBgm: 预加载某个背景音乐,之后可以直接播放 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=playbgm%EF%BC%9A%E6%92%AD%E6%94%BE%E8%83%8C%E6%99%AF%E9%9F%B3%E4%B9%90 +default : ["bgm.mp3"] +colour : this.soundColor +var code = '{"type": "loadBgm", "name": "'+EvalString_0+'"},\n'; +return code; +*/; + +freeBgm_s + : '释放背景音乐的缓存' EvalString Newline + + +/* freeBgm_s +tooltip : freeBgm: 释放背景音乐的缓存 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=playbgm%EF%BC%9A%E6%92%AD%E6%94%BE%E8%83%8C%E6%99%AF%E9%9F%B3%E4%B9%90 +default : ["bgm.mp3"] +colour : this.soundColor +var code = '{"type": "freeBgm", "name": "'+EvalString_0+'"},\n'; +return code; +*/; + playSound_s : '播放音效' EvalString Newline @@ -2157,6 +2185,14 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['resumeBgm_s'].xmlText([ this.next]); break + case "loadBgm": + this.next = MotaActionBlocks['loadBgm_s'].xmlText([ + data.name,this.next]); + break + case "freeBgm": + this.next = MotaActionBlocks['freeBgm_s'].xmlText([ + data.name,this.next]); + break case "setVolume": this.next = MotaActionBlocks['setVolume_s'].xmlText([ data.value, data.time||0, data.async||false, this.next]); diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 15c48840..34e90829 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -144,6 +144,8 @@ editor_blockly = function () { MotaActionBlocks['playBgm_s'].xmlText(), MotaActionBlocks['pauseBgm_s'].xmlText(), MotaActionBlocks['resumeBgm_s'].xmlText(), + MotaActionBlocks['loadBgm_s'].xmlText(), + MotaActionBlocks['freeBgm_s'].xmlText(), MotaActionBlocks['playSound_s'].xmlText(), MotaActionBlocks['setVolume_s'].xmlText(), ], diff --git a/docs/element.md b/docs/element.md index 807cacf4..ebec42ad 100644 --- a/docs/element.md +++ b/docs/element.md @@ -402,6 +402,14 @@ floorId指定的是目标楼层的唯一标识符(ID)。 !> iOS平台以及部分浏览器不支持获得当前网络状态,此时即使在使用Wifi也必须要用户点击“音乐开关”才能播放音乐。 +从V2.5.3开始,可以使用`loadBgm`事件来预加载一个bgm,这样到播放时无需等待,直接播放。 + +同时BGM将使用LRU算法增加缓存机制。默认最多缓存4个BGM(在core.js的musicStatus.cachedBgmCount控制)。 + +系统会自动释放最久未使用的BGM。 + +也可以使用`freeBgm`事件来手动释放一个无需再用的bgm。 + ## 录像 HTML5魔塔一大亮点就是存在录像系统,可以很方便进行录像回放。 diff --git a/docs/event.md b/docs/event.md index 061b97e6..a16a6737 100644 --- a/docs/event.md +++ b/docs/event.md @@ -1217,6 +1217,20 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 使用`{"type": "resumeBgm"}`可以恢复背景音乐的播放。 +### loadBgm:预加载一个背景音乐 + +使用loadBgm可以预加载一个背景音乐。 + +使用方法:`{"type": "loadBgm", "name": "bgm.mp3"}` + +有关BGM播放的详细说明参见[背景音乐](element#背景音乐) + +### freeBgm:释放一个背景音乐的缓存 + +使用freeBgm可以预加载一个背景音乐。 + +使用方法:`{"type": "freeBgm", "name": "bgm.mp3"}` + ### playSound:播放音效 使用playSound可以立刻播放一个音效。 diff --git a/libs/control.js b/libs/control.js index 25bcd17b..f82a8112 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2606,6 +2606,8 @@ control.prototype.playBgm = function (bgm) { } try { + // 缓存BGM + core.loader.loadBgm(bgm); // 如果当前正在播放,且和本BGM相同,直接忽略 if (core.musicStatus.playingBgm == bgm && core.musicStatus.isPlaying) { return; diff --git a/libs/core.js b/libs/core.js index 5c9871d1..86cc2836 100644 --- a/libs/core.js +++ b/libs/core.js @@ -58,6 +58,8 @@ function core() { 'isPlaying': false, 'gainNode': null, 'volume': 1.0, // 音量 + 'cachedBgms': [], // 缓存BGM内容 + 'cachedBgmCount': 4, // 缓存的bgm数量 } this.platform = { 'isOnline': true, // 是否http @@ -1405,6 +1407,16 @@ core.prototype.resumeBgm = function () { core.control.resumeBgm(); } +////// 预加载一个背景音乐 ////// +core.prototype.loadBgm = function (bgm) { + core.loader.loadBgm(bgm); +} + +////// 手动释放一个背景音乐的缓存 ////// +core.prototype.freeBgm = function (bgm) { + core.loader.freeBgm(bgm); +} + ////// 播放音频 ////// core.prototype.playSound = function (sound) { core.control.playSound(sound); diff --git a/libs/events.js b/libs/events.js index 518a5c25..e15818d0 100644 --- a/libs/events.js +++ b/libs/events.js @@ -901,6 +901,14 @@ events.prototype.doAction = function() { core.resumeBgm(); this.doAction(); break + case "loadBgm": + core.loadBgm(data.name); + this.doAction(); + break; + case "freeBgm": + core.freeBgm(data.name); + this.doAction(); + break; case "setVolume": data.value = core.clamp(parseInt(data.value)/100, 0, 1); core.setFlag("__volume__", data.value); diff --git a/libs/loader.js b/libs/loader.js index ff24e929..03b97e4b 100644 --- a/libs/loader.js +++ b/libs/loader.js @@ -208,12 +208,7 @@ loader.prototype.loadMusic = function () { } } else { - var music = new Audio(); - music.preload = 'none'; - if (main.bgmRemote) music.src = main.bgmRemoteRoot+core.firstData.name+'/'+t; - else music.src = 'project/sounds/'+t; - music.loop = 'loop'; - core.material.bgms[t] = music; + core.loader.loadOneMusic(t); } }); @@ -251,3 +246,38 @@ loader.prototype.loadMusic = function () { if (core.musicStatus.startDirectly && core.bgms.length>0) core.playBgm(core.bgms[0]); } + +loader.prototype.loadOneMusic = function (name) { + var music = new Audio(); + music.preload = 'none'; + if (main.bgmRemote) music.src = main.bgmRemoteRoot+core.firstData.name+'/'+t; + else music.src = 'project/sounds/'+name; + music.loop = 'loop'; + core.material.bgms[name] = music; +} + +loader.prototype.freeBgm = function (name) { + if (!core.isset(core.material.bgms[name])) return; + // 从cachedBgms中删除 + core.musicStatus.cachedBgms = core.musicStatus.cachedBgms.filter(function (t) {return t!=name; }); + // 清掉缓存 + core.material.bgms[name].removeAttribute("src"); + core.material.bgms[name].load(); + core.material.bgms[name] = null; + // 三秒后重新加载 + setTimeout(function () { + core.loader.loadOneMusic(name); + }, 3000); +} + +loader.prototype.loadBgm = function (name) { + if (!core.isset(core.material.bgms[name])) return; + // 预加载BGM + core.material.bgms[name].load(); + // 移动到缓存最前方 + core.musicStatus.cachedBgms = core.musicStatus.cachedBgms.filter(function (t) {return t!=name; }); + core.musicStatus.cachedBgms.unshift(name); + if (core.musicStatus.cachedBgms.length > core.musicStatus.cachedBgmCount) { + this.freeBgm(core.musicStatus.cachedBgms.pop()); + } +} \ No newline at end of file From f9133aff92a64ad990aa4880029837808dd58977 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 17 Dec 2018 00:40:26 +0800 Subject: [PATCH 75/81] Cache bgms --- libs/loader.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/libs/loader.js b/libs/loader.js index 03b97e4b..a513ecae 100644 --- a/libs/loader.js +++ b/libs/loader.js @@ -272,12 +272,19 @@ loader.prototype.freeBgm = function (name) { loader.prototype.loadBgm = function (name) { if (!core.isset(core.material.bgms[name])) return; - // 预加载BGM - core.material.bgms[name].load(); - // 移动到缓存最前方 - core.musicStatus.cachedBgms = core.musicStatus.cachedBgms.filter(function (t) {return t!=name; }); - core.musicStatus.cachedBgms.unshift(name); - if (core.musicStatus.cachedBgms.length > core.musicStatus.cachedBgmCount) { - this.freeBgm(core.musicStatus.cachedBgms.pop()); + // 是否已经预加载过 + var index = core.musicStatus.cachedBgms.indexOf(name); + if (index>=0) { + core.musicStatus.cachedBgms.splice(index, 1); } + else { + // 预加载BGM + core.material.bgms[name].load(); + // 清理尾巴 + if (core.musicStatus.cachedBgms.length == core.musicStatus.cachedBgmCount) { + this.freeBgm(core.musicStatus.cachedBgms.pop()); + } + } + // 移动到缓存最前方 + core.musicStatus.cachedBgms.unshift(name); } \ No newline at end of file From fd08290b73c129216925207fda2227746c67a3c1 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 17 Dec 2018 10:31:04 +0800 Subject: [PATCH 76/81] Fix bugs --- libs/control.js | 10 +++++++++- libs/core.js | 2 +- libs/loader.js | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/libs/control.js b/libs/control.js index f82a8112..88bba56a 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2782,11 +2782,19 @@ control.prototype.updateStatusBar = function () { control.prototype.triggerStatusBar = function (name, showToolbox) { if (name!='hide') name='show'; + + // 如果是隐藏 -> 显示工具栏,则先显示 + if (name == 'hide' && showToolbox && !core.domStyle.showStatusBar && !core.hasFlag("showToolbox")) { + this.triggerStatusBar("show"); + this.triggerStatusBar("hide", showToolbox); + return; + } + var statusItems = core.dom.status; var toolItems = core.dom.tools; core.domStyle.showStatusBar = name == 'show'; core.setFlag('hideStatusBar', core.domStyle.showStatusBar?null:true); - core.setFlag('showToolbox', showToolbox); + core.setFlag('showToolbox', showToolbox?true:null); if (!core.domStyle.showStatusBar) { for (var i = 0; i < statusItems.length; ++i) statusItems[i].style.opacity = 0; diff --git a/libs/core.js b/libs/core.js index 86cc2836..344806d2 100644 --- a/libs/core.js +++ b/libs/core.js @@ -322,7 +322,7 @@ core.prototype.init = function (coreData, callback) { core.musicStatus.bgmStatus = core.getLocalStorage('bgmStatus', true); if (!core.musicStatus.startDirectly) // 如果当前网络环境不允许 core.musicStatus.bgmStatus = false; - core.setLocalStorage('bgmStatus', core.musicStatus.bgmStatus); + // core.setLocalStorage('bgmStatus', core.musicStatus.bgmStatus); core.musicStatus.soundStatus = core.getLocalStorage('soundStatus', true); core.setLocalStorage('soundStatus', core.musicStatus.soundStatus); diff --git a/libs/loader.js b/libs/loader.js index a513ecae..d5185100 100644 --- a/libs/loader.js +++ b/libs/loader.js @@ -250,7 +250,7 @@ loader.prototype.loadMusic = function () { loader.prototype.loadOneMusic = function (name) { var music = new Audio(); music.preload = 'none'; - if (main.bgmRemote) music.src = main.bgmRemoteRoot+core.firstData.name+'/'+t; + if (main.bgmRemote) music.src = main.bgmRemoteRoot+core.firstData.name+'/'+name; else music.src = 'project/sounds/'+name; music.loop = 'loop'; core.material.bgms[name] = music; From f26bc14bf16ea40ed4e667797bf934abec110c8c Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Mon, 17 Dec 2018 14:38:34 +0800 Subject: [PATCH 77/81] Dynamic canvas --- _server/blockly/MotaAction.g4 | 4 +- editor-mobile.html | 1 - editor.html | 1 - index.html | 1 - libs/control.js | 109 +---------- libs/core.js | 4 + libs/events.js | 21 ++- libs/maps.js | 338 ++++++++++++++++------------------ libs/ui.js | 19 +- main.js | 1 - styles.css | 4 - 11 files changed, 199 insertions(+), 304 deletions(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index c99e1695..b72170e4 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -1290,7 +1290,7 @@ loadBgm_s /* loadBgm_s tooltip : loadBgm: 预加载某个背景音乐,之后可以直接播放 -helpUrl : https://h5mota.com/games/template/docs/#/event?id=playbgm%EF%BC%9A%E6%92%AD%E6%94%BE%E8%83%8C%E6%99%AF%E9%9F%B3%E4%B9%90 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=loadBgm%ef%bc%9a%e9%a2%84%e5%8a%a0%e8%bd%bd%e4%b8%80%e4%b8%aa%e8%83%8c%e6%99%af%e9%9f%b3%e4%b9%90 default : ["bgm.mp3"] colour : this.soundColor var code = '{"type": "loadBgm", "name": "'+EvalString_0+'"},\n'; @@ -1303,7 +1303,7 @@ freeBgm_s /* freeBgm_s tooltip : freeBgm: 释放背景音乐的缓存 -helpUrl : https://h5mota.com/games/template/docs/#/event?id=playbgm%EF%BC%9A%E6%92%AD%E6%94%BE%E8%83%8C%E6%99%AF%E9%9F%B3%E4%B9%90 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=freeBgm%ef%bc%9a%e9%87%8a%e6%94%be%e4%b8%80%e4%b8%aa%e8%83%8c%e6%99%af%e9%9f%b3%e4%b9%90%e7%9a%84%e7%bc%93%e5%ad%98 default : ["bgm.mp3"] colour : this.soundColor var code = '{"type": "freeBgm", "name": "'+EvalString_0+'"},\n'; diff --git a/editor-mobile.html b/editor-mobile.html index 41818ed2..1026c9dc 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -445,7 +445,6 @@ 此浏览器不支持HTML5 -
diff --git a/editor.html b/editor.html index 0838ffcb..7f865e9b 100644 --- a/editor.html +++ b/editor.html @@ -430,7 +430,6 @@ 此浏览器不支持HTML5 -
diff --git a/index.html b/index.html index c31e434a..028c5a6a 100644 --- a/index.html +++ b/index.html @@ -145,7 +145,6 @@ 此浏览器不支持HTML5 -
diff --git a/libs/control.js b/libs/control.js index 88bba56a..8f94e572 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1340,108 +1340,13 @@ control.prototype.checkBlock = function () { ////// 阻击事件(动画效果) ////// control.prototype.snipe = function (snipes) { - - var scan = { - 'up': {'x': 0, 'y': -1}, - 'left': {'x': -1, 'y': 0}, - 'down': {'x': 0, 'y': 1}, - 'right': {'x': 1, 'y': 0} - }; - - snipes.forEach(function (snipe) { - var x=snipe.x, y=snipe.y, direction = snipe.direction; - snipe.nx = x+scan[snipe.direction].x; - snipe.ny = y+scan[snipe.direction].y; - - core.removeGlobalAnimate(x, y); - - var block = core.getBlock(x,y).block; - - var cls = block.event.cls; - var height = block.event.height || 32; - - snipe.animate = block.event.animate || 1; - snipe.blockIcon = core.material.icons[cls][block.event.id]; - snipe.blockImage = core.material.images[cls]; - snipe.height = height; - - var damageString = core.enemys.getDamageString(block.event.id, x, y); - var damage = damageString.damage, color = damageString.color; - - snipe.damage = damage; - snipe.color = color; - snipe.block = core.clone(block); - - }) - - var finishSnipe = function () { - snipes.forEach(function (t) { - core.removeBlock(t.x, t.y); - var nBlock = core.clone(t.block); - nBlock.x = t.nx; nBlock.y = t.ny; - core.status.thisMap.blocks.push(nBlock); - core.drawBlock(nBlock); - core.addGlobalAnimate(nBlock); - }); - core.syncGlobalAnimate(); - core.updateStatusBar(); - return; - } - - if (core.status.replay.replaying) { - finishSnipe(); - } - else { - core.waitHeroToStop(function() { - - core.lockControl(); - - var time = 500, step = 0; - - var animateCurrent = 0; - var animateTime = 0; - - core.canvas.damage.textAlign = 'left'; - - var animate=window.setInterval(function() { - - step++; - animateTime += time / 16; - if (animateTime >= core.values.animateSpeed) { - animateCurrent++; - animateTime = 0; - } - - snipes.forEach(function (snipe) { - var x=snipe.x, y=snipe.y, direction = snipe.direction; - - var dx = scan[direction].x*2*step, dy = scan[direction].y*2*step; - var nowX = 32*x+dx, nowY = 32*y+dy; - - // 清空上一次 - core.clearMap('damage', nowX-2*scan[direction].x, nowY-2*scan[direction].y, 32, 32); - core.canvas.event.clearRect(nowX-2*scan[direction].x, nowY-2*scan[direction].y, 32, 32); - core.canvas.event2.clearRect(nowX-2*scan[direction].x, nowY-2*scan[direction].y-32, 32, 32) - - core.drawBlock(snipe.block, animateCurrent, dx, dy); - - if (core.hasItem('book')) { - // drawDamage - core.fillBoldText(core.canvas.damage, snipe.damage, snipe.color, nowX+1, nowY+31); - } - - }) - - if (step==16) { // 移动完毕 - clearInterval(animate); - finishSnipe(); - // 不存在自定义事件 - if (core.status.event.id==null) - core.unLockControl(); - } - }, time/16); - }); - } + // 阻击改成moveBlock事件完成 + var actions = []; + snipes.forEach(function (t) { + actions.push({"type": "move", "loc": [t.x, t.y], "steps": [t.direction], "time": 500, "keep": true, "async": true}); + }); + actions.push({"type": "waitAsync"}); + core.insertAction(actions); } ////// 更改天气效果 ////// diff --git a/libs/core.js b/libs/core.js index 344806d2..e27c657e 100644 --- a/libs/core.js +++ b/libs/core.js @@ -720,6 +720,10 @@ core.prototype.deleteCanvas = function (name) { core.ui.deleteCanvas(name); } +core.prototype.deleteAllCanvas = function () { + core.ui.deleteAllCanvas(); +} + core.prototype.drawBlock = function (block, animate, dx, dy) { core.maps.drawBlock(block, animate, dx, dy); } diff --git a/libs/events.js b/libs/events.js index e15818d0..edca31c1 100644 --- a/libs/events.js +++ b/libs/events.js @@ -9,7 +9,11 @@ events.prototype.init = function () { this.eventdata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.events; this.events = { 'battle': function (data, core, callback) { - //core.autosave(true); + // 正在执行自定义事件:不允许战斗 + if (core.status.event.id == 'action') { + if (core.isset(callback)) callback(); + return; + } core.battle(data.event.id, data.x, data.y); if (core.isset(callback)) callback(); @@ -20,13 +24,22 @@ events.prototype.init = function () { callback(); }, 'openDoor': function (data, core, callback) { - //core.autosave(true); + // 正在执行自定义事件:不允许开门 + if (core.status.event.id == 'action') { + if (core.isset(callback)) callback(); + return; + } core.openDoor(data.event.id, data.x, data.y, true, function () { if (core.isset(callback)) callback(); core.replay(); }); }, 'changeFloor': function (data, core, callback) { + // 正在执行自定义事件:不允许切换楼层 + if (core.status.event.id == 'action') { + if (core.isset(callback)) callback(); + return; + } var heroLoc = {}; if (core.isset(data.event.data.loc)) heroLoc = {'x': data.event.data.loc[0], 'y': data.event.data.loc[1]}; @@ -1691,13 +1704,11 @@ events.prototype.moveImage = function (code, to, opacityVal, time, callback) { var step = 0; var per_time = 10, steps = parseInt(time / per_time); - var preOpac = parseFloat(core.dymCanvas[name].canvas.style.opacity), opacStep; + var preOpac = parseFloat(core.dymCanvas[name].canvas.style.opacity), opacStep = 0; if (core.isset(opacityVal)) { opacityVal = core.calValue(opacityVal); opacStep = (opacityVal - preOpac) / steps; } - else - opacStep = 0; var moveStep = function () { preOpac += opacStep; diff --git a/libs/maps.js b/libs/maps.js index dfdba1f9..dc360888 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -370,29 +370,13 @@ maps.prototype.drawBlock = function (block, animate, dx, dy) { // none:空地 if (block.event.id=='none') return; - var cls = block.event.cls, height = block.event.height || 32; + var cls = block.event.cls; - var image, x, y; + var blockInfo = this.__getBlockInfo(block); + if (blockInfo == null) return; + var image = blockInfo.image, x = blockInfo.bx, y = blockInfo.by, height = blockInfo.height; + if (!blockInfo.isTileset) x = (animate||0)%(block.event.animate||1); - if (cls == 'tileset') { - var offset = core.icons.getTilesetOffset(block.event.id); - if (offset == null) return; - image = core.material.images.tilesets[offset.image]; - x = offset.x; - y = offset.y; - } - else if (cls == 'autotile') return; - // 空气墙的单独处理 - else if (block.id==17) { - if (!core.isset(core.material.images.airwall)) return; - image = core.material.images.airwall; - x = y = 0; - } - else { - image = core.material.images[cls]; - x = (animate||0)%(block.event.animate||1); - y = core.material.icons[cls][block.event.id]; - } dx = dx || 0; dy = dy || 0; @@ -776,6 +760,93 @@ maps.prototype.getBlockCls = function (x, y, floorId, showDisable) { return null; } +maps.prototype.__getBlockInfo = function (block) { + var image, bx, by, height = block.event.height || 32; + var faceIds = {}, isTileset = false; + if (block.event.cls == 'tileset') { + var offset = core.icons.getTilesetOffset(block.event.id); + if (offset==null) { + return null; + } + bx = offset.x; + by = offset.y; + image = core.material.images.tilesets[offset.image]; + isTileset = true; + } + // 不支持autotile + else if (block.event.cls == 'autotile') { + return null; + } + // 空气墙;忽略事件 + else if (block.id==17) { + if (!core.isset(core.material.images.airwall)) return null; + image = core.material.images.airwall; + bx = by = 0; + } + else { + image = core.material.images[block.event.cls]; + bx = 0; + by = core.material.icons[block.event.cls][block.event.id]; + faceIds = block.event.faceIds||{}; + } + return { + "image": image, + "bx": bx, + "by": by, + "height": height, + "isTileset": isTileset, + "faceIds": faceIds + }; +} + +maps.prototype.__moveBlockCanvas = function (image, bx, by, height, nowX, nowY, opacity, headCanvas, bodyCanvas, damageCanvas) { + // 重绘block & 重定位 + if (headCanvas != null) { + core.dymCanvas[headCanvas].clearRect(0, 0, 32, height); + core.dymCanvas[headCanvas].drawImage(image, bx * 32, by * height, 32, height - 32, 0, 0, 32, height - 32); + core.relocateCanvas(headCanvas, nowX - core.bigmap.offsetX, nowY+32-height - core.bigmap.offsetY); + core.setOpacity(headCanvas, opacity); + } + if (bodyCanvas != null) { + core.dymCanvas[bodyCanvas].clearRect(0, 0, 32, 32); + core.dymCanvas[bodyCanvas].drawImage(image, bx * 32, by * height + height - 32, 32, 32, 0, 0, 32, 32); + core.relocateCanvas(bodyCanvas, nowX - core.bigmap.offsetX, nowY - core.bigmap.offsetY); + core.setOpacity(bodyCanvas, opacity); + } + if (damageCanvas != null) { + core.relocateCanvas(damageCanvas, nowX - core.bigmap.offsetX, nowY - core.bigmap.offsetY); + core.setOpacity(damageCanvas, opacity); + } +} + +maps.prototype.__initBlockCanvas = function (block, height, x, y) { + var headCanvas = null, bodyCanvas = 'block'+x+"_"+y, damageCanvas = null; + + core.createCanvas(bodyCanvas, 0, 0, 32, 32, 35); + if (height > 32) { + headCanvas = "blockHead"+x+"_"+y; + core.createCanvas(headCanvas, 0, 0, 32, height - 32, 55); + } + // 显伤 + var damage = null, damageColor = null; + if ((block.event.cls == 'enemys' || block.event.cls == 'enemy48') && core.hasItem('book') + && block.event.displayDamage !== false) { + var damageString = core.enemys.getDamageString(block.event.id, x, y); + damage = damageString.damage; damageColor = damageString.color; + } + if (damage != null) { + damageCanvas = "blockDamage"+x+"_"+y; + core.createCanvas(damageCanvas, 0, 0, 32, 32, 65); + core.dymCanvas[damageCanvas].textAlign = 'left'; + core.fillBoldText(core.dymCanvas[damageCanvas], damage, damageColor, 1, 31); + } + return { + "headCanvas": headCanvas, + "bodyCanvas": bodyCanvas, + "damageCanvas": damageCanvas + } +} + ////// 显示移动某块的动画,达到{“type”:”move”}的效果 ////// maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { time = time || 500; @@ -791,35 +862,13 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { core.removeBlock(x,y); block=block.block; + var blockInfo = this.__getBlockInfo(block); + if (blockInfo == null) { + if (core.isset(callback)) callback(); + return; + } + var image = blockInfo.image, bx = blockInfo.bx, by = blockInfo.by, height = blockInfo.height, isTileset = blockInfo.isTileset, faceIds = blockInfo.faceIds; - var image, bx, by, height = block.event.height || 32; - var faceIds = {}; - if (block.event.cls == 'tileset') { - var offset = core.icons.getTilesetOffset(block.event.id); - if (offset==null) { - if (core.isset(callback)) callback(); - return; - } - bx = offset.x; - by = offset.y; - image = core.material.images.tilesets[offset.image]; - } - // 不支持autotile - else if (block.event.cls == 'autotile') { - if (core.isset(callback)) callback(); - return; - } - // 空气墙;忽略事件 - else if (block.id==17) { - if (core.isset(callback)) callback(); - return; - } - else { - image = core.material.images[block.event.cls]; - bx = 0; - by = core.material.icons[block.event.cls][block.event.id]; - faceIds = block.event.faceIds||{}; - } // 要运行的轨迹:将steps展开 var moveSteps=[]; steps.forEach(function (e) { @@ -846,32 +895,12 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { 'right': {'x': 1, 'y': 0} }; - var animateValue = block.event.animate || 1; - var animateCurrent = 0; - if (block.event.cls=='tileset') { - animateCurrent = bx; - } - var animateTime = 0; + var animateValue = block.event.animate || 1, animateCurrent = isTileset?bx:0, animateTime = 0; + var blockCanvas = this.__initBlockCanvas(block, height, x, y); + var headCanvas = blockCanvas.headCanvas, bodyCanvas = blockCanvas.bodyCanvas, damageCanvas = blockCanvas.damageCanvas; + var opacity = 1; - var alpha = 1, name = 'move'+x+'_'+y; - core.createCanvas(name, block.x - core.bigmap.offsetX, block.y * 32 +32 - height - core.bigmap.offsetY, 32, height, 45); - core.dymCanvas[name].textAlign = 'left'; - - // 显伤 - var damage = null, damageColor = null; - if ((block.event.cls == 'enemys' || block.event.cls == 'enemy48') && core.hasItem('book')) { - var damageString = core.enemys.getDamageString(block.event.id, x, y); - damage = damageString.damage; damageColor = damageString.color; - } - - var draw = function() { - core.dymCanvas[name].clearRect(0, 0, 32, height); - core.dymCanvas[name].drawImage(image, animateCurrent*32, by*height, 32, height, 0, 0, 32, height); - // 绘制显伤 - if (damage != null) - core.fillBoldText(core.dymCanvas[name], damage, damageColor, 1, height-1); - }; - draw(); + core.maps.__moveBlockCanvas(image, animateCurrent, by, height, nowX, nowY, opacity, headCanvas, bodyCanvas, damageCanvas); var animate=window.setInterval(function() { @@ -881,31 +910,27 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { animateTime = 0; if (animateCurrent>=animateValue) animateCurrent=0; } - if (block.event.cls=='tileset') { - animateCurrent = bx; - } + if (isTileset) animateCurrent = bx; // 已经移动完毕,消失 if (moveSteps.length==0) { - if (keep) alpha=0; - else alpha -= 0.06; - if (alpha<=0) { + if (keep) opacity=0; + else opacity -= 0.06; + if (opacity<=0) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); - core.deleteCanvas(name); + core.deleteCanvas(headCanvas); + core.deleteCanvas(bodyCanvas); + core.deleteCanvas(damageCanvas); // 不消失 if (keep) { core.setBlock(id, nowX/32, nowY/32); core.showBlock(nowX/32, nowY/32); } - else { - if (block.event.cls == 'enemys' || block.event.cls == 'enemy48') - core.clearMap('damage', nowX, nowY, 32, 32); - } if (core.isset(callback)) callback(); } else { - core.dymCanvas[name].canvas.style.opacity = alpha; + core.maps.__moveBlockCanvas(image, animateCurrent, by, height, nowX, nowY, opacity, headCanvas, bodyCanvas, damageCanvas); } } else { @@ -924,8 +949,7 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { nowX+=scan[direction].x*2; nowY+=scan[direction].y*2; // 移动 - core.relocateCanvas(name, nowX, nowY-height+32); - draw(); + core.maps.__moveBlockCanvas(image, animateCurrent, by, height, nowX, nowY, opacity, headCanvas, bodyCanvas, damageCanvas); if (step==16) { // 该移动完毕,继续 step=0; @@ -952,36 +976,12 @@ maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) { core.removeBlock(sx,sy); block=block.block; - var image, bx, by, height = block.event.height || 32; - if (block.event.cls == 'tileset') { - var offset = core.icons.getTilesetOffset(block.event.id); - if (offset==null) { - if (core.isset(callback)) callback(); - return; - } - bx = offset.x; - by = offset.y; - image = core.material.images.tilesets[offset.image]; - } - // 不支持autotile - else if (block.event.cls == 'autotile') { + var blockInfo = this.__getBlockInfo(block); + if (blockInfo == null) { if (core.isset(callback)) callback(); return; } - // 空气墙;忽略事件 - else if (block.id==17) { - if (core.isset(callback)) callback(); - return; - } - else { - image = core.material.images[block.event.cls]; - bx = 0; - by = core.material.icons[block.event.cls][block.event.id]; - } - - var alpha = 1; - core.setAlpha('route', alpha); - core.canvas.route.drawImage(image, bx*32, by * height, 32, height, block.x * 32, block.y * 32 +32 - height, 32, height); + var image = blockInfo.image, bx = blockInfo.bx, by = blockInfo.by, height = blockInfo.height, isTileset = blockInfo.isTileset, faceIds = blockInfo.faceIds; core.playSound('jump.mp3'); @@ -1009,35 +1009,27 @@ maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) { curry = (curry * jump_count + ey) / (jump_count + 1.0); } - var animateValue = block.event.animate || 1; - var animateCurrent = 0; - var animateTime = 0; + var blockCanvas = this.__initBlockCanvas(block, height, sx, sy); + var headCanvas = blockCanvas.headCanvas, bodyCanvas = blockCanvas.bodyCanvas, damageCanvas = blockCanvas.damageCanvas; + var opacity = 1; + + core.maps.__moveBlockCanvas(image, bx, by, height, drawX(), drawY(), opacity, headCanvas, bodyCanvas, damageCanvas); + var animate=window.setInterval(function() { - animateTime += time / 16 / core.status.replay.speed; - if (animateTime >= core.values.animateSpeed) { - animateCurrent++; - animateTime = 0; - if (animateCurrent >= animateValue) animateCurrent = 0; - } - if (block.event.cls=='tileset') { - animateCurrent = bx; - } - if (jump_count>0) { - core.clearMap('route', drawX(), drawY()-height+32, 32, height); updateJump(); - core.canvas.route.drawImage(image, animateCurrent * 32, by * height, 32, height, drawX(), drawY()-height+32, 32, height); + core.maps.__moveBlockCanvas(image, bx, by, height, drawX(), drawY(), opacity, headCanvas, bodyCanvas, damageCanvas); } else { - if (keep) alpha=0; - else alpha -= 0.06; - core.clearMap('route', drawX(), drawY()-height+32, 32, height); - if (alpha<=0) { + if (keep) opacity=0; + else opacity -= 0.06; + if (opacity<=0) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); - core.clearMap('route'); - core.setAlpha('route', 1); + core.deleteCanvas(headCanvas); + core.deleteCanvas(bodyCanvas); + core.deleteCanvas(damageCanvas); if (keep) { core.setBlock(id, ex, ey); core.showBlock(ex, ey); @@ -1045,9 +1037,7 @@ maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) { if (core.isset(callback)) callback(); } else { - core.setAlpha('route', alpha); - core.canvas.route.drawImage(image, animateCurrent * 32, by * height, 32, height, drawX(), drawY()-height+32, 32, height); - core.setAlpha('route', 1); + core.maps.__moveBlockCanvas(image, bx, by, height, drawX(), drawY(), opacity, headCanvas, bodyCanvas, damageCanvas); } } @@ -1068,66 +1058,47 @@ maps.prototype.animateBlock = function (loc,type,time,callback) { var block = core.getBlock(t[0],t[1],null,true); if (block==null) return; block=block.block; - var image, bx, by, height = block.event.height || 32; - if (block.event.cls == 'tileset') { - var offset = core.icons.getTilesetOffset(block.event.id); - if (offset==null) { - if (core.isset(callback)) callback(); - return; - } - bx = offset.x; - by = offset.y; - image = core.material.images.tilesets[offset.image]; - } - // 不支持autotile - else if (block.event.cls == 'autotile') { - return; - } - // 空气墙,忽略事件 - else if (block.id==17) return; - else { - image = core.material.images[block.event.cls]; - bx = 0; - by = core.material.icons[block.event.cls][block.event.id]; - } + + var blockInfo = core.maps.__getBlockInfo(block); + if (blockInfo == null) return; + var blockCanvas = core.maps.__initBlockCanvas(block, blockInfo.height, t[0], t[1]); + var headCanvas = blockCanvas.headCanvas, bodyCanvas = blockCanvas.bodyCanvas, damageCanvas = blockCanvas.damageCanvas; + list.push({ - 'x': t[0], 'y': t[1], 'height': height, - 'bx': bx, 'by': by, 'image': image - }) - }) + 'x': t[0], 'y': t[1], 'height': blockInfo.height, + 'bx': blockInfo.bx, 'by': blockInfo.by, 'image': blockInfo.image, + 'headCanvas': headCanvas, 'bodyCanvas': bodyCanvas, 'damageCanvas': damageCanvas + }); + + }); if (list.length==0) { if (core.isset(callback)) callback(); return; } - // core.status.replay.animate=true; - var clear = function () { - list.forEach(function (t) { - core.clearMap('route', t.x*32, t.y*32+32-t.height, 32, t.height); - }) - } + var opacity = 0; + if (type=='hide') opacity=1; + var draw = function () { list.forEach(function (t) { - core.canvas.route.drawImage(t.image, t.bx*32, t.by*t.height, 32, t.height, t.x*32, t.y*32+32-t.height, 32, t.height); + core.maps.__moveBlockCanvas(t.image, t.bx, t.by, t.height, t.x*32, t.y*32, opacity, t.headCanvas, t.bodyCanvas, t.damageCanvas); }) - } - - var alpha = 0; - if (type=='hide') alpha=1; - - core.setAlpha('route', alpha); + }; draw(); var per_time = 10, steps = parseInt(time / per_time), delta = 1 / steps; var animate = setInterval(function () { - if (type=='show') alpha += delta; - else alpha -= delta; - clear(); - if (alpha >=1 || alpha<=0) { + if (type=='show') opacity += delta; + else opacity -= delta; + if (opacity >=1 || opacity<=0) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); - core.setAlpha('route', 1); + list.forEach(function (t) { + core.deleteCanvas(t.headCanvas); + core.deleteCanvas(t.bodyCanvas); + core.deleteCanvas(t.damageCanvas); + }); if (type == 'show') { loc.forEach(function (t) { core.showBlock(t[0],t[1],data.floorId); @@ -1141,7 +1112,6 @@ maps.prototype.animateBlock = function (loc,type,time,callback) { if (core.isset(callback)) callback(); } else { - core.setAlpha('route', alpha); draw(); } }, per_time); diff --git a/libs/ui.js b/libs/ui.js index dc030742..266f059e 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2796,7 +2796,6 @@ ui.prototype.createCanvas = function (name, x, y, width, height, z) { newCanvas.style.zIndex = z; newCanvas.style.position = 'absolute'; core.dymCanvas[name] = newCanvas.getContext('2d'); - core.dom.dymCanvas.appendChild(newCanvas); core.dymCanvas._list.push({ "id": name, "style": { @@ -2804,10 +2803,12 @@ ui.prototype.createCanvas = function (name, x, y, width, height, z) { "top": y, } }); + core.dom.gameDraw.appendChild(newCanvas); } ////// canvas查找 ////// ui.prototype.findCanvas = function (name) { + if (!core.isset(name)) return -1; for (var index = 0; index < core.dymCanvas._list.length; index++) { if (core.dymCanvas._list[index].id == name) return index; @@ -2817,6 +2818,7 @@ ui.prototype.findCanvas = function (name) { ////// canvas重定位 ////// ui.prototype.relocateCanvas = function (name, x, y) { + if (!core.isset(name)) return; var index = core.findCanvas(name); if (index < 0) return; if (core.isset(x)) { @@ -2831,6 +2833,7 @@ ui.prototype.relocateCanvas = function (name, x, y) { ////// canvas重置 ////// ui.prototype.resizeCanvas = function (name, width, height) { + if (!core.isset(name)) return; var dstCanvas = core.dymCanvas[name].canvas; if (core.isset(width)) { dstCanvas.width = width; @@ -2843,9 +2846,19 @@ ui.prototype.resizeCanvas = function (name, width, height) { } ////// canvas删除 ////// ui.prototype.deleteCanvas = function (name) { + if (!core.isset(name)) return; var index = core.findCanvas(name); if (index == -1) return; - core.dom.dymCanvas.removeChild(core.dom.dymCanvas.childNodes[index]); - core.dymCanvas[name] = null; + core.dom.gameDraw.removeChild(core.dymCanvas[name].canvas); + delete core.dymCanvas[name]; core.dymCanvas._list.splice(index,1); } + +////// 删除所有动态canvas ////// +ui.prototype.deleteAllCanvas = function () { + core.dymCanvas._list.forEach(function (t) { + core.dom.gameDraw.removeChild(core.dymCanvas[t.id].canvas); + delete core.dymCanvas[t.id]; + }); + core.dymCanvas._list = []; +} diff --git a/main.js b/main.js index bb6be1bb..0454b03a 100644 --- a/main.js +++ b/main.js @@ -69,7 +69,6 @@ function main() { 'skillCol': document.getElementById('skillCol'), 'hard': document.getElementById('hard'), 'statusCanvas': document.getElementById('statusCanvas'), - 'dymCanvas': document.getElementById('dymCanvas'), }; this.mode = 'play'; this.loadList = [ diff --git a/styles.css b/styles.css index 6a967fd3..8609eedb 100644 --- a/styles.css +++ b/styles.css @@ -306,10 +306,6 @@ p#name { z-index: 170; } -#dymCanvas { - position: absolute; -} - .clearfix:before, .clearfix:after { content: "."; From fa6d503aacd2c46bb5a2f0f7319abb4aa216daa8 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Mon, 17 Dec 2018 15:41:23 +0800 Subject: [PATCH 78/81] dynamic canvas & Docs --- docs/api.md | 75 ++++++++++++++++ docs/event.md | 1 + docs/personalization.md | 51 ++++++++--- libs/control.js | 2 + libs/core.js | 75 ++++++++-------- libs/events.js | 1 + libs/ui.js | 184 +++++++++++++++++++--------------------- project/functions.js | 8 +- 8 files changed, 250 insertions(+), 147 deletions(-) diff --git a/docs/api.md b/docs/api.md index bba4bba2..7fe0257c 100644 --- a/docs/api.md +++ b/docs/api.md @@ -473,12 +473,87 @@ core.maps.removeBlockByIds(floorId, ids) ui.js主要用来进行UI窗口的绘制,比如对话框、怪物手册、楼传器、存读档界面等等。 +core.ui.fillText(name, text, x, y, style, font) +在某个画布上绘制一段文字。 +name为画布名,可以是系统画布之一,也可以是任意自定义动态创建的画布名。(下同) +text为要绘制的文本,x,y为要绘制的坐标,style可选为绘制的样式,font可选为绘制的字体。 + + +core.ui.fillBoldText(canvas, text, style, x, y, font) +在某个画布上绘制一个描黑边的文字。 +canvas为要绘制的画布的context,text为文本,style为颜色样式,x,y坐标,font可选为要绘制的字体。 + + +core.ui.fillRect(name, x, y, width, height, style) +绘制一个矩形。style可选为绘制样式。 + + +core.ui.strokeRect(name, x, y, width, height, style) +绘制一个矩形的边框。 + + +core.ui.drawLine(name, x1, y1, x2, y2, style, lineWidth) +绘制一条线。lineWidth可选为线宽。 + + +core.ui.drawArrow(name, x1, y1, x2, y2, style, lineWidth) +绘制一个箭头。 + + +core.ui.setFont(name, font) / core.ui.setLineWidth(name, lineWidth) +设置一个画布的字体/线宽。 + + +core.ui.setAlpha(name, font) / core.ui.setOpacity(name, font) +设置一个画布的绘制不透明度和画布本身的不透明度。 +两者区别如下: + - setAlpha是设置"接下来绘制的内容的不透明度",不会对已经绘制的内容产生影响。比如setAlpha('ui', 0.5)则会在接下来的绘制中使用0.5的不透明度。 + - setOpacity是设置"画布本身的不透明度",已经绘制的内容也会产生影响。比如我已经在UI层绘制了一段文字,再setOpacity则也会看起来变得透明。 +尽量不要对系统画布使用setOpacity(因为会对已经绘制的内容产生影响),自定义创建的画布则不受此限制。 + + +core.ui.setFillStyle(name, style) / core.ui.setStrokeStype(name, style) +设置一个画布的填充样式/描边样式。 + + +core.ui.createCanvas(name, x, y, width, height, zIndex) +动态创建一个画布。name为要创建的画布名,如果已存在则会直接取用当前存在的。 +x,y为创建的画布相对窗口左上角的像素坐标,width,height为创建的长宽。 +zIndex为创建的纵向高度(关系到画布之间的覆盖),z值高的将覆盖z值低的;系统画布的z值可在个性化中查看。 +创建一个画布后,可以通过 core.dymCanvas[name] 进行调用。 + + +core.ui.findCanvas(name) +寻找一个自定义画布的索引;如果存在该画布则返回对应的索引,不存在画布则返回-1。 + + +core.ui.relocateCanvas(name, x, y) +重新定位一个自定义画布。 + + +core.ui.resizeCanvas(name, x, y) +重新设置一个自定义画布的大小。 + + +core.ui.deleteCanvas(name) +删除一个自定义画布。 + + +core.ui.deleteAllCanvas() +清空所有的自定义画布。 + + + core.ui.drawThumbnail(floorId, canvas, blocks, x, y, size, heroLoc, heroIcon) 绘制一个缩略图,比如楼传器界面,存读档界面等情况。 floorId为目标楼层ID,canvas为要绘制到的图层,blocks为要绘制的所有图块。 x,y为该图层开始绘制的起始点坐标,size为每一格的像素,heroLoc为勇士坐标,heroIcon为勇士图标。 + + + + ========== core.utils.XXX 工具类的辅助函数 ========== utils.js主要用来进行一些辅助函数的计算。 diff --git a/docs/event.md b/docs/event.md index a16a6737..a17fcc93 100644 --- a/docs/event.md +++ b/docs/event.md @@ -2200,6 +2200,7 @@ if (core.getFlag("door",0)==2) { core.waitHeroToStop(function() { core.removeGlobalAnimate(0,0,true); core.clearMap('all'); core.clearMap('curtain'); // 清空全地图 + core.deleteAllCanvas(); core.drawText([ "\t[恭喜通关]你的分数是${status:hp}。" ], function () { diff --git a/docs/personalization.md b/docs/personalization.md index f88c49a2..59afe874 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -8,21 +8,44 @@ HTML5魔塔是使用画布(canvas)来绘制,存在若干个图层,它们之间有一个覆盖关系,后面的图层将覆盖前面的图层。 -所有图层从低往高依次如下:(加[B]的代表该层是大地图) +所有图层从低往高依次如下:(加[B]的代表该层是大地图,z-index代表该层的纵向高度) -- bg**[B]**:背景层;绘制背景图层素材bgmap,和背景贴图 -- event**[B]**:事件层;所有事件(道具、墙壁、NPC、怪物等)都绘制在这一层进行处理 -- hero:勇士层;主要用来绘制勇士 -- event2**[B]**:事件2层;本层主要用来绘制48x32的图片素材的上半部分(避免和勇士错位) -- fg**[B]**:前景层;绘制前景图层素材fgmap,和前景贴图 -- damage**[B]**:显伤层;主要用来绘制怪物显伤和领域显伤 -- animate:动画层;主要用来绘制动画。 -- weather:天气层;主要用来绘制天气(雨/雪/雾) -- route**[B]**:路线层;主要用来绘制勇士的行走路线图,也用来绘制图块的淡入/淡出效果,图块的移动等。 -- curtain:色调层;用来控制当前楼层的画面色调 -- image:图片层;主要用来绘制显示图片;该层之所以在curtain层上是为了可以在全黑时贴大头像图 -- ui:UI层;用来绘制一切UI窗口,如剧情文本、怪物手册、楼传器、系统菜单等等 -- data:数据层;用来绘制一些顶层的或更新比较快的数据,如左上角的提示,战斗界面中数据的变化等等。 +- bg**[B]**:背景层;绘制背景图层素材bgmap,和背景贴图 (z-index: 10) +- event**[B]**:事件层;所有事件(道具、墙壁、NPC、怪物等)都绘制在这一层进行处理 (z-index: 30) +- hero:勇士层;主要用来绘制勇士 (z-index: 40) +- event2**[B]**:事件2层;本层主要用来绘制48x32的图片素材的上半部分(避免和勇士错位) (z-index: 50) +- fg**[B]**:前景层;绘制前景图层素材fgmap,和前景贴图 (z-index: 60) +- damage**[B]**:显伤层;主要用来绘制怪物显伤和领域显伤 (z-index: 65) +- animate:动画层;主要用来绘制动画。 (z-index: 70) +- weather:天气层;主要用来绘制天气(雨/雪/雾) (z-index: 80) +- route**[B]**:路线层;主要用来绘制勇士的行走路线图。 (z-index: 95) +- curtain:色调层;用来控制当前楼层的画面色调 (z-index: 100) +- ui:UI层;用来绘制一切UI窗口,如剧情文本、怪物手册、楼传器、系统菜单等等 (z-index: 160) +- data:数据层;用来绘制一些顶层的或更新比较快的数据,如左上角的提示,战斗界面中数据的变化等等。 (z-index: 170) + +### 动态创建canvas + +从V2.5.3开始,可以在H5样板中任意动态创建canvas并进行使用。 + +使用`core.createCanvas(name, x, y, w, h, z)`来动态创建一个画布。 + +其中name为动态canvas名称,x,y,w,h为创建的画布相对窗口左上角的像素坐标和长宽,z为画布的纵向高度。 + +例如:`core.createCanvas('test', 10, 20, 100, 200, 74)` 创建了一个名为test的画布,其左上角相对窗口的像素坐标为(10,20),宽100高200,纵向高度74(在动画层和天气层之间)。 + +可以通过 `core.dymCanvas[name]` 来获得该画布的context;例如 `core.dymCanvas.test` 就是我们上面创建的画布的context,然后进行操作。 + +也可以简单的使用`core.fillText()`, `core.fillRect()`, `core.strokeRect()`等等对画布进行任意绘制。 + +``` js +core.fillText('test', '这是一段文字', 10, 30, '#FF0000', '16px Verdana'); // 绘制一段文本 +``` + +使用 `core.deleteCanvas(name)` 删除一个动态创建的画布,例如 `core.deleteCanvas('test')`。 + +`core.deleteAllCanvas()`可以删除所有动态创建的画布,`core.relocateCanvas(name, x, y)`和`core.resizeCanvas(name, x, y)`可以对画布的位置和大小进行改变。 + +更多详细API请参见[API列表](api)。 ## 自定义素材 diff --git a/libs/control.js b/libs/control.js index 8f94e572..d671933c 100644 --- a/libs/control.js +++ b/libs/control.js @@ -288,6 +288,7 @@ control.prototype.showStartAnimate = function (noAnimate, callback) { core.clearStatus(); core.clearMap('all'); core.clearMap('curtain'); + core.deleteAllCanvas(); // 重置音量 core.events.setVolume(1, 0); @@ -355,6 +356,7 @@ control.prototype.clearStatus = function() { } core.status = {}; core.clearStatusBar(); + core.deleteAllCanvas(); core.status.played = false; core.events.setHeroIcon('hero.png', true); } diff --git a/libs/core.js b/libs/core.js index e27c657e..9280b192 100644 --- a/libs/core.js +++ b/libs/core.js @@ -631,68 +631,77 @@ core.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback, } ////// 清除地图 ////// -core.prototype.clearMap = function (map, x, y, width, height) { - core.ui.clearMap(map, x, y, width, height); +core.prototype.clearMap = function (name, x, y, width, height) { + core.ui.clearMap(name, x, y, width, height); } ////// 在某个canvas上绘制一段文字 ////// -core.prototype.fillText = function (map, text, x, y, style, font) { - core.ui.fillText(map, text, x, y, style, font); +core.prototype.fillText = function (name, text, x, y, style, font) { + core.ui.fillText(name, text, x, y, style, font); +} + +////// 在某个canvas上绘制一段描边文字 ////// +core.prototype.fillBoldText = function (canvas, text, style, x, y, font) { + core.ui.fillBoldText(canvas, text, style , x, y, font); } ////// 在某个canvas上绘制一个矩形 ////// -core.prototype.fillRect = function (map, x, y, width, height, style) { - core.ui.fillRect(map, x, y, width, height, style) +core.prototype.fillRect = function (name, x, y, width, height, style) { + core.ui.fillRect(name, x, y, width, height, style) } ////// 在某个canvas上绘制一个矩形的边框 ////// -core.prototype.strokeRect = function (map, x, y, width, height, style, lineWidth) { - core.ui.strokeRect(map, x, y, width, height, style, lineWidth) +core.prototype.strokeRect = function (name, x, y, width, height, style, lineWidth) { + core.ui.strokeRect(name, x, y, width, height, style, lineWidth) } ////// 在某个canvas上绘制一条线 ////// -core.prototype.drawLine = function (map, x1, y1, x2, y2, style, lineWidth) { - core.ui.drawLine(map, x1, y1, x2, y2, style, lineWidth); +core.prototype.drawLine = function (name, x1, y1, x2, y2, style, lineWidth) { + core.ui.drawLine(name, x1, y1, x2, y2, style, lineWidth); +} + +////// 在某个canvas上绘制一个箭头 ////// +core.prototype.drawArrow = function (name, x1, y1, x2, y2, style, lineWidth) { + core.ui.drawArrow(name, x1, y1, x2, y2, style, lineWidth); } ////// 设置某个canvas的文字字体 ////// -core.prototype.setFont = function (map, font) { - core.ui.setFont(map, font); +core.prototype.setFont = function (name, font) { + core.ui.setFont(name, font); } ////// 设置某个canvas的线宽度 ////// -core.prototype.setLineWidth = function (map, lineWidth) { - core.ui.setLineWidth(map, lineWidth); +core.prototype.setLineWidth = function (name, lineWidth) { + core.ui.setLineWidth(name, lineWidth); } ////// 保存某个canvas状态 ////// -core.prototype.saveCanvas = function (map) { - core.ui.saveCanvas(map); +core.prototype.saveCanvas = function (name) { + core.ui.saveCanvas(name); } ////// 加载某个canvas状态 ////// -core.prototype.loadCanvas = function (map) { - core.ui.loadCanvas(map); +core.prototype.loadCanvas = function (name) { + core.ui.loadCanvas(name); } - -////// 设置某个canvas边框属性 ////// -core.prototype.setStrokeStyle = function (map, style) { - core.ui.setStrokeStyle(map, style); -} - ////// 设置某个canvas的alpha值 ////// -core.prototype.setAlpha = function (map, alpha) { - core.ui.setAlpha(map, alpha); +core.prototype.setAlpha = function (name, alpha) { + core.ui.setAlpha(name, alpha); } ////// 设置某个canvas的透明度 ////// -core.prototype.setOpacity = function (map, opacity) { - core.ui.setOpacity(map, opacity); +core.prototype.setOpacity = function (name, opacity) { + core.ui.setOpacity(name, opacity); } ////// 设置某个canvas的绘制属性(如颜色等) ////// -core.prototype.setFillStyle = function (map, style) { - core.ui.setFillStyle(map, style); +core.prototype.setFillStyle = function (name, style) { + core.ui.setFillStyle(name, style); +} + +////// 设置某个canvas的边框属性 ////// +core.prototype.setStrokeStyle = function (name, style) { + core.ui.setStrokeStyle(name, style); } ////// canvas创建 ////// @@ -719,7 +728,7 @@ core.prototype.resizeCanvas = function (name, width, height) { core.prototype.deleteCanvas = function (name) { core.ui.deleteCanvas(name); } - +////// 删除所有canvas ////// core.prototype.deleteAllCanvas = function () { core.ui.deleteAllCanvas(); } @@ -898,10 +907,6 @@ core.prototype.updateDamage = function () { core.control.updateDamage(); } -core.prototype.fillBoldText = function (canvas, text, color, x, y, font) { - core.ui.fillBoldText(canvas, text, color, x, y, font); -} - ////// 测试是否拥有某个特殊属性 ////// core.prototype.hasSpecial = function (special, test) { return core.enemys.hasSpecial(special, test); diff --git a/libs/events.js b/libs/events.js index edca31c1..4e7574b0 100644 --- a/libs/events.js +++ b/libs/events.js @@ -122,6 +122,7 @@ events.prototype.startGame = function (hard, seed, route, callback) { core.clearMap('all'); core.clearMap('curtain'); + core.deleteAllCanvas(); core.clearStatusBar(); var post_start = function () { diff --git a/libs/ui.js b/libs/ui.js index 266f059e..18f3719c 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -17,9 +17,17 @@ ui.prototype.init = function () { ////////////////// 地图设置 +ui.prototype.getContextByName = function (name) { + if (core.isset(core.canvas[name])) + return core.canvas[name]; + if (core.isset(core.dymCanvas[name])) + return core.dymCanvas[name]; + return null; +} + ////// 清除地图 ////// -ui.prototype.clearMap = function (map, x, y, width, height) { - if (map == 'all') { +ui.prototype.clearMap = function (name, x, y, width, height) { + if (name == 'all') { for (var m in core.canvas) { // 不擦除curtain层 if (m=='curtain') continue; @@ -28,168 +36,144 @@ ui.prototype.clearMap = function (map, x, y, width, height) { core.dom.gif.innerHTML = ""; } else { - core.canvas[map].clearRect(x||0, y||0, width||core.bigmap.width*32, height||core.bigmap.height*32); + var ctx = this.getContextByName(name); + if (ctx) ctx.clearRect(x||0, y||0, width||ctx.canvas.width, height||ctx.canvas.height); } } ////// 在某个canvas上绘制一段文字 ////// -ui.prototype.fillText = function (map, text, x, y, style, font) { +ui.prototype.fillText = function (name, text, x, y, style, font) { if (core.isset(style)) { - core.setFillStyle(map, style); + core.setFillStyle(name, style); } if (core.isset(font)) { - core.setFont(map, font); + core.setFont(name, font); } - core.canvas[map].fillText(text, x, y); + var ctx = this.getContextByName(name); + if (ctx) ctx.fillText(text, x, y); } ////// 在某个canvas上绘制粗体 ////// -ui.prototype.fillBoldText = function (canvas, text, color, x, y, font) { +ui.prototype.fillBoldText = function (canvas, text, style, x, y, font) { if (core.isset(font)) canvas.font = font; canvas.fillStyle = '#000000'; canvas.fillText(text, x-1, y-1); canvas.fillText(text, x-1, y+1); canvas.fillText(text, x+1, y-1); canvas.fillText(text, x+1, y+1); - canvas.fillStyle = color; + canvas.fillStyle = style; canvas.fillText(text, x, y); } ////// 在某个canvas上绘制一个矩形 ////// -ui.prototype.fillRect = function (map, x, y, width, height, style) { +ui.prototype.fillRect = function (name, x, y, width, height, style) { if (core.isset(style)) { - core.setFillStyle(map, style); + core.setFillStyle(name, style); } - core.canvas[map].fillRect(x, y, width, height); + var ctx = this.getContextByName(name); + if (ctx) ctx.fillRect(x, y, width, height); } ////// 在某个canvas上绘制一个矩形的边框 ////// -ui.prototype.strokeRect = function (map, x, y, width, height, style, lineWidth) { +ui.prototype.strokeRect = function (name, x, y, width, height, style, lineWidth) { if (core.isset(style)) { - core.setStrokeStyle(map, style); + core.setStrokeStyle(name, style); } if (core.isset(lineWidth)) { - core.setLineWidth(map, lineWidth); + core.setLineWidth(name, lineWidth); } - core.canvas[map].strokeRect(x, y, width, height); + var ctx = this.getContextByName(name); + if (ctx) ctx.strokeRect(x, y, width, height); } ////// 在某个canvas上绘制一条线 ////// -ui.prototype.drawLine = function (map, x1, y1, x2, y2, style, lineWidth) { +ui.prototype.drawLine = function (name, x1, y1, x2, y2, style, lineWidth) { if (core.isset(style)) { - core.setStrokeStyle(map, style); + core.setStrokeStyle(name, style); } if (core.isset(lineWidth)) { - core.setLineWidth(map, lineWidth); + core.setLineWidth(name, lineWidth); + } + var ctx = this.getContextByName(name); + if (ctx) { + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.stroke(); } - core.canvas[map].beginPath(); - core.canvas[map].moveTo(x1, y1); - core.canvas[map].lineTo(x2, y2); - core.canvas[map].stroke(); } ////// 在某个canvas上绘制一个箭头 ////// -ui.prototype.drawArrow = function (map, x1, y1, x2, y2, style, lineWidth) { +ui.prototype.drawArrow = function (name, x1, y1, x2, y2, style, lineWidth) { if (x1==x2 && y1==y2) return; if (core.isset(style)) { - core.setStrokeStyle(map, style); + core.setStrokeStyle(name, style); } if (core.isset(lineWidth)) { - core.setLineWidth(map, lineWidth); + core.setLineWidth(name, lineWidth); + } + var ctx = this.getContextByName(name); + if (ctx) { + var head = 10; + var dx = x2-x1, dy=y2-y1; + var angle = Math.atan2(dy,dx); + ctx.beginPath(); + ctx.moveTo(x1,y1); + ctx.lineTo(x2, y2); + ctx.lineTo(x2-head*Math.cos(angle-Math.PI/6),y2-head*Math.sin(angle-Math.PI/6)); + ctx.moveTo(x2, y2); + ctx.lineTo(x2-head*Math.cos(angle+Math.PI/6),y2-head*Math.sin(angle+Math.PI/6)); + ctx.stroke(); } - var head = 10; - var dx = x2-x1, dy=y2-y1; - var angle = Math.atan2(dy,dx); - core.canvas[map].beginPath(); - core.canvas[map].moveTo(x1,y1); - core.canvas[map].lineTo(x2, y2); - core.canvas[map].lineTo(x2-head*Math.cos(angle-Math.PI/6),y2-head*Math.sin(angle-Math.PI/6)); - core.canvas[map].moveTo(x2, y2); - core.canvas[map].lineTo(x2-head*Math.cos(angle+Math.PI/6),y2-head*Math.sin(angle+Math.PI/6)); - core.canvas[map].stroke(); } ////// 设置某个canvas的文字字体 ////// -ui.prototype.setFont = function (map, font) { - core.canvas[map].font = font; +ui.prototype.setFont = function (name, font) { + var ctx = this.getContextByName(name); + if (ctx) ctx.font = font; } ////// 设置某个canvas的线宽度 ////// -ui.prototype.setLineWidth = function (map, lineWidth) { - if (map == 'all') { - for (var m in core.canvas) { - core.canvas[m].lineWidth = lineWidth; - } - } - core.canvas[map].lineWidth = lineWidth; +ui.prototype.setLineWidth = function (name, lineWidth) { + var ctx = this.getContextByName(name); + if (ctx) ctx.lineWidth = lineWidth; } ////// 保存某个canvas状态 ////// -ui.prototype.saveCanvas = function (map) { - core.canvas[map].save(); +ui.prototype.saveCanvas = function (name) { + var ctx = this.getContextByName(name); + if (ctx) ctx.save(); } ////// 加载某个canvas状态 ////// -ui.prototype.loadCanvas = function (map) { - core.canvas[map].restore(); -} - -////// 设置某个canvas边框属性 ////// -ui.prototype.setStrokeStyle = function (map, style) { - if (map == 'all') { - for (var m in core.canvas) { - core.canvas[m].strokeStyle = style; - } - } - else { - core.canvas[map].strokeStyle = style; - } +ui.prototype.loadCanvas = function (name) { + var ctx = this.getContextByName(name); + if (ctx) ctx.restore(); } ////// 设置某个canvas的alpha值 ////// -ui.prototype.setAlpha = function (map, alpha) { - if (map == 'all') { - for (var m in core.canvas) { - core.canvas[m].globalAlpha = alpha; - } - } - else core.canvas[map].globalAlpha = alpha; +ui.prototype.setAlpha = function (name, alpha) { + var ctx = this.getContextByName(name); + if (ctx) ctx.globalAlpha = alpha; } ////// 设置某个canvas的透明度;尽量不要使用本函数,而是全部换成setAlpha实现 ////// -ui.prototype.setOpacity = function (map, opacity) { - if (map == 'all') { - for (var m in core.canvas) { - core.canvas[m].canvas.style.opacity = opacity; - } - } - else if (core.isset(core.canvas[map])) { - core.canvas[map].canvas.style.opacity = opacity; - } - else if (core.isset(core.dymCanvas[map])) { - core.dymCanvas[map].canvas.style.opacity = opacity; - } - else - console.log("未找到"+map); +ui.prototype.setOpacity = function (name, opacity) { + var ctx = this.getContextByName(name); + if (ctx) ctx.canvas.style.opacity = opacity; } ////// 设置某个canvas的绘制属性(如颜色等) ////// -ui.prototype.setFillStyle = function (map, style) { - if (map == 'all') { - for (var m in core.canvas) { - core.canvas[m].fillStyle = style; - } - } - else if (core.isset(core.canvas[map])) { - core.canvas[map].fillStyle = style; - } - else if (core.isset(core.dymCanvas[map])) { - core.dymCanvas[map].fillStyle = style; -} - else - console.log("未找到"+map); +ui.prototype.setFillStyle = function (name, style) { + var ctx = this.getContextByName(name); + if (ctx) ctx.fillStyle = style; } +////// 设置某个canvas边框属性 ////// +ui.prototype.setStrokeStyle = function (name, style) { + var ctx = this.getContextByName(name); + if (ctx) ctx.strokeStyle = style; +} ///////////////// UI绘制 @@ -2784,6 +2768,14 @@ ui.prototype.drawHelp = function () { ////// canvas创建 ////// ui.prototype.createCanvas = function (name, x, y, width, height, z) { + // 如果画布已存在则直接调用 + var cv = this.findCanvas(name); + if (cv!=-1) { + this.relocateCanvas(name, x, y); + this.resizeCanvas(name, width, height); + core.dymCanvas[name].canvas.style.zIndex = z; + return; + } var newCanvas = document.createElement("canvas"); newCanvas.id = name; newCanvas.style.display = 'block'; diff --git a/project/functions.js b/project/functions.js index 09ed1cdd..6d6083e2 100644 --- a/project/functions.js +++ b/project/functions.js @@ -60,6 +60,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.waitHeroToStop(function() { core.removeGlobalAnimate(0,0,true); core.clearMap('all'); core.clearMap('curtain'); // 清空全地图 + core.deleteAllCanvas(); // 请注意: // 成绩统计时是按照hp进行上传并排名,因此光在这里改${status:hp}是无效的 // 如需按照其他的的分数统计方式,请先将hp设置为你的得分 @@ -1207,8 +1208,11 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // core.plugin.drawLight(0.9, [[25,11,46],[105,121,88],[301,221,106]]); // 存在三个灯光效果,分别是中心(25,11)半径46,中心(105,121)半径88,中心(301,221)半径106。 // core.plugin.drawLight([0,0,255,0.3], [[25,11,46],[105,121,88,0.2]], 0.4); // 存在两个灯光效果,它们在内圈40%范围内保持全亮,且40%后才开始衰减。 this.drawLight = function (color, lights, lightDec) { - // 清空色调层;也可以修改成其它层比如animate层,或者用自己创建的canvas - var ctx = core.canvas.curtain; + // 清空色调层;也可以修改成其它层比如animate/weather层,或者用自己创建的canvas + var canvasName = 'curtain'; + var ctx = core.ui.getContextByName(canvasName); + if (ctx == null) return; + ctx.mozImageSmoothingEnabled = false; ctx.webkitImageSmoothingEnabled = false; ctx.msImageSmoothingEnabled = false; From 50babed47ab38769f79c36be807c5f92e71c84d6 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Mon, 17 Dec 2018 15:47:02 +0800 Subject: [PATCH 79/81] Docs --- docs/api.md | 21 ++++++++++----------- libs/core.js | 4 ++-- libs/maps.js | 26 +++++++++++++------------- project/functions.js | 26 +++++++++++++------------- 4 files changed, 38 insertions(+), 39 deletions(-) diff --git a/docs/api.md b/docs/api.md index 7fe0257c..15477fdd 100644 --- a/docs/api.md +++ b/docs/api.md @@ -184,12 +184,6 @@ core.trigger(x, y) [异步] 触发某个地点的事件。 -core.clearMap(mapName) -清空某个画布图层。 -mapName可为'bg', 'event', 'hero', 'event2', 'fg', 'damage', 'animate', 'weather', 'ui', 'data', 'all'之一。 -如果mapName为'all',则为清空所有画布;否则只清空对应的画布。 - - core.drawBlock(block) 重绘某个图块。block应为core.status.thisMap.blocks中的一项。 @@ -473,6 +467,16 @@ core.maps.removeBlockByIds(floorId, ids) ui.js主要用来进行UI窗口的绘制,比如对话框、怪物手册、楼传器、存读档界面等等。 +core.ui.getContextByName(name) +根据画布名找到一个画布的context;支持系统画布和自定义画布。如果不存在画布返回null。 + + +core.clearMap(name) +清空某个画布图层。 +name为画布名,可以是系统画布之一,也可以是任意自定义动态创建的画布名。 +如果name也可以是'all',若为all则为清空除色调层外的所有系统画布。 + + core.ui.fillText(name, text, x, y, style, font) 在某个画布上绘制一段文字。 name为画布名,可以是系统画布之一,也可以是任意自定义动态创建的画布名。(下同) @@ -543,17 +547,12 @@ core.ui.deleteAllCanvas() 清空所有的自定义画布。 - core.ui.drawThumbnail(floorId, canvas, blocks, x, y, size, heroLoc, heroIcon) 绘制一个缩略图,比如楼传器界面,存读档界面等情况。 floorId为目标楼层ID,canvas为要绘制到的图层,blocks为要绘制的所有图块。 x,y为该图层开始绘制的起始点坐标,size为每一格的像素,heroLoc为勇士坐标,heroIcon为勇士图标。 - - - - ========== core.utils.XXX 工具类的辅助函数 ========== utils.js主要用来进行一些辅助函数的计算。 diff --git a/libs/core.js b/libs/core.js index 9280b192..238ee2de 100644 --- a/libs/core.js +++ b/libs/core.js @@ -738,8 +738,8 @@ core.prototype.drawBlock = function (block, animate, dx, dy) { } ////// 绘制某张地图 ////// -core.prototype.drawMap = function (mapName, callback) { - core.maps.drawMap(mapName, callback); +core.prototype.drawMap = function (floorId, callback) { + core.maps.drawMap(floorId, callback); } ////// 绘制Autotile ////// diff --git a/libs/maps.js b/libs/maps.js index dc360888..96825f5d 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -474,9 +474,9 @@ maps.prototype.drawBgFgMap = function (floorId, canvas, name, animate) { } ////// 绘制某张地图 ////// -maps.prototype.drawMap = function (mapName, callback) { - mapName = mapName || core.status.floorId; - if (!core.isset(mapName)) { +maps.prototype.drawMap = function (floorId, callback) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) { if (core.isset(callback)) callback(); return; @@ -485,10 +485,10 @@ 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; + var width = core.floors[floorId].width || 13; + var height = core.floors[floorId].height || 13; - var groundId = (core.status.maps||core.floors)[mapName].defaultGround || "ground"; + var groundId = (core.status.maps||core.floors)[floorId].defaultGround || "ground"; var blockIcon = core.material.icons.terrains[groundId]; for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { @@ -497,8 +497,8 @@ maps.prototype.drawMap = function (mapName, callback) { } var images = []; - if (core.isset(core.status.maps[mapName].images)) { - images = core.status.maps[mapName].images; + if (core.isset(core.status.maps[floorId].images)) { + images = core.status.maps[floorId].images; if (typeof images == 'string') { images = [[0, 0, images]]; } @@ -507,7 +507,7 @@ maps.prototype.drawMap = function (mapName, callback) { 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) && + !core.hasFlag("floorimg_"+floorId+"_"+dx+"_"+dy) && core.isset(core.material.images.images[p])) { var image = core.material.images.images[p]; if (!t[3]) { @@ -537,8 +537,8 @@ maps.prototype.drawMap = function (mapName, callback) { } }); - core.maps.drawBgFgMap(mapName, core.canvas.bg, "bg", true); - core.maps.drawBgFgMap(mapName, core.canvas.fg, "fg", true); + core.maps.drawBgFgMap(floorId, core.canvas.bg, "bg", true); + core.maps.drawBgFgMap(floorId, core.canvas.fg, "fg", true); } if (main.mode=='editor'){ @@ -554,8 +554,8 @@ maps.prototype.drawMap = function (mapName, callback) { drawBg(); } - core.status.floorId = mapName; - core.status.thisMap = core.status.maps[mapName]; + core.status.floorId = floorId; + core.status.thisMap = core.status.maps[floorId]; var drawEvent = function(){ var mapData = core.status.maps[core.status.floorId]; diff --git a/project/functions.js b/project/functions.js index 6d6083e2..6bcaa815 100644 --- a/project/functions.js +++ b/project/functions.js @@ -423,12 +423,12 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = var mon_hp = enemy.hp, mon_atk = enemy.atk, mon_def = enemy.def, mon_special = enemy.special; var mon_money = enemy.money, mon_experience = enemy.experience, mon_point = enemy.point; // 模仿 - if (this.hasSpecial(mon_special, 10)) { + if (core.hasSpecial(mon_special, 10)) { mon_atk = hero_atk; mon_def = hero_def; } // 坚固 - if (this.hasSpecial(mon_special, 3) && mon_def < hero_atk - 1) { + if (core.hasSpecial(mon_special, 3) && mon_def < hero_atk - 1) { mon_def = hero_atk - 1; } @@ -464,7 +464,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // TODO:可以在这里新增其他的怪物数据变化 // 比如仿攻(怪物攻击不低于勇士攻击): - // if (this.hasSpecial(mon_special, 27) && mon_atk < hero_atk) { + // if (core.hasSpecial(mon_special, 27) && mon_atk < hero_atk) { // mon_atk = hero_atk; // } // 也可以按需增加各种自定义内容(比如幻塔的魔杖效果等) @@ -512,14 +512,14 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } // 如果是无敌属性,且勇士未持有十字架 - if (this.hasSpecial(mon_special, 20) && !core.hasItem("cross")) + if (core.hasSpecial(mon_special, 20) && !core.hasItem("cross")) return null; // 不可战斗 // 战前造成的额外伤害(可被魔防抵消) var init_damage = 0; // 吸血 - if (this.hasSpecial(mon_special, 11)) { + if (core.hasSpecial(mon_special, 11)) { var vampire_damage = hero_hp * enemy.value; // 如果有神圣盾免疫吸血等可以在这里写 @@ -537,28 +537,28 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 每回合怪物对勇士造成的战斗伤害 var per_damage = mon_atk - hero_def; // 魔攻:战斗伤害就是怪物攻击力 - if (this.hasSpecial(mon_special, 2)) per_damage = mon_atk; + if (core.hasSpecial(mon_special, 2)) per_damage = mon_atk; // 战斗伤害不能为负值 if (per_damage < 0) per_damage = 0; // 2连击 & 3连击 & N连击 - if (this.hasSpecial(mon_special, 4)) per_damage *= 2; - if (this.hasSpecial(mon_special, 5)) per_damage *= 3; - if (this.hasSpecial(mon_special, 6)) per_damage *= (enemy.n||4); + if (core.hasSpecial(mon_special, 4)) per_damage *= 2; + if (core.hasSpecial(mon_special, 5)) per_damage *= 3; + if (core.hasSpecial(mon_special, 6)) per_damage *= (enemy.n||4); // 每回合的反击伤害;反击是按照勇士的攻击次数来计算回合 var counterDamage = 0; - if (this.hasSpecial(mon_special, 8)) counterDamage += Math.floor(core.values.counterAttack * hero_atk); + if (core.hasSpecial(mon_special, 8)) counterDamage += Math.floor(core.values.counterAttack * hero_atk); // 先攻 - if (this.hasSpecial(mon_special, 1)) init_damage += per_damage; + if (core.hasSpecial(mon_special, 1)) init_damage += per_damage; // 破甲 - if (this.hasSpecial(mon_special, 7)) + if (core.hasSpecial(mon_special, 7)) init_damage += Math.floor(core.values.breakArmor * hero_def); // 净化 - if (this.hasSpecial(mon_special, 9)) + if (core.hasSpecial(mon_special, 9)) init_damage += Math.floor(core.values.purify * hero_mdef); // 勇士每回合对怪物造成的伤害 From 2919e3fd5e18e0d19da67654fbe71f1316671ae8 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Mon, 17 Dec 2018 15:51:59 +0800 Subject: [PATCH 80/81] Critical in moveBlock --- libs/maps.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libs/maps.js b/libs/maps.js index 96825f5d..b7f62b88 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -838,7 +838,15 @@ maps.prototype.__initBlockCanvas = function (block, height, x, y) { damageCanvas = "blockDamage"+x+"_"+y; core.createCanvas(damageCanvas, 0, 0, 32, 32, 65); core.dymCanvas[damageCanvas].textAlign = 'left'; + core.dymCanvas[damageCanvas].font = "bold 11px Arial"; core.fillBoldText(core.dymCanvas[damageCanvas], damage, damageColor, 1, 31); + if (core.flags.displayCritical) { + var critical = core.enemys.nextCriticals(block.event.id); + if (critical.length>0) critical=critical[0]; + critical = core.formatBigNumber(critical[0], true); + if (critical == '???') critical = '?'; + core.fillBoldText(core.dymCanvas[damageCanvas], critical, '#FFFFFF', 1, 21); + } } return { "headCanvas": headCanvas, From 266c684e53d5f4c088c0bc4ead98ad265ec7f930 Mon Sep 17 00:00:00 2001 From: tocque <364004564@qq.com> Date: Mon, 17 Dec 2018 16:55:06 +0900 Subject: [PATCH 81/81] fix window --- libs/ui.js | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/libs/ui.js b/libs/ui.js index 266f059e..76b97621 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -383,6 +383,7 @@ ui.prototype.getTitleAndIcon = function (content) { // 绘制选择光标 ui.prototype.drawWindowSelector = function(background,x,y,w,h) { + w = Math.round(w), h = Math.round(h); if (core.isset(core.dymCanvas.selector)) { core.relocateCanvas("selector", x, y); core.resizeCanvas("selector", w, h); @@ -410,19 +411,30 @@ ui.prototype.drawWindowSelector = function(background,x,y,w,h) { ui.prototype.drawWindowSkin = function(background,canvas,x,y,w,h,direction,px,py) { // 仿RM窗口皮肤 ↓ var dstImage = core.canvas[canvas]; + var dx = 0, dy = 0; + // 绘制背景 + dstImage.drawImage(background, 0, 0, 128, 128, x+2, y+2, w-4, h-4); + // 绘制边框 + // 上方 + dstImage.drawImage(background, 128, 0, 16, 16, x, y, 16, 16); + for (dx = 0; dx < w - 64; dx += 32) { + dstImage.drawImage(background, 144, 0, 32, 16,x+dx+16, y, 32, 16); + dstImage.drawImage(background, 144,48, 32, 16,x+dx+16, y+h-16, 32, 16); + } + dstImage.drawImage(background, 144, 0,w-dx-32, 16,x+dx+16, y,w-dx-32, 16); + dstImage.drawImage(background, 144,48,w-dx-32, 16,x+dx+16, y+h-16,w-dx-32, 16); + dstImage.drawImage(background, 176, 0, 16, 16, x+w-16, y, 16, 16); + // 左右 + for (dy = 0; dy < h - 64; dy += 32) { + dstImage.drawImage(background, 128,16, 16, 32, x,y+dy+16, 16, 32); + dstImage.drawImage(background, 176,16, 16, 32, x+w-16,y+dy+16, 16, 32); + } + dstImage.drawImage(background, 128,16, 16,h-dy-32, x,y+dy+16, 16,h-dy-32); + dstImage.drawImage(background, 176,16, 16,h-dy-32, x+w-16,y+dy+16, 16,h-dy-32); + // 下方 + dstImage.drawImage(background, 128,48, 16, 16, x, y+h-16, 16, 16); + dstImage.drawImage(background, 176,48, 16, 16, x+w-16, y+h-16, 16, 16); - // back - dstImage.drawImage(background,0,0,128,128,x+1,y+1,w-2,h-2); - // corner - dstImage.drawImage(background,128,0,16,16,x,y,16,16); - dstImage.drawImage(background,176,0,16,16,x+w-16,y,16,16); - dstImage.drawImage(background,128,48,16,16,x,y+h-16,16,16); - dstImage.drawImage(background,176,48,16,16,x+w-16,y+h-16,16,16); - // border - dstImage.drawImage(background,144,0,32,16,x+16,y,w-32,16); - dstImage.drawImage(background,144,48,32,16,x+16,y+h-16,w-32,16); - dstImage.drawImage(background,128,16,16,32,x,y+16,16,h-32); - dstImage.drawImage(background,176,16,16,32,x+w-16,y+16,16,h-32); // arrow if(core.isset(px) && core.isset(py)){ if(direction == 'up'){