Merge remote-tracking branch 'refs/remotes/ckcz123/v2.0' into v2.x

This commit is contained in:
YouWei Zhao 2018-07-21 21:45:14 +08:00
commit 1edb335803
19 changed files with 408 additions and 258 deletions

View File

@ -50,6 +50,7 @@ HTML5 canvas制作的魔塔样板支持全平台游戏
│ └─ 伤害和临界值计算器.exe # 一个能帮助计算怪物的伤害和临界值的小工具。 http://github.com/ckcz123/magic-tower-calculator/
├── /启动服务(mac版).app/ # 启动服务的mac版本。
├── editor.html # 可视化地图编辑工具
├── editor-mobile.html # 可视化地图编辑工具(手机版)
├── index.html # 主程序,游戏的入口
├── main.js # JS程序的入口将动态对所需JS进行加载
├── style.css # 游戏所需要用到的样式表
@ -58,6 +59,22 @@ HTML5 canvas制作的魔塔样板支持全平台游戏
## 更新说明
### 2018.7.9 V2.3.3
* [x] 适配手机端的造塔页面
* [x] 启动服务的多开版本
* [x] 新增事件:跟随效果
* [x] 怪物数据导出器
* [x] RM动画导出器也能导出音效
* [x] gif播放可随着分辨率自动放缩
* [x] 状态栏可随文字长度自动调整放缩
* [x] 楼传器一次可以翻10层
* [x] 也可以用status:exp来代替经验值的写法
* [x] V键也可以打开快捷商店
* [x] 破炸在周围只有一个目标时无需转向面对它
* [x] 道具效果中无需再将null改成""才能双击编辑了
* [x] 各个已知Bug的修复部分细节优化
### 2018.6.16 V2.3.1
* [x] 存档采用高比率压缩单个大小是原来的1/10

View File

@ -193,6 +193,7 @@ action
| setBlock_s
| setHeroIcon_s
| update_s
| updateEnemys_s
| sleep_s
| wait_s
| battle_s
@ -496,6 +497,18 @@ var code = '{"type": "update"},\n';
return code;
*/;
updateEnemys_s
: '更新怪物数据' Newline
/* updateEnemys_s
tooltip : updateEnemys: 立刻更新怪物数据
helpUrl : https://ckcz123.github.io/mota-js/#/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 '毫秒' Newline
@ -1702,6 +1715,10 @@ ActionParser.prototype.parseAction = function() {
this.next = MotaActionBlocks['update_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,this.next]);

View File

@ -495,6 +495,12 @@ data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"_bool": "bool",
"_data": "夹击方式是向上取整还是向下取整。如果此项为true则为向上取整为false则为向下取整"
},
"useLoop": {
"_leaf": true,
"_type": "checkbox",
"_bool": "bool",
"_data": "是否循环计算临界如果此项为true则使用循环法而不是回合数计算法来算临界"
},
"startDirectly": {
"_leaf": true,
"_type": "checkbox",

View File

@ -87,6 +87,7 @@ editor_blockly = function () {
MotaActionBlocks['setValue_s'].xmlText(),
MotaActionBlocks['input_s'].xmlText(),
MotaActionBlocks['update_s'].xmlText(),
MotaActionBlocks['updateEnemys_s'].xmlText(),
MotaActionBlocks['moveHero_s'].xmlText(),
MotaActionBlocks['jumpHero_s'].xmlText(),
MotaActionBlocks['changeFloor_s'].xmlText(),

View File

@ -99,6 +99,30 @@ functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
}
}
},
"enemy": {
"_leaf": false,
"_type": "object",
"_data": {
"getSpecials": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "怪物特殊属性的定义(获得怪物的特殊属性)"
},
"getDamageInfo": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "获得战斗伤害信息(实际伤害计算函数)"
},
"updateEnemys": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "更新怪物数据,可以在这里对怪物属性和数据进行动态更新"
}
}
},
"plugins": {
"_leaf": false,
"_type": "object",

View File

@ -338,7 +338,7 @@ core.enemys.getDamageInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef)
core.enemys.calDamage(enemy, hero_hp, hero_atk, hero_def, hero_mdef)
计算战斗伤害实际返回的是上面getDamageInfo中伤害的数值。
获得在某个勇士属性下怪物伤害实际返回的是上面getDamageInfo中伤害的数值。
core.enemys.getCurrentEnemys(floorId)

View File

@ -509,6 +509,12 @@ name是可选的代表目标行走图的文件名。
如果你需要刷新状态栏和地图显伤,只需要简单地调用 `{"type": "update"}` 即可。
### updateEnemys更新怪物数据
使用 `{"type": "updateEnemys"}` 可以动态修改怪物数据。
详见[怪物数据的动态修改](#怪物数据的动态修改)。
### sleep等待多少毫秒
等价于RMXP中的"等待x帧",不过是以毫秒来计算。
@ -1591,25 +1597,33 @@ core.insertAction([
而在我们的存档中是不会对怪物数据进行存储的只会存各个变量和Flag因此我们需要在读档后根据变量或Flag来调整怪物数据。
我们可以在脚本编辑中的`afterLoadData`进行处理。
我们可以在脚本编辑中的`updateEnemys`进行处理。
``` js
////// 读档事件后,载入事件前,可以执行的操作 //////
"afterLoadData" : function(data) {
// 读档事件后,载入事件前,可以执行的操作
if (core.hasFlag("fengyin")) { // 如果存在封印flag为真
core.material.enemys.blackKing.hp/=10; // 将怪物的血量变成原来的十分之一
// ...
}
// 同样难度分歧可以类似写 if (core.getFlag('hard', 0)==3) {...
"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;
}
*/
// 别忘了在事件中调用“更新怪物数据”事件!
}
```
// 在封印时可以调用setValue将该flag置为真然后调用自定义脚本 core.afterLoadData() 即可。
当我们获得一个道具(或者触发某个事件等)后,需要在事件中调用“更新怪物数据”事件。
``` js
// 调用`updateEnemys`(更新怪物数据)事件就可以触发了
"x,y": [
{"type": "setValue", "name": "flag:fengyin", "value": "true"}, // 封印
{"type": "function", "function": function() { // 手动调用自定义JS脚本 core.afterLoadData()
core.afterLoadData();
}}
"将flag:xxx置为真就可以让怪物数据发生改变",
{"type": "setValue", "name": "flag:xxx", "value": "true"}, // 将flag:xxx置为真
{"type": "updateEnemys"} // 更新怪物数据此时绿头怪攻击就会变成100了
]
```

View File

@ -244,6 +244,7 @@
<input type="button" value="数据区"/>
<input type="button" value="地图区"/>
<input type="button" value="素材库"/>
<input type="button" value="前往游戏" onclick="window.location='./index.html'"/>
</span>
<div id="menuDiv">
<div id="midMenu" style="display:none">
@ -268,10 +269,9 @@
<input type="button" value="保存地图" id='saveFloor'/>
<span id='mobileeditdata' style="display:none">
<input type="button" value="编辑"/>
<input type="button" value="显示完整名称"/>
<input type="button" value="显示完整名称" style="display: none;"/>
<input type="button" value="显示完整注释"/>
</span>
<input type="button" value="前往游戏" onclick="window.location='./index.html'"/>
<!-- -->
<div id="bgSelect" v-cloak style="display:none">
<span>当前地板: </span>

View File

@ -931,6 +931,8 @@ actions.prototype.clickBookDetail = function () {
actions.prototype.clickFly = function(x,y) {
if ((x==10 || x==11) && y==9) core.ui.drawFly(core.status.event.data-1);
if ((x==10 || x==11) && y==5) core.ui.drawFly(core.status.event.data+1);
if ((x==10 || x==11) && y==10) core.ui.drawFly(core.status.event.data-10);
if ((x==10 || x==11) && y==4) core.ui.drawFly(core.status.event.data+10);
if (x>=5 && x<=7 && y==12) core.ui.closePanel();
if (x>=0 && x<=9 && y>=3 && y<=11) {
var index=core.status.hero.flyRange.indexOf(core.status.floorId);
@ -948,8 +950,10 @@ actions.prototype.clickFly = function(x,y) {
////// 楼层传送器界面时,按下某个键的操作 //////
actions.prototype.keyDownFly = function (keycode) {
if (keycode==37 || keycode==38) core.ui.drawFly(core.status.event.data+1);
else if (keycode==39 || keycode==40) core.ui.drawFly(core.status.event.data-1);
if (keycode==37) core.ui.drawFly(core.status.event.data-10);
else if ( keycode==38) core.ui.drawFly(core.status.event.data+1);
else if (keycode==39) core.ui.drawFly(core.status.event.data+10);
else if (keycode==40) core.ui.drawFly(core.status.event.data-1);
return;
}
@ -1184,8 +1188,8 @@ actions.prototype.clickToolbox = function(x,y) {
}
// 下一页
if ((x == 8 || x == 9) && y == 12) {
var toolPage = parseInt(Object.keys(core.status.hero.items.tools).length/12)+1,
constantPage = parseInt(Object.keys(core.status.hero.items.constants).length/12)+1;
var toolPage = Math.ceil(Object.keys(core.status.hero.items.tools).length/12),
constantPage = Math.ceil(Object.keys(core.status.hero.items.constants).length/12);
if (page<toolPage) {
core.ui.drawToolbox(12*page);
}

View File

@ -292,10 +292,7 @@ control.prototype.resetStatus = function(hero, hard, floorId, route, maps, value
core.values = core.clone(values);
else core.values = core.clone(core.data.values);
core.flags = core.clone(core.data.flags);
core.events.initGame();
}
////// 开始游戏 //////
@ -1663,14 +1660,14 @@ control.prototype.startReplay = function (list) {
////// 更改播放状态 //////
control.prototype.triggerReplay = function () {
if (core.status.event.id=='save') return;
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (core.status.replay.pausing) this.resumeReplay();
else this.pauseReplay();
}
////// 暂停播放 //////
control.prototype.pauseReplay = function () {
if (core.status.event.id=='save') return;
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
core.status.replay.pausing = true;
core.updateStatusBar();
@ -1679,7 +1676,7 @@ control.prototype.pauseReplay = function () {
////// 恢复播放 //////
control.prototype.resumeReplay = function () {
if (core.status.event.id=='save') return;
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
core.status.replay.pausing = false;
core.updateStatusBar();
@ -1689,7 +1686,7 @@ control.prototype.resumeReplay = function () {
////// 加速播放 //////
control.prototype.speedUpReplay = function () {
if (core.status.event.id=='save') return;
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
var toAdd = core.status.replay.speed>=3?3:core.status.replay.speed>=2?2:1;
core.status.replay.speed = parseInt(10*core.status.replay.speed + toAdd)/10;
@ -1699,7 +1696,7 @@ control.prototype.speedUpReplay = function () {
////// 减速播放 //////
control.prototype.speedDownReplay = function () {
if (core.status.event.id=='save') return;
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
var toAdd = core.status.replay.speed>3?3:core.status.replay.speed>2?2:1;
core.status.replay.speed = parseInt(10*core.status.replay.speed - toAdd)/10;
@ -1709,7 +1706,7 @@ control.prototype.speedDownReplay = function () {
////// 停止播放 //////
control.prototype.stopReplay = function () {
if (core.status.event.id=='save') return;
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
core.status.replay.toReplay = [];
core.status.replay.totalList = [];
@ -1724,7 +1721,7 @@ control.prototype.stopReplay = function () {
////// 回退 //////
control.prototype.rewindReplay = function () {
if (core.status.event.id=='save') return;
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
if (!core.status.replay.pausing) {
core.drawTip("请先暂停录像");
@ -1759,6 +1756,7 @@ control.prototype.rewindReplay = function () {
////// 回放时存档 //////
control.prototype.saveReplay = function () {
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
if (!core.status.replay.pausing) {
core.drawTip("请先暂停录像");
@ -1779,6 +1777,7 @@ control.prototype.saveReplay = function () {
////// 回放时查看怪物手册 //////
control.prototype.bookReplay = function () {
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
if (!core.status.replay.pausing) {
core.drawTip("请先暂停录像");
@ -2331,7 +2330,8 @@ control.prototype.getStatus = function (statusName) {
////// 获得某个等级的名称 //////
control.prototype.getLvName = function () {
if (core.status.hero.lv>core.firstData.levelUp.length) return core.status.hero.lv;
if (!core.isset(core.firstData.levelUp) || core.status.hero.lv<=0
|| core.status.hero.lv>core.firstData.levelUp.length) return core.status.hero.lv;
return core.firstData.levelUp[core.status.hero.lv-1].name || core.status.hero.lv;
}

View File

@ -170,11 +170,12 @@ core.prototype.init = function (coreData, callback) {
core.flags.battleAnimate = false;
core.setLocalStorage('battleAnimate', false);
}
// core.initStatus.shops = core.firstData.shops;
core.firstData.shops.forEach(function (t) {
core.initStatus.shops[t.id] = t;
})
if (core.isset(core.firstData.shops)) {
core.firstData.shops.forEach(function (t) {
core.initStatus.shops[t.id] = t;
})
}
core.dom.versionLabel.innerHTML = core.firstData.version;
core.dom.logoLabel.innerHTML = core.firstData.title;
@ -310,7 +311,7 @@ core.prototype.resetStatus = function(hero, hard, floorId, route, maps, values)
////// 开始游戏 //////
core.prototype.startGame = function (hard, callback) {
core.control.startGame(hard, callback);huo
core.control.startGame(hard, callback);
}
////// 重新开始游戏;此函数将回到标题页面 //////

View File

@ -4,9 +4,9 @@ function enemys() {
////// 初始化 //////
enemys.prototype.init = function () {
// 怪物属性初始化定义:
this.enemys = enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80;
//delete(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80);
this.enemydata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.enemy;
this.enemydata.hasSpecial = function (a, b) {return core.enemys.hasSpecial(a, b)};
}
////// 获得一个或所有怪物数据 //////
@ -41,129 +41,112 @@ enemys.prototype.hasSpecial = function (special, test) {
return false;
}
enemys.prototype.getSpecials = function () {
return this.enemydata.getSpecials();
}
enemys.prototype.calContent = function (enemy, content) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
if (typeof content == 'string') return content;
if (content instanceof Function) {
return content(enemy);
}
return "";
}
////// 获得所有特殊属性的名称 //////
enemys.prototype.getSpecialText = function (enemyId) {
var enemy = core.material.enemys[enemyId];
enemys.prototype.getSpecialText = function (enemy) {
// 移动到了脚本编辑 - getSpecials中
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
if (!core.isset(enemy)) return [];
var special = enemy.special;
var text = [];
if (this.hasSpecial(special, 1)) text.push("先攻");
if (this.hasSpecial(special, 2)) text.push("魔攻");
if (this.hasSpecial(special, 3)) text.push("坚固");
if (this.hasSpecial(special, 4)) text.push("2连击");
if (this.hasSpecial(special, 5)) text.push("3连击");
if (this.hasSpecial(special, 6)) text.push((enemy.n||4)+"连击");
if (this.hasSpecial(special, 7)) text.push("破甲");
if (this.hasSpecial(special, 8)) text.push("反击");
if (this.hasSpecial(special, 9)) text.push("净化");
if (this.hasSpecial(special, 10)) text.push("模仿");
if (this.hasSpecial(special, 11)) text.push("吸血");
if (this.hasSpecial(special, 12)) text.push("中毒");
if (this.hasSpecial(special, 13)) text.push("衰弱");
if (this.hasSpecial(special, 14)) text.push("诅咒");
if (this.hasSpecial(special, 15)) text.push("领域");
if (this.hasSpecial(special, 16)) text.push("夹击");
if (this.hasSpecial(special, 17)) text.push("仇恨");
if (this.hasSpecial(special, 18)) text.push("阻击");
if (this.hasSpecial(special, 19)) text.push("自爆");
if (this.hasSpecial(special, 20)) text.push("无敌");
if (this.hasSpecial(special, 21)) text.push("退化");
if (this.hasSpecial(special, 22)) text.push("固伤");
if (this.hasSpecial(special, 23)) text.push("重生");
var specials=this.getSpecials();
if (core.isset(specials)) {
for (var i=0;i<specials.length;i++) {
if (this.hasSpecial(special, specials[i][0]))
text.push(this.calContent(enemy, specials[i][1]));
}
}
return text;
}
////// 获得每个特殊属性的说明 //////
enemys.prototype.getSpecialHint = function (enemy, special) {
// 移动到了脚本编辑 - getSpecials中
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
var specials=this.getSpecials();
if (!core.isset(special)) {
if (!core.isset(specials)) return [];
var hints = [];
for (var i=1;i<100;i++) {
if (this.hasSpecial(enemy.special, i)) {
var hint=this.getSpecialHint(enemy, i);
if (hint!='')
hints.push(hint);
}
for (var i=0;i<specials.length;i++) {
if (this.hasSpecial(enemy, specials[i][0]))
hints.push(this.calContent(enemy, specials[i][1])+""+this.calContent(enemy, specials[i][2]));
}
return hints;
}
switch (special) {
case 1: return "先攻:怪物首先攻击";
case 2: return "魔攻:怪物无视勇士的防御";
case 3: return "坚固勇士每回合最多只能对怪物造成1点伤害";
case 4: return "2连击怪物每回合攻击2次";
case 5: return "3连击怪物每回合攻击3次";
case 6: return (enemy.n||4)+"连击: 怪物每回合攻击"+(enemy.n||4)+"次";
case 7: return "破甲:战斗前,怪物附加角色防御的"+Math.floor(100*core.values.breakArmor||0)+"%作为伤害";
case 8: return "反击:战斗时,怪物每回合附加角色攻击的"+Math.floor(100*core.values.counterAttack||0)+"%作为伤害,无视角色防御";
case 9: return "净化:战斗前,怪物附加勇士魔防的"+core.values.purify+"倍作为伤害";
case 10: return "模仿:怪物的攻防和勇士攻防相等";
case 11: return "吸血:战斗前,怪物首先吸取角色的"+Math.floor(100*enemy.value||0)+"%生命作为伤害"+(enemy.add?",并把伤害数值加到自身生命上":"");
case 12: return "中毒:战斗后,勇士陷入中毒状态,每一步损失生命"+core.values.poisonDamage+"点";
case 13: return "衰弱:战斗后,勇士陷入衰弱状态,攻防暂时下降"+(core.values.weakValue>=1?core.values.weakValue+"点":parseInt(core.values.weakValue*100)+"%");
case 14: return "诅咒:战斗后,勇士陷入诅咒状态,战斗无法获得金币和经验";
case 15: return "领域:经过怪物周围"+(enemy.range||1)+"格时自动减生命"+(enemy.value||0)+"点";
case 16: return "夹击:经过两只相同的怪物中间,勇士生命值变成一半";
case 17: return "仇恨:战斗前,怪物附加之前积累的仇恨值作为伤害"+(core.flags.hatredDecrease?";战斗后,释放一半的仇恨值":"")+"。(每杀死一个怪物获得"+(core.values.hatred||0)+"点仇恨值)";
case 18: return "阻击:经过怪物的十字领域时自动减生命"+(enemy.value||0)+"点,同时怪物后退一格";
case 19: return "自爆战斗后勇士的生命值变成1";
case 20: return "无敌:勇士无法打败怪物,除非拥有十字架";
case 21: return "退化:战斗后勇士永久下降"+(enemy.atkValue||0)+"点攻击和"+(enemy.defValue||0)+"点防御";
case 22: return "固伤:战斗前,怪物对勇士造成"+(enemy.damage||0)+"点固定伤害,无视勇士魔防。";
case 23: return "重生:怪物被击败后,角色转换楼层则怪物将再次出现";
default: break;
if (!core.isset(specials)) return "";
for (var i=0;i<specials.length;i++) {
if (special == specials[i][0])
return this.calContent(enemy, specials[i][1])+""+this.calContent(enemy, specials[i][2]);
}
return "";
}
////// 能否获胜 //////
enemys.prototype.canBattle = function (monsterId) {
var damage = this.getDamage(monsterId);
enemys.prototype.canBattle = function (enemyId) {
var damage = this.getDamage(enemyId);
return damage != null && damage < core.status.hero.hp;
}
////// 获得某个怪物的伤害 //////
enemys.prototype.getDamage = function (monsterId) {
var monster = core.material.enemys[monsterId];
var damage = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
enemys.prototype.getDamage = function (enemy) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
var damage = this.calDamage(enemy, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
if (damage == null) return null;
return damage + this.getExtraDamage(monster);
return damage + this.getExtraDamage(enemy);
}
////// 获得某个怪物的额外伤害 //////
enemys.prototype.getExtraDamage = function (monster) {
enemys.prototype.getExtraDamage = function (enemy) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
var extra_damage = 0;
if (this.hasSpecial(monster.special, 17)) { // 仇恨
if (this.hasSpecial(enemy.special, 17)) { // 仇恨
extra_damage += core.getFlag('hatred', 0);
}
if (this.hasSpecial(monster.special, 22)) { // 固伤
extra_damage += monster.damage||0;
if (this.hasSpecial(enemy.special, 22)) { // 固伤
extra_damage += enemy.damage||0;
}
return extra_damage;
}
////// 接下来N个临界值和临界减伤计算 //////
enemys.prototype.nextCriticals = function (monsterId, number) {
enemys.prototype.nextCriticals = function (enemy, number) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
var useTurn = true; // 是否使用回合法计算临界值如果要用循环法则直接改为false。
var useTurn = !core.flags.useLoop; // 是否使用回合法计算临界值如果要用循环法则直接改为false。
number = number||1;
var monster = core.material.enemys[monsterId];
if (this.hasSpecial(monster.special, 3)) {
if (core.status.hero.atk<=monster.def) {
return [[monster.def+1-core.status.hero.atk,'?']];
if (this.hasSpecial(enemy.special, 3)) {
if (core.status.hero.atk<=enemy.def) {
return [[enemy.def+1-core.status.hero.atk,'?']];
}
return [];
}
// 坚固、模仿怪物没有临界!
if (this.hasSpecial(monster.special, 10)) return [];
var info = this.getDamageInfo(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
if (this.hasSpecial(enemy.special, 10)) return [];
var info = this.getDamageInfo(enemy, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
if (info == null) {
if (core.status.hero.atk<=monster.def) {
return [[monster.def+1-core.status.hero.atk,'?']];
if (core.status.hero.atk<=enemy.def) {
return [[enemy.def+1-core.status.hero.atk,'?']];
}
return [];
}
@ -173,14 +156,14 @@ enemys.prototype.nextCriticals = function (monsterId, number) {
}
var list = [], pre = null;
var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = monster.def, turn = info.turn;
var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = enemy.def, turn = info.turn;
if (useTurn) { // 回合数计算法
for (var t = turn-1;t>=1;t--) {
var nextAtk = Math.ceil(mon_hp/t) + mon_def;
if (nextAtk<=hero_atk) break;
if (nextAtk!=pre) {
var nextInfo = this.getDamageInfo(monster, core.status.hero.hp, nextAtk, core.status.hero.def, core.status.hero.mdef);
var nextInfo = this.getDamageInfo(enemy, core.status.hero.hp, nextAtk, core.status.hero.def, core.status.hero.mdef);
if (nextInfo==null) break;
list.push([nextAtk-hero_atk,info.damage-nextInfo.damage]);
if (nextInfo.damage<=0 && !core.flags.enableNegativeDamage) break;
@ -193,7 +176,7 @@ enemys.prototype.nextCriticals = function (monsterId, number) {
else { // 暴力for循环法
pre = info.damage;
for (var atk=hero_atk+1;atk<=mon_hp+mon_def;atk++) {
var nextInfo = this.getDamageInfo(monster, core.status.hero.hp, atk, core.status.hero.def, core.status.hero.mdef);
var nextInfo = this.getDamageInfo(enemy, core.status.hero.hp, atk, core.status.hero.def, core.status.hero.mdef);
if (nextInfo==null) break;
if (pre>nextInfo.damage) {
pre = nextInfo.damage;
@ -208,115 +191,34 @@ enemys.prototype.nextCriticals = function (monsterId, number) {
}
////// N防减伤计算 //////
enemys.prototype.getDefDamage = function (monsterId, k) {
enemys.prototype.getDefDamage = function (enemy, k) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
k = k || 1;
var monster = core.material.enemys[monsterId];
var nowDamage = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
var nextDamage = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def + k, core.status.hero.mdef);
var nowDamage = this.calDamage(enemy, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
var nextDamage = this.calDamage(enemy, core.status.hero.hp, core.status.hero.atk, core.status.hero.def + k, core.status.hero.mdef);
if (nowDamage == null || nextDamage ==null) return "???";
return nowDamage - nextDamage;
}
////// 获得战斗伤害信息 //////
enemys.prototype.getDamageInfo = function(monster, hero_hp, hero_atk, hero_def, hero_mdef) {
if (typeof monster == 'string') {
monster = core.material.enemys[monster];
}
var mon_hp = monster.hp, mon_atk = monster.atk, mon_def = monster.def, mon_special = monster.special;
hero_hp=Math.max(0, hero_hp);
hero_atk=Math.max(0, hero_atk);
hero_def=Math.max(0, hero_def);
hero_mdef=Math.max(0, hero_mdef);
if (this.hasSpecial(mon_special, 20) && !core.hasItem("cross")) // 如果是无敌属性,且勇士未持有十字架
return null; // 返回不可战斗
var initDamage = 0; // 战前伤害
// 吸血
if (this.hasSpecial(mon_special, 11)) {
var vampireDamage = hero_hp * monster.value;
// 如果有神圣盾免疫吸血等可以在这里写
vampireDamage = Math.floor(vampireDamage) || 0;
// 加到自身
if (monster.add) // 如果加到自身
mon_hp += vampireDamage;
initDamage += vampireDamage;
}
// 模仿
if (this.hasSpecial(mon_special,10)) {
mon_atk = hero_atk;
mon_def = hero_def;
}
// 坚固
if (this.hasSpecial(mon_special,3) && mon_def < hero_atk - 1) mon_def = hero_atk - 1;
if (hero_atk <= mon_def) return null; // 不可战斗时请直接返回null
var per_damage = mon_atk - hero_def;
// 魔攻
if (this.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 *= (monster.n||4);
var counterDamage = 0;
// 反击
if (this.hasSpecial(mon_special, 8)) counterDamage += Math.floor(core.values.counterAttack * hero_atk);
// 先攻
if (this.hasSpecial(mon_special, 1))
initDamage += per_damage;
// 破甲
if (this.hasSpecial(mon_special, 7))
initDamage += Math.floor(core.values.breakArmor * hero_def);
// 净化
if (this.hasSpecial(mon_special, 9))
initDamage += Math.floor(core.values.purify * hero_mdef);
// turn: 勇士攻击回合数
var turn = Math.ceil(mon_hp / (hero_atk - mon_def));
var ans = initDamage + (turn - 1) * per_damage + turn * counterDamage;
ans -= hero_mdef;
if (!core.flags.enableNegativeDamage)
ans=Math.max(0, ans);
return {
"hero_atk": hero_atk,
"hero_def": hero_def,
"hero_mdef": hero_mdef,
"mon_hp": mon_hp,
"mon_atk": mon_atk,
"mon_def": mon_def,
"per_damage": per_damage,
"initDamage": initDamage,
"turn": turn,
"damage": ans
};
////// 获得战斗伤害信息(实际伤害计算函数) //////
enemys.prototype.getDamageInfo = function(enemy, hero_hp, hero_atk, hero_def, hero_mdef) {
// 移动到了脚本编辑 - getDamageInfo中
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
return this.enemydata.getDamageInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef);
}
////// 具体的伤害计算公式 //////
enemys.prototype.calDamage = function (monster, hero_hp, hero_atk, hero_def, hero_mdef) {
////// 获得在某个勇士属性下怪物伤害 //////
enemys.prototype.calDamage = function (enemy, hero_hp, hero_atk, hero_def, hero_mdef) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
if (typeof monster == 'string') {
monster = core.material.enemys[monster];
}
var info = this.getDamageInfo(monster, hero_hp, hero_atk, hero_def, hero_mdef);
var info = this.getDamageInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef);
if (info == null) return null;
return info.damage;
}
////// 更新怪物数据 //////
enemys.prototype.updateEnemys = function () {
return this.enemydata.updateEnemys();
}
////// 获得当前楼层的怪物列表 //////
@ -328,42 +230,42 @@ enemys.prototype.getCurrentEnemys = function (floorId) {
for (var b = 0; b < mapBlocks.length; b++) {
if (core.isset(mapBlocks[b].event) && !(core.isset(mapBlocks[b].enable) && !mapBlocks[b].enable)
&& mapBlocks[b].event.cls.indexOf('enemy')==0) {
var monsterId = mapBlocks[b].event.id;
if (core.isset(used[monsterId])) continue;
var enemyId = mapBlocks[b].event.id;
if (core.isset(used[enemyId])) continue;
var monster = core.material.enemys[monsterId];
var mon_hp = monster.hp, mon_atk = monster.atk, mon_def = monster.def;
if (this.hasSpecial(monster.special, 10)) {
var enemy = core.material.enemys[enemyId];
var mon_hp = enemy.hp, mon_atk = enemy.atk, mon_def = enemy.def;
if (this.hasSpecial(enemy.special, 10)) {
mon_atk=core.status.hero.atk;
mon_def=core.status.hero.def;
}
if (this.hasSpecial(monster.special, 3) && mon_def < core.status.hero.atk - 1)
if (this.hasSpecial(enemy.special, 3) && mon_def < core.status.hero.atk - 1)
mon_def = core.status.hero.atk - 1;
var specialText = core.enemys.getSpecialText(monsterId);
var specialText = core.enemys.getSpecialText(enemyId);
if (specialText.length>=3) specialText = "多属性...";
else specialText = specialText.join(" ");
var critical = this.nextCriticals(monsterId);
var critical = this.nextCriticals(enemyId);
if (critical.length>0) critical=critical[0];
enemys.push({
'id': monsterId,
'name': monster.name,
'id': enemyId,
'name': enemy.name,
'hp': mon_hp,
'atk': mon_atk,
'def': mon_def,
'money': monster.money,
'experience': monster.experience,
'point': monster.point||0, // 加点
'money': enemy.money,
'experience': enemy.experience,
'point': enemy.point||0, // 加点
'special': specialText,
'damage': this.getDamage(monsterId),
'damage': this.getDamage(enemyId),
'critical': critical[0],
'criticalDamage': critical[1],
'defDamage': this.getDefDamage(monsterId)
'defDamage': this.getDefDamage(enemyId)
});
used[monsterId] = true;
used[enemyId] = true;
}
}

View File

@ -802,6 +802,11 @@ events.prototype.doAction = function() {
core.updateStatusBar();
this.doAction();
break;
case "updateEnemys":
core.enemys.updateEnemys();
core.updateStatusBar();
this.doAction();
break;
case "sleep": // 等待多少毫秒
if (core.status.replay.replaying)
core.events.doAction();
@ -1376,7 +1381,8 @@ events.prototype.setHeroIcon = function (name) {
////// 检查升级事件 //////
events.prototype.checkLvUp = function () {
if (!core.flags.enableLevelUp || core.status.hero.lv>=core.firstData.levelUp.length) return;
if (!core.flags.enableLevelUp || !core.isset(core.firstData.levelUp)
|| core.status.hero.lv>=core.firstData.levelUp.length) return;
// 计算下一个所需要的数值
var need=core.firstData.levelUp[core.status.hero.lv].need;
if (!core.isset(need)) return;

View File

@ -1307,10 +1307,10 @@ ui.prototype.drawBook = function (index) {
damage = core.formatBigNumber(damage);
if (core.enemys.hasSpecial(core.material.enemys[enemy.id], 19))
damage += "+";
if (core.material.enemys[enemy.id].notBomb)
damage += "[b]";
}
if (core.material.enemys[enemy.id].notBomb)
damage += "[b]";
core.fillText('ui', damage, damageOffset, 62 * i + 50, color, 'bold 13px Verdana');
core.canvas.ui.textAlign = "left";
@ -1419,10 +1419,16 @@ ui.prototype.drawFly = function(page) {
core.fillText('ui', '楼层跳跃', 208, 60, '#FFFFFF', "bold 28px Verdana");
core.fillText('ui', '返回游戏', 208, 403, '#FFFFFF', "bold 15px Verdana")
core.fillText('ui', title, 356, 247, '#FFFFFF', "bold 19px Verdana");
if (page<core.status.hero.flyRange.length-1)
core.fillText('ui', '▲', 356, 247-64, '#FFFFFF', "17px Verdana");
if (page>0)
core.fillText('ui', '▼', 356, 247+64, '#FFFFFF', "17px Verdana");
if (page<core.status.hero.flyRange.length-1) {
core.fillText('ui', '▲', 356, 247 - 64, '#FFFFFF', "17px Verdana");
core.fillText('ui', '▲', 356, 247 - 96, '#FFFFFF', "17px Verdana");
core.fillText('ui', '▲', 356, 247 - 96 - 7, '#FFFFFF', "17px Verdana");
}
if (page>0) {
core.fillText('ui', '▼', 356, 247 + 64, '#FFFFFF', "17px Verdana");
core.fillText('ui', '▼', 356, 247 + 96, '#FFFFFF', "17px Verdana");
core.fillText('ui', '▼', 356, 247 + 96 + 7, '#FFFFFF', "17px Verdana");
}
core.strokeRect('ui', 20, 100, 273, 273, '#FFFFFF', 2);
this.drawThumbnail(floorId, 'ui', core.status.maps[floorId].blocks, 20, 100, 273);
}
@ -1484,7 +1490,7 @@ ui.prototype.drawToolbox = function(index) {
}
var page = parseInt((index%1000)/12)+1;
var totalPage = parseInt(Math.max(tools.length, constants.length)/12)+1;
var totalPage = Math.ceil(Math.max(tools.length, constants.length)/12);
if (!core.hasItem(selectId)) selectId=null;
@ -1785,8 +1791,8 @@ ui.prototype.drawStatistics = function () {
'count': 0, 'money': 0, 'experience': 0, 'point': 0,
},
'count': {
'yellowDoor': 0, 'blueDoor': 0, 'redDoor': 0, 'steelDoor': 0,
'yellowKey': 0, 'blueKey': 0, 'redKey': 0, 'steelKey': 0,
'yellowDoor': 0, 'blueDoor': 0, 'redDoor': 0, 'greenDoor': 0, 'steelDoor': 0,
'yellowKey': 0, 'blueKey': 0, 'redKey': 0, 'greenKey': 0, 'steelKey': 0,
'redJewel': 0, 'blueJewel': 0, 'greenJewel': 0, 'yellowJewel': 0,
'redPotion': 0, 'bluePotion': 0, 'greenPotion': 0, 'yellowPotion': 0, 'superPotion': 0,
'pickaxe': 0, 'bomb': 0, 'centerFly': 0,
@ -1889,6 +1895,7 @@ ui.prototype.drawStatistics = function () {
if (key=='yellowDoor') name="黄门";
else if (key=='blueDoor') name="蓝门";
else if (key=='redDoor') name="红门";
else if (key=='greenDoor') name="绿门";
else if (key=='steelDoor') name="铁门";
else name=core.material.items[key].name;
if (core.isset(name)) {

View File

@ -2,7 +2,7 @@ function main() {
//------------------------ 用户修改内容 ------------------------//
this.version = "2.3.1"; // 游戏版本号如果更改了游戏内容建议修改此version以免造成缓存问题。
this.version = "2.3.2"; // 游戏版本号如果更改了游戏内容建议修改此version以免造成缓存问题。
this.useCompress = false; // 是否使用压缩文件
// 当你即将发布你的塔时请使用“JS代码压缩工具”将所有js代码进行压缩然后将这里的useCompress改为true。

View File

@ -26,7 +26,7 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"firstData" : {
"title": "魔塔样板",
"name": "template",
"version": "Ver 2.3.1",
"version": "Ver 2.3.2",
"floorId": "sample0",
"hero": {
"name": "阳光",
@ -152,9 +152,10 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"enableNegativeDamage": false,
"hatredDecrease": true,
"betweenAttackCeil": false,
"useLoop": false,
"startDirectly": false,
"canOpenBattleAnimate": true,
"showBattleAnimateConfirm": true,
"showBattleAnimateConfirm": false,
"battleAnimate": false,
"displayEnemyDamage": true,
"displayCritical": true,

View File

@ -301,9 +301,145 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a =
////// 读档事件后,载入事件前,可以执行的操作 //////
"afterLoadData" : function(data) {
// 读档事件后,载入事件前,可以执行的操作
// 可以在这里对怪物数据进行动态修改,详见文档——事件——怪物数据的动态修改
// 怪物数据的动态修改迁移到了“脚本编辑 - updateEnemys”中详见文档说明
core.enemys.updateEnemys();
}
},
"enemy": {
"getSpecials" : function() {
// 获得怪物的特殊属性,每一行定义一个特殊属性。
// 分为三项,第一项为该特殊属性的数字,第二项为特殊属性的名字,第三项为特殊属性的描述
// 可以直接写字符串也可以写个function将怪物传进去
return [
[1, "先攻", "怪物首先攻击"],
[2, "魔攻", "怪物无视勇士的防御"],
[3, "坚固", "勇士每回合最多只能对怪物造成1点伤害"],
[4, "2连击", "怪物每回合攻击2次"],
[5, "3连击", "怪物每回合攻击3次"],
[6, function(enemy) {return (enemy.n||4)+"连击";}, function(enemy) {return "怪物每回合攻击"+(enemy.n||4)+"次";}],
[7, "破甲", "战斗前,怪物附加角色防御的"+Math.floor(100*core.values.breakArmor||0)+"%作为伤害"],
[8, "反击", "战斗时,怪物每回合附加角色攻击的"+Math.floor(100*core.values.counterAttack||0)+"%作为伤害,无视角色防御"],
[9, "净化", "战斗前,怪物附加勇士魔防的"+core.values.purify+"倍作为伤害"],
[10, "模仿", "怪物的攻防和勇士攻防相等"],
[11, "吸血", function (enemy) {return "吸血:战斗前,怪物首先吸取角色的"+Math.floor(100*enemy.value||0)+"%生命作为伤害"+(enemy.add?",并把伤害数值加到自身生命上":"");}],
[12, "中毒", "战斗后,勇士陷入中毒状态,每一步损失生命"+core.values.poisonDamage+"点"],
[13, "衰弱", "战斗后,勇士陷入衰弱状态,攻防暂时下降"+(core.values.weakValue>=1?core.values.weakValue+"点":parseInt(core.values.weakValue*100)+"%")],
[14, "诅咒", "战斗后,勇士陷入诅咒状态,战斗无法获得金币和经验"],
[15, "领域", function (enemy) {return "经过怪物周围"+(enemy.range||1)+"格时自动减生命"+(enemy.value||0)+"点";}],
[16, "夹击", "经过两只相同的怪物中间,勇士生命值变成一半"],
[17, "仇恨", "战斗前,怪物附加之前积累的仇恨值作为伤害"+(core.flags.hatredDecrease?";战斗后,释放一半的仇恨值":"")+"。(每杀死一个怪物获得"+(core.values.hatred||0)+"点仇恨值)"],
[18, "阻击", function (enemy) {return "经过怪物的十字领域时自动减生命"+(enemy.value||0)+"点,同时怪物后退一格";}],
[19, "自爆", "战斗后勇士的生命值变成1"],
[20, "无敌", "勇士无法打败怪物,除非拥有十字架"],
[21, "退化", function (enemy) {return "战斗后勇士永久下降"+(enemy.atkValue||0)+"点攻击和"+(enemy.defValue||0)+"点防御";}],
[22, "固伤", function (enemy) {return "战斗前,怪物对勇士造成"+(enemy.damage||0)+"点固定伤害,无视勇士魔防。";}],
[23, "重生", "怪物被击败后,角色转换楼层则怪物将再次出现"]
];
},
"getDamageInfo" : function (enemy, hero_hp, hero_atk, hero_def, hero_mdef) {
// 获得战斗伤害信息(实际伤害计算函数)
// 怪物生命,怪物攻击、防御、特殊属性
var mon_hp = enemy.hp, mon_atk = enemy.atk, mon_def = enemy.def, mon_special = enemy.special;
// 勇士的负属性都按0计算
hero_hp=Math.max(0, hero_hp); hero_atk=Math.max(0, hero_atk); hero_def=Math.max(0, hero_def); hero_mdef=Math.max(0, hero_mdef);
// 如果是无敌属性,且勇士未持有十字架
if (this.hasSpecial(mon_special, 20) && !core.hasItem("cross"))
return null; // 不可战斗
// 战前造成的额外伤害(可被魔防抵消)
var init_damage = 0;
// 吸血
if (this.hasSpecial(mon_special, 11)) {
var vampire_damage = hero_hp * enemy.value;
// 如果有神圣盾免疫吸血等可以在这里写
// if (core.hasFlag('shield5')) vampire_damage = 0;
vampire_damage = Math.floor(vampire_damage) || 0;
// 加到自身
if (enemy.add) // 如果加到自身
mon_hp += vampire_damage;
init_damage += vampire_damage;
}
// 模仿
if (this.hasSpecial(mon_special, 10)) {
mon_atk = hero_atk;
mon_def = hero_def;
}
// 坚固
if (this.hasSpecial(mon_special, 3) && mon_def < hero_atk - 1)
mon_def = hero_atk - 1;
// 检查是否破防;否则直接返回不可战斗
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 (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);
// 每回合的反击伤害;反击是按照勇士的攻击次数来计算回合
var counterDamage = 0;
if (this.hasSpecial(mon_special, 8)) counterDamage += Math.floor(core.values.counterAttack * hero_atk);
// 先攻
if (this.hasSpecial(mon_special, 1)) init_damage += per_damage;
// 破甲
if (this.hasSpecial(mon_special, 7))
init_damage += Math.floor(core.values.breakArmor * hero_def);
// 净化
if (this.hasSpecial(mon_special, 9))
init_damage += Math.floor(core.values.purify * hero_mdef);
// 勇士每回合对怪物造成的伤害
var hero_per_damage = hero_atk - mon_def;
// 勇士的攻击回合数;为怪物生命除以每回合伤害向上取整
var turn = Math.ceil(mon_hp / hero_per_damage);
// 最终伤害:初始伤害 + 怪物对勇士造成的伤害 + 反击伤害
var damage = init_damage + (turn - 1) * per_damage + turn * counterDamage;
// 再扣去魔防
damage -= hero_mdef;
// 检查是否允许负伤
if (!core.flags.enableNegativeDamage)
damage=Math.max(0, damage);
return {
"mon_hp": mon_hp,
"mon_atk": mon_atk,
"mon_def": mon_def,
"init_damage": init_damage,
"per_damage": per_damage,
"hero_per_damage": hero_per_damage,
"turn": turn,
"damage": damage
};
},
"updateEnemys" : function () {
// 更新怪物数据,可以在这里对怪物属性和数据进行动态更新,详见文档——事件——怪物数据的动态修改
// 比如下面这个例子如果flag:xxx为真则将绿头怪的攻击设为100金币设为20
/*
if (core.hasFlag('xxx')) {
core.material.enemys.greenSlime.atk = 100;
core.material.enemys.greenSlime.money = 20;
}
*/
// 别忘了在事件中调用“更新怪物数据”事件!
}
},
"ui":{

Binary file not shown.

View File

@ -1,16 +1,30 @@
HTML5魔塔样板V2.3.2
HTML5魔塔样板V2.3.3
启动服务的多开版本 √
跟随效果 √
将怪物特殊属性定义和伤害计算函数移动到脚本编辑中 √
事件:画面震动
事件:更新怪物数据 √
移动事件和跳跃事件增加“不消失”选项
修改默认bgm √
修复读档开启战斗动画等Bug √
大量细节优化 √
-----------------------------------------------------------------------
HTML5魔塔样板V2.3.2
适配手机端的造塔页面
启动服务的多开版本
事件:跟随效果
怪物数据导出器
RM动画导出器也能导出音效 √
gif播放可随着分辨率自动放缩 √
状态栏可随文字长度自动调整放缩 √
也可以用status:exp来代替经验值的写法 √
V键也可以打开快捷商店 √
破炸在周围只有一个目标时无需转向面对它 √
道具效果中无需再将null改成""才能双击编辑了 √
各个已知Bug的修复部分细节优化 √
RM动画导出器也能导出音效
gif播放可随着分辨率自动放缩
状态栏可随文字长度自动调整放缩
楼传器一次可以翻10层
也可以用status:exp来代替经验值的写法
V键也可以打开快捷商店
破炸在周围只有一个目标时无需转向面对它
道具效果中无需再将null改成""才能双击编辑了
各个已知Bug的修复部分细节优化
-----------------------------------------------------------------------