diff --git a/.gitignore b/.gitignore
index 359a1962..94816db6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
.vscode
*ce5eec52_2fa1_447b_8dad_764e267a7fab*
+**/.DS_Store
+
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4
index 470e7b10..403d19d9 100644
--- a/_server/blockly/MotaAction.g4
+++ b/_server/blockly/MotaAction.g4
@@ -202,6 +202,8 @@ action
| changePos_1_s
| openShop_s
| disableShop_s
+ | follow_s
+ | unfollow_s
| animate_s
| showImage_0_s
| showImage_1_s
@@ -553,7 +555,7 @@ var floorstr = '';
if (PosString_0 && PosString_1) {
floorstr = ', "loc": ['+PosString_0+','+PosString_1+']';
}
-var code = '{"type": "changeFloor", "floorId": "'+IdString_0+floorstr+DirectionEx_List_0+Int_0+' },\n';
+var code = '{"type": "changeFloor", "floorId": "'+IdString_0+'"'+floorstr+DirectionEx_List_0+Int_0+' },\n';
return code;
*/;
@@ -591,6 +593,7 @@ openShop_s
/* openShop_s
tooltip : 全局商店
helpUrl : https://ckcz123.github.io/mota-js/#/event?id=openshop%EF%BC%9A%E6%89%93%E5%BC%80%E4%B8%80%E4%B8%AA%E5%85%A8%E5%B1%80%E5%95%86%E5%BA%97
+colour : this.dataColor
default : ["shop1"]
var code = '{"type": "openShop", "id": "'+IdString_0+'"},\n';
return code;
@@ -609,6 +612,33 @@ var code = '{"type": "disableShop", "id": "'+IdString_0+'"},\n';
return code;
*/;
+follow_s
+ : '跟随勇士' '行走图' EvalString Newline
+
+
+/* follow_s
+tooltip : follow: 跟随勇士
+helpUrl : https://ckcz123.github.io/mota-js/#/event?id=follow%ef%bc%9a%e8%b7%9f%e9%9a%8f%e5%8b%87%e5%a3%ab
+default : ["npc.png"]
+colour : this.dataColor
+var code = '{"type": "follow", "name": "'+EvalString_0+'"},\n';
+return code;
+*/;
+
+unfollow_s
+ : '取消跟随' '行走图' EvalString? Newline
+
+
+/* unfollow_s
+tooltip : unfollow: 取消跟随
+helpUrl : https://ckcz123.github.io/mota-js/#/event?id=unfollow%ef%bc%9a%e5%8f%96%e6%b6%88%e8%b7%9f%e9%9a%8f
+default : [""]
+colour : this.dataColor
+EvalString_0 = EvalString_0 ? (', "name": "' + EvalString_0 + '"') : "";
+var code = '{"type": "unfollow"' + EvalString_0 + '},\n';
+return code;
+*/;
+
animate_s
: '显示动画' IdString '位置' EvalString? Newline
@@ -1513,6 +1543,12 @@ ActionParser.prototype.parseAction = function() {
data.direction,this.next]);
}
break;
+ case "follow": // 跟随勇士
+ this.next = MotaActionBlocks['follow_s'].xmlText([data.name||"", this.next]);
+ break;
+ case "unfollow": // 取消跟随
+ this.next = MotaActionBlocks['unfollow_s'].xmlText([data.name||"", this.next]);
+ break;
case "animate": // 显示动画
var animate_loc = data.loc||'';
if(animate_loc && animate_loc!=='hero')animate_loc = animate_loc[0]+','+animate_loc[1];
diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js
index 5ccd9b02..a128b493 100644
--- a/_server/editor_blockly.js
+++ b/_server/editor_blockly.js
@@ -69,7 +69,6 @@ editor_blockly = function () {
MotaActionBlocks['showGif_1_s'].xmlText(),
MotaActionBlocks['moveImage_0_s'].xmlText(),
MotaActionBlocks['tip_s'].xmlText(),
- MotaActionBlocks['openShop_s'].xmlText(),
MotaActionBlocks['win_s'].xmlText(),
MotaActionBlocks['lose_s'].xmlText(),
MotaActionBlocks['choices_s'].xmlText([
@@ -91,8 +90,11 @@ editor_blockly = function () {
MotaActionBlocks['changePos_1_s'].xmlText(),
MotaActionBlocks['battle_s'].xmlText(),
MotaActionBlocks['openDoor_s'].xmlText(),
+ MotaActionBlocks['openShop_s'].xmlText(),
MotaActionBlocks['setBlock_s'].xmlText(),
MotaActionBlocks['setHeroIcon_s'].xmlText(),
+ MotaActionBlocks['follow_s'].xmlText(),
+ MotaActionBlocks['unfollow_s'].xmlText(),
'',
MotaActionBlocks['if_s'].xmlText(),
MotaActionBlocks['while_s'].xmlText(),
diff --git a/docs/event.md b/docs/event.md
index 814a2ff7..3e83793f 100644
--- a/docs/event.md
+++ b/docs/event.md
@@ -617,6 +617,38 @@ time为可选的,指定的话将作为楼层切换动画的时间。
使用disableShop可以永久禁用全局商店直到再次被openShop打开为止。有关全局商店的说明可参见[全局商店](#全局商店)。
+### follow:跟随勇士
+
+使用 `{"type": "follow"}` 可以让一个npc加入跟随。
+
+``` js
+"x,y": [ // 实际执行的事件列表
+ {"type": "follow", "name": "npc.png"}, // 将 npc.png 这个行走图加入跟随
+ {"type": "follow", "name": "hero.png"}, // 再将另一个行走图加入跟随
+]
+```
+
+name为必须的,是要加入跟随的行走图文件名。
+
+name所指定的图片必须存在,在全塔属性中的images中被定义过,且是一个合法的行走图(宽为128像素,高不限。)
+
+### unfollow:取消跟随
+
+使用 `{"type": "unfollow"}` 来取消一个跟随。
+
+``` js
+"x,y": [ // 实际执行的事件列表
+ {"type": "unfollow", "name": "npc.png"}, // 将 npc.png 这个行走图取消跟随
+ {"type": "follow"}, // 取消所有跟随
+]
+```
+
+name为可选的,是要取消跟随的行走图文件名。
+
+如果name指定了,则会检查所有当前正在跟随的行走图,并删除第一个文件名是name的跟随效果。
+
+如果name省略,则会取消所有的跟随效果。
+
### animate:显示动画
我们可以使用 `{"type": "animate"}` 来显示一段动画。
diff --git a/libs/actions.js b/libs/actions.js
index b3211f26..35e5f9d4 100644
--- a/libs/actions.js
+++ b/libs/actions.js
@@ -326,7 +326,7 @@ actions.prototype.keyUp = function(keyCode, fromReplay) {
if (core.status.heroStop)
core.turnHero();
break;
- case 75: // K
+ case 75: case 86: // K/V
if (core.status.heroStop)
core.openQuickShop(true);
break;
@@ -1139,7 +1139,7 @@ actions.prototype.keyDownQuickShop = function (keycode) {
////// 快捷商店界面时,放开某个键的操作 //////
actions.prototype.keyUpQuickShop = function (keycode) {
- if (keycode==27 || keycode==75 || keycode==88) {
+ if (keycode==27 || keycode==75 || keycode==88 || keycode==86) {
core.ui.closePanel();
return;
}
diff --git a/libs/control.js b/libs/control.js
index 2162ffd2..51622c78 100644
--- a/libs/control.js
+++ b/libs/control.js
@@ -92,10 +92,10 @@ control.prototype.setRequestAnimationFrame = function () {
if (timestamp-core.animateFrame.moveTime>16 && core.isset(core.status.heroMoving) && core.status.heroMoving>0) {
var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'), direction = core.getHeroLoc('direction');
if (core.status.heroMoving<=4) {
- core.drawHero(direction, x, y, 'leftFoot', 4*core.status.heroMoving*scan[direction].x, 4*core.status.heroMoving*scan[direction].y);
+ core.drawHero(direction, x, y, 'leftFoot', 4*core.status.heroMoving);
}
else if (core.status.heroMoving<=8) {
- core.drawHero(direction, x, y, 'rightFoot', 4*core.status.heroMoving*scan[direction].x, 4*core.status.heroMoving*scan[direction].y);
+ core.drawHero(direction, x, y, 'rightFoot', 4*core.status.heroMoving);
}
core.animateFrame.moveTime = timestamp;
}
@@ -379,6 +379,25 @@ control.prototype.clearContinueAutomaticRoute = function () {
core.status.automaticRoute.moveStepBeforeStop=[];
}
+////// 瞬间移动 //////
+control.prototype.moveDirectly = function (destX, destY) {
+ var ignoreSteps = core.canMoveDirectly(destX, destY);
+ if (ignoreSteps>0) {
+ core.clearMap('hero', 0, 0, 416, 416);
+ var lastDirection = core.status.route[core.status.route.length-1];
+ if (['left', 'right', 'up', 'down'].indexOf(lastDirection)>=0)
+ core.setHeroLoc('direction', lastDirection);
+ core.setHeroLoc('x', destX);
+ core.setHeroLoc('y', destY);
+ core.drawHero();
+ core.status.route.push("move:"+destX+":"+destY);
+ core.status.hero.statistics.moveDirectly++;
+ core.status.hero.statistics.ignoreSteps+=ignoreSteps;
+ return true;
+ }
+ return false;
+}
+
////// 设置自动寻路路线 //////
control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) {
if (!core.status.played || core.status.lockControl) {
@@ -392,19 +411,7 @@ control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) {
core.status.automaticRoute.moveDirectly = true;
setTimeout(function () {
if (core.status.automaticRoute.moveDirectly && core.status.heroMoving==0) {
- var ignoreSteps = core.canMoveDirectly(destX, destY);
- if (ignoreSteps>0) {
- core.clearMap('hero', 0, 0, 416, 416);
- var lastDirection = core.status.route[core.status.route.length-1];
- if (['left', 'right', 'up', 'down'].indexOf(lastDirection)>=0)
- core.setHeroLoc('direction', lastDirection);
- core.setHeroLoc('x', destX);
- core.setHeroLoc('y', destY);
- core.drawHero();
- core.status.route.push("move:"+destX+":"+destY);
- core.status.hero.statistics.moveDirectly++;
- core.status.hero.statistics.ignoreSteps+=ignoreSteps;
- }
+ core.control.moveDirectly(destX, destY);
}
core.status.automaticRoute.moveDirectly = false;
}, 100);
@@ -429,17 +436,8 @@ control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) {
// 单击瞬间移动
if (core.status.automaticRoute.clickMoveDirectly && core.status.heroStop) {
- var ignoreSteps = core.canMoveDirectly(destX, destY);
- if (ignoreSteps>0) {
- core.clearMap('hero', 0, 0, 416, 416);
- core.setHeroLoc('x', destX);
- core.setHeroLoc('y', destY);
- core.drawHero();
- core.status.route.push("move:"+destX+":"+destY);
- core.status.hero.statistics.moveDirectly++;
- core.status.hero.statistics.ignoreSteps+=ignoreSteps;
+ if (core.control.moveDirectly(destX, destY))
return;
- }
}
var step = 0;
@@ -656,8 +654,9 @@ control.prototype.setHeroMoveInterval = function (direction, x, y, callback) {
core.interval.heroMoveInterval = window.setInterval(function () {
core.status.heroMoving+=toAdd;
if (core.status.heroMoving>=8) {
- core.setHeroLoc('x', x+scan[direction].x);
- core.setHeroLoc('y', y+scan[direction].y);
+ core.setHeroLoc('x', x+scan[direction].x, true);
+ core.setHeroLoc('y', y+scan[direction].y, true);
+ core.control.updateFollowers();
core.moveOneStep();
core.clearMap('hero', 0, 0, 416, 416);
core.drawHero(direction);
@@ -837,15 +836,16 @@ control.prototype.eventMoveHero = function(steps, time, callback) {
core.setHeroLoc('direction', direction);
step++;
if (step <= 4) {
- core.drawHero(direction, x, y, 'leftFoot', 4 * step * scan[direction].x, 4 * step * scan[direction].y);
+ core.drawHero(direction, x, y, 'leftFoot', 4 * step);
}
else if (step <= 8) {
- core.drawHero(direction, x, y, 'rightFoot', 4 * step * scan[direction].x, 4 * step * scan[direction].y);
+ core.drawHero(direction, x, y, 'rightFoot', 4 * step);
}
if (step == 8) {
step = 0;
- core.setHeroLoc('x', x + scan[direction].x);
- core.setHeroLoc('y', y + scan[direction].y);
+ core.setHeroLoc('x', x + scan[direction].x, true);
+ core.setHeroLoc('y', y + scan[direction].y, true);
+ core.control.updateFollowers();
moveSteps.shift();
}
}
@@ -891,12 +891,16 @@ control.prototype.jumpHero = function (ex, ey, time, callback) {
curry = (curry * jump_count + ey) / (jump_count + 1.0);
}
+ if (core.isset(core.status.hero.followers) && core.status.hero.followers.length>0)
+ core.clearMap('hero');
+
var animate=window.setInterval(function() {
if (jump_count>0) {
core.clearMap('hero', drawX(), drawY()-height+32, 32, height);
updateJump();
- core.canvas.hero.drawImage(core.material.images.hero, heroIcon[status] * 32, heroIcon.loc * height, 32, height, drawX(), drawY() + 32-height, 32, height); }
+ core.canvas.hero.drawImage(core.material.images.hero, heroIcon[status] * 32, heroIcon.loc * height, 32, height, drawX(), drawY() + 32-height, 32, height);
+ }
else {
clearInterval(animate);
core.setHeroLoc('x', ex);
@@ -954,33 +958,72 @@ control.prototype.stopHero = function () {
}
////// 绘制勇士 //////
-control.prototype.drawHero = function (direction, x, y, status, offsetX, offsetY) {
- offsetX = offsetX || 0;
- offsetY = offsetY || 0;
- var dx=offsetX==0?0:offsetX/Math.abs(offsetX), dy=offsetY==0?0:offsetY/Math.abs(offsetY);
+control.prototype.drawHero = function (direction, x, y, status, offset) {
+ var scan = {
+ 'up': {'x': 0, 'y': -1},
+ 'left': {'x': -1, 'y': 0},
+ 'down': {'x': 0, 'y': 1},
+ 'right': {'x': 1, 'y': 0}
+ };
+
if (!core.isset(x)) x = core.getHeroLoc('x');
if (!core.isset(y)) y = core.getHeroLoc('y');
- core.clearAutomaticRouteNode(x+dx, y+dy);
- x = x * 32;
- y = y * 32;
status = status || 'stop';
- var heroIcon = core.material.icons.hero[direction || core.getHeroLoc('direction')];
- core.canvas.hero.clearRect(x - 32, y - 32, 96, 96);
- var height=core.material.icons.hero.height;
- core.canvas.hero.drawImage(core.material.images.hero, heroIcon[status] * 32, heroIcon.loc * height, 32, height, x + offsetX, y + offsetY + 32-height, 32, height);
+ direction = direction || core.getHeroLoc('direction');
+ offset = offset || 0;
+ var dx=offset==0?0:scan[direction].x, dy=offset==0?0:scan[direction].y;
+ core.clearAutomaticRouteNode(x+dx, y+dy);
+ core.canvas.hero.clearRect(32 * x - 32, 32 * y - 32, 96, 96);
+
+ var heroIconArr = core.material.icons.hero;
+ var drawObjs = [];
+ // add hero
+ drawObjs.push({
+ "img": core.material.images.hero,
+ "height": core.material.icons.hero.height,
+ "heroIcon": heroIconArr[direction],
+ "posx": 32 * x + scan[direction].x*offset,
+ "posy": 32 * y + scan[direction].y*offset,
+ "status": status,
+ "index": 0,
+ });
+
+ // Add other followers
+ if (core.isset(core.status.hero.followers)) {
+ var index=1;
+ core.status.hero.followers.forEach(function (t) {
+ core.canvas.hero.clearRect(32*t.x-32, 32*t.y-32, 96, 96);
+ if (core.isset(core.material.images.images[t.img])) {
+ drawObjs.push({
+ "img": core.material.images.images[t.img],
+ "height": core.material.images.images[t.img].height/4,
+ "heroIcon": heroIconArr[t.direction],
+ "posx": 32*t.x + (t.stop?0:scan[t.direction].x*offset),
+ "posy": 32*t.y + (t.stop?0:scan[t.direction].y*offset),
+ "status": t.stop?"stop":status,
+ "index": index++
+ });
+ }
+ });
+ }
+
+ drawObjs.sort(function (a, b) {
+ return a.posy==b.posy?b.index-a.index:a.posy-b.posy;
+ })
+
+ drawObjs.forEach(function (block) {
+ core.canvas.hero.drawImage(block.img, block.heroIcon[block.status]*32,
+ block.heroIcon.loc * block.height, 32, block.height,
+ block.posx, block.posy+32-block.height, 32, block.height);
+ })
}
////// 设置勇士的位置 //////
-control.prototype.setHeroLoc = function (itemName, itemVal) {
- if (itemVal == '++') {
- core.status.hero.loc[itemName]++;
- return;
- }
- else if (itemVal == '--') {
- core.status.hero.loc[itemName]--;
- return;
- }
+control.prototype.setHeroLoc = function (itemName, itemVal, noGather) {
core.status.hero.loc[itemName] = itemVal;
+ if ((itemName=='x' || itemName=='y') && !noGather) {
+ this.gatherFollowers();
+ }
}
////// 获得勇士的位置 //////
@@ -1011,6 +1054,62 @@ control.prototype.nextY = function (n) {
return core.getHeroLoc('y')+scan[core.getHeroLoc('direction')].y*(n||1);
}
+////// 聚集跟随者 //////
+control.prototype.gatherFollowers = function () {
+ if (!core.isset(core.status.hero.followers) || core.status.hero.followers.length==0) return;
+ var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'), dir=core.getHeroLoc('direction');
+ core.status.hero.followers.forEach(function (t) {
+ t.x = x;
+ t.y = y;
+ t.stop = true;
+ t.direction = dir;
+ });
+}
+
+////// 更新跟随者坐标 //////
+control.prototype.updateFollowers = function () {
+ if (!core.isset(core.status.hero.followers) || core.status.hero.followers.length==0) return;
+ var scan = {
+ 'up': {'x': 0, 'y': -1},
+ 'left': {'x': -1, 'y': 0},
+ 'down': {'x': 0, 'y': 1},
+ 'right': {'x': 1, 'y': 0}
+ };
+ core.status.hero.followers.forEach(function (t) {
+ if (!t.stop) {
+ t.x += scan[t.direction].x;
+ t.y += scan[t.direction].y;
+ }
+ })
+
+ var nowx = core.getHeroLoc('x'), nowy = core.getHeroLoc('y');
+ core.status.hero.followers.forEach(function (t) {
+ if (t.x == nowx && t.y == nowy) {
+ t.stop = true;
+ }
+ else {
+ var dx = nowx-t.x, dy = nowy-t.y;
+ if (dx==-1) {
+ t.stop=false;
+ t.direction='left';
+ }
+ else if (dx==1) {
+ t.stop=false;
+ t.direction='right';
+ }
+ else if (dy==-1) {
+ t.stop=false;
+ t.direction='up';
+ }
+ else if (dy==1) {
+ t.stop=false;
+ t.direction='down';
+ }
+ }
+ nowx=t.x; nowy=t.y;
+ })
+}
+
////// 更新领域、夹击、阻击的伤害地图 //////
control.prototype.updateCheckBlock = function() {
core.status.checkBlock = {};
@@ -1509,25 +1608,26 @@ control.prototype.updateFg = function () {
}
////// 执行一个表达式的effect操作 //////
-control.prototype.doEffect = function (expression) {
- // 必须使用"+="
- var arr = expression.split("+=");
- if (arr.length!=2) return;
- var name=arr[0], value=core.calValue(arr[1]);
- if (name.indexOf("status:")==0) {
- var status=name.substring(7);
- core.setStatus(status, core.getStatus(status)+value);
- }
- else if (name.indexOf("item:")==0) {
- var itemId=name.substring(5);
- core.setItem(itemId, core.itemCount(itemId)+value);
- }
+control.prototype.doEffect = function (effect) {
+ effect.split(";").forEach(function (expression) {
+ var arr = expression.split("+=");
+ if (arr.length!=2) return;
+ var name=arr[0], value=core.calValue(arr[1]);
+ if (name.indexOf("status:")==0) {
+ var status=name.substring(7);
+ core.setStatus(status, core.getStatus(status)+value);
+ }
+ else if (name.indexOf("item:")==0) {
+ var itemId=name.substring(5);
+ core.setItem(itemId, core.itemCount(itemId)+value);
+ }
+ });
}
////// 开启debug模式 //////
control.prototype.debug = function() {
core.setFlag('debug', true);
- core.insertAction(["\t[调试模式开启]此模式下按住Ctrl键可以穿墙并忽略一切事件。\n同时,录像将失效,也无法上传成绩。"]);
+ core.insertAction(["\t[调试模式开启]此模式下按住Ctrl键(或Ctrl+Shift键)可以穿墙并忽略一切事件。\n同时,录像将失效,也无法上传成绩。"]);
/*
core.setStatus('hp', 999999);
core.setStatus('atk', 10000);
@@ -1822,16 +1922,7 @@ control.prototype.replay = function () {
else if (action.indexOf('move:')==0) {
var pos=action.substring(5).split(":");
var x=parseInt(pos[0]), y=parseInt(pos[1]);
-
- var ignoreSteps = core.canMoveDirectly(x, y);
- if (ignoreSteps>0) {
- core.clearMap('hero', 0, 0, 416, 416);
- core.setHeroLoc('x', x);
- core.setHeroLoc('y', y);
- core.drawHero();
- core.status.route.push("move:"+x+":"+y);
- core.status.hero.statistics.moveDirectly++;
- core.status.hero.statistics.ignoreSteps+=ignoreSteps;
+ if (core.control.moveDirectly(x,y)) {
core.replay();
return;
}
diff --git a/libs/core.js b/libs/core.js
index ed43bd8a..4ae431dc 100644
--- a/libs/core.js
+++ b/libs/core.js
@@ -484,13 +484,13 @@ core.prototype.stopHero = function () {
}
////// 绘制勇士 //////
-core.prototype.drawHero = function (direction, x, y, status, offsetX, offsetY) {
- core.control.drawHero(direction, x, y, status, offsetX, offsetY);
+core.prototype.drawHero = function (direction, x, y, status, offset) {
+ core.control.drawHero(direction, x, y, status, offset);
}
////// 设置勇士的位置 //////
-core.prototype.setHeroLoc = function (itemName, itemVal) {
- core.control.setHeroLoc(itemName, itemVal);
+core.prototype.setHeroLoc = function (itemName, itemVal, noGather) {
+ core.control.setHeroLoc(itemName, itemVal, noGather);
}
////// 获得勇士的位置 //////
diff --git a/libs/events.js b/libs/events.js
index 3e5d1470..f8ff8424 100644
--- a/libs/events.js
+++ b/libs/events.js
@@ -405,6 +405,42 @@ events.prototype.doAction = function() {
this.doAction();
break;
}
+ case "follow": // 跟随
+ if (core.isset(core.material.images.images[data.name])
+ && core.material.images.images[data.name].width==128) {
+ if (!core.isset(core.status.hero.followers))
+ core.status.hero.followers = [];
+ core.status.hero.followers.push({"img": data.name});
+ core.control.gatherFollowers();
+ core.clearMap('hero');
+ core.drawHero();
+ }
+ this.doAction();
+ break;
+ case "unfollow": // 取消跟随
+ if (core.isset(core.status.hero.followers)) {
+ var remove = false;
+ if (!core.isset(data.name) && core.status.hero.followers.length>0) {
+ core.status.hero.followers = [];
+ remove=true;
+ }
+ if (core.isset(data.name)) {
+ for (var i=0;i0)
- return 0;
+ // 可以无视起点事件
+ // if (core.getBlock(fromX,fromY)!=null||core.status.checkBlock.damage[13*fromX+fromY]>0)
+ // return 0;
// BFS
var visited=[], queue=[];
diff --git a/libs/utils.js b/libs/utils.js
index 71da66d9..13a9f677 100644
--- a/libs/utils.js
+++ b/libs/utils.js
@@ -631,7 +631,7 @@ utils.prototype.hide = function (obj, speed, callback) {
}, speed);
}
-utils.prototype.export = function (floorIds) {
+utils.prototype._export = function (floorIds) {
if (!core.isset(floorIds)) floorIds = [core.status.floorId];
else if (floorIds=='all') floorIds = core.clone(core.floorIds);
else if (typeof floorIds == 'string') floorIds = [floorIds];
diff --git a/project/data.js b/project/data.js
index 6a33d6e3..984d3398 100644
--- a/project/data.js
+++ b/project/data.js
@@ -155,7 +155,7 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"startDirectly": false,
"canOpenBattleAnimate": true,
"showBattleAnimateConfirm": true,
- "battleAnimate": true,
+ "battleAnimate": false,
"displayEnemyDamage": true,
"displayCritical": true,
"displayExtraDamage": true,
diff --git a/更新说明.txt b/更新说明.txt
index 8601bc08..32a266cc 100644
--- a/更新说明.txt
+++ b/更新说明.txt
@@ -1,10 +1,12 @@
HTML5魔塔样板V2.3.2
启动服务的多开版本 √
+跟随效果 √
怪物数据导出器
gif播放可随着分辨率自动放缩 √
状态栏可随文字长度自动调整放缩 √
也可以用status:exp来代替经验值的写法 √
+V键也可以打开快捷商店 √
破炸在周围只有一个目标时无需转向面对它 √
道具效果中,无需再将null改成""才能双击编辑了 √
各个已知Bug的修复,部分细节优化 √