追逐战

This commit is contained in:
unanmed 2023-01-03 22:24:05 +08:00
parent 64a4fa05a8
commit bdf47dae82
15 changed files with 1096 additions and 670 deletions

View File

@ -3677,7 +3677,8 @@ control.prototype._playBgm_play = function (bgm, startTime) {
// 如果当前正在播放且和本BGM相同直接忽略
if (
core.musicStatus.playingBgm == bgm &&
!core.material.bgms[core.musicStatus.playingBgm].paused
!core.material.bgms[core.musicStatus.playingBgm].paused &&
!startTime
) {
return;
}

View File

@ -20,7 +20,7 @@ main.floors.MT14=
"name": "plot1.mp3"
}
],
"parallelDo": "if (flags.chase) {\n\tcore.changeChaseView(true);\n}",
"parallelDo": "",
"events": {
"24,7": {
"trigger": "action",
@ -101,7 +101,7 @@ main.floors.MT14=
"data": [
{
"type": "if",
"condition": "flag:finishChase",
"condition": "flag:finishChase1",
"true": [
{
"type": "function",

View File

@ -31,7 +31,7 @@ main.floors.MT15=
"\t[野蛮人]\b[up,hero]山路开始崎岖多变了,要更小心一些"
],
"eachArrive": [],
"parallelDo": "if (flags.chase) {\n\tcore.changeChaseView(true);\n}",
"parallelDo": "",
"events": {
"44,0": [
"不愧是你!!!"

View File

@ -12,7 +12,7 @@ main.floors.MT16=
"images": [],
"ratio": 1,
"defaultGround": "T331",
"bgm": null,
"bgm": "mount.mp3",
"color": null,
"weather": [
"cloud",
@ -37,7 +37,7 @@ main.floors.MT16=
"type": "pauseBgm"
}
],
"parallelDo": "if (flags.chase) {\n\tcore.changeChaseView(true);\n}",
"parallelDo": "",
"events": {
"23,19": [
{
@ -88,6 +88,9 @@ main.floors.MT16=
],
"no": [
"追逐战后录像会进行自动修复,不用担心录像问题",
{
"type": "hideStatusBar"
},
{
"type": "function",
"function": "function(){\ncore.status.maps.MT15.canFlyFrom = false\n}"
@ -360,11 +363,11 @@ main.floors.MT16=
"time": 3000
},
{
"type": "autoSave"
"type": "function",
"function": "function(){\ncore.startChase(1);\n}"
},
{
"type": "function",
"function": "function(){\ncore.startChase();\n}"
"type": "autoSave"
}
],
"2,23": [
@ -378,18 +381,11 @@ main.floors.MT16=
"即将开始追逐战,最好打开背景音乐,有耳机尽量佩戴耳机,这样游戏体验更佳",
"为了防止你撞上不该开的门,现在会将所有门打开,并删除所有物品",
"追逐的时候不能用2技能不能用楼传逃跑后要原路返回山洞",
"逃跑方式:哪里爆炸走哪里",
"注意,如果失败了必须要刷新页面才能重新开始,否则会出问题",
"请认真跑,虽然开始追逐的时候有一个自动存档,但不能保证该存档不会出问题",
"逃跑时的路线基本固定,但可能有一定难度,过不去就直接跳就行了",
"注意!!!再说一遍!!!重新跑需要刷新页面!!!",
"追逐战分为两个难度,简单难度会显示逃跑路径,困难模式不显示,困难模式逃跑成功可以获得成就",
"前方会有大约40秒的剧情之后开始追逐战并自动存档如果逃跑失败需要重打可以直接读自动存档",
{
"type": "hide",
"remove": true
},
{
"type": "function",
"function": "function(){\ncore.initChase();\n}"
}
]
},

View File

@ -121,6 +121,8 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
// 正在切换楼层过程中执行的操作;此函数的执行时间是“屏幕完全变黑“的那一刻
// floorId为要切换到的楼层IDheroLoc表示勇士切换到的位置
flags.floorChanging = true;
// ---------- 此时还没有进行切换当前floorId还是原来的 ---------- //
var currentId = core.status.floorId || null; // 获得当前的floorId可能为null
var fromLoad = core.hasFlag('__fromLoad__'); // 是否是读档造成的切换
@ -212,6 +214,13 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
// 转换楼层结束的事件;此函数会在整个楼层切换完全结束后再执行
// floorId是切换到的楼层
if (flags.onChase) {
flags.chaseTime ??= {};
flags.chaseTime[floorId] = Date.now();
}
flags.floorChanging = false;
// 如果是读档,则进行检查(是否需要恢复事件)
if (core.hasFlag('__fromLoad__')) {
core.events.recoverEvents(core.getFlag('__events__'));
@ -1417,7 +1426,10 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
},
loadData: function (data, callback) {
// 读档操作;从存储中读取了内容后的行为
if (window.flags && flags.onChase) {
flags.chase.end();
flags.onChase = true;
}
// 重置游戏和路线
core.resetGame(
data.hero,
@ -1468,6 +1480,13 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
core.removeFlag('__fromLoad__');
if (callback) callback();
if (flags.onChase) {
core.startChase(flags.chaseIndex);
if (flags.chaseIndex === 1) {
core.playBgm('escape.mp3', 43.5);
}
}
});
},
getStatusLabel: function (name) {

View File

@ -3411,601 +3411,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
this._checkBlock_repulse(core.status.checkBlock.repulse[loc]);
};
},
chase: function () {
// 山野追逐战
// 初始变量
// 视野路线 x, y, frame
var route = [
[10, 10, 0],
[0, 10, 100],
[0, 10, 200],
[49, 0, 500],
[49, 0, 550],
[45, 0, 640],
[40, 0, 760],
[40, 0, 820],
[41, 0, 850],
[37, 0, 950],
[31, 0, 1000],
[29, 0, 1020],
[29, 0, 1210],
[25, 0, 1270],
[12, 0, 1330],
[0, 0, 1470],
[0, 0, 2000],
[113, 0, 2500],
[109, 0, 2580],
[104, 0, 2600],
[104, 0, 2830],
[92, 0, 3000],
[84, 0, 3120],
[74, 0, 3300],
[65, 0, 3480],
[58, 0, 3600],
[47, 0, 3800],
[36, 0, 4000],
[0, 0, 4600]
];
// 效果函数
var funcs = [[0, wolfRun], [550, shake1], [10000000]];
var parrallels = [para1, para2]; // 并行脚本
var speed = 0; // 速度
var index = 0; // 当前要到达的索引
var fIndex = 0; // 函数索引
var frame = 0; // 帧数
var acc = 0; // 加速度
var currX = route[0][1] * 32; // 当前x轴
var inBlack = false;
var x = core.getHeroLoc('x');
var y = core.getHeroLoc('y'); // 勇士坐标
// 初始化,删除门和道具
this.initChase = function () {
speed = 0; // 速度
index = 0; // 当前要到达的索引
fIndex = 0; // 函数索引
frame = 0; // 帧数
acc = 0; // 加速度
currX = route[0][1] * 32; // 当前x轴
inBlack = false;
x = core.getHeroLoc('x');
y = core.getHeroLoc('y'); // 勇士坐标
// 循环删除
for (var i = 13; i < 16; i++) {
var floorId = 'MT' + i;
// 不可瞬移
core.status.maps[floorId].cannotMoveDirectly = true;
core.extractBlocks(floorId);
for (
var j = 0;
j < core.status.maps[floorId].blocks.length;
j++
) {
var block = core.status.maps[floorId].blocks[j];
var cls = block.event.cls,
id = block.event.id;
if (
(cls == 'animates' || cls == 'items') &&
!id.endsWith('Portal')
) {
core.removeBlock(block.x, block.y, floorId);
j--;
}
}
}
};
// 函数们
function wolfRun() {
core.moveBlock(
23,
17,
['down', 'down', 'down', 'down', 'down', 'down'],
80
);
setTimeout(() => {
core.setBlock(508, 23, 23);
core.moveBlock(
23,
23,
[
'left',
'left',
'left',
'left',
'left',
'left',
'left',
'left',
'left',
'left',
'left',
'left',
'left',
'left',
'left',
'left',
'left'
],
80,
true
);
}, 500);
}
// MT15函数1
function shake1() {
core.vibrate('vertical', 1000, 25, 2);
for (var tx = 53; tx < 58; tx++) {
for (var ty = 3; ty < 8; ty++) {
core.setBlock(336, tx, ty);
}
}
core.drawAnimate('explosion3', 55, 5);
core.drawAnimate('stone', 55, 5);
setTimeout(() => {
core.setBlock(336, 58, 9);
core.setBlock(336, 59, 9);
core.drawAnimate('explosion1', 58, 9);
core.drawAnimate('explosion1', 59, 9);
}, 250);
setTimeout(() => {
core.setBlock(336, 53, 8);
core.setBlock(336, 52, 8);
core.drawAnimate('explosion1', 53, 8);
core.drawAnimate('explosion1', 52, 8);
}, 360);
setTimeout(() => {
core.setBlock(336, 51, 7);
core.drawAnimate('explosion1', 51, 7);
}, 750);
setTimeout(() => {
core.vibrate('vertical', 6000, 25, 1);
core.setBlock(336, 47, 7);
core.setBlock(336, 49, 9);
core.drawAnimate('explosion1', 49, 9);
core.drawAnimate('explosion1', 47, 7);
}, 1000);
}
// 并行1
function para1() {
if (core.status.floorId != 'MT15') return;
if (x == 45 && y == 8 && !flags.p11) {
core.setBlock(336, 45, 9);
core.drawAnimate('explosion1', 45, 9);
flags.p11 = true;
}
if (x == 45 && y == 6 && !flags.p12) {
core.setBlock(336, 44, 6);
core.drawAnimate('explosion1', 44, 6);
flags.p12 = true;
}
if (x == 45 && y == 4 && !flags.p13) {
core.setBlock(336, 44, 4);
core.drawAnimate('explosion1', 44, 4);
core.drawAnimate('explosion1', 48, 6);
core.removeBlock(48, 6);
flags.p13 = true;
}
if (x == 41 && y == 3 && !flags.p14) {
core.setBlock(336, 41, 4);
core.setBlock(336, 32, 6);
core.drawAnimate('explosion1', 41, 4);
core.drawAnimate('explosion1', 32, 6);
flags.p14 = true;
}
if (x == 35 && y == 3 && !flags.p15) {
core.drawAnimate('explosion3', 37, 7);
core.vibrate('vertical', 1000, 25, 10);
for (var tx = 36; tx < 42; tx++) {
for (var ty = 4; ty < 11; ty++) {
core.setBlock(336, tx, ty);
}
}
flags.p15 = true;
}
if (x == 31 && y == 5 && !flags.p16) {
core.vibrate('vertical', 10000, 25, 1);
core.removeBlock(34, 8);
core.removeBlock(33, 8);
core.drawAnimate('explosion1', 34, 8);
core.drawAnimate('explosion1', 33, 8);
flags.p16 = true;
}
if (x == 33 && y == 7 && !flags.p17) {
core.setBlock(336, 32, 9);
core.drawAnimate('explosion1', 32, 9);
flags.p17 = true;
}
if ((x == 33 || x == 34 || x == 35) && y == 9 && !flags.p18) {
core.removeBlock(32, 9);
core.drawAnimate('explosion1', 32, 9);
flags.p18 = true;
}
if (x > 18 && x < 31 && y == 11 && !flags['p19' + x]) {
core.setBlock(336, x + 1, 11);
core.drawAnimate('explosion1', x + 1, 11);
flags['p19' + x] = true;
}
}
// 并行2
function para2() {
if (core.status.floorId != 'MT14') return;
if (x == 126 && y == 7 && !flags.p21) {
core.setBlock(336, 126, 6);
core.setBlock(336, 124, 6);
core.setBlock(336, 124, 9);
core.setBlock(336, 126, 9);
core.drawAnimate('explosion1', 126, 6);
core.drawAnimate('explosion1', 124, 6);
core.drawAnimate('explosion1', 124, 9);
core.drawAnimate('explosion1', 126, 9);
flags.p21 = true;
}
if (x == 123 && y == 7 && !flags.p22) {
core.setBlock(508, 127, 7);
core.jumpBlock(127, 7, 112, 7, 500, true);
setTimeout(() => {
core.setBlock(509, 112, 7);
}, 520);
core.drawHeroAnimate('amazed');
core.setBlock(336, 121, 6);
core.setBlock(336, 122, 6);
core.setBlock(336, 120, 8);
core.setBlock(336, 121, 8);
core.setBlock(336, 122, 8);
core.drawAnimate('explosion1', 121, 6);
core.drawAnimate('explosion1', 122, 6);
core.drawAnimate('explosion1', 120, 8);
core.drawAnimate('explosion1', 121, 8);
core.drawAnimate('explosion1', 122, 8);
flags.p22 = true;
}
if (x == 110 && y == 10 && !flags.p23) {
core.setBlock(336, 109, 11);
core.removeBlock(112, 8);
core.drawAnimate('explosion1', 109, 11);
core.drawAnimate('explosion1', 112, 8);
core.insertAction([
{ type: 'moveHero', time: 400, steps: ['backward:1'] }
]);
flags.p23 = true;
}
if (x == 112 && y == 8 && !flags.p24 && flags.p23) {
core.jumpBlock(112, 7, 110, 4, 500, true);
core.drawHeroAnimate('amazed');
setTimeout(() => {
core.setBlock(506, 110, 4);
}, 540);
flags.p24 = true;
}
if (x == 118 && y == 7 && !flags.p25) {
core.setBlock(336, 117, 6);
core.setBlock(336, 116, 6);
core.setBlock(336, 115, 6);
core.setBlock(336, 114, 6);
core.setBlock(336, 117, 8);
core.setBlock(336, 116, 8);
core.drawAnimate('explosion1', 117, 6);
core.drawAnimate('explosion1', 116, 6);
core.drawAnimate('explosion1', 115, 6);
core.drawAnimate('explosion1', 114, 6);
core.drawAnimate('explosion1', 116, 8);
core.drawAnimate('explosion1', 117, 8);
flags.p25 = true;
}
if (x == 112 && y == 7 && !flags.p26) {
core.setBlock(336, 112, 8);
core.setBlock(336, 113, 7);
core.drawAnimate('explosion1', 112, 8);
core.drawAnimate('explosion1', 113, 7);
flags.p26 = true;
}
if (x == 115 && y == 7 && !flags.p39) {
for (var tx = 111; tx <= 115; tx++) {
core.setBlock(336, tx, 10);
core.drawAnimate('explosion1', tx, 10);
}
core.setBlock(336, 112, 8);
core.drawAnimate('explosion1', 112, 8);
flags.p39 = true;
}
if (x == 110 && y == 7 && !flags.p27) {
core.jumpBlock(97, 4, 120, -3, 2000);
for (var tx = 109; tx <= 120; tx++) {
for (var ty = 3; ty <= 11; ty++) {
if (ty == 7) continue;
core.setBlock(336, tx, ty);
}
}
core.vibrate('vertical', 3000, 25, 10);
core.drawAnimate('explosion2', 119, 7);
core.insertAction([
{
type: 'autoText',
text: '\t[原始人]\b[down,hero]卧槽!!吓死我了!!',
time: 600
}
]);
core.removeBlock(105, 7);
core.drawAnimate('explosion1', 105, 7);
flags.p27 = true;
}
if (x == 97 && y == 3 && !flags.p28) {
core.setBlock(336, 95, 3);
core.setBlock(336, 93, 6);
core.drawAnimate('explosion1', 95, 3);
core.drawAnimate('explosion1', 93, 6);
flags.p28 = true;
}
if (x == 88 && y == 6 && !flags.p29) {
core.setBlock(336, 87, 4);
core.setBlock(336, 88, 5);
core.drawAnimate('explosion1', 87, 4);
core.drawAnimate('explosion1', 88, 5);
flags.p29 = true;
}
if (x == 86 && y == 6 && !flags.p30) {
core.setBlock(336, 84, 6);
core.setBlock(336, 85, 5);
core.setBlock(336, 86, 8);
core.drawAnimate('explosion1', 84, 6);
core.drawAnimate('explosion1', 85, 5);
core.drawAnimate('explosion1', 86, 8);
flags.p30 = true;
}
if (x == 81 && y == 9 && !flags.p31) {
core.setBlock(336, 81, 8);
core.setBlock(336, 82, 11);
core.drawAnimate('explosion1', 81, 8);
core.drawAnimate('explosion1', 82, 11);
flags.p31 = true;
}
if (x == 72 && y == 11 && !flags.p32) {
core.setBlock(336, 73, 8);
core.setBlock(336, 72, 4);
core.drawAnimate('explosion1', 73, 8);
core.drawAnimate('explosion1', 72, 4);
flags.p32 = true;
}
if (x == 72 && y == 7 && !flags.p33) {
for (var tx = 74; tx < 86; tx++) {
for (var ty = 3; ty < 12; ty++) {
core.setBlock(336, tx, ty);
}
}
core.drawAnimate('explosion2', 79, 7);
core.vibrate('vertical', 4000, 25, 15);
setTimeout(() => {
core.vibrate(10000, null, 4);
});
flags.p33 = true;
}
if (x == 68 && y == 5 && !flags.p34) {
core.setBlock(336, 68, 4);
core.setBlock(336, 67, 6);
core.drawAnimate('explosion1', 68, 4);
core.drawAnimate('explosion1', 67, 6);
flags.p34 = true;
}
if (x == 67 && y == 10 && !flags.p35) {
for (var tx = 65; tx <= 72; tx++) {
for (var ty = 3; ty <= 9; ty++) {
core.setBlock(336, tx, ty);
}
}
core.setBlock(336, 72, 10);
core.setBlock(336, 72, 11);
core.drawAnimate('explosion3', 69, 5);
core.vibrate('vertical', 2000, 25, 7);
flags.p35 = true;
}
if (x == 64 && y == 11 && !flags.p36) {
core.setBlock(336, 63, 9);
core.setBlock(336, 60, 8);
core.setBlock(336, 56, 11);
core.drawAnimate('explosion1', 63, 9);
core.drawAnimate('explosion1', 60, 8);
core.drawAnimate('explosion1', 56, 11);
flags.p36 = true;
}
if (x == 57 && y == 9 && !flags.p37) {
for (tx = 58; tx <= 64; tx++) {
for (var ty = 3; ty <= 11; ty++) {
core.setBlock(336, tx, ty);
}
}
core.drawAnimate('explosion2', 61, 7);
core.vibrate('vertical', 3000, 25, 12);
setTimeout(() => {
core.vibrate(20000, null, 4);
}, 3000);
flags.p37 = true;
}
if (x <= 48 && !flags['p38' + x] && x >= 21) {
for (var ty = 3; ty <= 11; ty++) {
core.setBlock(336, x + 4, ty);
core.drawAnimate('explosion1', x + 4, ty);
}
flags['p38' + x] = true;
}
if (x == 21 && flags.p37) {
core.endChase();
}
}
// 开始追逐
this.startChase = function () {
flags.__lockViewport__ = true;
flags.chase = true;
speed = 0; // 速度
index = 0; // 当前要到达的索引
fIndex = 0; // 函数索引
frame = 0; // 帧数
acc = 0; // 加速度
currX = route[0][1] * 32; // 当前x轴
inBlack = false;
x = core.getHeroLoc('x');
y = core.getHeroLoc('y'); // 勇士坐标
core.values.moveSpeed = 100;
core.loadOneSound('quake.mp3');
core.drawHero();
core.pauseBgm();
core.playBgm('escape.mp3', 43.5);
};
// 视野变化 useAcc:是否匀变速
this.changeChaseView = function (useAcc) {
if (flags.haveLost) return;
var floorId = core.status.floorId;
if (frame >= 3600) useAcc = false;
// 刚进MT15时
if (floorId === 'MT15' && !inBlack) {
frame = 500;
index = 3;
fIndex = 1;
speed = 0;
acc = 0;
currX = 32 * 49;
inBlack = true;
core.setGameCanvasTranslate('hero', 224, 0);
flags.startShake = true;
core.playSound('地震');
core.insertAction([{ type: 'sleep', time: 500, noSkip: true }]);
var interval = setInterval(() => {
core.playSound('地震');
if (index >= route.length - 1) clearInterval(interval);
}, 15000);
core.vibrate('vertical', 1000, 25);
setTimeout(() => {
core.blackEdge();
core.insertAction([
{
type: 'autoText',
text: '\t[原始人]\b[down,hero]糟糕,还地震了!',
time: 1500
},
{
type: 'autoText',
text: '\t[原始人]\b[down,hero]快跑!',
time: 1000
}
]);
flags.startShake = false;
}, 500);
}
// 超范围失败
if (x * 32 > currX + 480 + 64) {
flags.haveLost = true;
core.lose('逃跑失败');
return;
}
// 刚进MT14
if (floorId == 'MT14' && !flags.first14) {
frame = 2500;
index = 17;
fIndex = 2;
speed = 0;
acc = 0;
currX = 117 * 32;
core.vibrate('vertical', 10000, 25, 2);
core.setGameCanvasTranslate('hero', 224, 0);
flags.first14 = true;
}
// 停止运行
if (index >= route.length) return;
// 切换索引
if (frame > route[index][2]) {
index++;
if (index == 3 && floorId == 'MT16') {
core.lose('逃跑失败');
}
if (index >= route.length) {
return;
}
core.changeChaseIndex(useAcc);
}
// 碰到狼就死
if (floorId == 'MT16') {
if (x >= 6) {
if (x > 25 - (frame - 29) / 5) {
flags.haveLost = true;
core.lose('逃跑失败');
return;
}
}
}
// 执行函数
if (frame == funcs[fIndex][0]) {
funcs[fIndex][1]();
fIndex++;
}
// 并行
for (var i in parrallels) {
parrallels[i]();
}
if (useAcc) speed += acc;
currX += speed;
if (floorId == 'MT16') core.setViewport(currX, 320);
else core.setViewport(currX, 0);
x = core.getHeroLoc('x');
y = core.getHeroLoc('y');
frame++;
};
// 路线索引切换
this.changeChaseIndex = function (useAcc) {
var fromR = route[index - 1],
toR = route[index];
var dt = toR[2] - fromR[2],
dx = (toR[0] - fromR[0]) * 32;
if (dx == 0) {
acc = 0;
speed = 0;
}
if (useAcc) {
acc = (2 * (dx - speed * dt)) / (dt * dt);
} else {
speed = dx / dt;
}
};
// 黑边
this.blackEdge = function () {
core.createCanvas('edge', 0, 0, 480, 480, 100);
var f = 0;
var h = 0,
s = 2.56;
// 初始动画
function start() {
core.clearMap('edge');
core.fillRect('edge', 0, 0, 480, h);
core.fillRect('edge', 0, 480, 480, -h);
f++;
s -= 0.0512;
h += s;
if (f == 50) clearInterval(interval);
}
var interval = setInterval(start, 20);
};
// 结束追逐
this.endChase = function () {
flags.chase = false;
flags.__lockViewport__ = false;
core.autoFixRouteBoss(false);
// 黑边消失
clearInterval(interval);
var f = 0;
var h = 64,
s = 0;
var interval = setInterval(() => {
core.clearMap('edge');
core.fillRect('edge', 0, 0, 480, h);
core.fillRect('edge', 0, 480, 480, -h);
f++;
s += 0.0512;
h -= s;
if (f == 50) {
clearInterval(interval);
core.deleteCanvas('edge');
flags.finishChase = true;
}
});
};
},
hotReload: function () {
if (main.mode !== 'play' || main.replayChecking) return;

View File

@ -88,7 +88,7 @@ function draw() {
* 计算元素总长度
*/
async function calHeight() {
await new Promise(res => {
await sleep(20);
const canvas = ctx.canvas;
const style2 = getComputedStyle(canvas);
canvas.style.width = `${width}px`;
@ -105,10 +105,10 @@ async function calHeight() {
canvas.height = width * scale;
if (props.noScroll) canvas.style.height = `0px`;
}
await new Promise(res => {
requestAnimationFrame(() => {
const style = getComputedStyle(content);
total = parseFloat(style[canvasAttr]);
res('');
});
});
@ -193,7 +193,7 @@ onMounted(async () => {
useWheel(content, (x, y) => {
fromSelf = true;
const d = x !== 0 ? x : y;
if (Math.abs(d) > 50) {
if (Math.abs(d) > 30) {
content.style.transition = `${cssTarget} 0.2s ease-out`;
} else {
content.style.transition = '';

View File

@ -6,29 +6,183 @@
"这里显示本塔中需要注意的事项。",
"<br>",
"<br>",
"1. 本塔中<span style=\"color: gold\">几乎所有 ui </span>都可以纵向滚动,如果发现显示不全,",
"1. 本百科全书字数很多,可以选择性地阅读。",
"<br>",
"<br>",
"2. 本塔中<span style=\"color: gold\">几乎所有 ui </span>都可以纵向滚动,如果发现显示不全,",
"可以尝试上下拖动,就像浏览网页一样。电脑端还可以使用滚轮上下滚动。",
"大部分可以纵向滚动的 ui 都会在右方有一个滚动条,也可以拖动它进行滚动,例如本百科全书的条目列表和",
"条目说明都是可以通过上述方式滚动的。",
"<br>",
"<br>",
"2. 本百科全书的内容会<span style=\"color: gold\">随着游戏的推进而增加新内容</span>",
"3. 本百科全书的内容会<span style=\"color: gold\">随着游戏的推进而增加新内容</span>",
"同时每次增加新内容时都会有提示。",
"<br>",
"<br>",
"3. 本塔主要面向电脑端设计,",
"4. 本塔主要面向电脑端设计,",
"<span style=\"color: gold\">建议使用电脑游玩以获得更好的游戏体验</span>。但是手机依然可以游玩本塔,",
"但部分操作可能不是很方便ui 也可能不是很美观,不过依然可以完整体验本游戏。",
"<br>",
"<br>",
"4. 对于手机端,可以点击<span style=\"color: gold\">右下角的难度文字</span>来切换工具栏至数字键。",
"5. 对于手机端,可以点击<span style=\"color: gold\">右下角的难度文字</span>来切换工具栏至数字键。",
"这样,你可以更加方便地进行使用技能等操作。",
"<br>",
"<br>",
"5. 本塔中几乎所有 ui 在打开时都会有一个0.6s的动画,如果不想要,可以在开头捡的系统设置里面关闭(默认关闭)。",
"6. 本塔中几乎所有 ui 在打开时都会有一个0.6s的动画,如果不想要,可以在开头捡的系统设置里面关闭(默认关闭)。",
"同时,几乎所有 ui 的退出按钮都在左上角。"
]
},
"tutorial": {
"text": "新手教程",
"condition": "true",
"desc": [
"本条目是魔塔游戏的新手教程,如果对魔塔有一定的了解,可以直接忽略。",
"<br>",
"<br>",
"魔塔是一种固定数值rpg游戏在打怪的时候遵循<span style=\"color: gold\">我打你一下,你打我一下</span>",
"的原则,造成的伤害是己方攻击减去对方防御,最后怪物的伤害便是你在战斗中失去的生命值。当然,为了游戏体验,",
"战斗过程会被省略。",
"<br>",
"<br>",
"宝石可以增加你的属性,在大部分魔塔中,红宝石增加攻击,蓝宝石增加防御,本塔也不例外。血瓶可以增加你的生命值。",
"一般情况下,拾取宝物的优先级是<span style=\"color: gold\">红宝石 &gt; 蓝宝石 &gt; 血瓶</span>",
"但部分情况可能不是这样,这需要你自己的游玩经验等。",
"<br>",
"<br>",
"本塔还拥有升级机制,升级时能够给你增加大量的属性,因此,一般情况下当你接近升级时,需要尽快打怪升级。",
"<br>",
"<br>",
"然后是门。在魔塔中,很多门都不是必开的门,它们的作用一般是可以躲开怪物拿宝石,或者门里面有血瓶等。",
"当你血量足够时,这些门可以不用开,不然可能会有必开的门无法开启导致卡关。对于钥匙,每种颜色的钥匙开对应颜色的门,",
"价值是<span style=\"color: gold\">红 &gt; 蓝 &gt; 黄</span>。",
"<br>",
"<br>",
"为了更加方便,本塔增加了宝石血瓶显示数据的功能,这样你可以清晰地知道每个宝石增加了多少属性。",
"<br>",
"<br>",
"下面是勇士基础属性的说明:",
"<br>",
"<span style=\"color: lightgreen\">1. 生命值</span>",
"勇士的血量,当它归零时,游戏结束",
"<br>",
"<span style=\"color: lightcoral\">2. 攻击</span>",
"勇士的攻击,攻击越高,每回合对怪物造成的伤害越高",
"<br>",
"<span style=\"color: lightblue\">3. 防御</span>",
"勇士的防御,防御越高,怪物每回合对你造成的伤害越低",
"<br>",
"<span style=\"color: green\">4. 经验</span>",
"勇士的经验,到达一定值后会升级。本塔在状态栏中显示为距离升级剩余的经验",
"<br>",
"<span style=\"color: gold\">5. 金币</span>",
"勇士的金币,可以用于购买物品。本塔中在进入第二章后会有用",
"<br>",
"<span style=\"color: lightgreen\">6. 护盾</span>",
"勇士的护盾,用处是能够在战后减少同等数值的伤害,可以使伤害变为负值。本塔中,在点开无上之盾技能后,",
"智慧会充当护盾。更多信息可以查看“勇士属性”条目。"
]
},
"noun": {
"text": "名词解释",
"condition": "true",
"desc": [
"本条目会解释诸如临界等魔塔术语,对魔塔有一定了解的可以直接忽略。",
"<br>",
"<br>",
"<span style=\"color: lightcoral\">1. 临界</span>",
"在魔塔中,临界是一个非常重要的东西。首先,我们很容易可以得到,吃攻击时只有当减少了战斗回合数时怪物的伤害会减少,",
"那么,吃攻击时怪物的减伤是不连续的。而<span style=\"color: gold\">距离下一次减少怪物的伤害需要加的攻击的量</span>",
"便是临界。当我们吃一个攻击恰好使怪物伤害减少时,称为“踩临界”。一般情况下,踩临界的减伤要比吃防御要高,",
"因此,当能踩到临界时,我们应当先踩临界,再吃防御。",
"<br>",
"<br>",
"<span style=\"color: lightblue\">2. 加防</span>",
"加防指的是加防对怪物的减伤。在本塔中会以“n防”的形式显示在怪物手册或其他地方。在本塔中一般你不需要刻意计算",
"临界与加防减伤,你可以在怪物手册中<span style=\"color: gold\">查看减伤折线图</span>",
"更多信息请查看“怪物手册”条目。",
"<br>",
"<br>",
"<span style=\"color: gold\">3. 咸鱼</span>",
"一般来讲,开不必开的门,或者使用不必使用的道具被称为咸鱼,或者是咸门,咸道具。一般情况下,说“咸”便是指咸鱼。",
"一般情况下,门后面有宝石且无法通过其他方式进入的都是必开门,而只有血瓶的都是咸鱼门。"
]
},
"shortcut": {
"text": "快捷键",
"condition": "true",
"desc": [
"这里包含本塔中所有的快捷键。对于手机端,可以点击工具栏的难度的位置切换工具栏至数字键。",
"<br>",
"<br>",
"下面是样板中的所有快捷键:",
"<br>",
"<span style=\"color: gold\">X</span>:打开怪物手册",
"<br>",
"<span style=\"color: gold\">S</span>:打开存档界面",
"<br>",
"<span style=\"color: gold\">D</span>:打开读档界面",
"<br>",
"<span style=\"color: gold\">A或5</span>:读取自动存档",
"<br>",
"<span style=\"color: gold\">W或6</span>:撤销读取的自动存档",
"<br>",
"<span style=\"color: gold\">Q</span>:打开装备栏",
"<br>",
"<span style=\"color: gold\">T</span>:打开道具栏",
"<br>",
"<span style=\"color: gold\">G</span>:打开楼层传送器",
"<br>",
"<span style=\"color: gold\">Z或单击勇士</span>:勇士转向",
"<br>",
"<span style=\"color: gold\">空格或双击勇士或7</span>:轻按(拾取勇士周围的宝物但不移动勇士)",
"<br>",
"<span style=\"color: gold\">Esc</span>:打开游戏菜单",
"<br>",
"<span style=\"color: gold\">R</span>:打开录像回放菜单",
"<br>",
"<span style=\"color: gold\">N</span>:询问是否返回游戏主菜单",
"<br>",
"<span style=\"color: gold\">V</span>:打开快捷商店",
"<br>",
"<span style=\"color: gold\">B</span>:打开数据统计界面",
"<br>",
"<span style=\"color: gold\">Alt + 数字键</span>:快速换装",
"<br>",
"<span style=\"color: gold\">PgUp或PgDn</span>:浏览地图",
"<br>",
"<span style=\"color: gold\">P</span>:打开评论区",
"<br>",
"<br>",
"下面是本塔中新增的快捷键:",
"<br>",
"<span style=\"color: gold\">M</span>:快速标记怪物"
]
},
"extraAttr": {
"text": "勇士属性",
"condition": "true",
"desc": [
"这里只对本塔中新增的勇士属性进行说明。",
"<br>",
"<br>",
"<span style=\"color: lightblue\">1. 智慧</span>",
"智慧是该塔的核心属性之一。智慧可用于智慧加点,该功能会在进入第一章后开启。使用智慧可以点技能树。",
"除此之外,智慧也有其它功能。例如点开无上之盾技能后智慧还可以充当护盾,第二章点开学习技能后可以使用智慧学习怪物技能等。",
"<br>",
"<br>",
"<span style=\"color: lightgreen\">2. 生命回复</span>",
"生命回复指的是勇士每回合回复的生命值。当与怪物战斗时,勇士每回合都会回复对应量的生命值。因此,当吃攻击时,",
"与怪物战斗的回合数可能会减少,导致生命回复的总回复量减少。不过大部分情况下不需要在意这一点,",
"减少一回合并不会对吸的血造成很大的影响,除了一些特殊情况。",
"该项会显示在状态栏的生命值右方偏下的位置。",
"<br>",
"<br>",
"<span style=\"color: lightcoral\">3. 额外攻击</span>",
"额外攻击指的是勇士每回合的额外造成的伤害。一般情况下,当勇士破了怪物的防御时,该项便会起作用。",
"额外攻击相当于魔攻,无法通过一般方式减免。当勇士攻击怪物时,每回合都会附加对应量的伤害,对坚固怪同样有效。",
"额外攻击会显示在状态栏的攻击右方偏下的位置。"
]
},
"statusBar": {
"text": "状态栏",
"condition": "true",
@ -132,7 +286,7 @@
"<br>",
"点击一个怪物或者按下回车空格后,将进入怪物详细信息界面。这个界面分为多个栏,分别是特殊属性栏,详细临界栏,更多信息栏。",
"进入怪物详细信息后默认在特殊属性栏,该栏可以查看怪物的特殊属性。<span style=\"color: gold\">",
"同时也是唯一一个会在点击后返回到怪物手册界面的栏,更多信息请查看本条目的最后一段</span>。",
"同时也是唯一一个会在点击屏幕返回到怪物手册界面的栏,更多信息请查看本条目的最后一段</span>。",
"注意特殊属性依然可以纵向滚动。在特殊属性下方,",
"是怪物的临界表,可以粗略地查看怪物的临界信息。在下方,你可以点击详细临界信息进入详细临界栏。",
"<br>",
@ -149,7 +303,7 @@
"这一栏的核心功能是标记怪物。被标记的怪物会有一些非常方便的行为,这些行为可以在“标记怪物”条目中查看。",
"<br>",
"<br>",
"注意,在怪物详细信息中,只有特殊属性栏可以通过点击返回到怪物手册界面,详细临界与更多信息栏均不行。",
"注意,在怪物详细信息中,只有特殊属性栏可以通过点击屏幕返回到怪物手册界面,详细临界与更多信息栏均不行。",
"如果你是电脑端,在任意栏目中<span style=\"color: gold\">按下X键</span>会退出怪物手册,返回游戏,",
"<span style=\"color: gold\">按下回车Enter键</span>会回到怪物手册界面。"
]
@ -168,8 +322,8 @@
"首先,对于电脑端,最左侧显示区域信息,手机端则在上方的左侧。",
"<br>",
"<br>",
"然后,区域的右侧是小地图栏,这一栏会显示楼层的屏幕结构。你可以拖动,也可以使用滚轮或者双指放缩,当放缩到一定大小时,",
"会显示地图的缩略图。直接点击地图也可以选中地图,再次点击会传送至目标地图",
"然后,区域的右侧是小地图栏,这一栏会显示楼层的平面结构。你可以拖动,也可以使用滚轮或者双指放缩,当放缩到一定大小时,",
"会显示地图的缩略图。直接点击地图也可以选中地图,再次点击会传送至目标地图",
"<br>",
"<br>",
"对于电脑端,最右侧是当前选中的地图的缩略图,手机则在下方,点击缩略图也可以传送。缩略图的下方是当前选中的地图名,",
@ -204,31 +358,6 @@
"还会直接在勇士属性栏显示增加或减少的属性。"
]
},
"extraAttr": {
"text": "勇士属性",
"condition": "true",
"desc": [
"这里只对本塔中新增的勇士属性进行说明。",
"<br>",
"<br>",
"<span style=\"color: lightblue\">1. 智慧</span>",
"智慧是该塔的核心属性之一。智慧可用于智慧加点,该功能会在进入第一章后开启。使用智慧可以点技能树。",
"除此之外,智慧也有其它功能。例如点开无上之盾技能后智慧还可以充当护盾,第二章点开学习技能后可以使用智慧学习怪物技能等。",
"<br>",
"<br>",
"<span style=\"color: lightgreen\">2. 生命回复</span>",
"生命回复指的是勇士每回合回复的生命值。当与怪物战斗时,勇士每回合都会回复对应量的生命值。因此,当吃攻击时,",
"与怪物战斗的回合数可能会减少,导致生命回复的总回复量减少。不过大部分情况下不需要在意这一点,",
"减少一回合并不会对吸的血造成很大的影响,除了一些特殊情况。",
"该项会显示在状态栏的生命值右方偏下的位置。",
"<br>",
"<br>",
"<span style=\"color: lightcoral\">3. 额外攻击</span>",
"额外攻击指的是勇士每回合的额外造成的伤害。一般情况下,当勇士破了怪物的防御时,该项便会起作用。",
"额外攻击相当于魔攻,无法通过一般方式减免。当勇士攻击怪物时,每回合都会附加对应量的伤害,对坚固怪同样有效。",
"额外攻击会显示在状态栏的攻击右方偏下的位置。"
]
},
"skillTree": {
"text": "技能树",
"condition": "flags.chapter > 0",

View File

@ -9,6 +9,7 @@ import mark from './plugin/mark';
import setting from './plugin/settings';
import chapter from './plugin/ui/chapter';
import fly from './plugin/ui/fly';
import chase from './plugin/chase/chase';
function forward() {
// 每个引入的插件都要在这里执行,否则不会被转发
@ -22,7 +23,8 @@ function forward() {
mark(),
setting(),
chapter(),
fly()
fly(),
chase()
];
// 初始化所有插件并转发到core上

224
src/plugin/chase/chase.ts Normal file
View File

@ -0,0 +1,224 @@
import { Animation, sleep, TimingFn } from 'mutate-animate';
import { has } from '../utils';
import { ChaseCameraData, ChasePath, getChaseDataByIndex } from './data';
export default function init() {
return { startChase };
}
export function shake2(power: number, timing: TimingFn): TimingFn {
let r = 0;
return t => {
r += Math.PI / 2;
return Math.sin(r) * power * timing(t);
};
}
export class Chase {
/**
*
*/
ani: Animation = new Animation();
/**
*
*/
path: ChasePath;
/**
*
*/
showPath: boolean = false;
/**
*
* @param index
* @param path 线
* @param fn
*/
constructor(
path: ChasePath,
fns: ((chase: Chase) => void)[],
camera: ChaseCameraData[],
showPath: boolean = false
) {
this.path = path;
flags.__lockViewport__ = true;
flags.onChase = true;
flags.chaseTime = {
[core.status.floorId]: Date.now()
};
this.ani
.absolute()
.time(0)
.move(core.bigmap.offsetX / 32, core.bigmap.offsetY / 32);
fns.forEach(v => v(this));
const added: FloorIds[] = [];
const ctx = core.createCanvas('chasePath', 0, 0, 0, 0, 35);
for (const [id, x, y, start, time, mode, path] of camera) {
if (!added.includes(id)) {
this.on(
id,
0,
() => {
flags.__lockViewport__ = false;
core.drawHero();
flags.__lockViewport__ = true;
this.ani
.time(0)
.move(
core.bigmap.offsetX / 32,
core.bigmap.offsetY / 32
);
},
true
);
added.push(id);
}
if (!has(path)) {
this.on(id, start, () => {
this.ani.time(time).mode(mode).move(x, y);
});
} else {
this.on(id, start, () => {
this.ani.time(time).mode(mode).moveAs(path);
});
}
}
this.ani.ticker.add(() => {
if (!flags.floorChanging) {
core.setViewport(this.ani.x * 32, this.ani.y * 32);
core.relocateCanvas(ctx, -this.ani.x * 32, -this.ani.y * 32);
}
});
if (showPath) {
for (const [id, p] of Object.entries(path) as [
FloorIds,
LocArr[]
][]) {
this.on(id, 0, () => {
const floor = core.status.maps[id];
core.resizeCanvas(ctx, floor.width * 32, floor.height * 32);
ctx.beginPath();
ctx.moveTo(p[0][0] * 32 + 16, p[1][1] * 32 + 24);
ctx.lineJoin = 'round';
ctx.lineWidth = 4;
ctx.strokeStyle = 'cyan';
ctx.globalAlpha = 0.3;
p.forEach((v, i, a) => {
if (i === 0) return;
const [x, y] = v;
ctx.lineTo(x * 32 + 16, y * 32 + 24);
});
ctx.stroke();
});
}
}
}
/**
*
* @param floorId id
* @param time
* @param fn
*/
on(
floorId: FloorIds,
time: number,
fn: (chase: Chase) => void,
first: boolean = false
) {
const func = () => {
if (!flags.chaseTime?.[floorId]) return;
if (Date.now() - (flags.chaseTime?.[floorId] ?? 0) >= time) {
fn(this);
this.ani.ticker.remove(func);
}
};
this.ani.ticker.add(func, first);
}
/**
*
* @param x
* @param y
* @param floorId id
* @param fn
* @param mode 0
*/
onHeroLoc(
floorId: FloorIds,
fn: (chase: Chase) => void,
x?: number | number[],
y?: number | number[],
mode: 0 | 1 = 0
) {
if (mode === 1) {
if (typeof x === 'number') x = [x];
if (typeof y === 'number') y = [y];
x!.forEach(v => {
(y as number[]).forEach(vv => {
this.onHeroLoc(floorId, fn, v, vv);
});
});
return;
}
const judge = () => {
if (core.status.floorId !== floorId) return false;
if (has(x)) {
if (typeof x === 'number') {
if (core.status.hero.loc.x !== x) return false;
} else {
if (!x.includes(core.status.hero.loc.x)) return false;
}
}
if (has(y)) {
if (typeof y === 'number') {
if (core.status.hero.loc.y !== y) return false;
} else {
if (!y.includes(core.status.hero.loc.y)) return false;
}
}
return true;
};
const func = () => {
if (judge()) {
fn(this);
try {
this.ani.ticker.remove(func);
} catch {}
}
};
this.ani.ticker.add(func);
}
/**
*
* @param show
*/
setPathShowStatus(show: boolean) {
this.showPath = show;
}
/**
*
*/
end() {
this.ani.ticker.destroy();
delete flags.onChase;
delete flags.chase;
flags.__lockViewport__ = false;
core.deleteCanvas('chasePath');
}
}
export async function startChase(index: number) {
const data = getChaseDataByIndex(index);
flags.chaseIndex = index;
flags.onChase = true;
await sleep(20);
flags.chase = new Chase(data.path, data.fns, data.camera);
}

587
src/plugin/chase/chase1.ts Normal file
View File

@ -0,0 +1,587 @@
import { Animation, bezier, hyper, linear, shake, sleep } from 'mutate-animate';
import { Chase, shake2 } from './chase';
import { ChaseCameraData } from './data';
const ani = new Animation();
ani.register('rect', 0);
export const path1: Partial<Record<FloorIds, LocArr[]>> = {
MT16: [
[23, 23],
[0, 23]
],
MT15: [
[63, 4],
[61, 4],
[61, 5],
[58, 5],
[58, 8],
[54, 8],
[54, 11],
[51, 11],
[51, 8],
[45, 8],
[45, 4],
[47, 4],
[47, 6],
[51, 6],
[51, 5],
[52, 5],
[52, 3],
[50, 3],
[50, 5],
[48, 5],
[48, 3],
[35, 3],
[35, 5],
[31, 5],
[31, 7],
[34, 7],
[34, 9],
[31, 9],
[31, 11],
[12, 11],
[12, 8],
[1, 8],
[1, 7],
[0, 7]
],
MT14: [
[127, 7],
[126, 7],
[126, 8],
[124, 8],
[124, 7],
[115.2, 7],
[115.2, 9.2],
[110.2, 9.2],
[110.2, 11],
[109.8, 11],
[109.8, 8.8],
[111.8, 8.8],
[111.8, 7],
[104, 7],
[104, 3],
[100, 3],
[100, 4],
[98, 4],
[98, 3],
[96, 3],
[96, 6],
[95, 6],
[95, 7],
[88, 7],
[88, 6],
[85, 6],
[85, 8],
[83, 8],
[83, 9],
[81, 9],
[81, 11],
[72, 11],
[72, 5],
[68, 5],
[68, 8],
[67, 8],
[67, 10],
[65, 10],
[65, 11],
[62, 11],
[62, 9],
[60, 9],
[60, 11],
[57, 11],
[57, 9],
[54, 9]
]
};
export const camera1: ChaseCameraData[] = [
['MT16', 0, 10, 0, 1600, hyper('sin', 'in')],
['MT15', 45, 0, 0, 2324, hyper('sin', 'in')],
['MT15', 40, 0, 2324, 1992, hyper('sin', 'out')],
['MT15', 41, 0, 5312, 498, hyper('sin', 'in-out')],
['MT15', 37, 0, 5810, 1660, hyper('sin', 'in')],
['MT15', 29, 0, 7470, 830, hyper('sin', 'out')],
['MT15', 25, 0, 11454, 996, hyper('sin', 'in')],
['MT15', 12, 0, 12450, 996, linear()],
['MT15', 0, 0, 13446, 1470, hyper('sin', 'out')],
['MT14', 109, 0, 0, 1328, hyper('sin', 'in')],
['MT14', 104, 0, 1328, 332, hyper('sin', 'out')],
['MT14', 92, 0, 5478, 2822, hyper('sin', 'in')],
['MT14', 84, 0, 8300, 1992, linear()],
['MT14', 74, 0, 10292, 2988, linear()],
['MT14', 65, 0, 13280, 2988, linear()],
['MT14', 58, 0, 16268, 1992, linear()],
['MT14', 47, 0, 18260, 3320, linear()],
['MT14', 36, 0, 21580, 3320, linear()],
['MT14', 0, 0, 24900, 9960, linear()]
];
/**
*
*/
export function init1() {
const ids: FloorIds[] = ['MT13', 'MT14', 'MT15'];
const toRemove: [number, number, FloorIds][] = [];
ids.forEach(v => {
core.status.maps[v].cannotMoveDirectly = true;
core.extractBlocks(v);
core.status.maps[v].blocks.forEach(vv => {
if (
['animates', 'items'].includes(vv.event.cls) &&
!vv.event.id.endsWith('Portal')
) {
toRemove.push([vv.x, vv.y, v]);
}
});
});
toRemove.forEach(v => {
core.removeBlock(...v);
});
}
export function chaseShake(chase: Chase) {
chase.ani
.mode(shake2(2 / 32, bezier(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)), true)
.time(50000)
.shake(1, 0);
}
export async function wolfMove(chase: Chase) {
core.moveBlock(23, 17, Array(6).fill('down'), 80);
await sleep(550);
core.setBlock(508, 23, 23);
}
export function judgeFail1(chase: Chase) {
chase.ani.ticker.add(() => {
if (core.status.hero.loc.x > core.bigmap.offsetX / 32 + 17) {
chase.end();
ani.time(750).apply('rect', 0);
core.lose('逃跑失败');
}
});
}
export function drawBack(chase: Chase) {
chase.on('MT15', 0, () => {
ani.mode(hyper('sin', 'out')).time(1500).absolute().apply('rect', 64);
const ctx = core.createCanvas('chaseBack', 0, 0, 480, 480, 120);
ctx.fillStyle = '#000';
const fn = () => {
if (!ctx) ani.ticker.remove(fn);
core.clearMap(ctx);
ctx.fillRect(0, 0, 480, ani.value.rect);
ctx.fillRect(0, 480, 480, -ani.value.rect);
};
ani.ticker.add(fn);
});
}
export function para1(chase: Chase) {
chase.on('MT15', 830, () => {
for (let tx = 53; tx < 58; tx++) {
for (let ty = 3; ty < 8; ty++) {
core.setBlock(336, tx, ty);
}
}
core.drawAnimate('explosion3', 55, 5);
core.drawAnimate('stone', 55, 5);
});
chase.on('MT15', 1080, () => {
core.setBlock(336, 58, 9);
core.setBlock(336, 59, 9);
core.drawAnimate('explosion1', 58, 9);
core.drawAnimate('explosion1', 59, 9);
});
chase.on('MT15', 1190, () => {
core.setBlock(336, 53, 8);
core.setBlock(336, 52, 8);
core.drawAnimate('explosion1', 53, 8);
core.drawAnimate('explosion1', 52, 8);
});
chase.on('MT15', 1580, () => {
core.setBlock(336, 51, 7);
core.drawAnimate('explosion1', 51, 7);
});
chase.on('MT15', 1830, () => {
core.setBlock(336, 47, 7);
core.setBlock(336, 49, 9);
core.drawAnimate('explosion1', 49, 9);
core.drawAnimate('explosion1', 47, 7);
});
}
export function para2(chase: Chase) {
chase.onHeroLoc(
'MT15',
() => {
core.setBlock(336, 45, 9);
core.drawAnimate('explosion1', 45, 9);
},
45,
8
);
chase.onHeroLoc(
'MT15',
() => {
core.setBlock(336, 44, 6);
core.drawAnimate('explosion1', 44, 6);
},
45,
6
);
chase.onHeroLoc(
'MT15',
() => {
core.setBlock(336, 44, 4);
core.drawAnimate('explosion1', 44, 4);
core.drawAnimate('explosion1', 48, 6);
core.removeBlock(48, 6);
},
45,
4
);
chase.onHeroLoc(
'MT15',
() => {
core.setBlock(336, 41, 4);
core.setBlock(336, 32, 6);
core.drawAnimate('explosion1', 41, 4);
core.drawAnimate('explosion1', 32, 6);
},
41,
3
);
chase.onHeroLoc(
'MT15',
() => {
core.drawAnimate('explosion3', 37, 7);
core.vibrate('vertical', 1000, 25, 10);
for (let tx = 36; tx < 42; tx++) {
for (let ty = 4; ty < 11; ty++) {
core.setBlock(336, tx, ty);
}
}
},
35,
3
);
chase.onHeroLoc(
'MT15',
() => {
core.vibrate('vertical', 10000, 25, 1);
core.removeBlock(34, 8);
core.removeBlock(33, 8);
core.drawAnimate('explosion1', 34, 8);
core.drawAnimate('explosion1', 33, 8);
},
31,
5
);
chase.onHeroLoc(
'MT15',
() => {
core.setBlock(336, 32, 9);
core.drawAnimate('explosion1', 32, 9);
},
33,
7
);
chase.onHeroLoc(
'MT15',
() => {
core.removeBlock(32, 9);
core.drawAnimate('explosion1', 32, 9);
},
[33, 34, 34],
9
);
for (let x = 19; x < 31; x++) {
const xx = x;
chase.onHeroLoc(
'MT15',
() => {
core.setBlock(336, xx + 1, 11);
core.drawAnimate('explosion1', xx + 1, 11);
},
xx,
11
);
}
}
export function para3(chase: Chase) {
chase.onHeroLoc(
'MT14',
() => {
core.setBlock(336, 126, 6);
core.setBlock(336, 124, 6);
core.setBlock(336, 124, 9);
core.setBlock(336, 126, 9);
core.drawAnimate('explosion1', 126, 6);
core.drawAnimate('explosion1', 124, 6);
core.drawAnimate('explosion1', 124, 9);
core.drawAnimate('explosion1', 126, 9);
},
126,
7
);
chase.onHeroLoc(
'MT14',
() => {
core.setBlock(508, 127, 7);
core.jumpBlock(127, 7, 112, 7, 500, true);
setTimeout(() => {
core.setBlock(509, 112, 7);
}, 520);
core.drawHeroAnimate('amazed');
core.setBlock(336, 121, 6);
core.setBlock(336, 122, 6);
core.setBlock(336, 120, 8);
core.setBlock(336, 121, 8);
core.setBlock(336, 122, 8);
core.drawAnimate('explosion1', 121, 6);
core.drawAnimate('explosion1', 122, 6);
core.drawAnimate('explosion1', 120, 8);
core.drawAnimate('explosion1', 121, 8);
core.drawAnimate('explosion1', 122, 8);
},
123,
7
);
chase.onHeroLoc(
'MT14',
() => {
core.setBlock(336, 109, 11);
core.removeBlock(112, 8);
core.drawAnimate('explosion1', 109, 11);
core.drawAnimate('explosion1', 112, 8);
core.insertAction([
{ type: 'moveHero', time: 400, steps: ['backward:1'] }
]);
chase.onHeroLoc(
'MT14',
() => {
core.jumpBlock(112, 7, 110, 4, 500, true);
core.drawHeroAnimate('amazed');
setTimeout(() => {
core.setBlock(506, 110, 4);
}, 540);
},
112,
8
);
},
110,
10
);
chase.onHeroLoc(
'MT14',
() => {
core.setBlock(336, 117, 6);
core.setBlock(336, 116, 6);
core.setBlock(336, 115, 6);
core.setBlock(336, 114, 6);
core.setBlock(336, 117, 8);
core.setBlock(336, 116, 8);
core.drawAnimate('explosion1', 117, 6);
core.drawAnimate('explosion1', 116, 6);
core.drawAnimate('explosion1', 115, 6);
core.drawAnimate('explosion1', 114, 6);
core.drawAnimate('explosion1', 116, 8);
core.drawAnimate('explosion1', 117, 8);
},
118,
7
);
chase.onHeroLoc(
'MT14',
() => {
core.setBlock(336, 112, 8);
core.setBlock(336, 113, 7);
core.drawAnimate('explosion1', 112, 8);
core.drawAnimate('explosion1', 113, 7);
},
112,
7
);
chase.onHeroLoc(
'MT14',
() => {
for (let tx = 111; tx <= 115; tx++) {
core.setBlock(336, tx, 10);
core.drawAnimate('explosion1', tx, 10);
}
core.setBlock(336, 112, 8);
core.drawAnimate('explosion1', 112, 8);
},
115,
7
);
chase.onHeroLoc(
'MT14',
() => {
core.jumpBlock(97, 4, 120, -3, 2000);
for (let tx = 109; tx <= 120; tx++) {
for (let ty = 3; ty <= 11; ty++) {
if (ty == 7) continue;
core.setBlock(336, tx, ty);
}
}
core.drawAnimate('explosion2', 119, 7);
core.removeBlock(105, 7);
core.drawAnimate('explosion1', 105, 7);
},
110,
7
);
chase.onHeroLoc(
'MT14',
() => {
core.setBlock(336, 95, 3);
core.setBlock(336, 93, 6);
core.drawAnimate('explosion1', 95, 3);
core.drawAnimate('explosion1', 93, 6);
},
97,
3
);
chase.onHeroLoc(
'MT14',
() => {
core.setBlock(336, 87, 4);
core.setBlock(336, 88, 5);
core.drawAnimate('explosion1', 87, 4);
core.drawAnimate('explosion1', 88, 5);
},
88,
6
);
chase.onHeroLoc(
'MT14',
() => {
core.setBlock(336, 84, 6);
core.setBlock(336, 85, 5);
core.setBlock(336, 86, 8);
core.drawAnimate('explosion1', 84, 6);
core.drawAnimate('explosion1', 85, 5);
core.drawAnimate('explosion1', 86, 8);
},
86,
6
);
chase.onHeroLoc(
'MT14',
() => {
core.setBlock(336, 81, 8);
core.setBlock(336, 82, 11);
core.drawAnimate('explosion1', 81, 8);
core.drawAnimate('explosion1', 82, 11);
},
81,
9
);
chase.onHeroLoc(
'MT14',
() => {
core.setBlock(336, 73, 8);
core.setBlock(336, 72, 4);
core.drawAnimate('explosion1', 73, 8);
core.drawAnimate('explosion1', 72, 4);
},
72,
11
);
chase.onHeroLoc(
'MT14',
() => {
for (let tx = 74; tx < 86; tx++) {
for (let ty = 3; ty < 12; ty++) {
core.setBlock(336, tx, ty);
}
}
core.drawAnimate('explosion2', 79, 7);
core.vibrate('vertical', 4000, 25, 15);
},
71,
7
);
chase.onHeroLoc(
'MT14',
() => {
core.setBlock(336, 68, 4);
core.setBlock(336, 67, 6);
core.drawAnimate('explosion1', 68, 4);
core.drawAnimate('explosion1', 67, 6);
},
68,
5
);
chase.onHeroLoc(
'MT14',
() => {
for (let tx = 65; tx <= 72; tx++) {
for (let ty = 3; ty <= 9; ty++) {
core.setBlock(336, tx, ty);
}
}
core.setBlock(336, 72, 10);
core.setBlock(336, 72, 11);
core.drawAnimate('explosion3', 69, 5);
},
67,
10
);
chase.onHeroLoc(
'MT14',
() => {
core.setBlock(336, 63, 9);
core.setBlock(336, 60, 8);
core.setBlock(336, 56, 11);
core.drawAnimate('explosion1', 63, 9);
core.drawAnimate('explosion1', 60, 8);
core.drawAnimate('explosion1', 56, 11);
},
64,
11
);
chase.onHeroLoc(
'MT14',
() => {
for (let tx = 58; tx <= 64; tx++) {
for (let ty = 3; ty <= 11; ty++) {
core.setBlock(336, tx, ty);
}
}
core.drawAnimate('explosion2', 61, 7);
},
57,
9
);
for (let x = 21; x < 49; x++) {
chase.onHeroLoc(
'MT14',
() => {
for (let ty = 3; ty <= 11; ty++) {
core.setBlock(336, x + 4, ty);
core.drawAnimate('explosion1', x + 4, ty);
}
},
x
);
}
chase.onHeroLoc(
'MT14',
async () => {
flags.finishChase1 = true;
ani.time(750).apply('rect', 0);
chase.end();
await sleep(750);
ani.ticker.destroy();
core.deleteCanvas('chaseBack');
},
21
);
}

52
src/plugin/chase/data.ts Normal file
View File

@ -0,0 +1,52 @@
import { PathFn, TimingFn } from 'mutate-animate';
import { Chase } from './chase';
import {
camera1,
para1,
para2,
para3,
path1,
chaseShake,
wolfMove,
init1,
judgeFail1,
drawBack
} from './chase1';
export type ChaseCameraData = [
floorId: FloorIds, // 楼层
x: number, // 目标横坐标
y: number, // 目标纵坐标
start: number, // 开始时间
time: number, // 持续时间
mode: TimingFn, // 渐变函数
path?: PathFn // 路径函数
];
export type ChasePath = Partial<Record<FloorIds, LocArr[]>>;
interface ChaseData {
camera: ChaseCameraData[];
fns: ((chase: Chase) => void)[];
path: ChasePath;
}
export function getChaseDataByIndex(index: number): ChaseData {
if (index === 1) {
init1();
return {
camera: camera1,
fns: [
para1,
para2,
para3,
chaseShake,
wolfMove,
drawBack,
judgeFail1
],
path: path1
};
}
throw new ReferenceError(`Deliver wrong chase index.`);
}

7
src/types/map.d.ts vendored
View File

@ -146,6 +146,11 @@ interface FloorBase<T extends FloorIds = FloorIds> {
*/
cannotViewMap?: boolean;
/**
*
*/
cannotMoveDirectly?: boolean;
/**
*
*/
@ -1347,7 +1352,7 @@ interface Maps {
name: AnimationIds | NameMapIn<AnimationIds>,
x: number,
y: number,
alignWindow: boolean,
alignWindow?: boolean,
callback?: () => void
): number;

View File

@ -108,6 +108,12 @@ interface PluginUtils {
type: 'warn' | 'info' | 'success' | 'error' | 'warning' | 'loading',
text: string
): void;
/**
*
* @param index
*/
startChase(index: number): Promise<void>;
}
interface PluginUis {

4
src/types/ui.d.ts vendored
View File

@ -784,7 +784,7 @@ interface Ui {
*
*/
relocateCanvas(
name: string,
name: CtxRefer,
x: number,
y: number,
useDelta?: boolean
@ -806,7 +806,7 @@ interface Ui {
* @param isTempCanvas true
*/
resizeCanvas(
name: string,
name: CtxRefer,
x?: number,
y?: number,
styleOnly?: boolean,