refactor: 插件

This commit is contained in:
unanmed 2024-02-01 19:31:49 +08:00
parent ef9a3d6537
commit 325a1e85ec
69 changed files with 1704 additions and 1549 deletions

View File

@ -100,7 +100,7 @@ dam4.png ---- 存档 59
[] 优化各种 ui [] 优化各种 ui
[] 怪物脚下加入阴影 [] 怪物脚下加入阴影
[x] 着色器特效 [x] 着色器特效
[] 完全删除 core.plugin采用 Plugin.register 的形式进行插件编写 [x] 完全删除 core.plugin采用 Plugin.register 的形式进行插件编写
[] 通用 Addon 接口 [] 通用 Addon 接口
[] 完善加载系统 [] 完善加载系统
[] 不同怪物可以在怪物手册中添加一些不同的边框 [] 不同怪物可以在怪物手册中添加一些不同的边框
@ -113,5 +113,5 @@ dam4.png ---- 存档 59
[] 注册可录像操作,比如可以在点击的时候执行,自动计入录像 [] 注册可录像操作,比如可以在点击的时候执行,自动计入录像
[] 机关门显示绑定怪物 [] 机关门显示绑定怪物
[] 自定义状态栏,通过申请空间进行布局 [] 自定义状态栏,通过申请空间进行布局
[] 复写 apirewrite() [x] 复写 apirewrite()
[] 对 vnode 进行简单的包装,提供出显示文字、显示图片等 api 以及修改 css 的 api [] 对 vnode 进行简单的包装,提供出显示文字、显示图片等 api 以及修改 css 的 api

View File

@ -3850,7 +3850,7 @@ isShopVisited_e
/* isShopVisited_e /* isShopVisited_e
default : ['shop1'] default : ['shop1']
allShops : ['IdString_0'] 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]; return [code, Blockly.JavaScript.ORDER_ATOMIC];
*/; */;

View File

@ -1620,7 +1620,8 @@ actions.prototype._keyUpViewMaps = function (keycode) {
////// 快捷商店界面时的点击操作 ////// ////// 快捷商店界面时的点击操作 //////
actions.prototype._clickQuickShop = function (x, y) { 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; if (this._out(x)) return;
var topIndex = var topIndex =
this._HY_ - this._HY_ -
@ -1628,15 +1629,15 @@ actions.prototype._clickQuickShop = function (x, y) {
(core.status.event.ui.offset || 0); (core.status.event.ui.offset || 0);
if (y >= topIndex && y < topIndex + shopIds.length) { if (y >= topIndex && y < topIndex + shopIds.length) {
var shopId = shopIds[y - topIndex]; var shopId = shopIds[y - topIndex];
if (!core.plugin.shop.canOpenShop(shopId)) { if (!shop.canOpenShop(shopId)) {
core.playSound('操作失败'); core.playSound('操作失败');
core.drawTip('当前项尚未开启'); core.drawTip('当前项尚未开启');
return; return;
} }
var message = core.plugin.shop.canUseQuickShop(shopId); var message = shop.canUseQuickShop(shopId);
if (message == null) { if (message == null) {
// core.ui.closePanel(); // core.ui.closePanel();
core.plugin.shop.openShop(shopIds[y - topIndex], false); shop.openShop(shopIds[y - topIndex], false);
} else { } else {
core.playSound('操作失败'); core.playSound('操作失败');
core.drawTip(message); core.drawTip(message);
@ -1657,7 +1658,7 @@ actions.prototype._keyUpQuickShop = function (keycode) {
return; return;
} }
this._selectChoices( this._selectChoices(
core.plugin.shop.listShopIds().length + 1, Mota.Plugin.require('shop_g').listShopIds().length + 1,
keycode, keycode,
this._clickQuickShop this._clickQuickShop
); );

View File

@ -1449,9 +1449,10 @@ control.prototype.checkBlock = function () {
control.prototype._checkBlock_disableQuickShop = function () { control.prototype._checkBlock_disableQuickShop = function () {
// 禁用快捷商店 // 禁用快捷商店
const { setShopVisited } = Mota.Plugin.require('shop_g');
if (core.flags.disableShopOnDamage) { if (core.flags.disableShopOnDamage) {
Object.keys(core.status.shops).forEach(function (shopId) { 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.totalList = core.status.route.concat(list);
core.status.replay.steps = 0; core.status.replay.steps = 0;
core.status.replay.save = []; 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.createCanvas('replay', 0, core._PY_ - 40, core._PX_, 40, 199);
core.setOpacity('replay', 0.6); core.setOpacity('replay', 0.6);
this._replay_drawProgress(); this._replay_drawProgress();

View File

@ -279,7 +279,7 @@ core.prototype.init = async function (coreData, callback) {
this._init_flags(); this._init_flags();
this._init_platform(); this._init_platform();
this._init_others(); this._init_others();
await this._loadPlugin(); await this._loadGameProcess();
var b = main.mode == 'editor'; var b = main.mode == 'editor';
// 初始化画布 // 初始化画布
@ -307,34 +307,31 @@ core.prototype.initSync = function (coreData, callback) {
this._init_flags(); this._init_flags();
this._init_platform(); this._init_platform();
this._init_others(); this._init_others();
this._loadPluginSync(); this._loadGameProcessSync();
core.loader._load(function () { core.loader._load(function () {
core._afterLoadResources(callback); core._afterLoadResources(callback);
}); });
}; };
core.prototype._loadPluginSync = function () { core.prototype._loadGameProcess = async 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 = {};
// 加载插件
if (main.pluginUseCompress) { if (main.pluginUseCompress) {
await main.loadScript(`project/plugin.min.js?v=${main.version}`); await main.loadScript(`project/processG.min.js?v=${main.version}`);
} else { } else {
if (main.mode === 'play') { if (main.mode === 'play') {
await main.loadScript(`src/plugin/game/index.js`, true); await main.loadScript(`src/game/index.ts`, true);
} else { } 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.prototype._init_flags = function () {
core.flags = core.clone(core.data.flags); core.flags = core.clone(core.data.flags);
core.values = core.clone(core.data.values); core.values = core.clone(core.data.values);
@ -580,7 +577,6 @@ core.prototype._init_others = function () {
core.prototype._afterLoadResources = function (callback) { core.prototype._afterLoadResources = function (callback) {
// 初始化地图 // 初始化地图
core.initStatus.maps = core.maps._initMaps();
core.control._setRequestAnimationFrame(); core.control._setRequestAnimationFrame();
// 图片裁剪 // 图片裁剪
(main.splitImages || []).forEach(function (one) { (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(); core.showStartAnimate();
if (callback) callback(); if (callback) callback();
}; };
@ -664,8 +660,9 @@ core.prototype._forwardFunc = function (name, funcname) {
core.prototype.doFunc = function (func, _this) { core.prototype.doFunc = function (func, _this) {
if (typeof func == 'string') { if (typeof func == 'string') {
func = core.plugin[func]; throw new Error('Parameter func must be a function.');
_this = core.plugin; // func = core.plugin[func];
// _this = core.plugin;
} }
return func.apply(_this, Array.prototype.slice.call(arguments, 2)); return func.apply(_this, Array.prototype.slice.call(arguments, 2));
}; };

View File

@ -30,7 +30,7 @@ events.prototype.startGame = function (hard, seed, route, callback) {
} }
if (main.mode != 'play') return; if (main.mode != 'play') return;
core.plugin.skillTree.resetSkillLevel(); Mota.Plugin.require('skillTree_g').resetSkillLevel();
// 无动画的开始游戏 // 无动画的开始游戏
if (core.flags.startUsingCanvas || route != null) { 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) { events.prototype._action_openShop = function (data, x, y, prefix) {
core.plugin.shop.setShopVisited(data.id, true); Mota.Plugin.require('shop_g').setShopVisited(data.id, true);
if (data.open) core.plugin.shop.openShop(data.id, true); if (data.open) Mota.Plugin.require('shop_g').openShop(data.id, true);
core.doAction(); core.doAction();
}; };
events.prototype._action_disableShop = function (data, x, y, prefix) { 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(); core.doAction();
}; };
@ -3272,6 +3272,7 @@ events.prototype.openToolbox = function (fromUserAction) {
////// 点击快捷商店按钮时的打开操作 ////// ////// 点击快捷商店按钮时的打开操作 //////
events.prototype.openQuickShop = function (fromUserAction) { events.prototype.openQuickShop = function (fromUserAction) {
if (core.isReplaying()) return; if (core.isReplaying()) return;
const shop = Mota.Plugin.require('shop_g');
if (Object.keys(core.status.shops).length == 0) { if (Object.keys(core.status.shops).length == 0) {
core.playSound('操作失败'); core.playSound('操作失败');
@ -3283,18 +3284,18 @@ events.prototype.openQuickShop = function (fromUserAction) {
if (Object.keys(core.status.shops).length == 1) { if (Object.keys(core.status.shops).length == 1) {
var shopId = Object.keys(core.status.shops)[0]; var shopId = Object.keys(core.status.shops)[0];
if (core.status.event.id != null) return; if (core.status.event.id != null) return;
if (!core.plugin.shop.canOpenShop(shopId)) { if (!shop.canOpenShop(shopId)) {
core.playSound('操作失败'); core.playSound('操作失败');
core.drawTip('当前无法打开快捷商店!'); core.drawTip('当前无法打开快捷商店!');
return; return;
} }
var message = core.plugin.shop.canUseQuickShop(shopId); var message = shop.canUseQuickShop(shopId);
if (message != null) { if (message != null) {
core.playSound('操作失败'); core.playSound('操作失败');
core.drawTip(message); core.drawTip(message);
return; return;
} }
core.plugin.shop.openShop(shopId, false); shop.openShop(shopId, false);
return; return;
} }

View File

@ -3099,13 +3099,14 @@ ui.prototype._drawNotes = function () {
////// 绘制快捷商店选择栏 ////// ////// 绘制快捷商店选择栏 //////
ui.prototype._drawQuickShop = function () { ui.prototype._drawQuickShop = function () {
const shop = Mota.Plugin.require('shop');
core.status.event.id = 'selectShop'; core.status.event.id = 'selectShop';
var shopList = core.status.shops, var shopList = core.status.shops,
keys = core.plugin.shop.listShopIds(); keys = shop.listShopIds();
var choices = keys.map(function (shopId) { var choices = keys.map(function (shopId) {
return { return {
text: shopList[shopId].textInList, text: shopList[shopId].textInList,
color: core.plugin.shop.isShopVisited(shopId) ? null : '#999999' color: shop.isShopVisited(shopId) ? null : '#999999'
}; };
}); });
choices.push('返回游戏'); choices.push('返回游戏');

View File

@ -404,6 +404,7 @@ main.prototype.loadAsync = async function (mode, callback) {
}); });
await core.init(coreData, callback); await core.init(coreData, callback);
if (main.mode === 'play') main.loading.emit('coreInit'); if (main.mode === 'play') main.loading.emit('coreInit');
core.initStatus.maps = core.maps._initMaps();
core.resize(); core.resize();
@ -414,7 +415,7 @@ main.prototype.loadAsync = async function (mode, callback) {
if (auto && !core.domStyle.isVertical) { if (auto && !core.domStyle.isVertical) {
try { try {
core.plugin.utils.maxGameScale(); Mota.Plugin.require('utils_g').maxGameScale();
requestAnimationFrame(() => { requestAnimationFrame(() => {
var style = getComputedStyle(main.dom.gameGroup); var style = getComputedStyle(main.dom.gameGroup);
var height = parseFloat(style.height); var height = parseFloat(style.height);

View File

@ -413,7 +413,7 @@ main.floors.MT16=
"这里是漏怪检测,将会检测\r[gold]洞穴、山路、山脚、平原\r[white]地区的怪物是否清完", "这里是漏怪检测,将会检测\r[gold]洞穴、山路、山脚、平原\r[white]地区的怪物是否清完",
{ {
"type": "function", "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", "type": "loadBgm",

View File

@ -148,7 +148,7 @@ main.floors.MT31=
"这里是漏怪检测,会检测\r[gold]勇气之路\r[]区域是否有遗漏怪物", "这里是漏怪检测,会检测\r[gold]勇气之路\r[]区域是否有遗漏怪物",
{ {
"type": "function", "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}"
} }
] ]
}, },

View File

@ -76,7 +76,7 @@ main.floors.MT35=
"这里是漏怪检测,会检测\r[gold]智慧小径\r[]区域是否有遗漏怪物", "这里是漏怪检测,会检测\r[gold]智慧小径\r[]区域是否有遗漏怪物",
{ {
"type": "function", "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": [ "7,0": [

View File

@ -120,7 +120,7 @@ main.floors.MT5=
"这里是漏怪检测,会检测\r[gold]山洞\r[]区域的怪物是否清空", "这里是漏怪检测,会检测\r[gold]山洞\r[]区域的怪物是否清空",
{ {
"type": "function", "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}"
} }
] ]
}, },

View File

@ -21,7 +21,7 @@ main.floors.tower5=
"这里是漏怪检测,会检测\r[gold]智慧之塔\r[]区域是否有遗漏怪物", "这里是漏怪检测,会检测\r[gold]智慧之塔\r[]区域是否有遗漏怪物",
{ {
"type": "function", "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}"
} }
] ]
}, },

View File

@ -50,7 +50,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
core.hideStatusBar(core.hasFlag('showToolbox')); core.hideStatusBar(core.hasFlag('showToolbox'));
else core.showStatusBar(); else core.showStatusBar();
if (main.mode === 'play' && !main.replayChecking) { if (main.mode === 'play' && !main.replayChecking) {
Mota.Plugin.require('fly').splitArea(); Mota.Plugin.require('fly_r').splitArea();
Mota.require('var', 'hook').emit('reset'); Mota.require('var', 'hook').emit('reset');
} else { } else {
flags.autoSkill ??= true; flags.autoSkill ??= true;
@ -113,7 +113,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
// 正在切换楼层过程中执行的操作;此函数的执行时间是“屏幕完全变黑“的那一刻 // 正在切换楼层过程中执行的操作;此函数的执行时间是“屏幕完全变黑“的那一刻
// floorId为要切换到的楼层IDheroLoc表示勇士切换到的位置 // floorId为要切换到的楼层IDheroLoc表示勇士切换到的位置
const { checkLoopMap } = core.plugin.loopMap; const { checkLoopMap } = Mota.Plugin.require('loopMap_g');
flags.floorChanging = true; flags.floorChanging = true;
@ -131,8 +131,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
} }
// 根据分区信息自动砍层与恢复 // 根据分区信息自动砍层与恢复
if (core.plugin.removeMap.autoRemoveMaps) Mota.Plugin.require('removeMap_g')?.autoRemoveMaps?.(floorId);
core.plugin.removeMap.autoRemoveMaps(floorId);
// 重置画布尺寸 // 重置画布尺寸
core.maps.resizeMap(floorId); core.maps.resizeMap(floorId);
@ -201,7 +200,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
} }
} }
if (!flags.debug && !main.replayChecking) if (!flags.debug && !main.replayChecking)
Mota.Plugin.require('completion').checkVisitedFloor(); Mota.Plugin.require('completion_r').checkVisitedFloor();
}, },
flyTo: function (toId, callback) { flyTo: function (toId, callback) {
// 楼层传送器的使用从当前楼层飞往toId // 楼层传送器的使用从当前楼层飞往toId
@ -279,7 +278,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
version: core.firstData.version, version: core.firstData.version,
guid: core.getGuid(), guid: core.getGuid(),
time: new Date().getTime(), time: new Date().getTime(),
skills: core.plugin.skillTree.saveSkillTree() skills: Mota.Plugin.require('skillTree_g').saveSkillTree()
}; };
return data; return data;
@ -327,7 +326,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
} }
core.setFlag('__fromLoad__', true); 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 () { 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 (callback) callback();
if (flags.onChase) { if (flags.onChase) {
Mota.Plugin.require('chase').startChase(flags.chaseIndex); Mota.Plugin.require('chase_r').startChase(flags.chaseIndex);
if (flags.chaseIndex === 1) { if (flags.chaseIndex === 1) {
core.playBgm('escape.mp3', 43.5); core.playBgm('escape.mp3', 43.5);
} }
@ -388,7 +387,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
// 2, 将楼层属性中的cannotMoveDirectly这个开关勾上即禁止在该层楼使用瞬移。 // 2, 将楼层属性中的cannotMoveDirectly这个开关勾上即禁止在该层楼使用瞬移。
// 3. 将flag:cannotMoveDirectly置为true即可使用flag控制在某段剧情范围内禁止瞬移。 // 3. 将flag:cannotMoveDirectly置为true即可使用flag控制在某段剧情范围内禁止瞬移。
const { checkLoopMap } = core.plugin.loopMap; const { checkLoopMap } = Mota.Plugin.require('loopMap_g');
// 增加步数 // 增加步数
core.status.hero.steps++; core.status.hero.steps++;

View File

@ -40,8 +40,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "小绿宝石", "name": "小绿宝石",
"text": ",护盾+${core.values.greenGem}", "text": ",护盾+${core.values.greenGem}",
"itemEffect": "core.status.hero.mdef += 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\") * (core.plugin.skillTree.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", "useItemEffect": "core.status.hero.mdef += core.values.greenGem",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -97,8 +97,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "红血瓶", "name": "红血瓶",
"text": ",生命+${core.values.redPotion}", "text": ",生命+${core.values.redPotion}",
"itemEffect": "core.status.hero.hp += 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 + core.plugin.skillTree.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", "useItemEffect": "core.status.hero.hp += core.values.redPotion",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -106,8 +106,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "蓝血瓶", "name": "蓝血瓶",
"text": ",生命+${core.values.bluePotion}", "text": ",生命+${core.values.bluePotion}",
"itemEffect": "core.status.hero.hp += 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 + core.plugin.skillTree.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", "useItemEffect": "core.status.hero.hp += core.values.bluePotion",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -115,8 +115,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "黄血瓶", "name": "黄血瓶",
"text": ",生命+${core.values.yellowPotion}", "text": ",生命+${core.values.yellowPotion}",
"itemEffect": "core.status.hero.hp += 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 + core.plugin.skillTree.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", "useItemEffect": "core.status.hero.hp += core.values.yellowPotion",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -124,8 +124,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "绿血瓶", "name": "绿血瓶",
"text": ",生命+${core.values.greenPotion}", "text": ",生命+${core.values.greenPotion}",
"itemEffect": "core.status.hero.hp += 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 + core.plugin.skillTree.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", "useItemEffect": "core.status.hero.hp += core.values.greenPotion",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -349,7 +349,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"name": "查看技能", "name": "查看技能",
"text": "查看勇士的技能", "text": "查看勇士的技能",
"canUseItemEffect": true, "canUseItemEffect": true,
"useItemEffect": "core.plugin.gameUi.openSkill();" "useItemEffect": "Mota.Plugin.require('gameUi_g').openSkill();"
}, },
"dagger": { "dagger": {
"cls": "constants", "cls": "constants",
@ -522,7 +522,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"name": "技能树", "name": "技能树",
"text": "打开技能树", "text": "打开技能树",
"hideInReplay": true, "hideInReplay": true,
"useItemEffect": "core.plugin.skillTree.openTree();", "useItemEffect": "Mota.Plugin.require('skillTree_g').openTree();",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
"wand": { "wand": {
@ -626,8 +626,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "中绿宝石", "name": "中绿宝石",
"text": ",护盾+${core.values.greenGem}", "text": ",护盾+${core.values.greenGem}",
"itemEffect": "core.status.hero.mdef += 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\") * (core.plugin.skillTree.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", "useItemEffect": "core.status.hero.mdef += core.values.greenGem",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -729,8 +729,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "大绿宝石", "name": "大绿宝石",
"text": ",护盾+${core.values.greenGem}", "text": ",护盾+${core.values.greenGem}",
"itemEffect": "core.status.hero.mdef += 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\") * (core.plugin.skillTree.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", "useItemEffect": "core.status.hero.mdef += core.values.greenGem",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -896,8 +896,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "超大绿宝石", "name": "超大绿宝石",
"text": ",护盾+${core.values.greenGem}", "text": ",护盾+${core.values.greenGem}",
"itemEffect": "core.status.hero.mdef += 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\") * (core.plugin.skillTree.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", "useItemEffect": "core.status.hero.mdef += core.values.greenGem",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -1019,8 +1019,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "璀璨绿宝石", "name": "璀璨绿宝石",
"text": ",护盾+${core.values.greenGem}", "text": ",护盾+${core.values.greenGem}",
"itemEffect": "core.status.hero.mdef += 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\") * (core.plugin.skillTree.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", "useItemEffect": "core.status.hero.mdef += core.values.greenGem",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -1050,8 +1050,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "新物品", "name": "新物品",
"text": ",防御+${core.values.blueGem}", "text": ",防御+${core.values.blueGem}",
"itemEffect": "core.status.hero.mdef += 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\") * (core.plugin.skillTree.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", "useItemEffect": "core.status.hero.def += core.values.blueGem",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -1071,8 +1071,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "史诗绿宝石", "name": "史诗绿宝石",
"text": ",护盾+${core.values.greenGem}", "text": ",护盾+${core.values.greenGem}",
"itemEffect": "core.status.hero.mdef += 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\") * (core.plugin.skillTree.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", "useItemEffect": "core.status.hero.mdef += core.values.greenGem",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -1100,8 +1100,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "大红血瓶", "name": "大红血瓶",
"text": ",生命+${core.values.redPotion}", "text": ",生命+${core.values.redPotion}",
"itemEffect": "core.status.hero.hp += 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 + core.plugin.skillTree.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", "useItemEffect": "core.status.hero.hp += core.values.redPotion",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -1113,8 +1113,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "大蓝血瓶", "name": "大蓝血瓶",
"text": ",生命+${core.values.redPotion}", "text": ",生命+${core.values.redPotion}",
"itemEffect": "core.status.hero.hp += 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 + core.plugin.skillTree.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", "useItemEffect": "core.status.hero.hp += core.values.redPotion",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -1130,8 +1130,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "大绿血瓶", "name": "大绿血瓶",
"text": ",生命+${core.values.redPotion}", "text": ",生命+${core.values.redPotion}",
"itemEffect": "core.status.hero.hp += 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 + core.plugin.skillTree.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", "useItemEffect": "core.status.hero.hp += core.values.redPotion",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -1151,8 +1151,8 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "items", "cls": "items",
"name": "大黄血瓶", "name": "大黄血瓶",
"text": ",生命+${core.values.redPotion}", "text": ",生命+${core.values.redPotion}",
"itemEffect": "core.status.hero.hp += 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 + core.plugin.skillTree.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", "useItemEffect": "core.status.hero.hp += core.values.redPotion",
"canUseItemEffect": "true" "canUseItemEffect": "true"
}, },
@ -1181,7 +1181,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"cls": "constants", "cls": "constants",
"name": "学习", "name": "学习",
"canUseItemEffect": "true", "canUseItemEffect": "true",
"text": "可以学习怪物的技能,学习后持续${core.plugin.skillTree.getSkillLevel(11) * 3 + 2}场战斗" "text": "可以学习怪物的技能,学习后持续${Mota.Plugin.require('skillTree_g').getSkillLevel(11) * 3 + 2}场战斗"
}, },
"I574": { "I574": {
"cls": "items", "cls": "items",

View File

@ -19,28 +19,31 @@ import { gameKey } from './main/init/hotkey';
import { mainSetting, settingStorage } from './main/setting'; import { mainSetting, settingStorage } from './main/setting';
import { isMobile } from '../plugin/use'; import { isMobile } from '../plugin/use';
import { KeyCode } from '@/plugin/keyCodes'; import { KeyCode } from '@/plugin/keyCodes';
import { status } from '@/plugin/ui/statusBar';
import './plugin';
import './package';
interface AncTePlugin { // interface AncTePlugin {
pop: ReturnType<typeof import('../plugin/pop').default>; // pop: ReturnType<typeof import('../plugin/pop').default>;
use: ReturnType<typeof import('../plugin/use').default>; // use: ReturnType<typeof import('../plugin/use').default>;
animate: ReturnType<typeof import('../plugin/animateController').default>; // animate: ReturnType<typeof import('../plugin/animateController').default>;
utils: ReturnType<typeof import('../plugin/utils').default>; // utils: ReturnType<typeof import('../plugin/utils').default>;
status: ReturnType<typeof import('../plugin/ui/statusBar').default>; // status: ReturnType<typeof import('../plugin/ui/statusBar').default>;
fly: ReturnType<typeof import('../plugin/ui/fly').default>; // fly: ReturnType<typeof import('../plugin/ui/fly').default>;
chase: ReturnType<typeof import('../plugin/chase/chase').default>; // chase: ReturnType<typeof import('../plugin/chase/chase').default>;
webglUtils: ReturnType<typeof import('../plugin/webgl/utils').default>; // webglUtils: ReturnType<typeof import('../plugin/webgl/utils').default>;
shadow: ReturnType<typeof import('../plugin/shadow/shadow').default>; // shadow: ReturnType<typeof import('../plugin/shadow/shadow').default>;
gameShadow: ReturnType< // gameShadow: ReturnType<
typeof import('../plugin/shadow/gameShadow').default // typeof import('../plugin/shadow/gameShadow').default
>; // >;
achievement: ReturnType<typeof import('../plugin/ui/achievement').default>; // achievement: ReturnType<typeof import('../plugin/ui/achievement').default>;
completion: ReturnType<typeof import('../plugin/completion').default>; // completion: ReturnType<typeof import('../plugin/completion').default>;
path: ReturnType<typeof import('../plugin/fx/path').default>; // path: ReturnType<typeof import('../plugin/fx/path').default>;
gameCanvas: ReturnType<typeof import('../plugin/fx/gameCanvas').default>; // gameCanvas: ReturnType<typeof import('../plugin/fx/gameCanvas').default>;
noise: ReturnType<typeof import('../plugin/fx/noise').default>; // noise: ReturnType<typeof import('../plugin/fx/noise').default>;
smooth: ReturnType<typeof import('../plugin/fx/smoothView').default>; // smooth: ReturnType<typeof import('../plugin/fx/smoothView').default>;
frag: ReturnType<typeof import('../plugin/fx/frag').default>; // frag: ReturnType<typeof import('../plugin/fx/frag').default>;
} // }
// export interface Mota { // export interface Mota {
// sound: SoundController; // sound: SoundController;
@ -93,3 +96,4 @@ Mota.register('var', 'KeyCode', KeyCode);
Mota.register('var', 'resource', resource); Mota.register('var', 'resource', resource);
Mota.register('var', 'zipResource', zipResource); Mota.register('var', 'zipResource', zipResource);
Mota.register('var', 'settingStorage', settingStorage); Mota.register('var', 'settingStorage', settingStorage);
Mota.register('var', 'status', status);

View File

@ -16,6 +16,7 @@ const showFixed = debounce((block: Block) => {
const e = core.material.enemys[block.event.id as EnemyIds]; const e = core.material.enemys[block.event.id as EnemyIds];
if (!e) return; if (!e) return;
const enemy = core.status.thisMap.enemy.get(block.x, block.y); const enemy = core.status.thisMap.enemy.get(block.x, block.y);
if (!enemy) return;
fixedUi.open( fixedUi.open(
'fixed', 'fixed',
{ enemy, close, loc: [cx, cy] }, { enemy, close, loc: [cx, cy] },

15
src/core/package.ts Normal file
View File

@ -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);

View File

@ -17,21 +17,32 @@
// import frag from '@/plugin/fx/frag'; // import frag from '@/plugin/fx/frag';
// import { Mota } from '.'; // import { Mota } from '.';
import * as shadow from '@/plugin/shadow/shadow';
import * as gameShadow from '@/plugin/shadow/gameShadow'; import * as gameShadow from '@/plugin/shadow/gameShadow';
import * as fly from '@/plugin/ui/fly'; import * as fly from '@/plugin/ui/fly';
import * as chase from '@/plugin/chase/chase'; import * as chase from '@/plugin/chase/chase';
import * as completion from '@/plugin/completion'; import * as completion from '@/plugin/completion';
import * as pop from '@/plugin/pop'; import * as pop from '@/plugin/pop';
import * as status from '@/plugin/ui/statusBar';
import * as frag from '@/plugin/fx/frag'; 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('shadow_r', shadow, shadow.init);
Mota.Plugin.register('fly', fly); Mota.Plugin.register('gameShadow_r', gameShadow, gameShadow.init);
Mota.Plugin.register('chase', chase); Mota.Plugin.register('fly_r', fly);
Mota.Plugin.register('completion', completion); Mota.Plugin.register('chase_r', chase);
Mota.Plugin.register('pop', pop, pop.init); Mota.Plugin.register('completion_r', completion);
Mota.Plugin.register('status', status); // todo: 改成系统变量,而非插件 Mota.Plugin.register('pop_r', pop, pop.init);
Mota.Plugin.register('frag', frag, frag.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: 将插件更改为注册形式,分为渲染进程和游戏进程两部分,同时分配优先级 // // todo: 将插件更改为注册形式,分为渲染进程和游戏进程两部分,同时分配优先级

View File

@ -483,14 +483,14 @@
}, },
"study": { "study": {
"text": "学习", "text": "学习",
"condition": "core.plugin.skillTree.getSkillLevel(11) > 0", "condition": "Mota.Plugin.require('skillTree_g').getSkillLevel(11) > 0",
"desc": [ "desc": [
"本条目会详细说明学习的机制与所有可以被学习的技能被学习后的效果。当前已经学习的技能会以与状态栏类似的盒子展示出来。", "本条目会详细说明学习的机制与所有可以被学习的技能被学习后的效果。当前已经学习的技能会以与状态栏类似的盒子展示出来。",
"<br>", "<br>",
"<br>", "<br>",
"首先学习技能消耗的智慧点会越来越多初始消耗的智慧点为500每学习一次增加250。", "首先学习技能消耗的智慧点会越来越多初始消耗的智慧点为500每学习一次增加250。",
"学习的技能可以持续5场战斗在技能树界面每升级一次增加3场", "学习的技能可以持续5场战斗在技能树界面每升级一次增加3场",
"<span style=\"color: gold\">当前为${core.plugin.skillTree.getSkillLevel(11) * 3 + 2}场</span>。", "<span style=\"color: gold\">当前为${Mota.Plugin.require('skillTree_g').getSkillLevel(11) * 3 + 2}场</span>。",
"学习后对应属性的值,例如抱团怪增加的属性百分比,会与被学习的怪物相同。学习界面可以使用背包中的道具或点击状态栏打开。", "学习后对应属性的值,例如抱团怪增加的属性百分比,会与被学习的怪物相同。学习界面可以使用背包中的道具或点击状态栏打开。",
"<br>", "<br>",
"<br>", "<br>",

View File

@ -8,7 +8,7 @@
}, },
"blade": { "blade": {
"text": "1断灭之刃", "text": "1断灭之刃",
"opened": "core.plugin.skillTree.getSkillLevel(2) > 0", "opened": "Mota.Plugin.require('skillTree_g').getSkillLevel(2) > 0",
"desc": [ "desc": [
"<span style=\"color: gold\">快捷键1</span>,开启后勇士攻击增加${level:2 * 10}%", "<span style=\"color: gold\">快捷键1</span>,开启后勇士攻击增加${level:2 * 10}%",
"同时防御减少${level:2 * 10}%。", "同时防御减少${level:2 * 10}%。",
@ -31,7 +31,7 @@
}, },
"shield": { "shield": {
"text": "3铸剑为盾", "text": "3铸剑为盾",
"opened": "core.plugin.skillTree.getSkillLevel(10) > 0", "opened": "Mota.Plugin.require('skillTree_g').getSkillLevel(10) > 0",
"desc": [ "desc": [
"<span style=\"color: gold\">快捷键3</span>,开启后勇士防御增加${level:10 * 10}%", "<span style=\"color: gold\">快捷键3</span>,开启后勇士防御增加${level:10 * 10}%",
"同时攻击减少${level:10 * 10}%。", "同时攻击减少${level:10 * 10}%。",

View File

@ -1 +1,2 @@
import './system'; import './system';
import '../plugin/game/index';

View File

@ -25,9 +25,10 @@ import type {
} from '@/core/main/setting'; } from '@/core/main/setting';
import type { GameStorage } from '@/core/main/storage'; import type { GameStorage } from '@/core/main/storage';
import type { DamageEnemy, EnemyCollection } from '@/plugin/game/enemy/damage'; 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 { Range } from '@/plugin/game/range';
import type { KeyCode } from '@/plugin/keyCodes'; import type { KeyCode } from '@/plugin/keyCodes';
import type { Ref } from 'vue';
interface ClassInterface { interface ClassInterface {
// 渲染进程与游戏进程通用 // 渲染进程与游戏进程通用
@ -82,9 +83,10 @@ interface VariableInterface {
resource: ResourceStore<Exclude<ResourceType, 'zip'>>; resource: ResourceStore<Exclude<ResourceType, 'zip'>>;
zipResource: ResourceStore<'zip'>; zipResource: ResourceStore<'zip'>;
settingStorage: GameStorage<SettingStorage>; settingStorage: GameStorage<SettingStorage>;
status: Ref<boolean>;
// 定义于游戏进程,渲染进程依然可用 // 定义于游戏进程,渲染进程依然可用
haloSpecials: number[]; haloSpecials: number[];
enemySpecials: typeof enemySpecials; enemySpecials: typeof specials;
} }
interface SystemInterfaceMap { interface SystemInterfaceMap {
@ -95,12 +97,67 @@ interface SystemInterfaceMap {
type InterfaceType = keyof 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 { export interface IMota {
rewrite: typeof rewrite; rewrite: typeof rewrite;
r: typeof r;
rf: typeof rf;
/** 样板插件接口 */
Plugin: IPlugin; Plugin: IPlugin;
/**
* 使
* polyfill使
* 使main.replayChecking进行检查使
*/
Package: IPackage;
/** /**
* *
@ -145,15 +202,12 @@ export interface IMota {
} }
export interface IPlugin { export interface IPlugin {
inited: boolean;
/** /**
* *
*/ */
init(): void; 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<K extends string>(plugin: K, init: (plugin: K) => any): void; register<K extends string>(plugin: K, init: (plugin: K) => any): void;
} }
export interface IPackage {
/**
* 使
* @param name
*/
require<K extends keyof PackageInterface>(name: K): PackageInterface[K];
/**
* 使
*/
requireAll(): PackageInterface;
register<K extends keyof PackageInterface>(
name: K,
data: PackageInterface[K]
): void;
}
interface IPluginData { interface IPluginData {
/** 插件类型content表示直接注册了内容function表示注册了初始化函数内容从其返回值获取 */ /** 插件类型content表示直接注册了内容function表示注册了初始化函数内容从其返回值获取 */
type: 'content' | 'function'; type: 'content' | 'function';
@ -219,8 +291,8 @@ interface IPluginData {
class MPlugin { class MPlugin {
private static plugins: Record<string, IPluginData> = {}; private static plugins: Record<string, IPluginData> = {};
private static inited = false;
private static pluginData: Record<string, any> = {}; private static pluginData: Record<string, any> = {};
static inited = false;
constructor() { constructor() {
throw new Error(`System plugin class cannot be constructed.`); throw new Error(`System plugin class cannot be constructed.`);
@ -248,8 +320,8 @@ class MPlugin {
return this.plugins[key].data; return this.plugins[key].data;
} }
static requireAll() { static requireAll(): PluginInterface {
return this.pluginData; return this.pluginData as PluginInterface;
} }
static register(key: string, data: any, init?: any) { 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<K extends keyof PackageInterface>(
name: K
): PackageInterface[K] {
return this.packages[name];
}
static requireAll() {
return this.packages;
}
static register<K extends keyof PackageInterface>(
name: K,
data: PackageInterface[K]
) {
this.packages[name] = data;
}
}
/** /**
* Mota * Mota
*/ */
@ -278,7 +376,10 @@ class Mota {
private static variables: Record<string, any> = {}; private static variables: Record<string, any> = {};
static rewrite = rewrite; static rewrite = rewrite;
static r = r;
static rf = rf;
static Plugin = MPlugin; static Plugin = MPlugin;
static Package = MPackage;
constructor() { constructor() {
throw new Error(`System interface class cannot be constructed.`); throw new Error(`System interface class cannot be constructed.`);
@ -330,11 +431,19 @@ type _Func = (...params: any) => any;
* @param bind base * @param bind base
* @param rebind base * @param rebind base
*/ */
function rewrite<O, K extends SelectKey<O, _Func>, T = O>( function rewrite<
O,
K extends SelectKey<O, _Func>,
R extends 'full' | 'front',
T = O
>(
base: O, base: O,
key: K, key: K,
type: 'full' | 'front', type: R,
re: (this: T, ...params: [..._F<O[K]>[0], ...any[]]) => _F<O[K]>[1], re: (
this: T,
...params: [..._F<O[K]>[0], ...any[]]
) => R extends 'full' ? _F<O[K]>[1] : void,
bind?: any, bind?: any,
rebind?: T rebind?: T
): (this: T, ...params: [..._F<O[K]>[0], ...any[]]) => _F<O[K]>[1]; ): (this: T, ...params: [..._F<O[K]>[0], ...any[]]) => _F<O[K]>[1];
@ -345,8 +454,8 @@ function rewrite<O, K extends SelectKey<O, _Func>, T = O>(
* @param type add表示在函数后追加 * @param type add表示在函数后追加
* @param re add时表示在原函数后面追加复写函数 * @param re add时表示在原函数后面追加复写函数
* *
* @param bind base * @param bind `base`
* @param rebind base * @param rebind `base`
*/ */
function rewrite<O, K extends SelectKey<O, _Func>, T = O>( function rewrite<O, K extends SelectKey<O, _Func>, T = O>(
base: O, base: O,
@ -390,7 +499,7 @@ function rewrite<O, K extends SelectKey<O, _Func>, T = O>(
const origin = base[key]; const origin = base[key];
function res(this: T, ...params: [..._F<O[K]>[0], ...any[]]) { function res(this: T, ...params: [..._F<O[K]>[0], ...any[]]) {
// @ts-ignore // @ts-ignore
re.call(rebind ?? base, v, ...params); re.call(rebind ?? base, ...params);
const ret = (origin as _Func).call(bind ?? base, ...params); const ret = (origin as _Func).call(bind ?? base, ...params);
return ret; return ret;
} }
@ -399,6 +508,43 @@ function rewrite<O, K extends SelectKey<O, _Func>, T = O>(
} }
} }
/**
*
* ui显示
* @param fn `Mota.Package.requireAll()`
* @param thisArg `this`
*/
function r<T = undefined>(
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<F extends (...params: any) => any, T>(
fn: F,
thisArg?: T
): (this: T, ...params: Parameters<F>) => ReturnType<F> | undefined {
// @ts-ignore
if (main.replayChecking) return () => {};
else {
return (...params) => {
return fn.call(thisArg, ...params);
};
}
}
declare global { declare global {
interface Window { interface Window {
Mota: IMota; Mota: IMota;

View File

@ -123,7 +123,7 @@ export const camera1: ChaseCameraData[] = [
* *
*/ */
export function init1() { export function init1() {
return core.plugin.chase.chaseInit1(); return Mota.Plugin.require('chase_g').chaseInit1();
} }
export function chaseShake(chase: Chase) { export function chaseShake(chase: Chase) {
@ -561,7 +561,7 @@ export function para3(chase: Chase) {
'MT14', 'MT14',
async () => { async () => {
flags.finishChase1 = true; flags.finishChase1 = true;
core.plugin.replay.clip('choices:0'); Mota.Plugin.require('replay_g').clip('choices:0');
core.showStatusBar(); core.showStatusBar();
ani.time(750).apply('rect', 0); ani.time(750).apply('rect', 0);
chase.end(); chase.end();

View File

@ -5,6 +5,7 @@ import {
} from './ui/achievement'; } from './ui/achievement';
import { changeLocalStorage } from './utils'; import { changeLocalStorage } from './utils';
import list from '../data/achievement.json'; import list from '../data/achievement.json';
import { loading } from '@/core/loader/load';
export const floors: Record<number, FloorIds[]> = { export const floors: Record<number, FloorIds[]> = {
1: ['MT0', 'tower7'] 1: ['MT0', 'tower7']
@ -21,6 +22,15 @@ export const achiDict: Record<number, number> = {
1: 0 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;
});
});
/** /**
* *
*/ */

View File

@ -7,7 +7,9 @@ tran.value.y = 0;
let needSmooth = false; let needSmooth = false;
export default function init() { export function init() {
const setting = Mota.require('var', 'mainSetting');
tran.ticker.add(() => { tran.ticker.add(() => {
if (core.isPlaying() && needSmooth) { if (core.isPlaying() && needSmooth) {
core.setViewport(tran.value.x, tran.value.y); core.setViewport(tran.value.x, tran.value.y);
@ -18,50 +20,47 @@ export default function init() {
needSmooth = false; needSmooth = false;
}, 700); }, 700);
control.prototype._drawHero_updateViewport = function ( Mota.rewrite(
x: number, core.control,
y: number, '_drawHero_updateViewport',
offset: Loc 'full',
) { (x, y, offset) => {
const ox = core.clamp( const ox = core.clamp(
(x - core._HALF_WIDTH_) * 32 + offset.x, (x - core._HALF_WIDTH_) * 32 + offset.x,
0, 0,
Math.max(32 * core.bigmap.width - core._PX_, 0) Math.max(32 * core.bigmap.width - core._PX_, 0)
); );
const oy = core.clamp( const oy = core.clamp(
(y - core._HALF_HEIGHT_) * 32 + offset.y, (y - core._HALF_HEIGHT_) * 32 + offset.y,
0, 0,
Math.max(32 * core.bigmap.height - core._PY_, 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) { const t = setting.getValue('screen.smoothView', false);
needSmooth = true; if (!t) return;
func(); if (tran.easeTime > 0) {
} else { needSmooth = true;
core.setViewport(tran.value.x, tran.value.y); func();
} else {
core.setViewport(tran.value.x, tran.value.y);
}
} }
}; );
const hso = hyper('sin', 'out');
let time2 = Date.now(); let time2 = Date.now();
const origin1 = control.prototype._moveAction_moving; Mota.rewrite(core.control, '_moveAction_moving', 'front', () => {
control.prototype._moveAction_moving = function (...params: any[]) { const t = setting.getValue('screen.smoothView', false) ? 200 : 1;
if (Date.now() - time2 > 20) if (Date.now() - time2 > 20) tran.mode(hso).time(t).absolute();
tran.mode(hyper('sin', 'out')).time(200).absolute(); });
return origin1.call(this, ...params); Mota.rewrite(core.control, 'moveDirectly', 'front', () => {
}; const t = setting.getValue('screen.smoothView', false) ? 600 : 1;
const origin2 = control.prototype.moveDirectly;
control.prototype.moveDirectly = function (...params: any[]) {
time2 = Date.now(); time2 = Date.now();
tran.mode(hyper('sin', 'out')).time(600).absolute(); tran.mode(hso).time(t).absolute();
return origin2.call(this, ...params); });
}; Mota.rewrite(core.events, '_changeFloor_beforeChange', 'front', () => {
const origin3 = events.prototype._changeFloor_beforeChange;
events.prototype._changeFloor_beforeChange = function (...params: any[]) {
tran.time(1).absolute(); tran.time(1).absolute();
return origin3.call(this, ...params); });
};
} }

View File

@ -1,6 +1,6 @@
export function chaseInit1() { export function chaseInit1() {
const ids = ['MT13', 'MT14', 'MT15']; const ids: FloorIds[] = ['MT13', 'MT14', 'MT15'];
const toRemove = []; const toRemove: [number, number, FloorIds][] = [];
ids.forEach(v => { ids.forEach(v => {
core.status.maps[v].cannotMoveDirectly = true; core.status.maps[v].cannotMoveDirectly = true;
core.extractBlocks(v); core.extractBlocks(v);
@ -17,7 +17,3 @@ export function chaseInit1() {
core.removeBlock(...v); core.removeBlock(...v);
}); });
} }
core.plugin.chase = {
chaseInit1
};

View File

@ -22,232 +22,224 @@ export function getEnemy(
return enemy; return enemy;
} }
core.enemys.canBattle = function ( export function init() {
x: number, core.enemys.canBattle = function (
y: number, x: number,
floorId: FloorIds = core.status.floorId y: number,
) { floorId: FloorIds = core.status.floorId
const enemy = getEnemy(x, y, floorId); ) {
const { damage } = enemy.calDamage(); const enemy = getEnemy(x, y, floorId);
return damage < core.status.hero.hp; const { damage } = enemy.calDamage();
}; return damage < core.status.hero.hp;
};
core.events.battle = function ( core.events.battle = function (
x: number, x: number,
y: number, y: number,
force: boolean = false, force: boolean = false,
callback?: () => void callback?: () => void
) { ) {
core.saveAndStopAutomaticRoute(); core.saveAndStopAutomaticRoute();
const enemy = getEnemy(x, y); const enemy = getEnemy(x, y);
// 非强制战斗 // 非强制战斗
if (!core.enemys.canBattle(x, y) && !force && !core.status.event.id) { if (!core.enemys.canBattle(x, y) && !force && !core.status.event.id) {
core.stopSound(); core.stopSound();
core.playSound('操作失败'); core.playSound('操作失败');
core.drawTip('你打不过此怪物!', enemy.id); core.drawTip('你打不过此怪物!', enemy.id);
return core.clearContinueAutomaticRoute(callback); 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);
} }
} 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) { core.events.afterBattle = function (
if (data.id) { enemy: DamageEnemy,
const enemy = getSingleEnemy(data.id as EnemyIds); x?: number,
// todo: 与不在地图上的怪物战斗 y?: number
} else { ) {
if (data.floorId != core.status.floorId) { const floorId = core.status.floorId;
core.doAction(); 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; 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; core.status.hero.hp -= damage;
const enemys: CurrentEnemy[] = []; core.status.hero.statistics.battleDamage += damage;
const used: Record<string, DamageEnemy[]> = {}; core.status.hero.statistics.battle++;
ensureFloorDamage(floorId);
const floor = core.status.maps[floorId]; // 智慧之源
floor.enemy.list.forEach(v => { if (special.includes(14) && flags.hard === 2) {
if (!(v.id in used)) { core.addFlag(
const e = new DamageEnemy(v.enemy); 'inte_' + floorId,
e.calAttribute(); Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10
e.getRealInfo(); );
e.calDamage(); core.status.hero.mdef -=
const curr: CurrentEnemy = { Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10;
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; if (special.includes(22)) {
const bd = b.enemy.calDamage().damage; flags[`night_${floorId}`] ??= 0;
return ad - bd; flags[`night_${floorId}`] -= enemy.enemy.night!;
}); }
}; if (special.includes(23)) {
flags[`night_${floorId}`] ??= 0;
flags[`night_${floorId}`] += enemy.enemy.day;
}
declare global { // if (core.plugin.skillTree.getSkillLevel(11) > 0) {
interface Events { // core.plugin.study.declineStudiedSkill();
beforeBattle(enemy: DamageEnemy, x: number, y: number): boolean; // }
afterBattle(enemy: DamageEnemy, x: number, y: number): void;
}
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<string, DamageEnemy[]> = {};
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;
});
};
} }

View File

@ -1,157 +1,162 @@
import { drawHalo } from '../fx/halo'; import { drawHalo } from '../fx/halo';
// 伤害弹出 export function init() {
// 复写阻激夹域检测 // 伤害弹出
control.prototype.checkBlock = function (forceMockery: boolean = false) { // 复写阻激夹域检测
const x = core.getHeroLoc('x'), control.prototype.checkBlock = function (forceMockery: boolean = false) {
y = core.getHeroLoc('y'), const x = core.getHeroLoc('x'),
loc = x + ',' + y; y = core.getHeroLoc('y'),
const info = core.status.thisMap.enemy.mapDamage[loc]; loc = x + ',' + y;
const damage = info?.damage; const info = core.status.thisMap.enemy.mapDamage[loc];
if (damage) { const damage = info?.damage;
if (!main.replayChecking) { if (damage) {
Mota.Plugin.require('pop').addPop( if (!main.replayChecking) {
(x - core.bigmap.offsetX / 32) * 32 + 12, Mota.Plugin.require('pop_r').addPop(
(y - core.bigmap.offsetY / 32) * 32 + 20, (x - core.bigmap.offsetX / 32) * 32 + 12,
(-damage).toString() (y - core.bigmap.offsetY / 32) * 32 + 20,
); (-damage).toString()
} );
core.status.hero.hp -= damage; }
const type = [...info.type]; core.status.hero.hp -= damage;
const text = type.join('') || '伤害'; const type = [...info.type];
core.drawTip('受到' + text + damage + '点'); const text = type.join('') || '伤害';
core.drawHeroAnimate('zone'); core.drawTip('受到' + text + damage + '点');
this._checkBlock_disableQuickShop(); core.drawHeroAnimate('zone');
core.status.hero.statistics.extraDamage += damage; this._checkBlock_disableQuickShop();
if (core.status.hero.hp <= 0) { core.status.hero.statistics.extraDamage += damage;
core.status.hero.hp = 0; if (core.status.hero.hp <= 0) {
core.updateStatusBar(); core.status.hero.hp = 0;
core.events.lose(); core.updateStatusBar();
return; core.events.lose();
} 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
)
return; return;
} else {
core.updateStatusBar();
}
} }
var alpha = core.setAlpha(ctx, one.alpha); checkMockery(loc, forceMockery);
core.fillBoldText(ctx, one.text, px, py, one.color as string); };
core.setAlpha(ctx, alpha);
});
core.setTextAlign(ctx, 'left'); control.prototype._drawDamage_draw = function (
core.setTextBaseline(ctx, 'alphabetic'); ctx: CanvasRenderingContext2D,
core.status.damage.data.forEach(function (one) { onMap: boolean,
var px = one.px, floorId: FloorIds
py = one.py; ) {
if (onMap && core.bigmap.v2) { if (!core.hasItem('book')) return;
px -= core.bigmap.posX * 32; drawHalo(ctx, onMap, floorId);
py -= core.bigmap.posY * 32;
if ( core.setFont(ctx, "14px 'normal'");
px < -32 * 2 || core.setTextAlign(ctx, 'center');
px > core._PX_ + 32 || core.setTextBaseline(ctx, 'middle');
py < -32 || core.status.damage.extraData.forEach(function (one) {
py > core._PY_ + 32 var px = one.px,
) py = one.py;
return; 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(); if (callback) return this.moveAction(callback);
ctx.lineCap = 'round'; this._moveHero_moving();
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();
};
function checkMockery(loc: string, force: boolean = false) { function checkMockery(loc: string, force: boolean = false) {
if (core.status.lockControl && !force) return; if (core.status.lockControl && !force) return;

View File

@ -394,7 +394,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
getHaloSpecials(): number[] { getHaloSpecials(): number[] {
if (!this.floorId) return []; 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 special = this.info.special ?? this.enemy.special;
const filter = special.filter(v => { const filter = special.filter(v => {
return haloSpecials.includes(v) && !this.providedHalo.includes(v); return haloSpecials.includes(v) && !this.providedHalo.includes(v);
@ -424,7 +424,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
if (this.progress !== 2) return; if (this.progress !== 2) return;
this.progress = 3; this.progress = 3;
if (!this.floorId) return; 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; const col = this.col ?? core.status.maps[this.floorId].enemy;
if (!col) return; if (!col) return;
const special = this.getHaloSpecials(); const special = this.getHaloSpecials();
@ -950,8 +950,3 @@ declare global {
enemy: EnemyCollection; enemy: EnemyCollection;
} }
} }
core.plugin.damage = {
Enemy: DamageEnemy,
Collection: EnemyCollection
};

View File

@ -1,27 +1,19 @@
///<reference path="../../../../src/types/core.d.ts" />
// todo: 优化,直接调用 floor.enemy.list 进行计算 // todo: 优化,直接调用 floor.enemy.list 进行计算
/** /**
* *
* @param {FloorIds[]} floorIds
*/ */
export function checkRemainEnemy(floorIds) { export function checkRemainEnemy(floorIds: FloorIds[]) {
/** const enemy: Partial<Record<FloorIds, { loc: LocArr; id: EnemyIds }[]>> =
* @type {Record<FloorIds, {loc: LocArr, id: EnemyIds}[]>} {};
*/
const enemy = {};
floorIds.forEach(v => { floorIds.forEach(v => {
core.extractBlocks(v); core.extractBlocks(v);
const blocks = core.status.maps[v].blocks; const blocks = core.status.maps[v].blocks;
blocks.forEach(block => { blocks.forEach(block => {
if (!block.event.cls.startsWith('enemy') || block.disable) return; if (!block.event.cls.startsWith('enemy') || block.disable) return;
/** const id: EnemyIds = block.event.id as EnemyIds;
* @type {EnemyIds}
*/
const id = block.event.id;
enemy[v] ??= []; enemy[v] ??= [];
const info = enemy[v]; const info = enemy[v]!;
info.push({ loc: [block.x, block.y], id }); 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 enemy = checkRemainEnemy(floorIds);
const str = []; const str = [];
let now = []; let now = [];
for (const floor in enemy) { for (const floor in enemy) {
/** const all: { loc: LocArr; id: EnemyIds }[] = enemy[floor as FloorIds]!;
* @type {{loc: LocArr, id: EnemyIds}[]} const remain: Partial<Record<EnemyIds, number>> = {};
*/
const all = enemy[floor];
/**
* @type {Record<EnemyIds, number>}
*/
const remain = {};
all.forEach(v => { all.forEach(v => {
const id = v.id; const id = v.id;
remain[id] ??= 0; 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) { for (const id in remain) {
const name = core.material.enemys[id].name; const name = core.material.enemys[id as EnemyIds].name;
now.push(`${title}(${floor}): ${name} * ${remain[id]}`); now.push(`${title}(${floor}): ${name} * ${remain[id as EnemyIds]}`);
if (now.length === 10) { if (now.length === 10) {
str.push(now.join('\n')); str.push(now.join('\n'));
now = []; now = [];
@ -67,8 +52,3 @@ export function getRemainEnemyString(floorIds) {
return str; return str;
} }
core.plugin.remainEnemy = {
checkRemainEnemy,
getRemainEnemyString
};

View File

@ -7,7 +7,7 @@ export interface SpecialDeclaration {
color: string; color: string;
} }
export const enemySpecials: SpecialDeclaration[] = [ export const specials: SpecialDeclaration[] = [
{ {
code: 0, code: 0,
name: '空', name: '空',
@ -202,11 +202,3 @@ export const enemySpecials: SpecialDeclaration[] = [
color: '#ff6f0a' color: '#ff6f0a'
} }
]; ];
declare global {
interface PluginDeclaration {
special: SpecialDeclaration[];
}
}
core.plugin.special = enemySpecials;

View File

@ -1,199 +0,0 @@
///<reference path="../../../src/types/core.d.ts" />
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)
};
};

View File

@ -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)
};
};
}

View File

@ -1,58 +0,0 @@
///<reference path="../../../../src/types/core.d.ts" />
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;
};

View File

@ -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;
};
}

View File

@ -1,33 +1,35 @@
import { ensureFloorDamage } from '../enemy/damage'; import { ensureFloorDamage } from '../enemy/damage';
core.control.updateDamage = function (floorId = core.status.floorId, ctx) { export function init() {
if (!floorId || core.status.gameOver || main.mode !== 'play') return; core.control.updateDamage = function (floorId = core.status.floorId, ctx) {
const onMap = ctx == null; if (!floorId || core.status.gameOver || main.mode !== 'play') return;
const floor = core.status.maps[floorId]; const onMap = ctx == null;
const floor = core.status.maps[floorId];
// 没有怪物手册 // 没有怪物手册
// if (!core.hasItem('book')) return; // if (!core.hasItem('book')) return;
core.status.damage.posX = core.bigmap.posX; core.status.damage.posX = core.bigmap.posX;
core.status.damage.posY = core.bigmap.posY; core.status.damage.posY = core.bigmap.posY;
if (!onMap) { if (!onMap) {
const width = core.floors[floorId].width, const width = core.floors[floorId].width,
height = core.floors[floorId].height; height = core.floors[floorId].height;
// 地图过大的缩略图不绘制显伤 // 地图过大的缩略图不绘制显伤
if (width * height > core.bigmap.threshold) return; if (width * height > core.bigmap.threshold) return;
} }
// 计算伤害 // 计算伤害
ensureFloorDamage(floorId); ensureFloorDamage(floorId);
floor.enemy.extract(); floor.enemy.extract();
floor.enemy.calDamage(true); floor.enemy.calDamage(true);
floor.enemy.calMapDamage(); floor.enemy.calMapDamage();
core.status.damage.data = []; core.status.damage.data = [];
floor.enemy.render(true); floor.enemy.render(true);
getItemDetail(floorId, onMap); // 宝石血瓶详细信息 getItemDetail(floorId, onMap); // 宝石血瓶详细信息
this.drawDamage(ctx, floorId); this.drawDamage(ctx, floorId);
}; };
}
// 获取宝石信息 并绘制 // 获取宝石信息 并绘制
function getItemDetail(floorId: FloorIds, onMap: boolean) { function getItemDetail(floorId: FloorIds, onMap: boolean) {

View File

@ -1,59 +1,61 @@
import { getEnemy } from '../enemy/battle'; import { getEnemy } from '../enemy/battle';
import { formatDamage } from '../utils'; import { formatDamage } from '../utils';
core.maps._initDetachedBlock = function ( export function init() {
info: BlockInfo, core.maps._initDetachedBlock = function (
x: number, info: BlockInfo,
y: number, x: number,
displayDamage: boolean = false 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
) { ) {
const enemy = getEnemy(x, y); let headCanvas = null,
const dam = enemy.calDamage(); bodyCanvas = '__body_' + x + '_' + y,
const { damage, color } = formatDamage(dam.damage); damageCanvas = null;
damageCanvas = '__damage_' + x + '_' + y; // head
const ctx = core.createCanvas(damageCanvas, 0, 0, 32, 32, 65); if (!info.bigImage && info.height > 32) {
ctx.textAlign = 'left'; headCanvas = '__head_' + x + '_' + y;
ctx.font = '14px normal'; core.createCanvas(headCanvas, 0, 0, 32, info.height - 32, 55);
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');
} }
} // body
return { if (info.bigImage) {
headCanvas, var bigImageInfo = this._getBigImageInfo(
bodyCanvas, info.bigImage,
damageCanvas 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
};
}; };
}; }

View File

@ -54,6 +54,7 @@ function getRealStatus(
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[], name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
floorId: FloorIds = core.status.floorId floorId: FloorIds = core.status.floorId
): any { ): any {
const { getSkillLevel } = Mota.Plugin.require('skillTree_g');
if (name instanceof Array) { if (name instanceof Array) {
return Object.fromEntries( return Object.fromEntries(
name.map(v => [v, getRealStatus(status, v, floorId)]) name.map(v => [v, getRealStatus(status, v, floorId)])
@ -84,7 +85,7 @@ function getRealStatus(
// 技能 // 技能
if (flags.bladeOn && flags.blade) { if (flags.bladeOn && flags.blade) {
const level = core.plugin.skillTree.getSkillLevel(2); const level = getSkillLevel(2);
if (name === 'atk') { if (name === 'atk') {
s *= 1 + 0.1 * level; s *= 1 + 0.1 * level;
} }
@ -93,7 +94,7 @@ function getRealStatus(
} }
} }
if (flags.shield && flags.shieldOn) { if (flags.shield && flags.shieldOn) {
const level = core.plugin.skillTree.getSkillLevel(10); const level = getSkillLevel(10);
if (name === 'atk') { if (name === 'atk') {
s *= 1 - 0.1 * level; s *= 1 - 0.1 * level;
} }
@ -119,8 +120,3 @@ declare global {
}; };
} }
} }
core.plugin.hero = {
getHeroStatusOf,
getHeroStatusOn
};

View File

@ -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
};

65
src/plugin/game/index.ts Normal file
View File

@ -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
// };

View File

@ -1,230 +0,0 @@
///<reference path="../../../src/types/core.d.ts" />
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
};

257
src/plugin/game/loopMap.ts Normal file
View File

@ -0,0 +1,257 @@
///<reference path="../../../src/types/core.d.ts" />
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<DiredLoc> = {};
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<Block> = { 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;
};
}

View File

@ -1,3 +1,5 @@
import { has } from './utils';
type RangeScanFn<C extends Partial<Loc>> = ( type RangeScanFn<C extends Partial<Loc>> = (
collection: Range<C>, collection: Range<C>,
data: any data: any
@ -77,8 +79,8 @@ Range.registerRangeType(
return list.filter(v => { return list.filter(v => {
return ( return (
core.has(v.x) && has(v.x) &&
core.has(v.y) && has(v.y) &&
Math.abs(v.x - x) <= r && Math.abs(v.x - x) <= r &&
Math.abs(v.y - y) <= r Math.abs(v.y - y) <= r
); );
@ -87,8 +89,8 @@ Range.registerRangeType(
(col, { x, y, d }, item) => { (col, { x, y, d }, item) => {
const r = Math.floor(d / 2); const r = Math.floor(d / 2);
return ( return (
core.has(item.x) && has(item.x) &&
core.has(item.y) && has(item.y) &&
Math.abs(item.x - x) <= r && Math.abs(item.x - x) <= r &&
Math.abs(item.y - y) <= r Math.abs(item.y - y) <= r
); );

View File

@ -1,14 +1,20 @@
///<reference path="../../../src/types/core.d.ts" /> ///<reference path="../../../src/types/core.d.ts" />
export function removeMaps(fromId, toId, force) { export function removeMaps(
fromId: FloorIds,
toId: FloorIds,
force: boolean = false
) {
toId = toId || fromId; toId = toId || fromId;
var fromIndex = core.floorIds.indexOf(fromId), var fromIndex = core.floorIds.indexOf(fromId),
toIndex = core.floorIds.indexOf(toId); toIndex = core.floorIds.indexOf(toId);
if (toIndex < 0) toIndex = core.floorIds.length - 1; if (toIndex < 0) toIndex = core.floorIds.length - 1;
flags.__visited__ = flags.__visited__ || {}; // @ts-ignore
flags.__removed__ = flags.__removed__ || []; flags.__visited__ ??= {};
flags.__disabled__ = flags.__disabled__ || {}; flags.__removed__ ??= [];
flags.__leaveLoc__ = flags.__leaveLoc__ || {}; flags.__disabled__ ??= {};
// @ts-ignore
flags.__leaveLoc__ ??= {};
flags.__forceDelete__ ??= {}; flags.__forceDelete__ ??= {};
let deleted = false; let deleted = false;
for (var i = fromIndex; i <= toIndex; ++i) { for (var i = fromIndex; i <= toIndex; ++i) {
@ -36,11 +42,11 @@ export function removeMaps(fromId, toId, force) {
deleted = true; deleted = true;
} }
if (deleted && !main.replayChecking) { 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[`jump_${floorId}`];
delete flags[`inte_${floorId}`]; delete flags[`inte_${floorId}`];
delete flags[`loop_${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("MT1", "MT300") 恢复MT1~MT300之间的全部层
// core.plugin.removeMap.resumeMaps("MT10") 只恢复MT10层 // core.plugin.removeMap.resumeMaps("MT10") 只恢复MT10层
export function resumeMaps(fromId, toId) { export function resumeMaps(fromId: FloorIds, toId: FloorIds) {
toId = toId || fromId; toId = toId || fromId;
var fromIndex = core.floorIds.indexOf(fromId), var fromIndex = core.floorIds.indexOf(fromId),
toIndex = core.floorIds.indexOf(toId); toIndex = core.floorIds.indexOf(toId);
@ -65,19 +71,21 @@ export function resumeMaps(fromId, toId) {
flags.__forceDelete__[floorId] flags.__forceDelete__[floorId]
) )
continue; continue;
// @ts-ignore
flags.__removed__ = flags.__removed__.filter(f => { flags.__removed__ = flags.__removed__.filter(f => {
return f != floorId; return f != floorId;
}); });
// @ts-ignore
core.status.maps[floorId] = core.loadFloor(floorId); core.status.maps[floorId] = core.loadFloor(floorId);
} }
} }
// 分区砍层相关 // 分区砍层相关
var inAnyPartition = floorId => { var inAnyPartition = (floorId: FloorIds) => {
var inPartition = false; var inPartition = false;
(core.floorPartitions || []).forEach(floor => { (core.floorPartitions || []).forEach(floor => {
var fromIndex = core.floorIds.indexOf(floor[0]); 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); var index = core.floorIds.indexOf(floorId);
if (fromIndex < 0 || index < 0) return; if (fromIndex < 0 || index < 0) return;
if (toIndex < 0) toIndex = core.floorIds.length - 1; 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; if (main.mode != 'play' || !inAnyPartition(floorId)) return;
// 根据分区信息自动砍层与恢复 // 根据分区信息自动砍层与恢复
(core.floorPartitions || []).forEach(floor => { (core.floorPartitions || []).forEach(floor => {
var fromIndex = core.floorIds.indexOf(floor[0]); 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); var index = core.floorIds.indexOf(floorId);
if (fromIndex < 0 || index < 0) return; if (fromIndex < 0 || index < 0) return;
if (toIndex < 0) toIndex = core.floorIds.length - 1; if (toIndex < 0) toIndex = core.floorIds.length - 1;
if (index >= fromIndex && index <= toIndex) { if (index >= fromIndex && index <= toIndex) {
core.plugin.removeMap.resumeMaps( resumeMaps(core.floorIds[fromIndex], core.floorIds[toIndex]);
core.floorIds[fromIndex],
core.floorIds[toIndex]
);
} else { } else {
removeMaps(core.floorIds[fromIndex], core.floorIds[toIndex]); removeMaps(core.floorIds[fromIndex], core.floorIds[toIndex]);
} }
}); });
} }
core.plugin.removeMap = {
removeMaps,
deleteFlags,
resumeMaps,
autoRemoveMaps
};

View File

@ -1,122 +0,0 @@
///<reference path="../../../src/types/core.d.ts" />
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
};

121
src/plugin/game/replay.ts Normal file
View File

@ -0,0 +1,121 @@
///<reference path="../../../src/types/core.d.ts" />
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;
});
}

View File

@ -1,27 +1,29 @@
///<reference path="../../../src/types/core.d.ts" /> export function openShop(shopId: string, noRoute: boolean) {
const shop = core.status.shops[shopId] as ItemShopEvent;
const { openItemShop } = core.plugin.gameUi;
export function openShop(shopId, noRoute) {
var shop = core.status.shops[shopId];
// Step 1: 检查能否打开此商店 // Step 1: 检查能否打开此商店
if (!this.canOpenShop(shopId)) { if (!canOpenShop(shopId)) {
core.drawTip('该商店尚未开启'); core.drawTip('该商店尚未开启');
return false; return false;
} }
// Step 3: 检查道具商店 or 公共事件 // Step 3: 检查道具商店 or 公共事件
if (shop.item) { if (shop.item) {
if (openItemShop) openItemShop(shopId); Mota.r(() => {
if (!core.isReplaying()) {
Mota.require('var', 'mainUi').open('shop', {
shopId: shopId
});
}
});
return; return;
} }
return true; return true;
} }
/// 是否访问过某个快捷商店 /// 是否访问过某个快捷商店
export function isShopVisited(id) { export function isShopVisited(id: string) {
flags.__shops__ ??= {}; flags.__shops__ ??= {};
var shops = core.getFlag('__shops__'); var shops = core.getFlag<any>('__shops__');
if (!shops[id]) shops[id] = {}; if (!shops[id]) shops[id] = {};
return shops[id].visited; return shops[id].visited;
} }
@ -29,25 +31,24 @@ export function isShopVisited(id) {
/// 当前应当显示的快捷商店列表 /// 当前应当显示的快捷商店列表
export function listShopIds() { export function listShopIds() {
return Object.keys(core.status.shops).filter(id => { return Object.keys(core.status.shops).filter(id => {
return ( // @ts-ignore
core.plugin.shop.isShopVisited(id) || return isShopVisited(id) || !core.status.shops[id].mustEnable;
!core.status.shops[id].mustEnable
);
}); });
} }
/// 是否能够打开某个商店 /// 是否能够打开某个商店
export function canOpenShop(id) { export function canOpenShop(id: string) {
if (this.isShopVisited(id)) return true; if (isShopVisited(id)) return true;
var shop = core.status.shops[id]; var shop = core.status.shops[id];
// @ts-ignore
if (shop.item || shop.commonEvent || shop.mustEnable) return false; if (shop.item || shop.commonEvent || shop.mustEnable) return false;
return true; return true;
} }
/// 启用或禁用某个快捷商店 /// 启用或禁用某个快捷商店
export function setShopVisited(id, visited) { export function setShopVisited(id: string, visited: boolean) {
if (!core.hasFlag('__shops__')) core.setFlag('__shops__', {}); if (!core.hasFlag('__shops__')) core.setFlag('__shops__', {});
var shops = core.getFlag('__shops__'); var shops = core.getFlag<any>('__shops__');
if (!shops[id]) shops[id] = {}; if (!shops[id]) shops[id] = {};
if (visited) shops[id].visited = true; if (visited) shops[id].visited = true;
else delete shops[id].visited; else delete shops[id].visited;
@ -63,12 +64,3 @@ export function canUseQuickShop() {
return '当前楼层不能使用快捷商店。'; return '当前楼层不能使用快捷商店。';
return null; return null;
} }
core.plugin.shop = {
openShop,
isShopVisited,
listShopIds,
canOpenShop,
setShopVisited,
canUseQuickShop
};

View File

@ -1,4 +1,4 @@
///<reference path="../../../src/types/core.d.ts" /> // @ts-nocheck
// 所有的主动技能效果 // 所有的主动技能效果
var ignoreInJump = { var ignoreInJump = {
@ -19,8 +19,7 @@ var ignoreInJump = {
] ]
}; };
/** @type {FloorIds[]} */ export const jumpIgnoreFloor: FloorIds[] = [
export const jumpIgnoreFloor = [
'MT31', 'MT31',
'snowTown', 'snowTown',
'MT36', 'MT36',
@ -178,8 +177,3 @@ export function jumpSkill() {
return { x: x, y: y }; return { x: x, y: y };
} }
} }
core.plugin.skillEffects = {
jumpSkill,
jumpIgnoreFloor
};

View File

@ -1,14 +1,11 @@
///<reference path="../../../src/types/core.d.ts" /> ///<reference path="../../../src/types/core.d.ts" />
/** let levels: number[] = [];
* @type {number[]}
*/
let levels = [];
/** /**
* @type {Record<Chapter, Skill[]>} * @type {Record<Chapter, Skill[]>}
*/ */
const skills = { export const skills: Record<Chapter, Skill[]> = {
chapter1: [ chapter1: [
{ {
index: 0, index: 0,
@ -195,13 +192,11 @@ const skills = {
] ]
}; };
core.plugin.skills = skills;
export function resetSkillLevel() { export function resetSkillLevel() {
levels = []; levels = [];
} }
export function getSkillFromIndex(index) { export function getSkillFromIndex(index: number) {
for (const [, skill] of Object.entries(skills)) { for (const [, skill] of Object.entries(skills)) {
const s = skill.find(v => v.index === index); const s = skill.find(v => v.index === index);
if (s) return s; if (s) return s;
@ -212,16 +207,21 @@ export function getSkillFromIndex(index) {
* *
* @param {number} skill * @param {number} skill
*/ */
export function getSkillLevel(skill) { export function getSkillLevel(skill: number) {
return (levels[skill] ??= 0); return (levels[skill] ??= 0);
} }
export function getSkillConsume(skill) { export function getSkillConsume(skill: number) {
return eval( return eval(
getSkillFromIndex(skill).consume.replace(/level(:\d+)?/g, (str, $1) => { getSkillFromIndex(skill)?.consume.replace(
if ($1) return `core.plugin.skillTree.getSkillLevel(${$1})`; /level(:\d+)?/g,
else return `core.plugin.skillTree.getSkillLevel(${skill})`; (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) { export function canUpgrade(skill: number) {
const consume = core.plugin.skillTree.getSkillConsume(skill); const consume = getSkillConsume(skill);
if (consume > core.status.hero.mdef) return false; if (consume > core.status.hero.mdef) return false;
const level = core.plugin.skillTree.getSkillLevel(skill); const level = getSkillLevel(skill);
const s = getSkillFromIndex(skill); const s = getSkillFromIndex(skill);
if (level === s.max) return false; if (level === s?.max) return false;
const front = s.front; const front = s?.front ?? [];
for (const [skill, level] of front) { for (const [skill, level] of front) {
if (core.plugin.skillTree.getSkillLevel(skill) < level) return false; if (getSkillLevel(skill) < level) return false;
} }
return true; return true;
} }
@ -251,7 +250,7 @@ export function canUpgrade(skill) {
* *
* @param {number} skill * @param {number} skill
*/ */
export function upgradeSkill(skill) { export function upgradeSkill(skill: number) {
if (!canUpgrade(skill)) return false; if (!canUpgrade(skill)) return false;
switch (skill) { switch (skill) {
case 0: // 力量 +2攻击 case 0: // 力量 +2攻击
@ -302,17 +301,6 @@ export function saveSkillTree() {
return levels.slice(); return levels.slice();
} }
export function loadSkillTree(data) { export function loadSkillTree(data: number[]) {
levels = data ?? []; levels = data ?? [];
} }
core.plugin.skillTree = {
getSkillConsume,
getSkillFromIndex,
getSkillLevel,
saveSkillTree,
loadSkillTree,
upgradeSkill,
openTree,
resetSkillLevel
};

View File

@ -12,7 +12,8 @@ const cannotStudy = [9, 12, 14, 15, 24];
export function canStudySkill(number: number) { export function canStudySkill(number: number) {
const s = (core.status.hero.special ??= { num: [], last: [] }); 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.length >= 1) return false;
if (s.num.includes(number)) return false; if (s.num.includes(number)) return false;
if (cannotStudy.includes(number)) return false; if (cannotStudy.includes(number)) return false;

View File

@ -1,4 +1,4 @@
///<reference path="../../../src/types/core.d.ts" /> // @ts-nocheck
import { clip } from './replay.js'; import { clip } from './replay.js';
// 1000多行改不动了原来什么样就什么样吧 // 1000多行改不动了原来什么样就什么样吧
@ -11,7 +11,7 @@ var stage = 1,
boomLocs = [], // 随机轰炸 boomLocs = [], // 随机轰炸
heroHp; heroHp;
// 初始化 // 初始化
function initTowerBoss() { export function initTowerBoss() {
stage = 1; stage = 1;
hp = 10000; hp = 10000;
seconds = 0; seconds = 0;
@ -496,7 +496,7 @@ function intelligentArrow(fromSelf) {
damaged[loc + direction] = true; damaged[loc + direction] = true;
core.drawHeroAnimate('hand'); core.drawHeroAnimate('hand');
core.status.hero.hp -= 1000; core.status.hero.hp -= 1000;
Mota.Plugin.require('pop').addPop( Mota.Plugin.require('pop_r').addPop(
x * 32 + 16, x * 32 + 16,
y * 32 + 16, y * 32 + 16,
-1000 -1000
@ -515,7 +515,7 @@ function intelligentArrow(fromSelf) {
damaged[loc + direction] = true; damaged[loc + direction] = true;
core.drawHeroAnimate('hand'); core.drawHeroAnimate('hand');
core.status.hero.hp -= 1000; core.status.hero.hp -= 1000;
Mota.Plugin.require('pop').addPop( Mota.Plugin.require('pop_r').addPop(
x * 32 + 16, x * 32 + 16,
y * 32 + 16, y * 32 + 16,
-1000 -1000
@ -645,7 +645,7 @@ function icyMomentem() {
if (x == locs[index][0] && y == locs[index][1]) { if (x == locs[index][0] && y == locs[index][1]) {
core.drawHeroAnimate('hand'); core.drawHeroAnimate('hand');
core.status.hero.hp -= 5000; core.status.hero.hp -= 5000;
Mota.Plugin.require('pop').addPop( Mota.Plugin.require('pop_r').addPop(
x * 32 + 16, x * 32 + 16,
y * 32 + 16, y * 32 + 16,
-5000 -5000
@ -824,7 +824,7 @@ function getThunderDamage(x, y, power) {
hy = core.status.hero.loc.y; hy = core.status.hero.loc.y;
if (Math.abs(hx - x) <= 1 && Math.abs(hy - y) <= 1) { if (Math.abs(hx - x) <= 1 && Math.abs(hy - y) <= 1) {
core.status.hero.hp -= 3000 * power; core.status.hero.hp -= 3000 * power;
Mota.Plugin.require('pop').addPop( Mota.Plugin.require('pop_r').addPop(
x * 32 + 16, x * 32 + 16,
y * 32 + 16, y * 32 + 16,
-3000 * power -3000 * power
@ -992,7 +992,7 @@ function ballThunder() {
) { ) {
damaged[i] = true; damaged[i] = true;
core.status.hero.hp -= 3000; core.status.hero.hp -= 3000;
Mota.Plugin.require('pop').addPop( Mota.Plugin.require('pop_r').addPop(
x * 32 + 16, x * 32 + 16,
y * 32 + 16, y * 32 + 16,
-3000 -3000
@ -1502,7 +1502,7 @@ function boomingAnimate() {
hy = core.status.hero.loc.y; hy = core.status.hero.loc.y;
if (loc[0] == hx && loc[1] == hy) { if (loc[0] == hx && loc[1] == hy) {
core.status.hero.hp -= 3000; core.status.hero.hp -= 3000;
Mota.Plugin.require('pop').addPop( Mota.Plugin.require('pop_r').addPop(
x * 32 + 16, x * 32 + 16,
y * 32 + 16, y * 32 + 16,
-3000 -3000
@ -1545,7 +1545,7 @@ function lineDamage(x1, y1, x2, y2, damage) {
n2 = ((y2 - y1) / (x2 - x1)) * (loc2[0] - x1) + y1 - loc2[1]; n2 = ((y2 - y1) / (x2 - x1)) * (loc2[0] - x1) + y1 - loc2[1];
if (n1 * n2 <= 0) { if (n1 * n2 <= 0) {
core.status.hero.hp -= damage; core.status.hero.hp -= damage;
Mota.Plugin.require('pop').addPop( Mota.Plugin.require('pop_r').addPop(
x * 32 + 16, x * 32 + 16,
y * 32 + 16, y * 32 + 16,
-damage -damage
@ -1569,7 +1569,7 @@ function lineDamage(x1, y1, x2, y2, damage) {
n2 = ((y2 - y1) / (x2 - x1)) * (loc2[0] - x1) + y1 - loc2[1]; n2 = ((y2 - y1) / (x2 - x1)) * (loc2[0] - x1) + y1 - loc2[1];
if (n1 * n2 <= 0) { if (n1 * n2 <= 0) {
core.status.hero.hp -= damage; core.status.hero.hp -= damage;
Mota.Plugin.require('pop').addPop( Mota.Plugin.require('pop_r').addPop(
x * 32 + 16, x * 32 + 16,
y * 32 + 16, y * 32 + 16,
-damage -damage
@ -1587,9 +1587,3 @@ function lineDamage(x1, y1, x2, y2, damage) {
} }
} }
} }
core.plugin.towerBoss = {
initTowerBoss
};
export {};

View File

@ -1,29 +1,8 @@
///<reference path="../../../src/types/core.d.ts" /> // @ts-nocheck
export {};
(function () { export function init() {
const { mainUi, fixedUi } = Mota.requireAll('var'); 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 () { ui.prototype.drawBook = function () {
if (!core.isReplaying()) return mainUi.open('book'); if (!core.isReplaying()) return mainUi.open('book');
}; };
@ -86,14 +65,11 @@ export {};
core.dom.toolBar.style.display = 'none'; core.dom.toolBar.style.display = 'none';
} }
}; };
}
function openSkill() { function updateVueStatusBar() {
if (core.isReplaying()) return; Mota.r(() => {
mainUi.open('skill'); const status = Mota.require('var', 'status');
} status.value = !status.value;
});
core.plugin.gameUi = { }
openItemShop,
openSkill
};
})();

View File

@ -169,18 +169,3 @@ export function findDir(from: Loc, to: Loc): Dir2 | 'none' {
})?.[0] as Dir2) ?? 'none' })?.[0] as Dir2) ?? 'none'
); );
} }
declare global {
interface GamePluginUtils {
ofDir: typeof ofDir;
}
}
core.plugin.utils = {
slide,
backDir,
has,
maxGameScale,
ofDir
};
core.has = has;

View File

@ -35,8 +35,8 @@ const marked: MarkInfo<EnemyIds>[] = [];
*/ */
export function markEnemy(id: EnemyIds) { export function markEnemy(id: EnemyIds) {
if (hasMarkedEnemy(id)) return; if (hasMarkedEnemy(id)) return;
const { Enemy } = core.plugin.damage; const { DamageEnemy } = Mota.Plugin.require('damage_g');
const enemy = new Enemy(core.material.enemys[id]); const enemy = new DamageEnemy(core.material.enemys[id]);
enemy.calAttribute(); enemy.calAttribute();
enemy.getRealInfo(); enemy.getRealInfo();
@ -44,7 +44,7 @@ export function markEnemy(id: EnemyIds) {
id, id,
enemy, enemy,
mode: 0b011111, mode: 0b011111,
lastAtk: core.plugin.hero.getHeroStatusOn('atk', 'empty'), lastAtk: Mota.Plugin.require('hero_g').getHeroStatusOn('atk', 'empty'),
lastDamage: enemy.calDamage().damage, lastDamage: enemy.calDamage().damage,
status: 0b0, status: 0b0,
update: ref(true) update: ref(true)
@ -66,9 +66,10 @@ export function unmarkEnemy(id: EnemyIds) {
} }
export function checkMarkedEnemy() { export function checkMarkedEnemy() {
const { getHeroStatusOn } = Mota.Plugin.require('hero_g');
marked.forEach(v => { marked.forEach(v => {
const { id, enemy, mode, lastAtk, lastDamage, markDamage } = 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; let tip = 0;
if (mode & 0b11110) { if (mode & 0b11110) {
const damage = enemy.calDamage().damage; const damage = enemy.calDamage().damage;

View File

@ -36,26 +36,11 @@ export interface Light {
_offset?: Loc; _offset?: Loc;
} }
export default function init() { export function init() {
core.registerAnimationFrame('shadow', true, () => { core.registerAnimationFrame('shadow', true, () => {
if (!needRefresh) return; if (!needRefresh) return;
drawShadow(); drawShadow();
}); });
return {
initShadowCanvas,
drawShadow,
addLight,
removeLight,
setLight,
setShadowNodes,
setBackground,
animateLight,
transitionLight,
moveLightAs,
getAllLights,
refreshLight
};
} }
let canvas: HTMLCanvasElement; let canvas: HTMLCanvasElement;

View File

@ -59,13 +59,14 @@ export function getNowStatus(nowEquip?: Equip, onCol: boolean = false) {
'hpmax', 'hpmax',
'money' 'money'
] as (keyof SelectType<HeroStatus, number>)[]; ] as (keyof SelectType<HeroStatus, number>)[];
const { getHeroStatusOn } = Mota.Plugin.require('hero_g');
return ( return (
<div id="hero-status"> <div id="hero-status">
{toShow.map(v => { {toShow.map(v => {
let status: string; let status: string;
if (v === 'lv') status = core.getLvName() ?? ''; if (v === 'lv') status = core.getLvName() ?? '';
else status = core.plugin.hero.getHeroStatusOn(v)?.toString(); else status = getHeroStatusOn(v)?.toString();
let add = 0; let add = 0;
if (has(nowEquip)) { if (has(nowEquip)) {

View File

@ -29,7 +29,7 @@ export function getDetailedEnemy(
return typeof func === 'string' ? func : func(enemy); return typeof func === 'string' ? func : func(enemy);
}; };
const special: [string, string, string][] = enemy.enemy.special.map(vv => { 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 [ return [
fromFunc(s.name, enemy.enemy), fromFunc(s.name, enemy.enemy),
fromFunc(s.desc, enemy.enemy), fromFunc(s.desc, enemy.enemy),

View File

@ -225,6 +225,7 @@ export async function doByInterval(
/** /**
* *
* @deprecated
* @param name * @param name
* @param fn * @param fn
* @param defaultValue * @param defaultValue
@ -287,7 +288,8 @@ export function spliceBy<T>(arr: T[], from: T): T[] {
} }
export async function triggerFullscreen(full: boolean) { 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) { if (!!document.fullscreenElement && !full) {
await document.exitFullscreen(); await document.exitFullscreen();
requestAnimationFrame(() => { requestAnimationFrame(() => {

View File

@ -1068,6 +1068,9 @@ interface Control {
* *
*/ */
resize(): void; resize(): void;
_drawHero_updateViewport(x: number, y: number, offset: Loc): void;
_moveAction_moving(callback: () => void): void;
} }
declare const control: new () => Control; declare const control: new () => Control;

8
src/types/core.d.ts vendored
View File

@ -1062,11 +1062,6 @@ interface Core extends Pick<Main, CoreDataFromMain> {
*/ */
readonly actions: Actions; readonly actions: Actions;
/**
*
*/
readonly plugin: PluginDeclaration;
/** /**
* *
* @param coreData * @param coreData
@ -1098,8 +1093,7 @@ type CoreMixin = Core &
Forward<Ui> & Forward<Ui> &
Forward<Utils> & Forward<Utils> &
Forward<Icons> & Forward<Icons> &
Forward<Actions> & Forward<Actions>;
Forward<PluginDeclaration>;
interface MainStyle extends Readonly<StatusStyle> { interface MainStyle extends Readonly<StatusStyle> {
/** /**

View File

@ -272,6 +272,8 @@ interface Enemys {
floorId?: FloorIds, floorId?: FloorIds,
dir?: Dir | 'none' | (Dir | 'none')[] dir?: Dir | 'none' | (Dir | 'none')[]
): boolean; ): boolean;
getCurrentEnemys(floorId: FloorIds): any[];
} }
declare const enemys: new () => Enemys; declare const enemys: new () => Enemys;

View File

@ -758,11 +758,16 @@ interface Events extends EventData {
*/ */
tryUseItem(itemId: ItemIdOf<'tools' | 'constants'>): void; tryUseItem(itemId: ItemIdOf<'tools' | 'constants'>): void;
beforeBattle(): boolean;
afterBattle(enemy: DamageEnemy, x?: number, y?: number): void;
_sys_battle(data: Block, callback?: () => void): void; _sys_battle(data: Block, callback?: () => void): void;
_action_battle(data: any, x?: number, y?: number, prefix?: any): void; _action_battle(data: any, x?: number, y?: number, prefix?: any): void;
__action_getLoc(data: any, x?: number, y?: number, prefix?: any): any; __action_getLoc(data: any, x?: number, y?: number, prefix?: any): any;
_changeFloor_beforeChange(info: any, callback: () => void): void;
} }
declare const events: new () => Events; declare const events: new () => Events;

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

@ -84,6 +84,10 @@ interface Block<N extends Exclude<AllNumbers, 0> = Exclude<AllNumbers, 0>> {
* *
*/ */
doorInfo?: DoorInfo; doorInfo?: DoorInfo;
data?: any;
script?: string;
event?: MotaEvent;
}; };
} }

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

@ -713,7 +713,9 @@ type MotaTrigger =
| 'openDoor' | 'openDoor'
| 'ski' | 'ski'
| 'custom' | 'custom'
| 'getItem'; | 'getItem'
| 'changeFloor'
| 'null';
/** /**
* *

View File

@ -83,7 +83,7 @@ const special = (() => {
}; };
const show = s.slice(0, 2).map(v => { 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]; return [fromFunc(s.name, enemy.enemy), s.color];
}); });
if (s.length > 2) show.push(['...', 'white']); if (s.length > 2) show.push(['...', 'white']);

View File

@ -58,7 +58,7 @@ const content = computed(() => {
.join('') .join('')
.replace( .replace(
/level:(\d+)/g, /level:(\d+)/g,
'core.plugin.skillTree.getSkillLevel($1)' 'Mota.Plugin.require("skillTree_g").getSkillLevel($1)'
) + ) +
'`' '`'
); );

View File

@ -89,6 +89,8 @@ const props = defineProps<{
ui: GameUi; ui: GameUi;
}>(); }>();
const skillTree = Mota.Plugin.require('skillTree_g');
let canvas: HTMLCanvasElement; let canvas: HTMLCanvasElement;
let ctx: CanvasRenderingContext2D; let ctx: CanvasRenderingContext2D;
@ -103,9 +105,11 @@ const chapterDict = {
flags.skillTree ??= 0; 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]; chapter.value = chapterList[flags.skillTree];
watch(selected, draw); watch(selected, draw);
@ -115,20 +119,19 @@ const mdef = ref(core.status.hero.mdef);
const skill = computed(() => { const skill = computed(() => {
update.value; update.value;
return core.plugin.skillTree.getSkillFromIndex(selected.value); return skillTree.getSkillFromIndex(selected.value);
}); });
const skills = computed(() => { const skills = computed(() => {
return core.plugin.skills[chapter.value]; return s[chapter.value];
}); });
const desc = computed(() => { const desc = computed(() => {
return eval( return eval(
'`' + '`' +
splitText(skill.value.desc).replace(/level(:\d+)?/g, (str, $1) => { splitText(skill.value.desc).replace(/level(:\d+)?/g, (str, $1) => {
if ($1) return `core.plugin.skillTree.getSkillLevel(${$1})`; if ($1) return `skillTree.getSkillLevel(${$1})`;
else else return `skillTree.getSkillLevel(${skill.value.index})`;
return `core.plugin.skillTree.getSkillLevel(${skill.value.index})`;
}) + }) +
'`' '`'
); );
@ -143,9 +146,9 @@ const effect = computed(() => {
.join('') .join('')
.replace(/level(:\d+)?/g, (str, $1) => { .replace(/level(:\d+)?/g, (str, $1) => {
if ($1) if ($1)
return `(core.plugin.skillTree.getSkillLevel(${$1}) + ${v})`; return `(skillTree.getSkillLevel(${$1}) + ${v})`;
else 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(() => { const front = computed(() => {
return skill.value.front.map(v => { return skill.value.front.map(v => {
return `${ return `${skillTree.getSkillLevel(v[0]) >= v[1] ? 'a' : 'b'}${
core.plugin.skillTree.getSkillLevel(v[0]) >= v[1] ? 'a' : 'b' v[1]
}${v[1]}${skills.value[dict.value[v[0]]].title}`; }${skills.value[dict.value[v[0]]].title}`;
}); });
}); });
const consume = computed(() => { const consume = computed(() => {
update.value; update.value;
return core.plugin.skillTree.getSkillConsume(selected.value); return skillTree.getSkillConsume(selected.value);
}); });
const level = computed(() => { const level = computed(() => {
update.value; update.value;
return core.plugin.skillTree.getSkillLevel(selected.value); return skillTree.getSkillLevel(selected.value);
}); });
function exit() { function exit() {
@ -204,9 +207,9 @@ function draw() {
ctx.lineTo( ctx.lineTo(
...(s.loc.map(v => (v * 2 - 1) * per + per / 2) as LocArr) ...(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'; ctx.strokeStyle = '#aaa';
else if (core.plugin.skillTree.getSkillLevel(s.index) === s.max) else if (skillTree.getSkillLevel(s.index) === s.max)
ctx.strokeStyle = '#ff0'; ctx.strokeStyle = '#ff0';
else ctx.strokeStyle = '#0f8'; else ctx.strokeStyle = '#0f8';
ctx.lineWidth = devicePixelRatio; ctx.lineWidth = devicePixelRatio;
@ -215,7 +218,7 @@ function draw() {
}); });
skills.value.forEach(v => { skills.value.forEach(v => {
const [x, y] = v.loc.map(v => v * 2 - 1); 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.save();
ctx.lineWidth = per * 0.06; ctx.lineWidth = per * 0.06;
@ -256,7 +259,7 @@ function click(e: MouseEvent) {
} }
function upgrade(index: number) { function upgrade(index: number) {
const success = core.plugin.skillTree.upgradeSkill(index); const success = skillTree.upgradeSkill(index);
if (!success) tip('error', '升级失败!'); if (!success) tip('error', '升级失败!');
else { else {
tip('success', '升级成功!'); tip('success', '升级成功!');
@ -296,7 +299,7 @@ function selectChapter(delta: number) {
const to = now + delta; const to = now + delta;
if (has(chapterList[to]) && flags.chapter > to) { 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]; chapter.value = chapterList[to];
update.value = !update.value; update.value = !update.value;
flags.skillTree = to; flags.skillTree = to;

View File

@ -137,6 +137,8 @@ import { status } from '../plugin/ui/statusBar';
import { isMobile } from '../plugin/use'; import { isMobile } from '../plugin/use';
import { has } from '../plugin/utils'; import { has } from '../plugin/utils';
const skillTree = Mota.Plugin.require('skillTree_g');
const width = ref( const width = ref(
isMobile ? window.innerWidth - 60 : window.innerWidth * 0.175 isMobile ? window.innerWidth - 60 : window.innerWidth * 0.175
); );
@ -155,7 +157,7 @@ const skill = ref<string>(flags.autoSkill ? '自动切换' : '无');
const up = ref(0); const up = ref(0);
const spring = ref<number>(); const spring = ref<number>();
const skillOpened = ref(core.getFlag('chapter', 0) > 0); 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<number>(); const jumpCnt = ref<number>();
/** /**
* 要展示的勇士属性 * 要展示的勇士属性
@ -178,9 +180,8 @@ watch(status, update);
* 更新显示内容 * 更新显示内容
*/ */
function update() { function update() {
if (!core?.plugin?.hero?.getHeroStatusOn) return;
toShow.forEach(v => { 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[0] = core.itemCount('yellowKey');
keys[1] = core.itemCount('blueKey'); keys[1] = core.itemCount('blueKey');
@ -205,10 +206,12 @@ function update() {
spring.value = void 0; spring.value = void 0;
} }
skillOpened.value = core.getFlag('chapter', 0) > 0; skillOpened.value = core.getFlag('chapter', 0) > 0;
studyOpened.value = core.plugin.skillTree.getSkillLevel(11) > 0; studyOpened.value = skillTree.getSkillLevel(11) > 0;
jumpCnt.value = jumpCnt.value =
flags.skill2 && 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) ? 3 - (flags[`jump_${core.status.floorId}`] ?? 0)
: void 0; : void 0;
} }