mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-18 20:09:27 +08:00
怪物标记功能
This commit is contained in:
parent
22350c4dda
commit
8418bccdf6
@ -388,9 +388,6 @@ actions.prototype._sys_keyDown_lockControl = function (keyCode) {
|
||||
case 'viewMaps':
|
||||
this._keyDownViewMaps(keyCode);
|
||||
break;
|
||||
case 'toolbox':
|
||||
this._keyDownToolbox(keyCode);
|
||||
break;
|
||||
case 'save':
|
||||
case 'load':
|
||||
case 'replayLoad':
|
||||
|
@ -1,6 +1,6 @@
|
||||
var enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 =
|
||||
{
|
||||
"greenSlime": {"name":"绿头怪","hp":100,"atk":11,"def":3,"money":0,"exp":1,"point":0,"special":[]},
|
||||
"greenSlime": {"name":"绿头怪","hp":100,"atk":11,"def":3,"money":0,"exp":1,"point":0,"special":[],"description":"一种极其低级的怪物,低级到普通人用手都可以打死。"},
|
||||
"redSlime": {"name":"红头怪","hp":120,"atk":16,"def":6,"money":0,"exp":2,"point":0,"special":[],"value":10},
|
||||
"blackSlime": {"name":"青头怪","hp":170,"atk":20,"def":8,"money":0,"exp":3,"point":0,"special":[]},
|
||||
"slimelord": {"name":"粘液王","hp":200,"atk":58,"def":24,"money":0,"exp":8,"point":0,"special":[]},
|
||||
|
@ -21,10 +21,10 @@ main.floors.MT0=
|
||||
[141,141,141,141, 0, 0, 0,141, 0, 0, 0,141, 33, 33,20040],
|
||||
[141, 34, 34,141, 0,141, 0, 0, 0,141, 0,494,482,482,20040],
|
||||
[141, 33, 33,492, 0,141, 0, 0, 0,141, 0,141, 33, 33,20040],
|
||||
[141, 34, 34,141, 0,141, 0, 0, 0,141, 0,141,141,141,20040],
|
||||
[141,141,141,141, 0,129,558, 46,322,129, 0,141, 33, 33,20040],
|
||||
[141, 34, 34,141, 0,141, 0,559, 0,141, 0,141,141,141,20040],
|
||||
[141,141,141,141, 0,129,558, 46,560, 0, 0,141, 33, 33,20040],
|
||||
[141, 33, 33,141, 0,141,367, 0,129,141, 0,494,482,482,20040],
|
||||
[141, 33, 33,492, 0,141,129, 0,129,141, 0,141, 33, 33,20040],
|
||||
[141, 33, 33,492, 0,141, 0, 0,129,141, 0,141, 33, 33,20040],
|
||||
[141,141,141,141,141,141,141,141,141,141,141,141,141,141,20040]
|
||||
],
|
||||
"firstArrive": [
|
||||
@ -46,22 +46,11 @@ main.floors.MT0=
|
||||
"\t[原始人]\b[up,hero]出去找些柴火"
|
||||
],
|
||||
"8,13": [
|
||||
"对状态栏的说明",
|
||||
"PC端:\n从上到下依次是楼层名、境界名、生命(右方为每回合生命回复)、攻击(右方为额外攻击)、防御、智慧、金币、距离升级剩余经验、三色钥匙",
|
||||
"手机端:\n最左边一列为生命、生命(右方为每回合生命回复)、攻击(右方为额外攻击)\n第二列为智慧、金币、距离升级剩余经验\n第三列为三色钥匙、楼层名、等级名"
|
||||
],
|
||||
"6,13": [
|
||||
"你可以在初始赠送的系统设置里面修改一些设置\n带地图的楼传开启时,如果是手机玩家,请尽量使用2D绘图模式而不是3D,因为3D绘图比较耗能,该功能可以有效解决找不到路的问题\n你也可以用定点查看代替怪物手册,对性能消耗较低,更加流畅",
|
||||
"打开小地图时,小地图会在右上角显示,可随意开启或关闭,打开时,点击小地图可以进入大地图模式,大地图模式下可以按W或点击相应位置开启区域地图模式(比较耗性能,因为是绘制整个区域的地图,而不是6格以内的地图)\n楼传界面中可以按PgUp和PgDn来上楼或下楼,上下左右移动地图\n在地图界面中用紫色标记的地图为目前可以到达(即去到了临近的地图)却没有到达的地图,可以防止找不到路",
|
||||
"注意,小地图和平面楼传只能浏览和传送当前区域的地图,非当前区域可能无法浏览和传送",
|
||||
"你面前的三个道具比较重要,请充分利用"
|
||||
"本塔有很多新的功能,所有的说明都详细地写在了前方的百科全书里面,里面包含所有的功能说明,不阅读可能会影响正常的游戏体验,请仔细阅读。"
|
||||
],
|
||||
"8,12": [
|
||||
"该塔计分方式:生命+5000*黄钥匙+15000*蓝钥匙"
|
||||
],
|
||||
"9,11": [
|
||||
"对怪物手册的说明:\n1.该塔可以显示未破防时的临界显伤,如果减伤项为黄色且有->标识,说明改临界是在当前未破防的情况下算得的,比如 临界 10 减伤 \r[#ffd700] ->1000\r[] 说明再加10点攻击破防,破防后伤害为1000"
|
||||
],
|
||||
"5,11": [
|
||||
"原声音乐可以在网易云音乐搜索:魔塔 人类:开天辟地 bgm,部分音乐因为版权问题可能无法播放或者不在歌单内"
|
||||
]
|
||||
|
@ -515,7 +515,9 @@ var icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1 =
|
||||
"I489": 92,
|
||||
"I490": 93,
|
||||
"I491": 94,
|
||||
"I558": 95
|
||||
"I558": 95,
|
||||
"I559": 96,
|
||||
"I560": 97
|
||||
},
|
||||
"autotile": {
|
||||
"autotile": 0,
|
||||
|
@ -1242,5 +1242,18 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
|
||||
"canUseItemEffect": "true",
|
||||
"text": "可以查看游戏内你已经听过的bgm,歌曲名格式:歌手——歌曲名",
|
||||
"useItemEffect": "core.openBgms();"
|
||||
},
|
||||
"I559": {
|
||||
"cls": "constants",
|
||||
"name": "系统设置",
|
||||
"canUseItemEffect": "true",
|
||||
"text": "内含所有系统设置项",
|
||||
"useItemEffect": "if (!main.replayChecking) {\n\tcore.plugin.settingsOpened.value = true;\n}"
|
||||
},
|
||||
"I560": {
|
||||
"cls": "constants",
|
||||
"name": "百科全书",
|
||||
"canUseItemEffect": "true",
|
||||
"text": "一个包含游戏中所有功能详细说明的百科全书,可以查看游戏中所有的功能"
|
||||
}
|
||||
}
|
@ -483,6 +483,8 @@ var maps_90f36752_8815_4be8_b32b_d7fad1d0542e =
|
||||
"556": {"cls":"enemys","id":"E556"},
|
||||
"557": {"cls":"enemys","id":"E557"},
|
||||
"558": {"cls":"items","id":"I558"},
|
||||
"559": {"cls":"items","id":"I559"},
|
||||
"560": {"cls":"items","id":"I560"},
|
||||
"20037": {"cls":"tileset","id":"X20037","cannotOut":["up","left"],"cannotIn":["up","left"]},
|
||||
"20038": {"cls":"tileset","id":"X20038","cannotOut":["up"],"cannotIn":["up"]},
|
||||
"20039": {"cls":"tileset","id":"X20039","cannotOut":["up","right"],"cannotIn":["up","right"]},
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 38 KiB |
@ -3370,13 +3370,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
* 如有bug在大群或造塔群@古祠
|
||||
*/
|
||||
|
||||
// 谁tm在即捡即用效果里面调用带有含刷新状态栏的函数
|
||||
var origin = core.control.updateStatusBar;
|
||||
core.updateStatusBar = core.control.updateStatusBar = function () {
|
||||
if (core.getFlag('__statistics__')) return;
|
||||
else return origin.apply(core.control, arguments);
|
||||
};
|
||||
|
||||
core.bigmap.threshold = 256;
|
||||
|
||||
core.control.updateDamage = function (floorId, ctx) {
|
||||
@ -8008,268 +8001,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
}
|
||||
};
|
||||
},
|
||||
weatherSuperimpose: function () {
|
||||
// 天气叠加功能
|
||||
////// 更改天气效果 //////
|
||||
control.prototype.setWeather = function (type, level) {
|
||||
// 非雨雪
|
||||
if (type == null) {
|
||||
Object.keys(core.control.weathers).forEach(one => {
|
||||
core.deleteCanvas('weather' + one);
|
||||
});
|
||||
core.animateFrame.weather.type = [];
|
||||
core.animateFrame.weather.nodes = {};
|
||||
core.animateFrame.weather.level = {};
|
||||
core.animateFrame.weather.time = {};
|
||||
return;
|
||||
}
|
||||
if (!core.animateFrame.weather.level || level == null)
|
||||
core.animateFrame.weather.level = {};
|
||||
if (!core.animateFrame.weather.type)
|
||||
core.animateFrame.weather.type = [];
|
||||
level = core.clamp(parseInt(level) || 5, 1, 10);
|
||||
// 当前天气:则忽略
|
||||
if (
|
||||
core.animateFrame.weather.type.includes(type) &&
|
||||
level == core.animateFrame.weather.level[type]
|
||||
)
|
||||
return;
|
||||
if (core.animateFrame.weather.nodes[type]) return;
|
||||
// 计算当前的宽高
|
||||
core.createCanvas(
|
||||
'weather' + type,
|
||||
0,
|
||||
0,
|
||||
core.__PIXELS__,
|
||||
core.__PIXELS__,
|
||||
80
|
||||
);
|
||||
core.animateFrame.weather.type.push(type);
|
||||
core.animateFrame.weather.level[type] = level;
|
||||
this._setWeather_createNodes(type, level);
|
||||
};
|
||||
control.prototype._setWeather_createNodes = function (type, level) {
|
||||
var number =
|
||||
level *
|
||||
parseInt(
|
||||
(20 * core.bigmap.width * core.bigmap.height) /
|
||||
(core.__SIZE__ * core.__SIZE__)
|
||||
);
|
||||
if (!core.animateFrame.weather.nodes[type])
|
||||
core.animateFrame.weather.nodes[type] = [];
|
||||
switch (type) {
|
||||
case 'rain':
|
||||
for (var a = 0; a < number; a++) {
|
||||
core.animateFrame.weather.nodes.rain.push({
|
||||
x: Math.random() * core.bigmap.width * 32,
|
||||
y: Math.random() * core.bigmap.height * 32,
|
||||
l: Math.random() * 2.5,
|
||||
xs: -4 + Math.random() * 4 + 2,
|
||||
ys: Math.random() * 10 + 10
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'snow':
|
||||
for (var a = 0; a < number; a++) {
|
||||
core.animateFrame.weather.nodes.snow.push({
|
||||
x: Math.random() * core.bigmap.width * 32,
|
||||
y: Math.random() * core.bigmap.height * 32,
|
||||
r: Math.random() * 5 + 1,
|
||||
d: Math.random() * Math.min(level, 200)
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'fog':
|
||||
if (core.animateFrame.weather.fog) {
|
||||
core.animateFrame.weather.nodes[type] = [
|
||||
{
|
||||
level: number,
|
||||
x: 0,
|
||||
y: -core.__PIXELS__ / 2,
|
||||
dx: -Math.random() * 1.5,
|
||||
dy: Math.random(),
|
||||
delta: 0.001
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case 'cloud':
|
||||
if (core.animateFrame.weather.cloud) {
|
||||
core.animateFrame.weather.nodes[type] = [
|
||||
{
|
||||
level: number,
|
||||
x: 0,
|
||||
y: -core.__PIXELS__ / 2,
|
||||
dx: -Math.random() * 1.5,
|
||||
dy: Math.random(),
|
||||
delta: 0.001
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case 'sun':
|
||||
if (core.animateFrame.weather.sun) {
|
||||
// 直接绘制
|
||||
core.clearMap('weather' + type);
|
||||
core.setAlpha('weather' + type, level / 10);
|
||||
core.drawImage(
|
||||
'weather' + type,
|
||||
core.animateFrame.weather.sun,
|
||||
0,
|
||||
0,
|
||||
core.animateFrame.weather.sun.width,
|
||||
core.animateFrame.weather.sun.height,
|
||||
0,
|
||||
0,
|
||||
core.__PIXELS__,
|
||||
core.__PIXELS__
|
||||
);
|
||||
core.setAlpha('weather' + type, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
core.registerAnimationFrame('weather', true, timestamp => {
|
||||
var weather = core.animateFrame.weather;
|
||||
if (!weather.type) return;
|
||||
weather.type.forEach(one => {
|
||||
if (
|
||||
timestamp - weather.time[one] <= 30 ||
|
||||
!core.dymCanvas['weather' + one]
|
||||
)
|
||||
return;
|
||||
core.control['_animationFrame_weather_' + one]();
|
||||
weather.time[one] = timestamp;
|
||||
});
|
||||
});
|
||||
// 雨
|
||||
control.prototype._animationFrame_weather_rain = function () {
|
||||
var ctx = core.dymCanvas.weatherrain,
|
||||
ox = core.bigmap.offsetX,
|
||||
oy = core.bigmap.offsetY;
|
||||
core.clearMap('weatherrain');
|
||||
ctx.strokeStyle = 'rgba(174,194,224,0.8)';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.lineCap = 'round';
|
||||
core.animateFrame.weather.nodes.rain.forEach(p => {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(p.x - ox, p.y - oy);
|
||||
ctx.lineTo(p.x + p.l * p.xs - ox, p.y + p.l * p.ys - oy);
|
||||
ctx.stroke();
|
||||
p.x += p.xs;
|
||||
p.y += p.ys;
|
||||
if (
|
||||
p.x > core.bigmap.width * 32 ||
|
||||
p.y > core.bigmap.height * 32
|
||||
) {
|
||||
p.x = Math.random() * core.bigmap.width * 32;
|
||||
p.y = -10;
|
||||
}
|
||||
});
|
||||
ctx.fill();
|
||||
};
|
||||
// 雪
|
||||
control.prototype._animationFrame_weather_snow = function () {
|
||||
var ctx = core.dymCanvas.weathersnow,
|
||||
ox = core.bigmap.offsetX,
|
||||
oy = core.bigmap.offsetY;
|
||||
core.clearMap('weathersnow');
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
|
||||
ctx.beginPath();
|
||||
if (!core.animateFrame.weather.data)
|
||||
core.animateFrame.weather.data = {};
|
||||
core.animateFrame.weather.data.snow =
|
||||
core.animateFrame.weather.data.snow || 0;
|
||||
core.animateFrame.weather.data.snow += 0.01;
|
||||
var angle = core.animateFrame.weather.data.snow;
|
||||
core.animateFrame.weather.nodes.snow.forEach(p => {
|
||||
ctx.moveTo(p.x - ox, p.y - oy);
|
||||
ctx.arc(p.x - ox, p.y - oy, p.r, 0, Math.PI * 2, true);
|
||||
// update
|
||||
p.x += Math.sin(angle) * core.animateFrame.weather.level.snow;
|
||||
p.y += Math.cos(angle + p.d) + 1 + p.r / 2;
|
||||
if (
|
||||
p.x > core.bigmap.width * 32 + 5 ||
|
||||
p.x < -5 ||
|
||||
p.y > core.bigmap.height * 32
|
||||
) {
|
||||
if (Math.random() > 1 / 3) {
|
||||
p.x = Math.random() * core.bigmap.width * 32;
|
||||
p.y = -10;
|
||||
} else {
|
||||
if (Math.sin(angle) > 0) p.x = -5;
|
||||
else p.x = core.bigmap.width * 32 + 5;
|
||||
p.y = Math.random() * core.bigmap.height * 32;
|
||||
}
|
||||
}
|
||||
});
|
||||
ctx.fill();
|
||||
};
|
||||
// 图片天气
|
||||
control.prototype.__animateFrame_weather_image = function (
|
||||
image,
|
||||
type
|
||||
) {
|
||||
if (!image) return;
|
||||
var node = core.animateFrame.weather.nodes[type][0];
|
||||
core.setAlpha('weather' + type, node.level / 500);
|
||||
var wind = 1.5;
|
||||
var width = image.width,
|
||||
height = image.height;
|
||||
node.x += node.dx * wind;
|
||||
node.y += (2 * node.dy - 1) * wind;
|
||||
if (node.x + 3 * width <= core.__PIXELS__) {
|
||||
node.x += 4 * width;
|
||||
while (node.x > 0) node.x -= width;
|
||||
}
|
||||
node.dy += node.delta;
|
||||
if (node.dy >= 1) {
|
||||
node.delta = -0.001;
|
||||
} else if (node.dy <= 0) {
|
||||
node.delta = 0.001;
|
||||
}
|
||||
if (node.y + 3 * height <= core.__PIXELS__) {
|
||||
node.y += 4 * height;
|
||||
while (node.y > 0) node.y -= height;
|
||||
} else if (node.y >= 0) {
|
||||
node.y -= height;
|
||||
}
|
||||
for (var i = 0; i < 3; ++i) {
|
||||
for (var j = 0; j < 3; ++j) {
|
||||
if (
|
||||
node.x + (i + 1) * width <= 0 ||
|
||||
node.x + i * width >= core.__PIXELS__ ||
|
||||
node.y + (j + 1) * height <= 0 ||
|
||||
node.y + j * height >= core.__PIXELS__
|
||||
)
|
||||
continue;
|
||||
core.drawImage(
|
||||
'weather' + type,
|
||||
image,
|
||||
node.x + i * width,
|
||||
node.y + j * height
|
||||
);
|
||||
}
|
||||
}
|
||||
core.setAlpha('weather' + type, 1);
|
||||
};
|
||||
// 雾
|
||||
control.prototype._animationFrame_weather_fog = function () {
|
||||
core.clearMap('weatherfog');
|
||||
this.__animateFrame_weather_image(
|
||||
core.animateFrame.weather.fog,
|
||||
'fog'
|
||||
);
|
||||
};
|
||||
// 云
|
||||
control.prototype._animationFrame_weather_cloud = function () {
|
||||
core.clearMap('weathercloud');
|
||||
this.__animateFrame_weather_image(
|
||||
core.animateFrame.weather.cloud,
|
||||
'cloud'
|
||||
);
|
||||
};
|
||||
},
|
||||
weatherSuperimpose: function () {},
|
||||
popupDamage: function () {
|
||||
// 伤害弹出
|
||||
// 复写阻激夹域检测
|
||||
@ -9266,6 +8998,13 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
uiChange: function () {
|
||||
if (main.replayChecking) return;
|
||||
|
||||
function updateVueStatusBar() {
|
||||
if (main.replayChecking) return;
|
||||
core.plugin.statusBarStatus.value =
|
||||
!core.plugin.statusBarStatus.value;
|
||||
core.checkMarkedEnemy();
|
||||
}
|
||||
|
||||
ui.prototype.drawBook = function () {
|
||||
return (core.plugin.bookOpened.value = true);
|
||||
};
|
||||
@ -9286,8 +9025,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
core.clearRouteFolding();
|
||||
core.control.noAutoEvents = true;
|
||||
// 更新vue状态栏
|
||||
core.plugin.statusBarStatus.value =
|
||||
!core.plugin.statusBarStatus.value;
|
||||
updateVueStatusBar();
|
||||
};
|
||||
|
||||
control.prototype.showStatusBar = function () {
|
||||
|
@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<div id="non-ui">
|
||||
<StatusBar v-if="showStatusBar"></StatusBar>
|
||||
<MarkedEnemy></MarkedEnemy>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -8,6 +9,7 @@
|
||||
import { ref } from 'vue';
|
||||
import StatusBar from './ui/statusBar.vue';
|
||||
import { showStatusBar } from './plugin/uiController';
|
||||
import MarkedEnemy from './ui/markedEnemy.vue';
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
@ -38,6 +38,7 @@ import { onMounted, onUnmounted, onUpdated, ref, watch } from 'vue';
|
||||
import { DragOutlined } from '@ant-design/icons-vue';
|
||||
import { isMobile, useDrag, cancelGlobalDrag } from '../plugin/use';
|
||||
import { has } from '../plugin/utils';
|
||||
import { sleep } from 'mutate-animate';
|
||||
|
||||
const props = defineProps<{
|
||||
resizable?: boolean;
|
||||
@ -143,15 +144,16 @@ function resize() {
|
||||
if (has(props.width)) width.value = props.width;
|
||||
if (has(props.height)) height.value = props.height;
|
||||
|
||||
main.style.left = `${left}px`;
|
||||
main.style.top = `${top}px`;
|
||||
main.style.width = `${width}px`;
|
||||
main.style.height = `${height}px`;
|
||||
main.style.left = `${left.value}px`;
|
||||
main.style.top = `${top.value}px`;
|
||||
main.style.width = `${width.value}px`;
|
||||
main.style.height = `${height.value}px`;
|
||||
}
|
||||
|
||||
onUpdated(resize);
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
await sleep(50);
|
||||
resize();
|
||||
|
||||
useDrag(
|
||||
|
@ -14,7 +14,7 @@ import { has } from '../plugin/utils';
|
||||
const id = (Math.random() * 1e8).toFixed(0);
|
||||
|
||||
const props = defineProps<{
|
||||
id: AllIds | 'hero';
|
||||
id: AllIds | 'hero' | 'none';
|
||||
noborder?: boolean;
|
||||
width?: number;
|
||||
height?: number;
|
||||
@ -47,6 +47,8 @@ function draw() {
|
||||
c.height = scale * h;
|
||||
ctx.scale(scale, scale);
|
||||
|
||||
if (props.id === 'none') return;
|
||||
|
||||
if (props.id === 'hero') {
|
||||
const img = core.material.images.hero;
|
||||
ctx.drawImage(img, 0, 0, img.width / 4, img.height / 4, 0, 0, w, h);
|
||||
@ -56,7 +58,7 @@ function draw() {
|
||||
drawFn = () => {
|
||||
core.clearMap(ctx);
|
||||
const frame = core.status.globalAnimateStatus % frames;
|
||||
core.drawIcon(ctx, props.id, 0, 0, w, h, frame);
|
||||
core.drawIcon(ctx, props.id as AllIds, 0, 0, w, h, frame);
|
||||
};
|
||||
|
||||
drawFn();
|
||||
|
40
src/data/desc.json
Normal file
40
src/data/desc.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"statusBar": {
|
||||
"text": "状态栏",
|
||||
"desc": [
|
||||
"在本塔中,状态栏与游戏画面是分开的。你可以自由拖动状态栏,也可以修改其大小。",
|
||||
"具体方法如下:点击一下状态栏之后,左上角的拖拽图标会放大,此时你可以按住它拖动状态栏。",
|
||||
"你可以直接将鼠标放到状态栏的边框上,然后直接拖动以改变状态栏的大小。手机端可以先点击一下状态栏使边框",
|
||||
"变宽,然后拖动。电脑端点击状态栏也可以使边框变宽。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"状态栏可以纵向滚动,如果你发现状态栏显示不全,可以尝试拉大状态栏,或者纵向拖动状态栏,就像网页上下拖动一样。",
|
||||
"电脑端还可以使用滚轮上下滚动。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"如果你觉得状态栏有些碍事,你完全可以将其缩小,或者把它放到不碍事的地方。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"状态栏上面可能会有按钮(在开启技能树后会出现),你可以直接点击。"
|
||||
]
|
||||
},
|
||||
"markEnemy": {
|
||||
"text": "标记怪物",
|
||||
"desc": [
|
||||
"标记怪物可以使你能够更加方便地了解一个怪物的情况。你可以在怪物手册的怪物更多信息栏进行标记。",
|
||||
"当一个怪物被标记后,怪物会有以下行为:",
|
||||
"<br>",
|
||||
"1. 当勇士恰好能打败怪物时,会进行提示",
|
||||
"<br>",
|
||||
"2. 当怪物的伤害恰好低于勇士生命值的2/3或1/3时,会进行提示",
|
||||
"<br>",
|
||||
"3. 当勇士恰好踩到怪物的临界时,会进行提示",
|
||||
"<br>",
|
||||
"4. 被标记的怪物会出现类似于状态栏的盒子,可以随意拖动和改变大小。你也可以选择关闭这个盒子,",
|
||||
"被关闭后可以通过重新标记来打开。这个盒子会显示标记的怪物的临界与伤害信息等,依然可以纵向滚动。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"这个功能可以用于标记boss或者较强的挡路怪,当这些怪能够攻击时你可以直接收到信息,不需要再时刻费心注意怪物的伤害。"
|
||||
]
|
||||
}
|
||||
}
|
6
src/data/settings.json
Normal file
6
src/data/settings.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"transition": {
|
||||
"text": "界面动画",
|
||||
"desc": "是否展示当一个ui界面,如怪物手册等的打开与关闭时的动画。当此项开启时,所有界面被打开或关闭时都会展示动画,否则会直接展示出来"
|
||||
}
|
||||
}
|
@ -5,10 +5,19 @@ import use from './plugin/use';
|
||||
import animate from './plugin/animateController';
|
||||
import utils from './plugin/utils';
|
||||
import status from './plugin/ui/statusBar';
|
||||
import mark from './plugin/mark';
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
// 每个引入的插件都要在这里执行,否则不会被转发
|
||||
const toForward: any[] = [pop(), ui(), use(), animate(), utils(), status()];
|
||||
const toForward: any[] = [
|
||||
pop(),
|
||||
ui(),
|
||||
use(),
|
||||
animate(),
|
||||
utils(),
|
||||
status(),
|
||||
mark()
|
||||
];
|
||||
|
||||
// 初始化所有插件,并转发到core上
|
||||
(async function () {
|
||||
|
77
src/panel/enemyTarget.vue
Normal file
77
src/panel/enemyTarget.vue
Normal file
@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<div id="enemy-target">
|
||||
<div id="enemy-desc">
|
||||
<span>怪物描述</span>
|
||||
<Scroll id="enemy-desc-scroll">
|
||||
<span>{{ enemy.description }}</span>
|
||||
</Scroll>
|
||||
</div>
|
||||
<a-divider dashed style="border-color: #ddd4"></a-divider>
|
||||
<div>
|
||||
<div id="mark-target">
|
||||
<span
|
||||
id="mark-info"
|
||||
:style="{ color: marked ? 'lightgreen' : 'lightcoral' }"
|
||||
>{{ marked ? '已标记该怪物' : '未标记该怪物' }}</span
|
||||
>
|
||||
<span class="button-text" @click="mark">{{
|
||||
marked ? '取消标记该怪物' : '标记该怪物为目标'
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import Scroll from '../components/scroll.vue';
|
||||
import { hasMarkedEnemy, markEnemy, unmarkEnemy } from '../plugin/mark';
|
||||
|
||||
const enemy = core.plugin.bookDetailEnemy;
|
||||
const marked = ref(hasMarkedEnemy(enemy.id));
|
||||
|
||||
function mark() {
|
||||
if (marked.value) unmarkEnemy(enemy.id);
|
||||
if (!marked.value) markEnemy(enemy.id);
|
||||
marked.value = !marked.value;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
#enemy-target {
|
||||
width: 100%;
|
||||
font-size: 2.5vh;
|
||||
}
|
||||
|
||||
#enemy-desc {
|
||||
width: 100%;
|
||||
height: 30vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#enemy-desc-scroll {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#mark-target {
|
||||
margin-top: 10%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
font-size: 3.3vh;
|
||||
}
|
||||
|
||||
#mark-info {
|
||||
transition: color 0.2s linear;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
#enemy-target {
|
||||
font-size: 3vw;
|
||||
}
|
||||
}
|
||||
</style>
|
127
src/plugin/mark.ts
Normal file
127
src/plugin/mark.ts
Normal file
@ -0,0 +1,127 @@
|
||||
import { reactive, ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
const markedEnemy = reactive<EnemyIds[]>([]);
|
||||
|
||||
interface MarkInfo {
|
||||
nextCritical: number;
|
||||
}
|
||||
|
||||
const markInfo: Partial<Record<EnemyIds, MarkInfo>> = {};
|
||||
const criticalReached: Partial<Record<EnemyIds, Record<number, boolean>>> = {};
|
||||
const enemyDamageInfo: Partial<Record<EnemyIds, Record<number, boolean>>> = {};
|
||||
|
||||
/**
|
||||
* 标记一个怪物,标记后的怪物会在勇士刚好能打过怪物时、伤害刚好小于勇士生命值的2/3和1/3时、踩到临界时提示
|
||||
* @param id 标记的怪物id
|
||||
*/
|
||||
export function markEnemy(id: EnemyIds) {
|
||||
if (hasMarkedEnemy(id)) return;
|
||||
markedEnemy.push(id);
|
||||
markInfo[id] = {
|
||||
nextCritical:
|
||||
core.nextCriticals(id, 1)[0]?.[0] ?? 0 + core.status.hero.atk
|
||||
};
|
||||
criticalReached[id] = { 0: true };
|
||||
enemyDamageInfo[id] = { 1: false, 2: false, 3: false };
|
||||
getMarkInfo(id);
|
||||
checkMarkedEnemy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否标记过某个怪物
|
||||
*/
|
||||
export function hasMarkedEnemy(id: EnemyIds) {
|
||||
return markedEnemy.includes(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消标记某个怪物
|
||||
*/
|
||||
export function unmarkEnemy(id: EnemyIds) {
|
||||
const index = markedEnemy.indexOf(id);
|
||||
if (index === -1) return;
|
||||
markedEnemy.splice(index, 1);
|
||||
checkMarkedEnemy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得所有被标记的怪物
|
||||
*/
|
||||
export function getMarkedEnemy() {
|
||||
return markedEnemy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取怪物的临界信息
|
||||
* @param id 怪物id
|
||||
*/
|
||||
export function getMarkInfo(id: EnemyIds) {
|
||||
const reached = criticalReached[id]!;
|
||||
const info = markInfo[id]!;
|
||||
if (core.status.hero.atk >= info.nextCritical) {
|
||||
if (!reached[info.nextCritical]) {
|
||||
message.success({
|
||||
content: `踩到了${core.material.enemys[id].name}的临界!`,
|
||||
class: 'antdv-message'
|
||||
});
|
||||
}
|
||||
reached[info.nextCritical] = true;
|
||||
const n = core.nextCriticals(id, 1)[0]?.[0];
|
||||
const next = (n ?? 0) + core.status.hero.atk;
|
||||
info.nextCritical = next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查被标记怪物的状态
|
||||
*/
|
||||
export function checkMarkedEnemy() {
|
||||
checkMarkedStatus.value = !checkMarkedStatus.value;
|
||||
const toDelete: EnemyIds[] = [];
|
||||
const hp = core.status.hero.hp;
|
||||
getMarkedEnemy().forEach(v => {
|
||||
getMarkInfo(v);
|
||||
const damage = core.getDamageInfo(v)?.damage ?? -1;
|
||||
if (damage === -1) return;
|
||||
const info = enemyDamageInfo[v]!;
|
||||
const name = core.material.enemys[v].name;
|
||||
if (damage < hp / 3) {
|
||||
if (!info[3]) {
|
||||
message.success({
|
||||
content: `${name}的伤害已降至勇士生命值的1/3!`,
|
||||
class: 'antdv-message'
|
||||
});
|
||||
}
|
||||
info[1] = true;
|
||||
info[2] = true;
|
||||
info[3] = true;
|
||||
} else if (damage < (hp / 3) * 2) {
|
||||
if (!info[2]) {
|
||||
message.success({
|
||||
content: `${name}的伤害已降至勇士生命值的2/3!`,
|
||||
class: 'antdv-message'
|
||||
});
|
||||
}
|
||||
info[1] = true;
|
||||
info[2] = true;
|
||||
info[3] = false;
|
||||
} else if (damage < hp) {
|
||||
if (!info[1]) {
|
||||
message.success({
|
||||
content: `${name}的伤害已降至勇士生命值的2/3!`,
|
||||
class: 'antdv-message'
|
||||
});
|
||||
}
|
||||
info[1] = true;
|
||||
info[2] = false;
|
||||
info[3] = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const checkMarkedStatus = ref(false);
|
||||
|
||||
export default function init() {
|
||||
return { checkMarkedEnemy, checkStatus: checkMarkedStatus };
|
||||
}
|
15
src/plugin/settings.ts
Normal file
15
src/plugin/settings.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
/**
|
||||
* 打开和关闭ui时是否展示动画
|
||||
*/
|
||||
export const transition = ref(true);
|
||||
|
||||
watch(transition, n => {
|
||||
core.plugin.transition.value = n;
|
||||
core.setLocalStorage('transition', n);
|
||||
});
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
transition.value = core.getLocalStorage('transition');
|
||||
});
|
@ -3,12 +3,15 @@ import { Component, markRaw, ref, Ref, watch } from 'vue';
|
||||
import Book from '../ui/book.vue';
|
||||
import Toolbox from '../ui/toolbox.vue';
|
||||
import Equipbox from '../ui/equipbox.vue';
|
||||
import StatusBar from '../ui/statusBar.vue';
|
||||
import Settings from '../ui/settings.vue';
|
||||
import Desc from '../ui/desc.vue';
|
||||
|
||||
export const bookOpened = ref(false);
|
||||
export const toolOpened = ref(false);
|
||||
export const equipOpened = ref(false);
|
||||
export const showStatusBar = ref(false);
|
||||
export const settingsOpened = ref(false);
|
||||
export const descOpened = ref(false);
|
||||
|
||||
export const transition = ref(true);
|
||||
export const noClosePanel = ref(false);
|
||||
@ -19,7 +22,9 @@ let app: HTMLDivElement;
|
||||
const UI_LIST: [Ref<boolean>, Component][] = [
|
||||
[bookOpened, Book],
|
||||
[toolOpened, Toolbox],
|
||||
[equipOpened, Equipbox]
|
||||
[equipOpened, Equipbox],
|
||||
[settingsOpened, Settings],
|
||||
[descOpened, Desc]
|
||||
];
|
||||
|
||||
/** ui栈 */
|
||||
@ -48,7 +53,8 @@ export default function init() {
|
||||
bookOpened,
|
||||
toolOpened,
|
||||
equipOpened,
|
||||
showStatusBar
|
||||
showStatusBar,
|
||||
settingsOpened
|
||||
};
|
||||
}
|
||||
|
||||
@ -57,7 +63,7 @@ async function showApp() {
|
||||
if (transition.value) {
|
||||
app.style.transition = 'all 0.6s linear';
|
||||
} else {
|
||||
app.style.transition = '';
|
||||
app.style.transition = 'none';
|
||||
}
|
||||
app.style.display = 'flex';
|
||||
await sleep(50);
|
||||
|
@ -100,10 +100,7 @@ export function useDrag(
|
||||
export function cancelGlobalDrag(fn: DragFn): void {
|
||||
const fns = dragFnMap.get(fn);
|
||||
dragFnMap.delete(fn);
|
||||
if (!fns)
|
||||
throw new ReferenceError(
|
||||
'The drag function to be canceled does not exist.'
|
||||
);
|
||||
if (!fns) return;
|
||||
document.removeEventListener('mousemove', fns[0]);
|
||||
document.removeEventListener('touchmove', fns[1]);
|
||||
document.removeEventListener('mouseup', fns[0]);
|
||||
|
@ -99,6 +99,7 @@ export function type(
|
||||
if (typeof toShow !== 'string') {
|
||||
throw new TypeError('Error str type in typing!');
|
||||
}
|
||||
if (toShow.startsWith('!!html')) return ref(toShow);
|
||||
if (avr) time *= toShow.length;
|
||||
const ani = new Animation();
|
||||
const content = ref('');
|
||||
|
2
src/source/cls.d.ts
vendored
2
src/source/cls.d.ts
vendored
@ -482,6 +482,8 @@ interface IdToCls {
|
||||
E556: 'enemys';
|
||||
E557: 'enemys';
|
||||
I558: 'items';
|
||||
I559: 'items';
|
||||
I560: 'items';
|
||||
X20037: 'tileset';
|
||||
X20038: 'tileset';
|
||||
X20039: 'tileset';
|
||||
|
2
src/source/items.d.ts
vendored
2
src/source/items.d.ts
vendored
@ -179,4 +179,6 @@ interface ItemDeclaration {
|
||||
I490: 'items';
|
||||
I491: 'items';
|
||||
I558: 'constants';
|
||||
I559: 'constants';
|
||||
I560: 'constants';
|
||||
}
|
4
src/source/maps.d.ts
vendored
4
src/source/maps.d.ts
vendored
@ -482,6 +482,8 @@ interface IdToNumber {
|
||||
E556: 556;
|
||||
E557: 557;
|
||||
I558: 558;
|
||||
I559: 559;
|
||||
I560: 560;
|
||||
X20037: 20037;
|
||||
X20038: 20038;
|
||||
X20039: 20039;
|
||||
@ -998,6 +1000,8 @@ interface NumberToId {
|
||||
556: 'E556';
|
||||
557: 'E557';
|
||||
558: 'I558';
|
||||
559: 'I559';
|
||||
560: 'I560';
|
||||
20037: 'X20037';
|
||||
20038: 'X20038';
|
||||
20039: 'X20039';
|
||||
|
5
src/types/enemy.d.ts
vendored
5
src/types/enemy.d.ts
vendored
@ -46,6 +46,11 @@ type Enemy<I extends EnemyIds = EnemyIds> = {
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* 怪物说明
|
||||
*/
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* 在怪物手册中映射到的怪物ID。如果此项不为null,则在怪物手册中,将用目标ID来替换该怪物原本的ID。
|
||||
* 常被运用在同一个怪物的多朝向上
|
||||
|
19
src/types/plugin.d.ts
vendored
19
src/types/plugin.d.ts
vendored
@ -30,7 +30,7 @@ interface PluginDeclaration extends PluginUtils {
|
||||
bookDetailPos: number;
|
||||
|
||||
/** 怪物手册详细信息展示的怪物 */
|
||||
bookDetailEnemy: Enemy & DetailedEnemy;
|
||||
bookDetailEnemy: DetailedEnemy;
|
||||
|
||||
/** ui是否使用渐变 */
|
||||
readonly transition: Ref<boolean>;
|
||||
@ -44,18 +44,24 @@ interface PluginDeclaration extends PluginUtils {
|
||||
/** 装备栏是否打开 */
|
||||
readonly equipOpened: Ref<boolean>;
|
||||
|
||||
/** 状态栏信息,取反后刷新状态栏 */
|
||||
readonly statusBarStatus: Ref<boolean>;
|
||||
|
||||
/** 是否显示状态栏 */
|
||||
readonly showStatusBar: Ref<boolean>;
|
||||
|
||||
/** 设置界面是否打开 */
|
||||
readonly settingsOpened: Ref<boolean>;
|
||||
|
||||
/** ui栈 */
|
||||
readonly uiStack: Ref<Component[]>;
|
||||
|
||||
/** 是否是移动设备 */
|
||||
readonly isMobile: boolean;
|
||||
|
||||
/** 状态栏信息,取反后刷新状态栏 */
|
||||
readonly statusBarStatus: Ref<boolean>;
|
||||
|
||||
/** 检查标记的怪物,取反后更新显示信息 */
|
||||
readonly checkMarkedStatus: Ref<boolean>;
|
||||
|
||||
/**
|
||||
* 向一个元素添加拖拽事件
|
||||
* @param ele 目标元素
|
||||
@ -105,6 +111,11 @@ interface PluginDeclaration extends PluginUtils {
|
||||
* @param fn 要移除的函数
|
||||
*/
|
||||
removeAnimate(fn: (time: number) => void);
|
||||
|
||||
/**
|
||||
* 检查被标记怪物的状态,是否需要更新
|
||||
*/
|
||||
checkMarkedEnemy();
|
||||
}
|
||||
|
||||
interface PluginUtils {
|
||||
|
@ -127,6 +127,8 @@ async function show() {
|
||||
async function exit() {
|
||||
noClosePanel.value = true;
|
||||
core.plugin.bookOpened.value = false;
|
||||
if (core.plugin.transition.value) await sleep(650);
|
||||
else await sleep(100);
|
||||
if (core.events.recoverEvents(core.status.event.interval)) {
|
||||
return;
|
||||
} else if (has(core.status.event.ui)) {
|
||||
@ -134,7 +136,6 @@ async function exit() {
|
||||
// @ts-ignore
|
||||
core.ui._drawViewMaps(core.status.event.ui);
|
||||
} else core.ui.closePanel();
|
||||
await sleep(650);
|
||||
}
|
||||
|
||||
function checkScroll() {
|
||||
@ -202,7 +203,8 @@ function keydown(e: KeyboardEvent) {
|
||||
onMounted(async () => {
|
||||
const div = document.getElementById('book') as HTMLDivElement;
|
||||
div.style.opacity = '1';
|
||||
await sleep(600);
|
||||
if (core.plugin.transition.value) await sleep(600);
|
||||
else await sleep(100);
|
||||
document.addEventListener('keyup', keyup);
|
||||
document.addEventListener('keydown', keydown);
|
||||
});
|
||||
|
@ -11,6 +11,7 @@
|
||||
<Transition name="detail">
|
||||
<EnemySpecial v-if="panel === 'special'"></EnemySpecial>
|
||||
<EnemyCritical v-else-if="panel === 'critical'"></EnemyCritical>
|
||||
<EnemyTarget v-else-if="panel === 'target'"></EnemyTarget>
|
||||
</Transition>
|
||||
<div id="detail-more">
|
||||
<Transition name="detail">
|
||||
@ -19,7 +20,12 @@
|
||||
class="detial-more"
|
||||
v-if="panel === 'special'"
|
||||
>
|
||||
<span></span>
|
||||
<span
|
||||
id="enemy-target"
|
||||
class="button-text more"
|
||||
@click="changePanel($event, 'target')"
|
||||
><LeftOutlined /> 怪物更多信息</span
|
||||
>
|
||||
<span
|
||||
id="critical-more"
|
||||
class="button-text more"
|
||||
@ -39,6 +45,19 @@
|
||||
><left-outlined /> 怪物特殊属性</span
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
id="special-more"
|
||||
class="detial-more"
|
||||
v-else-if="panel === 'target'"
|
||||
>
|
||||
<span></span>
|
||||
<span
|
||||
id="enemy-pos"
|
||||
class="button-text more"
|
||||
@click="changePanel($event, 'special')"
|
||||
>怪物特殊属性 <RightOutlined
|
||||
/></span>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
@ -54,6 +73,7 @@ import EnemyCritical from '../panel/enemyCritical.vue';
|
||||
import { KeyCode } from '../plugin/keyCodes';
|
||||
import { keycode } from '../plugin/utils';
|
||||
import { sleep } from 'mutate-animate';
|
||||
import EnemyTarget from '../panel/enemyTarget.vue';
|
||||
|
||||
const enemy = core.plugin.bookDetailEnemy;
|
||||
const top = ref(core.plugin.bookDetailPos);
|
||||
@ -104,7 +124,7 @@ onMounted(async () => {
|
||||
if (y > (parseFloat(style.height) * 4) / 5) moved = true;
|
||||
},
|
||||
() => {
|
||||
if (moved === false && panel.value !== 'critical') {
|
||||
if (moved === false && panel.value === 'special') {
|
||||
close();
|
||||
}
|
||||
moved = false;
|
||||
|
14
src/ui/desc.vue
Normal file
14
src/ui/desc.vue
Normal file
@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<div id="desc"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
#desc {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
156
src/ui/markedEnemy.vue
Normal file
156
src/ui/markedEnemy.vue
Normal file
@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<div id="marked-enemy">
|
||||
<div v-for="v of all">
|
||||
<Box
|
||||
v-if="!getBoxPos(v).hidden"
|
||||
v-model:left="getBoxPos(v).left"
|
||||
v-model:top="getBoxPos(v).top"
|
||||
v-model:width="getBoxPos(v).width"
|
||||
v-model:height="getBoxPos(v).height"
|
||||
:resizable="true"
|
||||
>
|
||||
<Scroll class="box-scroll" :no-scroll="true">
|
||||
<div class="marked-main">
|
||||
<div class="marked-info">
|
||||
<BoxAnimate
|
||||
:id="v"
|
||||
:width="24"
|
||||
:height="24"
|
||||
></BoxAnimate>
|
||||
<span class="marked-name marked-item">{{
|
||||
getName(v)
|
||||
}}</span>
|
||||
</div>
|
||||
<span class="marked-damage marked-item"
|
||||
>伤害:{{ getDamage(v) }}</span
|
||||
>
|
||||
<span class="marked-critical marked-item"
|
||||
>临界: {{ getCritical(v)[0] }}</span
|
||||
>
|
||||
<span class="marked-critical-damage marked-item"
|
||||
>减伤: {{ getCritical(v)[1] }}</span
|
||||
>
|
||||
<span class="marked-def marked-item"
|
||||
>{{ ratio }}防: {{ getDefDamage(v) }}</span
|
||||
>
|
||||
<div class="marked-button">
|
||||
<span
|
||||
class="marked-hide button-text"
|
||||
@click="getBoxPos(v).hidden = true"
|
||||
>隐藏盒子</span
|
||||
>
|
||||
<span
|
||||
class="marked-cancel button-text"
|
||||
@click="unmarkEnemy(v)"
|
||||
>取消标记</span
|
||||
>
|
||||
</div>
|
||||
</div></Scroll
|
||||
>
|
||||
</Box>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import { checkMarkedStatus, getMarkedEnemy, unmarkEnemy } from '../plugin/mark';
|
||||
import { has } from '../plugin/utils';
|
||||
import Box from '../components/box.vue';
|
||||
import Scroll from '../components/scroll.vue';
|
||||
import BoxAnimate from '../components/boxAnimate.vue';
|
||||
|
||||
interface BoxPos {
|
||||
left: number;
|
||||
top: number;
|
||||
width: number;
|
||||
height: number;
|
||||
hidden: boolean;
|
||||
}
|
||||
|
||||
const ratio = core.status.thisMap?.ratio ?? 1;
|
||||
|
||||
let all = getMarkedEnemy();
|
||||
|
||||
watch(checkMarkedStatus, update);
|
||||
|
||||
const boxPos = reactive<Partial<Record<EnemyIds, BoxPos>>>({});
|
||||
|
||||
function update() {
|
||||
all.push(...all.splice(0, all.length));
|
||||
for (const id in boxPos) {
|
||||
if (!all.includes(id as EnemyIds)) delete boxPos[id as EnemyIds];
|
||||
}
|
||||
}
|
||||
|
||||
function getBoxPos(id: EnemyIds) {
|
||||
if (has(boxPos[id])) return boxPos[id]!;
|
||||
boxPos[id] = {
|
||||
left: window.innerWidth - 300,
|
||||
top: 100,
|
||||
width: 200,
|
||||
height: 150,
|
||||
hidden: false
|
||||
};
|
||||
return boxPos[id]!;
|
||||
}
|
||||
|
||||
function getName(id: EnemyIds) {
|
||||
return core.material.enemys[id].name;
|
||||
}
|
||||
|
||||
function getDamage(id: EnemyIds) {
|
||||
return core.formatBigNumber(core.getDamageInfo(id)?.damage) ?? '???';
|
||||
}
|
||||
|
||||
function getCritical(id: EnemyIds) {
|
||||
return (
|
||||
core.nextCriticals(id, 1)[0]?.map(v => core.formatBigNumber(v)) ?? [
|
||||
0, 0
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
function getDefDamage(id: EnemyIds) {
|
||||
return core.formatBigNumber(core.getDefDamage(id, ratio));
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
#marked-enemy {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.box-scroll {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.marked-main {
|
||||
padding: 1vh 0 1vh 0;
|
||||
background-color: #0009;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.marked-info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.marked-item {
|
||||
margin-left: 10%;
|
||||
}
|
||||
|
||||
.marked-button {
|
||||
align-self: center;
|
||||
width: 80%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
}
|
||||
</style>
|
106
src/ui/settings.vue
Normal file
106
src/ui/settings.vue
Normal file
@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<div id="settings">
|
||||
<div id="tools">
|
||||
<span class="button-text tools" @click="exit"
|
||||
><left-outlined /> 返回游戏</span
|
||||
>
|
||||
</div>
|
||||
<div id="settings-main">
|
||||
<Scroll id="setting-left">
|
||||
<div id="setting-list">
|
||||
<span
|
||||
class="selectable setting-item"
|
||||
:selected="selected === 'transition'"
|
||||
@click="transition = !transition"
|
||||
>界面动画: {{
|
||||
transition ? 'ON' : 'OFF'
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
</Scroll>
|
||||
<a-divider id="divider" type="vertical"></a-divider>
|
||||
<div id="setting-right">
|
||||
<Scroll style="height: 100%">
|
||||
<span
|
||||
v-if="descText.value.startsWith('!!html')"
|
||||
v-html="descText.value"
|
||||
></span>
|
||||
<span v-else>{{ descText.value }}</span>
|
||||
</Scroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { transition } from '../plugin/settings';
|
||||
import settingInfo from '../data/settings.json';
|
||||
import { type } from '../plugin/utils';
|
||||
import Scroll from '../components/scroll.vue';
|
||||
import { LeftOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
type Settings = typeof settingInfo;
|
||||
|
||||
const selected = ref<keyof Settings>('transition');
|
||||
|
||||
const descText = computed(() => {
|
||||
return type(settingInfo[selected.value].desc);
|
||||
});
|
||||
|
||||
function exit() {
|
||||
core.plugin.settingsOpened.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
#settings {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: 'normal';
|
||||
font-size: 24px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#settings-main {
|
||||
width: 60%;
|
||||
height: 60%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#setting-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.setting-item {
|
||||
width: 100%;
|
||||
padding: 1% 3% 1% 3%;
|
||||
}
|
||||
|
||||
#setting-left {
|
||||
flex-basis: 40%;
|
||||
}
|
||||
|
||||
#setting-right {
|
||||
flex-basis: 60%;
|
||||
}
|
||||
|
||||
#divider {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#tools {
|
||||
width: 100%;
|
||||
font-family: 'normal';
|
||||
font-size: 1.7em;
|
||||
height: 5vh;
|
||||
position: fixed;
|
||||
left: 10vw;
|
||||
top: 10vh;
|
||||
}
|
||||
</style>
|
@ -149,7 +149,6 @@ watch(mode, n => {
|
||||
const descText = computed(() => {
|
||||
const s = selected.value;
|
||||
if (s === 'none') return ref('没有选择道具');
|
||||
if (all[s].text!.startsWith('!!html')) return ref(all[s].text);
|
||||
return type(all[s].text!, 25, hyper('sin', 'out'), true);
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user