diff --git a/idea.md b/idea.md index 58e3b0b..e8699c5 100644 --- a/idea.md +++ b/idea.md @@ -100,7 +100,7 @@ dam4.png ---- 存档 59 [] 优化各种 ui [] 怪物脚下加入阴影 [x] 着色器特效 -[] 完全删除 core.plugin,采用 Plugin.register 的形式进行插件编写 +[x] 完全删除 core.plugin,采用 Plugin.register 的形式进行插件编写 [] 通用 Addon 接口 [] 完善加载系统 [] 不同怪物可以在怪物手册中添加一些不同的边框 @@ -113,5 +113,5 @@ dam4.png ---- 存档 59 [] 注册可录像操作,比如可以在点击的时候执行,自动计入录像 [] 机关门显示绑定怪物 [] 自定义状态栏,通过申请空间进行布局 -[] 复写 api,rewrite() +[x] 复写 api,rewrite() [] 对 vnode 进行简单的包装,提供出显示文字、显示图片等 api 以及修改 css 的 api diff --git a/public/_server/MotaAction.g4 b/public/_server/MotaAction.g4 index 7c6670b..4b9753f 100644 --- a/public/_server/MotaAction.g4 +++ b/public/_server/MotaAction.g4 @@ -3850,7 +3850,7 @@ isShopVisited_e /* isShopVisited_e default : ['shop1'] allShops : ['IdString_0'] -var code = 'core.plugin.shop.isShopVisited(\'' + IdString_0 + '\')'; +var code = 'Mota.Plugin.require("shop_g").isShopVisited(\'' + IdString_0 + '\')'; return [code, Blockly.JavaScript.ORDER_ATOMIC]; */; diff --git a/public/libs/actions.js b/public/libs/actions.js index 20cbd9e..170b781 100644 --- a/public/libs/actions.js +++ b/public/libs/actions.js @@ -1620,7 +1620,8 @@ actions.prototype._keyUpViewMaps = function (keycode) { ////// 快捷商店界面时的点击操作 ////// actions.prototype._clickQuickShop = function (x, y) { - var shopIds = core.plugin.shop.listShopIds(); + const shop = Mota.Plugin.require('shop_g'); + var shopIds = shop.listShopIds(); if (this._out(x)) return; var topIndex = this._HY_ - @@ -1628,15 +1629,15 @@ actions.prototype._clickQuickShop = function (x, y) { (core.status.event.ui.offset || 0); if (y >= topIndex && y < topIndex + shopIds.length) { var shopId = shopIds[y - topIndex]; - if (!core.plugin.shop.canOpenShop(shopId)) { + if (!shop.canOpenShop(shopId)) { core.playSound('操作失败'); core.drawTip('当前项尚未开启'); return; } - var message = core.plugin.shop.canUseQuickShop(shopId); + var message = shop.canUseQuickShop(shopId); if (message == null) { // core.ui.closePanel(); - core.plugin.shop.openShop(shopIds[y - topIndex], false); + shop.openShop(shopIds[y - topIndex], false); } else { core.playSound('操作失败'); core.drawTip(message); @@ -1657,7 +1658,7 @@ actions.prototype._keyUpQuickShop = function (keycode) { return; } this._selectChoices( - core.plugin.shop.listShopIds().length + 1, + Mota.Plugin.require('shop_g').listShopIds().length + 1, keycode, this._clickQuickShop ); diff --git a/public/libs/control.js b/public/libs/control.js index af0555b..946d99b 100644 --- a/public/libs/control.js +++ b/public/libs/control.js @@ -1449,9 +1449,10 @@ control.prototype.checkBlock = function () { control.prototype._checkBlock_disableQuickShop = function () { // 禁用快捷商店 + const { setShopVisited } = Mota.Plugin.require('shop_g'); if (core.flags.disableShopOnDamage) { Object.keys(core.status.shops).forEach(function (shopId) { - core.plugin.shop.setShopVisited(shopId, false); + setShopVisited(shopId, false); }); } }; @@ -1544,7 +1545,7 @@ control.prototype.startReplay = function (list) { core.status.replay.totalList = core.status.route.concat(list); core.status.replay.steps = 0; core.status.replay.save = []; - core.plugin.replay.ready(); + Mota.Plugin.require('replay_g').ready(); core.createCanvas('replay', 0, core._PY_ - 40, core._PX_, 40, 199); core.setOpacity('replay', 0.6); this._replay_drawProgress(); diff --git a/public/libs/core.js b/public/libs/core.js index d47913d..8db9113 100644 --- a/public/libs/core.js +++ b/public/libs/core.js @@ -279,7 +279,7 @@ core.prototype.init = async function (coreData, callback) { this._init_flags(); this._init_platform(); this._init_others(); - await this._loadPlugin(); + await this._loadGameProcess(); var b = main.mode == 'editor'; // 初始化画布 @@ -307,34 +307,31 @@ core.prototype.initSync = function (coreData, callback) { this._init_flags(); this._init_platform(); this._init_others(); - this._loadPluginSync(); + this._loadGameProcessSync(); core.loader._load(function () { core._afterLoadResources(callback); }); }; -core.prototype._loadPluginSync = function () { - core.plugin = {}; - if (main.useCompress) main.loadMod('project', 'plugin', () => 0); - else main.loadMod('project', 'plugin.min', () => 0); -}; - -core.prototype._loadPlugin = async function () { - const mainData = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.main; - core.plugin = {}; - // 加载插件 +core.prototype._loadGameProcess = async function () { + // 加载游戏进程代码 if (main.pluginUseCompress) { - await main.loadScript(`project/plugin.min.js?v=${main.version}`); + await main.loadScript(`project/processG.min.js?v=${main.version}`); } else { if (main.mode === 'play') { - await main.loadScript(`src/plugin/game/index.js`, true); + await main.loadScript(`src/game/index.ts`, true); } else { - await main.loadScript(`src/plugin/game/index.esm.js`, true); + await main.loadScript(`src/game/index.esm.ts`, true); } } }; +core.prototype._loadGameProcessSync = function () { + if (main.useCompress) main.loadMod('project', 'processG', () => 0); + else main.loadMod('project', 'processG.min', () => 0); +}; + core.prototype._init_flags = function () { core.flags = core.clone(core.data.flags); core.values = core.clone(core.data.values); @@ -580,7 +577,6 @@ core.prototype._init_others = function () { core.prototype._afterLoadResources = function (callback) { // 初始化地图 - core.initStatus.maps = core.maps._initMaps(); core.control._setRequestAnimationFrame(); // 图片裁剪 (main.splitImages || []).forEach(function (one) { @@ -604,7 +600,7 @@ core.prototype._afterLoadResources = function (callback) { } }); - if (core.plugin._afterLoadResources) core.plugin._afterLoadResources(); + // if (core.plugin._afterLoadResources) core.plugin._afterLoadResources(); core.showStartAnimate(); if (callback) callback(); }; @@ -664,8 +660,9 @@ core.prototype._forwardFunc = function (name, funcname) { core.prototype.doFunc = function (func, _this) { if (typeof func == 'string') { - func = core.plugin[func]; - _this = core.plugin; + throw new Error('Parameter func must be a function.'); + // func = core.plugin[func]; + // _this = core.plugin; } return func.apply(_this, Array.prototype.slice.call(arguments, 2)); }; diff --git a/public/libs/events.js b/public/libs/events.js index f2e4355..d6a5ed7 100644 --- a/public/libs/events.js +++ b/public/libs/events.js @@ -30,7 +30,7 @@ events.prototype.startGame = function (hard, seed, route, callback) { } if (main.mode != 'play') return; - core.plugin.skillTree.resetSkillLevel(); + Mota.Plugin.require('skillTree_g').resetSkillLevel(); // 无动画的开始游戏 if (core.flags.startUsingCanvas || route != null) { @@ -2079,13 +2079,13 @@ events.prototype._action_unloadEquip = function (data, x, y, prefix) { }; events.prototype._action_openShop = function (data, x, y, prefix) { - core.plugin.shop.setShopVisited(data.id, true); - if (data.open) core.plugin.shop.openShop(data.id, true); + Mota.Plugin.require('shop_g').setShopVisited(data.id, true); + if (data.open) Mota.Plugin.require('shop_g').openShop(data.id, true); core.doAction(); }; events.prototype._action_disableShop = function (data, x, y, prefix) { - core.plugin.shop.setShopVisited(data.id, false); + Mota.Plugin.require('shop_g').setShopVisited(data.id, false); core.doAction(); }; @@ -3272,6 +3272,7 @@ events.prototype.openToolbox = function (fromUserAction) { ////// 点击快捷商店按钮时的打开操作 ////// events.prototype.openQuickShop = function (fromUserAction) { if (core.isReplaying()) return; + const shop = Mota.Plugin.require('shop_g'); if (Object.keys(core.status.shops).length == 0) { core.playSound('操作失败'); @@ -3283,18 +3284,18 @@ events.prototype.openQuickShop = function (fromUserAction) { if (Object.keys(core.status.shops).length == 1) { var shopId = Object.keys(core.status.shops)[0]; if (core.status.event.id != null) return; - if (!core.plugin.shop.canOpenShop(shopId)) { + if (!shop.canOpenShop(shopId)) { core.playSound('操作失败'); core.drawTip('当前无法打开快捷商店!'); return; } - var message = core.plugin.shop.canUseQuickShop(shopId); + var message = shop.canUseQuickShop(shopId); if (message != null) { core.playSound('操作失败'); core.drawTip(message); return; } - core.plugin.shop.openShop(shopId, false); + shop.openShop(shopId, false); return; } diff --git a/public/libs/ui.js b/public/libs/ui.js index 4424846..1002e4e 100644 --- a/public/libs/ui.js +++ b/public/libs/ui.js @@ -3099,13 +3099,14 @@ ui.prototype._drawNotes = function () { ////// 绘制快捷商店选择栏 ////// ui.prototype._drawQuickShop = function () { + const shop = Mota.Plugin.require('shop'); core.status.event.id = 'selectShop'; var shopList = core.status.shops, - keys = core.plugin.shop.listShopIds(); + keys = shop.listShopIds(); var choices = keys.map(function (shopId) { return { text: shopList[shopId].textInList, - color: core.plugin.shop.isShopVisited(shopId) ? null : '#999999' + color: shop.isShopVisited(shopId) ? null : '#999999' }; }); choices.push('返回游戏'); diff --git a/public/main.js b/public/main.js index 08d1799..b29017d 100644 --- a/public/main.js +++ b/public/main.js @@ -404,6 +404,7 @@ main.prototype.loadAsync = async function (mode, callback) { }); await core.init(coreData, callback); if (main.mode === 'play') main.loading.emit('coreInit'); + core.initStatus.maps = core.maps._initMaps(); core.resize(); @@ -414,7 +415,7 @@ main.prototype.loadAsync = async function (mode, callback) { if (auto && !core.domStyle.isVertical) { try { - core.plugin.utils.maxGameScale(); + Mota.Plugin.require('utils_g').maxGameScale(); requestAnimationFrame(() => { var style = getComputedStyle(main.dom.gameGroup); var height = parseFloat(style.height); diff --git a/public/project/floors/MT16.js b/public/project/floors/MT16.js index 85e4707..b036750 100644 --- a/public/project/floors/MT16.js +++ b/public/project/floors/MT16.js @@ -413,7 +413,7 @@ main.floors.MT16= "这里是漏怪检测,将会检测\r[gold]洞穴、山路、山脚、平原\r[white]地区的怪物是否清完", { "type": "function", - "function": "function(){\nconst enemy = core.plugin.remainEnemy.getRemainEnemyString(core.floorIds.slice(5, 17));\nif (enemy.length === 0) {\n\tcore.insertAction(['当前无剩余怪物!', { \"type\": \"hide\", \"remove\": true }, ]);\n} else {\n\tcore.insertAction(enemy);\n}\n}" + "function": "function(){\nconst enemy = Mota.Plugin.require('remainEnemy_g').getRemainEnemyString(core.floorIds.slice(5, 17));\nif (enemy.length === 0) {\n\tcore.insertAction(['当前无剩余怪物!', { \"type\": \"hide\", \"remove\": true }, ]);\n} else {\n\tcore.insertAction(enemy);\n}\n}" }, { "type": "loadBgm", diff --git a/public/project/floors/MT31.js b/public/project/floors/MT31.js index adf7323..aa5bb7e 100644 --- a/public/project/floors/MT31.js +++ b/public/project/floors/MT31.js @@ -148,7 +148,7 @@ main.floors.MT31= "这里是漏怪检测,会检测\r[gold]勇气之路\r[]区域是否有遗漏怪物", { "type": "function", - "function": "function(){\nconst enemy = core.plugin.remainEnemy.getRemainEnemyString(core.floorIds.slice(17, 22));\nif (enemy.length === 0) {\n\tcore.insertAction(['当前无剩余怪物!', { \"type\": \"hide\", \"remove\": true }, ]);\n} else {\n\tcore.insertAction(enemy);\n}\n}" + "function": "function(){\nconst enemy = Mota.Plugin.require('remainEnemy_g').getRemainEnemyString(core.floorIds.slice(17, 22));\nif (enemy.length === 0) {\n\tcore.insertAction(['当前无剩余怪物!', { \"type\": \"hide\", \"remove\": true }, ]);\n} else {\n\tcore.insertAction(enemy);\n}\n}" } ] }, diff --git a/public/project/floors/MT35.js b/public/project/floors/MT35.js index 1a32956..cbeff6a 100644 --- a/public/project/floors/MT35.js +++ b/public/project/floors/MT35.js @@ -76,7 +76,7 @@ main.floors.MT35= "这里是漏怪检测,会检测\r[gold]智慧小径\r[]区域是否有遗漏怪物", { "type": "function", - "function": "function(){\nconst enemy = core.plugin.remainEnemy.getRemainEnemyString(core.floorIds.slice(30, 40));\nif (enemy.length === 0) {\n\tcore.insertAction(['当前无剩余怪物!', { \"type\": \"hide\", \"remove\": true }, ]);\n} else {\n\tcore.insertAction(enemy);\n}\n}" + "function": "function(){\nconst enemy = Mota.Plugin.require('remainEnemy_g').getRemainEnemyString(core.floorIds.slice(30, 40));\nif (enemy.length === 0) {\n\tcore.insertAction(['当前无剩余怪物!', { \"type\": \"hide\", \"remove\": true }, ]);\n} else {\n\tcore.insertAction(enemy);\n}\n}" } ], "7,0": [ diff --git a/public/project/floors/MT5.js b/public/project/floors/MT5.js index a4eba57..eb78c12 100644 --- a/public/project/floors/MT5.js +++ b/public/project/floors/MT5.js @@ -120,7 +120,7 @@ main.floors.MT5= "这里是漏怪检测,会检测\r[gold]山洞\r[]区域的怪物是否清空", { "type": "function", - "function": "function(){\nconst enemy = core.plugin.remainEnemy.getRemainEnemyString(core.floorIds.slice(0, 5));\nif (enemy.length === 0) {\n\tcore.insertAction(['当前无剩余怪物!', { \"type\": \"hide\", \"remove\": true }, ]);\n} else {\n\tcore.insertAction(enemy);\n}\n}" + "function": "function(){\nconst enemy = Mota.Plugin.require('remainEnemy_g').getRemainEnemyString(core.floorIds.slice(0, 5));\nif (enemy.length === 0) {\n\tcore.insertAction(['当前无剩余怪物!', { \"type\": \"hide\", \"remove\": true }, ]);\n} else {\n\tcore.insertAction(enemy);\n}\n}" } ] }, diff --git a/public/project/floors/tower5.js b/public/project/floors/tower5.js index f1b1215..170fec6 100644 --- a/public/project/floors/tower5.js +++ b/public/project/floors/tower5.js @@ -21,7 +21,7 @@ main.floors.tower5= "这里是漏怪检测,会检测\r[gold]智慧之塔\r[]区域是否有遗漏怪物", { "type": "function", - "function": "function(){\nconst enemy = core.plugin.remainEnemy.getRemainEnemyString([\"tower1\", \"tower2\", \"tower3\", \"tower4\", \"tower5\", \"tower6\"]);\nif (enemy.length === 0) {\n\tcore.insertAction(['当前无剩余怪物!', { \"type\": \"hide\", \"remove\": true }, ]);\n} else {\n\tcore.insertAction(enemy);\n}\n}" + "function": "function(){\nconst enemy = Mota.Plugin.require('remainEnemy_g').getRemainEnemyString([\"tower1\", \"tower2\", \"tower3\", \"tower4\", \"tower5\", \"tower6\"]);\nif (enemy.length === 0) {\n\tcore.insertAction(['当前无剩余怪物!', { \"type\": \"hide\", \"remove\": true }, ]);\n} else {\n\tcore.insertAction(enemy);\n}\n}" } ] }, diff --git a/public/project/functions.js b/public/project/functions.js index a50de05..fd48fff 100644 --- a/public/project/functions.js +++ b/public/project/functions.js @@ -50,7 +50,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { core.hideStatusBar(core.hasFlag('showToolbox')); else core.showStatusBar(); if (main.mode === 'play' && !main.replayChecking) { - Mota.Plugin.require('fly').splitArea(); + Mota.Plugin.require('fly_r').splitArea(); Mota.require('var', 'hook').emit('reset'); } else { flags.autoSkill ??= true; @@ -113,7 +113,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { // 正在切换楼层过程中执行的操作;此函数的执行时间是“屏幕完全变黑“的那一刻 // floorId为要切换到的楼层ID;heroLoc表示勇士切换到的位置 - const { checkLoopMap } = core.plugin.loopMap; + const { checkLoopMap } = Mota.Plugin.require('loopMap_g'); flags.floorChanging = true; @@ -131,8 +131,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { } // 根据分区信息自动砍层与恢复 - if (core.plugin.removeMap.autoRemoveMaps) - core.plugin.removeMap.autoRemoveMaps(floorId); + Mota.Plugin.require('removeMap_g')?.autoRemoveMaps?.(floorId); // 重置画布尺寸 core.maps.resizeMap(floorId); @@ -201,7 +200,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { } } if (!flags.debug && !main.replayChecking) - Mota.Plugin.require('completion').checkVisitedFloor(); + Mota.Plugin.require('completion_r').checkVisitedFloor(); }, flyTo: function (toId, callback) { // 楼层传送器的使用,从当前楼层飞往toId @@ -279,7 +278,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { version: core.firstData.version, guid: core.getGuid(), time: new Date().getTime(), - skills: core.plugin.skillTree.saveSkillTree() + skills: Mota.Plugin.require('skillTree_g').saveSkillTree() }; return data; @@ -327,7 +326,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { } core.setFlag('__fromLoad__', true); - core.plugin.skillTree.loadSkillTree(data.skills); + Mota.Plugin.require('skillTree_g').loadSkillTree(data.skills); // 切换到对应的楼层 core.changeFloor(data.floorId, null, data.hero.loc, 0, function () { @@ -340,7 +339,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { if (callback) callback(); if (flags.onChase) { - Mota.Plugin.require('chase').startChase(flags.chaseIndex); + Mota.Plugin.require('chase_r').startChase(flags.chaseIndex); if (flags.chaseIndex === 1) { core.playBgm('escape.mp3', 43.5); } @@ -388,7 +387,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { // 2, 将楼层属性中的cannotMoveDirectly这个开关勾上,即禁止在该层楼使用瞬移。 // 3. 将flag:cannotMoveDirectly置为true,即可使用flag控制在某段剧情范围内禁止瞬移。 - const { checkLoopMap } = core.plugin.loopMap; + const { checkLoopMap } = Mota.Plugin.require('loopMap_g'); // 增加步数 core.status.hero.steps++; diff --git a/public/project/items.js b/public/project/items.js index 263c252..388d438 100644 --- a/public/project/items.js +++ b/public/project/items.js @@ -40,8 +40,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "小绿宝石", "text": ",护盾+${core.values.greenGem}", - "itemEffect": "core.status.hero.mdef += 20 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (core.plugin.skillTree.getSkillLevel(12) / 20 + 1)", - "itemEffectTip": ",智慧+${20 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (core.plugin.skillTree.getSkillLevel(12) / 20 + 1)}", + "itemEffect": "core.status.hero.mdef += 20 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1)", + "itemEffectTip": ",智慧+${20 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1)}", "useItemEffect": "core.status.hero.mdef += core.values.greenGem", "canUseItemEffect": "true" }, @@ -97,8 +97,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "红血瓶", "text": ",生命+${core.values.redPotion}", - "itemEffect": "core.status.hero.hp += 100 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)", - "itemEffectTip": ",生命+${100 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)}", + "itemEffect": "core.status.hero.hp += 100 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)", + "itemEffectTip": ",生命+${100 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)}", "useItemEffect": "core.status.hero.hp += core.values.redPotion", "canUseItemEffect": "true" }, @@ -106,8 +106,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "蓝血瓶", "text": ",生命+${core.values.bluePotion}", - "itemEffect": "core.status.hero.hp += 200 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)", - "itemEffectTip": ",生命+${200 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)}", + "itemEffect": "core.status.hero.hp += 200 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)", + "itemEffectTip": ",生命+${200 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)}", "useItemEffect": "core.status.hero.hp += core.values.bluePotion", "canUseItemEffect": "true" }, @@ -115,8 +115,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "黄血瓶", "text": ",生命+${core.values.yellowPotion}", - "itemEffect": "core.status.hero.hp += 400 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)", - "itemEffectTip": ",生命+${400 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)}", + "itemEffect": "core.status.hero.hp += 400 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)", + "itemEffectTip": ",生命+${400 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)}", "useItemEffect": "core.status.hero.hp += core.values.yellowPotion", "canUseItemEffect": "true" }, @@ -124,8 +124,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "绿血瓶", "text": ",生命+${core.values.greenPotion}", - "itemEffect": "core.status.hero.hp += 800 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)", - "itemEffectTip": ",生命+${800 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)}", + "itemEffect": "core.status.hero.hp += 800 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)", + "itemEffectTip": ",生命+${800 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)}", "useItemEffect": "core.status.hero.hp += core.values.greenPotion", "canUseItemEffect": "true" }, @@ -349,7 +349,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "name": "查看技能", "text": "查看勇士的技能", "canUseItemEffect": true, - "useItemEffect": "core.plugin.gameUi.openSkill();" + "useItemEffect": "Mota.Plugin.require('gameUi_g').openSkill();" }, "dagger": { "cls": "constants", @@ -522,7 +522,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "name": "技能树", "text": "打开技能树", "hideInReplay": true, - "useItemEffect": "core.plugin.skillTree.openTree();", + "useItemEffect": "Mota.Plugin.require('skillTree_g').openTree();", "canUseItemEffect": "true" }, "wand": { @@ -626,8 +626,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "中绿宝石", "text": ",护盾+${core.values.greenGem}", - "itemEffect": "core.status.hero.mdef += 40 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (core.plugin.skillTree.getSkillLevel(12) / 20 + 1)", - "itemEffectTip": ",智慧+${40 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (core.plugin.skillTree.getSkillLevel(12) / 20 + 1)}", + "itemEffect": "core.status.hero.mdef += 40 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1)", + "itemEffectTip": ",智慧+${40 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1)}", "useItemEffect": "core.status.hero.mdef += core.values.greenGem", "canUseItemEffect": "true" }, @@ -729,8 +729,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "大绿宝石", "text": ",护盾+${core.values.greenGem}", - "itemEffect": "core.status.hero.mdef += 80 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (core.plugin.skillTree.getSkillLevel(12) / 20 + 1)", - "itemEffectTip": ",智慧+${80 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (core.plugin.skillTree.getSkillLevel(12) / 20 + 1)}", + "itemEffect": "core.status.hero.mdef += 80 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1)", + "itemEffectTip": ",智慧+${80 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1)}", "useItemEffect": "core.status.hero.mdef += core.values.greenGem", "canUseItemEffect": "true" }, @@ -896,8 +896,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "超大绿宝石", "text": ",护盾+${core.values.greenGem}", - "itemEffect": "core.status.hero.mdef += 160 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (core.plugin.skillTree.getSkillLevel(12) / 20 + 1)", - "itemEffectTip": ",智慧+${160 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (core.plugin.skillTree.getSkillLevel(12) / 20 + 1)}", + "itemEffect": "core.status.hero.mdef += 160 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1)", + "itemEffectTip": ",智慧+${160 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1)}", "useItemEffect": "core.status.hero.mdef += core.values.greenGem", "canUseItemEffect": "true" }, @@ -1019,8 +1019,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "璀璨绿宝石", "text": ",护盾+${core.values.greenGem}", - "itemEffect": "core.status.hero.mdef += 320 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (core.plugin.skillTree.getSkillLevel(12) / 20 + 1)", - "itemEffectTip": ",智慧+${320 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (core.plugin.skillTree.getSkillLevel(12) / 20 + 1)}", + "itemEffect": "core.status.hero.mdef += 320 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1)", + "itemEffectTip": ",智慧+${320 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1)}", "useItemEffect": "core.status.hero.mdef += core.values.greenGem", "canUseItemEffect": "true" }, @@ -1050,8 +1050,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "新物品", "text": ",防御+${core.values.blueGem}", - "itemEffect": "core.status.hero.mdef += 640 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (core.plugin.skillTree.getSkillLevel(12) / 20 + 1)", - "itemEffectTip": ",智慧+${640 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (core.plugin.skillTree.getSkillLevel(12) / 20 + 1)}", + "itemEffect": "core.status.hero.mdef += 640 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1)", + "itemEffectTip": ",智慧+${640 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1)}", "useItemEffect": "core.status.hero.def += core.values.blueGem", "canUseItemEffect": "true" }, @@ -1071,8 +1071,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "史诗绿宝石", "text": ",护盾+${core.values.greenGem}", - "itemEffect": "core.status.hero.mdef += 1280 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (core.plugin.skillTree.getSkillLevel(12) / 20 + 1)", - "itemEffectTip": ",智慧+${1280 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (core.plugin.skillTree.getSkillLevel(12) / 20 + 1)}", + "itemEffect": "core.status.hero.mdef += 1280 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1)", + "itemEffectTip": ",智慧+${1280 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1)}", "useItemEffect": "core.status.hero.mdef += core.values.greenGem", "canUseItemEffect": "true" }, @@ -1100,8 +1100,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "大红血瓶", "text": ",生命+${core.values.redPotion}", - "itemEffect": "core.status.hero.hp += 1000 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)", - "itemEffectTip": ",生命+${1000 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)}", + "itemEffect": "core.status.hero.hp += 1000 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)", + "itemEffectTip": ",生命+${1000 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)}", "useItemEffect": "core.status.hero.hp += core.values.redPotion", "canUseItemEffect": "true" }, @@ -1113,8 +1113,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "大蓝血瓶", "text": ",生命+${core.values.redPotion}", - "itemEffect": "core.status.hero.hp += 2000 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)", - "itemEffectTip": ",生命+${2000 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)}", + "itemEffect": "core.status.hero.hp += 2000 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)", + "itemEffectTip": ",生命+${2000 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)}", "useItemEffect": "core.status.hero.hp += core.values.redPotion", "canUseItemEffect": "true" }, @@ -1130,8 +1130,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "大绿血瓶", "text": ",生命+${core.values.redPotion}", - "itemEffect": "core.status.hero.hp += 8000 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)", - "itemEffectTip": ",生命+${8000 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)}", + "itemEffect": "core.status.hero.hp += 8000 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)", + "itemEffectTip": ",生命+${8000 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)}", "useItemEffect": "core.status.hero.hp += core.values.redPotion", "canUseItemEffect": "true" }, @@ -1151,8 +1151,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "items", "name": "大黄血瓶", "text": ",生命+${core.values.redPotion}", - "itemEffect": "core.status.hero.hp += 4000 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)", - "itemEffectTip": ",生命+${4000 * core.status.thisMap.ratio * (1 + core.plugin.skillTree.getSkillLevel(13) / 50)}", + "itemEffect": "core.status.hero.hp += 4000 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)", + "itemEffectTip": ",生命+${4000 * core.status.thisMap.ratio * (1 + Mota.Plugin.require('skillTree_g').getSkillLevel(13) / 50)}", "useItemEffect": "core.status.hero.hp += core.values.redPotion", "canUseItemEffect": "true" }, @@ -1181,7 +1181,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "constants", "name": "学习", "canUseItemEffect": "true", - "text": "可以学习怪物的技能,学习后持续${core.plugin.skillTree.getSkillLevel(11) * 3 + 2}场战斗" + "text": "可以学习怪物的技能,学习后持续${Mota.Plugin.require('skillTree_g').getSkillLevel(11) * 3 + 2}场战斗" }, "I574": { "cls": "items", diff --git a/src/core/index.ts b/src/core/index.ts index 458c7ed..00ec4d3 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -19,28 +19,31 @@ import { gameKey } from './main/init/hotkey'; import { mainSetting, settingStorage } from './main/setting'; import { isMobile } from '../plugin/use'; import { KeyCode } from '@/plugin/keyCodes'; +import { status } from '@/plugin/ui/statusBar'; +import './plugin'; +import './package'; -interface AncTePlugin { - pop: ReturnType; - use: ReturnType; - animate: ReturnType; - utils: ReturnType; - status: ReturnType; - fly: ReturnType; - chase: ReturnType; - webglUtils: ReturnType; - shadow: ReturnType; - gameShadow: ReturnType< - typeof import('../plugin/shadow/gameShadow').default - >; - achievement: ReturnType; - completion: ReturnType; - path: ReturnType; - gameCanvas: ReturnType; - noise: ReturnType; - smooth: ReturnType; - frag: ReturnType; -} +// interface AncTePlugin { +// pop: ReturnType; +// use: ReturnType; +// animate: ReturnType; +// utils: ReturnType; +// status: ReturnType; +// fly: ReturnType; +// chase: ReturnType; +// webglUtils: ReturnType; +// shadow: ReturnType; +// gameShadow: ReturnType< +// typeof import('../plugin/shadow/gameShadow').default +// >; +// achievement: ReturnType; +// completion: ReturnType; +// path: ReturnType; +// gameCanvas: ReturnType; +// noise: ReturnType; +// smooth: ReturnType; +// frag: ReturnType; +// } // export interface Mota { // sound: SoundController; @@ -93,3 +96,4 @@ Mota.register('var', 'KeyCode', KeyCode); Mota.register('var', 'resource', resource); Mota.register('var', 'zipResource', zipResource); Mota.register('var', 'settingStorage', settingStorage); +Mota.register('var', 'status', status); diff --git a/src/core/main/init/fixed.ts b/src/core/main/init/fixed.ts index 2f8ba9d..163beb2 100644 --- a/src/core/main/init/fixed.ts +++ b/src/core/main/init/fixed.ts @@ -16,6 +16,7 @@ const showFixed = debounce((block: Block) => { const e = core.material.enemys[block.event.id as EnemyIds]; if (!e) return; const enemy = core.status.thisMap.enemy.get(block.x, block.y); + if (!enemy) return; fixedUi.open( 'fixed', { enemy, close, loc: [cx, cy] }, diff --git a/src/core/package.ts b/src/core/package.ts new file mode 100644 index 0000000..4b354e7 --- /dev/null +++ b/src/core/package.ts @@ -0,0 +1,15 @@ +import * as axios from 'axios'; +import * as chart from 'chart.js'; +import jszip from 'jszip'; +import * as lodash from 'lodash-es'; +import * as lzstring from 'lz-string'; +import * as animate from 'mutate-animate'; +import * as vue from 'vue'; + +Mota.Package.register('axios', axios); +Mota.Package.register('chart.js', chart); +Mota.Package.register('jszip', jszip); +Mota.Package.register('lodash', lodash); +Mota.Package.register('lz-string', lzstring); +Mota.Package.register('mutate-animate', animate); +Mota.Package.register('vue', vue); diff --git a/src/core/plugin.ts b/src/core/plugin.ts index 3ec5582..aba958a 100644 --- a/src/core/plugin.ts +++ b/src/core/plugin.ts @@ -17,21 +17,32 @@ // import frag from '@/plugin/fx/frag'; // import { Mota } from '.'; +import * as shadow from '@/plugin/shadow/shadow'; import * as gameShadow from '@/plugin/shadow/gameShadow'; import * as fly from '@/plugin/ui/fly'; import * as chase from '@/plugin/chase/chase'; import * as completion from '@/plugin/completion'; import * as pop from '@/plugin/pop'; -import * as status from '@/plugin/ui/statusBar'; import * as frag from '@/plugin/fx/frag'; +import * as use from '@/plugin/use'; +import * as gameCanvas from '@/plugin/fx/gameCanvas'; +import * as smooth from '@/plugin/fx/smoothView'; +import { loading } from './loader/load'; -Mota.Plugin.register('gameShadow', gameShadow, gameShadow.init); -Mota.Plugin.register('fly', fly); -Mota.Plugin.register('chase', chase); -Mota.Plugin.register('completion', completion); -Mota.Plugin.register('pop', pop, pop.init); -Mota.Plugin.register('status', status); // todo: 改成系统变量,而非插件 -Mota.Plugin.register('frag', frag, frag.init); +Mota.Plugin.register('shadow_r', shadow, shadow.init); +Mota.Plugin.register('gameShadow_r', gameShadow, gameShadow.init); +Mota.Plugin.register('fly_r', fly); +Mota.Plugin.register('chase_r', chase); +Mota.Plugin.register('completion_r', completion); +Mota.Plugin.register('pop_r', pop, pop.init); +Mota.Plugin.register('frag_r', frag, frag.init); +Mota.Plugin.register('use_r', use); +Mota.Plugin.register('gameCanvas_r', gameCanvas); +Mota.Plugin.register('smooth_r', smooth, smooth.init); + +loading.once('coreInit', () => { + Mota.Plugin.init(); +}); // // todo: 将插件更改为注册形式,分为渲染进程和游戏进程两部分,同时分配优先级 diff --git a/src/data/desc.json b/src/data/desc.json index 4fe36fb..286b79b 100644 --- a/src/data/desc.json +++ b/src/data/desc.json @@ -483,14 +483,14 @@ }, "study": { "text": "学习", - "condition": "core.plugin.skillTree.getSkillLevel(11) > 0", + "condition": "Mota.Plugin.require('skillTree_g').getSkillLevel(11) > 0", "desc": [ "本条目会详细说明学习的机制与所有可以被学习的技能被学习后的效果。当前已经学习的技能会以与状态栏类似的盒子展示出来。", "
", "
", "首先,学习技能消耗的智慧点会越来越多,初始消耗的智慧点为500,每学习一次增加250。", "学习的技能可以持续5场战斗,在技能树界面每升级一次增加3场,", - "当前为${core.plugin.skillTree.getSkillLevel(11) * 3 + 2}场。", + "当前为${Mota.Plugin.require('skillTree_g').getSkillLevel(11) * 3 + 2}场。", "学习后对应属性的值,例如抱团怪增加的属性百分比,会与被学习的怪物相同。学习界面可以使用背包中的道具或点击状态栏打开。", "
", "
", diff --git a/src/data/skill.json b/src/data/skill.json index 312cec5..7bab032 100644 --- a/src/data/skill.json +++ b/src/data/skill.json @@ -8,7 +8,7 @@ }, "blade": { "text": "1:断灭之刃", - "opened": "core.plugin.skillTree.getSkillLevel(2) > 0", + "opened": "Mota.Plugin.require('skillTree_g').getSkillLevel(2) > 0", "desc": [ "快捷键1,开启后勇士攻击增加${level:2 * 10}%,", "同时防御减少${level:2 * 10}%。", @@ -31,7 +31,7 @@ }, "shield": { "text": "3:铸剑为盾", - "opened": "core.plugin.skillTree.getSkillLevel(10) > 0", + "opened": "Mota.Plugin.require('skillTree_g').getSkillLevel(10) > 0", "desc": [ "快捷键3,开启后勇士防御增加${level:10 * 10}%,", "同时攻击减少${level:10 * 10}%。", diff --git a/src/game/index.ts b/src/game/index.ts index da933d9..fb59fb5 100644 --- a/src/game/index.ts +++ b/src/game/index.ts @@ -1 +1,2 @@ import './system'; +import '../plugin/game/index'; diff --git a/src/game/system.ts b/src/game/system.ts index 392ed67..706f24a 100644 --- a/src/game/system.ts +++ b/src/game/system.ts @@ -25,9 +25,10 @@ import type { } from '@/core/main/setting'; import type { GameStorage } from '@/core/main/storage'; import type { DamageEnemy, EnemyCollection } from '@/plugin/game/enemy/damage'; -import type { enemySpecials } from '@/plugin/game/enemy/special'; +import type { specials } from '@/plugin/game/enemy/special'; import type { Range } from '@/plugin/game/range'; import type { KeyCode } from '@/plugin/keyCodes'; +import type { Ref } from 'vue'; interface ClassInterface { // 渲染进程与游戏进程通用 @@ -82,9 +83,10 @@ interface VariableInterface { resource: ResourceStore>; zipResource: ResourceStore<'zip'>; settingStorage: GameStorage; + status: Ref; // 定义于游戏进程,渲染进程依然可用 haloSpecials: number[]; - enemySpecials: typeof enemySpecials; + enemySpecials: typeof specials; } interface SystemInterfaceMap { @@ -95,12 +97,67 @@ interface SystemInterfaceMap { type InterfaceType = keyof SystemInterfaceMap; -interface PluginInterface {} +interface PluginInterface { + // 渲染进程定义的插件 + pop_r: typeof import('../plugin/pop'); + use_r: typeof import('../plugin/use'); + // animate: typeof import('../plugin/animateController'); + // utils: typeof import('../plugin/utils'); + // status: typeof import('../plugin/ui/statusBar'); + fly_r: typeof import('../plugin/ui/fly'); + chase_r: typeof import('../plugin/chase/chase'); + // webglUtils: typeof import('../plugin/webgl/utils'); + shadow_r: typeof import('../plugin/shadow/shadow'); + gameShadow_r: typeof import('../plugin/shadow/gameShadow'); + // achievement: typeof import('../plugin/ui/achievement'); + completion_r: typeof import('../plugin/completion'); + // path: typeof import('../plugin/fx/path'); + gameCanvas_r: typeof import('../plugin/fx/gameCanvas'); + // noise: typeof import('../plugin/fx/noise'); + smooth_r: typeof import('../plugin/fx/smoothView'); + frag_r: typeof import('../plugin/fx/frag'); + // 游戏进程定义的插件 + utils_g: typeof import('../plugin/game/utils'); + loopMap_g: typeof import('../plugin/game/loopMap'); + shop_g: typeof import('../plugin/game/shop'); + replay_g: typeof import('../plugin/game/replay'); + skillTree_g: typeof import('../plugin/game/skillTree'); + removeMap_g: typeof import('../plugin/game/removeMap'); + remainEnemy_g: typeof import('../plugin/game/enemy/remainEnemy'); + chase_g: typeof import('../plugin/game/chase'); + skill_g: typeof import('../plugin/game/skill'); + towerBoss_g: typeof import('../plugin/game/towerBoss'); + heroFourFrames_g: typeof import('../plugin/game/fx/heroFourFrames'); + rewrite_g: typeof import('../plugin/game/fx/rewrite'); + itemDetail_g: typeof import('../plugin/game/fx/itemDetail'); + checkBlock_g: typeof import('../plugin/game/enemy/checkblock'); + halo_g: typeof import('../plugin/game/fx/halo'); + study_g: typeof import('../plugin/game/study'); +} + +interface PackageInterface { + axios: typeof import('axios'); + 'chart.js': typeof import('chart.js'); + jszip: typeof import('jszip'); + lodash: typeof import('lodash-es'); + 'lz-string': typeof import('lz-string'); + 'mutate-animate': typeof import('mutate-animate'); + vue: typeof import('vue'); +} export interface IMota { rewrite: typeof rewrite; + r: typeof r; + rf: typeof rf; + /** 样板插件接口 */ Plugin: IPlugin; + /** + * 样板使用的第三方库接口,可以直接获取到库的原有接口。 + * 接口在渲染进程中引入,在游戏进程中不会polyfill,因此在游戏进程中使用时, + * 应先使用main.replayChecking进行检查,保证该值不存在时才进行使用,否则会引起录像出错 + */ + Package: IPackage; /** * 获取一个样板接口 @@ -145,15 +202,12 @@ export interface IMota { } export interface IPlugin { + inited: boolean; + /** * 初始化所有插件 */ init(): void; - /** - * 初始化指定插件 - * @param plugin 要初始化的插件 - */ - init(plugin: string): void; /** * 获取到一个插件的内容 @@ -169,7 +223,7 @@ export interface IPlugin { /** * 获取所有插件 */ - requireAll(): PluginInterface; + requireAll(): PluginInterface & { [x: string]: any }; /** * 注册一个插件 @@ -210,6 +264,24 @@ export interface IPlugin { register(plugin: K, init: (plugin: K) => any): void; } +export interface IPackage { + /** + * 获取样板使用的第三方库 + * @param name 要获取的第三方库 + */ + require(name: K): PackageInterface[K]; + + /** + * 获取样板使用的所有第三方库 + */ + requireAll(): PackageInterface; + + register( + name: K, + data: PackageInterface[K] + ): void; +} + interface IPluginData { /** 插件类型,content表示直接注册了内容,function表示注册了初始化函数,内容从其返回值获取 */ type: 'content' | 'function'; @@ -219,8 +291,8 @@ interface IPluginData { class MPlugin { private static plugins: Record = {}; - private static inited = false; private static pluginData: Record = {}; + static inited = false; constructor() { throw new Error(`System plugin class cannot be constructed.`); @@ -248,8 +320,8 @@ class MPlugin { return this.plugins[key].data; } - static requireAll() { - return this.pluginData; + static requireAll(): PluginInterface { + return this.pluginData as PluginInterface; } static register(key: string, data: any, init?: any) { @@ -269,6 +341,32 @@ class MPlugin { } } +class MPackage { + // @ts-ignore + private static packages: PackageInterface = {}; + + constructor() { + throw new Error(`System package class cannot be constructed.`); + } + + static require( + name: K + ): PackageInterface[K] { + return this.packages[name]; + } + + static requireAll() { + return this.packages; + } + + static register( + name: K, + data: PackageInterface[K] + ) { + this.packages[name] = data; + } +} + /** * 样板接口系统,通过 Mota 获取到样板的核心功能,不可实例化 */ @@ -278,7 +376,10 @@ class Mota { private static variables: Record = {}; static rewrite = rewrite; + static r = r; + static rf = rf; static Plugin = MPlugin; + static Package = MPackage; constructor() { throw new Error(`System interface class cannot be constructed.`); @@ -330,11 +431,19 @@ type _Func = (...params: any) => any; * @param bind 原函数的调用对象,默认为base * @param rebind 复写函数的调用对象,默认为base */ -function rewrite, T = O>( +function rewrite< + O, + K extends SelectKey, + R extends 'full' | 'front', + T = O +>( base: O, key: K, - type: 'full' | 'front', - re: (this: T, ...params: [..._F[0], ...any[]]) => _F[1], + type: R, + re: ( + this: T, + ...params: [..._F[0], ...any[]] + ) => R extends 'full' ? _F[1] : void, bind?: any, rebind?: T ): (this: T, ...params: [..._F[0], ...any[]]) => _F[1]; @@ -345,8 +454,8 @@ function rewrite, T = O>( * @param type 复写类型,add表示在函数后追加 * @param re 复写函数,类型为add时表示在原函数后面追加复写函数,会在第一个参数中传入原函数的返回值, * 并要求复写函数必须有返回值,作为复写的最终返回值。 - * @param bind 原函数的调用对象,默认为base - * @param rebind 复写函数的调用对象,默认为base + * @param bind 原函数的调用对象,默认为`base` + * @param rebind 复写函数的调用对象,默认为`base` */ function rewrite, T = O>( base: O, @@ -390,7 +499,7 @@ function rewrite, T = O>( const origin = base[key]; function res(this: T, ...params: [..._F[0], ...any[]]) { // @ts-ignore - re.call(rebind ?? base, v, ...params); + re.call(rebind ?? base, ...params); const ret = (origin as _Func).call(bind ?? base, ...params); return ret; } @@ -399,6 +508,43 @@ function rewrite, T = O>( } } +/** + * 在渲染进程包裹下执行一段代码,该段代码不会在录像验证中执行,因此里面的内容一定不会引起录像报错 + * 一般特效,或者是ui显示、内容显示、交互监听等内容应当在渲染进程包裹下执行 + * @param fn 要执行的函数,传入一个参数,表示所有的第三方库,也就是`Mota.Package.requireAll()`的内容 + * @param thisArg 函数的执行上下文,即函数中`this`指向 + */ +function r( + fn: (this: T, packages: PackageInterface) => void, + thisArg?: T +) { + if (!main.replayChecking) fn.call(thisArg as T, MPackage.requireAll()); +} + +/** + * 将一个函数包裹成渲染进程函数,执行这个函数时将直接在渲染进程下执行。该函数与 {@link r} 函数的关系, + * 与`call`和`bind`的关系类似。 + * ```ts + * const fn = rf((x) => x * x); + * console.log(fn(2)); // 在正常游玩中会输出 4,但是录像验证中会输出undefined,因为录像验证中不会执行渲染进程函数 + * ``` + * @param fn 要执行的函数 + * @param thisArg 函数执行时的上下文,即this指向 + * @returns 经过渲染进程包裹的函数,直接调用即是在渲染进程下执行的 + */ +function rf any, T>( + fn: F, + thisArg?: T +): (this: T, ...params: Parameters) => ReturnType | undefined { + // @ts-ignore + if (main.replayChecking) return () => {}; + else { + return (...params) => { + return fn.call(thisArg, ...params); + }; + } +} + declare global { interface Window { Mota: IMota; diff --git a/src/plugin/chase/chase1.ts b/src/plugin/chase/chase1.ts index 7b2c3e7..bfed89b 100644 --- a/src/plugin/chase/chase1.ts +++ b/src/plugin/chase/chase1.ts @@ -123,7 +123,7 @@ export const camera1: ChaseCameraData[] = [ * 追逐战开始前的初始化函数,移除所有血瓶和门等 */ export function init1() { - return core.plugin.chase.chaseInit1(); + return Mota.Plugin.require('chase_g').chaseInit1(); } export function chaseShake(chase: Chase) { @@ -561,7 +561,7 @@ export function para3(chase: Chase) { 'MT14', async () => { flags.finishChase1 = true; - core.plugin.replay.clip('choices:0'); + Mota.Plugin.require('replay_g').clip('choices:0'); core.showStatusBar(); ani.time(750).apply('rect', 0); chase.end(); diff --git a/src/plugin/completion.ts b/src/plugin/completion.ts index 00a47a6..6e80b07 100644 --- a/src/plugin/completion.ts +++ b/src/plugin/completion.ts @@ -5,6 +5,7 @@ import { } from './ui/achievement'; import { changeLocalStorage } from './utils'; import list from '../data/achievement.json'; +import { loading } from '@/core/loader/load'; export const floors: Record = { 1: ['MT0', 'tower7'] @@ -21,6 +22,15 @@ export const achiDict: Record = { 1: 0 }; +loading.once('coreInit', () => { + Object.values(floors).forEach((v, i) => { + const from = core.floorIds.indexOf(v[0]); + const to = core.floorIds.indexOf(v[1]); + const all = core.floorIds.slice(from, to + 1); + floors[i + 1] = all; + }); +}); + /** * 检查所有到达过的楼层,用于成就的计算 */ diff --git a/src/plugin/fx/smoothView.ts b/src/plugin/fx/smoothView.ts index b663c7c..e701649 100644 --- a/src/plugin/fx/smoothView.ts +++ b/src/plugin/fx/smoothView.ts @@ -7,7 +7,9 @@ tran.value.y = 0; let needSmooth = false; -export default function init() { +export function init() { + const setting = Mota.require('var', 'mainSetting'); + tran.ticker.add(() => { if (core.isPlaying() && needSmooth) { core.setViewport(tran.value.x, tran.value.y); @@ -18,50 +20,47 @@ export default function init() { needSmooth = false; }, 700); - control.prototype._drawHero_updateViewport = function ( - x: number, - y: number, - offset: Loc - ) { - const ox = core.clamp( - (x - core._HALF_WIDTH_) * 32 + offset.x, - 0, - Math.max(32 * core.bigmap.width - core._PX_, 0) - ); - const oy = core.clamp( - (y - core._HALF_HEIGHT_) * 32 + offset.y, - 0, - Math.max(32 * core.bigmap.height - core._PY_, 0) - ); + Mota.rewrite( + core.control, + '_drawHero_updateViewport', + 'full', + (x, y, offset) => { + const ox = core.clamp( + (x - core._HALF_WIDTH_) * 32 + offset.x, + 0, + Math.max(32 * core.bigmap.width - core._PX_, 0) + ); + const oy = core.clamp( + (y - core._HALF_HEIGHT_) * 32 + offset.y, + 0, + Math.max(32 * core.bigmap.height - core._PY_, 0) + ); - tran.transition('x', ox).transition('y', oy); + tran.transition('x', ox).transition('y', oy); - if (tran.easeTime > 0) { - needSmooth = true; - func(); - } else { - core.setViewport(tran.value.x, tran.value.y); + const t = setting.getValue('screen.smoothView', false); + if (!t) return; + if (tran.easeTime > 0) { + needSmooth = true; + func(); + } else { + core.setViewport(tran.value.x, tran.value.y); + } } - }; + ); + const hso = hyper('sin', 'out'); let time2 = Date.now(); - const origin1 = control.prototype._moveAction_moving; - control.prototype._moveAction_moving = function (...params: any[]) { - if (Date.now() - time2 > 20) - tran.mode(hyper('sin', 'out')).time(200).absolute(); - return origin1.call(this, ...params); - }; - - const origin2 = control.prototype.moveDirectly; - control.prototype.moveDirectly = function (...params: any[]) { + Mota.rewrite(core.control, '_moveAction_moving', 'front', () => { + const t = setting.getValue('screen.smoothView', false) ? 200 : 1; + if (Date.now() - time2 > 20) tran.mode(hso).time(t).absolute(); + }); + Mota.rewrite(core.control, 'moveDirectly', 'front', () => { + const t = setting.getValue('screen.smoothView', false) ? 600 : 1; time2 = Date.now(); - tran.mode(hyper('sin', 'out')).time(600).absolute(); - return origin2.call(this, ...params); - }; - - const origin3 = events.prototype._changeFloor_beforeChange; - events.prototype._changeFloor_beforeChange = function (...params: any[]) { + tran.mode(hso).time(t).absolute(); + }); + Mota.rewrite(core.events, '_changeFloor_beforeChange', 'front', () => { tran.time(1).absolute(); - return origin3.call(this, ...params); - }; + }); } diff --git a/src/plugin/game/chase.js b/src/plugin/game/chase.ts similarity index 81% rename from src/plugin/game/chase.js rename to src/plugin/game/chase.ts index 5f81107..36cf8c3 100644 --- a/src/plugin/game/chase.js +++ b/src/plugin/game/chase.ts @@ -1,6 +1,6 @@ export function chaseInit1() { - const ids = ['MT13', 'MT14', 'MT15']; - const toRemove = []; + const ids: FloorIds[] = ['MT13', 'MT14', 'MT15']; + const toRemove: [number, number, FloorIds][] = []; ids.forEach(v => { core.status.maps[v].cannotMoveDirectly = true; core.extractBlocks(v); @@ -17,7 +17,3 @@ export function chaseInit1() { core.removeBlock(...v); }); } - -core.plugin.chase = { - chaseInit1 -}; diff --git a/src/plugin/game/enemy/battle.ts b/src/plugin/game/enemy/battle.ts index bf62765..a453bf6 100644 --- a/src/plugin/game/enemy/battle.ts +++ b/src/plugin/game/enemy/battle.ts @@ -22,232 +22,224 @@ export function getEnemy( return enemy; } -core.enemys.canBattle = function ( - x: number, - y: number, - floorId: FloorIds = core.status.floorId -) { - const enemy = getEnemy(x, y, floorId); - const { damage } = enemy.calDamage(); - return damage < core.status.hero.hp; -}; +export function init() { + core.enemys.canBattle = function ( + x: number, + y: number, + floorId: FloorIds = core.status.floorId + ) { + const enemy = getEnemy(x, y, floorId); + const { damage } = enemy.calDamage(); + return damage < core.status.hero.hp; + }; -core.events.battle = function ( - x: number, - y: number, - force: boolean = false, - callback?: () => void -) { - core.saveAndStopAutomaticRoute(); - const enemy = getEnemy(x, y); - // 非强制战斗 - if (!core.enemys.canBattle(x, y) && !force && !core.status.event.id) { - core.stopSound(); - core.playSound('操作失败'); - core.drawTip('你打不过此怪物!', enemy.id); - return core.clearContinueAutomaticRoute(callback); - } - // 自动存档 - if (!core.status.event.id) core.autosave(true); - // 战前事件 - if (!this.beforeBattle(enemy, x, y)) - return core.clearContinueAutomaticRoute(callback); - // 战后事件 - this.afterBattle(enemy, x, y); - callback?.(); -}; - -core.events.beforeBattle = function () { - return true; -}; - -core.events.afterBattle = function ( - enemy: DamageEnemy, - x?: number, - y?: number -) { - const floorId = core.status.floorId; - const special = enemy.info.special; - - // 播放战斗动画 - let animate: AnimationIds = 'hand'; - // 检查当前装备是否存在攻击动画 - const equipId = core.getEquip(0); - if (equipId && (core.material.items[equipId].equip || {}).animate) - animate = core.material.items[equipId].equip.animate; - - // 检查该动画是否存在SE,如果不存在则使用默认音效 - if (!core.material.animates[animate]?.se) core.playSound('attack.mp3'); - - // 战斗伤害 - const info = enemy.calDamage(core.status.hero); - const damage = info.damage; - // 判定是否致死 - if (damage >= core.status.hero.hp) { - core.status.hero.hp = 0; - core.updateStatusBar(false, true); - core.events.lose('战斗失败'); - return; - } - - // 扣减体力值并记录统计数据 - core.status.hero.hp -= damage; - core.status.hero.statistics.battleDamage += damage; - core.status.hero.statistics.battle++; - - // 智慧之源 - if (special.includes(14) && flags.hard === 2) { - core.addFlag( - 'inte_' + floorId, - Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10 - ); - core.status.hero.mdef -= - Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10; - } - - // 极昼永夜 - if (special.includes(22)) { - flags[`night_${floorId}`] ??= 0; - flags[`night_${floorId}`] -= enemy.enemy.night!; - } - if (special.includes(23)) { - flags[`night_${floorId}`] ??= 0; - flags[`night_${floorId}`] += enemy.enemy.day; - } - - // if (core.plugin.skillTree.getSkillLevel(11) > 0) { - // core.plugin.study.declineStudiedSkill(); - // } - - // 如果是融化怪,需要特殊标记一下 - if (special.includes(25) && core.has(x) && core.has(y)) { - flags[`melt_${floorId}`] ??= {}; - flags[`melt_${floorId}`][`${x},${y}`] = enemy.enemy.melt; - } - - // 获得金币 - const money = enemy.enemy.money; - core.status.hero.money += money; - core.status.hero.statistics.money += money; - - // 获得经验 - const exp = enemy.enemy.exp; - core.status.hero.exp += exp; - core.status.hero.statistics.exp += exp; - - const hint = - '打败 ' + enemy.enemy.name + ',金币+' + money + ',经验+' + exp; - core.drawTip(hint, enemy.id); - - if (core.getFlag('bladeOn') && core.getFlag('blade')) { - core.setFlag('blade', false); - } - if (core.getFlag('shieldOn') && core.getFlag('shield')) { - core.setFlag('shield', false); - } - - // 事件的处理 - const todo: MotaEvent = []; - - // 战后事件 - if (has(core.status.floorId)) { - const loc = `${x},${y}` as LocString; - todo.push(...(core.floors[core.status.floorId].afterBattle[loc] ?? [])); - } - todo.push(...(enemy.enemy.afterBattle ?? [])); - - // 如果事件不为空,将其插入 - if (todo.length > 0) core.insertAction(todo, x, y); - - if (has(x) && has(y)) { - core.drawAnimate(animate, x, y); - core.removeBlock(x, y); - } else core.drawHeroAnimate(animate); - - // 如果已有事件正在处理中 - if (core.status.event.id == null) core.continueAutomaticRoute(); - else core.clearContinueAutomaticRoute(); -}; - -core.events._sys_battle = function (data: Block, callback?: () => void) { - // 检查战前事件 - const floor = core.floors[core.status.floorId]; - const beforeBattle: MotaEvent = []; - const loc = `${data.x},${data.y}` as LocString; - const enemy = getEnemy(data.x, data.y); - - beforeBattle.push(...(floor.beforeBattle[loc] ?? [])); - beforeBattle.push(...(enemy.enemy.beforeBattle ?? [])); - - if (beforeBattle.length > 0) { - beforeBattle.push({ type: 'battle', x: data.x, y: data.y }); - core.clearContinueAutomaticRoute(); - - // 自动存档 - var inAction = core.status.event.id == 'action'; - if (inAction) { - core.insertAction(beforeBattle, data.x, data.y); - core.doAction(); - } else { - core.autosave(true); - core.insertAction(beforeBattle, data.x, data.y, callback); + core.events.battle = function ( + x: number, + y: number, + force: boolean = false, + callback?: () => void + ) { + core.saveAndStopAutomaticRoute(); + const enemy = getEnemy(x, y); + // 非强制战斗 + if (!core.enemys.canBattle(x, y) && !force && !core.status.event.id) { + core.stopSound(); + core.playSound('操作失败'); + core.drawTip('你打不过此怪物!', enemy.id); + return core.clearContinueAutomaticRoute(callback); } - } else { - this.battle(data.x, data.y, false, callback); - } -}; + // 自动存档 + if (!core.status.event.id) core.autosave(true); + // 战前事件 + // 战后事件 + this.afterBattle(enemy, x, y); + callback?.(); + }; -core.events._action_battle = function (data, x, y, prefix) { - if (data.id) { - const enemy = getSingleEnemy(data.id as EnemyIds); - // todo: 与不在地图上的怪物战斗 - } else { - if (data.floorId != core.status.floorId) { - core.doAction(); + core.events.afterBattle = function ( + enemy: DamageEnemy, + x?: number, + y?: number + ) { + const floorId = core.status.floorId; + const special = enemy.info.special; + + // 播放战斗动画 + let animate: AnimationIds = 'hand'; + // 检查当前装备是否存在攻击动画 + const equipId = core.getEquip(0); + if (equipId && (core.material.items[equipId].equip || {}).animate) + animate = core.material.items[equipId].equip.animate; + + // 检查该动画是否存在SE,如果不存在则使用默认音效 + if (!core.material.animates[animate]?.se) core.playSound('attack.mp3'); + + // 战斗伤害 + const info = enemy.calDamage(core.status.hero); + const damage = info.damage; + // 判定是否致死 + if (damage >= core.status.hero.hp) { + core.status.hero.hp = 0; + core.updateStatusBar(false, true); + core.events.lose('战斗失败'); return; } - const [ex, ey] = this.__action_getLoc(data.loc, x, y, prefix) as LocArr; - this.battle(ex, ey, true, core.doAction); - } -}; -core.enemys.getCurrentEnemys = function (floorId = core.status.floorId) { - floorId = floorId || core.status.floorId; - const enemys: CurrentEnemy[] = []; - const used: Record = {}; - ensureFloorDamage(floorId); - const floor = core.status.maps[floorId]; - floor.enemy.list.forEach(v => { - if (!(v.id in used)) { - const e = new DamageEnemy(v.enemy); - e.calAttribute(); - e.getRealInfo(); - e.calDamage(); - const curr: CurrentEnemy = { - enemy: e, - onMapEnemy: [v] - }; - enemys.push(curr); - used[v.id] = curr.onMapEnemy; - } else { - used[v.id].push(v); + // 扣减体力值并记录统计数据 + core.status.hero.hp -= damage; + core.status.hero.statistics.battleDamage += damage; + core.status.hero.statistics.battle++; + + // 智慧之源 + if (special.includes(14) && flags.hard === 2) { + core.addFlag( + 'inte_' + floorId, + Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10 + ); + core.status.hero.mdef -= + Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10; } - }); - return enemys.sort((a, b) => { - const ad = a.enemy.calDamage().damage; - const bd = b.enemy.calDamage().damage; - return ad - bd; - }); -}; + // 极昼永夜 + if (special.includes(22)) { + flags[`night_${floorId}`] ??= 0; + flags[`night_${floorId}`] -= enemy.enemy.night!; + } + if (special.includes(23)) { + flags[`night_${floorId}`] ??= 0; + flags[`night_${floorId}`] += enemy.enemy.day; + } -declare global { - interface Events { - beforeBattle(enemy: DamageEnemy, x: number, y: number): boolean; - afterBattle(enemy: DamageEnemy, x: number, y: number): void; - } + // if (core.plugin.skillTree.getSkillLevel(11) > 0) { + // core.plugin.study.declineStudiedSkill(); + // } - interface Enemys { - getCurrentEnemys(floorId?: FloorIds): CurrentEnemy[]; - } + // 如果是融化怪,需要特殊标记一下 + if (special.includes(25) && has(x) && has(y)) { + flags[`melt_${floorId}`] ??= {}; + flags[`melt_${floorId}`][`${x},${y}`] = enemy.enemy.melt; + } + + // 获得金币 + const money = enemy.enemy.money; + core.status.hero.money += money; + core.status.hero.statistics.money += money; + + // 获得经验 + const exp = enemy.enemy.exp; + core.status.hero.exp += exp; + core.status.hero.statistics.exp += exp; + + const hint = + '打败 ' + enemy.enemy.name + ',金币+' + money + ',经验+' + exp; + core.drawTip(hint, enemy.id); + + if (core.getFlag('bladeOn') && core.getFlag('blade')) { + core.setFlag('blade', false); + } + if (core.getFlag('shieldOn') && core.getFlag('shield')) { + core.setFlag('shield', false); + } + + // 事件的处理 + const todo: MotaEvent = []; + + // 战后事件 + if (has(core.status.floorId)) { + const loc = `${x},${y}` as LocString; + todo.push( + ...(core.floors[core.status.floorId].afterBattle[loc] ?? []) + ); + } + todo.push(...(enemy.enemy.afterBattle ?? [])); + + // 如果事件不为空,将其插入 + if (todo.length > 0) core.insertAction(todo, x, y); + + if (has(x) && has(y)) { + core.drawAnimate(animate, x, y); + core.removeBlock(x, y); + } else core.drawHeroAnimate(animate); + + // 如果已有事件正在处理中 + if (core.status.event.id == null) core.continueAutomaticRoute(); + else core.clearContinueAutomaticRoute(); + }; + + core.events._sys_battle = function (data: Block, callback?: () => void) { + // 检查战前事件 + const floor = core.floors[core.status.floorId]; + const beforeBattle: MotaEvent = []; + const loc = `${data.x},${data.y}` as LocString; + const enemy = getEnemy(data.x, data.y); + + beforeBattle.push(...(floor.beforeBattle[loc] ?? [])); + beforeBattle.push(...(enemy.enemy.beforeBattle ?? [])); + + if (beforeBattle.length > 0) { + beforeBattle.push({ type: 'battle', x: data.x, y: data.y }); + core.clearContinueAutomaticRoute(); + + // 自动存档 + var inAction = core.status.event.id == 'action'; + if (inAction) { + core.insertAction(beforeBattle, data.x, data.y); + core.doAction(); + } else { + core.autosave(true); + core.insertAction(beforeBattle, data.x, data.y, callback); + } + } else { + this.battle(data.x, data.y, false, callback); + } + }; + + core.events._action_battle = function (data, x, y, prefix) { + if (data.id) { + const enemy = getSingleEnemy(data.id as EnemyIds); + // todo: 与不在地图上的怪物战斗 + } else { + if (data.floorId != core.status.floorId) { + core.doAction(); + return; + } + const [ex, ey] = this.__action_getLoc( + data.loc, + x, + y, + prefix + ) as LocArr; + this.battle(ex, ey, true, core.doAction); + } + }; + + core.enemys.getCurrentEnemys = function (floorId = core.status.floorId) { + floorId = floorId || core.status.floorId; + const enemys: CurrentEnemy[] = []; + const used: Record = {}; + ensureFloorDamage(floorId); + const floor = core.status.maps[floorId]; + floor.enemy.list.forEach(v => { + if (!(v.id in used)) { + const e = new DamageEnemy(v.enemy); + e.calAttribute(); + e.getRealInfo(); + e.calDamage(); + const curr: CurrentEnemy = { + enemy: e, + onMapEnemy: [v] + }; + enemys.push(curr); + used[v.id] = curr.onMapEnemy; + } else { + used[v.id].push(v); + } + }); + + return enemys.sort((a, b) => { + const ad = a.enemy.calDamage().damage; + const bd = b.enemy.calDamage().damage; + return ad - bd; + }); + }; } diff --git a/src/plugin/game/enemy/checkblock.ts b/src/plugin/game/enemy/checkblock.ts index 48a3c9f..95cb588 100644 --- a/src/plugin/game/enemy/checkblock.ts +++ b/src/plugin/game/enemy/checkblock.ts @@ -1,157 +1,162 @@ import { drawHalo } from '../fx/halo'; -// 伤害弹出 -// 复写阻激夹域检测 -control.prototype.checkBlock = function (forceMockery: boolean = false) { - const x = core.getHeroLoc('x'), - y = core.getHeroLoc('y'), - loc = x + ',' + y; - const info = core.status.thisMap.enemy.mapDamage[loc]; - const damage = info?.damage; - if (damage) { - if (!main.replayChecking) { - Mota.Plugin.require('pop').addPop( - (x - core.bigmap.offsetX / 32) * 32 + 12, - (y - core.bigmap.offsetY / 32) * 32 + 20, - (-damage).toString() - ); - } - core.status.hero.hp -= damage; - const type = [...info.type]; - const text = type.join(',') || '伤害'; - core.drawTip('受到' + text + damage + '点'); - core.drawHeroAnimate('zone'); - this._checkBlock_disableQuickShop(); - core.status.hero.statistics.extraDamage += damage; - if (core.status.hero.hp <= 0) { - core.status.hero.hp = 0; - core.updateStatusBar(); - core.events.lose(); - return; - } else { - core.updateStatusBar(); - } - } - checkMockery(loc, forceMockery); -}; - -control.prototype._drawDamage_draw = function ( - ctx: CanvasRenderingContext2D, - onMap: boolean, - floorId: FloorIds -) { - if (!core.hasItem('book')) return; - drawHalo(ctx, onMap, floorId); - - core.setFont(ctx, "14px 'normal'"); - core.setTextAlign(ctx, 'center'); - core.setTextBaseline(ctx, 'middle'); - core.status.damage.extraData.forEach(function (one) { - var px = one.px, - py = one.py; - if (onMap && core.bigmap.v2) { - px -= core.bigmap.posX * 32; - py -= core.bigmap.posY * 32; - if ( - px < -32 || - px > core._PX_ + 32 || - py < -32 || - py > core._PY_ + 32 - ) +export function init() { + // 伤害弹出 + // 复写阻激夹域检测 + control.prototype.checkBlock = function (forceMockery: boolean = false) { + const x = core.getHeroLoc('x'), + y = core.getHeroLoc('y'), + loc = x + ',' + y; + const info = core.status.thisMap.enemy.mapDamage[loc]; + const damage = info?.damage; + if (damage) { + if (!main.replayChecking) { + Mota.Plugin.require('pop_r').addPop( + (x - core.bigmap.offsetX / 32) * 32 + 12, + (y - core.bigmap.offsetY / 32) * 32 + 20, + (-damage).toString() + ); + } + core.status.hero.hp -= damage; + const type = [...info.type]; + const text = type.join(',') || '伤害'; + core.drawTip('受到' + text + damage + '点'); + core.drawHeroAnimate('zone'); + this._checkBlock_disableQuickShop(); + core.status.hero.statistics.extraDamage += damage; + if (core.status.hero.hp <= 0) { + core.status.hero.hp = 0; + core.updateStatusBar(); + core.events.lose(); return; + } else { + core.updateStatusBar(); + } } - var alpha = core.setAlpha(ctx, one.alpha); - core.fillBoldText(ctx, one.text, px, py, one.color as string); - core.setAlpha(ctx, alpha); - }); + checkMockery(loc, forceMockery); + }; - core.setTextAlign(ctx, 'left'); - core.setTextBaseline(ctx, 'alphabetic'); - core.status.damage.data.forEach(function (one) { - var px = one.px, - py = one.py; - if (onMap && core.bigmap.v2) { - px -= core.bigmap.posX * 32; - py -= core.bigmap.posY * 32; - if ( - px < -32 * 2 || - px > core._PX_ + 32 || - py < -32 || - py > core._PY_ + 32 - ) - return; + control.prototype._drawDamage_draw = function ( + ctx: CanvasRenderingContext2D, + onMap: boolean, + floorId: FloorIds + ) { + if (!core.hasItem('book')) return; + drawHalo(ctx, onMap, floorId); + + core.setFont(ctx, "14px 'normal'"); + core.setTextAlign(ctx, 'center'); + core.setTextBaseline(ctx, 'middle'); + core.status.damage.extraData.forEach(function (one) { + var px = one.px, + py = one.py; + if (onMap && core.bigmap.v2) { + px -= core.bigmap.posX * 32; + py -= core.bigmap.posY * 32; + if ( + px < -32 || + px > core._PX_ + 32 || + py < -32 || + py > core._PY_ + 32 + ) + return; + } + var alpha = core.setAlpha(ctx, one.alpha); + core.fillBoldText(ctx, one.text, px, py, one.color as string); + core.setAlpha(ctx, alpha); + }); + + core.setTextAlign(ctx, 'left'); + core.setTextBaseline(ctx, 'alphabetic'); + core.status.damage.data.forEach(function (one) { + var px = one.px, + py = one.py; + if (onMap && core.bigmap.v2) { + px -= core.bigmap.posX * 32; + py -= core.bigmap.posY * 32; + if ( + px < -32 * 2 || + px > core._PX_ + 32 || + py < -32 || + py > core._PY_ + 32 + ) + return; + } + core.fillBoldText(ctx, one.text, px, py, one.color as string); + }); + + ctx.save(); + ctx.lineCap = 'round'; + ctx.lineJoin = 'round'; + ctx.lineWidth = 2; + core.status.damage.dir.forEach(v => { + let x = v.x; + let y = v.y; + if (onMap && core.bigmap.v2) { + x -= core.bigmap.posX; + y -= core.bigmap.posY; + } + if (x < -1 || x > 15 || y < 0 || y > 15) return; + let px = x * 32; + let py = y * 32; + ctx.beginPath(); + if (v.dir === 'down') { + py -= 32; + ctx.moveTo(px + 16, py + 18); + ctx.lineTo(px + 16, py + 32); + ctx.moveTo(px + 10, py + 26); + ctx.lineTo(px + 16, py + 32); + ctx.lineTo(px + 22, py + 26); + } else if (v.dir === 'left') { + px += 32; + ctx.moveTo(px + 14, py + 16); + ctx.lineTo(px, py + 16); + ctx.moveTo(px + 6, py + 10); + ctx.lineTo(px, py + 16); + ctx.lineTo(px + 6, py + 22); + } else if (v.dir === 'up') { + py += 32; + ctx.moveTo(px + 16, py + 14); + ctx.lineTo(px + 16, py); + ctx.moveTo(px + 10, py + 6); + ctx.lineTo(px + 16, py); + ctx.lineTo(px + 22, py + 6); + } else { + px -= 32; + ctx.moveTo(px + 18, py + 16); + ctx.lineTo(px + 32, py + 16); + ctx.moveTo(px + 26, py + 10); + ctx.lineTo(px + 32, py + 16); + ctx.lineTo(px + 26, py + 22); + } + ctx.strokeStyle = 'black'; + ctx.lineWidth = 2.5; + ctx.stroke(); + ctx.strokeStyle = v.color as string; + ctx.lineWidth = 1; + ctx.stroke(); + }); + ctx.restore(); + }; + + control.prototype.moveHero = function ( + direction: Dir, + callback: () => void + ) { + // 如果正在移动,直接return + if (core.status.heroMoving != 0) return; + if (core.isset(direction)) core.setHeroLoc('direction', direction); + + const nx = core.nextX(); + const ny = core.nextY(); + if (core.status.thisMap.enemy.mapDamage[`${nx},${ny}`]?.mockery) { + core.autosave(); } - core.fillBoldText(ctx, one.text, px, py, one.color as string); - }); - ctx.save(); - ctx.lineCap = 'round'; - ctx.lineJoin = 'round'; - ctx.lineWidth = 2; - core.status.damage.dir.forEach(v => { - let x = v.x; - let y = v.y; - if (onMap && core.bigmap.v2) { - x -= core.bigmap.posX; - y -= core.bigmap.posY; - } - if (x < -1 || x > 15 || y < 0 || y > 15) return; - let px = x * 32; - let py = y * 32; - ctx.beginPath(); - if (v.dir === 'down') { - py -= 32; - ctx.moveTo(px + 16, py + 18); - ctx.lineTo(px + 16, py + 32); - ctx.moveTo(px + 10, py + 26); - ctx.lineTo(px + 16, py + 32); - ctx.lineTo(px + 22, py + 26); - } else if (v.dir === 'left') { - px += 32; - ctx.moveTo(px + 14, py + 16); - ctx.lineTo(px, py + 16); - ctx.moveTo(px + 6, py + 10); - ctx.lineTo(px, py + 16); - ctx.lineTo(px + 6, py + 22); - } else if (v.dir === 'up') { - py += 32; - ctx.moveTo(px + 16, py + 14); - ctx.lineTo(px + 16, py); - ctx.moveTo(px + 10, py + 6); - ctx.lineTo(px + 16, py); - ctx.lineTo(px + 22, py + 6); - } else { - px -= 32; - ctx.moveTo(px + 18, py + 16); - ctx.lineTo(px + 32, py + 16); - ctx.moveTo(px + 26, py + 10); - ctx.lineTo(px + 32, py + 16); - ctx.lineTo(px + 26, py + 22); - } - ctx.strokeStyle = 'black'; - ctx.lineWidth = 2.5; - ctx.stroke(); - ctx.strokeStyle = v.color as string; - ctx.lineWidth = 1; - ctx.stroke(); - }); - ctx.restore(); -}; - -control.prototype.moveHero = function (direction: Dir, callback: () => void) { - // 如果正在移动,直接return - if (core.status.heroMoving != 0) return; - if (core.isset(direction)) core.setHeroLoc('direction', direction); - - const nx = core.nextX(); - const ny = core.nextY(); - if (core.status.thisMap.enemy.mapDamage[`${nx},${ny}`]?.mockery) { - core.autosave(); - } - - if (callback) return this.moveAction(callback); - this._moveHero_moving(); -}; + if (callback) return this.moveAction(callback); + this._moveHero_moving(); + }; +} function checkMockery(loc: string, force: boolean = false) { if (core.status.lockControl && !force) return; diff --git a/src/plugin/game/enemy/damage.ts b/src/plugin/game/enemy/damage.ts index 3665a13..6f4958b 100644 --- a/src/plugin/game/enemy/damage.ts +++ b/src/plugin/game/enemy/damage.ts @@ -394,7 +394,7 @@ export class DamageEnemy { getHaloSpecials(): number[] { if (!this.floorId) return []; - if (!core.has(this.x) || !core.has(this.y)) return []; + if (!has(this.x) || !has(this.y)) return []; const special = this.info.special ?? this.enemy.special; const filter = special.filter(v => { return haloSpecials.includes(v) && !this.providedHalo.includes(v); @@ -424,7 +424,7 @@ export class DamageEnemy { if (this.progress !== 2) return; this.progress = 3; if (!this.floorId) return; - if (!core.has(this.x) || !core.has(this.y)) return; + if (!has(this.x) || !has(this.y)) return; const col = this.col ?? core.status.maps[this.floorId].enemy; if (!col) return; const special = this.getHaloSpecials(); @@ -950,8 +950,3 @@ declare global { enemy: EnemyCollection; } } - -core.plugin.damage = { - Enemy: DamageEnemy, - Collection: EnemyCollection -}; diff --git a/src/plugin/game/enemy/remainEnemy.js b/src/plugin/game/enemy/remainEnemy.ts similarity index 51% rename from src/plugin/game/enemy/remainEnemy.js rename to src/plugin/game/enemy/remainEnemy.ts index aed64c2..d07a2b5 100644 --- a/src/plugin/game/enemy/remainEnemy.js +++ b/src/plugin/game/enemy/remainEnemy.ts @@ -1,27 +1,19 @@ -/// - // todo: 优化,直接调用 floor.enemy.list 进行计算 /** * 检查漏怪 - * @param {FloorIds[]} floorIds */ -export function checkRemainEnemy(floorIds) { - /** - * @type {Record} - */ - const enemy = {}; +export function checkRemainEnemy(floorIds: FloorIds[]) { + const enemy: Partial> = + {}; floorIds.forEach(v => { core.extractBlocks(v); const blocks = core.status.maps[v].blocks; blocks.forEach(block => { if (!block.event.cls.startsWith('enemy') || block.disable) return; - /** - * @type {EnemyIds} - */ - const id = block.event.id; + const id: EnemyIds = block.event.id as EnemyIds; enemy[v] ??= []; - const info = enemy[v]; + const info = enemy[v]!; info.push({ loc: [block.x, block.y], id }); }); }); @@ -30,30 +22,23 @@ export function checkRemainEnemy(floorIds) { /** * 获取剩余怪物字符串 - * @param {FloorIds[]} floorIds */ -export function getRemainEnemyString(floorIds) { +export function getRemainEnemyString(floorIds: FloorIds[]) { const enemy = checkRemainEnemy(floorIds); const str = []; let now = []; for (const floor in enemy) { - /** - * @type {{loc: LocArr, id: EnemyIds}[]} - */ - const all = enemy[floor]; - /** - * @type {Record} - */ - const remain = {}; + const all: { loc: LocArr; id: EnemyIds }[] = enemy[floor as FloorIds]!; + const remain: Partial> = {}; all.forEach(v => { const id = v.id; remain[id] ??= 0; - remain[id]++; + remain[id]!++; }); - const title = core.status.maps[floor].title; + const title = core.status.maps[floor as FloorIds].title; for (const id in remain) { - const name = core.material.enemys[id].name; - now.push(`${title}(${floor}): ${name} * ${remain[id]}`); + const name = core.material.enemys[id as EnemyIds].name; + now.push(`${title}(${floor}): ${name} * ${remain[id as EnemyIds]}`); if (now.length === 10) { str.push(now.join('\n')); now = []; @@ -67,8 +52,3 @@ export function getRemainEnemyString(floorIds) { return str; } - -core.plugin.remainEnemy = { - checkRemainEnemy, - getRemainEnemyString -}; diff --git a/src/plugin/game/enemy/special.ts b/src/plugin/game/enemy/special.ts index cf48ba0..0710d3b 100644 --- a/src/plugin/game/enemy/special.ts +++ b/src/plugin/game/enemy/special.ts @@ -7,7 +7,7 @@ export interface SpecialDeclaration { color: string; } -export const enemySpecials: SpecialDeclaration[] = [ +export const specials: SpecialDeclaration[] = [ { code: 0, name: '空', @@ -202,11 +202,3 @@ export const enemySpecials: SpecialDeclaration[] = [ color: '#ff6f0a' } ]; - -declare global { - interface PluginDeclaration { - special: SpecialDeclaration[]; - } -} - -core.plugin.special = enemySpecials; diff --git a/src/plugin/game/fiveLayer.js b/src/plugin/game/fiveLayer.js deleted file mode 100644 index f155857..0000000 --- a/src/plugin/game/fiveLayer.js +++ /dev/null @@ -1,199 +0,0 @@ -/// -export {}; - -// 创建新图层 -function createCanvas(name, zIndex) { - if (!name) return; - var canvas = document.createElement('canvas'); - canvas.id = name; - canvas.className = 'gameCanvas no-anti-aliasing'; - // 编辑器模式下设置zIndex会导致加入的图层覆盖优先级过高 - if (main.mode != 'editor') canvas.style.zIndex = zIndex || 0; - // 将图层插入进游戏内容 - document.getElementById('gameDraw').appendChild(canvas); - var ctx = canvas.getContext('2d'); - core.canvas[name] = ctx; - - return canvas; -} - -var bg2Canvas = createCanvas('bg2', 20); -var fg2Canvas = createCanvas('fg2', 63); -// 大地图适配 -core.bigmap.canvas = ['bg2', 'fg2', 'bg', 'event', 'event2', 'fg', 'damage']; -core.initStatus.bg2maps = {}; -core.initStatus.fg2maps = {}; - -if (main.mode == 'editor') { - /*插入编辑器的图层 不做此步新增图层无法在编辑器显示*/ - // 编辑器图层覆盖优先级 eui > efg > fg(前景层) > event2(48*32图块的事件层) > event(事件层) > bg(背景层) - // 背景层2(bg2) 插入事件层(event)之前(即bg与event之间) - document - .getElementById('mapEdit') - .insertBefore(bg2Canvas, document.getElementById('event')); - // 前景层2(fg2) 插入编辑器前景(efg)之前(即fg之后) - document - .getElementById('mapEdit') - .insertBefore(fg2Canvas, document.getElementById('ebm')); - // 原本有三个图层 从4开始添加 - var num = 4; - // 新增图层存入editor.dom中 - editor.dom.bg2c = core.canvas.bg2.canvas; - editor.dom.bg2Ctx = core.canvas.bg2; - editor.dom.fg2c = core.canvas.fg2.canvas; - editor.dom.fg2Ctx = core.canvas.fg2; - editor.dom.maps.push('bg2map', 'fg2map'); - editor.dom.canvas.push('bg2', 'fg2'); - - // 创建编辑器上的按钮 - var createCanvasBtn = name => { - // 电脑端创建按钮 - var input = document.createElement('input'); - // layerMod4/layerMod5 - var id = 'layerMod' + num++; - // bg2map/fg2map - var value = name + 'map'; - input.type = 'radio'; - input.name = 'layerMod'; - input.id = id; - input.value = value; - editor.dom[id] = input; - input.onchange = () => { - editor.uifunctions.setLayerMod(value); - }; - return input; - }; - - var createCanvasBtn_mobile = name => { - // 手机端往选择列表中添加子选项 - var input = document.createElement('option'); - var id = 'layerMod' + num++; - var value = name + 'map'; - input.name = 'layerMod'; - input.value = value; - editor.dom[id] = input; - return input; - }; - if (!editor.isMobile) { - var input = createCanvasBtn('bg2'); - var input2 = createCanvasBtn('fg2'); - // 获取事件层及其父节点 - var child = document.getElementById('layerMod'), - parent = child.parentNode; - // 背景层2插入事件层前 - parent.insertBefore(input, child); - // 不能直接更改背景层2的innerText 所以创建文本节点 - var txt = document.createTextNode('背2'); - // 插入事件层前(即新插入的背景层2前) - parent.insertBefore(txt, child); - // 向最后插入前景层2(即插入前景层后) - parent.appendChild(input2); - var txt2 = document.createTextNode('前2'); - parent.appendChild(txt2); - } else { - var input = createCanvasBtn_mobile('bg2'); - var input2 = createCanvasBtn_mobile('fg2'); - // 手机端因为是选项 所以可以直接改innerText - input.innerText = '背景2'; - input2.innerText = '前景2'; - var parent = document.getElementById('layerMod'); - parent.insertBefore(input, parent.children[1]); - parent.appendChild(input2); - } -} -maps.prototype._loadFloor_doNotCopy = function () { - return [ - 'firstArrive', - 'eachArrive', - 'blocks', - 'parallelDo', - 'map', - 'bgmap', - 'fgmap', - 'bg2map', - 'fg2map', - 'events', - 'changeFloor', - 'afterBattle', - 'afterGetItem', - 'afterOpenDoor', - 'cannotMove', - 'enemy' - ]; -}; -////// 绘制背景和前景层 ////// -maps.prototype._drawBg_draw = function (floorId, toDrawCtx, cacheCtx, config) { - config.ctx = cacheCtx; - core.maps._drawBg_drawBackground(floorId, config); - // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。 - core.maps._drawFloorImages( - floorId, - config.ctx, - 'bg', - null, - null, - config.onMap - ); - core.maps._drawBgFgMap(floorId, 'bg', config); - if (config.onMap) { - core.drawImage( - toDrawCtx, - cacheCtx.canvas, - core.bigmap.v2 ? -32 : 0, - core.bigmap.v2 ? -32 : 0 - ); - core.clearMap('bg2'); - core.clearMap(cacheCtx); - } - core.maps._drawBgFgMap(floorId, 'bg2', config); - if (config.onMap) - core.drawImage( - 'bg2', - cacheCtx.canvas, - core.bigmap.v2 ? -32 : 0, - core.bigmap.v2 ? -32 : 0 - ); - config.ctx = toDrawCtx; -}; -maps.prototype._drawFg_draw = function (floorId, toDrawCtx, cacheCtx, config) { - config.ctx = cacheCtx; - // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制前景图块;后绘制的覆盖先绘制的。 - core.maps._drawFloorImages( - floorId, - config.ctx, - 'fg', - null, - null, - config.onMap - ); - core.maps._drawBgFgMap(floorId, 'fg', config); - if (config.onMap) { - core.drawImage( - toDrawCtx, - cacheCtx.canvas, - core.bigmap.v2 ? -32 : 0, - core.bigmap.v2 ? -32 : 0 - ); - core.clearMap('fg2'); - core.clearMap(cacheCtx); - } - core.maps._drawBgFgMap(floorId, 'fg2', config); - if (config.onMap) - core.drawImage( - 'fg2', - cacheCtx.canvas, - core.bigmap.v2 ? -32 : 0, - core.bigmap.v2 ? -32 : 0 - ); - config.ctx = toDrawCtx; -}; -////// 移动判定 ////// -maps.prototype._generateMovableArray_arrays = function (floorId) { - return { - bgArray: this.getBgMapArray(floorId), - fgArray: this.getFgMapArray(floorId), - eventArray: this.getMapArray(floorId), - bg2Array: this._getBgFgMapArray('bg2', floorId), - fg2Array: this._getBgFgMapArray('fg2', floorId) - }; -}; diff --git a/src/plugin/game/fiveLayer.ts b/src/plugin/game/fiveLayer.ts new file mode 100644 index 0000000..f4531f5 --- /dev/null +++ b/src/plugin/game/fiveLayer.ts @@ -0,0 +1,219 @@ +// @ts-nocheck + +// 创建新图层 +function createCanvas(name, zIndex) { + if (!name) return; + var canvas = document.createElement('canvas'); + canvas.id = name; + canvas.className = 'gameCanvas no-anti-aliasing'; + // 编辑器模式下设置zIndex会导致加入的图层覆盖优先级过高 + if (main.mode != 'editor') canvas.style.zIndex = zIndex || 0; + // 将图层插入进游戏内容 + document.getElementById('gameDraw').appendChild(canvas); + var ctx = canvas.getContext('2d'); + core.canvas[name] = ctx; + + return canvas; +} + +export function init() { + var bg2Canvas = createCanvas('bg2', 20); + var fg2Canvas = createCanvas('fg2', 63); + // 大地图适配 + core.bigmap.canvas = [ + 'bg2', + 'fg2', + 'bg', + 'event', + 'event2', + 'fg', + 'damage' + ]; + core.initStatus.bg2maps = {}; + core.initStatus.fg2maps = {}; + + if (main.mode == 'editor') { + /*插入编辑器的图层 不做此步新增图层无法在编辑器显示*/ + // 编辑器图层覆盖优先级 eui > efg > fg(前景层) > event2(48*32图块的事件层) > event(事件层) > bg(背景层) + // 背景层2(bg2) 插入事件层(event)之前(即bg与event之间) + document + .getElementById('mapEdit') + .insertBefore(bg2Canvas, document.getElementById('event')); + // 前景层2(fg2) 插入编辑器前景(efg)之前(即fg之后) + document + .getElementById('mapEdit') + .insertBefore(fg2Canvas, document.getElementById('ebm')); + // 原本有三个图层 从4开始添加 + var num = 4; + // 新增图层存入editor.dom中 + editor.dom.bg2c = core.canvas.bg2.canvas; + editor.dom.bg2Ctx = core.canvas.bg2; + editor.dom.fg2c = core.canvas.fg2.canvas; + editor.dom.fg2Ctx = core.canvas.fg2; + editor.dom.maps.push('bg2map', 'fg2map'); + editor.dom.canvas.push('bg2', 'fg2'); + + // 创建编辑器上的按钮 + var createCanvasBtn = name => { + // 电脑端创建按钮 + var input = document.createElement('input'); + // layerMod4/layerMod5 + var id = 'layerMod' + num++; + // bg2map/fg2map + var value = name + 'map'; + input.type = 'radio'; + input.name = 'layerMod'; + input.id = id; + input.value = value; + editor.dom[id] = input; + input.onchange = () => { + editor.uifunctions.setLayerMod(value); + }; + return input; + }; + + var createCanvasBtn_mobile = name => { + // 手机端往选择列表中添加子选项 + var input = document.createElement('option'); + var id = 'layerMod' + num++; + var value = name + 'map'; + input.name = 'layerMod'; + input.value = value; + editor.dom[id] = input; + return input; + }; + if (!editor.isMobile) { + var input = createCanvasBtn('bg2'); + var input2 = createCanvasBtn('fg2'); + // 获取事件层及其父节点 + var child = document.getElementById('layerMod'), + parent = child.parentNode; + // 背景层2插入事件层前 + parent.insertBefore(input, child); + // 不能直接更改背景层2的innerText 所以创建文本节点 + var txt = document.createTextNode('背2'); + // 插入事件层前(即新插入的背景层2前) + parent.insertBefore(txt, child); + // 向最后插入前景层2(即插入前景层后) + parent.appendChild(input2); + var txt2 = document.createTextNode('前2'); + parent.appendChild(txt2); + } else { + var input = createCanvasBtn_mobile('bg2'); + var input2 = createCanvasBtn_mobile('fg2'); + // 手机端因为是选项 所以可以直接改innerText + input.innerText = '背景2'; + input2.innerText = '前景2'; + var parent = document.getElementById('layerMod'); + parent.insertBefore(input, parent.children[1]); + parent.appendChild(input2); + } + } + + maps.prototype._loadFloor_doNotCopy = function () { + return [ + 'firstArrive', + 'eachArrive', + 'blocks', + 'parallelDo', + 'map', + 'bgmap', + 'fgmap', + 'bg2map', + 'fg2map', + 'events', + 'changeFloor', + 'afterBattle', + 'afterGetItem', + 'afterOpenDoor', + 'cannotMove', + 'enemy' + ]; + }; + ////// 绘制背景和前景层 ////// + maps.prototype._drawBg_draw = function ( + floorId, + toDrawCtx, + cacheCtx, + config + ) { + config.ctx = cacheCtx; + core.maps._drawBg_drawBackground(floorId, config); + // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。 + core.maps._drawFloorImages( + floorId, + config.ctx, + 'bg', + null, + null, + config.onMap + ); + core.maps._drawBgFgMap(floorId, 'bg', config); + if (config.onMap) { + core.drawImage( + toDrawCtx, + cacheCtx.canvas, + core.bigmap.v2 ? -32 : 0, + core.bigmap.v2 ? -32 : 0 + ); + core.clearMap('bg2'); + core.clearMap(cacheCtx); + } + core.maps._drawBgFgMap(floorId, 'bg2', config); + if (config.onMap) + core.drawImage( + 'bg2', + cacheCtx.canvas, + core.bigmap.v2 ? -32 : 0, + core.bigmap.v2 ? -32 : 0 + ); + config.ctx = toDrawCtx; + }; + maps.prototype._drawFg_draw = function ( + floorId, + toDrawCtx, + cacheCtx, + config + ) { + config.ctx = cacheCtx; + // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制前景图块;后绘制的覆盖先绘制的。 + core.maps._drawFloorImages( + floorId, + config.ctx, + 'fg', + null, + null, + config.onMap + ); + core.maps._drawBgFgMap(floorId, 'fg', config); + if (config.onMap) { + core.drawImage( + toDrawCtx, + cacheCtx.canvas, + core.bigmap.v2 ? -32 : 0, + core.bigmap.v2 ? -32 : 0 + ); + core.clearMap('fg2'); + core.clearMap(cacheCtx); + } + core.maps._drawBgFgMap(floorId, 'fg2', config); + if (config.onMap) + core.drawImage( + 'fg2', + cacheCtx.canvas, + core.bigmap.v2 ? -32 : 0, + core.bigmap.v2 ? -32 : 0 + ); + config.ctx = toDrawCtx; + }; + ////// 移动判定 ////// + maps.prototype._generateMovableArray_arrays = function (floorId) { + return { + bgArray: this.getBgMapArray(floorId), + fgArray: this.getFgMapArray(floorId), + eventArray: this.getMapArray(floorId), + bg2Array: this._getBgFgMapArray('bg2', floorId), + fg2Array: this._getBgFgMapArray('fg2', floorId) + }; + }; +} diff --git a/src/plugin/game/fx/heroFourFrames.js b/src/plugin/game/fx/heroFourFrames.js deleted file mode 100644 index 7aba4d4..0000000 --- a/src/plugin/game/fx/heroFourFrames.js +++ /dev/null @@ -1,58 +0,0 @@ -/// -export {}; - -['up', 'down', 'left', 'right'].forEach(one => { - // 指定中间帧动画 - core.material.icons.hero[one].midFoot = 2; -}); - -var heroMoving = timestamp => { - if (core.status.heroMoving <= 0) return; - if (timestamp - core.animateFrame.moveTime > core.values.moveSpeed) { - core.animateFrame.leftLeg++; - core.animateFrame.moveTime = timestamp; - } - core.drawHero( - ['stop', 'leftFoot', 'midFoot', 'rightFoot'][ - core.animateFrame.leftLeg % 4 - ], - 4 * core.status.heroMoving - ); -}; -core.registerAnimationFrame('heroMoving', true, heroMoving); - -core.events._eventMoveHero_moving = function (step, moveSteps) { - var curr = moveSteps[0]; - var direction = curr[0], - x = core.getHeroLoc('x'), - y = core.getHeroLoc('y'); - // ------ 前进/后退 - var o = direction == 'backward' ? -1 : 1; - if (direction == 'forward' || direction == 'backward') - direction = core.getHeroLoc('direction'); - var faceDirection = direction; - if (direction == 'leftup' || direction == 'leftdown') - faceDirection = 'left'; - if (direction == 'rightup' || direction == 'rightdown') - faceDirection = 'right'; - core.setHeroLoc('direction', direction); - if (curr[1] <= 0) { - core.setHeroLoc('direction', faceDirection); - moveSteps.shift(); - return true; - } - if (step <= 4) core.drawHero('stop', 4 * o * step); - else if (step <= 8) core.drawHero('leftFoot', 4 * o * step); - else if (step <= 12) core.drawHero('midFoot', 4 * o * (step - 8)); - else if (step <= 16) core.drawHero('rightFoot', 4 * o * (step - 8)); // if (step == 8) { - if (step == 8 || step == 16) { - core.setHeroLoc('x', x + o * core.utils.scan2[direction].x, true); - core.setHeroLoc('y', y + o * core.utils.scan2[direction].y, true); - core.updateFollowers(); - curr[1]--; - if (curr[1] <= 0) moveSteps.shift(); - core.setHeroLoc('direction', faceDirection); - return step == 16; - } - return false; -}; diff --git a/src/plugin/game/fx/heroFourFrames.ts b/src/plugin/game/fx/heroFourFrames.ts new file mode 100644 index 0000000..a1cdf60 --- /dev/null +++ b/src/plugin/game/fx/heroFourFrames.ts @@ -0,0 +1,60 @@ +// @ts-nocheck + +var heroMoving = timestamp => { + if (core.status.heroMoving <= 0) return; + if (timestamp - core.animateFrame.moveTime > core.values.moveSpeed) { + core.animateFrame.leftLeg++; + core.animateFrame.moveTime = timestamp; + } + core.drawHero( + ['stop', 'leftFoot', 'midFoot', 'rightFoot'][ + core.animateFrame.leftLeg % 4 + ], + 4 * core.status.heroMoving + ); +}; + +export function init() { + ['up', 'down', 'left', 'right'].forEach(one => { + // 指定中间帧动画 + core.material.icons.hero[one].midFoot = 2; + }); + + core.registerAnimationFrame('heroMoving', true, heroMoving); + + core.events._eventMoveHero_moving = function (step, moveSteps) { + var curr = moveSteps[0]; + var direction = curr[0], + x = core.getHeroLoc('x'), + y = core.getHeroLoc('y'); + // ------ 前进/后退 + var o = direction == 'backward' ? -1 : 1; + if (direction == 'forward' || direction == 'backward') + direction = core.getHeroLoc('direction'); + var faceDirection = direction; + if (direction == 'leftup' || direction == 'leftdown') + faceDirection = 'left'; + if (direction == 'rightup' || direction == 'rightdown') + faceDirection = 'right'; + core.setHeroLoc('direction', direction); + if (curr[1] <= 0) { + core.setHeroLoc('direction', faceDirection); + moveSteps.shift(); + return true; + } + if (step <= 4) core.drawHero('stop', 4 * o * step); + else if (step <= 8) core.drawHero('leftFoot', 4 * o * step); + else if (step <= 12) core.drawHero('midFoot', 4 * o * (step - 8)); + else if (step <= 16) core.drawHero('rightFoot', 4 * o * (step - 8)); // if (step == 8) { + if (step == 8 || step == 16) { + core.setHeroLoc('x', x + o * core.utils.scan2[direction].x, true); + core.setHeroLoc('y', y + o * core.utils.scan2[direction].y, true); + core.updateFollowers(); + curr[1]--; + if (curr[1] <= 0) moveSteps.shift(); + core.setHeroLoc('direction', faceDirection); + return step == 16; + } + return false; + }; +} diff --git a/src/plugin/game/fx/itemDetail.ts b/src/plugin/game/fx/itemDetail.ts index 1f272c0..31efeed 100644 --- a/src/plugin/game/fx/itemDetail.ts +++ b/src/plugin/game/fx/itemDetail.ts @@ -1,33 +1,35 @@ import { ensureFloorDamage } from '../enemy/damage'; -core.control.updateDamage = function (floorId = core.status.floorId, ctx) { - if (!floorId || core.status.gameOver || main.mode !== 'play') return; - const onMap = ctx == null; - const floor = core.status.maps[floorId]; +export function init() { + core.control.updateDamage = function (floorId = core.status.floorId, ctx) { + if (!floorId || core.status.gameOver || main.mode !== 'play') return; + const onMap = ctx == null; + const floor = core.status.maps[floorId]; - // 没有怪物手册 - // if (!core.hasItem('book')) return; - core.status.damage.posX = core.bigmap.posX; - core.status.damage.posY = core.bigmap.posY; - if (!onMap) { - const width = core.floors[floorId].width, - height = core.floors[floorId].height; - // 地图过大的缩略图不绘制显伤 - if (width * height > core.bigmap.threshold) return; - } - // 计算伤害 - ensureFloorDamage(floorId); + // 没有怪物手册 + // if (!core.hasItem('book')) return; + core.status.damage.posX = core.bigmap.posX; + core.status.damage.posY = core.bigmap.posY; + if (!onMap) { + const width = core.floors[floorId].width, + height = core.floors[floorId].height; + // 地图过大的缩略图不绘制显伤 + if (width * height > core.bigmap.threshold) return; + } + // 计算伤害 + ensureFloorDamage(floorId); - floor.enemy.extract(); - floor.enemy.calDamage(true); - floor.enemy.calMapDamage(); - core.status.damage.data = []; + floor.enemy.extract(); + floor.enemy.calDamage(true); + floor.enemy.calMapDamage(); + core.status.damage.data = []; - floor.enemy.render(true); + floor.enemy.render(true); - getItemDetail(floorId, onMap); // 宝石血瓶详细信息 - this.drawDamage(ctx, floorId); -}; + getItemDetail(floorId, onMap); // 宝石血瓶详细信息 + this.drawDamage(ctx, floorId); + }; +} // 获取宝石信息 并绘制 function getItemDetail(floorId: FloorIds, onMap: boolean) { diff --git a/src/plugin/game/fx/rewrite.ts b/src/plugin/game/fx/rewrite.ts index 5a19f1f..4a1f989 100644 --- a/src/plugin/game/fx/rewrite.ts +++ b/src/plugin/game/fx/rewrite.ts @@ -1,59 +1,61 @@ import { getEnemy } from '../enemy/battle'; import { formatDamage } from '../utils'; -core.maps._initDetachedBlock = function ( - info: BlockInfo, - x: number, - y: number, - displayDamage: boolean = false -) { - let headCanvas = null, - bodyCanvas = '__body_' + x + '_' + y, - damageCanvas = null; - - // head - if (!info.bigImage && info.height > 32) { - headCanvas = '__head_' + x + '_' + y; - core.createCanvas(headCanvas, 0, 0, 32, info.height - 32, 55); - } - // body - if (info.bigImage) { - var bigImageInfo = this._getBigImageInfo( - info.bigImage, - info.face, - info.posX - ); - const { per_width, per_height } = bigImageInfo; - core.createCanvas(bodyCanvas, 0, 0, per_width, per_height, 35); - } else { - core.createCanvas(bodyCanvas, 0, 0, 32, 32, 35); - } - - // 伤害 - if ( - info.cls.indexOf('enemy') == 0 && - core.hasItem('book') && - displayDamage +export function init() { + core.maps._initDetachedBlock = function ( + info: BlockInfo, + x: number, + y: number, + displayDamage: boolean = false ) { - const enemy = getEnemy(x, y); - const dam = enemy.calDamage(); - const { damage, color } = formatDamage(dam.damage); + let headCanvas = null, + bodyCanvas = '__body_' + x + '_' + y, + damageCanvas = null; - damageCanvas = '__damage_' + x + '_' + y; - const ctx = core.createCanvas(damageCanvas, 0, 0, 32, 32, 65); - ctx.textAlign = 'left'; - ctx.font = '14px normal'; - core.fillBoldText(ctx, damage, 1, 31, color as string); - if (core.flags.displayCritical) { - const critical = enemy.calCritical(1); - const atk = core.formatBigNumber(critical[0]?.delta, true); - const display = atk === '???' ? '?' : atk; - core.fillBoldText(ctx, display, 1, 21, '#FFFFFF'); + // head + if (!info.bigImage && info.height > 32) { + headCanvas = '__head_' + x + '_' + y; + core.createCanvas(headCanvas, 0, 0, 32, info.height - 32, 55); } - } - return { - headCanvas, - bodyCanvas, - damageCanvas + // body + if (info.bigImage) { + var bigImageInfo = this._getBigImageInfo( + info.bigImage, + info.face, + info.posX + ); + const { per_width, per_height } = bigImageInfo; + core.createCanvas(bodyCanvas, 0, 0, per_width, per_height, 35); + } else { + core.createCanvas(bodyCanvas, 0, 0, 32, 32, 35); + } + + // 伤害 + if ( + info.cls.indexOf('enemy') == 0 && + core.hasItem('book') && + displayDamage + ) { + const enemy = getEnemy(x, y); + const dam = enemy.calDamage(); + const { damage, color } = formatDamage(dam.damage); + + damageCanvas = '__damage_' + x + '_' + y; + const ctx = core.createCanvas(damageCanvas, 0, 0, 32, 32, 65); + ctx.textAlign = 'left'; + ctx.font = '14px normal'; + core.fillBoldText(ctx, damage, 1, 31, color as string); + if (core.flags.displayCritical) { + const critical = enemy.calCritical(1); + const atk = core.formatBigNumber(critical[0]?.delta, true); + const display = atk === '???' ? '?' : atk; + core.fillBoldText(ctx, display, 1, 21, '#FFFFFF'); + } + } + return { + headCanvas, + bodyCanvas, + damageCanvas + }; }; -}; +} diff --git a/src/plugin/game/hero.ts b/src/plugin/game/hero.ts index 0cd2528..2aa1c0c 100644 --- a/src/plugin/game/hero.ts +++ b/src/plugin/game/hero.ts @@ -54,6 +54,7 @@ function getRealStatus( name: keyof HeroStatus | 'all' | (keyof HeroStatus)[], floorId: FloorIds = core.status.floorId ): any { + const { getSkillLevel } = Mota.Plugin.require('skillTree_g'); if (name instanceof Array) { return Object.fromEntries( name.map(v => [v, getRealStatus(status, v, floorId)]) @@ -84,7 +85,7 @@ function getRealStatus( // 技能 if (flags.bladeOn && flags.blade) { - const level = core.plugin.skillTree.getSkillLevel(2); + const level = getSkillLevel(2); if (name === 'atk') { s *= 1 + 0.1 * level; } @@ -93,7 +94,7 @@ function getRealStatus( } } if (flags.shield && flags.shieldOn) { - const level = core.plugin.skillTree.getSkillLevel(10); + const level = getSkillLevel(10); if (name === 'atk') { s *= 1 - 0.1 * level; } @@ -119,8 +120,3 @@ declare global { }; } } - -core.plugin.hero = { - getHeroStatusOf, - getHeroStatusOn -}; diff --git a/src/plugin/game/index.js b/src/plugin/game/index.js deleted file mode 100644 index 5fc5141..0000000 --- a/src/plugin/game/index.js +++ /dev/null @@ -1,41 +0,0 @@ -import './fiveLayer'; -import './fx/heroFourFrames'; -import './dev/hotReload'; -import './fx/itemDetail'; -import './enemy/checkblock'; -import './replay'; -import './ui'; -import './fx/rewrite'; -import * as halo from './fx/halo'; -import * as hero from './hero'; -import * as loopMap from './loopMap'; -import * as remainEnemy from './enemy/remainEnemy'; -import * as removeMap from './removeMap'; -import * as shop from './shop'; -import * as skill from './skills'; -import * as skillTree from './skillTree'; -import * as study from './study'; -import * as towerBoss from './towerBoss'; -import * as utils from './utils'; -import * as chase from './chase'; -import * as damage from './enemy/damage'; -import * as battle from './enemy/battle'; -import * as special from './enemy/special'; - -export { - halo, - hero, - loopMap, - remainEnemy, - removeMap, - shop, - skill, - skillTree, - study, - towerBoss, - utils, - chase, - damage, - battle, - special -}; diff --git a/src/plugin/game/index.ts b/src/plugin/game/index.ts new file mode 100644 index 0000000..b09ce87 --- /dev/null +++ b/src/plugin/game/index.ts @@ -0,0 +1,65 @@ +/* @__PURE__ */ import './dev/hotReload'; // 仅开发会用到 +import * as fiveLayer from './fiveLayer'; +import * as heroFourFrames from './fx/heroFourFrames'; +import * as itemDetail from './fx/itemDetail'; +import * as checkBlock from './enemy/checkblock'; +import * as replay from './replay'; +import * as ui from './ui'; +import * as rewrite from './fx/rewrite'; +import * as halo from './fx/halo'; +import * as hero from './hero'; +import * as loopMap from './loopMap'; +import * as remainEnemy from './enemy/remainEnemy'; +import * as removeMap from './removeMap'; +import * as shop from './shop'; +import * as skill from './skill'; +import * as skillTree from './skillTree'; +import * as study from './study'; +import * as towerBoss from './towerBoss'; +import * as utils from './utils'; +import * as chase from './chase'; +import * as damage from './enemy/damage'; +import * as battle from './enemy/battle'; +import * as special from './enemy/special'; + +Mota.Plugin.register('utils_g', utils); +Mota.Plugin.register('loopMap_g', loopMap, loopMap.init); +Mota.Plugin.register('shop_g', shop); +Mota.Plugin.register('replay_g', replay, replay.init); +Mota.Plugin.register('skillTree_g', skillTree); +Mota.Plugin.register('removeMap_g', removeMap); +Mota.Plugin.register('remainEnemy_g', remainEnemy); +Mota.Plugin.register('chase_g', chase); +Mota.Plugin.register('skill_g', skill); +Mota.Plugin.register('towerBoss_g', towerBoss); +Mota.Plugin.register('fiveLayer_g', fiveLayer, fiveLayer.init); +Mota.Plugin.register('heroFourFrames_g', heroFourFrames, heroFourFrames.init); +Mota.Plugin.register('rewrite_g', rewrite, rewrite.init); +Mota.Plugin.register('itemDetail_g', itemDetail, itemDetail.init); +Mota.Plugin.register('checkBlock_g', checkBlock, checkBlock.init); +Mota.Plugin.register('halo_g', halo); +Mota.Plugin.register('study_g', study); +// todo: 这几个不应该放到插件 +Mota.Plugin.register('damage_g', damage); +Mota.Plugin.register('battle_g', battle, battle.init); +Mota.Plugin.register('special_g', special); +Mota.Plugin.register('hero_g', hero); +Mota.Plugin.register('ui_g', ui, ui.init); + +// export { +// halo, +// hero, +// loopMap, +// remainEnemy, +// removeMap, +// shop, +// skill, +// skillTree, +// study, +// towerBoss, +// utils, +// chase, +// damage, +// battle, +// special +// }; diff --git a/src/plugin/game/loopMap.js b/src/plugin/game/loopMap.js deleted file mode 100644 index 4cdef85..0000000 --- a/src/plugin/game/loopMap.js +++ /dev/null @@ -1,230 +0,0 @@ -/// -import { slide } from './utils'; - -const list = ['tower6']; - -/** - * 设置循环地图的偏移量 - * @param {number} offset 横向偏移量 - * @param {FloorIds} floorId - */ -function setLoopMap(offset, floorId) { - const floor = core.status.maps[floorId]; - if (offset < 9) { - moveMap(floor.width - 17, floorId); - } - if (offset > floor.width - 9) { - moveMap(17 - floor.width, floorId); - } -} - -/** - * 当勇士移动时自动设置循环地图 - * @param {FloorIds} floorId - */ -function autoSetLoopMap(floorId) { - setLoopMap(core.status.hero.loc.x, floorId); -} - -export function checkLoopMap() { - if (isLoopMap(core.status.floorId)) { - autoSetLoopMap(core.status.floorId); - } -} - -/** - * 移动地图 - * @param {number} delta - * @param {FloorIds} floorId - */ -function moveMap(delta, floorId) { - core.extractBlocks(floorId); - const floor = core.status.maps[floorId]; - core.setHeroLoc('x', core.status.hero.loc.x + delta); - flags[`loop_${floorId}`] += delta; - flags[`loop_${floorId}`] %= floor.width; - const origin = floor.blocks.slice(); - for (let i = 0; i < origin.length; i++) { - core.removeBlockByIndex(0, floorId); - core.removeGlobalAnimate(origin[i].x, origin[i].y); - } - origin.forEach(v => { - let to = v.x + delta; - if (to >= floor.width) to -= floor.width; - if (to < 0) to += floor.width; - core.setBlock(v.id, to, v.y, floorId, true); - core.setMapBlockDisabled(floorId, to, v.y, false); - }); - core.drawMap(); - core.drawHero(); -} - -function isLoopMap(floorId) { - return list.includes(floorId); -} - -events.prototype._sys_changeFloor = function (data, callback) { - data = data.event.data; - let heroLoc = {}; - if (isLoopMap(data.floorId)) { - const floor = core.status.maps[data.floorId]; - flags[`loop_${data.floorId}`] ??= 0; - let tx = data.loc[0] + flags[`loop_${data.floorId}`]; - tx %= floor.width; - if (tx < 0) tx += floor.width; - heroLoc = { - x: tx, - y: data.loc[1] - }; - } else if (data.loc) heroLoc = { x: data.loc[0], y: data.loc[1] }; - if (data.direction) heroLoc.direction = data.direction; - if (core.status.event.id != 'action') core.status.event.id = null; - core.changeFloor(data.floorId, data.stair, heroLoc, data.time, function () { - core.replay(); - if (callback) callback(); - }); -}; - -events.prototype.trigger = function (x, y, callback) { - var _executeCallback = function () { - // 因为trigger之后还有可能触发其他同步脚本(比如阻激夹域检测) - // 所以这里强制callback被异步触发 - if (callback) { - setTimeout(callback, 1); // +1是为了录像检测系统 - } - return; - }; - if (core.status.gameOver) return _executeCallback(); - if (core.status.event.id == 'action') { - core.insertAction( - { - type: 'function', - function: - 'function () { core.events._trigger_inAction(' + - x + - ',' + - y + - '); }', - async: true - }, - null, - null, - null, - true - ); - return _executeCallback(); - } - if (core.status.event.id) return _executeCallback(); - - let block = core.getBlock(x, y); - const id = core.status.floorId; - const loop = isLoopMap(id); - if (loop && flags[`loop_${id}`] !== 0) { - if (block && block.event.trigger === 'changeFloor') { - delete block.event.trigger; - core.maps._addInfo(block); - } else { - const floor = core.status.maps[id]; - let tx = x - flags[`loop_${id}`]; - tx %= floor.width; - if (tx < 0) tx += floor.width; - const c = core.floors[id].changeFloor[`${tx},${y}`]; - if (c) { - const b = { event: {}, x: tx, y }; - b.event.data = c; - b.event.trigger = 'changeFloor'; - block = b; - } - } - } - - if (block == null) return _executeCallback(); - - // 执行该点的脚本 - if (block.event.script) { - core.clearRouteFolding(); - try { - eval(block.event.script); - } catch (ee) { - console.error(ee); - } - } - - // 碰触事件 - if (block.event.event) { - core.clearRouteFolding(); - core.insertAction(block.event.event, block.x, block.y); - // 不再执行该点的系统事件 - return _executeCallback(); - } - - if (block.event.trigger && block.event.trigger != 'null') { - var noPass = block.event.noPass, - trigger = block.event.trigger; - if (noPass) core.clearAutomaticRouteNode(x, y); - - // 转换楼层能否穿透 - if ( - trigger == 'changeFloor' && - !noPass && - this._trigger_ignoreChangeFloor(block) && - !loop - ) - return _executeCallback(); - core.status.automaticRoute.moveDirectly = false; - this.doSystemEvent(trigger, block); - } - return _executeCallback(); -}; - -maps.prototype._getBgFgMapArray = function (name, floorId, noCache) { - floorId = floorId || core.status.floorId; - if (!floorId) return []; - var width = core.floors[floorId].width; - var height = core.floors[floorId].height; - - if (!noCache && core.status[name + 'maps'][floorId]) - return core.status[name + 'maps'][floorId]; - - var arr = - main.mode == 'editor' && - !(window.editor && editor.uievent && editor.uievent.isOpen) - ? core.cloneArray(editor[name + 'map']) - : null; - if (arr == null) - arr = core.cloneArray(core.floors[floorId][name + 'map'] || []); - - if (isLoopMap(floorId) && window.flags) { - flags[`loop_${floorId}`] ??= 0; - arr.forEach(v => { - slide(v, flags[`loop_${floorId}`] % width); - }); - } - - for (var y = 0; y < height; ++y) { - if (arr[y] == null) arr[y] = Array(width).fill(0); - } - (core.getFlag('__' + name + 'v__', {})[floorId] || []).forEach(function ( - one - ) { - arr[one[1]][one[0]] = one[2] || 0; - }); - (core.getFlag('__' + name + 'd__', {})[floorId] || []).forEach(function ( - one - ) { - arr[one[1]][one[0]] = 0; - }); - if (main.mode == 'editor') { - for (var x = 0; x < width; x++) { - for (var y = 0; y < height; y++) { - arr[y][x] = arr[y][x].idnum || arr[y][x] || 0; - } - } - } - if (core.status[name + 'maps']) core.status[name + 'maps'][floorId] = arr; - return arr; -}; - -core.plugin.loopMap = { - checkLoopMap -}; diff --git a/src/plugin/game/loopMap.ts b/src/plugin/game/loopMap.ts new file mode 100644 index 0000000..34ba824 --- /dev/null +++ b/src/plugin/game/loopMap.ts @@ -0,0 +1,257 @@ +/// +import { slide } from './utils'; + +const list = ['tower6']; + +/** + * 设置循环地图的偏移量 + * @param offset 横向偏移量 + */ +function setLoopMap(offset: number, floorId: FloorIds) { + const floor = core.status.maps[floorId]; + if (offset < 9) { + moveMap(floor.width - 17, floorId); + } + if (offset > floor.width - 9) { + moveMap(17 - floor.width, floorId); + } +} + +/** + * 当勇士移动时自动设置循环地图 + */ +function autoSetLoopMap(floorId: FloorIds) { + setLoopMap(core.status.hero.loc.x, floorId); +} + +export function checkLoopMap() { + if (isLoopMap(core.status.floorId)) { + autoSetLoopMap(core.status.floorId); + } +} + +/** + * 移动地图 + */ +function moveMap(delta: number, floorId: FloorIds) { + core.extractBlocks(floorId); + const floor = core.status.maps[floorId]; + core.setHeroLoc('x', core.status.hero.loc.x + delta); + flags[`loop_${floorId}`] += delta; + flags[`loop_${floorId}`] %= floor.width; + const origin = floor.blocks.slice(); + for (let i = 0; i < origin.length; i++) { + core.removeBlockByIndex(0, floorId); + core.removeGlobalAnimate(origin[i].x, origin[i].y); + } + origin.forEach(v => { + let to = v.x + delta; + if (to >= floor.width) to -= floor.width; + if (to < 0) to += floor.width; + core.setBlock(v.id, to, v.y, floorId, true); + core.setMapBlockDisabled(floorId, to, v.y, false); + }); + core.drawMap(); + core.drawHero(); +} + +function isLoopMap(floorId: FloorIds) { + return list.includes(floorId); +} + +export function init() { + events.prototype._sys_changeFloor = function ( + data: any, + callback: () => void + ) { + data = data.event.data; + let heroLoc: Partial = {}; + if (isLoopMap(data.floorId)) { + const floor = core.status.maps[data.floorId as FloorIds] as Floor; + flags[`loop_${data.floorId}`] ??= 0; + let tx = data.loc[0] + flags[`loop_${data.floorId}`]; + tx %= floor.width; + if (tx < 0) tx += floor.width; + heroLoc = { + x: tx, + y: data.loc[1] + }; + } else if (data.loc) heroLoc = { x: data.loc[0], y: data.loc[1] }; + if (data.direction) heroLoc.direction = data.direction; + // @ts-ignore + if (core.status.event.id != 'action') core.status.event.id = null; + core.changeFloor( + data.floorId, + data.stair, + heroLoc, + data.time, + function () { + core.replay(); + if (callback) callback(); + } + ); + }; + + events.prototype.trigger = function ( + x: number, + y: number, + callback: () => void + ) { + var _executeCallback = function () { + // 因为trigger之后还有可能触发其他同步脚本(比如阻激夹域检测) + // 所以这里强制callback被异步触发 + if (callback) { + setTimeout(callback, 1); // +1是为了录像检测系统 + } + return; + }; + if (core.status.gameOver) return _executeCallback(); + if (core.status.event.id == 'action') { + core.insertAction( + { + type: 'function', + function: + 'function () { core.events._trigger_inAction(' + + x + + ',' + + y + + '); }', + async: true + }, + void 0, + void 0, + void 0, + true + ); + return _executeCallback(); + } + if (core.status.event.id) return _executeCallback(); + + let block = core.getBlock(x, y); + const id = core.status.floorId; + const loop = isLoopMap(id); + if (loop && flags[`loop_${id}`] !== 0) { + if (block && block.event.trigger === 'changeFloor') { + delete block.event.trigger; + // @ts-ignore + core.maps._addInfo(block); + } else { + const floor = core.status.maps[id]; + let tx = x - flags[`loop_${id}`]; + tx %= floor.width; + if (tx < 0) tx += floor.width; + const c = core.floors[id].changeFloor[`${tx},${y}`]; + if (c) { + const b: DeepPartial = { event: {}, x: tx, y }; + b.event!.data = c; + b.event!.trigger = 'changeFloor'; + block = b as Block; + } + } + } + + if (block == null) return _executeCallback(); + + // 执行该点的脚本 + if (block.event.script) { + core.clearRouteFolding(); + try { + eval(block.event.script); + } catch (ee) { + console.error(ee); + } + } + + // 碰触事件 + if (block.event.event) { + core.clearRouteFolding(); + core.insertAction(block.event.event, block.x, block.y); + // 不再执行该点的系统事件 + return _executeCallback(); + } + + if (block.event.trigger && block.event.trigger !== 'null') { + var noPass = block.event.noPass, + trigger = block.event.trigger; + if (noPass) core.clearAutomaticRouteNode(x, y); + + // 转换楼层能否穿透 + if ( + trigger == 'changeFloor' && + !noPass && + this._trigger_ignoreChangeFloor(block) && + !loop + ) + return _executeCallback(); + // @ts-ignore + core.status.automaticRoute.moveDirectly = false; + this.doSystemEvent(trigger, block); + } + return _executeCallback(); + }; + + maps.prototype._getBgFgMapArray = function ( + name: string, + floorId: FloorIds, + noCache: boolean + ) { + floorId = floorId || core.status.floorId; + if (!floorId) return []; + var width = core.floors[floorId].width; + var height = core.floors[floorId].height; + + // @ts-ignore + if (!noCache && core.status[name + 'maps'][floorId]) + // @ts-ignore + return core.status[name + 'maps'][floorId]; + + var arr: number[][] = + main.mode == 'editor' && + // @ts-ignore + !(window.editor && editor.uievent && editor.uievent.isOpen) + ? // @ts-ignore + core.cloneArray(editor[name + 'map']) + : null; + if (arr == null) + // @ts-ignore + arr = core.cloneArray(core.floors[floorId][name + 'map'] || []); + + if (isLoopMap(floorId) && window.flags) { + flags[`loop_${floorId}`] ??= 0; + arr.forEach(v => { + slide(v, flags[`loop_${floorId}`] % width); + }); + } + + for (var y = 0; y < height; ++y) { + if (arr[y] == null) arr[y] = Array(width).fill(0); + } + // @ts-ignore + (core.getFlag('__' + name + 'v__', {})[floorId] || []).forEach( + // @ts-ignore + function (one) { + arr[one[1]][one[0]] = one[2] || 0; + } + ); + // @ts-ignore + (core.getFlag('__' + name + 'd__', {})[floorId] || []).forEach( + // @ts-ignore + function (one) { + arr[one[1]][one[0]] = 0; + } + ); + if (main.mode == 'editor') { + for (var x = 0; x < width; x++) { + for (var y = 0; y < height; y++) { + // @ts-ignore + arr[y][x] = arr[y][x].idnum || arr[y][x] || 0; + } + } + } + // @ts-ignore + if (core.status[name + 'maps']) + // @ts-ignore + core.status[name + 'maps'][floorId] = arr; + return arr; + }; +} diff --git a/src/plugin/game/range.ts b/src/plugin/game/range.ts index c858933..497d1f7 100644 --- a/src/plugin/game/range.ts +++ b/src/plugin/game/range.ts @@ -1,3 +1,5 @@ +import { has } from './utils'; + type RangeScanFn> = ( collection: Range, data: any @@ -77,8 +79,8 @@ Range.registerRangeType( return list.filter(v => { return ( - core.has(v.x) && - core.has(v.y) && + has(v.x) && + has(v.y) && Math.abs(v.x - x) <= r && Math.abs(v.y - y) <= r ); @@ -87,8 +89,8 @@ Range.registerRangeType( (col, { x, y, d }, item) => { const r = Math.floor(d / 2); return ( - core.has(item.x) && - core.has(item.y) && + has(item.x) && + has(item.y) && Math.abs(item.x - x) <= r && Math.abs(item.y - y) <= r ); diff --git a/src/plugin/game/removeMap.js b/src/plugin/game/removeMap.ts similarity index 80% rename from src/plugin/game/removeMap.js rename to src/plugin/game/removeMap.ts index 69f7f10..0cbcabd 100644 --- a/src/plugin/game/removeMap.js +++ b/src/plugin/game/removeMap.ts @@ -1,14 +1,20 @@ /// -export function removeMaps(fromId, toId, force) { +export function removeMaps( + fromId: FloorIds, + toId: FloorIds, + force: boolean = false +) { toId = toId || fromId; var fromIndex = core.floorIds.indexOf(fromId), toIndex = core.floorIds.indexOf(toId); if (toIndex < 0) toIndex = core.floorIds.length - 1; - flags.__visited__ = flags.__visited__ || {}; - flags.__removed__ = flags.__removed__ || []; - flags.__disabled__ = flags.__disabled__ || {}; - flags.__leaveLoc__ = flags.__leaveLoc__ || {}; + // @ts-ignore + flags.__visited__ ??= {}; + flags.__removed__ ??= []; + flags.__disabled__ ??= {}; + // @ts-ignore + flags.__leaveLoc__ ??= {}; flags.__forceDelete__ ??= {}; let deleted = false; for (var i = fromIndex; i <= toIndex; ++i) { @@ -36,11 +42,11 @@ export function removeMaps(fromId, toId, force) { deleted = true; } if (deleted && !main.replayChecking) { - Mota.Plugin.require('fly').splitArea(); + Mota.Plugin.require('fly_r').splitArea(); } } -export function deleteFlags(floorId) { +export function deleteFlags(floorId: FloorIds) { delete flags[`jump_${floorId}`]; delete flags[`inte_${floorId}`]; delete flags[`loop_${floorId}`]; @@ -51,7 +57,7 @@ export function deleteFlags(floorId) { // 恢复楼层 // core.plugin.removeMap.resumeMaps("MT1", "MT300") 恢复MT1~MT300之间的全部层 // core.plugin.removeMap.resumeMaps("MT10") 只恢复MT10层 -export function resumeMaps(fromId, toId) { +export function resumeMaps(fromId: FloorIds, toId: FloorIds) { toId = toId || fromId; var fromIndex = core.floorIds.indexOf(fromId), toIndex = core.floorIds.indexOf(toId); @@ -65,19 +71,21 @@ export function resumeMaps(fromId, toId) { flags.__forceDelete__[floorId] ) continue; + // @ts-ignore flags.__removed__ = flags.__removed__.filter(f => { return f != floorId; }); + // @ts-ignore core.status.maps[floorId] = core.loadFloor(floorId); } } // 分区砍层相关 -var inAnyPartition = floorId => { +var inAnyPartition = (floorId: FloorIds) => { var inPartition = false; (core.floorPartitions || []).forEach(floor => { var fromIndex = core.floorIds.indexOf(floor[0]); - var toIndex = core.floorIds.indexOf(floor[1]); + var toIndex = core.floorIds.indexOf(floor[1]!); var index = core.floorIds.indexOf(floorId); if (fromIndex < 0 || index < 0) return; if (toIndex < 0) toIndex = core.floorIds.length - 1; @@ -87,29 +95,19 @@ var inAnyPartition = floorId => { }; // 分区砍层 -export function autoRemoveMaps(floorId) { +export function autoRemoveMaps(floorId: FloorIds) { if (main.mode != 'play' || !inAnyPartition(floorId)) return; // 根据分区信息自动砍层与恢复 (core.floorPartitions || []).forEach(floor => { var fromIndex = core.floorIds.indexOf(floor[0]); - var toIndex = core.floorIds.indexOf(floor[1]); + var toIndex = core.floorIds.indexOf(floor[1]!); var index = core.floorIds.indexOf(floorId); if (fromIndex < 0 || index < 0) return; if (toIndex < 0) toIndex = core.floorIds.length - 1; if (index >= fromIndex && index <= toIndex) { - core.plugin.removeMap.resumeMaps( - core.floorIds[fromIndex], - core.floorIds[toIndex] - ); + resumeMaps(core.floorIds[fromIndex], core.floorIds[toIndex]); } else { removeMaps(core.floorIds[fromIndex], core.floorIds[toIndex]); } }); } - -core.plugin.removeMap = { - removeMaps, - deleteFlags, - resumeMaps, - autoRemoveMaps -}; diff --git a/src/plugin/game/replay.js b/src/plugin/game/replay.js deleted file mode 100644 index c63e634..0000000 --- a/src/plugin/game/replay.js +++ /dev/null @@ -1,122 +0,0 @@ -/// - -import { studySkill, canStudySkill } from './study'; - -const replayableSettings = ['autoSkill']; - -let cliping = false; -let startIndex = 0; - -export function ready() {} - -export function readyClip() { - cliping = true; - return (startIndex = core.status.route.length - 1); -} - -export function clip(...replace) { - if (!cliping) return; - cliping = false; - - core.status.route.splice(startIndex); - core.status.route.push(...replace); -} - -// 注册修改设置的录像操作 -core.registerReplayAction('settings', name => { - if (!name.startsWith('set:')) return false; - const [, setting, value] = name.split(':'); - const v = eval(value); - if (typeof v !== 'boolean') return false; - if (!replayableSettings.includes(setting)) return false; - flags[setting] = v; - core.status.route.push(name); - core.replay(); - return true; -}); - -core.registerReplayAction('upgradeSkill', name => { - if (!name.startsWith('skill:')) return false; - const skill = parseInt(name.slice(6)); - core.plugin.skillTree.upgradeSkill(skill); - core.status.route.push(name); - core.replay(); - return true; -}); - -core.registerReplayAction('study', name => { - // todo - // if (!name.startsWith('study:')) return false; - // const [num, x, y] = name - // .slice(6) - // .split(',') - // .map(v => parseInt(v)); - // if (!canStudySkill(num)) return false; - // const id = core.getBlockId(x, y); - // const enemy = core.getEnemyInfo(id, void 0, x, y); - // if (!enemy.special.includes(num)) return false; - // studySkill(enemy, num); - // core.status.route.push(name); - // core.replay(); - // return true; -}); - -// 商店 -let shopOpened = false; -let openedShopId = ''; -core.registerReplayAction('openShop', name => { - if (!name.startsWith('openShop:')) return false; - if (shopOpened) return false; - openedShopId = name.slice(9); - shopOpened = true; - core.status.route.push(name); - core.replay(); - return true; -}); - -core.registerReplayAction('buy', name => { - if (!name.startsWith('buy:') && !name.startsWith('sell:')) return false; - if (!shopOpened) return false; - if (!openedShopId) return false; - const [type, id, num] = name - .split(':') - .map(v => (/^\d+$/.test(v) ? parseInt(v) : v)); - const shop = core.status.shops[openedShopId]; - const item = shop.choices.find(v => v.id === id); - if (!item) return false; - flags.itemShop ??= {}; - flags.itemShop[openedShopId] ??= {}; - flags.itemShop[openedShopId][id] ??= 0; - if (num > item.number - flags.itemShop[openedShopId][id]) { - return false; - } - let cost = 0; - if (type === 'buy') { - cost = item.money * num; - } else { - cost = -item.sell * num; - } - if (cost > core.status.hero.money) return false; - core.status.hero.money -= cost; - flags.itemShop[openedShopId][id] += type === 'buy' ? num : -num; - core.addItem(id, type === 'buy' ? num : -num); - core.status.route.push(name); - core.replay(); - return true; -}); - -core.registerReplayAction('closeShop', name => { - if (name !== 'closeShop') return false; - if (!shopOpened) return false; - shopOpened = false; - openedShopId = ''; - core.status.route.push(name); - core.replay(); - return true; -}); - -core.plugin.replay = { - ready, - readyClip, - clip -}; diff --git a/src/plugin/game/replay.ts b/src/plugin/game/replay.ts new file mode 100644 index 0000000..f600083 --- /dev/null +++ b/src/plugin/game/replay.ts @@ -0,0 +1,121 @@ +/// + +import { upgradeSkill } from './skillTree'; + +const replayableSettings = ['autoSkill']; + +let cliping = false; +let startIndex = 0; + +export function ready() {} + +export function readyClip() { + cliping = true; + return (startIndex = core.status.route.length - 1); +} + +export function clip(...replace: string[]) { + if (!cliping) return; + cliping = false; + + core.status.route.splice(startIndex); + core.status.route.push(...replace); +} + +export function init() { + // 注册修改设置的录像操作 + core.registerReplayAction('settings', name => { + if (!name.startsWith('set:')) return false; + const [, setting, value] = name.split(':'); + const v = eval(value); + if (typeof v !== 'boolean') return false; + if (!replayableSettings.includes(setting)) return false; + flags[setting] = v; + core.status.route.push(name); + core.replay(); + return true; + }); + + core.registerReplayAction('upgradeSkill', name => { + if (!name.startsWith('skill:')) return false; + const skill = parseInt(name.slice(6)); + upgradeSkill(skill); + core.status.route.push(name); + core.replay(); + return true; + }); + + core.registerReplayAction('study', name => { + // todo + // if (!name.startsWith('study:')) return false; + // const [num, x, y] = name + // .slice(6) + // .split(',') + // .map(v => parseInt(v)); + // if (!canStudySkill(num)) return false; + // const id = core.getBlockId(x, y); + // const enemy = core.getEnemyInfo(id, void 0, x, y); + // if (!enemy.special.includes(num)) return false; + // studySkill(enemy, num); + // core.status.route.push(name); + // core.replay(); + return true; + }); + + // 商店 + let shopOpened = false; + let openedShopId = ''; + core.registerReplayAction('openShop', name => { + if (!name.startsWith('openShop:')) return false; + if (shopOpened) return false; + openedShopId = name.slice(9); + shopOpened = true; + core.status.route.push(name); + core.replay(); + return true; + }); + + core.registerReplayAction('buy', name => { + if (!name.startsWith('buy:') && !name.startsWith('sell:')) return false; + if (!shopOpened) return false; + if (!openedShopId) return false; + const [type, id, num] = name + .split(':') + .map(v => (/^\d+$/.test(v) ? parseInt(v) : v)); + const shop = core.status.shops[openedShopId] as ItemShopEvent; + const item = shop.choices.find(v => v.id === id); + if (!item) return false; + flags.itemShop ??= {}; + flags.itemShop[openedShopId] ??= {}; + flags.itemShop[openedShopId][id] ??= 0; + if ((num as number) > item.number - flags.itemShop[openedShopId][id]) { + return false; + } + let cost = 0; + if (type === 'buy') { + cost = parseInt(item.money) * (num as number); + } else { + cost = -item.sell * (num as number); + } + if (cost > core.status.hero.money) return false; + core.status.hero.money -= cost; + flags.itemShop[openedShopId][id] += type === 'buy' ? num : -num; + core.addItem( + id as AllIdsOf<'items'>, + (type === 'buy' ? num : -num) as number + ); + core.status.route.push(name); + core.replay(); + return true; + }); + + core.registerReplayAction('closeShop', name => { + if (name !== 'closeShop') return false; + if (!shopOpened) return false; + shopOpened = false; + openedShopId = ''; + core.status.route.push(name); + core.replay(); + return true; + }); +} diff --git a/src/plugin/game/shop.js b/src/plugin/game/shop.ts similarity index 62% rename from src/plugin/game/shop.js rename to src/plugin/game/shop.ts index 9dff3c6..c268747 100644 --- a/src/plugin/game/shop.js +++ b/src/plugin/game/shop.ts @@ -1,27 +1,29 @@ -/// - -const { openItemShop } = core.plugin.gameUi; - -export function openShop(shopId, noRoute) { - var shop = core.status.shops[shopId]; +export function openShop(shopId: string, noRoute: boolean) { + const shop = core.status.shops[shopId] as ItemShopEvent; // Step 1: 检查能否打开此商店 - if (!this.canOpenShop(shopId)) { + if (!canOpenShop(shopId)) { core.drawTip('该商店尚未开启'); return false; } // Step 3: 检查道具商店 or 公共事件 if (shop.item) { - if (openItemShop) openItemShop(shopId); + Mota.r(() => { + if (!core.isReplaying()) { + Mota.require('var', 'mainUi').open('shop', { + shopId: shopId + }); + } + }); return; } return true; } /// 是否访问过某个快捷商店 -export function isShopVisited(id) { +export function isShopVisited(id: string) { flags.__shops__ ??= {}; - var shops = core.getFlag('__shops__'); + var shops = core.getFlag('__shops__'); if (!shops[id]) shops[id] = {}; return shops[id].visited; } @@ -29,25 +31,24 @@ export function isShopVisited(id) { /// 当前应当显示的快捷商店列表 export function listShopIds() { return Object.keys(core.status.shops).filter(id => { - return ( - core.plugin.shop.isShopVisited(id) || - !core.status.shops[id].mustEnable - ); + // @ts-ignore + return isShopVisited(id) || !core.status.shops[id].mustEnable; }); } /// 是否能够打开某个商店 -export function canOpenShop(id) { - if (this.isShopVisited(id)) return true; +export function canOpenShop(id: string) { + if (isShopVisited(id)) return true; var shop = core.status.shops[id]; + // @ts-ignore if (shop.item || shop.commonEvent || shop.mustEnable) return false; return true; } /// 启用或禁用某个快捷商店 -export function setShopVisited(id, visited) { +export function setShopVisited(id: string, visited: boolean) { if (!core.hasFlag('__shops__')) core.setFlag('__shops__', {}); - var shops = core.getFlag('__shops__'); + var shops = core.getFlag('__shops__'); if (!shops[id]) shops[id] = {}; if (visited) shops[id].visited = true; else delete shops[id].visited; @@ -63,12 +64,3 @@ export function canUseQuickShop() { return '当前楼层不能使用快捷商店。'; return null; } - -core.plugin.shop = { - openShop, - isShopVisited, - listShopIds, - canOpenShop, - setShopVisited, - canUseQuickShop -}; diff --git a/src/plugin/game/skills.js b/src/plugin/game/skill.ts similarity index 96% rename from src/plugin/game/skills.js rename to src/plugin/game/skill.ts index 4729a55..fd6b232 100644 --- a/src/plugin/game/skills.js +++ b/src/plugin/game/skill.ts @@ -1,4 +1,4 @@ -/// +// @ts-nocheck // 所有的主动技能效果 var ignoreInJump = { @@ -19,8 +19,7 @@ var ignoreInJump = { ] }; -/** @type {FloorIds[]} */ -export const jumpIgnoreFloor = [ +export const jumpIgnoreFloor: FloorIds[] = [ 'MT31', 'snowTown', 'MT36', @@ -178,8 +177,3 @@ export function jumpSkill() { return { x: x, y: y }; } } - -core.plugin.skillEffects = { - jumpSkill, - jumpIgnoreFloor -}; diff --git a/src/plugin/game/skillTree.js b/src/plugin/game/skillTree.ts similarity index 89% rename from src/plugin/game/skillTree.js rename to src/plugin/game/skillTree.ts index bcb0848..2882517 100644 --- a/src/plugin/game/skillTree.js +++ b/src/plugin/game/skillTree.ts @@ -1,14 +1,11 @@ /// -/** - * @type {number[]} - */ -let levels = []; +let levels: number[] = []; /** * @type {Record} */ -const skills = { +export const skills: Record = { chapter1: [ { index: 0, @@ -195,13 +192,11 @@ const skills = { ] }; -core.plugin.skills = skills; - export function resetSkillLevel() { levels = []; } -export function getSkillFromIndex(index) { +export function getSkillFromIndex(index: number) { for (const [, skill] of Object.entries(skills)) { const s = skill.find(v => v.index === index); if (s) return s; @@ -212,16 +207,21 @@ export function getSkillFromIndex(index) { * 获取技能等级 * @param {number} skill */ -export function getSkillLevel(skill) { +export function getSkillLevel(skill: number) { return (levels[skill] ??= 0); } -export function getSkillConsume(skill) { +export function getSkillConsume(skill: number) { return eval( - getSkillFromIndex(skill).consume.replace(/level(:\d+)?/g, (str, $1) => { - if ($1) return `core.plugin.skillTree.getSkillLevel(${$1})`; - else return `core.plugin.skillTree.getSkillLevel(${skill})`; - }) + getSkillFromIndex(skill)?.consume.replace( + /level(:\d+)?/g, + (str, $1) => { + if ($1) + return `Mota.Plugin.require('skillTree_g').getSkillLevel(${$1})`; + else + return `Mota.Plugin.require('skillTree_g').getSkillLevel(${skill})`; + } + ) ?? '' ); } @@ -232,17 +232,16 @@ export function openTree() { /** * 能否升级某个技能 - * @param {number} skill */ -export function canUpgrade(skill) { - const consume = core.plugin.skillTree.getSkillConsume(skill); +export function canUpgrade(skill: number) { + const consume = getSkillConsume(skill); if (consume > core.status.hero.mdef) return false; - const level = core.plugin.skillTree.getSkillLevel(skill); + const level = getSkillLevel(skill); const s = getSkillFromIndex(skill); - if (level === s.max) return false; - const front = s.front; + if (level === s?.max) return false; + const front = s?.front ?? []; for (const [skill, level] of front) { - if (core.plugin.skillTree.getSkillLevel(skill) < level) return false; + if (getSkillLevel(skill) < level) return false; } return true; } @@ -251,7 +250,7 @@ export function canUpgrade(skill) { * 实际升级效果 * @param {number} skill */ -export function upgradeSkill(skill) { +export function upgradeSkill(skill: number) { if (!canUpgrade(skill)) return false; switch (skill) { case 0: // 力量 +2攻击 @@ -302,17 +301,6 @@ export function saveSkillTree() { return levels.slice(); } -export function loadSkillTree(data) { +export function loadSkillTree(data: number[]) { levels = data ?? []; } - -core.plugin.skillTree = { - getSkillConsume, - getSkillFromIndex, - getSkillLevel, - saveSkillTree, - loadSkillTree, - upgradeSkill, - openTree, - resetSkillLevel -}; diff --git a/src/plugin/game/study.ts b/src/plugin/game/study.ts index 8a5e533..94798e2 100644 --- a/src/plugin/game/study.ts +++ b/src/plugin/game/study.ts @@ -12,7 +12,8 @@ const cannotStudy = [9, 12, 14, 15, 24]; export function canStudySkill(number: number) { const s = (core.status.hero.special ??= { num: [], last: [] }); - if (core.plugin.skillTree.getSkillLevel(11) === 0) return false; + if (Mota.Plugin.require('skillTree_g').getSkillLevel(11) === 0) + return false; if (s.num.length >= 1) return false; if (s.num.includes(number)) return false; if (cannotStudy.includes(number)) return false; diff --git a/src/plugin/game/towerBoss.js b/src/plugin/game/towerBoss.ts similarity index 98% rename from src/plugin/game/towerBoss.js rename to src/plugin/game/towerBoss.ts index 07b882f..b2bfbb9 100644 --- a/src/plugin/game/towerBoss.js +++ b/src/plugin/game/towerBoss.ts @@ -1,4 +1,4 @@ -/// +// @ts-nocheck import { clip } from './replay.js'; // 1000多行,改不动了,原来什么样就什么样吧 @@ -11,7 +11,7 @@ var stage = 1, boomLocs = [], // 随机轰炸 heroHp; // 初始化 -function initTowerBoss() { +export function initTowerBoss() { stage = 1; hp = 10000; seconds = 0; @@ -496,7 +496,7 @@ function intelligentArrow(fromSelf) { damaged[loc + direction] = true; core.drawHeroAnimate('hand'); core.status.hero.hp -= 1000; - Mota.Plugin.require('pop').addPop( + Mota.Plugin.require('pop_r').addPop( x * 32 + 16, y * 32 + 16, -1000 @@ -515,7 +515,7 @@ function intelligentArrow(fromSelf) { damaged[loc + direction] = true; core.drawHeroAnimate('hand'); core.status.hero.hp -= 1000; - Mota.Plugin.require('pop').addPop( + Mota.Plugin.require('pop_r').addPop( x * 32 + 16, y * 32 + 16, -1000 @@ -645,7 +645,7 @@ function icyMomentem() { if (x == locs[index][0] && y == locs[index][1]) { core.drawHeroAnimate('hand'); core.status.hero.hp -= 5000; - Mota.Plugin.require('pop').addPop( + Mota.Plugin.require('pop_r').addPop( x * 32 + 16, y * 32 + 16, -5000 @@ -824,7 +824,7 @@ function getThunderDamage(x, y, power) { hy = core.status.hero.loc.y; if (Math.abs(hx - x) <= 1 && Math.abs(hy - y) <= 1) { core.status.hero.hp -= 3000 * power; - Mota.Plugin.require('pop').addPop( + Mota.Plugin.require('pop_r').addPop( x * 32 + 16, y * 32 + 16, -3000 * power @@ -992,7 +992,7 @@ function ballThunder() { ) { damaged[i] = true; core.status.hero.hp -= 3000; - Mota.Plugin.require('pop').addPop( + Mota.Plugin.require('pop_r').addPop( x * 32 + 16, y * 32 + 16, -3000 @@ -1502,7 +1502,7 @@ function boomingAnimate() { hy = core.status.hero.loc.y; if (loc[0] == hx && loc[1] == hy) { core.status.hero.hp -= 3000; - Mota.Plugin.require('pop').addPop( + Mota.Plugin.require('pop_r').addPop( x * 32 + 16, y * 32 + 16, -3000 @@ -1545,7 +1545,7 @@ function lineDamage(x1, y1, x2, y2, damage) { n2 = ((y2 - y1) / (x2 - x1)) * (loc2[0] - x1) + y1 - loc2[1]; if (n1 * n2 <= 0) { core.status.hero.hp -= damage; - Mota.Plugin.require('pop').addPop( + Mota.Plugin.require('pop_r').addPop( x * 32 + 16, y * 32 + 16, -damage @@ -1569,7 +1569,7 @@ function lineDamage(x1, y1, x2, y2, damage) { n2 = ((y2 - y1) / (x2 - x1)) * (loc2[0] - x1) + y1 - loc2[1]; if (n1 * n2 <= 0) { core.status.hero.hp -= damage; - Mota.Plugin.require('pop').addPop( + Mota.Plugin.require('pop_r').addPop( x * 32 + 16, y * 32 + 16, -damage @@ -1587,9 +1587,3 @@ function lineDamage(x1, y1, x2, y2, damage) { } } } - -core.plugin.towerBoss = { - initTowerBoss -}; - -export {}; diff --git a/src/plugin/game/ui.js b/src/plugin/game/ui.ts similarity index 73% rename from src/plugin/game/ui.js rename to src/plugin/game/ui.ts index 079d91d..3565bc8 100644 --- a/src/plugin/game/ui.js +++ b/src/plugin/game/ui.ts @@ -1,29 +1,8 @@ -/// -export {}; +// @ts-nocheck -(function () { +export function init() { const { mainUi, fixedUi } = Mota.requireAll('var'); - if (main.replayChecking) - return (core.plugin.gameUi = { - openItemShop: () => 0, - openSkill: () => 0 - }); - - function openItemShop(itemShopId) { - if (!core.isReplaying()) { - Mota.require('var', 'mainUi').open('shop', { - shopId: itemShopId - }); - } - } - - function updateVueStatusBar() { - if (main.replayChecking) return; - const status = Mota.Plugin.require('status'); - status.statusBarStatus.value = !status.statusBarStatus.value; - } - ui.prototype.drawBook = function () { if (!core.isReplaying()) return mainUi.open('book'); }; @@ -86,14 +65,11 @@ export {}; core.dom.toolBar.style.display = 'none'; } }; +} - function openSkill() { - if (core.isReplaying()) return; - mainUi.open('skill'); - } - - core.plugin.gameUi = { - openItemShop, - openSkill - }; -})(); +function updateVueStatusBar() { + Mota.r(() => { + const status = Mota.require('var', 'status'); + status.value = !status.value; + }); +} diff --git a/src/plugin/game/utils.ts b/src/plugin/game/utils.ts index 1df59f1..e279f00 100644 --- a/src/plugin/game/utils.ts +++ b/src/plugin/game/utils.ts @@ -169,18 +169,3 @@ export function findDir(from: Loc, to: Loc): Dir2 | 'none' { })?.[0] as Dir2) ?? 'none' ); } - -declare global { - interface GamePluginUtils { - ofDir: typeof ofDir; - } -} - -core.plugin.utils = { - slide, - backDir, - has, - maxGameScale, - ofDir -}; -core.has = has; diff --git a/src/plugin/mark.ts b/src/plugin/mark.ts index 821ce65..631c2c2 100644 --- a/src/plugin/mark.ts +++ b/src/plugin/mark.ts @@ -35,8 +35,8 @@ const marked: MarkInfo[] = []; */ export function markEnemy(id: EnemyIds) { if (hasMarkedEnemy(id)) return; - const { Enemy } = core.plugin.damage; - const enemy = new Enemy(core.material.enemys[id]); + const { DamageEnemy } = Mota.Plugin.require('damage_g'); + const enemy = new DamageEnemy(core.material.enemys[id]); enemy.calAttribute(); enemy.getRealInfo(); @@ -44,7 +44,7 @@ export function markEnemy(id: EnemyIds) { id, enemy, mode: 0b011111, - lastAtk: core.plugin.hero.getHeroStatusOn('atk', 'empty'), + lastAtk: Mota.Plugin.require('hero_g').getHeroStatusOn('atk', 'empty'), lastDamage: enemy.calDamage().damage, status: 0b0, update: ref(true) @@ -66,9 +66,10 @@ export function unmarkEnemy(id: EnemyIds) { } export function checkMarkedEnemy() { + const { getHeroStatusOn } = Mota.Plugin.require('hero_g'); marked.forEach(v => { const { id, enemy, mode, lastAtk, lastDamage, markDamage } = v; - const atk = core.plugin.hero.getHeroStatusOn('atk', 'empty'); + const atk = getHeroStatusOn('atk', 'empty'); let tip = 0; if (mode & 0b11110) { const damage = enemy.calDamage().damage; diff --git a/src/plugin/shadow/shadow.ts b/src/plugin/shadow/shadow.ts index 1e30105..58c2402 100644 --- a/src/plugin/shadow/shadow.ts +++ b/src/plugin/shadow/shadow.ts @@ -36,26 +36,11 @@ export interface Light { _offset?: Loc; } -export default function init() { +export function init() { core.registerAnimationFrame('shadow', true, () => { if (!needRefresh) return; drawShadow(); }); - - return { - initShadowCanvas, - drawShadow, - addLight, - removeLight, - setLight, - setShadowNodes, - setBackground, - animateLight, - transitionLight, - moveLightAs, - getAllLights, - refreshLight - }; } let canvas: HTMLCanvasElement; diff --git a/src/plugin/ui/equipbox.tsx b/src/plugin/ui/equipbox.tsx index e29c9ad..d9cb668 100644 --- a/src/plugin/ui/equipbox.tsx +++ b/src/plugin/ui/equipbox.tsx @@ -59,13 +59,14 @@ export function getNowStatus(nowEquip?: Equip, onCol: boolean = false) { 'hpmax', 'money' ] as (keyof SelectType)[]; + const { getHeroStatusOn } = Mota.Plugin.require('hero_g'); return (
{toShow.map(v => { let status: string; if (v === 'lv') status = core.getLvName() ?? ''; - else status = core.plugin.hero.getHeroStatusOn(v)?.toString(); + else status = getHeroStatusOn(v)?.toString(); let add = 0; if (has(nowEquip)) { diff --git a/src/plugin/ui/fixed.ts b/src/plugin/ui/fixed.ts index ef261e9..045a294 100644 --- a/src/plugin/ui/fixed.ts +++ b/src/plugin/ui/fixed.ts @@ -29,7 +29,7 @@ export function getDetailedEnemy( return typeof func === 'string' ? func : func(enemy); }; const special: [string, string, string][] = enemy.enemy.special.map(vv => { - const s = core.plugin.special[vv]; + const s = Mota.Plugin.require('special_g').special[vv]; return [ fromFunc(s.name, enemy.enemy), fromFunc(s.desc, enemy.enemy), diff --git a/src/plugin/utils.ts b/src/plugin/utils.ts index 8c2ff00..f66476b 100644 --- a/src/plugin/utils.ts +++ b/src/plugin/utils.ts @@ -225,6 +225,7 @@ export async function doByInterval( /** * 更改一个本地存储 + * @deprecated * @param name 要更改的信息 * @param fn 更改时执行的函数 * @param defaultValue 如果不存在时获取的默认值 @@ -287,7 +288,8 @@ export function spliceBy(arr: T[], from: T): T[] { } export async function triggerFullscreen(full: boolean) { - const { maxGameScale } = core.plugin.utils; + if (!Mota.Plugin.inited) return; + const { maxGameScale } = Mota.Plugin.require('utils_g'); if (!!document.fullscreenElement && !full) { await document.exitFullscreen(); requestAnimationFrame(() => { diff --git a/src/types/control.d.ts b/src/types/control.d.ts index 21fd83f..2ae13d4 100644 --- a/src/types/control.d.ts +++ b/src/types/control.d.ts @@ -1068,6 +1068,9 @@ interface Control { * 屏幕分辨率改变后执行的函数 */ resize(): void; + + _drawHero_updateViewport(x: number, y: number, offset: Loc): void; + _moveAction_moving(callback: () => void): void; } declare const control: new () => Control; diff --git a/src/types/core.d.ts b/src/types/core.d.ts index 8d8265c..08555bc 100644 --- a/src/types/core.d.ts +++ b/src/types/core.d.ts @@ -1062,11 +1062,6 @@ interface Core extends Pick { */ readonly actions: Actions; - /** - * 游戏的插件模块 - */ - readonly plugin: PluginDeclaration; - /** * 进行游戏初始化 * @param coreData 初始化信息 @@ -1098,8 +1093,7 @@ type CoreMixin = Core & Forward & Forward & Forward & - Forward & - Forward; + Forward; interface MainStyle extends Readonly { /** diff --git a/src/types/enemy.d.ts b/src/types/enemy.d.ts index ed71c57..9b54a3a 100644 --- a/src/types/enemy.d.ts +++ b/src/types/enemy.d.ts @@ -272,6 +272,8 @@ interface Enemys { floorId?: FloorIds, dir?: Dir | 'none' | (Dir | 'none')[] ): boolean; + + getCurrentEnemys(floorId: FloorIds): any[]; } declare const enemys: new () => Enemys; diff --git a/src/types/event.d.ts b/src/types/event.d.ts index 6d3f47f..1110d1b 100644 --- a/src/types/event.d.ts +++ b/src/types/event.d.ts @@ -758,11 +758,16 @@ interface Events extends EventData { */ tryUseItem(itemId: ItemIdOf<'tools' | 'constants'>): void; + beforeBattle(): boolean; + afterBattle(enemy: DamageEnemy, x?: number, y?: number): void; + _sys_battle(data: Block, callback?: () => void): void; _action_battle(data: any, x?: number, y?: number, prefix?: any): void; __action_getLoc(data: any, x?: number, y?: number, prefix?: any): any; + + _changeFloor_beforeChange(info: any, callback: () => void): void; } declare const events: new () => Events; diff --git a/src/types/map.d.ts b/src/types/map.d.ts index cddf381..3976321 100644 --- a/src/types/map.d.ts +++ b/src/types/map.d.ts @@ -84,6 +84,10 @@ interface Block = Exclude> { * 门信息 */ doorInfo?: DoorInfo; + + data?: any; + script?: string; + event?: MotaEvent; }; } diff --git a/src/types/util.d.ts b/src/types/util.d.ts index ff9ebe4..2cf0231 100644 --- a/src/types/util.d.ts +++ b/src/types/util.d.ts @@ -713,7 +713,9 @@ type MotaTrigger = | 'openDoor' | 'ski' | 'custom' - | 'getItem'; + | 'getItem' + | 'changeFloor' + | 'null'; /** * 切换楼层的目标坐标 diff --git a/src/ui/fixed.vue b/src/ui/fixed.vue index f344e4a..b035c1a 100644 --- a/src/ui/fixed.vue +++ b/src/ui/fixed.vue @@ -83,7 +83,7 @@ const special = (() => { }; const show = s.slice(0, 2).map(v => { - const s = core.plugin.special[v]; + const s = Mota.Plugin.require('special_g').specials[v]; return [fromFunc(s.name, enemy.enemy), s.color]; }); if (s.length > 2) show.push(['...', 'white']); diff --git a/src/ui/skill.vue b/src/ui/skill.vue index f332b54..f8ba6fe 100644 --- a/src/ui/skill.vue +++ b/src/ui/skill.vue @@ -58,7 +58,7 @@ const content = computed(() => { .join('') .replace( /level:(\d+)/g, - 'core.plugin.skillTree.getSkillLevel($1)' + 'Mota.Plugin.require("skillTree_g").getSkillLevel($1)' ) + '`' ); diff --git a/src/ui/skillTree.vue b/src/ui/skillTree.vue index 4ae6292..09e0633 100644 --- a/src/ui/skillTree.vue +++ b/src/ui/skillTree.vue @@ -89,6 +89,8 @@ const props = defineProps<{ ui: GameUi; }>(); +const skillTree = Mota.Plugin.require('skillTree_g'); + let canvas: HTMLCanvasElement; let ctx: CanvasRenderingContext2D; @@ -103,9 +105,11 @@ const chapterDict = { flags.skillTree ??= 0; -const chapterList = Object.keys(core.plugin.skills) as Chapter[]; +const s = Mota.Plugin.require('skillTree_g').skills; -selected.value = core.plugin.skills[chapterList[flags.skillTree]][0].index; +const chapterList = Object.keys(s) as Chapter[]; + +selected.value = s[chapterList[flags.skillTree]][0].index; chapter.value = chapterList[flags.skillTree]; watch(selected, draw); @@ -115,20 +119,19 @@ const mdef = ref(core.status.hero.mdef); const skill = computed(() => { update.value; - return core.plugin.skillTree.getSkillFromIndex(selected.value); + return skillTree.getSkillFromIndex(selected.value); }); const skills = computed(() => { - return core.plugin.skills[chapter.value]; + return s[chapter.value]; }); const desc = computed(() => { return eval( '`' + splitText(skill.value.desc).replace(/level(:\d+)?/g, (str, $1) => { - if ($1) return `core.plugin.skillTree.getSkillLevel(${$1})`; - else - return `core.plugin.skillTree.getSkillLevel(${skill.value.index})`; + if ($1) return `skillTree.getSkillLevel(${$1})`; + else return `skillTree.getSkillLevel(${skill.value.index})`; }) + '`' ); @@ -143,9 +146,9 @@ const effect = computed(() => { .join('') .replace(/level(:\d+)?/g, (str, $1) => { if ($1) - return `(core.plugin.skillTree.getSkillLevel(${$1}) + ${v})`; + return `(skillTree.getSkillLevel(${$1}) + ${v})`; else - return `(core.plugin.skillTree.getSkillLevel(${skill.value.index}) + ${v})`; + return `(skillTree.getSkillLevel(${skill.value.index}) + ${v})`; }) + '`' ); @@ -163,20 +166,20 @@ const dict = computed(() => { const front = computed(() => { return skill.value.front.map(v => { - return `${ - core.plugin.skillTree.getSkillLevel(v[0]) >= v[1] ? 'a' : 'b' - }${v[1]}级 ${skills.value[dict.value[v[0]]].title}`; + return `${skillTree.getSkillLevel(v[0]) >= v[1] ? 'a' : 'b'}${ + v[1] + }级 ${skills.value[dict.value[v[0]]].title}`; }); }); const consume = computed(() => { update.value; - return core.plugin.skillTree.getSkillConsume(selected.value); + return skillTree.getSkillConsume(selected.value); }); const level = computed(() => { update.value; - return core.plugin.skillTree.getSkillLevel(selected.value); + return skillTree.getSkillLevel(selected.value); }); function exit() { @@ -204,9 +207,9 @@ function draw() { ctx.lineTo( ...(s.loc.map(v => (v * 2 - 1) * per + per / 2) as LocArr) ); - if (core.plugin.skillTree.getSkillLevel(s.index) < v.front[i][1]) + if (skillTree.getSkillLevel(s.index) < v.front[i][1]) ctx.strokeStyle = '#aaa'; - else if (core.plugin.skillTree.getSkillLevel(s.index) === s.max) + else if (skillTree.getSkillLevel(s.index) === s.max) ctx.strokeStyle = '#ff0'; else ctx.strokeStyle = '#0f8'; ctx.lineWidth = devicePixelRatio; @@ -215,7 +218,7 @@ function draw() { }); skills.value.forEach(v => { const [x, y] = v.loc.map(v => v * 2 - 1); - const level = core.plugin.skillTree.getSkillLevel(v.index); + const level = skillTree.getSkillLevel(v.index); // 技能图标 ctx.save(); ctx.lineWidth = per * 0.06; @@ -256,7 +259,7 @@ function click(e: MouseEvent) { } function upgrade(index: number) { - const success = core.plugin.skillTree.upgradeSkill(index); + const success = skillTree.upgradeSkill(index); if (!success) tip('error', '升级失败!'); else { tip('success', '升级成功!'); @@ -296,7 +299,7 @@ function selectChapter(delta: number) { const to = now + delta; if (has(chapterList[to]) && flags.chapter > to) { - selected.value = core.plugin.skills[chapterList[to]][0].index; + selected.value = s[chapterList[to]][0].index; chapter.value = chapterList[to]; update.value = !update.value; flags.skillTree = to; diff --git a/src/ui/statusBar.vue b/src/ui/statusBar.vue index f5257b4..dc73a48 100644 --- a/src/ui/statusBar.vue +++ b/src/ui/statusBar.vue @@ -137,6 +137,8 @@ import { status } from '../plugin/ui/statusBar'; import { isMobile } from '../plugin/use'; import { has } from '../plugin/utils'; +const skillTree = Mota.Plugin.require('skillTree_g'); + const width = ref( isMobile ? window.innerWidth - 60 : window.innerWidth * 0.175 ); @@ -155,7 +157,7 @@ const skill = ref(flags.autoSkill ? '自动切换' : '无'); const up = ref(0); const spring = ref(); const skillOpened = ref(core.getFlag('chapter', 0) > 0); -const studyOpened = ref(core.plugin.skillTree.getSkillLevel(11) > 0); +const studyOpened = ref(skillTree.getSkillLevel(11) > 0); const jumpCnt = ref(); /** * 要展示的勇士属性 @@ -178,9 +180,8 @@ watch(status, update); * 更新显示内容 */ function update() { - if (!core?.plugin?.hero?.getHeroStatusOn) return; toShow.forEach(v => { - hero[v] = core.plugin.hero.getHeroStatusOn(v); + hero[v] = Mota.Plugin.require('hero_g').getHeroStatusOn(v); }); keys[0] = core.itemCount('yellowKey'); keys[1] = core.itemCount('blueKey'); @@ -205,10 +206,12 @@ function update() { spring.value = void 0; } skillOpened.value = core.getFlag('chapter', 0) > 0; - studyOpened.value = core.plugin.skillTree.getSkillLevel(11) > 0; + studyOpened.value = skillTree.getSkillLevel(11) > 0; jumpCnt.value = flags.skill2 && - !core.plugin.skillEffects.jumpIgnoreFloor.includes(core.status.floorId) + !Mota.Plugin.require('skill_g').jumpIgnoreFloor.includes( + core.status.floorId + ) ? 3 - (flags[`jump_${core.status.floorId}`] ?? 0) : void 0; }