diff --git a/README.md b/README.md index cfc384fe..1006b2c4 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,9 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏! * [List / HTML5魔塔游戏列表](https://h5mota.com/) * [Demo / 样板效果](https://ckcz123.com/games/template/) * [Docs / 使用文档说明](https://ckcz123.github.io/mota-js/) + ![样板](./docs/img/sample0.png) ## 目录结构 @@ -53,6 +54,19 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏! ## 更新说明 +### 2018.9.18 V2.4.1 + +* [x] 增加背景层和前景层的图块绘制,多层图块可叠加 +* [x] 背景层/前景层图块的显示、隐藏、修改等事件 +* [x] 专门的装备页面(Q键开启);装备系统大改造 +* [x] 灯光和漆黑层效果,通过插件函数方式给出 +* [x] 将状态栏更新和阻激夹域的计算移动到脚本编辑中 +* [x] 增加控制免疫阻激夹域的flag:no_zone等 +* [x] 打字机效果时点击显示全部文字 +* [x] 修复更改画面色调的Bug +* [x] 修复更改剧情文本属性后读档恢复原样的问题 +* [x] 部分细节优化 + ### 2018.8.28 V2.4 * [x] 大地图的支持 @@ -293,7 +307,7 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏! - [JS代码压缩工具](http://github.com/ckcz123/JSCompressor/):能对Javascript代码进行压缩和整合,从而减少IO请求量。 - [便捷PS工具](http://github.com/ckcz123/ps/):能只用复制和粘贴来快速对素材进行PS操作。 - [地图生成器](http://github.com/ckcz123/map_generator/):能从一张截图识别出来具体的数字数组,方便复刻已有的塔。 -- [怪物数据导出器](http://github.com/ckcz123/enemy_export/):能从RMXP中带出怪物数据,以供H5使用。 +- [怪物数据导出器](http://github.com/ckcz123/enemy_export/):能从RMXP中导出怪物数据,以供H5使用。 - [伤害和临界值计算器](http://github.com/ckcz123/magic-tower-calculator/):一个能帮助计算怪物的伤害和临界值的小工具。 ## 联系我们 @@ -321,4 +335,6 @@ HTML5魔塔交流群群号: `539113091` [@fux4](https://github.com/fux4) 打通了RM和H5之间的障壁(从而使RM动画导出器和怪物数据导出器成为可能),同时也是部分新功能(如跳跃、跟随、画面震动)等的编写者。 +[@tocque](https://github.com/tocque) 装备栏的编写者。 + 以及[百度贴吧魔塔吧](https://tieba.baidu.com/f?kw=%E9%AD%94%E5%A1%94)和H5魔塔交流群`539113091`内的诸位魔塔爱好者们对本样板的大力支持! diff --git a/_server/README.md b/_server/README.md index 2d6a8d08..374db923 100644 --- a/_server/README.md +++ b/_server/README.md @@ -70,7 +70,7 @@ editor.file.editFunctions(["change","['events']['afterChangeLight']","function(x 生成表格并绑定事件的函数 ```javascript editor.mode.loc(); -editor.mode.emenyitem(); +editor.mode.enemyitem(); editor.mode.floor(); editor.mode.tower(); editor.mode.functions(); @@ -83,7 +83,7 @@ editor.mode.onmode('save');//保存 editor.mode.onmode('nextChange');//下次onmode时前端进行切换 editor.mode.onmode('loc'); -editor.mode.onmode('emenyitem'); +editor.mode.onmode('enemyitem'); editor.mode.onmode('floor'); editor.mode.onmode('tower'); editor.mode.onmode('functions'); diff --git a/_server/comment.js b/_server/comment.js index 9f7bb124..cceaf71f 100644 --- a/_server/comment.js +++ b/_server/comment.js @@ -23,7 +23,7 @@ comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "equips" ] }, - "_data": "只能取keys(钥匙) items(宝石、血瓶) constants(永久物品) tools(消耗道具) equip(装备)" + "_data": "只能取keys(钥匙) items(宝石、血瓶) constants(永久物品) tools(消耗道具) equips(装备)" }, "name": { "_leaf": true, @@ -38,36 +38,9 @@ comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_data": "道具在道具栏中显示的描述" }, "equip": { - "_leaf": false, - "_type": "object", - "_data": { - "type": { - "_leaf": true, - "_type": "textarea", - "_data": "如果是装备,其类别,与equipName按顺序对应(从0开始)" - }, - "atk": { - "_leaf": true, - "_type": "textarea", - "_data": "如果是装备,其增加的攻击数值" - }, - "def": { - "_leaf": true, - "_type": "textarea", - "_data": "如果是装备,其增加的防御数值" - }, - "mdef": { - "_leaf": true, - "_type": "textarea", - "_data": "如果是装备,其增加的魔防数值" - }, - "animate": { - "_leaf": true, - "_type": "textarea", - "_string": true, - "_data": "如果是装备,其攻击动画,仅对type为0的装备有效" - } - } + "_leaf": true, + "_type": "textarea", + "_data": "装备属性设置,仅对cls为equips有效。\n如果此项不为null,需要是一个对象,里面可含\"type\",\"atk\",\"def\",\"mdef\",\"animate\"五项,分别对应装备部位、攻防魔防和动画。\n具体详见文档(元件说明-装备)和已有的几个装备的写法。" }, } }, @@ -238,7 +211,7 @@ comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "pushBox" ] }, - "_data": "图块的默认触发器" + "_data": "该图块的默认触发器" }, "noPass": { "_leaf": true, @@ -250,7 +223,7 @@ comment_c456ea59_6018_45ef_8bcc_211a24c627dc = false ] }, - "_data": "图块默认可通行状态" + "_data": "该图块是否不可通行;true代表不可通行,false代表可通行,null代表使用系统缺省值" } } }, diff --git a/_server/editor.js b/_server/editor.js index 07741e42..6b53043a 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -709,8 +709,8 @@ editor.prototype.listen = function () { } tip.infos = JSON.parse(JSON.stringify(editor.info)); editor_mode.onmode('nextChange'); - editor_mode.onmode('emenyitem'); - //editor_mode.emenyitem(); + editor_mode.onmode('enemyitem'); + //editor_mode.enemyitem(); } } } @@ -779,7 +779,7 @@ editor.prototype.listen = function () { dataSelection.style.height = ysize - 6 + 'px'; tip.infos = JSON.parse(JSON.stringify(editor.info)); editor_mode.onmode('nextChange'); - editor_mode.onmode('emenyitem'); + editor_mode.onmode('enemyitem'); } var fields = Object.keys(editor.file.comment._data.floors._data.loc._data); diff --git a/_server/editor_mode.js b/_server/editor_mode.js index 47ddbd94..3fe44261 100644 --- a/_server/editor_mode.js +++ b/_server/editor_mode.js @@ -4,7 +4,7 @@ editor_mode = function (editor) { function editor_mode() { this.ids = { 'loc': 'left2', - 'emenyitem': 'left3', + 'enemyitem': 'left3', 'floor': 'left4', 'tower': 'left5', 'functions': 'left8', @@ -208,7 +208,7 @@ editor_mode = function (editor) { editor.drawEventBlock(); }); break; - case 'emenyitem': + case 'enemyitem': if (editor_mode.info.images == 'enemys' || editor_mode.info.images == 'enemy48') { editor.file.editEnemy(editor_mode.info.id, actionList, function (objs_) {/*console.log(objs_);*/ @@ -310,7 +310,7 @@ editor_mode = function (editor) { if (Boolean(callback)) callback(); } - editor_mode.prototype.emenyitem = function (callback) { + editor_mode.prototype.enemyitem = function (callback) { //editor.info=editor.ids[editor.indexs[201]]; if (!core.isset(editor.info)) return; diff --git a/docs/V2.0.md b/docs/V2.0.md index 2c87474d..0df0686a 100644 --- a/docs/V2.0.md +++ b/docs/V2.0.md @@ -1,6 +1,6 @@ # V2.0版本介绍 -?> 目前版本**v2.4**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.4.1**,上次更新时间:* {docsify-updated} * 目前样板已经更新到V2.0版本以上,本章将对V2.0的一些内容进行介绍。 diff --git a/docs/api.md b/docs/api.md index c7ced584..e411229f 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,6 +1,6 @@ # 附录: API列表 -?> 目前版本**v2.4**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.4.1**,上次更新时间:* {docsify-updated} * **这里只列出所有可能会被造塔者用到的常用API,更多的有关内容请在代码内进行查询。** @@ -72,8 +72,17 @@ core.setItem('pickaxe', 10) 将破墙镐个数设置为10个。这里可以写任何道具的ID。 +core.addItem('pickaxe', 2) +将破墙镐的个数增加2个,无任何特效。这里可以写任何道具的ID。 + + core.getItem('pickaxe', 4) -另勇士获得四个破墙镐。这里可以写任何道具的ID。 +令勇士获得4个破墙镐。这里可以写任何道具的ID。 +和addItem相比,使用getItem会播放获得道具的音效,也会在左上角绘制获得提示。 + + +core.removeItem('pickaxe', 3) +删除3个破墙镐。第二项可忽略,默认值为1。 core.itemCount('pickaxe') @@ -84,6 +93,15 @@ core.hasItem('pickaxe') 返回当前是否存在某个道具。等价于 core.itemCount('pickaxe')>0 。 +core.getEquip(0) +获得0号装备类型(武器)的当前装备的itemId。如果不存在则返回null。 +这里可以写任意装备类型,从0开始和全塔属性中的equipName一一对应。 + + +core.hasEquip('sword1') +获得当前某个具体的装备是否处于正在被装备状态。 + + core.setFlag('xyz', 2) 设置某个flag/变量的值为2。这里可以写任何的flag变量名。 @@ -229,12 +247,12 @@ core.canUseItem(itemId) 返回当前能否使用某个道具。 -core.addItem(itemId, number) -将某个道具增加number个。 +core.loadEquip(itemId, callback) +装备上某个装备。itemId为装备的ID,callback为成功或失败后的回调。 -core.removeItem(itemId) -将某个道具个数-1;如果道具个数归0则从道具列表删除。 +core.unloadEquip(equipType, callback) +卸下某个部位的装备。equipType为装备类型,从0开始;callback为成功或失败后的回调。 core.getNextItem() @@ -266,6 +284,11 @@ core.getLocalStorage(key, defaultValue) 从localStorage中获得某个数据(已被parse);如果对应的key不存在则返回defaultValue。 +core.getLocalForage(key, defaultValue, successCallback, errorCallback) +从localForage中获得某个数据(已被parse),如果对应的key不存在则返回defaultValue。 +如果成功则通过successCallback回调,失败则通过errorCallback回调。 + + core.clone(data) 深拷贝某个对象。 @@ -399,6 +422,10 @@ core.events.setHeroIcon(name) items.js将处理和道具相关的内容,比如道具的使用,获取和删除等等。 +core.items.compareEquipment(equipId1, equipId2) +比较两个装备的属性变化值 + + ========== core.loader.XXX 和游戏加载相关的函数 ========== loader.js将主要用来进行资源的加载,比如加载音乐、图片、动画等等。 diff --git a/docs/element.md b/docs/element.md index 882f54f5..0fd64fc8 100644 --- a/docs/element.md +++ b/docs/element.md @@ -1,6 +1,6 @@ # 元件说明 -?> 目前版本**v2.4**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.4.1**,上次更新时间:* {docsify-updated} * 在本章中,将对样板里的各个元件进行说明。各个元件主要包括道具、门、怪物、楼梯等等。 @@ -24,7 +24,58 @@ 如果需要让剑盾等变成装备,可以直接在`data.js`中设置`'equipment': true`即可。 -有关装备更为详细的资料可参见[自定义装备](personalization#自定义装备)的说明。 +从V2.4.1开始,HTML5魔塔样板终于拥有了属于自己的装备页面。 + +### 装备栏的设置,装备类型 + +在全塔属性中,有一个`equipName`项,其定义了本塔的所有可装备的装备栏。 + +其需要是一个不小于1且不大于6的数组,其中每一项为装备栏的名称,**建议是两个汉字**。 + +例如下面这种写法就是定义了四个装备孔,名称分别为武器、防御、首饰和魔杖。 + +``` js +"equipName": ["武器","防具","首饰","魔杖"] +``` + +这么定义好后,装备类型即为每个装备孔的索引(从0开始)。 + +即,武器的装备类型是0,防御的装备类型是1,首饰的装备类型是2,魔杖的装备类型是3。 + +### 设置每个装备的属性 + +如果要将一个道具设置为装备,首先需要将其`cls`设为`equips`。 + +然后在图块属性的`equip`一项中设置装备的具体属性。该项写法如下: +``` js +{"type": 0, "atk": 0, "def": 0, "mdef":0, "animate": "hand"} +``` + +type为该装备的类型,必填,和上面装备栏一一对应。例如,0就是武器,2就是首饰等等。 + +atk/def/mdef为该装备分别增加的攻防魔防数值(支持负数);如果不加也可省略不写。 + +animate为该装备的攻击动画,仅对type为0时有效。具体可参见[动画和天气系统](#动画和天气系统)。 + +下面是几个写法例子。 + +``` js +{"type": 0, "atk": 10} // 装备类型是武器,效果是攻击+10,使用默认的攻击动画 +{"type": 0, "atk": 40, "animate": "sword"} // 装备类型为武器,效果是攻击+10,攻击动画是sword +{"type": 1, "def": 40} // 装备类型是防具,效果是防御+40 +{"type": 1, "def": 100, "mdef": 100} // 装备类型是防具,效果是防御和魔防各+100 +{"type": 3, "atk": -20, "def": 50, "mdef": 50} // 装备类型是魔杖,效果是攻击-20,防御和魔防各+50 +``` + +### 检测是否存在装备 + +可以使用`core.hasEquip(itemId)`来检测是否装上某个装备。 + +使用`core.hasItem(itemId)`来检测是否存在一个未装上的装备。 + +使用`core.getEquip(equipType)`来获得某个装备类型的当前装备。 + +更多相关API详见[附录:API列表](api)。 ## 门 @@ -32,6 +83,8 @@ 开门后可触发该层的`afterOpenDoor`事件,有关事件的详细介绍请参见第四章。 +如果要新增自己的门,请参见[新增门和对应的钥匙](personalization#新增门和对应的钥匙)。 + ## 暗墙 本塔支持暗墙。 @@ -139,16 +192,26 @@ N连击怪物的special是6,且我们可以为它定义n代表实际连击数 领域怪还可以设置`range`选项代表该领域怪的范围,不写则默认为1。 +**将`flag:no_zone`设置为true可以取消领域效果。** + 阻击怪同样需要设置value,代表阻击伤害的数值。如果勇士生命值扣减到0,则直接死亡触发lose事件。 +**将`flag:no_snipe`设置为true可以取消阻击效果。** + !> 阻击怪后退的地点不能有任何事件存在,即使是已经被禁用的自定义事件! 激光怪同样需要设置value,代表激光伤害的数值。 请注意如果吸血、领域、阻击中任何两个同时存在,则value会冲突。**因此请勿将吸血、领域、阻击或激光放置在同一个怪物身上。** +**将`flag:no_laser`设置为true可以免疫激光效果。** + 退化怪需要设置'atkValue'和'defValue'表示退化的数值;也可以不设置默认为0。 +夹击可以通过全塔属性中的`betweenAttackCeil`设为true可以将伤害向上取整。 + +**将`flag:no_betweenAttack`设置为true可以免疫夹击效果。** + 固伤怪则需要设置`damage`选项,代表战前扣血数值。 如有额外需求,可参见[自定义怪物属性](personalization#自定义自定义怪物属性),里面讲了如何设置一个新的怪物属性。 diff --git a/docs/event.md b/docs/event.md index 4786774d..bc1a9561 100644 --- a/docs/event.md +++ b/docs/event.md @@ -1,6 +1,6 @@ # 事件 -?> 目前版本**v2.4**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.4.1**,上次更新时间:* {docsify-updated} * 本章内将对样板所支持的事件进行介绍。 diff --git a/docs/index.md b/docs/index.md index 4bfabadd..b4ca28de 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,6 @@ # HTML5 魔塔样板说明文档 -?> 目前版本**v2.4**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.4.1**,上次更新时间:* {docsify-updated} * 众所周知,魔塔的趋势是向移动端发展,贴吧中也常常能见到“求手机魔塔”的帖子。然而现有的工具中,NekoRPG有着比较大的局限性,游戏感较差,更是完全没法在iOS上运行。而一些APP的魔塔虽然可用,但是必须要下载安装,对于Android和iOS还必须开发不同的版本,非常麻烦。 @@ -12,9 +12,9 @@ > 这个魔塔样板,可以让你在完全不懂任何编程的情况下,做出自己的H5魔塔。不会代码?没关系!只要你想做,就能做出来! 继续查看文档的详细介绍,让你学会如何使用这一个样板来制作属于自己的HTML5魔塔。 - + ========================================================================================== [继续阅读下一章:现在就做出自己的第一部H5魔塔!](start) diff --git a/docs/personalization.md b/docs/personalization.md index be460129..87280538 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -1,6 +1,6 @@ # 个性化 -?> 目前版本**v2.4**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.4.1**,上次更新时间:* {docsify-updated} * 有时候只靠样板本身可能是不够的。我们需要一些个性化、自定义的素材,道具效果,怪物属性,等等。 @@ -308,25 +308,13 @@ function (enemy, hero_hp, hero_atk, hero_def, hero_mdef) { } // ... 下略 ``` -3. 免疫领域、夹击、阻击效果:在`control.js`中,找到checkBlock函数,并编辑成如果有神圣盾标记,则将伤害变成0。 +3. 免疫领域、夹击、阻击效果:在2.4.1之后,可以直接将flag:no_zone设为true来免疫领域效果,其他几个同理。 ``` js -// 检查领域、夹击、阻击事件 -control.prototype.checkBlock = function () { - var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'); - var damage = core.status.checkBlock.damage[x+core.bigmap.width*y]; - if (damage>0) { - if (core.hasFlag("shield5")) damage = 0; // 如果存在神圣盾,则将伤害变成0 - core.status.hero.hp -= damage; - - // 检查阻击事件 - var snipe = []; - var scan = { - 'up': {'x': 0, 'y': -1}, - 'left': {'x': -1, 'y': 0}, - 'down': {'x': 0, 'y': 1}, - 'right': {'x': 1, 'y': 0} - } -// ... 下略 +// 同样写在道具的itemEffect中 +core.setFlag("no_zone", true); // 免疫领域 +core.setFlag("no_snipe", true); // 免疫阻击 +core.setFlag("no_laser", true); // 免疫激光 +core.setFlag("no_betweenAttack", true); // 免疫夹击 ``` 4. 如果有更高的需求,例如想让吸血效果变成一半,则还是在上面这些地方进行对应的修改即可。 @@ -375,6 +363,7 @@ control.prototype.useFly = function (need) { ``` 修改时,请先把`null`改成空字符串`""`,然后再双击进行编辑。 + + ## 自定义怪物属性 如果你对现有的怪物不满意,想自行添加怪物属性也是可以的。具体参见脚本编辑-getSpecials。 diff --git a/docs/start.md b/docs/start.md index 46d5346d..6e330a4a 100644 --- a/docs/start.md +++ b/docs/start.md @@ -1,6 +1,6 @@ # 快速上手 -?> 目前版本**v2.4**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.4.1**,上次更新时间:* {docsify-updated} * 在这一节中,将详细介绍做一部塔的流程。现在,让我们来做一部单层塔! @@ -201,6 +201,8 @@ HTML5的塔都是可以进行控制台调试的。 - `core.getItem('pickaxe', 2)` 令勇士获得两个破墙镐。 - `core.itemCount('pickaxe')` 返回勇士某个道具的个数。 - `core.hasItem('pickaxe')` 返回勇士是否拥有某个道具。等价于`core.itemCount('pickaxe')!=0`。 +- `core.getEquip(0)` 返回0号装备类型(武器)的当前装备的itemId,不存在则返回null +- `core.hasEquip('sword1')` 返回某个装备当前是否处于被装备状态 - `core.setFlag('xxx', 1)` 设置某个flag/自定义变量的值。 - `core.getFlag('xxx', 10)` 获得某个flag/自定义变量的值;如果该项不存在(未被定义),则返回第二个参数的值。 - `core.hasFlag('xxx')` 返回是否存在某个变量且不为0。等价于`core.getFlag('xxx', 0)!=0`。 @@ -210,7 +212,6 @@ HTML5的塔都是可以进行控制台调试的。 - `core.getBlock(3, 5, 'MT1')` 获得当前地图上某一个块的信息。第三个参数为floorId,可省略表示当前楼层。 - `core.getBlockId(3, 5, 'MT1')` 获得当前地图上某一个点的图块ID。第三个参数为floorId,可省略表示当前楼层。 - `core.resetMap()` 重置当前层地图。**当修改地图后再读档,修改的地图不会立刻生效,此时可以使用resetMap来重置当前楼层的地图。** -- `localStorage` 获得所有的存档数据。可以用 `core.getLocalStorage('save1')` 来具体获得某个存档。 - …… 更多API和详细参数介绍可参见[API列表](api)。 diff --git a/editor-mobile.html b/editor-mobile.html index 5d5a7d8b..90b4810f 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -88,7 +88,7 @@ -
+

图块属性  

@@ -264,7 +264,7 @@ - + @@ -393,7 +393,6 @@
-
@@ -403,6 +402,7 @@ + 此浏览器不支持HTML5
@@ -449,7 +449,7 @@ if (location.protocol.indexOf("http")!=0) { editor.pos = {x: 0, y: 0}; editor.mode.loc(); editor.info = editor.ids[editor.indexs[201]]; - editor.mode.emenyitem(); + editor.mode.enemyitem(); editor.mode.floor(); editor.mode.tower(); editor.mode.functions(); diff --git a/index.html b/index.html index c97c9a8e..56128d9d 100644 --- a/index.html +++ b/index.html @@ -111,7 +111,6 @@
-
@@ -121,6 +120,7 @@ + 此浏览器不支持HTML5
diff --git a/libs/actions.js b/libs/actions.js index 53fb05ae..706eac89 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -808,6 +808,12 @@ actions.prototype.keyUpConfirmBox = function (keycode) { actions.prototype.clickAction = function (x,y) { if (core.status.event.data.type=='text') { + + // 打字机效果显示全部文字 + if (core.status.event.interval!=null) { + core.insertAction({"type": "text", "text": core.status.event.ui, "showAll": true}); + } + // 文字 core.doAction(); return; @@ -859,6 +865,10 @@ actions.prototype.keyDownAction = function (keycode) { ////// 自定义事件时,放开某个键的操作 ////// actions.prototype.keyUpAction = function (keycode) { if (core.status.event.data.type=='text' && (keycode==13 || keycode==32 || keycode==67)) { + // 打字机效果显示全部文字 + if (core.status.event.interval!=null) { + core.insertAction({"type": "text", "text": core.status.event.ui, "showAll": true}); + } core.doAction(); return; } @@ -1245,24 +1255,28 @@ actions.prototype.clickToolbox = function(x,y) { } */ var toolsPage = core.status.event.data.toolsPage; - var constantsPage = core.status.event.data.constantsPage + var constantsPage = core.status.event.data.constantsPage; // 上一页 if (x == 3 || x == 4) { - if ( y == 7 && toolsPage>1) + if (y == 7 && toolsPage>1) { core.status.event.data.toolsPage--; - if ( y == 12 && constantsPage>1) - core.status.event.data.constantsPage--; - core.ui.drawToolbox(core.status.event.selection) - return; + core.ui.drawToolbox(core.status.event.selection); + } + if (y == 12 && constantsPage>1) { + core.status.event.data.toolsPage--; + core.ui.drawToolbox(core.status.event.selection); + } } // 下一页 - if ((x == 8 || x == 9)) { - if (( y == 7 && toolsPage1) { + if (index==0) { // 处理向前翻页 + if (toolsPage > 1) { core.status.event.data.toolsPage--; index = 11; } else return; // 第一页不向前翻 - else if (index==12) - if (constantsPage>1) { + } + else if (index==12) { + if (constantsPage == 1) { + if (toolsTotalPage==0) return; + core.status.event.data.toolsPage = toolsTotalPage; + index = (tools.length+11)%12; + } + else { core.status.event.data.constantsPage--; index = 23; } - else return; + } else index -= 1 ; this.clickToolboxIndex(index); return; } if (keycode==38) { // up - if (toolsPage==toolsTotalPage&&index<18&&index>11) { // 进入tools + if (index>=12&&index<=17) { // 进入tools if (toolsTotalPage==0) return; - if (tools.length%12<=6 && tools.length%12>index%12) index -= 12; - else if (tools.length%12>6 && tools.length%6>index%12) index -= 6; - else index = tools.length%12-1; + if (toolsLastIndex>=6) index = Math.min(toolsLastIndex, index-6); + else index = Math.min(toolsLastIndex, index-12); } else if (index<6) return; // 第一行没有向上 else index -= 6; @@ -1349,28 +1370,33 @@ actions.prototype.keyDownToolbox = function (keycode) { core.status.event.data.constantsPage++; index = 12; } - else if((toolsPage==toolsTotalPage && index==tools.length%12-1) || - (constantsPage==constantsTotalPage && index==constants.length%12+11)) // 一个物品无操作 + else if (index == toolsLastIndex) { + if (constantsTotalPage==0) return; + core.status.event.data.constantsPage = 1; + index = 12; + } + else if(index==constantsLastIndex) // 一个物品无操作 return; - else index +=1; + else index++; this.clickToolboxIndex(index); return; } if (keycode==40) { // down - if ((index>5 || (toolsPage==toolsTotalPage && tools.length%12<=6)) && index<12) {// 进入constant - if (constantsTotalPage == 0) return; - if (constantsTotalPage == constantsPage && constants.length%12<(index%6+1)) - index = constants.length%12+11; - else if (index<6) index += 12; - else index += 6; + var nextIndex = null; + if (index<=5) { + if (toolsLastIndex > 5) nextIndex = Math.min(toolsLastIndex, index + 6); + else index+=6; + } + if (nextIndex==null && index<=11) { + if (constantsTotalPage == 0) return; + nextIndex = Math.min(index+6, constantsLastIndex); + } + if (nextIndex==null && index<=17) { + if (constantsLastIndex > 17) nextIndex = Math.min(constantsLastIndex, index+6); + } + if (nextIndex!=null) { + this.clickToolboxIndex(nextIndex); } - else if (toolsPage==toolsTotalPage && tools.length%12>6 && index > tools.length%6 &&index<6) - index = tools.length%12-1; - else if (constantsPage==constantsTotalPage && constants.length%12>6 && index>constants.length%6+11 && index<18) - index = constants.length%12+11; - else if (index>17 || (constantsPage==constantsTotalPage && constants.length%12<=6 && index>11)) return;//最后一行无操作 - else index += 6; - this.clickToolboxIndex(index); return; } } @@ -1438,43 +1464,41 @@ actions.prototype.clickEquipbox = function(x,y) { // 下一页 if ((x == 8 || x == 9) && y == 12) { var lastPage = Math.ceil(Object.keys(core.status.hero.items.equips).length/12); - if (page=0) + if (index>=0) { + if (index<12) index = parseInt(index/2); this.clickEquipboxIndex(index); + } } ////// 选择装备栏界面中某个Index后的操作 ////// actions.prototype.clickEquipboxIndex = function(index) { - if (index<12) { - if (index>=core.status.hero.equipment.length) return; - if (index==core.status.event.selection && core.status.hero.equipment[index] != "blank") { + if (index<6) { + if (index>=(main.equipName||[]).length) return; + if (index==core.status.event.selection && core.isset(core.status.hero.equipment[index])) { core.unloadEquip(index); + core.status.route.push("unEquip:"+index); } } - else { - var equips = null; - equips = Object.keys(core.status.hero.items.equips).sort(); - if (equips==null) return; - if (index>=equips.length+12) return; + else if (index>=12) { + var equips = Object.keys(core.status.hero.items.equips||{}).sort(); if (index==core.status.event.selection) { - var equipId = equips[index-12]; + var equipId = equips[index-12 + (core.status.event.data.page-1)*12]; core.loadEquip(equipId); - equips = Object.keys(core.status.hero.items.equips).sort(); - if ( equips.length == 0) - index = core.status.hero.equipment.length-1; + core.status.route.push("equip:"+equipId); } } core.ui.drawEquipbox(index); @@ -1484,35 +1508,36 @@ actions.prototype.clickEquipboxIndex = function(index) { actions.prototype.keyDownEquipbox = function (keycode) { if (!core.isset(core.status.event.data)) return; - var equipCapacity = core.status.hero.equipment.length; + var equipCapacity = (main.equipName||[]).length; var ownEquipment = Object.keys(core.status.hero.items.equips).sort(); var index = core.status.event.selection; var page = core.status.event.data.page; var totalPage = Math.ceil(ownEquipment.length/12); + var totalLastIndex = 12+(page1) { + if (index==12) { + if (page > 1) { core.status.event.data.page--; index = 23; } - else if (page==1) - index = equipCapacity-1; + else if (page == 1) + index = equipCapacity - 1; else return; + } else index -= 1; this.clickEquipboxIndex(index); return; } if (keycode==38) { // up - if (index<18 && index>11) { // 进入当前装备 - index = Math.ceil((index-12)/2); - if (equipCapacity<=3 && equipCapacity>index) index += 0; - else if (equipCapacity>3 && equipCapacity>index) index += 3; - else index = equipCapacity-1; + if (index<3) return; + else if (index<6) index -= 3; + else if (index < 18) { + index = parseInt((index-12)/2); + if (equipCapacity>3) index = Math.min(equipCapacity-1, index + 3); + else index = Math.min(equipCapacity-1, index); } - else if (index<3) return; // 第一行没有向上 - else if (index<12) index -= 3; else index -= 6; this.clickEquipboxIndex(index); return; @@ -1522,28 +1547,31 @@ actions.prototype.keyDownEquipbox = function (keycode) { core.status.event.data.page++; index = 12; } - else if (index==equipCapacity-1 && totalPage>0) + else if (index==equipCapacity-1) { + if (totalPage==0) return; index = 12; - else if (page==totalPage && index==ownEquipment.length%12+11) + } + else if (index==totalLastIndex) return; - else index += 1; + else index++; this.clickEquipboxIndex(index); return; } if (keycode==40) { // down - if ((index>2 || equipCapacity<=3) && index<12) {// 进入拥有装备 - index = (index%3)*2+13; - if (totalPage == 0) return; - if (totalPage == page && ownEquipment.length%12<(index%6+1)) - index = ownEquipment.length%12+11; + if (index<3) { + if (equipCapacity>3) index = Math.min(index+3, equipCapacity-1); + else { + if (totalPage == 0) return; + index = Math.min(2*index+1+12, totalLastIndex); + } } - else if (equipCapacity>3 && equipCapacity%36 && index>ownEquipment.length%6+11 && index<18) - index = ownEquipment.length%12+11; - else if (index>17 || (totalPage==page && ownEquipment.length%12<=6 && index>11)) return;//最后一行无操作 - else if (index<12) index += 3; - else index += 6; + else if (index < 6) { + if (totalPage == 0) return; + index = Math.min(2*(index-3)+1+12, totalLastIndex); + } + else if (index < 18) + index = Math.min(index+6, totalLastIndex); + else return; this.clickEquipboxIndex(index); return; } diff --git a/libs/control.js b/libs/control.js index 8b9bc67b..962c6c09 100644 --- a/libs/control.js +++ b/libs/control.js @@ -187,8 +187,6 @@ control.prototype.showStartAnimate = function (callback) { core.dom.startButtonGroup.style.display = 'none'; core.dom.startButtons.style.display = 'block'; core.dom.levelChooseButtons.style.display = 'none'; - core.dom.curtain.style.background = "#000000"; - core.dom.curtain.style.opacity = 0; core.status.played = false; core.clearStatus(); core.clearMap('all'); @@ -1451,8 +1449,9 @@ control.prototype.setFg = function(color, time, callback) { if (time==0) { // 直接变色 - core.dom.curtain.style.background = core.arrayToRGB(color); - core.dom.curtain.style.opacity = color[3]; + core.clearMap('curtain'); + core.setAlpha('curtain', color[3]); + core.fillRect('curtain', 0, 0, 416, 416, core.arrayToRGB(color)); core.status.curtainColor = color; if (core.isset(callback)) callback(); return; @@ -1467,8 +1466,9 @@ control.prototype.setFg = function(color, time, callback) { var nowR = parseInt(fromColor[0]+(color[0]-fromColor[0])*step/25); var nowG = parseInt(fromColor[1]+(color[1]-fromColor[1])*step/25); var nowB = parseInt(fromColor[2]+(color[2]-fromColor[2])*step/25); - core.dom.curtain.style.background = core.arrayToRGB([nowR,nowG,nowB]); - core.dom.curtain.style.opacity = nowAlpha; + core.clearMap('curtain'); + core.setAlpha('curtain', nowAlpha); + core.fillRect('curtain', 0, 0, 416, 416, core.arrayToRGB([nowR,nowG,nowB])); if (step>=25) { clearInterval(changeAnimate); @@ -1857,22 +1857,25 @@ control.prototype.replay = function () { } } else if (action.indexOf("unEquip:")==0) { - var unloadEquipId = action.substring(8); - var equipType = core.material.items[unloadEquipId].equip.type; - core.ui.drawEquipbox(equipType); - setTimeout(function () { - core.ui.closePanel(); - core.unloadEquip(equipType, function () { - core.replay(); - }); - }, 750 / Math.max(1, core.status.replay.speed)); - return; + var equipType = parseInt(action.substring(8)); + if (core.isset(equipType)) { + core.ui.drawEquipbox(equipType); + core.status.route.push(action); + setTimeout(function () { + core.ui.closePanel(); + core.unloadEquip(equipType, function () { + core.replay(); + }); + }, 750 / Math.max(1, core.status.replay.speed)); + return; + } } else if (action.indexOf("equip:")==0) { var equipId = action.substring(6); var ownEquipment = Object.keys(core.status.hero.items.equips).sort(); var index = ownEquipment.indexOf(equipId); if (index>=0) { + core.status.route.push(action); core.status.event.data = {"page":Math.floor(index/12)+1, "selectId":null}; index = index%12+12; core.ui.drawEquipbox(index); @@ -2365,6 +2368,8 @@ control.prototype.loadData = function (data, callback) { } } + core.status.textAttribute = core.getFlag('textAttribute', core.status.textAttribute); + // load icons var icon = core.getFlag("heroIcon", "hero.png"); if (core.isset(core.material.images.images[icon])) { @@ -2638,8 +2643,6 @@ control.prototype.updateStatusBar = function () { core.statusBar.image.settings.src = core.statusBar.icons.settings.src; } - - core.updateDamage(); } ////// 屏幕分辨率改变后重新自适应 ////// @@ -2841,6 +2844,7 @@ control.prototype.resize = function(clientWidth, clientHeight) { height:(canvasWidth - SPACE*2) + unit, } }, + /* { id: 'curtain', rules: { @@ -2848,6 +2852,7 @@ control.prototype.resize = function(clientWidth, clientHeight) { height:(canvasWidth - SPACE*2) + unit, } }, + */ { id: 'gameDraw', rules: { diff --git a/libs/core.js b/libs/core.js index 1c6a8625..f3155dd9 100644 --- a/libs/core.js +++ b/libs/core.js @@ -834,8 +834,13 @@ core.prototype.hasItem = function (itemId) { } ////// 是否装备某件装备 ////// -core.prototype.hasEquip = function (equipId) { - return core.items.hasEquip(equipId); +core.prototype.hasEquip = function (itemId) { + return core.items.hasEquip(itemId); +} + +////// 获得某个装备类型的当前装备 ///// +core.prototype.getEquip = function (equipType) { + return core.items.getEquip(equipType); } ////// 设置某个物品的个数 ////// @@ -844,8 +849,8 @@ core.prototype.setItem = function (itemId, itemNum) { } ////// 删除某个物品 ////// -core.prototype.removeItem = function (itemId) { - return core.items.removeItem(itemId); +core.prototype.removeItem = function (itemId, itemNum) { + return core.items.removeItem(itemId, itemNum); } ////// 使用某个物品 ////// diff --git a/libs/events.js b/libs/events.js index f1a585a0..e55bcee9 100644 --- a/libs/events.js +++ b/libs/events.js @@ -280,6 +280,7 @@ events.prototype.doAction = function() { // 清空boxAnimate和UI层 core.status.boxAnimateObjs = []; clearInterval(core.status.event.interval); + core.status.event.interval = null; core.clearMap('ui'); core.setAlpha('ui', 1.0); @@ -328,7 +329,7 @@ events.prototype.doAction = function() { if (core.status.replay.replaying) core.events.doAction(); else - core.ui.drawTextBox(data.text); + core.ui.drawTextBox(data.text, data.showAll); break; case "autoText": if (core.status.replay.replaying) @@ -356,6 +357,7 @@ events.prototype.doAction = function() { if (core.isset(data.time)) { core.status.textAttribute.time=data.time; } + core.setFlag('textAttribute', core.status.textAttribute); core.events.doAction(); break; case "tip": @@ -1234,15 +1236,17 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback var color = core.floors[floorId].color; // 直接变色 - core.dom.curtain.style.background = core.arrayToRGB(color); + core.clearMap('curtain'); if (core.isset(color[3])) - core.dom.curtain.style.opacity = color[3]; - else core.dom.curtain.style.opacity=1; + core.setAlpha('curtain', color[3]); + else + core.setAlpha('curtain', 1); + core.fillRect('curtain', 0, 0, 416, 416, core.arrayToRGB(color)); core.status.curtainColor = color; } else { - core.dom.curtain.style.background = "#000000"; - core.dom.curtain.style.opacity = 0; + core.clearMap('curtain'); + core.setAlpha('curtain', 0); } } diff --git a/libs/items.js b/libs/items.js index fe052929..3d0fdef6 100644 --- a/libs/items.js +++ b/libs/items.js @@ -97,17 +97,23 @@ items.prototype.hasItem = function (itemId) { } ////// 是否装备某件装备 ////// -items.prototype.hasEquip = function (equipId) { +items.prototype.hasEquip = function (itemId) { - if (!core.isset(equipId)) return null; - if (!core.isset((core.material.items[equipId]||{}).equip)) return null; + if (!core.isset(itemId)) return null; + if (!core.isset((core.material.items[itemId]||{}).equip)) return null; - var equiptype = core.material.items[equipId].equip.type; - return equipId == (core.status.hero.equipment||[])[equiptype]; + return itemId == this.getEquip(core.material.items[itemId].equip.type); +} + +////// 获得某个装备类型的当前装备 ////// +items.prototype.getEquip = function (equipType) { + return (core.status.hero.equipment||[])[equipType]||null; } ////// 设置某个物品的个数 ////// 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])) { @@ -120,11 +126,12 @@ items.prototype.setItem = function (itemId, itemNum) { } ////// 删除某个物品 ////// -items.prototype.removeItem = function (itemId) { +items.prototype.removeItem = function (itemId, itemNum) { + itemNum = itemNum || 1; if (!core.hasItem(itemId)) return false; var itemCls = core.material.items[itemId].cls; - core.status.hero.items[itemCls][itemId]--; - if (itemCls!='keys' && core.status.hero.items[itemCls][itemId]==0) { + core.status.hero.items[itemCls][itemId]-=itemNum; + if (itemCls!='keys' && core.status.hero.items[itemCls][itemId]<=0) { delete core.status.hero.items[itemCls][itemId]; } core.updateStatusBar(); @@ -178,7 +185,7 @@ items.prototype.loadEquip = function (equipId, callback) { core.updateStatusBar(); // 记录路线 - core.status.route.push("equip:"+equipId); + // core.status.route.push("equip:"+equipId); // 装备更换完毕:删除换上的装备 core.removeItem(equipId); @@ -187,7 +194,7 @@ items.prototype.loadEquip = function (equipId, callback) { if (core.isset(unloadEquipId)) core.addItem(unloadEquipId, 1); - core.log("已装备上"+loadEquip.name, core.material.icons.items[equipId]); + core.drawTip("已装备上"+loadEquip.name, core.material.icons.items[equipId]); if (core.isset(callback)) callback(); } @@ -217,7 +224,7 @@ items.prototype.unloadEquip = function (equipType, callback) { core.updateStatusBar(); // 记录路线 - core.status.route.push("unEquip:"+unloadEquipId); + // core.status.route.push("unEquip:"+equipType); // 装备更换完毕:增加卸下的装备 core.addItem(unloadEquipId, 1); diff --git a/libs/maps.js b/libs/maps.js index 6ad50ff5..69c138d7 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -74,7 +74,7 @@ maps.prototype.addInfo = function (block) { block.event.trigger = 'getItem'; } if (!core.isset(block.event.noPass)) { - if (block.event.cls.indexOf("enemy")==0 || block.event.cls.indexOf("npc")==0 || block.event.cls=='terrains') { + if (block.event.cls.indexOf("enemy")==0 || block.event.cls.indexOf("npc")==0 || block.event.cls=='terrains' || block.event.cls=='autotile') { block.event.noPass = true; } } diff --git a/libs/ui.js b/libs/ui.js index 68d7c2d7..eb94dcdf 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -18,6 +18,8 @@ ui.prototype.init = function () { ui.prototype.clearMap = function (map, x, y, width, height) { if (map == 'all') { for (var m in core.canvas) { + // 不擦除curtain层 + if (m=='curtain') continue; core.canvas[m].clearRect(0, 0, core.bigmap.width*32, core.bigmap.height*32); } core.dom.gif.innerHTML = ""; @@ -282,9 +284,14 @@ ui.prototype.drawText = function (contents, callback) { } ////// 绘制一个对话框 ////// -ui.prototype.drawTextBox = function(content) { +ui.prototype.drawTextBox = function(content, showAll) { + + if (core.isset(core.status.event) && core.status.event.id=='action') { + core.status.event.ui = content; + } clearInterval(core.status.event.interval); + core.status.event.interval = null; // 获得name, image, icon var id=null, name=null, image=null, icon=null, iconHeight=32, animate=null; @@ -541,7 +548,7 @@ ui.prototype.drawTextBox = function(content) { } - if (textAttribute.time<=0 || core.status.event.id!='action') { + if (showAll || textAttribute.time<=0 || core.status.event.id!='action') { drawContent(content); } else { @@ -550,6 +557,7 @@ ui.prototype.drawTextBox = function(content) { drawContent(content.substring(0, ++index)); if (index==content.length) { clearInterval(core.status.event.interval); + core.status.event.interval = null; } }, textAttribute.time); } @@ -559,6 +567,8 @@ ui.prototype.drawTextBox = function(content) { ////// 绘制一个选项界面 ////// ui.prototype.drawChoices = function(content, choices) { + choices = choices || []; + var background = core.canvas.ui.createPattern(core.material.ground, "repeat"); core.clearMap('ui'); @@ -569,7 +579,15 @@ ui.prototype.drawChoices = function(content, choices) { // Step 1: 计算长宽高 var length = choices.length; - var left=85, width = 416-2*left; // 宽度 + + // 宽度计算:考虑选项的长度 + var width = 416 - 2*85; + core.setFont('ui', "bold 17px Verdana"); + for (var i = 0; i < choices.length; i++) { + width = Math.max(width, core.canvas.ui.measureText(core.replaceText(choices[i].text || choices[i])).width + 30); + } + + var left=parseInt((416 - width) / 2); // 左边界 // 高度 var height = 32*(length+2), bottom = 208+height/2; if (length%2==0) bottom+=16; @@ -685,8 +703,9 @@ ui.prototype.drawChoices = function(content, choices) { content_top = top+55; var title_offset = left+width/2; // 动画 + if (id=='hero' || core.isset(icon)) - title_offset += 22; + title_offset += 12; if (id == 'hero') { var heroHeight = core.material.icons.hero.height; @@ -1206,7 +1225,9 @@ ui.prototype.drawReplay = function () { ////// 绘制分页 ////// ui.prototype.drawPagination = function (page, totalPage, top) { - if (totalPage <= 1) return; + // if (totalPage0) index=0; + if (equipLength>0 && core.isset(equipEquipment[0])) index=0; else if (ownEquipment.length>0) index=12; else index=0; } - core.status.event.selection=index; - - var selectId; + if (index>=12 && ownEquipment.length==0) index = 0; + var selectId=null; if (index<12) { - if (index>=equipEquipment.length) index=Math.max(0, equipEquipment.length-1); - selectId = equipEquipment[index]; + if (index >= equipLength) index=Math.max(0, equipLength - 1); + selectId = equipEquipment[index]||null; } else { - if (index+12*(page-2)>=ownEquipment.length) index=12+Math.max(0, ownEquipment.length%12-1); - selectId = ownEquipment[index-12]; + if (page == totalPage) index = Math.min(index, (ownEquipment.length+11)%12+12); + selectId = ownEquipment[index-12 + (page-1)*12]; if (!core.hasItem(selectId)) selectId=null; } + core.status.event.selection=index; core.status.event.data.selectId=selectId; core.clearMap('ui', 0, 0, 416, 416); @@ -1792,16 +1820,17 @@ ui.prototype.drawEquipbox = function(index) { core.canvas.ui.textAlign = 'left'; - console.log(equipEquipment[0]); // 描述 if (core.isset(selectId)) { var equip=core.material.items[selectId]; - core.fillText('ui', equip.name, 10, 32, '#FFD700', "bold 20px Verdana") + if (!core.isset(equip.equip)) equip.equip = {"type": 0}; + var equipType = equip.equip.type; + core.fillText('ui', equip.name + "(" + (allEquips[equipType]||"未知部位") + ")", 10, 32, '#FFD700', "bold 20px Verdana") var text = equip.text||"该装备暂无描述。"; var lines = core.splitLines('ui', text, 406, '17px Verdana'); - core.fillText('ui', lines[0], 10, 62, '#FFFFFF', '17px Verdana'); + core.fillText('ui', lines[0], 10, 62, '#FFFFFF', '17px Verdana'); // 比较属性 if (lines.length==1) { @@ -1810,43 +1839,20 @@ ui.prototype.drawEquipbox = function(index) { else { compare = core.compareEquipment(selectId, equipEquipment[equip.equip.type]); } - // 绘制 - var drawList; //= [['攻击',atk],['防御',def],['魔防',mdef]]; - var drawPointer = 0; - var color; - if (compare.atk!=0) { - if (compare.atk>0) color = '#00FF00'; - else color = '#FF0000'; - drawList = '攻击 '+core.status.hero.atk+'->'; - core.fillText('ui', drawList, 10+drawPointer, 89, '#CCCCCC', 'bold 14px Verdana'); - drawPointer += core.canvas.ui.measureText(drawList).width; + var drawOffset = 10; - drawList = (core.status.hero.atk+compare.atk)+' '; - core.fillText('ui', drawList, 10+drawPointer, 89, color, 'bold 14px Verdana'); - drawPointer += core.canvas.ui.measureText(drawList).width; - } - if (compare.def!=0) { - if (compare.def>0) color = '#00FF00'; - else color = '#FF0000'; - drawList = '防御 '+core.status.hero.atk+'->'; - core.fillText('ui', drawList, 10+drawPointer, 89, '#CCCCCC', 'bold 14px Verdana'); - drawPointer += core.canvas.ui.measureText(drawList).width; - - drawList = (core.status.hero.atk+compare.def)+' '; - core.fillText('ui', drawList, 10+drawPointer, 89, color, 'bold 14px Verdana'); - drawPointer += core.canvas.ui.measureText(drawList).width; - } - if (compare.mdef!=0) { - if (compare.mdef>0) color = '#00FF00'; - else color = '#FF0000'; - drawList = '魔防 '+core.status.hero.atk+'->'; - core.fillText('ui', drawList, 10+drawPointer, 89, '#CCCCCC', 'bold 14px Verdana'); - drawPointer += core.canvas.ui.measureText(drawList).width; - - drawList = (core.status.hero.atk+compare.mdef)+' '; - core.fillText('ui', drawList, 10+drawPointer, 89, color, 'bold 14px Verdana'); - drawPointer += core.canvas.ui.measureText(drawList).width; - } + [['攻击','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 content = title + ' ' + core.getStatus(name) + '->'; + core.fillText('ui', content, drawOffset, 89, '#CCCCCC', 'bold 14px Verdana'); + drawOffset += core.canvas.ui.measureText(content).width; + var newValue = core.getStatus(name) + compare[name] + ""; + core.fillText('ui', newValue, drawOffset, 89, color); + drawOffset += core.canvas.ui.measureText(newValue).width + 15; + }) } else { var leftText = text.substring(lines[0].length); @@ -1858,34 +1864,33 @@ ui.prototype.drawEquipbox = function(index) { var images = core.material.images.items; // 当前装备 - for (var i = 0 ; i < core.status.hero.equipment.length ; i++) { - var equipId = core.status.hero.equipment[i]; + for (var i = 0 ; i < equipLength ; i++) { + var equipId = equipEquipment[i] || null; if (core.isset(equipId)) { var icon = core.material.icons.items[equipId]; - core.canvas.ui.drawImage(images, 0, icon*32, 32, 32, 16*(8*(i%3)+5)+5, 144+Math.floor(i/3)*64+5-ydelta, 32, 32); + core.canvas.ui.drawImage(images, 0, icon*32, 32, 32, 16*(8*(i%3)+5)+5, 144+Math.floor(i/3)*54+5-ydelta, 32, 32); } - core.fillText('ui', main.equipName[i], 16*(8*(i%3)+1)+40, 144+Math.floor(i/3)*64+32-ydelta, '#FFFFFF', "bold 16px Verdana"); - if (index == i) - core.strokeRect('ui', 16*(8*(i%3)+5)+1, 144+Math.floor(i/3)*64+1-ydelta, 40, 40, '#FFD700'); + core.fillText('ui', allEquips[i]||"未知", 16*(8*(i%3)+1)+40, 144+Math.floor(i/3)*54+32-ydelta, '#FFFFFF', "bold 16px Verdana"); + core.strokeRect('ui', 16*(8*(i%3)+5)+1, 144+Math.floor(i/3)*54+1-ydelta, 40, 40, index==i?'#FFD700':"#FFFFFF"); } // 现有装备 for (var i=0;i<12;i++) { var ownEquip=ownEquipment[12*(page-1)+i]; - if (!core.isset(ownEquip)) break; + if (!core.isset(ownEquip)) continue; var icon=core.material.icons.items[ownEquip]; - core.canvas.ui.drawImage(images, 0, icon*32, 32, 32, 16*(4*(i%6)+1)+5, 304+Math.floor(i/6)*64+5-ydelta, 32, 32) + core.canvas.ui.drawImage(images, 0, icon*32, 32, 32, 16*(4*(i%6)+1)+5, 304+Math.floor(i/6)*54+5-ydelta, 32, 32) // 个数 if (core.itemCount(ownEquip)>1) - core.fillText('ui', core.itemCount(ownEquip), 16*(4*(i%6)+1)+40, 304+Math.floor(i/6)*64+38-ydelta, '#FFFFFF', "bold 14px Verdana"); - if (selectId == ownEquip) - core.strokeRect('ui', 16*(4*(i%6)+1)+1, 304+Math.floor(i/6)*64+1-ydelta, 40, 40, '#FFD700'); + core.fillText('ui', core.itemCount(ownEquip), 16*(4*(i%6)+1)+40, 304+Math.floor(i/6)*54+38-ydelta, '#FFFFFF', "bold 14px Verdana"); + if (index>=12 && selectId == ownEquip) + core.strokeRect('ui', 16*(4*(i%6)+1)+1, 304+Math.floor(i/6)*54+1-ydelta, 40, 40, '#FFD700'); } this.drawPagination(page, totalPage, 12); // 道具栏 core.canvas.ui.textAlign = 'center'; - core.fillText('ui', '道具栏', 370, 19,'#DDDDDD', 'bold 15px Verdana'); + core.fillText('ui', '[道具栏]', 370, 25,'#DDDDDD', 'bold 15px Verdana'); // 退出按钮 core.fillText('ui', '返回游戏', 370, 403,'#DDDDDD', 'bold 15px Verdana'); } diff --git a/libs/utils.js b/libs/utils.js index 3551cea1..9a05a0a1 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -325,7 +325,7 @@ utils.prototype.encodeRoute = function (route) { if (t.indexOf('item:')==0) ans+="I"+t.substring(5)+":"; else if (t.indexOf('unEquip:')==0) - ans+="u"+t.substring(8)+":"; + ans+="u"+t.substring(8); else if (t.indexOf('equip:')==0) ans+="e"+t.substring(6)+":"; else if (t.indexOf('fly:')==0) @@ -387,7 +387,7 @@ utils.prototype.decodeRoute = function (route) { while (index=core.bigmap.width || ny<0 || ny>=core.bigmap.height) continue; + // 如果是十字领域,则还需要满足 |dx|+|dy|<=range if (!zoneSquare && Math.abs(dx)+Math.abs(dy)>range) continue; core.status.checkBlock.damage[nx+ny*core.bigmap.width]+=enemy.value||0; } @@ -574,6 +595,7 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 存在激光 // 如果要防止激光伤害,可以直接简单的将 flag:no_laser 设为true if (core.enemys.hasSpecial(enemy.special, 24) && !core.hasFlag("no_laser")) { + // 检查同行和同列,增加激光伤害值 for (var nx=0;nx0 && x0 && y1) core.status.checkBlock.damage[x+core.bigmap.width*y] += Math.floor((leftHp+(core.flags.betweenAttackCeil?0:1))/2); } @@ -635,9 +662,9 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } } } - }, - "ui": { - "drawAbout": function() { + }, + "ui": { + "drawAbout": function() { // 绘制“关于”界面 if (!core.isPlaying()) { core.status.event = {'id': null, 'data': null}; @@ -664,9 +691,9 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.fillText('ui', 'HTML5魔塔交流群:539113091', text_start, top+112+32); // TODO: 写自己的“关于”页面,每次增加32像素即可 } - }, - "plugins": { - "plugin": function () { + }, + "plugins": { + "plugin": function () { ////// 插件编写,可以在这里写自己额外需要执行的脚本 ////// // 在这里写的代码,在所有模块加载完毕后,游戏开始前会被执行 @@ -677,12 +704,76 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 在这里写所有需要自定义的函数 // 写法必须是 this.xxx = function (args) { ... // 如果不写this的话,函数将无法被外部所访问 - this.test = function () { + this.test = function () { console.log("插件函数执行测试"); + }; + + + // 绘制灯光/漆黑层效果。调用方式 core.plugin.drawLight(...) + // 【参数说明】 + // color:可选,灯光以外部分的颜色,可以是一个四元数组,或者简单的一个0到1之间的数。忽略则默认为0.9。 + // 如果是四元数组,则代表RGBA值,如 [255,255,0,0.2] 就代表 #FFFF00 且不透明度0.2 + // 如果是一个数,则只是不透明度的值,RGB均为0,如 0.9 就代表 [0,0,0,0.9] + // lights:可选,一个数组,定义了每个独立的灯光。 + // 其中每一项是三元组 [x,y,r] 或者四元组 [x,y,r,o] + // x和y分别为该灯光的横纵坐标,r为该灯光的半径,o为该灯光中心的不透明度,可忽略默认为0。 + // lightDec:可选,0到1之间,光从多少百分比才开始衰减(在此范围内保持全亮),不设置默认为0。 + // 比如lightDec为0.5代表,每个灯光部分内圈50%的范围全亮,50%以后才开始快速衰减。 + // 【调用样例】 + // core.plugin.drawLight(); // 绘制一个0.9的全图不透明度,等价于更改画面色调为[0,0,0,0.9]。 + // core.plugin.drawLight(0.95, [[25,11,46]]); // 全图不透明度0.95,其中在(25,11)点存在一个半径为46的灯光效果。 + // core.plugin.drawLight([255,255,0,0.2], [[25,11,46,0.1]]); // 全图为不透明度0.2的黄色,其中在(25,11)点存在一个半径为46的灯光效果,灯光中心不透明度0.1。 + // core.plugin.drawLight(0.9, [[25,11,46],[105,121,88],[301,221,106]]); // 存在三个灯光效果,分别是中心(25,11)半径46,中心(105,121)半径88,中心(301,221)半径106。 + // core.plugin.drawLight([0,0,255,0.3], [[25,11,46],[105,121,88,0.2]], 0.4); // 存在两个灯光效果,它们在内圈40%范围内保持全亮,且40%后才开始衰减。 + // 【注意事项】 + // 此函数会和更改画面色调发生冲突,请只选择一个使用。 + this.drawLight = function (color, lights, lightDec) { + // 清空色调层 + var ctx = core.canvas.curtain; + ctx.mozImageSmoothingEnabled = false; + ctx.webkitImageSmoothingEnabled = false; + ctx.msImageSmoothingEnabled = false; + ctx.imageSmoothingEnabled = false; + core.clearMap('curtain'); + core.setOpacity('curtain', 1); + core.setAlpha('curtain', 1); + + // 绘制色调层,默认不透明度 + if (!core.isset(color)) color = 0.9; + if (typeof color == "number") color = [0,0,0,color]; + core.fillRect('curtain', 0, 0, 416, 416, + 'rgba('+color[0]+','+color[1]+','+color[2]+','+core.clamp(color[3],0,1)+')'); + + // 绘制每个灯光效果 + if (!core.isset(lights) || lights.length==0) return; + lightDec = core.clamp(lightDec, 0, 1); + lights.forEach(function (light) { + // 坐标,半径,中心不透明度 + var x = light[0], y = light[1], r = light[2], o = 255 * (1 - core.clamp(light[3], 0, 1)); + // 计算衰减距离 + var decDistance = parseInt(r * lightDec), leftDistance = r - decDistance; + // 正方形区域的直径和左上角坐标 + var d = r * 2, sx = x - r, sy = y - r; + // 获得正方形区域的颜色信息 + var imageData = ctx.getImageData(sx, sy, d, d); + // 对每个像素点进行遍历 + for (var i = 0; i < imageData.data.length; i+=4) { + // 当前点的坐标 + var index = i / 4, cx = parseInt(index/d), cy = index%d; + // 当前点距离中心点的距离 + var dx = r - cx, dy = r - cy, distance = Math.sqrt(dx*dx+dy*dy); + if (distance >= r) continue; + // 计算当前点的alpha值 + var alpha = imageData.data[i+3] - (distance