diff --git a/public/libs/control.js b/public/libs/control.js index f5503f9..8c4f800 100644 --- a/public/libs/control.js +++ b/public/libs/control.js @@ -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; } diff --git a/public/project/floors/MT14.js b/public/project/floors/MT14.js index cc0db69..65be6af 100644 --- a/public/project/floors/MT14.js +++ b/public/project/floors/MT14.js @@ -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", diff --git a/public/project/floors/MT15.js b/public/project/floors/MT15.js index 602c927..a91ddc1 100644 --- a/public/project/floors/MT15.js +++ b/public/project/floors/MT15.js @@ -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": [ "不愧是你!!!" diff --git a/public/project/floors/MT16.js b/public/project/floors/MT16.js index a0cd5c4..6497269 100644 --- a/public/project/floors/MT16.js +++ b/public/project/floors/MT16.js @@ -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}" } ] }, diff --git a/public/project/functions.js b/public/project/functions.js index 17b4b98..2e90c3d 100644 --- a/public/project/functions.js +++ b/public/project/functions.js @@ -121,6 +121,8 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { // 正在切换楼层过程中执行的操作;此函数的执行时间是“屏幕完全变黑“的那一刻 // floorId为要切换到的楼层ID;heroLoc表示勇士切换到的位置 + 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) { diff --git a/public/project/plugins.js b/public/project/plugins.js index 9e43239..ecaa78b 100644 --- a/public/project/plugins.js +++ b/public/project/plugins.js @@ -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; diff --git a/src/components/scroll.vue b/src/components/scroll.vue index 7ce3db4..206d69c 100644 --- a/src/components/scroll.vue +++ b/src/components/scroll.vue @@ -88,27 +88,27 @@ function draw() { * 计算元素总长度 */ async function calHeight() { - await new Promise(res => { - const canvas = ctx.canvas; - const style2 = getComputedStyle(canvas); - canvas.style.width = `${width}px`; - canvas.width = width * scale; - canvas.height = parseFloat(style2.height) * scale; - if (props.noScroll) canvas.style.width = `0px`; + await sleep(20); + const canvas = ctx.canvas; + const style2 = getComputedStyle(canvas); + canvas.style.width = `${width}px`; + canvas.width = width * scale; + canvas.height = parseFloat(style2.height) * scale; + if (props.noScroll) canvas.style.width = `0px`; - if (props.type === 'horizontal') { - main.style.flexDirection = 'column'; - canvas.style.height = `${width}px`; - canvas.style.width = '98%'; - canvas.style.margin = '0 1% 0 1%'; - canvas.width = parseFloat(style2.width) * scale; - canvas.height = width * scale; - if (props.noScroll) canvas.style.height = `0px`; - } + if (props.type === 'horizontal') { + main.style.flexDirection = 'column'; + canvas.style.height = `${width}px`; + canvas.style.width = '98%'; + canvas.style.margin = '0 1% 0 1%'; + canvas.width = parseFloat(style2.width) * scale; + 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 = ''; diff --git a/src/data/desc.json b/src/data/desc.json index 2c5d79d..ff7672d 100644 --- a/src/data/desc.json +++ b/src/data/desc.json @@ -6,29 +6,183 @@ "这里显示本塔中需要注意的事项。", "
", "
", - "1. 本塔中几乎所有 ui 都可以纵向滚动,如果发现显示不全,", + "1. 本百科全书字数很多,可以选择性地阅读。", + "
", + "
", + "2. 本塔中几乎所有 ui 都可以纵向滚动,如果发现显示不全,", "可以尝试上下拖动,就像浏览网页一样。电脑端还可以使用滚轮上下滚动。", "大部分可以纵向滚动的 ui 都会在右方有一个滚动条,也可以拖动它进行滚动,例如本百科全书的条目列表和", "条目说明都是可以通过上述方式滚动的。", "
", "
", - "2. 本百科全书的内容会随着游戏的推进而增加新内容,", + "3. 本百科全书的内容会随着游戏的推进而增加新内容,", "同时每次增加新内容时都会有提示。", "
", "
", - "3. 本塔主要面向电脑端设计,", + "4. 本塔主要面向电脑端设计,", "建议使用电脑游玩以获得更好的游戏体验。但是手机依然可以游玩本塔,", "但部分操作可能不是很方便,ui 也可能不是很美观,不过依然可以完整体验本游戏。", "
", "
", - "4. 对于手机端,可以点击右下角的难度文字来切换工具栏至数字键。", + "5. 对于手机端,可以点击右下角的难度文字来切换工具栏至数字键。", "这样,你可以更加方便地进行使用技能等操作。", "
", "
", - "5. 本塔中几乎所有 ui 在打开时都会有一个0.6s的动画,如果不想要,可以在开头捡的系统设置里面关闭(默认关闭)。", + "6. 本塔中几乎所有 ui 在打开时都会有一个0.6s的动画,如果不想要,可以在开头捡的系统设置里面关闭(默认关闭)。", "同时,几乎所有 ui 的退出按钮都在左上角。" ] }, + "tutorial": { + "text": "新手教程", + "condition": "true", + "desc": [ + "本条目是魔塔游戏的新手教程,如果对魔塔有一定的了解,可以直接忽略。", + "
", + "
", + "魔塔是一种固定数值rpg游戏,在打怪的时候,遵循我打你一下,你打我一下", + "的原则,造成的伤害是己方攻击减去对方防御,最后怪物的伤害便是你在战斗中失去的生命值。当然,为了游戏体验,", + "战斗过程会被省略。", + "
", + "
", + "宝石可以增加你的属性,在大部分魔塔中,红宝石增加攻击,蓝宝石增加防御,本塔也不例外。血瓶可以增加你的生命值。", + "一般情况下,拾取宝物的优先级是红宝石 > 蓝宝石 > 血瓶,", + "但部分情况可能不是这样,这需要你自己的游玩经验等。", + "
", + "
", + "本塔还拥有升级机制,升级时能够给你增加大量的属性,因此,一般情况下当你接近升级时,需要尽快打怪升级。", + "
", + "
", + "然后是门。在魔塔中,很多门都不是必开的门,它们的作用一般是可以躲开怪物拿宝石,或者门里面有血瓶等。", + "当你血量足够时,这些门可以不用开,不然可能会有必开的门无法开启导致卡关。对于钥匙,每种颜色的钥匙开对应颜色的门,", + "价值是红 > 蓝 > 黄。", + "
", + "
", + "为了更加方便,本塔增加了宝石血瓶显示数据的功能,这样你可以清晰地知道每个宝石增加了多少属性。", + "
", + "
", + "下面是勇士基础属性的说明:", + "
", + "1. 生命值:", + "勇士的血量,当它归零时,游戏结束", + "
", + "2. 攻击:", + "勇士的攻击,攻击越高,每回合对怪物造成的伤害越高", + "
", + "3. 防御:", + "勇士的防御,防御越高,怪物每回合对你造成的伤害越低", + "
", + "4. 经验:", + "勇士的经验,到达一定值后会升级。本塔在状态栏中显示为距离升级剩余的经验", + "
", + "5. 金币:", + "勇士的金币,可以用于购买物品。本塔中在进入第二章后会有用", + "
", + "6. 护盾:", + "勇士的护盾,用处是能够在战后减少同等数值的伤害,可以使伤害变为负值。本塔中,在点开无上之盾技能后,", + "智慧会充当护盾。更多信息可以查看“勇士属性”条目。" + ] + }, + "noun": { + "text": "名词解释", + "condition": "true", + "desc": [ + "本条目会解释诸如临界等魔塔术语,对魔塔有一定了解的可以直接忽略。", + "
", + "
", + "1. 临界:", + "在魔塔中,临界是一个非常重要的东西。首先,我们很容易可以得到,吃攻击时只有当减少了战斗回合数时怪物的伤害会减少,", + "那么,吃攻击时怪物的减伤是不连续的。而距离下一次减少怪物的伤害需要加的攻击的量", + "便是临界。当我们吃一个攻击恰好使怪物伤害减少时,称为“踩临界”。一般情况下,踩临界的减伤要比吃防御要高,", + "因此,当能踩到临界时,我们应当先踩临界,再吃防御。", + "
", + "
", + "2. 加防:", + "加防指的是加防对怪物的减伤。在本塔中,会以“n防”的形式显示在怪物手册或其他地方。在本塔中,一般你不需要刻意计算", + "临界与加防减伤,你可以在怪物手册中查看减伤折线图,", + "更多信息请查看“怪物手册”条目。", + "
", + "
", + "3. 咸鱼:", + "一般来讲,开不必开的门,或者使用不必使用的道具被称为咸鱼,或者是咸门,咸道具。一般情况下,说“咸”便是指咸鱼。", + "一般情况下,门后面有宝石且无法通过其他方式进入的都是必开门,而只有血瓶的都是咸鱼门。" + ] + }, + "shortcut": { + "text": "快捷键", + "condition": "true", + "desc": [ + "这里包含本塔中所有的快捷键。对于手机端,可以点击工具栏的难度的位置切换工具栏至数字键。", + "
", + "
", + "下面是样板中的所有快捷键:", + "
", + "X:打开怪物手册", + "
", + "S:打开存档界面", + "
", + "D:打开读档界面", + "
", + "A或5:读取自动存档", + "
", + "W或6:撤销读取的自动存档", + "
", + "Q:打开装备栏", + "
", + "T:打开道具栏", + "
", + "G:打开楼层传送器", + "
", + "Z或单击勇士:勇士转向", + "
", + "空格或双击勇士或7:轻按(拾取勇士周围的宝物但不移动勇士)", + "
", + "Esc:打开游戏菜单", + "
", + "R:打开录像回放菜单", + "
", + "N:询问是否返回游戏主菜单", + "
", + "V:打开快捷商店", + "
", + "B:打开数据统计界面", + "
", + "Alt + 数字键:快速换装", + "
", + "PgUp或PgDn:浏览地图", + "
", + "P:打开评论区", + "
", + "
", + "下面是本塔中新增的快捷键:", + "
", + "M:快速标记怪物" + ] + }, + "extraAttr": { + "text": "勇士属性", + "condition": "true", + "desc": [ + "这里只对本塔中新增的勇士属性进行说明。", + "
", + "
", + "1. 智慧:", + "智慧是该塔的核心属性之一。智慧可用于智慧加点,该功能会在进入第一章后开启。使用智慧可以点技能树。", + "除此之外,智慧也有其它功能。例如点开无上之盾技能后智慧还可以充当护盾,第二章点开学习技能后可以使用智慧学习怪物技能等。", + "
", + "
", + "2. 生命回复:", + "生命回复指的是勇士每回合回复的生命值。当与怪物战斗时,勇士每回合都会回复对应量的生命值。因此,当吃攻击时,", + "与怪物战斗的回合数可能会减少,导致生命回复的总回复量减少。不过大部分情况下不需要在意这一点,", + "减少一回合并不会对吸的血造成很大的影响,除了一些特殊情况。", + "该项会显示在状态栏的生命值右方偏下的位置。", + "
", + "
", + "3. 额外攻击:", + "额外攻击指的是勇士每回合的额外造成的伤害。一般情况下,当勇士破了怪物的防御时,该项便会起作用。", + "额外攻击相当于魔攻,无法通过一般方式减免。当勇士攻击怪物时,每回合都会附加对应量的伤害,对坚固怪同样有效。", + "额外攻击会显示在状态栏的攻击右方偏下的位置。" + ] + }, "statusBar": { "text": "状态栏", "condition": "true", @@ -132,7 +286,7 @@ "
", "点击一个怪物或者按下回车空格后,将进入怪物详细信息界面。这个界面分为多个栏,分别是特殊属性栏,详细临界栏,更多信息栏。", "进入怪物详细信息后默认在特殊属性栏,该栏可以查看怪物的特殊属性。", - "同时也是唯一一个会在点击后返回到怪物手册界面的栏,更多信息请查看本条目的最后一段。", + "同时也是唯一一个会在点击屏幕后会返回到怪物手册界面的栏,更多信息请查看本条目的最后一段。", "注意特殊属性依然可以纵向滚动。在特殊属性下方,", "是怪物的临界表,可以粗略地查看怪物的临界信息。在下方,你可以点击详细临界信息进入详细临界栏。", "
", @@ -149,7 +303,7 @@ "这一栏的核心功能是标记怪物。被标记的怪物会有一些非常方便的行为,这些行为可以在“标记怪物”条目中查看。", "
", "
", - "注意,在怪物详细信息中,只有特殊属性栏可以通过点击返回到怪物手册界面,详细临界与更多信息栏均不行。", + "注意,在怪物详细信息中,只有特殊属性栏可以通过点击屏幕返回到怪物手册界面,详细临界与更多信息栏均不行。", "如果你是电脑端,在任意栏目中按下X键会退出怪物手册,返回游戏,", "按下回车(Enter)键会回到怪物手册界面。" ] @@ -168,8 +322,8 @@ "首先,对于电脑端,最左侧显示区域信息,手机端则在上方的左侧。", "
", "
", - "然后,区域的右侧是小地图栏,这一栏会显示楼层的屏幕结构。你可以拖动,也可以使用滚轮或者双指放缩,当放缩到一定大小时,", - "会显示地图的缩略图。直接点击地图也可以选中地图,再次点击会传送至目标地图", + "然后,区域的右侧是小地图栏,这一栏会显示楼层的平面结构。你可以拖动,也可以使用滚轮或者双指放缩,当放缩到一定大小时,", + "会显示地图的缩略图。直接点击地图也可以选中地图,再次点击会传送至目标地图。", "
", "
", "对于电脑端,最右侧是当前选中的地图的缩略图,手机则在下方,点击缩略图也可以传送。缩略图的下方是当前选中的地图名,", @@ -204,31 +358,6 @@ "还会直接在勇士属性栏显示增加或减少的属性。" ] }, - "extraAttr": { - "text": "勇士属性", - "condition": "true", - "desc": [ - "这里只对本塔中新增的勇士属性进行说明。", - "
", - "
", - "1. 智慧:", - "智慧是该塔的核心属性之一。智慧可用于智慧加点,该功能会在进入第一章后开启。使用智慧可以点技能树。", - "除此之外,智慧也有其它功能。例如点开无上之盾技能后智慧还可以充当护盾,第二章点开学习技能后可以使用智慧学习怪物技能等。", - "
", - "
", - "2. 生命回复:", - "生命回复指的是勇士每回合回复的生命值。当与怪物战斗时,勇士每回合都会回复对应量的生命值。因此,当吃攻击时,", - "与怪物战斗的回合数可能会减少,导致生命回复的总回复量减少。不过大部分情况下不需要在意这一点,", - "减少一回合并不会对吸的血造成很大的影响,除了一些特殊情况。", - "该项会显示在状态栏的生命值右方偏下的位置。", - "
", - "
", - "3. 额外攻击:", - "额外攻击指的是勇士每回合的额外造成的伤害。一般情况下,当勇士破了怪物的防御时,该项便会起作用。", - "额外攻击相当于魔攻,无法通过一般方式减免。当勇士攻击怪物时,每回合都会附加对应量的伤害,对坚固怪同样有效。", - "额外攻击会显示在状态栏的攻击右方偏下的位置。" - ] - }, "skillTree": { "text": "技能树", "condition": "flags.chapter > 0", diff --git a/src/initPlugin.ts b/src/initPlugin.ts index ea69e0f..8f9749d 100644 --- a/src/initPlugin.ts +++ b/src/initPlugin.ts @@ -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上 diff --git a/src/plugin/chase/chase.ts b/src/plugin/chase/chase.ts new file mode 100644 index 0000000..4f6248a --- /dev/null +++ b/src/plugin/chase/chase.ts @@ -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); +} diff --git a/src/plugin/chase/chase1.ts b/src/plugin/chase/chase1.ts new file mode 100644 index 0000000..a232ef2 --- /dev/null +++ b/src/plugin/chase/chase1.ts @@ -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> = { + 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 + ); +} diff --git a/src/plugin/chase/data.ts b/src/plugin/chase/data.ts new file mode 100644 index 0000000..0a79ff5 --- /dev/null +++ b/src/plugin/chase/data.ts @@ -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>; + +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.`); +} diff --git a/src/types/map.d.ts b/src/types/map.d.ts index dc9df48..fdff9f1 100644 --- a/src/types/map.d.ts +++ b/src/types/map.d.ts @@ -146,6 +146,11 @@ interface FloorBase { */ cannotViewMap?: boolean; + /** + * 是否不能瞬移 + */ + cannotMoveDirectly?: boolean; + /** * 是否是地下层 */ @@ -1347,7 +1352,7 @@ interface Maps { name: AnimationIds | NameMapIn, x: number, y: number, - alignWindow: boolean, + alignWindow?: boolean, callback?: () => void ): number; diff --git a/src/types/plugin.d.ts b/src/types/plugin.d.ts index 9a0a934..d521aa7 100644 --- a/src/types/plugin.d.ts +++ b/src/types/plugin.d.ts @@ -108,6 +108,12 @@ interface PluginUtils { type: 'warn' | 'info' | 'success' | 'error' | 'warning' | 'loading', text: string ): void; + + /** + * 开始一个追逐战 + * @param index 追逐战索引 + */ + startChase(index: number): Promise; } interface PluginUis { diff --git a/src/types/ui.d.ts b/src/types/ui.d.ts index 73b05f8..5a2bd2c 100644 --- a/src/types/ui.d.ts +++ b/src/types/ui.d.ts @@ -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,