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/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index c4c827c9..b72170e4 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; */; @@ -50,15 +51,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; */; @@ -222,6 +224,7 @@ action | text_1_s | comment_s | autoText_s + | scrollText_s | setText_s | tip_s | setValue_s @@ -259,13 +262,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 + | moveImage_s | showGif_0_s | showGif_1_s - | moveImage_0_s | setFg_0_s | setFg_1_s | setWeather_s @@ -276,6 +278,8 @@ action | playBgm_s | pauseBgm_s | resumeBgm_s + | loadBgm_s + | freeBgm_s | playSound_s | setVolume_s | win_s @@ -365,6 +369,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 @@ -509,7 +526,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; @@ -542,7 +559,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; @@ -798,14 +815,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; */; @@ -1005,58 +1024,50 @@ 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 '% 不透明度' Number '时间' 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"] +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 -var code = '{"type": "showImage", "name": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+']},\n'; +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": '+Number_0+', "time": '+Int_3+async+'},\n'; return code; */; -showImage_1_s - : '清除所有图片' Newline +showTextImage_s + : '显示图片化文本' '文本内容' EvalString BGNL? + '图片编号' Int '起点像素位置' 'x' PosString 'y' PosString '不透明度' Number '时间' Int '不等待执行完毕' Bool Newline -/* showImage_1_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 +/* showTextImage_s +tooltip : showTextImage:显示图片化文本 +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 -var code = '{"type": "showImage"},\n'; +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": '+Number_0+', "time": '+Int_1+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=hideImage%ef%bc%9a%e6%b8%85%e9%99%a4%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] +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; */; @@ -1085,19 +1096,23 @@ var code = '{"type": "showGif"},\n'; return code; */; -moveImage_0_s - : '图片移动' EvalString '起点像素位置' 'x' PosString 'y' PosString BGNL - '终点像素位置' 'x' PosString 'y' PosString '移动时间' Int '保留图片' Bool '不等待执行完毕' Bool Newline +moveImage_s + : '图片移动' '图片编号' Int '终点像素位置' 'x' PosString? 'y' PosString? BGNL? + '不透明度' EvalString? '移动时间' Int '不等待执行完毕' Bool Newline -/* moveImage_0_s +/* 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 : ["bg.jpg","0","0","0","0",500,true,false] +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 -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'; +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+']'; +EvalString_0 = (EvalString_0!=='') ? (', "opacity": '+EvalString_0):''; +var async = Bool_0?', "async": true':''; +var code = '{"type": "moveImage", "code": '+Int_0+toloc+EvalString_0+',"time": '+Int_1+async+'},\n'; return code; */; @@ -1119,7 +1134,7 @@ Number_0 = limit(Number_0,0,255); 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):''; +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; @@ -1134,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; @@ -1168,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'; @@ -1184,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; @@ -1206,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'; @@ -1226,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; @@ -1269,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=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'; +return code; +*/; + +freeBgm_s + : '释放背景音乐的缓存' EvalString Newline + + +/* freeBgm_s +tooltip : freeBgm: 释放背景音乐的缓存 +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'; +return code; +*/; + playSound_s : '播放音效' EvalString Newline @@ -1291,7 +1332,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; @@ -1490,15 +1531,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; */; @@ -1650,8 +1692,8 @@ Arithmetic_List ; Weather_List - : '无'|'雨'|'雪' - /*Weather_List ['','rain','snow']*/; + : '无'|'雨'|'雪'|'雾' + /*Weather_List ['','rain','snow','fog']*/; B_0_List : '不改变'|'不可通行'|'可以通行' @@ -1666,16 +1708,16 @@ 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 : '全局字体'|'横屏左侧状态栏背景'|'竖屏上方状态栏背景'|'竖屏下方道具栏背景'|'边框颜色'|'状态栏文字色'|'难度显示文字色'|'楼层转换背景'|'楼层转换文字色' /*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' @@ -1787,7 +1829,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': @@ -1817,7 +1859,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]); @@ -1901,12 +1943,15 @@ 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,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;} @@ -1915,7 +1960,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([ @@ -2057,22 +2102,23 @@ 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]); - } + data.loc=data.loc||['',''] + this.next = MotaActionBlocks['showImage_s'].xmlText([ + 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 "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]); - } 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]); - } + 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([ + this.EvalString(data.text),data.code,data.loc[0],data.loc[1],data.opacity,data.time||0,data.async||false,this.next]); + break; + 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": // 显示动图 if(this.isset(data.name)){ @@ -2083,11 +2129,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, data.keep||false, data.async||false, this.next - ]); - break; case "setFg": // 颜色渐变 if(this.isset(data.color)){ var alpha = data.color[3]; @@ -2144,9 +2185,17 @@ 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, data.async||false, this.next]); + data.value, data.time||0, data.async||false, this.next]); break case "setValue": this.next = MotaActionBlocks['setValue_s'].xmlText([ @@ -2225,7 +2274,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([ @@ -2237,7 +2286,7 @@ ActionParser.prototype.parseAction = function() { break; case "hideStatusBar": this.next = MotaActionBlocks['hideStatusBar_s'].xmlText([ - this.next]); + data.toolbox||false,this.next]); break; case "updateEnemys": this.next = MotaActionBlocks['updateEnemys_s'].xmlText([ @@ -2245,7 +2294,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([ @@ -2335,7 +2384,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/comment.js b/_server/comment.js index 2b7fcc33..b44cc428 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, @@ -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", @@ -334,7 +340,7 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_leaf": true, "_type": "event", "_event": "eachArrive", - "_data": "每次到该楼层触发的事件,可以双击进入事件编辑器;该事件会比firstArrive先执行。" + "_data": "每次到该楼层触发的事件,可以双击进入事件编辑器;该事件会在firstArrive执行后再执行。" }, "parallelDo": { "_leaf": true, @@ -376,7 +382,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/_server/css/editor.css b/_server/css/editor.css index 928a0964..ebd4b009 100644 --- a/_server/css/editor.css +++ b/_server/css/editor.css @@ -392,3 +392,21 @@ table.row td { [v-cloak] { display: none !important; } + +#searchBlock { + 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: 6px; + background-image:url('data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJmdWxsIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpldj0iaHR0cDovL3d3dy53My5vcmcvMjAwMS94bWwtZXZlbnRzIj4KPGc%2BCgk8cG9seWdvbiBmaWxsPSIjNjY2IiBwb2ludHM9IjkuMjA3LDYuMTI2IDcuNzkzLDcuNTQxIDExLjc5MywxMS41NDEgMTMuMjA3LDEwLjEyNiIgLz4KCTxwYXRoIGZpbGw9IiM2NjYiIGQ9Ik01LjkxNywyYzEuNjA4LDAsMi45MTcsMS4zMDgsMi45MTcsMi45MTdTNy41MjUsNy44MzMsNS45MTcsNy44MzNTMyw2LjUyNSwzLDQuOTE3UzQuMzA4LDIsNS45MTcsMgoJCSBNNS45MTcsMEMzLjIwMSwwLDEsMi4yMDEsMSw0LjkxN3MyLjIwMSw0LjkxNyw0LjkxNyw0LjkxN3M0LjkxNy0yLjIwMSw0LjkxNy00LjkxN0MxMC44MzMsMi4yMDEsOC42MzIsMCw1LjkxNywwTDUuOTE3LDB6IiAvPgo8L2c%2BCjwvc3ZnPgo%3D'); +} \ No newline at end of file diff --git a/_server/data.comment.js b/_server/data.comment.js index 300a5fc0..fc527ef8 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -388,7 +388,12 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "animateSpeed": { "_leaf": true, "_type": "textarea", - "_data": "动画时间,一般300比较合适" + "_data": "全局动画时间,即怪物振动频率,一般300比较合适" + }, + "floorChangeTime": { + "_leaf": true, + "_type": "textarea", + "_data": "默认楼层切换时间" } } }, @@ -522,20 +527,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", @@ -566,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", @@ -578,6 +575,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", @@ -655,6 +664,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/editor.js b/_server/editor.js index 3da2558c..77b802e1 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]] }) }); } @@ -225,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; @@ -275,12 +286,27 @@ 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 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(); @@ -327,7 +353,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 +657,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); @@ -701,7 +736,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; @@ -795,7 +830,7 @@ editor.prototype.listen = function () { } } - var preMapData = {}; + editor.preMapData = null; var currDrawData = { pos: [], info: {} @@ -809,18 +844,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)); @@ -863,6 +898,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'); @@ -991,7 +1035,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; @@ -1016,7 +1060,7 @@ editor.prototype.listen = function () { throw(err) } ;printf('复制事件成功'); - editor.drawEventBlock(); + editor.drawPosSelection(); }); } @@ -1024,7 +1068,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){ @@ -1054,7 +1098,7 @@ 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 + editor.currentFloorData[v][last.x+','+last.y]=temp_atsfcytaf; }) editor.file.saveFloorFile(function (err) { if (err) { @@ -1062,7 +1106,7 @@ editor.prototype.listen = function () { throw(err) } ;printf('两位置的事件已互换'); - editor.drawEventBlock(); + editor.drawPosSelection(); }); } @@ -1070,7 +1114,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(''); @@ -1078,7 +1122,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) { @@ -1086,7 +1130,7 @@ editor.prototype.listen = function () { throw(err) } ;printf('清空此点及事件成功'); - editor.drawEventBlock(); + editor.drawPosSelection(); }); } diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index c16c0a12..34e90829 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; } @@ -60,14 +61,14 @@ 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(), - MotaActionBlocks['animateImage_1_s'].xmlText(), - MotaActionBlocks['showImage_1_s'].xmlText(), + MotaActionBlocks['showImage_s'].xmlText(), + MotaActionBlocks['hideImage_s'].xmlText(), + MotaActionBlocks['showTextImage_s'].xmlText(), + MotaActionBlocks['moveImage_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(), @@ -143,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(), ], @@ -242,15 +245,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'); @@ -268,6 +275,23 @@ var workspace = Blockly.inject(blocklyDiv,{ }, trashcan: false, }); + +editor_blockly.searchBlockCategoryCallback = function(workspace) { + var xmlList = []; + var labels = editor_blockly.searchBlock(); + for (var i = 0; i < labels.length; i++) { + var blockText = '' + + MotaActionBlocks[labels[i]].xmlText() + + ''; + var block = Blockly.Xml.textToDom(blockText).firstChild; + block.setAttribute("gap", 5); + xmlList.push(block); + } + return xmlList; +}; + +workspace.registerToolboxCategoryCallback( + 'searchBlockCategory', editor_blockly.searchBlockCategoryCallback); var onresize = function(e) { blocklyDiv.style.width = blocklyArea.offsetWidth + 'px'; @@ -288,8 +312,11 @@ 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==='create'){ + editor_blockly.addIntoLastUsedType(event.blockId); + } if(event.type==='ui'){ var newClick = [new Date().getTime(),event.blockId]; var lastClick = doubleClickCheck.shift(); @@ -407,7 +434,7 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ MotaActionFunctions.parse( eval('obj=' + codeAreaHL.getValue().replace(/[<>&]/g, function (c) { return {'<': '<', '>': '>', '&': '&'}[c]; - })), + }).replace(/\\r/g, '\\\\r').replace(/\\f/g, '\\\\f')), document.getElementById('entryType').value ); } @@ -422,7 +449,7 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ 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(); @@ -492,8 +519,10 @@ 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', + 'showTextImage_s': 'EvalString_0', 'function_s': 'RawEvalString_0', 'shopsub': 'EvalString_3', } @@ -509,6 +538,97 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ } } + 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) { + var b = editor_blockly.workspace.getBlockById(blockId); + if(!b)return; + var blockType = b.type; + if(!blockType || blockType.indexOf("_s")!==blockType.length-2 || blockType==='pass_s')return; + 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(); + 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(); + 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") { + element.click(); + return; + } + } + */ + editor_blockly.workspace.toolbox_.clearSelection(); + } + + var searchInput = document.getElementById("searchBlock"); + 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/_server/editor_file.js b/_server/editor_file.js index 3e938917..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", @@ -901,7 +902,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/_server/editor_mode.js b/_server/editor_mode.js index 3dd40ece..031dd8b9 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(); } @@ -585,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 目前版本**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..15477fdd 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,更多的有关内容请在代码内进行查询。** @@ -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 @@ -180,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中的一项。 @@ -469,6 +467,86 @@ 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为画布名,可以是系统画布之一,也可以是任意自定义动态创建的画布名。(下同) +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为要绘制的所有图块。 @@ -500,7 +578,7 @@ core.utils.decodeBase64(str) Base64解密字符串 -core.utils.formatBigNumber(x) +core.utils.formatBigNumber(x, onMap) 大数据的格式化 diff --git a/docs/element.md b/docs/element.md index 254f8ad9..ebec42ad 100644 --- a/docs/element.md +++ b/docs/element.md @@ -1,6 +1,6 @@ # 元件说明 -?> 目前版本**v2.5.2**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.3**,上次更新时间:* {docsify-updated} * 在本章中,将对样板里的各个元件进行说明。各个元件主要包括道具、门、怪物、楼梯等等。 @@ -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%的属性。 ### 检测是否存在装备 @@ -330,7 +318,7 @@ floorId指定的是目标楼层的唯一标识符(ID)。 另外一点是,V2.5.2以后,对话框`\b`可以根据文字长度来自动控制文本框宽度,其基本控制原理如下: - 如果用户存在手动换行`\n`,则选取**最长的一段话**作为文本框宽度。 -- 如果用户不存在手动换行,则会将文本框宽度调整为**尽量刚好达到三行**的最佳宽度。 +- 如果用户不存在手动换行,则会将文本框宽度调整为X行半的最佳宽度。 - 文本框宽度存在上下界,最终宽度一定会控制在该范围内。 该自动调整仅对`\b`的对话框效果有效。非对话框仍然会绘制整个界面的宽度。 @@ -373,7 +361,7 @@ floorId指定的是目标楼层的唯一标识符(ID)。 在每层楼的剧本文件里存在一个weather选项,表示该层楼的默认天气。 ``` js -// 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain"或"snow"代表雨雪,第二项为1-10之间的数代表强度。 +// 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain","snow"或"fog"代表雨雪雾,第二项为1-10之间的数代表强度。 "weather": ["snow",5] ``` @@ -414,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 7720332f..a17fcc93 100644 --- a/docs/event.md +++ b/docs/event.md @@ -1,6 +1,6 @@ # 事件 -?> 目前版本**v2.5.2**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.3**,上次更新时间:* {docsify-updated} * 本章内将对样板所支持的事件进行介绍。 @@ -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` @@ -419,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;可以省略代表当前楼层。 @@ -728,7 +750,7 @@ name是可选的,代表目标行走图的文件名。 使用`{"type": "hideStatusBar"}`可以隐藏状态栏。读档或重新开始游戏时,状态栏会重新显示。 -隐藏状态栏的状态下,将无法点击工具栏里面的按钮(如存读档怪物手册等)。建议仅在事件中使用,事件结束前显示。 +可以添加`"toolbox": true`来不隐藏竖屏模式下的工具栏。 ### showStatusBar:显示状态栏 @@ -901,7 +923,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 ] ``` -name为动画名,**请确保动画在main.js中的this.animates中被定义过。** +name为动画名,**请确保动画在全塔属性中的animates中被定义过。** loc为动画的位置,可以是`[x,y]`表示在(x,y)点显示,也可以是字符串`"hero"`表示在勇士点显示。 @@ -917,48 +939,66 @@ 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": 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毫秒,异步执行;这张图片将被上一张遮盖 ] ``` -name为图片名。**请确保图片在data.js中的images中被定义过。** +code为图片编号,如果两张图片重叠,编号较大会覆盖编号较小的。该值需要在1~50之间。 + +image为图片名。**请确保图片在全塔属性中的images中被定义过。** loc为图片左上角坐标,以像素为单位进行计算。 -如果不指定name则清除所有显示的图片。 +dw和dh为图片的横向、纵向放大率,默认值为100,即不进行缩放。 -调用show/hide/move/animate等几个事件同样会清除所有显示的图片。 +opacity为图片不透明度,在0~1之间,默认值为1,即不透明。 -### animateImage:图片淡入淡出 - -我们还可以使用 `{"type": "animateImage"}` 来造成显示图片的淡入淡出效果。 - -``` 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,异步执行 -] -``` - -action为淡入还是淡出,`show`为淡入,`hide`会淡出。 - -name为图片名。**请确保图片在data.js中的images中被定义过。** - -loc为图片左上角坐标,以像素为单位进行计算。 - -time为淡入淡出的时间,如果是0则忽略此项。 - -keep可选,如果为true则在淡入图片后立刻调用showImage以保留图片,在淡出图片前先清除再动画。 +time为渐变时间,默认值为0,即不渐变直接显示。 async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。 -如果多张图片的淡入淡出可以采用以下方式(仅供参考): +### showTextImage:显示文本化图片 -假设我现在已经有了`1.jpg`显示在屏幕上: -- 淡入显示`2.png`:调用`animateImage`淡入图片,然后立刻调用`showImage`显示图片。 -- 淡出`1.png`:清除所有图片,`showImage`显示`2.png`,然后调用`animateImage`淡出`1.jpg` +我们可以使用 `{"type": "showTextImage"}` 以图片的方式显示文本。 + +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "showTextImage", "code": 1, "text": "第一排\n第二排\n\n空行后的一排", "loc": [231,297], "opacity": 1, "time" : 0}, // 在(231,297)显示"第一排\n第二排\n\n空行后的一排" +] +``` + +code为图片编号,如果两张图片重叠,编号较大会覆盖编号较小的。该值需要在1~50之间。 + +text为要显示的文本。默认行宽为416。 + +loc为图片左上角坐标,以像素为单位进行计算。 + +opacity为图片不透明度,在0~1之间,默认值为1,即不透明。 + +time为渐变时间,默认值为0,即不渐变直接显示。 + +async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。 + +文本通过图片的方式显示后,即视为一张正常图片,可以被清除或者移动。 + +### hideImage:清除图片 + +我们可以使用 `{"type": "hideImage"}` 来清除一张图片。 + +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "hideImage", "code": 1, "time" : 0}, // 使1号图片消失 + {"type": "hideImage", "code": 12, "time" : 1000}, // 使12号图片渐变消失,时间为1000毫秒 +] +``` + +time为渐变时间,默认值为0,即不渐变直接消除。 + +code为显示图片时输入的图片编号。 + +async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。 ### showGif:显示动图 @@ -971,7 +1011,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 ] ``` -name为图片名。**请确保图片在data.js中的images中被定义过。** +name为图片名。**请确保图片在全塔属性中的images中被定义过。** loc为动图左上角坐标,以像素为单位进行计算。 @@ -979,24 +1019,24 @@ loc为动图左上角坐标,以像素为单位进行计算。 ### moveImage:图片移动 -我们可以使用 `{"type": "moveImage"}` 来造成图片移动效果。 +我们可以使用 `{"type": "moveImage"}` 来造成图片移动,淡入淡出等效果。 ``` js "x,y": [ // 实际执行的事件列表 - {"type": "moveImage", "name": "bg.jpg", "from": [231,297], "to": [22,333], "time": 500, "keep": true, "async": true}, + {"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,异步执行 ] ``` -name为图片名。**请确保图片在data.js中的images中被定义过。** +code为图片编号。该值需要在1~50之间。 -from为起点图片左上角坐标,以像素为单位进行计算。 +to为终点图片左上角坐标,以像素为单位进行计算,不填写则视为当前图片位置。 -to为终点图片左上角坐标,以像素为单位进行计算。 +opacity为完成时图片不透明度,移动过程中逐渐变化。在0~1之间。 time为总移动的时间。 -keep可选,如果为true则在移动结束后立刻调用showImage以保留图片。 - async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。 ### setFg:更改画面色调 @@ -1035,6 +1075,8 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 name为天气选项。目前只支持`rain`和`snow`,即雨天和雪天。 +从V2.5.3开始,也支持雾天`fog`。 + level为天气的强度等级,在1-10之间。1级为最弱,10级为最强。 如果想改回晴天则直接不加任何参数。 @@ -1175,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可以立刻播放一个音效。 @@ -1610,6 +1666,8 @@ core.insertAction([ // 请勿直接调用 core.changeFloor(toFloor, ...),这个代码是异步的,会导致事件处理和录像出问题! ``` +!> 从V2.5.3开始,提供了一个"不自动执行下一个事件"的选项(`"async": true`)。如果设置了此项,那么在该部分代码执行完毕后,不会立刻执行下一个事件。你需要在脚本中手动调用`core.events.doAction()`来执行下一个事件。可以通过此项来实现一些异步的代码,即在异步函数的回调中再执行下一个事件。使用此选项请谨慎,最好向开发者寻求咨询。 + ## 同一个点的多事件处理 我们可以发现,就目前而且,每个点的事件是和该点进行绑定,并以该点坐标作为唯一索引来查询。 @@ -1825,8 +1883,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 @@ -1868,7 +1926,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(例如升级全属性提升),使用分号分开,参见经验商店的写法。 像这样定义了全局商店后,即可在快捷栏中看到。 @@ -2142,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/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..59afe874 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -1,6 +1,6 @@ # 个性化 -?> 目前版本**v2.5.2**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.5.3**,上次更新时间:* {docsify-updated} * 有时候只靠样板本身可能是不够的。我们需要一些个性化、自定义的素材,道具效果,怪物属性,等等。 @@ -8,21 +8,44 @@ HTML5魔塔是使用画布(canvas)来绘制,存在若干个图层,它们之间有一个覆盖关系,后面的图层将覆盖前面的图层。 -所有图层从低往高依次如下: +所有图层从低往高依次如下:(加[B]的代表该层是大地图,z-index代表该层的纵向高度) -- bg:背景层;绘制背景图层素材bgmap,和背景贴图 -- event:事件层;所有事件(道具、墙壁、NPC、怪物等)都绘制在这一层进行处理 -- hero:勇士层;主要用来绘制勇士 -- event2:事件2层;本层主要用来绘制48x32的图片素材的上半部分(避免和勇士错位) -- fg:前景层;绘制前景图层素材fgmap,和前景贴图 -- damage:显伤层;主要用来绘制怪物显伤和领域显伤 -- animate:动画层;主要用来绘制动画。showImage事件绘制的图片也是在这一层。 -- weather:天气层;主要用来绘制天气(雨/雪) -- route:路线层;主要用来绘制勇士的行走路线图,也用来绘制图块的淡入/淡出效果,图块的移动等。 -- 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)。 ## 自定义素材 @@ -351,10 +374,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 +644,7 @@ this.statusBar = { }, 'icons': { // ...其他略 - 'speed': 24, // 图标的定义,这里对应的是icons.png中的索引 + 'speed': 37, // 图标的定义,这里对应的是icons.png中的索引 }, // ...其他略 'speed': document.getElementById('speed'), // 显示内容(数据)的定义 @@ -778,6 +802,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")) + ]); +} +``` + + + ## 多角色的支持 其实,我们的样板还能支持多角色的制作。比如《黑·白·间》之类的塔也是完全可以刻的。 @@ -786,7 +869,7 @@ if (core.flags.enableSkill) { 1. 每个角色弄一张行走图。相关信息参见[自定义事件:setHeroIcon](event#setHeroIcon:更改角色行走图)。 2. [覆盖楼传事件](#覆盖楼传事件),这样可以通过点工具栏的楼层传送按钮来切换角色。当然你也完全可以自己写一个道具,或[自定义快捷键](#自定义快捷键)来进行绑定。 -3. 将下述代码直接贴入脚本编辑 - 插件编写中。(写在`var _useEquipment = ...`之前。) +3. 将下述代码直接贴入脚本编辑 - 插件编写中。 ``` js // 所有需要保存的内容;这些保存的内容不会多角色共用,在切换时会进行恢复。 // 你也可以自行新增或删除,比如不共用金币则可以加上"money"的初始化,不共用道具则可以加上"items"的初始化, @@ -854,38 +937,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/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/editor-mobile.html b/editor-mobile.html index 89b98714..1026c9dc 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -179,6 +179,11 @@ + +
+ + +
@@ -353,7 +358,7 @@

-
+

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

-
+

-
+

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

-
+

@@ -404,6 +409,9 @@
+ + +
@@ -435,7 +443,6 @@ - 此浏览器不支持HTML5
diff --git a/editor.html b/editor.html index b5f76989..7f865e9b 100644 --- a/editor.html +++ b/editor.html @@ -178,6 +178,10 @@ +
+ + +
@@ -339,7 +343,7 @@

-
+

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

-
+

-
+

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

-
+

@@ -390,6 +394,9 @@
+ + +
@@ -421,7 +428,6 @@ - 此浏览器不支持HTML5
diff --git a/index.html b/index.html index 4e65f98a..028c5a6a 100644 --- a/index.html +++ b/index.html @@ -58,7 +58,7 @@

-
+

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

-
+

-
+

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

-
+

@@ -109,6 +109,9 @@
+ + +
@@ -140,7 +143,6 @@ - 此浏览器不支持HTML5
diff --git a/libs/actions.js b/libs/actions.js index 5b8a3ede..f41f52dc 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -192,8 +192,8 @@ 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) { @@ -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; @@ -658,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 () { @@ -780,12 +784,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; @@ -1082,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+"不足"); @@ -1103,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++; @@ -1830,19 +1828,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; @@ -1902,9 +1887,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: @@ -2249,14 +2236,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: @@ -2270,7 +2257,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 { @@ -2281,7 +2268,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: @@ -2423,6 +2410,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"); } @@ -2432,13 +2426,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/control.js b/libs/control.js index 56bdff04..d671933c 100644 --- a/libs/control.js +++ b/libs/control.js @@ -57,8 +57,10 @@ 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; core.animateFrame.weather.time = core.animateFrame.weather.time||timestamp; // move time @@ -109,28 +111,49 @@ control.prototype.setRequestAnimationFrame = function () { core.animateFrame.boxTime = timestamp; } + // selectorTime + if (timestamp-core.animateFrame.selectorTime>20 && core.isset(core.dymCanvas.selector)) { + var opacity = parseFloat(core.dymCanvas.selector.canvas.style.opacity); + if (core.animateFrame.selectorUp) + opacity += 0.02; + else + opacity -= 0.02; + if (opacity > 0.95 || opacity < 0.55) + core.animateFrame.selectorUp = !core.animateFrame.selectorUp; + core.setOpacity("selector", opacity); + core.animateFrame.selectorTime = timestamp; + } + // Animate if (timestamp-core.animateFrame.animateTime>50 && core.isset(core.status.animateObjs) && core.status.animateObjs.length>0) { 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; } // 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 @@ -203,6 +226,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; @@ -234,6 +288,10 @@ control.prototype.showStartAnimate = function (noAnimate, callback) { core.clearStatus(); core.clearMap('all'); core.clearMap('curtain'); + core.deleteAllCanvas(); + + // 重置音量 + core.events.setVolume(1, 0); if (core.flags.startUsingCanvas) { core.dom.startTop.style.display = 'none'; @@ -298,6 +356,7 @@ control.prototype.clearStatus = function() { } core.status = {}; core.clearStatusBar(); + core.deleteAllCanvas(); core.status.played = false; core.events.setHeroIcon('hero.png', true); } @@ -314,9 +373,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 @@ -336,6 +392,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, @@ -350,13 +408,15 @@ 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); else core.values = core.clone(core.data.values); core.events.initGame(); + this.updateGlobalAttribute(Object.keys(core.status.globalAttribute)); + this.triggerStatusBar(core.getFlag('hideStatusBar', false)?'hide':'show', core.getFlag("showToolbox")); core.status.played = true; } @@ -983,19 +1043,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 ////// @@ -1294,142 +1342,20 @@ 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 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 += "^"; - } - - 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.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); - } - - }) - - 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); } ////// 更改天气效果 ////// 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; @@ -1476,6 +1402,18 @@ control.prototype.setWeather = function (type, level) { }) } } + else if (type=='fog') { + if (core.animateFrame.weather.fog) { + for (var a=0;a=25) { + if (step>=steps) { delete core.animateFrame.asyncId[changeAnimate]; clearInterval(changeAnimate); core.status.curtainColor = color; // core.status.replay.animate=false; if (core.isset(callback)) callback(); } - }, time/25/core.status.replay.speed); + }, per_time); core.animateFrame.asyncId[changeAnimate] = true; } @@ -1557,51 +1495,18 @@ 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); - 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); } // 临界显伤 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); - 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); } } @@ -1625,15 +1530,8 @@ control.prototype.updateDamage = function (floorId, canvas) { for (var y=0;y0) { - damage = core.formatBigNumber(damage); - 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); + damage = core.formatBigNumber(damage, true); + core.fillBoldText(canvas, damage, "#FF7F00", 32*x+16, 32*(y+1)-14); } } } @@ -1648,11 +1546,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); @@ -1661,6 +1559,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); + } }); } @@ -2078,7 +1980,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; } @@ -2199,7 +2101,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; // 游戏开始前读档 @@ -2226,17 +2128,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"); } ////// 实际进行存读档事件 ////// @@ -2251,7 +2159,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 +2196,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) { @@ -2484,6 +2392,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])) { @@ -2602,6 +2513,8 @@ control.prototype.playBgm = function (bgm) { } try { + // 缓存BGM + core.loader.loadBgm(bgm); // 如果当前正在播放,且和本BGM相同,直接忽略 if (core.musicStatus.playingBgm == bgm && core.musicStatus.isPlaying) { return; @@ -2634,7 +2547,7 @@ control.prototype.pauseBgm = function () { core.musicStatus.isPlaying = false; } catch (e) { - console.log("无法暂停BGM "+bgm); + console.log("无法暂停BGM"); console.log(e); } } @@ -2662,7 +2575,7 @@ control.prototype.resumeBgm = function () { } } catch (e) { - console.log("无法恢复BGM "+bgm); + console.log("无法恢复BGM"); console.log(e); } } @@ -2774,16 +2687,28 @@ control.prototype.updateStatusBar = function () { } } -control.prototype.triggerStatusBar = function (name) { +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?true:null); 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) @@ -2825,31 +2750,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': @@ -2873,10 +2797,19 @@ 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.screenMode != 'vertical') useButton = false; + if (!core.domStyle.isVertical) useButton = false; core.domStyle.toolbarBtn = useButton; if (useButton) { @@ -2894,7 +2827,37 @@ 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"; + } +} + +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; @@ -2977,11 +2931,9 @@ control.prototype.resize = function(clientWidth, clientHeight) { var tempWidth = DEFAULT_CANVAS_WIDTH * scale; if(!isHorizontal){ //竖屏 core.domStyle.screenMode = 'vertical'; + core.domStyle.isVertical = true; //显示快捷商店图标 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; @@ -2989,6 +2941,8 @@ control.prototype.resize = function(clientWidth, clientHeight) { gameGroupHeight = tempWidth + tempTopBarH + tempBotBarH; gameGroupWidth = tempWidth + statusCanvasWidth = canvasWidth; + statusCanvasHeight = tempTopBarH; canvasTop = tempTopBarH; // canvasLeft = 0; toolBarWidth = statusBarWidth = canvasWidth; @@ -3014,6 +2968,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; @@ -3022,6 +2977,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; @@ -3044,6 +3001,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; @@ -3056,6 +3014,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; @@ -3091,6 +3051,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: { @@ -3105,15 +3073,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: { @@ -3157,7 +3116,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' } }, { @@ -3203,84 +3163,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: { @@ -3289,8 +3171,29 @@ 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.isVertical) { + 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; + } + if (core.isPlaying()) + core.updateStatusBar(); } ////// 渲染DOM ////// @@ -3335,5 +3238,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 f6cfe375..238ee2de 100644 --- a/libs/core.js +++ b/libs/core.js @@ -32,8 +32,12 @@ function core() { 'globalAnimate': false, 'globalTime': null, 'boxTime': null, + 'selectorTime': null, + 'selectorUp': true, 'animateTime': null, 'moveTime': null, + 'lastLegTime': null, + 'leftLeg': true, 'speed': null, 'weather': { 'time': null, @@ -41,6 +45,7 @@ function core() { 'level': 0, 'nodes': [], 'data': null, + 'fog': null, }, "asyncId": {} } @@ -53,6 +58,8 @@ function core() { 'isPlaying': false, 'gainNode': null, 'volume': 1.0, // 音量 + 'cachedBgms': [], // 缓存BGM内容 + 'cachedBgmCount': 4, // 缓存的bgm数量 } this.platform = { 'isOnline': true, // 是否http @@ -74,6 +81,8 @@ function core() { this.domStyle = { styles: [], scale: 1.0, + screenMode: null, + isVertical: false, toolbarBtn: false, showStatusBar: true, } @@ -183,6 +192,9 @@ function core() { 'animateObjs': [], }; this.status = {}; + this.dymCanvas = { + "_list": [] + }; } /////////// 系统事件相关 /////////// @@ -310,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); @@ -327,6 +339,12 @@ 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'); core.loader.load(function () { @@ -417,8 +435,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); } ////// 点击(触摸)事件按下时 ////// @@ -613,68 +631,106 @@ 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创建 ////// +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); +} +////// 删除所有canvas ////// +core.prototype.deleteAllCanvas = function () { + core.ui.deleteAllCanvas(); } core.prototype.drawBlock = function (block, animate, dx, dy) { @@ -682,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 ////// @@ -757,8 +813,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); } ////// 将某个块从启用变成禁用状态,但是并不删除它 ////// @@ -954,18 +1010,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); } ////// 字符串自动换行的分割 ////// @@ -1026,8 +1082,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); } ////// 两位数显示 ////// @@ -1081,6 +1137,11 @@ core.prototype.closePanel = function () { core.ui.closePanel(); } +////// 一般清除事件 ////// +core.prototype.clearLastEvent = function () { + core.ui.clearLastEvent(); +} + ////// 更改播放状态 ////// core.prototype.triggerReplay = function () { core.control.triggerReplay(); @@ -1355,6 +1416,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); @@ -1380,6 +1451,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/enemys.js b/libs/enemys.js index c6dd1311..cc3ca193 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]; @@ -164,9 +196,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); @@ -181,7 +211,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 / (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); if (nextInfo==null) break; if (pre>nextInfo.damage) { @@ -257,11 +289,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/events.js b/libs/events.js index a1a3184a..4e7574b0 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]}; @@ -109,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 () { @@ -117,7 +131,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 @@ -171,6 +185,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(); @@ -210,8 +226,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; @@ -344,7 +359,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 }} // 停止勇士 @@ -361,8 +376,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) { @@ -420,6 +434,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; @@ -701,29 +732,54 @@ 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 (!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(); } 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": // 显示动图 @@ -747,19 +803,14 @@ events.prototype.doAction = function() { 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.moveImage(data.code, data.to, data.opacity, data.time); + this.doAction(); } else { - this.doAction(); + core.events.moveImage(data.code, data.to, data.opacity, data.time, function() { + core.events.doAction(); + }); } } break; @@ -864,16 +915,23 @@ 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 = 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(); }); } @@ -916,6 +974,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); @@ -1053,14 +1116,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": @@ -1072,7 +1140,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": @@ -1092,13 +1160,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) { @@ -1160,6 +1224,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); } @@ -1384,10 +1450,12 @@ 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(); @@ -1514,91 +1582,150 @@ 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; + 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); + 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 { + var per_time = 10, steps = parseInt(time / per_time), per_add = opacityVal / steps; + var opacity = 0; + core.setOpacity(name, 0); + var animate = setInterval(function () { + 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(); + } + }, per_time); + + 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) { +////// 隐藏图片 ////// +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 { + var opacityVal = parseFloat(core.dymCanvas[name].canvas.style.opacity); + var per_time = 10, steps = parseInt(time / per_time), per_add = opacityVal / steps; + var animate = setInterval(function () { + 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(); + } + }, per_time); - 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.4倍行距计算 + 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.moveImage = function (code, to, opacityVal, time, callback) { time = time || 1000; - clearInterval(core.interval.tipAnimate); - core.setAlpha('data', 1); - var width = image.width, height = image.height; + 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, toX = fromX, toY = fromY; - // 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]); - - if (keep) core.clearMap('image', fromX, fromY, width, height); - - var step = 0, preX = fromX, preY = fromY; - var per_time = 10, steps = parseInt(time / per_time); - var drawImage = function () { - preX = parseInt(fromX + (toX-fromX)*step/steps); - preY = parseInt(fromY + (toY-fromY)*step/steps); - core.canvas.data.drawImage(image, preX, preY); + if (core.isset(to)) { + toX = core.calValue(to[0]) || toX; + toY = core.calValue(to[1]) || toY; } - drawImage(); + var step = 0; + var per_time = 10, steps = parseInt(time / per_time); + var preOpac = parseFloat(core.dymCanvas[name].canvas.style.opacity), opacStep = 0; + if (core.isset(opacityVal)) { + opacityVal = core.calValue(opacityVal); + opacStep = (opacityVal - preOpac) / steps; + } + + var moveStep = function () { + preOpac += opacStep; + core.setOpacity(name, preOpac); + preX = parseInt(fromX + (toX-fromX)*step/steps); + preY = parseInt(fromY + (toY-fromY)*step/steps); + core.relocateCanvas(name, preX, preY); + } 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); @@ -1622,21 +1749,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; } @@ -1743,20 +1869,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 need=core.calValue((core.firstData.levelUp[core.status.hero.lv]||{}).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); - 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); } ////// 尝试使用道具 ////// @@ -1870,13 +2005,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); + core.setFlag("equip_def_buff", core.getFlag("equip_def_buff", 1) - core.values.weakValue); + } } if (data.event.id=='curseNet') { // 咒网 if (core.hasFlag('curse')) return; diff --git a/libs/items.js b/libs/items.js index ea6fcd59..d7c5a7ff 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') { @@ -82,10 +87,11 @@ 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(); + if (!core.isset(core.status.event.id)) core.status.event.data = null; if (core.isset(callback)) callback(); } @@ -95,11 +101,18 @@ items.prototype.canUseItem = function (itemId) { // 没有道具 if (!core.hasItem(itemId)) return false; + var able = false; if (itemId in this.canUseItemEffect) { - return eval(this.canUseItemEffect[itemId]); + try { + able = eval(this.canUseItemEffect[itemId]); + } + catch (e) { + console.log(e); + } } + if (!able) core.status.event.data = null; - return false; + return able; } ////// 获得某个物品的个数 ////// @@ -107,7 +120,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; } ////// 是否存在某个物品 ////// @@ -121,7 +134,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,16 +145,17 @@ 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) { - 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(); } ////// 删除某个物品 ////// @@ -150,8 +164,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; @@ -159,7 +174,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; @@ -171,9 +186,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(); } @@ -182,28 +202,45 @@ 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; } 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'); 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); @@ -218,9 +255,6 @@ items.prototype.loadEquip = function (equipId, callback) { core.status.hero.equipment[loadEquipType] = equipId; core.updateStatusBar(); - // 记录路线 - // core.status.route.push("equip:"+equipId); - // 装备更换完毕:删除换上的装备 core.removeItem(equipId); @@ -245,10 +279,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); @@ -263,9 +297,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/loader.js b/libs/loader.js index d5a4d3d3..d5185100 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); @@ -212,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); } }); @@ -238,7 +229,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'); @@ -255,3 +246,45 @@ 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+'/'+name; + 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; + // 是否已经预加载过 + 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 diff --git a/libs/maps.js b/libs/maps.js index 2c9c5f83..b7f62b88 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]); @@ -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]); } } @@ -317,6 +321,12 @@ maps.prototype.canMoveDirectly = function (destX,destY) { // 不可瞬间移动请返回-1 if (!core.flags.enableMoveDirectly) return -1; + // 检查该楼层是否不可瞬间移动 + if (core.status.thisMap.cannotMoveDirectly) return -1; + + // flag:cannotMoveDirectly为true:不能 + if (core.hasFlag('cannotMoveDirectly')) return -1; + // 中毒状态:不能 if (core.hasFlag('poison')) return -1; @@ -360,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; @@ -476,13 +470,13 @@ 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); } ////// 绘制某张地图 ////// -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; @@ -491,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++) { @@ -503,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]]; } @@ -513,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]) { @@ -543,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'){ @@ -560,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]; @@ -766,6 +760,101 @@ 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.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, + "bodyCanvas": bodyCanvas, + "damageCanvas": damageCanvas + } +} + ////// 显示移动某块的动画,达到{“type”:”move”}的效果 ////// maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { time = time || 500; @@ -781,39 +870,12 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { core.removeBlock(x,y); block=block.block; - - 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') { + 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]; - 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 image = blockInfo.image, bx = blockInfo.bx, by = blockInfo.by, height = blockInfo.height, isTileset = blockInfo.isTileset, faceIds = blockInfo.faceIds; // 要运行的轨迹:将steps展开 var moveSteps=[]; @@ -841,9 +903,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; - 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; + + core.maps.__moveBlockCanvas(image, animateCurrent, by, height, nowX, nowY, opacity, headCanvas, bodyCanvas, damageCanvas); var animate=window.setInterval(function() { @@ -853,30 +918,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; - core.clearMap('route', nowX, nowY-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.deleteCanvas(headCanvas); + core.deleteCanvas(bodyCanvas); + core.deleteCanvas(damageCanvas); // 不消失 if (keep) { core.setBlock(id, nowX/32, nowY/32); core.showBlock(nowX/32, nowY/32); } - core.setAlpha('route',1); 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.maps.__moveBlockCanvas(image, animateCurrent, by, height, nowX, nowY, opacity, headCanvas, bodyCanvas, damageCanvas); } } else { @@ -891,13 +953,11 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { by = tby; } } - - 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.maps.__moveBlockCanvas(image, animateCurrent, by, height, nowX, nowY, opacity, headCanvas, bodyCanvas, damageCanvas); if (step==16) { // 该移动完毕,继续 step=0; @@ -924,36 +984,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'); @@ -981,35 +1017,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); @@ -1017,9 +1045,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); } } @@ -1040,65 +1066,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 animate = window.setInterval(function () { - if (type=='show') alpha += 0.1; - else alpha -= 0.1; - clear(); - if (alpha >=1 || alpha<=0) { + var per_time = 10, steps = parseInt(time / per_time), delta = 1 / steps; + var animate = setInterval(function () { + 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); @@ -1112,10 +1120,9 @@ maps.prototype.animateBlock = function (loc,type,time,callback) { if (core.isset(callback)) callback(); } else { - core.setAlpha('route', alpha); draw(); } - }, time / 10 / core.status.replay.speed); + }, per_time); core.animateFrame.asyncId[animate] = true; } @@ -1449,13 +1456,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 diff --git a/libs/ui.js b/libs/ui.js index 635d0221..575dbf24 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,144 +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, 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 = 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 core.canvas[map].canvas.style.opacity = opacity; +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 { - core.canvas[map].fillStyle = style; - } +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绘制 @@ -174,8 +182,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 +191,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,40 +366,59 @@ 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) { + w = Math.round(w), h = Math.round(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); } // 绘制皮肤 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'){ @@ -403,6 +437,11 @@ ui.prototype.calTextBoxWidth = function (canvas, content, min_width, max_width) // 如果不存在手动换行,则二分自动换行 if (allLines.length == 1) { + var w = core.canvas[canvas].measureText(allLines[0]).width; + if (w=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; @@ -715,6 +751,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.4倍行距计算 + 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) { @@ -847,7 +939,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); } @@ -865,9 +957,19 @@ 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); + core.clearLastEvent(); + + 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); @@ -880,29 +982,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, strokeLeft, bottom-35-20, len+10, 28); + else + core.strokeRect('ui', strokeLeft, bottom-35-20, len+10, 28, "#FFD700", 2); } @@ -919,8 +1027,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); @@ -966,11 +1072,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); @@ -1262,22 +1366,39 @@ ui.prototype.drawWaiting = function(text) { core.lockControl(); core.status.event.id = 'waiting'; - core.clearMap('ui'); - core.setAlpha('ui', 1); - core.setFillStyle('ui', core.material.groundPattern); + core.clearLastEvent(); + + 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); } @@ -1327,7 +1448,7 @@ ui.prototype.drawReplay = function () { ui.prototype.drawGameInfo = function () { core.status.event.id = 'gameInfo'; this.drawChoices(null, [ - "数据统计", "查看评论", "操作帮助", "关于本塔", "返回上级菜单" + "数据统计", "查看工程", "查看评论", "操作帮助", "关于本塔","下载离线版本", "返回主菜单" ]); } @@ -1381,11 +1502,7 @@ 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.clearMap('ui'); - core.setAlpha('ui', 1); + core.clearLastEvent(); core.setFillStyle('ui', core.material.groundPattern); core.fillRect('ui', 0, 0, 416, 416); @@ -1482,8 +1599,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 = '无法战斗'; @@ -1503,7 +1620,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"; @@ -1573,7 +1689,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]);}))); } } @@ -1607,7 +1723,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)) @@ -1699,8 +1815,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)'); @@ -2034,30 +2149,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); @@ -2154,8 +2280,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'); @@ -2170,8 +2296,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); @@ -2343,7 +2469,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); @@ -2379,6 +2505,11 @@ ui.prototype.drawKeyBoard = function () { core.fillText("ui", "返回游戏", 416-80, offset-3, '#FFFFFF', 'bold 15px '+globalFont); } +////// 绘制状态栏 ///// +ui.prototype.drawStatusBar = function () { + this.uidata.drawStatusBar(); +} + ////// 绘制“数据统计”界面 ////// ui.prototype.drawStatistics = function () { @@ -2448,6 +2579,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; @@ -2455,6 +2588,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) {} @@ -2555,7 +2689,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)+"点。", @@ -2587,7 +2722,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); @@ -2641,3 +2776,93 @@ ui.prototype.drawHelp = function () { ]); } +////// 动态canvas ////// + +////// 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'; + 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.dymCanvas._list.push({ + "id": name, + "style": { + "left": x, + "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; + } + return -1; +} + +////// 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)) { + 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) { + if (!core.isset(name)) return; + 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) { + if (!core.isset(name)) return; + var index = core.findCanvas(name); + if (index == -1) return; + 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/libs/utils.js b/libs/utils.js index aad199fb..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; @@ -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; + } } } @@ -735,14 +743,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 +765,12 @@ utils.prototype.show = function (obj, speed, callback) { ////// 动画使某对象消失 ////// utils.prototype.hide = function (obj, speed, callback) { - if (!core.isset(speed)) { + if (!core.isset(speed) || main.mode!='play'){ obj.style.display = 'none'; + if (core.isset(callback)) callback(); return; } - if (main.mode!='play'){ - obj.style.display = 'none'; - if (core.isset(callback)) {callback();} - return; - } + obj.style.opacity = 1; var opacityVal = 1; var hideAnimate = window.setInterval(function () { opacityVal -= 0.03; @@ -812,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 = []; @@ -819,11 +826,6 @@ utils.prototype.decodeCanvas = function (arr, width, height) { for (var i=0;i=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); + core.setFlag("equip_def_buff", core.getFlag("equip_def_buff", 1) - core.values.weakValue); + } } // 诅咒 if (core.enemys.hasSpecial(special, 14) && !core.hasFlag('curse')) { @@ -416,16 +423,20 @@ 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; } - - // 光环效果 + + // V2.5.3备注: + // 这一部分是检查光环代码的,需要对整个地图上的图块进行遍历,可能会造成不必要的性能的损耗,尤其是循环计算临界会变得非常慢。 + // 因此默认注释掉此段代码以加快游戏运行速度。 + // 如果游戏中有光环怪物存在,取消注释(或按需根据floorId加判定)即可。 + /* // 检查当前楼层所有光环怪物(数字25) var hp_delta = 0, atk_delta = 0, def_delta = 0, cnt = 0; // 遍历每个图块 @@ -449,10 +460,11 @@ 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:可以在这里新增其他的怪物数据变化 // 比如仿攻(怪物攻击不低于勇士攻击): - // if (this.hasSpecial(mon_special, 27) && mon_atk < hero_atk) { + // if (core.hasSpecial(mon_special, 27) && mon_atk < hero_atk) { // mon_atk = hero_atk; // } // 也可以按需增加各种自定义内容(比如幻塔的魔杖效果等) @@ -484,12 +496,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之中 @@ -502,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; // 如果有神圣盾免疫吸血等可以在这里写 @@ -524,38 +534,39 @@ 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; // 魔攻:战斗伤害就是怪物攻击力 - 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); // 勇士每回合对怪物造成的伤害 - 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; + // 勇士的攻击回合数;为怪物生命除以每回合伤害向上取整 var turn = Math.ceil(mon_hp / hero_per_damage); // 最终伤害:初始伤害 + 怪物对勇士造成的伤害 + 反击伤害 @@ -679,7 +690,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')) { @@ -726,6 +737,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } } break; + case 55: // 快捷键7:绑定为轻按,方便手机版操作 + core.getNextItem(); + break; case 118: // F7:开启debug模式 core.debug(); break; @@ -809,16 +823,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) { @@ -841,9 +850,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (core.flags.enableLevelUp && core.status.hero.lv=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\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);\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", @@ -411,5 +411,6 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "greenJewel": "true", "yellowJewel": "true", "skill1": "true" - } + }, + "canEquip": {} } \ No newline at end of file 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'}, // 技能:二倍斩 ////////////////////////// 门、楼梯、传送点部分 ////////////////////////// diff --git a/styles.css b/styles.css index a1505d1e..8609eedb 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; @@ -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 { @@ -254,7 +255,7 @@ p#name { position: absolute; background: #000000; overflow: hidden; - z-index: 135; + z-index: 185; } #bg { @@ -297,16 +298,12 @@ p#name { z-index: 100; } -#image { - z-index: 105; -} - #ui { - z-index: 110; + z-index: 160; } #data { - z-index: 120; + z-index: 170; } .clearfix:before, diff --git a/常用工具/便捷PS工具.exe b/常用工具/便捷PS工具.exe index 422d76fa..0fe753ae 100644 Binary files a/常用工具/便捷PS工具.exe and b/常用工具/便捷PS工具.exe differ