diff --git a/API列表.txt b/API列表.txt index 4ed96670..6271e411 100644 --- a/API列表.txt +++ b/API列表.txt @@ -776,10 +776,6 @@ hero可为null或一个对象,具体将使用core.getRealStatusOrDefault(hero, 从V2.5.5开始,该函数也允许直接返回一个数字,代表战斗伤害值,此时回合数将视为0。 -core.updateEnemys() -更新怪物数据。该函数实际被转发到了脚本编辑中。详见文档-事件-更新怪物数据。 - - core.getCurrentEnemys(floorId) 获得某个楼层不重复的怪物信息,floorId不填默认为当前楼层。该函数会被怪物手册所调用。 该函数将返回一个列表,每一项都是一个不同的怪物,按照伤害值从小到大排序。 @@ -2084,7 +2080,7 @@ num如果设置大于0,则生成一个[0, num-1]之间的数;否则生成一 即先生成一个真随机数,根据该数来推进伪随机的种子,这样就可以放心调用core.rand()啦。 -core.readFile(success, error) +core.readFile(success, error, accept) 读取一个本地文件内容。success和error分别为读取成功或失败的回调函数。 iOS平台暂不支持读取文件操作。 diff --git a/_docs/api.md b/_docs/api.md index 38916a10..735ddd86 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -338,7 +338,7 @@ core.setHeroMoveInterval(callback) core.moveOneStep(x, y) -每走完一步后执行的操作,被转发到了脚本编辑中。 +每走完一步后执行的操作,被转发到了脚本编辑中,执行脚本编辑moveOneStep中的内容。 core.moveAction(callback) @@ -349,6 +349,7 @@ core.moveAction(callback) core.moveHero(direction, callback) 令勇士朝一个方向行走。如果设置了callback,则只会行走一步,并执行回调。 否则,将一直朝该方向行走,直到core.status.heroStop为true为止。 +direction可为"up","down","right","left",分别对应上,下,右,左。 core.isMoving() @@ -361,10 +362,11 @@ core.waitHeroToStop(callback) core.turnHero(direction) 转向。如果设置了direction则会转到该方向,否则会右转。该函数会自动计入录像。 +direction可为"up","down","right","left",分别对应上,下,右,左。 core.moveDirectly(destX, destY) -尝试瞬间移动到某点,被转发到了脚本编辑中。 +尝试瞬间移动到某点,被转发到了脚本编辑中,执行脚本编辑中的内容。 此函数返回非负值代表成功进行瞬移,返回值是省略的步数;如果返回-1则代表没有成功瞬移。 @@ -499,12 +501,12 @@ core.syncSave(type) / core.syncLoad() core.saveData() -获得要存档的内容,实际转发到了脚本编辑中。 +获得要存档的内容,实际转发到了脚本编辑中,执行脚本编辑中的内容。 core.loadData(data, callback) 实际执行一次读档行为,data为读取到的数据,callback为执行完毕的回调。 -实际转发到了脚本编辑中。 +实际转发到了脚本编辑中,执行脚本编辑中的内容。 core.getSave(index, callback) @@ -534,19 +536,23 @@ core.removeSave(index) // ------ 属性、状态、位置、变量等 ------ // core.setStatus(name, value) -设置勇士当前的某个属性。 +设置勇士当前的某个属性,name可为"atk","def","hp"等。 +如core.setStatus("atk", 100)则为设置勇士攻击为100。 core.addStatus(name, value) -加减勇士当前的某个属性。等价于 core.setStatus(name, core.getStatus(name) + value) +加减勇士当前的某个属性,name可为"atk","def","hp"等。 +如core.addStatus("atk", 100)则为增加勇士攻击100点。 +等价于 core.setStatus(name, core.getStatus(name) + value)。 core.getStatus(name) -获得勇士的某个原始属性值。 +获得勇士的某个原始属性值,该值不受百分比增幅影响。 +譬如你有一件道具加10%的攻击,你可以使用该函数获得你的攻击被增幅前的数值 core.getStatusOrDefault(status, name) -尝试从status中获得某个原始属性值;如果status为null或不存在对应属性值则从勇士属性中获取。 +尝试从status中获得某个原始属性值,该值不受百分比增幅影响;如果status为null或不存在对应属性值则从勇士属性中获取。 此项在伤害计算函数中使用较多,例如传递新的攻击和防御来计算临界和1防减伤。 @@ -572,12 +578,14 @@ core.getBuff(name) core.setHeroLoc(name, value, noGather) -设置勇士位置属性。name只能为'x', 'y'和'direction'之一。 +设置勇士位置属性。name只能为'x'(勇士x坐标), 'y'(勇士y坐标)和'direction'(勇士朝向)之一。 如果noGather为true,则不会聚集所有的跟随者。 +譬如core.setHeroLoc("x", 1, true)则为设置勇士x坐标为1,不聚集所有跟随者。 core.getHeroLoc(name) 获得勇士的某个位置属性。如果name为null则直接返回core.status.hero.loc。 +譬如core.getHeroLoc("x")则返回勇士当前x坐标 core.getLvName(lv) @@ -586,19 +594,26 @@ core.getLvName(lv) core.setFlag(name, value) 设置某个自定义变量或flag。如果value为null则会调用core.removeFlag进行删除。 +这里的变量与事件中使用的变量等价 +譬如core.setFlag("xxx",1)则为设置变量xxx为1。 core.addFlag(name, value) 加减某个自定义的变量或flag。等价于 core.setFlag(name, core.getFlag(name, 0) + value) +这里的变量与事件中使用的变量等价 +譬如core.addFlag("xxx",1)则为增加变量xxx1 core.getFlag(name, defaultValue) -获得某个自定义的变量或flag。如果该flag不存在(从未赋值过),则返回defaultValue值。 +获得某个自定义的变量或flag。如果该flag不存在(从未赋值过),则返回defaultValue的值。 +这里的变量与事件中使用的变量等价 +譬如core.getFlag("xxx",1)则为获得变量xxx的值,如变量xxx不存在则返回1 core.hasFlag(name) 判定是否拥有某个自定义变量或flag。等价于 !!core.getFlag(name, 0) - +这里的变量与事件中使用的变量等价 +譬如core.hasFlag("xxx",1)则为判断变量xxx是否存在 core.removeFlag(name) 删除一个自定义变量或flag。 @@ -619,6 +634,8 @@ core.setWeather(type, level) core.setCurtain(color, time, callback) 更改画面色调。color为更改到的色调,是个三元或四元组;time为渐变时间,0代表立刻切换。 +譬如core.setCurtain([255,255,255,1], 0)即为无回调无等待更改画面色调为白色 + core.screenFlash(color, time, times, callback) @@ -707,7 +724,7 @@ special为要测试的内容,允许接收如下类型参数: core.getSpecials() -获得所有特殊属性的列表。实际上被转发到了脚本编辑中。 +获得所有特殊属性的列表。实际上被转发到了脚本编辑中,执行脚本编辑中的内容。 core.getSpecialText(enemy) @@ -747,7 +764,7 @@ number为要计算的临界值数量,不填默认为1。 core.getDefDamage(enemy, k, x, y, floorId) -获得某个怪物的k防减伤值。k可不填默认为1。 +获得某个怪物的k防减伤值。k可不填默认为1,x,y,floorId为当前xy坐标和楼层。 core.getEnemyInfo(enemy, hero, x, y, floorId) @@ -764,10 +781,6 @@ hero可为null或一个对象,具体将使用core.getRealStatusOrDefault(hero, 从V2.5.5开始,该函数也允许直接返回一个数字,代表战斗伤害值,此时回合数将视为0。 -core.updateEnemys() -更新怪物数据。该函数实际被转发到了脚本编辑中。详见文档-事件-更新怪物数据。 - - core.getCurrentEnemys(floorId) 获得某个楼层不重复的怪物信息,floorId不填默认为当前楼层。该函数会被怪物手册所调用。 该函数将返回一个列表,每一项都是一个不同的怪物,按照伤害值从小到大排序。 @@ -776,7 +789,7 @@ core.getCurrentEnemys(floorId) core.hasEnemyLeft(enemyId, floorId) 检查某个楼层是否还有剩余的(指定)怪物。 -floorId为楼层ID,可忽略表示当前楼层。也可以传数组如["MT0","MT1"]同时检测多个楼层。 +floorId为楼层ID,可忽略表示当前楼层。也可以填数组如["MT0","MT1"]同时检测多个楼层。 enemyId如果不填或null则检查是否剩余任何怪物,否则只检查是否剩余指定的某类怪物。 ``` @@ -806,16 +819,16 @@ seed为开始时要设置的的种子,route为要开始播放的录像,callb core.setInitData() 根据难度分歧来初始化难度,包括设置flag:hard,设置初始属性等。 -该函数实际被转发到了脚本编辑中。 +该函数实际被转发到了脚本编辑中,执行脚本编辑中的内容。 core.win(reason, norank) 游戏胜利,reason为结局名,norank如果为真则该结局不计入榜单。 -该函数实际被转发到了脚本编辑中。 +该函数实际被转发到了脚本编辑中,执行脚本编辑中的内容。 core.lose(reason) -游戏失败,reason为结局名。该函数实际被转发到了脚本编辑中。 +游戏失败,reason为结局名。该函数实际被转发到了脚本编辑中,执行脚本编辑中的内容。 core.gameOver(ending, fromReplay, norank) @@ -855,7 +868,7 @@ id为怪物的ID,x和y为怪物坐标,force如果为真将强制战斗,cal core.beforeBattle(enemyId, x, y) -战前事件。实际被转发到了脚本编辑中,可以在这里加上一些战前特效。 +战前事件。实际被转发到了脚本编辑中,执行脚本编辑中的内容,可以用于加上一些战前特效。 此函数在“检测能否战斗和自动存档”【之后】执行。 如果需要更早的战前事件,请在插件中覆重写 core.events.doSystemEvent 函数。 此函数返回true则将继续本次战斗,返回false将不再战斗。 @@ -863,7 +876,7 @@ core.beforeBattle(enemyId, x, y) core.afterBattle(enemyId, x, y, callback) 战后事件,将执行扣血、加金币经验、特殊属性处理、战后事件处理等操作。 -实际被转发到了脚本编辑中。 +实际被转发到了脚本编辑中,执行脚本编辑中的内容。 core.openDoor(x, y, needKey, callback) @@ -872,16 +885,17 @@ core.openDoor(x, y, needKey, callback) core.afterOpenDoor(doorId, x, y, callback) -开完一个门后执行的事件,实际被转发到了脚本编辑中。 +开完一个门后执行的事件,实际被转发到了脚本编辑中,执行脚本编辑中的内容。 core.getItem(id, num, x, y, callback) 获得若干个道具。itemId为道具ID,itemNum为获得的道具个数,不填默认为1。 -x和y为道具点的坐标,如果设置则会擦除地图上的该点。 +x和y为道具点的坐标,如果设置则会擦除地图上的该点,也可不填。 +譬如core.getItem("yellowKey",2)会直接获得两把黄钥匙。 core.afterGetItem(id, x, y, callback) -获得一个道具后执行的事件,实际被转发到了脚本编辑中。 +获得一个道具后执行的事件,实际被转发到了脚本编辑中,执行脚本编辑中的内容。 core.getNextItem(noRoute) @@ -918,7 +932,7 @@ core.pushBox(data) core.afterPushBox() -推箱子之后触发的事件,实际被转发到了脚本编辑中。 +推箱子之后触发的事件,实际被转发到了脚本编辑中,执行脚本编辑中的内容。 core.changeLight(id, x, y) @@ -1024,15 +1038,21 @@ core.follow(name) / core.unfollow(name) core.setValue(name, value, prefix) / core.addValue(name, value, prefix) 设置/增减某个数值。name可以是status:xxx,item:xxx或flag:xxx。 -value可以是一个表达式,将调用core.calValue()计算。prefix为前缀,独立开关使用。 +value可以是一个表达式,将调用core.calValue()计算。prefix为前缀,独立开关使用,脚本中一般忽略。 core.doEffect(effect, need, times) 执行一个effect操作。该函数目前仅被全局商店的status:xxx+=yyy所调用。 +core.setEnemy(id, name, value, prefix) +设置一个怪物属性。id为怪物的ID,name为要设置的项,比如hp,atk,def等等。 +value可以是一个表达式,将调用core.calValue()计算。prefix为前缀,独立开关使用,脚本中一般忽略。 + + core.setFloorInfo(name, values, floorId, prefix) -设置某层楼的楼层属性。 +设置某层楼的楼层属性,其中name为该楼层属性对应的条目,values为要设置的值,floorId为楼层id,prefix一般直接忽略。 +譬如core.setFloorInfo("name","4", "MT1")则为设置MT1显示在状态栏中的层数为4 core.setGlobalAttribute(name, value) @@ -1191,8 +1211,9 @@ core.addItem(itemId, itemNum) core.getEquipTypeByName(name) -根据装备位名称来找到一个空的装备孔,适用于多重装备。 +根据装备位名称来找到一个空的装备孔,适用于多重装备,装备位名称可在全塔属性中设置。 如果没有一个装备孔是该装备名称,则返回-1。 +譬如:core.getEquipTypeByName("武器")默认返回全塔属性中武器对应的装备孔号0。 core.getEquipTypeById(equipId) @@ -1205,11 +1226,12 @@ core.canEquip(equipId, hint) core.loadEquip(equipId, callback) -穿上某个装备。 +穿上某个装备,equipId为装备id。 core.unloadEquip(equipType, callback) 脱下某个装备孔的装备。 +譬如core.unloadEquip(0)则为脱下0号装备孔中的装备,默认0号装备孔对应“武器”,1号装备孔对应“盾牌” core.compareEquipment(compareEquipId, beComparedEquipId) @@ -1285,7 +1307,7 @@ map为存档信息,如果某项在map中不存在则会从core.floors中读取 core.getNumberById(id) -给定一个图块ID,找到对应的数字。 +给定一个图块ID,找到图块对应的图块编号。 core.initBlock(x, y, id, addInfo, eventFloor) @@ -1421,7 +1443,7 @@ toDraw为要绘制到的信息(可为null,或为一个画布名),包括 // ------ 获得某个点的图块信息 ------ // core.noPass(x, y, floorId) -判定某个点是否有noPass的图块。 +判定某个点是否有noPass(不可通行)的图块。 core.npcExists(x, y, floorId) @@ -1429,7 +1451,7 @@ core.npcExists(x, y, floorId) core.terrainExists(x, y, id, floorId) -判定某个点是否有(指定的)地形存在。 +判定某个点是否有(id对应的)地形存在。 如果id为null,则只要存在terrains即为真,否则还会判定对应点的ID。 @@ -1442,7 +1464,7 @@ core.nearStair() core.enemyExists(x, y, id, floorId) -判定某个点是否有(指定的)怪物存在。 +判定某个点是否有(id对应的)怪物存在。 如果id为null,则只要存在怪物即为真,否则还会判定对应点的怪物ID。 请注意,如果需要判定某个楼层是否存在怪物请使用core.hasEnemyLeft()函数。 @@ -1499,14 +1521,17 @@ core.removeBlock(x, y, floorId) core.removeBlockById(index, floorId) +每个楼层的图块存成一个数组,index即为该数组中的索引,每个索引对应该地图中的一个图块 根据索引从地图的block数组中尽可能删除一个图块。floorId可不填或null表示当前楼层。 core.removeBlockByIds(floorId, ids) +ids为由索引组成的数组,如[0,1]等 根据索引数组从地图的block数组中尽可能删除一系列图块。floorId可不填或null表示当前楼层。 core.canRemoveBlock(block, floorId) +block为图块信息,可由core.getBlock获取 判定当前能否完全删除某个图块。floorId可不填或null表示当前楼层。 如果该点存在自定义事件,或者是重生怪,则不可进行删除。 @@ -1550,7 +1575,7 @@ number为要设置到的图块数字,x,y和floorId为目标点坐标和楼层 core.resetMap(floorId) 重置某层或若干层的地图和楼层属性。 -floorId可为某个楼层ID,或者一个楼层数组(同时重置若干层);如果不填则只重置当前楼层。 +floorId可为某个楼层ID,或者一个楼层数组如["MT1","MT2"](同时重置若干层);如果不填则只重置当前楼层。 // ------ 移动/跳跃图块,淡入淡出图块 ------ // @@ -1626,9 +1651,13 @@ core.clearMap(name) core.fillText(name, text, x, y, style, font, maxWidth) 在某个画布上绘制一段文字。 text为要绘制的文本,x,y为要绘制的坐标,style可选为绘制的样式,font可选为绘制的字体。(下同) +style可直接使用"red","white"等或用"rgba(255,255,255,1)"或用"#FFFFFF"等方式来获得字体对应的颜色 +font的格式为"20px Verdana"前者为字体大小,后者为字体 如果maxWidth不为null,则视为文字最大宽度,如果超过此宽度则会自动放缩文字直到自适应为止。 请注意textAlign和textBaseline将决定绘制的左右对齐和上下对齐方式。 具体可详见core.setTextAlign()和core.setTextBaseline()函数。 +譬如:core.fillText("ui", "这是要描绘的文字", 10, 10, "red", "20px Verdana", 100) +即是在ui图层上,以10,10为起始点,描绘20像素大小,Verdana字体的红色字,长度不超过100像素 core.fillBoldText(name, text, x, y, style, font) @@ -1636,7 +1665,7 @@ core.fillBoldText(name, text, x, y, style, font) core.fillRect(name, x, y, width, height, style) -绘制一个矩形。style可选为绘制样式。如果设置将调用core.setFillStyle()。(下同) +绘制一个矩形。width, height为矩形宽高,style可选为绘制样式。如果设置将调用core.setFillStyle()。(下同) core.strokeRect(name, x, y, width, height, style, lineWidth) @@ -1645,11 +1674,11 @@ lineWidth如果设置将调用core.setLineWidth()。(下同) core.drawLine(name, x1, y1, x2, y2, style, lineWidth) -绘制一条线。 +绘制一条线,x1y1为起始点像素,x2y2为终止点像素。 core.drawArrow(name, x1, y1, x2, y2, style, lineWidth) -绘制一个箭头。 +绘制一个箭头,x1y1为起始点像素,x2y2为终止点像素。 core.setFont(name, font) / core.setLineWidth(name, lineWidth) @@ -1671,7 +1700,7 @@ core.setFillStyle(name, style) / core.setStrokeStyle(name, style) core.setTextAlign(name, align) -设置一个画布的文字横向对齐模式,这里的align只能为'left', 'right'和'center'。 +设置一个画布的文字横向对齐模式,这里的align只能为'left', 'right'和'center',分别对应左对齐,右对齐,居中。 默认为'left'。 @@ -1862,7 +1891,7 @@ z值为创建的纵向高度(关系到画布之间的覆盖),z值高的将 core.ui.relocateCanvas(name, x, y) -重新定位一个自定义画布。x和y为画布的左上角坐标。 +重新定位一个自定义画布。x和y为画布的左上角坐标,name为画布名。 core.ui.resizeCanvas(name, width, height, styleOnly) @@ -2051,6 +2080,7 @@ core.matchWildcard(pattern, string) core.encodeBase64(str) / core.decodeBase64(str) 将字符串进行base64加密或解密。 +可用于解压缩录像数据 core.convertBase(str, fromBase, toBase) @@ -2073,8 +2103,9 @@ num如果设置大于0,则生成一个[0, num-1]之间的数;否则生成一 即先生成一个真随机数,根据该数来推进伪随机的种子,这样就可以放心调用core.rand()啦。 -core.readFile(success, error) +core.readFile(success, error, accept) 读取一个本地文件内容。success和error分别为读取成功或失败的回调函数。 +accept如果设置则控制能选择的文件类型。 iOS平台暂不支持读取文件操作。 diff --git a/_docs/event.md b/_docs/event.md index 461b2c9c..20a47522 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -499,6 +499,27 @@ value是一个表达式,将通过这个表达式计算出的结果赋值给nam ![](img/events/14.jpg) + +### setEnemy:设置怪物属性 + +使用`{"type":"setEnemy"}`可以设置某个怪物的某个属性 + +``` js +[ + {"type": "setEnemy", "id": "greenSlime", "name": "hp", "value": "1000"}, // 设置绿色史莱姆生命1000 + {"type": "setEnemy", "id": "redSlime", "name": "special", "value": "[1,2]"}, // 设置红色史莱姆先攻魔攻 + {"type": "setEnemy", "id": "redSlime", "name": "name", "value": "'小史莱姆'"}, // 设置怪物名称 +] +``` + +![](img/events/15.png) + +id为必填项,代表要修改的怪物ID。 + +name为必填项,代表要修改的项,例如`hp`, `atk`, `def`, `money`, `experience`, `point`, `special`, `name`。 + +value为必填项,代表要修改到的内容。对于修改名称的,必须加单引号。 + ### setFloor:设置楼层属性 使用`{"type":"setFloor"}`可以设置某层楼的楼层属性。 @@ -898,12 +919,6 @@ name是可选的,代表目标行走图的文件名。 使用`{"type": "showHero"}`会重新显示勇士。 -### updateEnemys:更新怪物数据 - -使用 `{"type": "updateEnemys"}` 可以动态修改怪物数据。 - -详见[怪物数据的动态修改](#怪物数据的动态修改)。 - ### sleep:等待多少毫秒 等价于RMXP中的"等待x帧",不过是以毫秒来计算。 @@ -2646,43 +2661,6 @@ if (core.flags.enableAddPoint && point > 0) { } ``` -## 怪物数据的动态修改 - -有时候我们可能还需要在游戏过程中动态修改怪物数据,例如50层魔塔的封印魔王,或者根据难度分歧来调整最终Boss的属性数据。 - -而在我们的存档中,是不会对怪物数据进行存储的,只会存各个变量和Flag,因此我们需要在读档后根据变量或Flag来调整怪物数据。 - -我们可以在脚本编辑中的`updateEnemys`进行处理。 - -``` js -"updateEnemys" : function () { - // 更新怪物数据,可以在这里对怪物属性和数据进行动态更新,详见文档——事件——怪物数据的动态修改 - // 比如下面这个例子,如果flag:xxx为真,则将绿头怪的攻击设为100,红头怪的金币设为20 - // 推荐写变化后的具体数值,以免多次变化导致冲突 - /* - // 如果flag:xxx为真;你也可以写其他判断语句比如core.hasItem(...)等等 - if (core.hasFlag('xxx')) { - core.material.enemys.greenSlime.atk = 100; - core.material.enemys.redSlime.money = 20; - } - */ - // 别忘了在事件中调用“更新怪物数据”事件! -} -``` - -当我们获得一个道具(或者触发某个事件等)后,需要在事件中调用“更新怪物数据”事件。 - -``` js -// 调用`updateEnemys`(更新怪物数据)事件就可以触发了 -[ - "将flag:xxx置为真,就可以让怪物数据发生改变!", - {"type": "setValue", "name": "flag:xxx", "value": "true"}, // 将flag:xxx置为真 - {"type": "updateEnemys"} // 更新怪物数据;此时绿头怪攻击就会变成100了 -] -``` - -事实上,除了动态修改怪物属性外,也可以在这里动态修改道具的类型、使用效果等等。都是一样的。 - ## 战前剧情 有时候光战后事件`afterBattle`是不够的,我们可能还需要战前剧情,例如Boss战之前和Boss进行一段对话。 diff --git a/_docs/img/events/15.png b/_docs/img/events/15.png new file mode 100644 index 00000000..b1fe91cc Binary files /dev/null and b/_docs/img/events/15.png differ diff --git a/_docs/start.md b/_docs/start.md index ced7faa1..8db27c1c 100644 --- a/_docs/start.md +++ b/_docs/start.md @@ -235,7 +235,7 @@ HTML5的塔都是可以进行控制台调试的。 ## 编辑器的基本操作 -- **Alt+0~9, Ctrl+0~9** 保存和读取当前选中图块 +- **Alt+0~9, 0~9** 保存和读取当前选中图块 - **W/A/S/D** 移动大地图 - **Ctrl+Z** 撤销上次绘图 - **Ctrl+Y** 重做上次绘图 diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index 48c07482..fcde32aa 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -322,6 +322,7 @@ action | tip_s | setValue_s | addValue_s + | setEnemy_s | setFloor_s | setGlobalAttribute_s | setGlobalValue_s @@ -345,7 +346,6 @@ action | hideStatusBar_s | showHero_s | hideHero_s - | updateEnemys_s | sleep_s | wait_s | waitAsync_s @@ -610,6 +610,21 @@ var code = '{"type": "addValue", "name": "'+idString_e_0+'", "value": "'+express return code; */; + +setEnemy_s + : '设置怪物属性' ':' '怪物ID' IdString '的' EnemyId_List '值' expression Newline + + +/* setEnemy_s +tooltip : setEnemy:设置某个怪物的属性 +default : ["greenSlime", "atk", "0"] +helpUrl : https://h5mota.com/games/template/_docs/#/event?id=addValue%ef%bc%9a%e5%a2%9e%e5%87%8f%e5%8b%87%e5%a3%ab%e7%9a%84%e6%9f%90%e4%b8%aa%e5%b1%9e%e6%80%a7%e3%80%81%e9%81%93%e5%85%b7%e4%b8%aa%e6%95%b0%ef%bc%8c%e6%88%96%e6%9f%90%e4%b8%aa%e5%8f%98%e9%87%8f%2fFlag%e7%9a%84%e5%80%bc +colour : this.dataColor +var code = '{"type": "setEnemy", "id": "'+IdString_0+'", "name": "'+EnemyId_List_0+'", "value": "'+expression_0+'"},\n'; +return code; +*/; + + setFloor_s : '设置楼层属性' ':' Floor_Meta_List '楼层名' IdString? '值' EvalString Newline @@ -1086,18 +1101,6 @@ var code = '{"type": "hideHero"},\n'; return code; */; -updateEnemys_s - : '更新怪物数据' Newline - - -/* updateEnemys_s -tooltip : updateEnemys: 立刻更新怪物数据 -helpUrl : https://h5mota.com/games/template/_docs/#/event?id=updateEnemys%ef%bc%9a%e6%9b%b4%e6%96%b0%e6%80%aa%e7%89%a9%e6%95%b0%e6%8d%ae -colour : this.dataColor -var code = '{"type": "updateEnemys"},\n'; -return code; -*/; - sleep_s : '等待' Int '毫秒' '不可被Ctrl跳过' Bool Newline @@ -1724,15 +1727,16 @@ return code; */; win_s - : '游戏胜利,结局' ':' EvalString? '不计入榜单' Bool Newline + : '游戏胜利,结局' ':' EvalString? '不计入榜单' Bool '不结束游戏' Bool Newline /* win_s tooltip : win: 获得胜利, 该事件会显示获胜页面, 并重新游戏 helpUrl : https://h5mota.com/games/template/_docs/#/event?id=win%EF%BC%9A%E8%8E%B7%E5%BE%97%E8%83%9C%E5%88%A9 -default : ["",false] +default : ["",false, false] Bool_0 = Bool_0?', "norank": 1':''; -var code = '{"type": "win", "reason": "'+EvalString_0+'"'+Bool_0+'},\n'; +Bool_1 = Bool_1?', "noexit": 1':''; +var code = '{"type": "win", "reason": "'+EvalString_0+'"'+Bool_0+Bool_1+'},\n'; return code; */; @@ -2592,6 +2596,46 @@ return [code, Blockly.JavaScript.ORDER_ATOMIC]; */; +//这一条不会被antlr识别,总是会被归到idString_e +idString_3_e + : '怪物' IdString '的' EnemyId_List + + +/* idString_3_e +colour : this.idstring_eColor +default : ['greenSlime',"攻击"] +//todo 将其output改成'idString_e' +var code = 'enemy:'+IdString_0+'.'+EnemyId_List_0; +return [code, Blockly.JavaScript.ORDER_ATOMIC]; +*/; + + +//这一条不会被antlr识别,总是会被归到idString_e +idString_4_e + : '图块ID:' Int ',' Int + + +/* idString_4_e +colour : this.idstring_eColor +default : [0,0] +var code = 'blockId:'+Int_0+','+Int_1; +return [code, Blockly.JavaScript.ORDER_ATOMIC]; +*/; + + +//这一条不会被antlr识别,总是会被归到idString_e +idString_5_e + : '图块类别:' Int ',' Int + + +/* idString_5_e +colour : this.idstring_eColor +default : [0,0] +var code = 'blockCls:'+Int_0+','+Int_1; +return [code, Blockly.JavaScript.ORDER_ATOMIC]; +*/; + + evFlag_e : '独立开关' Letter_List @@ -2743,6 +2787,10 @@ Id_List : '变量' | '状态' | '物品' | '独立开关' | '全局存储' /*Id_List ['flag','status','item', 'switch', 'global']*/; +EnemyId_List + : '生命'|'攻击'|'防御'|'金币'|'经验'|'加点'|'属性'|'名称' + /*EnemyId_List ['hp','atk','def','money','experience','point','special','name']*/; + //转blockly后不保留需要加" EvalString : Equote_double (ESC_double | ~["\\])* Equote_double @@ -2803,6 +2851,9 @@ this.evisitor.mapColor=175; delete(this.block('negate_e').inputsInline); this.block('idString_1_e').output='idString_e'; this.block('idString_2_e').output='idString_e'; +this.block('idString_3_e').output='idString_e'; +this.block('idString_4_e').output='idString_e'; +this.block('idString_5_e').output='idString_e'; this.block('evFlag_e').output='idString_e'; */ @@ -3304,6 +3355,10 @@ ActionParser.prototype.parseAction = function() { MotaActionBlocks['evalString_e'].xmlText([data.value]), this.next]); break; + case "setEnemy": + this.next = MotaActionBlocks['setEnemy_s'].xmlText([ + data.id, data.name, MotaActionBlocks['evalString_e'].xmlText([data.value]), this.next]); + break; case "setFloor": this.next = MotaActionBlocks['setFloor_s'].xmlText([ data.name, data.floorId||null, data.value, this.next]); @@ -3397,7 +3452,7 @@ ActionParser.prototype.parseAction = function() { break; case "win": this.next = MotaActionBlocks['win_s'].xmlText([ - data.reason,data.norank?true:false,this.next]); + data.reason,data.norank?true:false,data.noexit?true:false,this.next]); break; case "lose": this.next = MotaActionBlocks['lose_s'].xmlText([ @@ -3433,10 +3488,6 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['hideHero_s'].xmlText([ this.next]); break; - case "updateEnemys": - this.next = MotaActionBlocks['updateEnemys_s'].xmlText([ - this.next]); - break; case "sleep": // 等待多少毫秒 this.next = MotaActionBlocks['sleep_s'].xmlText([ data.time||0,data.noSkip||false,this.next]); @@ -3778,7 +3829,7 @@ MotaActionFunctions.pattern.replaceStatusList = [ ["mana", "魔力"], ["money", "金币"], ["experience", "经验"], - ["steps", "步数"] + ["steps", "步数"], ]; MotaActionFunctions.pattern.replaceItemList = [ @@ -3832,6 +3883,17 @@ MotaActionFunctions.pattern.replaceItemList = [ ["jumpShoes", "跳跃靴"], ]; +MotaActionFunctions.pattern.replaceEnemyList = [ + // 保证顺序! + ["name", "名称"], + ["atk", "攻击"], + ["def", "防御"], + ["money", "金币"], + ["experience", "经验"], + ["point", "加点"], + ["special", "属性"], +]; + MotaActionFunctions.disableReplace = false; MotaActionFunctions.replaceToName = function (str) { @@ -3851,6 +3913,16 @@ MotaActionFunctions.replaceToName = function (str) { return map[b] ? ("物品:" + map[b]) : b; }).replace(/item:/g, "物品:"); str = str.replace(/flag:/g, "变量:").replace(/switch:/g, "独立开关:").replace(/global:/g, "全局存储:"); + + map = {}; list = []; + MotaActionFunctions.pattern.replaceEnemyList.forEach(function (v) { + map[v[0]] = v[1]; list.push(v[0]); + }); + str = str.replace(new RegExp("enemy:([a-zA-Z0-9_]+).(" + list.join("|") + ")", "g"), function (a, b, c) { + return map[c] ? ("怪物:" + b + ":" + map[c]) : c; + }).replace(/enemy:/g, "怪物:"); + + str = str.replace(/blockId:/g, "图块ID:").replace(/blockCls:/g, "图块类别:"); return str; } @@ -3871,6 +3943,17 @@ MotaActionFunctions.replaceFromName = function (str) { return map[b] ? ("item:" + map[b]) : b; }).replace(/物品[::]/g, "item:"); str = str.replace(/变量[::]/g, "flag:").replace(/独立开关[::]/g, "switch:").replace(/全局存储[::]/g, "global:"); + + map = {}; list = []; + MotaActionFunctions.pattern.replaceEnemyList.forEach(function (v) { + map[v[1]] = v[0]; list.push(v[1]); + }); + str = str.replace(new RegExp("(enemy:|怪物[::])([a-zA-Z0-9_]+)[::](" + list.join("|") + ")", "g"), function (a, b, c, d) { + return map[d] ? ("enemy:" + c + ":" + map[d]) : d; + }).replace(/怪物[::]/g, "enemy:"); + + str = str.replace(/图块I[dD][::]/g, "blockId:").replace(/图块类别[::]/g, "blockCls:"); + return str; } diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index ef318e6a..53907f1c 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -105,6 +105,7 @@ editor_blockly = function () { MotaActionBlocks['setValue_s'].xmlText([ MotaActionBlocks['idString_1_e'].xmlText(['status','生命']) ]), + MotaActionBlocks['setEnemy_s'].xmlText(), MotaActionBlocks['setFloor_s'].xmlText(), MotaActionBlocks['setGlobalAttribute_s'].xmlText(), MotaActionBlocks['setGlobalValue_s'].xmlText(), @@ -112,7 +113,6 @@ editor_blockly = function () { MotaActionBlocks['input_s'].xmlText(), MotaActionBlocks['input2_s'].xmlText(), MotaActionBlocks['update_s'].xmlText(), - MotaActionBlocks['updateEnemys_s'].xmlText(), MotaActionBlocks['moveHero_s'].xmlText(), MotaActionBlocks['jumpHero_s'].xmlText(), MotaActionBlocks['changeFloor_s'].xmlText(), @@ -229,6 +229,9 @@ editor_blockly = function () { MotaActionBlocks['idString_e'].xmlText(), MotaActionBlocks['idString_1_e'].xmlText(), MotaActionBlocks['idString_2_e'].xmlText(), + MotaActionBlocks['idString_3_e'].xmlText(), + MotaActionBlocks['idString_4_e'].xmlText(), + MotaActionBlocks['idString_5_e'].xmlText(), MotaActionBlocks['evalString_e'].xmlText(), ], '常见事件模板':[ @@ -910,6 +913,28 @@ function omitedcheckUpdateFunction(event) { return Object.keys(editor.used_flags || {}).filter(function (one) { return one != token && one.startsWith(token); }).sort(); + } else if (before.endsWith("怪物") || (ch == ':' && before.endsWith("enemy"))) { + return Object.keys(core.material.enemys).filter(function (one) { + return one != token && one.startsWith(token); + }) + } else { + var index2 = Math.max(content.lastIndexOf(":", index-1), content.lastIndexOf(":", index-1)); + var ch2 = content.charAt(index2); + if (index2 >= 0) { + before = content.substring(0, index2); + if (before.endsWith("怪物") || (ch == ':' && ch2 == ':' && before.endsWith("enemy"))) { + var list = ["name", "hp", "atk", "def", "money", "experience", "point", "special"]; + if (before.endsWith("怪物") && MotaActionFunctions) { + list = MotaActionFunctions.pattern.replaceEnemyList.map(function (v) { + return v[1]; + }).concat(list); + } + return list.filter(function (one) { + return one != token && one.startsWith(token); + }) + } + } + } } } @@ -1039,7 +1064,7 @@ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) { // --- awesomplete var awesomplete = new Awesomplete(htmlInput, { - minChars: 2, + minChars: pb.type == "idString_3_e" ? 1 : 2, maxItems: 12, autoFirst: true, replace: function (text) { @@ -1094,6 +1119,13 @@ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) { } var list = editor_blockly.getAutoCompletions(value); + if (pb.type == "idString_3_e") { + list = list.concat(Object.keys(core.material.enemys).filter(function (one) { + return one != value && one.startsWith(value); + })); + list.sort(); + } + awesomplete.list = list; awesomplete.ul.style.marginLeft = getCaretCoordinates(htmlInput, htmlInput.selectionStart).left - htmlInput.scrollLeft - 20 + "px"; diff --git a/_server/editor_datapanel.js b/_server/editor_datapanel.js index 5e1baa46..08678104 100644 --- a/_server/editor_datapanel.js +++ b/_server/editor_datapanel.js @@ -511,7 +511,7 @@ editor_datapanel_wrapper = function (editor) { editor.dom.selectAppend.onchange(); }); }); - }, null, 'img'); + }, null, 'image/*', 'img'); return; } diff --git a/_server/editor_game.js b/_server/editor_game.js index 27c51001..4690f17c 100644 --- a/_server/editor_game.js +++ b/_server/editor_game.js @@ -115,10 +115,12 @@ editor_game_wrapper = function (editor, main, core) { var img = core.material.images.tilesets[imgName]; var width = Math.floor(img.width / 32), height = Math.floor(img.height / 32); if (img.width % 32 || img.height % 32) { - alert(imgName + '的长或宽不是32的整数倍, 请修改后刷新页面'); + // alert(imgName + '的长或宽不是32的整数倍, 请修改后刷新页面'); + console.warn(imgName + '的长或宽不是32的整数倍, 请修改后刷新页面'); } if (img.width * img.height > 32 * 32 * 3000) { - alert(imgName + '上的图块数量超过了3000,请修改后刷新页面'); + // alert(imgName + '上的图块数量超过了3000,请修改后刷新页面'); + console.warn(imgName + '上的图块数量超过了3000,请修改后刷新页面'); } for (var id = startOffset; id < startOffset + width * height; id++) { var x = (id - startOffset) % width, y = parseInt((id - startOffset) / width); diff --git a/_server/editor_legacy.js b/_server/editor_legacy.js index 1313ebbc..7242553c 100644 --- a/_server/editor_legacy.js +++ b/_server/editor_legacy.js @@ -217,7 +217,8 @@ tip.showHelp = function(value) { 'ESC或点击空白处可以自动保存当前修改', 'H键可以打开操作帮助哦', 'tileset贴图模式下可以按选中tileset素材,并在地图上拖动来一次绘制一个区域', - '可以拖动地图上的图块和事件,或按Ctrl+C, Ctrl+X和Ctrl+V进行复制,剪切和粘贴,Delete删除' + '可以拖动地图上的图块和事件,或按Ctrl+C, Ctrl+X和Ctrl+V进行复制,剪切和粘贴,Delete删除', + 'Alt+数字键保存图块,数字键读取保存的图块', ]; if (value == null) value = Math.floor(Math.random() * tips.length); printf('tips: ' + tips[value]) diff --git a/_server/editor_ui.js b/_server/editor_ui.js index 589b19d0..a82601e3 100644 --- a/_server/editor_ui.js +++ b/_server/editor_ui.js @@ -111,11 +111,6 @@ editor_ui_wrapper = function (editor) { if (editor_multi.id != "" || editor_blockly.id != "") return; - // 禁止快捷键的默认行为 - if (e.ctrlKey && [89, 90, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1) - e.preventDefault(); - 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 && editor.uivalues.preMapData && editor.uivalues.currDrawData.pos.length && selectBox.isSelected()) { editor.map = JSON.parse(JSON.stringify(editor.uivalues.preMapData.map)); @@ -153,22 +148,10 @@ editor_ui_wrapper = function (editor) { } return; } - //ctrl + 0~9 切换到快捷图块 - if (e.ctrlKey && [48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1) { - editor.setSelectBoxFromInfo(JSON.parse(JSON.stringify(editor.uivalues.shortcut[e.keyCode] || 0))); - return; - } - //alt + 0~9 改变快捷图块 - if (e.altKey && [48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1) { - var infoToSave = JSON.stringify(editor.info || 0); - if (infoToSave == JSON.stringify({})) return; - editor.uivalues.shortcut[e.keyCode] = JSON.parse(infoToSave); - printf('已保存该快捷图块, ctrl + ' + (e.keyCode - 48) + ' 使用.') - core.setLocalStorage('shortcut', editor.uivalues.shortcut); - return; - } + var focusElement = document.activeElement; - if (!focusElement || focusElement.tagName.toLowerCase() == 'body') { + if (!focusElement || focusElement.tagName.toLowerCase() == 'body' + || focusElement.id == 'selectFloor') { // Ctrl+C, Ctrl+X, Ctrl+V if (e.ctrlKey && e.keyCode == 67 && !selectBox.isSelected()) { e.preventDefault(); @@ -223,6 +206,20 @@ editor_ui_wrapper = function (editor) { editor.info = {}; return; } + //alt + 0~9 改变快捷图块 + if (e.altKey && [48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1) { + var infoToSave = JSON.stringify(editor.info || 0); + if (infoToSave == JSON.stringify({})) return; + editor.uivalues.shortcut[e.keyCode] = JSON.parse(infoToSave); + printf('已保存该快捷图块, 数字键 ' + (e.keyCode - 48) + ' 使用.') + core.setLocalStorage('shortcut', editor.uivalues.shortcut); + return; + } + //ctrl + 0~9 切换到快捷图块 + if ([48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1) { + editor.setSelectBoxFromInfo(JSON.parse(JSON.stringify(editor.uivalues.shortcut[e.keyCode] || 0))); + return; + } switch (e.keyCode) { // WASD case 87: editor.moveViewport(0, -1); break; @@ -256,7 +253,7 @@ editor_ui_wrapper = function (editor) { "双击地图:选中对应点的素材\n" + "右键地图:弹出菜单栏\n" + "Alt+0~9:保存当前使用的图块\n" + - "Ctrl+0~9:选中保存的图块\n" + + "0~9:选中保存的图块\n" + "Ctrl+Z / Ctrl+Y:撤销/重做上次绘制\n" + "Ctrl+S:事件与脚本编辑器的保存并退出\n" + "双击事件编辑器:长文本编辑/脚本编辑/地图选点/UI绘制预览" diff --git a/_server/table/functions.comment.js b/_server/table/functions.comment.js index 55dc8d1c..6f30fa75 100644 --- a/_server/table/functions.comment.js +++ b/_server/table/functions.comment.js @@ -128,12 +128,6 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = { "_type": "textarea", "_lint": true, "_data": "获得战斗伤害信息" - }, - "updateEnemys": { - "_leaf": true, - "_type": "textarea", - "_lint": true, - "_data": "更新怪物数据" } } }, diff --git a/libs/actions.js b/libs/actions.js index 7caba11d..1a8597dd 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -2103,7 +2103,7 @@ actions.prototype._clickSyncSave_readFile = function () { if (obj.version != core.firstData.version) return alert("游戏版本不一致!"); if (!obj.data) return alert("无效的存档!"); core.control._syncLoad_write(obj.data); - }); + }, null, ".h5save"); } actions.prototype._clickSyncSave_replay = function () { diff --git a/libs/control.js b/libs/control.js index 6f0a3854..5f7b5e6b 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1122,7 +1122,7 @@ control.prototype.chooseReplayFile = function () { return; } _replay(); - }); + }, null, ".h5route"); } ////// 开始播放 ////// diff --git a/libs/enemys.js b/libs/enemys.js index 70e8263b..e9aaab26 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -19,7 +19,16 @@ enemys.prototype._init = function () { } enemys.prototype.getEnemys = function () { - return core.clone(this.enemys); + var enemys = core.clone(this.enemys); + var enemyInfo = core.getFlag('enemyInfo'); + if (enemyInfo) { + for (var id in enemyInfo) { + for (var name in enemyInfo[id]) { + enemys[id][name] = core.clone(enemyInfo[id][name]); + } + } + } + return enemys; } ////// 判断是否含有某特殊属性 ////// @@ -298,10 +307,8 @@ enemys.prototype._calDamage = function (enemy, hero, x, y, floorId) { return info.damage; } -////// 更新怪物数据 ////// -enemys.prototype.updateEnemys = function () { - return this.enemydata.updateEnemys(); -} +////// 更新怪物数据。已经不再使用,这里留空进行兼容。 ////// +enemys.prototype.updateEnemys = function () {} ////// 获得当前楼层的怪物列表 ////// enemys.prototype.getCurrentEnemys = function (floorId) { diff --git a/libs/events.js b/libs/events.js index f6b4a0ec..85758759 100644 --- a/libs/events.js +++ b/libs/events.js @@ -108,9 +108,9 @@ events.prototype.setInitData = function () { } ////// 游戏获胜事件 ////// -events.prototype.win = function (reason, norank) { - core.status.gameOver = true; - return this.eventdata.win(reason, norank); +events.prototype.win = function (reason, norank, noexit) { + if (!noexit) core.status.gameOver = true; + return this.eventdata.win(reason, norank, noexit); } ////// 游戏失败事件 ////// @@ -121,10 +121,12 @@ events.prototype.lose = function (reason) { ////// 游戏结束 ////// events.prototype.gameOver = function (ending, fromReplay, norank) { - core.clearMap('all'); - core.deleteAllCanvas(); - core.dom.gif2.innerHTML = ""; - core.setWeather(); + if (!core.status.extraEvent) { + core.clearMap('all'); + core.deleteAllCanvas(); + core.dom.gif2.innerHTML = ""; + core.setWeather(); + } core.ui.closePanel(); if (main.isCompetition && ending != null) { @@ -220,12 +222,22 @@ events.prototype._gameOver_confirmDownload = function (ending) { } events.prototype._gameOver_askRate = function (ending) { + core.ui.closePanel(); + + // 继续接下来的事件 + if (core.status.extraEvent) { + core.status.event = core.status.extraEvent; + delete core.status.extraEvent; + core.lockControl(); + core.doAction(); + return; + } + if (ending == null) { core.restart(); return; } - core.ui.closePanel(); core.ui.drawConfirmBox("恭喜通关本塔,你想进行评分吗?", function () { if (core.platform.isPC) { window.open("/score.php?name=" + core.firstData.name + "&num=10", "_blank"); @@ -1453,6 +1465,11 @@ events.prototype._action_addValue = function (data, x, y, prefix) { core.doAction(); } +events.prototype._action_setEnemy = function (data, x, y, prefix) { + this.setEnemy(data.id, data.name, data.value, prefix); + core.doAction(); +} + events.prototype._action_setFloor = function (data, x, y, prefix) { this.setFloorInfo(data.name, data.value, data.floorId, prefix); core.doAction(); @@ -1624,7 +1641,7 @@ events.prototype._action_continue = function (data, x, y, prefix) { } events.prototype._action_win = function (data, x, y, prefix) { - this.win(data.reason, data.norank); + this.win(data.reason, data.norank, data.noexit); } events.prototype._action_lose = function (data, x, y, prefix) { @@ -1675,12 +1692,6 @@ events.prototype._action_hideHero = function (data, x, y, prefix) { core.doAction(); } -events.prototype._action_updateEnemys = function (data, x, y, prefix) { - core.enemys.updateEnemys(); - core.updateStatusBar(); - core.doAction(); -} - events.prototype._action_vibrate = function (data, x, y, prefix) { this.__action_doAsyncFunc(data.async, core.vibrate, data.time); } @@ -2138,6 +2149,19 @@ events.prototype.doEffect = function (effect, need, times) { }); } +////// 设置一个怪物属性 ////// +events.prototype.setEnemy = function (id, name, value, prefix) { + if (!core.hasFlag('enemyInfo')) { + core.setFlag('enemyInfo', {}); + } + var enemyInfo = core.getFlag('enemyInfo'); + if (!enemyInfo[id]) enemyInfo[id] = {}; + value = core.calValue(value, prefix); + enemyInfo[id][name] = value; + (core.material.enemys[id]||{})[name] = core.clone(value); + core.updateStatusBar(); +} + ////// 设置楼层属性 ////// events.prototype.setFloorInfo = function (name, value, floorId, prefix) { floorId = floorId || core.status.floorId; diff --git a/libs/loader.js b/libs/loader.js index 489d9ea4..5d4da850 100644 --- a/libs/loader.js +++ b/libs/loader.js @@ -107,11 +107,16 @@ loader.prototype.loadImages = function (names, toSave, callback) { for (var i = 0; i < names.length; i++) { this.loadImage(names[i], function (id, image) { core.loader._setStartLoadTipText('正在加载图片 ' + id + "..."); - toSave[id] = image; - items++; - core.loader._setStartProgressVal(items * (100 / names.length)); - if (items == names.length) { - if (callback) callback(); + if (toSave[id] !== undefined) { + if (image != null) + toSave[id] = image; + return; + } + toSave[id] = image; + items++; + core.loader._setStartProgressVal(items * (100 / names.length)); + if (items == names.length) { + if (callback) callback(); } }) } @@ -126,7 +131,12 @@ loader.prototype.loadImage = function (imgName, callback) { image.onload = function () { callback(imgName, image); } + image.onerror = function () { + callback(imgName, null); + } image.src = 'project/images/' + name + "?v=" + main.version; + if (name.endsWith('.gif')) + callback(imgName, null); } catch (e) { main.log(e); diff --git a/libs/ui.js b/libs/ui.js index 5491449f..a1b88121 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -459,7 +459,7 @@ ui.prototype.clearUI = function () { ////// 左上角绘制一段提示 ////// ui.prototype.drawTip = function (text, id, clear) { - if (clear) this.clearTip(); + this.clearTip(); var one = { text: text, textX: 21, diff --git a/libs/utils.js b/libs/utils.js index dd46d468..d8f811c7 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -81,6 +81,12 @@ utils.prototype.calValue = function (value, prefix, need, times) { value = value.replace(/switch:([a-zA-Z0-9_]+)/g, "core.getFlag('" + (prefix || ":f@x@y") + "@$1', 0)"); if (value.indexOf('global:') >= 0) value = value.replace(/global:([a-zA-Z0-9_\u4E00-\u9FCC]+)/g, "core.getGlobal('$1', 0)"); + if (value.indexOf('enemy:')>=0) + value = value.replace(/enemy:([a-zA-Z0-9_]+)\.([a-zA-Z0-9_]+)/g, "core.material.enemys['$1'].$2"); + if (value.indexOf('blockId:')>=0) + value = value.replace(/blockId:(\d+),(\d+)/g, "core.getBlockId($1, $2)"); + if (value.indexOf('blockCls:')>=0) + value = value.replace(/blockCls:(\d+),(\d+)/g, "core.getBlockCls($1, $2)"); } return eval(value); } @@ -648,6 +654,7 @@ utils.prototype.setStatusBarInnerHTML = function (name, value, css) { // 判定是否斜体 var italic = /^[-a-zA-Z0-9`~!@#$%^&*()_=+\[{\]}\\|;:'",<.>\/?]*$/.test(value); var style = 'font-style: ' + (italic ? 'italic' : 'normal') + '; '; + style += 'text-shadow: #000 1px 0 0, #000 0 1px 0, #000 -1px 0 0, #000 0 -1px 0; '; // 判定是否需要缩放 var length = this.strlen(value) || 1; style += 'font-size: ' + Math.min(1, 7 / length) + 'em; '; @@ -761,7 +768,7 @@ utils.prototype.__next_rand = function (_rand) { } ////// 读取一个本地文件内容 ////// -utils.prototype.readFile = function (success, error, readType) { +utils.prototype.readFile = function (success, error, accept, readType) { core.platform.successCallback = success; core.platform.errorCallback = error; @@ -800,6 +807,7 @@ utils.prototype.readFile = function (success, error, readType) { else core.platform.fileReader.readAsDataURL(core.platform.fileInput.files[0]); core.platform.fileInput.value = ''; } + if (accept) core.platform.fileInput.accept = accept; } core.platform.fileInput.click(); diff --git a/project/functions.js b/project/functions.js index ee55d2f7..71f6223a 100644 --- a/project/functions.js +++ b/project/functions.js @@ -71,26 +71,32 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 设置已经到过的楼层 core.setFlag("__visited__", {}); - - core.updateEnemys(); }, - "win": function(reason, norank) { + "win": function (reason, norank, noexit) { + // 游戏获胜事件 + // 请注意,成绩统计时是按照hp进行上传并排名 + // 可以先在这里对最终分数进行计算,比如将2倍攻击和5倍黄钥匙数量加到分数上 + // core.status.hero.hp += 2 * core.getRealStatus('atk') + 5 * core.itemCount('yellowKey'); + + // 如果不退出,则临时存储数据 + if (noexit) { + core.status.extraEvent = core.clone(core.status.event); + } + // 游戏获胜事件 core.ui.closePanel(); var replaying = core.isReplaying(); if (replaying) core.stopReplay(); - core.waitHeroToStop(function() { - core.clearMap('all'); // 清空全地图 - core.deleteAllCanvas(); // 删除所有创建的画布 - core.dom.gif2.innerHTML = ""; - // 请注意: - // 成绩统计时是按照hp进行上传并排名,因此光在这里改${status:hp}是无效的 - // 如需按照其他的的分数统计方式,请先将hp设置为你的得分 - // core.setStatus('hp', ...); + core.waitHeroToStop(function () { + if (!noexit) { + core.clearMap('all'); // 清空全地图 + core.deleteAllCanvas(); // 删除所有创建的画布 + core.dom.gif2.innerHTML = ""; + } core.drawText([ - "\t[" + (reason||"恭喜通关") + "]你的分数是${status:hp}。" + "\t[" + (reason || "恭喜通关") + "]你的分数是${status:hp}。" ], function () { - core.events.gameOver(reason||'', replaying, norank); + core.events.gameOver(reason || '', replaying, norank); }) }); }, @@ -634,9 +640,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = hero_atk = core.getRealStatusOrDefault(hero, 'atk'), hero_def = core.getRealStatusOrDefault(hero, 'def'), hero_mdef = core.getRealStatusOrDefault(hero, 'mdef'), - origin_hero_hp = hero_hp, - origin_hero_atk = hero_atk, - origin_hero_def = hero_def; + origin_hero_hp = core.getStatusOrDefault(hero, 'hp'), + origin_hero_atk = core.getStatusOrDefault(hero, 'atk'), + origin_hero_def = core.getStatusOrDefault(hero, 'def'); // 勇士的负属性都按0计算 hero_hp = Math.max(0, hero_hp); @@ -766,18 +772,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = "turn": Math.floor(turn), "damage": Math.floor(damage) }; -}, - "updateEnemys": function () { - // 更新怪物数据,可以在这里对怪物属性和数据进行动态更新,详见文档——事件——怪物数据的动态修改 - // 此函数执行时间:重新开始游戏、读档后、通过事件调用“更新怪物数据”时 - - // 比如下面这个例子,如果flag:xxx为真,则将绿头怪的攻击设为100,金币设为20 - /* - if (core.hasFlag('xxx')) { - core.material.enemys.greenSlime.atk = 100; - core.material.enemys.greenSlime.money = 20; - } - */ } }, "actions": { @@ -1004,8 +998,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.material.icons.hero.width = core.material.images.images[icon].width / 4; core.material.icons.hero.height = core.material.images.images[icon].height / 4; } - // 刷新怪物数据 - core.updateEnemys(); // TODO:增加自己的一些读档处理 @@ -1342,20 +1334,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = main.log(e); } } - - // 下面是一个并行事件开门的样例 - /* - // 如果某个flag为真 - if (core.hasFlag("xxx")) { - // 千万别忘了将该flag清空!否则下次仍然会执行这段代码。 - core.removeFlag("xxx"); - // 使用insertAction来插入若干自定义事件执行 - core.insertAction([ - {"type":"openDoor", "loc":[0,0], "floorId": "MT0"} - ]) - // 也可以写任意其他的脚本代码 - } - */ } }, "ui": {