mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-19 04:19:30 +08:00
临界信息
This commit is contained in:
parent
8517dbdabf
commit
9771247b79
2
components.d.ts
vendored
2
components.d.ts
vendored
@ -8,7 +8,7 @@ export {}
|
|||||||
declare module '@vue/runtime-core' {
|
declare module '@vue/runtime-core' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
ADivider: typeof import('ant-design-vue/es')['Divider']
|
ADivider: typeof import('ant-design-vue/es')['Divider']
|
||||||
BookOne: typeof import('./src/components/bookOne.vue')['default']
|
ASlider: typeof import('ant-design-vue/es')['Slider']
|
||||||
BoxAnimate: typeof import('./src/components/boxAnimate.vue')['default']
|
BoxAnimate: typeof import('./src/components/boxAnimate.vue')['default']
|
||||||
EnemyOne: typeof import('./src/components/enemyOne.vue')['default']
|
EnemyOne: typeof import('./src/components/enemyOne.vue')['default']
|
||||||
Scroll: typeof import('./src/components/scroll.vue')['default']
|
Scroll: typeof import('./src/components/scroll.vue')['default']
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<meta name="x5-orientation" content="portrait">
|
<meta name="x5-orientation" content="portrait">
|
||||||
<meta name="x5-fullscreen" content="true">
|
<meta name="x5-fullscreen" content="true">
|
||||||
<meta name="x5-page-mode" content="app">
|
<meta name="x5-page-mode" content="app">
|
||||||
<link type='text/css' href='styles.css' rel='stylesheet'>
|
<link type='text/css' href='/styles.css' rel='stylesheet'>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"@ant-design/icons-vue": "^6.1.0",
|
"@ant-design/icons-vue": "^6.1.0",
|
||||||
"ant-design-vue": "^3.2.13",
|
"ant-design-vue": "^3.2.13",
|
||||||
"axios": "^1.1.3",
|
"axios": "^1.1.3",
|
||||||
|
"chart.js": "^4.0.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lz-string": "^1.4.4",
|
"lz-string": "^1.4.4",
|
||||||
"mutate-animate": "^0.1.0",
|
"mutate-animate": "^0.1.0",
|
||||||
|
@ -12,6 +12,7 @@ specifiers:
|
|||||||
'@vitejs/plugin-vue-jsx': ^2.1.1
|
'@vitejs/plugin-vue-jsx': ^2.1.1
|
||||||
ant-design-vue: ^3.2.13
|
ant-design-vue: ^3.2.13
|
||||||
axios: ^1.1.3
|
axios: ^1.1.3
|
||||||
|
chart.js: ^4.0.1
|
||||||
compressing: ^1.6.2
|
compressing: ^1.6.2
|
||||||
fontmin: ^0.9.9
|
fontmin: ^0.9.9
|
||||||
form-data: ^4.0.0
|
form-data: ^4.0.0
|
||||||
@ -32,6 +33,7 @@ dependencies:
|
|||||||
'@ant-design/icons-vue': 6.1.0_vue@3.2.45
|
'@ant-design/icons-vue': 6.1.0_vue@3.2.45
|
||||||
ant-design-vue: 3.2.15_vue@3.2.45
|
ant-design-vue: 3.2.15_vue@3.2.45
|
||||||
axios: 1.1.3
|
axios: 1.1.3
|
||||||
|
chart.js: 4.0.1
|
||||||
lodash: 4.17.21
|
lodash: 4.17.21
|
||||||
lz-string: 1.4.4
|
lz-string: 1.4.4
|
||||||
mutate-animate: 0.1.0
|
mutate-animate: 0.1.0
|
||||||
@ -1069,6 +1071,11 @@ packages:
|
|||||||
supports-color: 5.5.0
|
supports-color: 5.5.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/chart.js/4.0.1:
|
||||||
|
resolution: {integrity: sha512-5/8/9eBivwBZK81mKvmIwTb2Pmw4D/5h1RK9fBWZLLZ8mCJ+kfYNmV9rMrGoa5Hgy2/wVDBMLSUDudul2/9ihA==}
|
||||||
|
engines: {pnpm: ^7.0.0}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/chokidar/3.5.3:
|
/chokidar/3.5.3:
|
||||||
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
||||||
engines: {node: '>= 8.10.0'}
|
engines: {node: '>= 8.10.0'}
|
||||||
|
File diff suppressed because it is too large
Load Diff
3910
public/libs/ui.js
3910
public/libs/ui.js
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@ var enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 =
|
|||||||
"blackSlime": {"name":"青头怪","hp":170,"atk":20,"def":8,"money":0,"exp":3,"point":0,"special":[]},
|
"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":[]},
|
"slimelord": {"name":"粘液王","hp":200,"atk":58,"def":24,"money":0,"exp":8,"point":0,"special":[]},
|
||||||
"bat": {"name":"小蝙蝠","hp":60,"atk":15,"def":0,"money":0,"exp":2,"point":0,"special":[4]},
|
"bat": {"name":"小蝙蝠","hp":60,"atk":15,"def":0,"money":0,"exp":2,"point":0,"special":[4]},
|
||||||
"bigBat": {"name":"大蝙蝠","hp":150,"atk":17,"def":5,"money":0,"exp":4,"point":0,"special":[4]},
|
"bigBat": {"name":"大蝙蝠","hp":150,"atk":17,"def":5,"money":0,"exp":4,"point":0,"special":[4,5,6],"crit":0,"charge":0,"courage":0,"together":0,"hungry":0,"value":100,"n":1000},
|
||||||
"redBat": {"name":"恐怖蝙蝠","hp":1200,"atk":260,"def":110,"money":1,"exp":32,"point":0,"special":[5]},
|
"redBat": {"name":"恐怖蝙蝠","hp":1200,"atk":260,"def":110,"money":1,"exp":32,"point":0,"special":[5]},
|
||||||
"vampire": {"name":"冥灵魔王","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
"vampire": {"name":"冥灵魔王","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
||||||
"skeleton": {"name":"骷髅人","hp":300,"atk":80,"def":10,"money":0,"exp":9,"point":0,"special":[1],"crit":300},
|
"skeleton": {"name":"骷髅人","hp":300,"atk":80,"def":10,"money":0,"exp":9,"point":0,"special":[1],"crit":300},
|
||||||
|
@ -9311,5 +9311,10 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"uiChange": function () {
|
||||||
|
ui.prototype.drawBook = function () {
|
||||||
|
return core.plugin.bookOpened.value = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -33,12 +33,13 @@ onMounted(() => {
|
|||||||
c.height *= scale;
|
c.height *= scale;
|
||||||
ctx.scale(scale, scale);
|
ctx.scale(scale, scale);
|
||||||
|
|
||||||
const fn = (time: number) => {
|
const fn = () => {
|
||||||
core.clearMap(ctx);
|
core.clearMap(ctx);
|
||||||
const frame = core.status.globalAnimateStatus % frames;
|
const frame = core.status.globalAnimateStatus % frames;
|
||||||
core.drawIcon(ctx, props.id, 0, 0, props.width, props.height, frame);
|
core.drawIcon(ctx, props.id, 0, 0, props.width, props.height, frame);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn();
|
||||||
addAnimate(fn);
|
addAnimate(fn);
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="enemy-container">
|
<div class="enemy-container" @click="select">
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<div class="leftbar">
|
<div class="leftbar">
|
||||||
<span class="name">{{ enemy.name }}</span>
|
<span class="name">{{ enemy.name }}</span>
|
||||||
@ -24,7 +24,7 @@
|
|||||||
<a-divider
|
<a-divider
|
||||||
type="vertical"
|
type="vertical"
|
||||||
dashed
|
dashed
|
||||||
style="height: 100%; margin: 0 3% 0 3%; border-color: #ddd4"
|
style="height: 100%; margin: 0 3% 0 1%; border-color: #ddd4"
|
||||||
></a-divider>
|
></a-divider>
|
||||||
<div class="rightbar">
|
<div class="rightbar">
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
@ -66,9 +66,9 @@
|
|||||||
<div class="detail-info">
|
<div class="detail-info">
|
||||||
<span style="color: cyan"
|
<span style="color: cyan"
|
||||||
>{{
|
>{{
|
||||||
core.status.thisMap.ratio
|
core.formatBigNumber(core.status.thisMap.ratio)
|
||||||
}}防 {{
|
}}防 {{
|
||||||
core.formatBigNumber(enemy.money)
|
core.formatBigNumber(enemy.defDamage)
|
||||||
}}</span
|
}}</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
@ -120,7 +120,18 @@ const props = defineProps<{
|
|||||||
enemy: Enemy & DetailedEnemy;
|
enemy: Enemy & DetailedEnemy;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const emits = defineEmits<{
|
||||||
|
(e: 'select'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const core = window.core;
|
const core = window.core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择这个怪物时
|
||||||
|
*/
|
||||||
|
function select(e: MouseEvent) {
|
||||||
|
emits('select');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@ -146,13 +157,14 @@ const core = window.core;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.leftbar {
|
.leftbar {
|
||||||
width: 10%;
|
width: 15%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 1.3vw;
|
font-size: 2vh;
|
||||||
|
padding-left: 1%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
@ -168,11 +180,14 @@ const core = window.core;
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
display: block;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-items: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rightbar {
|
.rightbar {
|
||||||
font-size: 1.3vw;
|
font-size: 2.5vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 1.5vh 0 1.5vh 0;
|
padding: 1.5vh 0 1.5vh 0;
|
||||||
@ -184,7 +199,7 @@ const core = window.core;
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.detail-info {
|
.detail-info {
|
||||||
flex-basis: 33%;
|
flex-basis: 33.3%;
|
||||||
line-height: 0;
|
line-height: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -192,4 +207,14 @@ const core = window.core;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
.rightbar {
|
||||||
|
font-size: 4vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leftbar {
|
||||||
|
font-size: 2vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -11,10 +11,17 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, onUpdated } from 'vue';
|
import { onMounted, onUnmounted, onUpdated } from 'vue';
|
||||||
import { useDrag, useWheel } from '../plugin/use';
|
import { cancelGlobalDrag, isMobile, useDrag, useWheel } from '../plugin/use';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
now?: number;
|
||||||
type?: 'vertical' | 'horizontal';
|
type?: 'vertical' | 'horizontal';
|
||||||
|
drag?: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emits = defineEmits<{
|
||||||
|
(e: 'update:now', value: number): void;
|
||||||
|
(e: 'update:drag', value: boolean): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let now = 0;
|
let now = 0;
|
||||||
@ -44,6 +51,7 @@ function draw() {
|
|||||||
} else if (now < 0) {
|
} else if (now < 0) {
|
||||||
now = 0;
|
now = 0;
|
||||||
}
|
}
|
||||||
|
emits('update:now', now);
|
||||||
const length =
|
const length =
|
||||||
Math.min(ctx.canvas[canvasAttr] / total / scale, 1) *
|
Math.min(ctx.canvas[canvasAttr] / total / scale, 1) *
|
||||||
ctx.canvas[canvasAttr];
|
ctx.canvas[canvasAttr];
|
||||||
@ -52,12 +60,12 @@ function draw() {
|
|||||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
if (props.type === 'horizontal') {
|
if (props.type === 'horizontal') {
|
||||||
ctx.moveTo(Math.max(py + 5, 5), 20 * scale);
|
ctx.moveTo(Math.max(py + 5, 5), 10 * scale);
|
||||||
ctx.lineTo(Math.min(py + length - 5, ctx.canvas.width - 5), 20 * scale);
|
ctx.lineTo(Math.min(py + length - 5, ctx.canvas.width - 5), 10 * scale);
|
||||||
} else {
|
} else {
|
||||||
ctx.moveTo(20 * scale, Math.max(py + 5, 5));
|
ctx.moveTo(10 * scale, Math.max(py + 5, 5));
|
||||||
ctx.lineTo(
|
ctx.lineTo(
|
||||||
20 * scale,
|
10 * scale,
|
||||||
Math.min(py + length - 5, ctx.canvas.height - 5)
|
Math.min(py + length - 5, ctx.canvas.height - 5)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -81,10 +89,35 @@ function scroll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onUpdated(() => {
|
onUpdated(() => {
|
||||||
|
now = props.now ?? now;
|
||||||
calHeight();
|
calHeight();
|
||||||
draw();
|
draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let last: number;
|
||||||
|
let contentLast: number;
|
||||||
|
|
||||||
|
function canvasDrag(x: number, y: number) {
|
||||||
|
emits('update:drag', true);
|
||||||
|
const d = props.type === 'horizontal' ? x : y;
|
||||||
|
const dy = d - last;
|
||||||
|
last = d;
|
||||||
|
if (ctx.canvas[canvasAttr] < total * scale)
|
||||||
|
now += ((dy * total) / ctx.canvas[canvasAttr]) * scale;
|
||||||
|
content.style.transition = '';
|
||||||
|
scroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
function contentDrag(x: number, y: number) {
|
||||||
|
emits('update:drag', true);
|
||||||
|
const d = props.type === 'horizontal' ? x : y;
|
||||||
|
const dy = d - contentLast;
|
||||||
|
contentLast = d;
|
||||||
|
if (ctx.canvas[canvasAttr] < total * scale) now -= dy;
|
||||||
|
content.style.transition = '';
|
||||||
|
scroll();
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const div = document.getElementById(`scroll-div-${id}`) as HTMLDivElement;
|
const div = document.getElementById(`scroll-div-${id}`) as HTMLDivElement;
|
||||||
const canvas = document.getElementById(`scroll-${id}`) as HTMLCanvasElement;
|
const canvas = document.getElementById(`scroll-${id}`) as HTMLCanvasElement;
|
||||||
@ -96,7 +129,7 @@ onMounted(() => {
|
|||||||
content.addEventListener('resize', resize);
|
content.addEventListener('resize', resize);
|
||||||
|
|
||||||
const style = getComputedStyle(canvas);
|
const style = getComputedStyle(canvas);
|
||||||
canvas.width = 40 * scale;
|
canvas.width = 20 * scale;
|
||||||
canvas.height = parseFloat(style.height) * scale;
|
canvas.height = parseFloat(style.height) * scale;
|
||||||
|
|
||||||
if (props.type === 'horizontal') {
|
if (props.type === 'horizontal') {
|
||||||
@ -105,59 +138,44 @@ onMounted(() => {
|
|||||||
canvas.style.width = '98%';
|
canvas.style.width = '98%';
|
||||||
canvas.style.margin = '0 1% 0 1%';
|
canvas.style.margin = '0 1% 0 1%';
|
||||||
canvas.width = parseFloat(style.width) * scale;
|
canvas.width = parseFloat(style.width) * scale;
|
||||||
canvas.height = 40 * scale;
|
canvas.height = 20 * scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
draw();
|
draw();
|
||||||
|
|
||||||
let last: number;
|
|
||||||
let contentLast: number;
|
|
||||||
|
|
||||||
// 绑定滚动条拖拽事件
|
// 绑定滚动条拖拽事件
|
||||||
useDrag(
|
useDrag(
|
||||||
canvas,
|
canvas,
|
||||||
(x, y) => {
|
canvasDrag,
|
||||||
const d = props.type === 'horizontal' ? x : y;
|
|
||||||
const dy = d - last;
|
|
||||||
last = d;
|
|
||||||
if (canvas[canvasAttr] < total * scale)
|
|
||||||
now += ((dy * total) / canvas[canvasAttr]) * scale;
|
|
||||||
content.style.transition = '';
|
|
||||||
scroll();
|
|
||||||
},
|
|
||||||
(x, y) => {
|
(x, y) => {
|
||||||
last = props.type === 'horizontal' ? x : y;
|
last = props.type === 'horizontal' ? x : y;
|
||||||
},
|
},
|
||||||
|
() => {
|
||||||
|
setTimeout(() => emits('update:drag', false));
|
||||||
|
},
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
// 绑定文本拖拽事件
|
// 绑定文本拖拽事件
|
||||||
useDrag(
|
useDrag(
|
||||||
content,
|
content,
|
||||||
(x, y) => {
|
contentDrag,
|
||||||
const d = props.type === 'horizontal' ? x : y;
|
|
||||||
const dy = d - contentLast;
|
|
||||||
contentLast = d;
|
|
||||||
if (canvas[canvasAttr] < total * scale) now -= dy;
|
|
||||||
content.style.transition = '';
|
|
||||||
scroll();
|
|
||||||
},
|
|
||||||
(x, y) => {
|
(x, y) => {
|
||||||
contentLast = props.type === 'horizontal' ? x : y;
|
contentLast = props.type === 'horizontal' ? x : y;
|
||||||
},
|
},
|
||||||
|
() => {
|
||||||
|
setTimeout(() => emits('update:drag', false));
|
||||||
|
},
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
useWheel(content, (x, y) => {
|
useWheel(content, (x, y) => {
|
||||||
const d = x !== 0 ? x : y;
|
const d = x !== 0 ? x : y;
|
||||||
if (!core.domStyle.isVertical) {
|
if (Math.abs(d) > 50) {
|
||||||
if (Math.abs(d) > 50) {
|
content.style.transition = `${cssTarget} 0.2s ease-out`;
|
||||||
content.style.transition = `${cssTarget} 0.2s ease-out`;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
content.style.transition = '';
|
content.style.transition = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
now += d;
|
now += d;
|
||||||
scroll();
|
scroll();
|
||||||
});
|
});
|
||||||
@ -165,16 +183,15 @@ onMounted(() => {
|
|||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
content.removeEventListener('resize', resize);
|
content.removeEventListener('resize', resize);
|
||||||
|
cancelGlobalDrag(canvasDrag);
|
||||||
|
cancelGlobalDrag(contentDrag);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.scroll {
|
.scroll {
|
||||||
opacity: 0.2;
|
opacity: 0.2;
|
||||||
width: 40px;
|
width: 20px;
|
||||||
height: 98%;
|
|
||||||
margin-top: 1%;
|
|
||||||
margin-bottom: 1%;
|
|
||||||
transition: opacity 0.2s linear;
|
transition: opacity 0.2s linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
193
src/panel/enemyCritical.vue
Normal file
193
src/panel/enemyCritical.vue
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
<template>
|
||||||
|
<div id="critical-main">
|
||||||
|
<div id="critical">
|
||||||
|
<div class="des">加攻伤害</div>
|
||||||
|
<canvas ref="critical" class="chart"></canvas>
|
||||||
|
<div class="slider-div">
|
||||||
|
<span>加攻数值 {{ addAtk }}</span>
|
||||||
|
<a-slider
|
||||||
|
class="slider"
|
||||||
|
v-model:value="addAtk"
|
||||||
|
:max="(originCri.at(-1)?.[0] ?? 2) - 1"
|
||||||
|
></a-slider>
|
||||||
|
<span
|
||||||
|
>最大值 {{
|
||||||
|
(originCri.at(-1)?.[0] ?? 2) - 1
|
||||||
|
}}</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a-divider
|
||||||
|
dashed
|
||||||
|
style="width: 100%; border-color: #ddd4; margin: 1vh 0 1vh 0"
|
||||||
|
></a-divider>
|
||||||
|
<div id="def">
|
||||||
|
<div class="des">加防伤害</div>
|
||||||
|
<canvas ref="def" class="chart"></canvas>
|
||||||
|
<div class="slider-div">
|
||||||
|
<span>加防数值 {{ addDef }}</span>
|
||||||
|
<a-slider
|
||||||
|
class="slider"
|
||||||
|
v-model:value="addDef"
|
||||||
|
:max="(originDef.at(-1)?.[0] ?? 2) - 1"
|
||||||
|
></a-slider>
|
||||||
|
<span
|
||||||
|
>最大值 {{
|
||||||
|
(originDef.at(-1)?.[0] ?? 2) - 1
|
||||||
|
}}</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="now-damage">
|
||||||
|
<span
|
||||||
|
>当前加攻 {{
|
||||||
|
format(addAtk * ratio)
|
||||||
|
}}</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
>当前加防 {{
|
||||||
|
format(addDef * ratio)
|
||||||
|
}}</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
>当前减伤 {{
|
||||||
|
format(nowDamage[0], false, nowDamage[0] < 0)
|
||||||
|
}}</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
>当前伤害 {{
|
||||||
|
format(nowDamage[1])
|
||||||
|
}}</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
|
import { getCriticalDamage, getDefDamage } from '../plugin/book';
|
||||||
|
import Chart, { ChartConfiguration } from 'chart.js/auto';
|
||||||
|
import { has, setCanvasSize } from '../plugin/utils';
|
||||||
|
|
||||||
|
const critical = ref<HTMLCanvasElement>();
|
||||||
|
const def = ref<HTMLCanvasElement>();
|
||||||
|
|
||||||
|
const enemy = core.plugin.bookDetailEnemy;
|
||||||
|
|
||||||
|
const originCri = getCriticalDamage(enemy);
|
||||||
|
const originDef = getDefDamage(enemy);
|
||||||
|
|
||||||
|
// 当前数据
|
||||||
|
const allCri = ref(originCri);
|
||||||
|
const allDef = ref(originDef);
|
||||||
|
|
||||||
|
// 加攻加防数量
|
||||||
|
const addAtk = ref(0);
|
||||||
|
const addDef = ref(0);
|
||||||
|
|
||||||
|
const originDamage = core.getDamageInfo(enemy);
|
||||||
|
|
||||||
|
// 转发core上的内容至当前作用域
|
||||||
|
const format = core.formatBigNumber;
|
||||||
|
const ratio = core.status.thisMap.ratio;
|
||||||
|
|
||||||
|
const nowDamage = computed(() => {
|
||||||
|
const dam = core.getDamageInfo(enemy, {
|
||||||
|
atk: core.status.hero.atk + addAtk.value,
|
||||||
|
def: core.status.hero.def + addDef.value
|
||||||
|
});
|
||||||
|
if (!has(dam)) return ['???', '???'];
|
||||||
|
if (!has(originDamage)) return [-dam.damage, dam.damage];
|
||||||
|
return [originDamage.damage - dam.damage, dam.damage];
|
||||||
|
});
|
||||||
|
|
||||||
|
function generateChart(ele: HTMLCanvasElement, data: [number, number][]) {
|
||||||
|
const config: ChartConfiguration = {
|
||||||
|
type: 'line',
|
||||||
|
data: generateData(data)
|
||||||
|
};
|
||||||
|
return new Chart(ele, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateData(data: [number, number][]) {
|
||||||
|
return {
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: '怪物伤害',
|
||||||
|
data: data.map(v => v[1])
|
||||||
|
}
|
||||||
|
],
|
||||||
|
labels: data.map(v => v[0])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function update(atk: Chart, def: Chart) {
|
||||||
|
allCri.value = getCriticalDamage(enemy, addAtk.value, addDef.value);
|
||||||
|
allDef.value = getDefDamage(enemy, addDef.value, addAtk.value);
|
||||||
|
|
||||||
|
atk.data = generateData(allCri.value);
|
||||||
|
def.data = generateData(allDef.value);
|
||||||
|
atk.update('resize');
|
||||||
|
def.update('resize');
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const div = document.getElementById('critical-main') as HTMLDivElement;
|
||||||
|
const style = getComputedStyle(div);
|
||||||
|
|
||||||
|
const width = parseFloat(style.width);
|
||||||
|
const height = window.innerHeight / 5;
|
||||||
|
const c = critical.value!;
|
||||||
|
const d = def.value!;
|
||||||
|
|
||||||
|
setCanvasSize(c, width, height);
|
||||||
|
setCanvasSize(d, width, height);
|
||||||
|
|
||||||
|
const criChart = generateChart(c, allCri.value);
|
||||||
|
const defChart = generateChart(d, allDef.value);
|
||||||
|
|
||||||
|
watch(addAtk, n => {
|
||||||
|
update(criChart, defChart);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(addDef, n => {
|
||||||
|
update(criChart, defChart);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
#critical-main {
|
||||||
|
width: 100%;
|
||||||
|
height: 50vh;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.des {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 2.5vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-div {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 1.1vw;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#now-damage {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-around;
|
||||||
|
font-size: 3vh;
|
||||||
|
}
|
||||||
|
</style>
|
94
src/panel/enemySpecial.vue
Normal file
94
src/panel/enemySpecial.vue
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<div id="special-main">
|
||||||
|
<Scroll id="special-scroll">
|
||||||
|
<div id="special">
|
||||||
|
<component :is="info"></component>
|
||||||
|
</div>
|
||||||
|
</Scroll>
|
||||||
|
<a-divider
|
||||||
|
dashed
|
||||||
|
style="margin: 2vh 0 2vh 0; border-color: #ddd4"
|
||||||
|
></a-divider>
|
||||||
|
<div id="critical">
|
||||||
|
<div style="font-size: 2.5vh; width: 100%; text-align: center">
|
||||||
|
临界表
|
||||||
|
</div>
|
||||||
|
<div id="critical-main">
|
||||||
|
<div id="critical-des">
|
||||||
|
<span>加攻</span>
|
||||||
|
<span>减伤</span>
|
||||||
|
</div>
|
||||||
|
<div v-for="[atk, dam] of criticals" class="critical">
|
||||||
|
<span class="critical-atk">{{ format(atk) }}</span>
|
||||||
|
<span>{{
|
||||||
|
dam < 0 ? `-> ${format(-dam)}` : format(dam)
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { isMobile } from '../plugin/use';
|
||||||
|
import { getSpecialHint } from '../plugin/book';
|
||||||
|
|
||||||
|
const enemy = core.plugin.bookDetailEnemy;
|
||||||
|
|
||||||
|
const info = getSpecialHint(enemy);
|
||||||
|
|
||||||
|
const criticals = core.nextCriticals(enemy, isMobile ? 4 : 8);
|
||||||
|
|
||||||
|
const format = core.formatBigNumber;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
#special-main {
|
||||||
|
width: 100%;
|
||||||
|
user-select: none;
|
||||||
|
font-size: 2em;
|
||||||
|
position: absolute;
|
||||||
|
top: 20vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#critical-main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
#critical-des,
|
||||||
|
.critical {
|
||||||
|
font-size: 1.6vw;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.critical-atk {
|
||||||
|
border-bottom: 1px solid #ddd4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.critical {
|
||||||
|
border-left: 1px solid #ddd4;
|
||||||
|
padding-left: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#special-scroll {
|
||||||
|
height: 40vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
#detail-main {
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#special-scroll {
|
||||||
|
height: 50vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#critical-des,
|
||||||
|
.critical {
|
||||||
|
font-size: 3.6vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
121
src/plugin/book.tsx
Normal file
121
src/plugin/book.tsx
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import { has } from './utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取怪物的特殊技能描述
|
||||||
|
* @param enemy 怪物实例
|
||||||
|
*/
|
||||||
|
export function getSpecialHint(enemy: Enemy & DetailedEnemy) {
|
||||||
|
const all = core
|
||||||
|
.getSpecials()
|
||||||
|
.filter(v => enemy.special.includes(v[0]))
|
||||||
|
.sort((a, b) => a[0] - b[0]);
|
||||||
|
|
||||||
|
const des = all.map(v => {
|
||||||
|
const des = v[2];
|
||||||
|
if (des instanceof Function) {
|
||||||
|
return des(enemy);
|
||||||
|
}
|
||||||
|
return des;
|
||||||
|
});
|
||||||
|
const name = all.map(v => {
|
||||||
|
const name = v[1];
|
||||||
|
if (name instanceof Function) {
|
||||||
|
return name(enemy);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{all.map((v, i) => {
|
||||||
|
return (
|
||||||
|
<div class="special">
|
||||||
|
<span style={{ color: core.arrayToRGBA(v[3]) }}>
|
||||||
|
{name[i]}:
|
||||||
|
</span>
|
||||||
|
<span innerHTML={des[i]}></span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得怪物的最近100个加防减伤
|
||||||
|
* @param enemy 怪物实例
|
||||||
|
*/
|
||||||
|
export function getDefDamage(
|
||||||
|
enemy: Enemy & DetailedEnemy,
|
||||||
|
addDef: number = 0,
|
||||||
|
addAtk: number = 0
|
||||||
|
) {
|
||||||
|
const ratio = core.status.thisMap.ratio;
|
||||||
|
const res: [number, number][] = [];
|
||||||
|
|
||||||
|
let origin: number | undefined;
|
||||||
|
let last = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i <= 100; i++) {
|
||||||
|
const dam = core.getDamageInfo(enemy, {
|
||||||
|
def: core.status.hero.def + ratio * i + addDef,
|
||||||
|
atk: core.status.hero.atk + addAtk
|
||||||
|
});
|
||||||
|
|
||||||
|
if (i === 0) {
|
||||||
|
origin = dam?.damage;
|
||||||
|
if (has(origin)) {
|
||||||
|
res.push([addDef, origin]);
|
||||||
|
last = origin;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!has(dam)) continue;
|
||||||
|
if (dam.damage === origin) continue;
|
||||||
|
if (dam.damage === res.at(-1)?.[1]) continue;
|
||||||
|
if (last <= 0) break;
|
||||||
|
last = dam.damage;
|
||||||
|
res.push([ratio * i + addDef, dam.damage]);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取怪物的临界信息
|
||||||
|
* @param enemy 怪物实例
|
||||||
|
*/
|
||||||
|
export function getCriticalDamage(
|
||||||
|
enemy: Enemy & DetailedEnemy,
|
||||||
|
addAtk: number = 0,
|
||||||
|
addDef: number = 0
|
||||||
|
): [number, number][] {
|
||||||
|
const ratio = core.status.thisMap.ratio;
|
||||||
|
const res: [number, number][] = [];
|
||||||
|
|
||||||
|
let origin: number | undefined;
|
||||||
|
let last = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i <= 100; i++) {
|
||||||
|
const dam = core.getDamageInfo(enemy, {
|
||||||
|
atk: core.status.hero.atk + ratio * i + addAtk,
|
||||||
|
def: core.status.hero.def + addDef
|
||||||
|
});
|
||||||
|
|
||||||
|
if (i === 0) {
|
||||||
|
origin = dam?.damage;
|
||||||
|
if (has(origin)) {
|
||||||
|
res.push([addAtk, origin]);
|
||||||
|
last = origin;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!has(dam)) continue;
|
||||||
|
if (dam.damage === origin) continue;
|
||||||
|
if (dam.damage === res.at(-1)?.[1]) continue;
|
||||||
|
if (dam.damage <= 0) break;
|
||||||
|
last = dam.damage;
|
||||||
|
res.push([ratio * i + addAtk, dam.damage]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
@ -1,17 +1,13 @@
|
|||||||
|
import { sleep } from 'mutate-animate';
|
||||||
import { Component, markRaw, ref, Ref, watch } from 'vue';
|
import { Component, markRaw, ref, Ref, watch } from 'vue';
|
||||||
import Book from '../ui/book.vue';
|
import Book from '../ui/book.vue';
|
||||||
import BookDetail from '../ui/bookDetail.vue';
|
|
||||||
|
|
||||||
export const bookOpened = ref(false);
|
export const bookOpened = ref(false);
|
||||||
export const bookDetail = ref(false);
|
|
||||||
|
|
||||||
let app: HTMLDivElement;
|
let app: HTMLDivElement;
|
||||||
|
|
||||||
/** ui声明列表 */
|
/** ui声明列表 */
|
||||||
const UI_LIST: [Ref<boolean>, Component][] = [
|
const UI_LIST: [Ref<boolean>, Component][] = [[bookOpened, Book]];
|
||||||
[bookOpened, Book],
|
|
||||||
[bookDetail, BookDetail]
|
|
||||||
];
|
|
||||||
|
|
||||||
/** ui栈 */
|
/** ui栈 */
|
||||||
export const uiStack = ref<Component[]>([]);
|
export const uiStack = ref<Component[]>([]);
|
||||||
@ -32,15 +28,19 @@ export default function init() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return { uiStack, bookDetail, bookOpened };
|
return { uiStack, bookOpened };
|
||||||
}
|
}
|
||||||
|
|
||||||
function showApp() {
|
async function showApp() {
|
||||||
app.style.display = 'flex';
|
app.style.display = 'flex';
|
||||||
|
await sleep(50);
|
||||||
|
app.style.opacity = '1';
|
||||||
core.lockControl();
|
core.lockControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideApp() {
|
async function hideApp() {
|
||||||
|
app.style.opacity = '0';
|
||||||
|
await sleep(600);
|
||||||
app.style.display = 'none';
|
app.style.display = 'none';
|
||||||
core.unlockControl();
|
core.unlockControl();
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,23 @@
|
|||||||
export default function init() {
|
export default function init() {
|
||||||
return { useDrag, useWheel, isMobile };
|
return { useDrag, useWheel, useUp, isMobile };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DragFn = (x: number, y: number, e: MouseEvent | TouchEvent) => void;
|
||||||
|
|
||||||
|
type DragMap = [
|
||||||
|
(e: MouseEvent) => void,
|
||||||
|
(e: TouchEvent) => void,
|
||||||
|
((e: MouseEvent) => void)?,
|
||||||
|
((e: TouchEvent) => void)?
|
||||||
|
];
|
||||||
|
|
||||||
|
const dragFnMap = new Map<DragFn, DragMap>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否是移动设备
|
||||||
|
*/
|
||||||
|
export const isMobile = matchMedia('(max-width: 600px)').matches;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 向一个元素添加拖拽事件
|
* 向一个元素添加拖拽事件
|
||||||
* @param ele 目标元素
|
* @param ele 目标元素
|
||||||
@ -11,8 +27,9 @@ export default function init() {
|
|||||||
*/
|
*/
|
||||||
export function useDrag(
|
export function useDrag(
|
||||||
ele: HTMLElement,
|
ele: HTMLElement,
|
||||||
fn: (x: number, y: number, e: MouseEvent | TouchEvent) => void,
|
fn: DragFn,
|
||||||
ondown?: (x: number, y: number, e: MouseEvent | TouchEvent) => void,
|
ondown?: DragFn,
|
||||||
|
onUp?: (e: MouseEvent | TouchEvent) => void,
|
||||||
global: boolean = false
|
global: boolean = false
|
||||||
) {
|
) {
|
||||||
let down = false;
|
let down = false;
|
||||||
@ -25,21 +42,66 @@ export function useDrag(
|
|||||||
if (ondown) ondown(e.touches[0].clientX, e.touches[0].clientY, e);
|
if (ondown) ondown(e.touches[0].clientX, e.touches[0].clientY, e);
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('mouseup', () => (down = false));
|
|
||||||
document.addEventListener('touchend', () => (down = false));
|
|
||||||
|
|
||||||
const target = global ? document : ele;
|
const target = global ? document : ele;
|
||||||
|
|
||||||
target.addEventListener('mousemove', e => {
|
const mouseFn = (e: MouseEvent) => {
|
||||||
if (!down) return;
|
if (!down) return;
|
||||||
const ee = e as MouseEvent;
|
fn(e.clientX, e.clientY, e);
|
||||||
fn(ee.clientX, ee.clientY, ee);
|
};
|
||||||
});
|
|
||||||
target.addEventListener('touchmove', e => {
|
const touchFn = (e: TouchEvent) => {
|
||||||
if (!down) return;
|
if (!down) return;
|
||||||
const ee = e as TouchEvent;
|
fn(e.touches[0].clientX, e.touches[0].clientY, e);
|
||||||
fn(ee.touches[0].clientX, ee.touches[0].clientY, ee);
|
};
|
||||||
});
|
|
||||||
|
const mouseUp = (e: MouseEvent) => {
|
||||||
|
if (!down) return;
|
||||||
|
onUp && onUp(e);
|
||||||
|
down = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const touchUp = (e: TouchEvent) => {
|
||||||
|
if (!down) return;
|
||||||
|
onUp && onUp(e);
|
||||||
|
down = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
target.addEventListener(
|
||||||
|
'mouseup',
|
||||||
|
mouseUp as EventListenerOrEventListenerObject
|
||||||
|
);
|
||||||
|
target.addEventListener(
|
||||||
|
'touchend',
|
||||||
|
touchUp as EventListenerOrEventListenerObject
|
||||||
|
);
|
||||||
|
|
||||||
|
dragFnMap.set(fn, [mouseFn, touchFn, mouseUp, touchUp]);
|
||||||
|
|
||||||
|
target.addEventListener(
|
||||||
|
'mousemove',
|
||||||
|
mouseFn as EventListenerOrEventListenerObject
|
||||||
|
);
|
||||||
|
target.addEventListener(
|
||||||
|
'touchmove',
|
||||||
|
touchFn as EventListenerOrEventListenerObject
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 去除一个全局拖拽函数
|
||||||
|
* @param fn 要去除的函数
|
||||||
|
*/
|
||||||
|
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.'
|
||||||
|
);
|
||||||
|
document.removeEventListener('mousemove', fns[0]);
|
||||||
|
document.removeEventListener('touchmove', fns[1]);
|
||||||
|
document.removeEventListener('mouseup', fns[0]);
|
||||||
|
document.removeEventListener('touchend', fns[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,6 +119,15 @@ export function useWheel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否是移动设备
|
* 当鼠标或手指松开时执行函数
|
||||||
|
* @param ele 目标元素
|
||||||
|
* @param fn 当鼠标或手指松开时执行的函数
|
||||||
*/
|
*/
|
||||||
export const isMobile = matchMedia('(max-width: 600px)').matches;
|
export function useUp(ele: HTMLElement, fn: DragFn): void {
|
||||||
|
ele.addEventListener('mouseup', e => {
|
||||||
|
fn(e.clientX, e.clientY, e);
|
||||||
|
});
|
||||||
|
ele.addEventListener('touchend', e => {
|
||||||
|
fn(e.touches[0].clientX, e.touches[0].clientY, e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -25,3 +25,20 @@ export function getDamageColor(damage: number): string {
|
|||||||
if (damage < core.status.hero.hp) return '#f22';
|
if (damage < core.status.hero.hp) return '#f22';
|
||||||
return '#f00';
|
return '#f00';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置画布的长宽
|
||||||
|
* @param canvas 画布
|
||||||
|
* @param w 宽度
|
||||||
|
* @param h 高度
|
||||||
|
*/
|
||||||
|
export function setCanvasSize(
|
||||||
|
canvas: HTMLCanvasElement,
|
||||||
|
w: number,
|
||||||
|
h: number
|
||||||
|
): void {
|
||||||
|
canvas.width = w;
|
||||||
|
canvas.height = h;
|
||||||
|
canvas.style.width = `${w}px`;
|
||||||
|
canvas.style.height = `${h}px`;
|
||||||
|
}
|
||||||
|
@ -7,4 +7,7 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
transition: all 0.6s linear;
|
||||||
|
opacity: 0;
|
||||||
|
background-color: #000d;
|
||||||
}
|
}
|
||||||
|
4
src/types/enemy.d.ts
vendored
4
src/types/enemy.d.ts
vendored
@ -105,7 +105,7 @@ declare class enemys {
|
|||||||
x?: number,
|
x?: number,
|
||||||
y?: number,
|
y?: number,
|
||||||
floorId?: string
|
floorId?: string
|
||||||
): number[][];
|
): [atk: number, dam: number][];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算再加若干点防御能使某只敌人对主角的总伤害降低多少
|
* 计算再加若干点防御能使某只敌人对主角的总伤害降低多少
|
||||||
@ -198,5 +198,5 @@ declare class enemys {
|
|||||||
turn: number;
|
turn: number;
|
||||||
damage: number;
|
damage: number;
|
||||||
[x: string]: any;
|
[x: string]: any;
|
||||||
};
|
} | null;
|
||||||
}
|
}
|
||||||
|
29
src/types/plugin.d.ts
vendored
29
src/types/plugin.d.ts
vendored
@ -4,6 +4,8 @@ type Ref<T> = {
|
|||||||
value: T;
|
value: T;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type DragFn = (x: number, y: number, e: MouseEvent | TouchEvent) => void;
|
||||||
|
|
||||||
interface PluginDeclaration extends PluginUtils {
|
interface PluginDeclaration extends PluginUtils {
|
||||||
/**
|
/**
|
||||||
* 添加函数 例:添加弹出文字,像这个就可以使用core.addPop或core.plugin.addPop调用
|
* 添加函数 例:添加弹出文字,像这个就可以使用core.addPop或core.plugin.addPop调用
|
||||||
@ -16,12 +18,15 @@ interface PluginDeclaration extends PluginUtils {
|
|||||||
/** 添加变量 例:所有的正在弹出的文字,像这个就可以使用core.plugin.pop获取 */
|
/** 添加变量 例:所有的正在弹出的文字,像这个就可以使用core.plugin.pop获取 */
|
||||||
pop: any[];
|
pop: any[];
|
||||||
|
|
||||||
|
/** 怪物手册的怪物详细信息的初始位置 */
|
||||||
|
bookDetailPos: number;
|
||||||
|
|
||||||
|
/** 怪物手册详细信息展示的怪物 */
|
||||||
|
bookDetailEnemy: Enemy & DetailedEnemy;
|
||||||
|
|
||||||
/** 手册是否打开 */
|
/** 手册是否打开 */
|
||||||
readonly bookOpened: Ref<boolean>;
|
readonly bookOpened: Ref<boolean>;
|
||||||
|
|
||||||
/** 手册详细信息 */
|
|
||||||
readonly bookDetail: Ref<boolean>;
|
|
||||||
|
|
||||||
/** ui栈 */
|
/** ui栈 */
|
||||||
readonly uiStack: Ref<Component[]>;
|
readonly uiStack: Ref<Component[]>;
|
||||||
|
|
||||||
@ -37,11 +42,18 @@ interface PluginDeclaration extends PluginUtils {
|
|||||||
*/
|
*/
|
||||||
useDrag(
|
useDrag(
|
||||||
ele: HTMLElement,
|
ele: HTMLElement,
|
||||||
fn: (x: number, y: number, e: MouseEvent | TouchEvent) => void,
|
fn: DragFn,
|
||||||
ondown?: (x: number, y: number, e: MouseEvent | TouchEvent) => void,
|
ondown?: DragFn,
|
||||||
|
onUp?: (e: MouseEvent | TouchEvent) => void,
|
||||||
global: boolean = false
|
global: boolean = false
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 去除一个全局拖拽函数
|
||||||
|
* @param fn 要去除的函数
|
||||||
|
*/
|
||||||
|
cancelGlobalDrag(fn: DragFn): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当触发滚轮时执行函数
|
* 当触发滚轮时执行函数
|
||||||
* @param ele 目标元素
|
* @param ele 目标元素
|
||||||
@ -52,6 +64,13 @@ interface PluginDeclaration extends PluginUtils {
|
|||||||
fn: (x: number, y: number, z: number, e: WheelEvent) => void
|
fn: (x: number, y: number, z: number, e: WheelEvent) => void
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当鼠标或手指松开时执行函数
|
||||||
|
* @param ele 目标元素
|
||||||
|
* @param fn 当鼠标或手指松开时执行的函数
|
||||||
|
*/
|
||||||
|
useUp(ele: HTMLElement, fn: DragFn): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加一个动画
|
* 添加一个动画
|
||||||
* @param fn 要添加的函数
|
* @param fn 要添加的函数
|
||||||
|
8
src/types/util.d.ts
vendored
8
src/types/util.d.ts
vendored
@ -100,7 +100,11 @@ declare class utils {
|
|||||||
* @param onMap 可选,true表示用于地图显伤,结果总字符数最多为5,否则最多为6
|
* @param onMap 可选,true表示用于地图显伤,结果总字符数最多为5,否则最多为6
|
||||||
* @returns 格式化结果
|
* @returns 格式化结果
|
||||||
*/
|
*/
|
||||||
formatBigNumber(x: number, onMap?: boolean, onCritical?: boolean): string;
|
formatBigNumber(
|
||||||
|
x: number | string,
|
||||||
|
onMap?: boolean,
|
||||||
|
onCritical?: boolean
|
||||||
|
): string;
|
||||||
|
|
||||||
/** 变速移动 */
|
/** 变速移动 */
|
||||||
applyEasing(mode?: string): (number) => number;
|
applyEasing(mode?: string): (number) => number;
|
||||||
@ -119,7 +123,7 @@ declare class utils {
|
|||||||
* @param color 一行三列或一行四列的数组,前三个元素必须为不大于255的自然数。第四个元素(如果有)必须为0或不大于1的数字,第四个元素不填视为1
|
* @param color 一行三列或一行四列的数组,前三个元素必须为不大于255的自然数。第四个元素(如果有)必须为0或不大于1的数字,第四个元素不填视为1
|
||||||
* @returns 该颜色的字符串表示
|
* @returns 该颜色的字符串表示
|
||||||
*/
|
*/
|
||||||
arrayToRGBA(color: [number, number, number, number]): string;
|
arrayToRGBA(color: [number, number, number, number?] | string): string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 录像一压,其结果会被再次base64压缩
|
* 录像一压,其结果会被再次base64压缩
|
||||||
|
@ -4,9 +4,14 @@
|
|||||||
<div v-if="enemy.length === 0" id="none">
|
<div v-if="enemy.length === 0" id="none">
|
||||||
<div>本层无怪物</div>
|
<div>本层无怪物</div>
|
||||||
</div>
|
</div>
|
||||||
<Scroll v-else style="width: 100%; height: 100%; font-family: normal">
|
<Scroll
|
||||||
<div v-for="e of enemy" class="enemy">
|
v-else
|
||||||
<EnemyOne :enemy="e"></EnemyOne>
|
style="width: 100%; height: 100%; font-family: normal"
|
||||||
|
v-model:now="scroll"
|
||||||
|
v-model:drag="drag"
|
||||||
|
>
|
||||||
|
<div v-for="(e, i) of enemy" class="enemy">
|
||||||
|
<EnemyOne :enemy="e" @select="select(e, i)"></EnemyOne>
|
||||||
<a-divider
|
<a-divider
|
||||||
dashed
|
dashed
|
||||||
style="width: 100%; border-color: #ddd4"
|
style="width: 100%; border-color: #ddd4"
|
||||||
@ -14,18 +19,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</Scroll>
|
</Scroll>
|
||||||
</div>
|
</div>
|
||||||
|
<BookDetail v-if="detail" @close="closeDetail()"></BookDetail>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { onMounted } from 'vue';
|
import { sleep } from 'mutate-animate';
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
import EnemyOne from '../components/enemyOne.vue';
|
import EnemyOne from '../components/enemyOne.vue';
|
||||||
import Scroll from '../components/scroll.vue';
|
import Scroll from '../components/scroll.vue';
|
||||||
import { getDamageColor } from '../plugin/utils';
|
import { getDamageColor } from '../plugin/utils';
|
||||||
|
import BookDetail from './bookDetail.vue';
|
||||||
|
|
||||||
const floorId = core.floorIds[core.status.event?.ui] ?? core.status.floorId;
|
const floorId = core.floorIds[core.status.event?.ui] ?? core.status.floorId;
|
||||||
const enemy = core.getCurrentEnemys(floorId);
|
const enemy = core.getCurrentEnemys(floorId);
|
||||||
|
|
||||||
|
const scroll = ref(0);
|
||||||
|
const drag = ref(false);
|
||||||
|
const detail = ref(false);
|
||||||
|
|
||||||
// 解析
|
// 解析
|
||||||
enemy.forEach(v => {
|
enemy.forEach(v => {
|
||||||
const l = v.specialText.length;
|
const l = v.specialText.length;
|
||||||
@ -46,18 +58,52 @@ onMounted(() => {
|
|||||||
const div = document.getElementById('book') as HTMLDivElement;
|
const div = document.getElementById('book') as HTMLDivElement;
|
||||||
div.style.opacity = '1';
|
div.style.opacity = '1';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择怪物,展示详细信息
|
||||||
|
* @param enemy 选择的怪物
|
||||||
|
* @param index 选择的怪物索引
|
||||||
|
*/
|
||||||
|
function select(enemy: Enemy & DetailedEnemy, index: number) {
|
||||||
|
if (drag.value) return;
|
||||||
|
const h = window.innerHeight;
|
||||||
|
const y = index * h * 0.2 - scroll.value;
|
||||||
|
core.plugin.bookDetailEnemy = enemy;
|
||||||
|
core.plugin.bookDetailPos = y;
|
||||||
|
detail.value = true;
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function hide() {
|
||||||
|
const div = document.getElementById('book') as HTMLDivElement;
|
||||||
|
div.style.opacity = '0';
|
||||||
|
await sleep(600);
|
||||||
|
div.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function closeDetail() {
|
||||||
|
show();
|
||||||
|
await sleep(600);
|
||||||
|
detail.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function show() {
|
||||||
|
const div = document.getElementById('book') as HTMLDivElement;
|
||||||
|
div.style.display = 'block';
|
||||||
|
await sleep(50);
|
||||||
|
div.style.opacity = '1';
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
#book {
|
#book {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
background-color: #000d;
|
|
||||||
transition: opacity 0.6s linear;
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
font-family: 'normal';
|
font-family: 'normal';
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
transition: opacity 0.6s linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
@media screen and (max-width: 600px) {
|
||||||
|
@ -1,7 +1,175 @@
|
|||||||
<!-- 怪物详细信息 -->
|
<!-- 怪物详细信息 -->
|
||||||
|
<template>
|
||||||
|
<div id="detail">
|
||||||
|
<div id="info" :style="{ top: `${top}px` }">
|
||||||
|
<EnemyOne :enemy="enemy"></EnemyOne>
|
||||||
|
<a-divider
|
||||||
|
dashed
|
||||||
|
style="margin: 2vh 0 2vh 0; border-color: #ddd4; width: 100%"
|
||||||
|
></a-divider>
|
||||||
|
</div>
|
||||||
|
<Transition name="detail">
|
||||||
|
<EnemySpecial v-if="panel === 'special'"></EnemySpecial>
|
||||||
|
<EnemyCritical v-else-if="panel === 'critical'"></EnemyCritical>
|
||||||
|
</Transition>
|
||||||
|
<div id="detail-more">
|
||||||
|
<Transition name="detail">
|
||||||
|
<div
|
||||||
|
id="special-more"
|
||||||
|
class="detial-more"
|
||||||
|
v-if="panel === 'special'"
|
||||||
|
>
|
||||||
|
<span id="enemy-pos" class="more"
|
||||||
|
><left-outlined /> 怪物分布情况</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
id="critical-more"
|
||||||
|
class="more"
|
||||||
|
@click="changePanel($event, 'critical')"
|
||||||
|
>详细临界信息 <right-outlined
|
||||||
|
/></span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
id="special-more"
|
||||||
|
class="detial-more"
|
||||||
|
v-else-if="panel === 'critical'"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
id="enemy-pos"
|
||||||
|
class="more"
|
||||||
|
@click="changePanel($event, 'special')"
|
||||||
|
><left-outlined /> 怪物特殊属性</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template></template>
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import EnemyOne from '../components/enemyOne.vue';
|
||||||
|
import { useDrag } from '../plugin/use';
|
||||||
|
import EnemySpecial from '../panel/enemySpecial.vue';
|
||||||
|
import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue';
|
||||||
|
import EnemyCritical from '../panel/enemyCritical.vue';
|
||||||
|
|
||||||
<script lang="tsx" setup></script>
|
const enemy = core.plugin.bookDetailEnemy;
|
||||||
|
const top = ref(core.plugin.bookDetailPos);
|
||||||
|
const panel = ref('special');
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
const emits = defineEmits<{
|
||||||
|
(e: 'close'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
function changePanel(e: MouseEvent, to: string) {
|
||||||
|
e.stopPropagation();
|
||||||
|
panel.value = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
top.value = 0;
|
||||||
|
const div = document.getElementById('detail') as HTMLDivElement;
|
||||||
|
div.style.opacity = '1';
|
||||||
|
|
||||||
|
const style = getComputedStyle(div);
|
||||||
|
|
||||||
|
let moved = false;
|
||||||
|
useDrag(
|
||||||
|
div,
|
||||||
|
() => {
|
||||||
|
moved = true;
|
||||||
|
},
|
||||||
|
(x, y) => {
|
||||||
|
if (y > (parseFloat(style.height) * 4) / 5) moved = true;
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
if (moved === false) {
|
||||||
|
top.value = core.plugin.bookDetailPos;
|
||||||
|
div.style.opacity = '0';
|
||||||
|
emits('close');
|
||||||
|
}
|
||||||
|
moved = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
#info {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.6s ease;
|
||||||
|
height: 20vh;
|
||||||
|
padding: 0 1% 0 1%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#detail {
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
left: 14%;
|
||||||
|
font-family: 'normal';
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
width: 72%;
|
||||||
|
height: 90%;
|
||||||
|
transition: all 0.6s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#detail-more {
|
||||||
|
position: absolute;
|
||||||
|
margin-top: 3%;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 3vh;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detial-more {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.more {
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.2s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.more:hover {
|
||||||
|
color: aqua;
|
||||||
|
}
|
||||||
|
|
||||||
|
.more:active {
|
||||||
|
color: aquamarine;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-enter-active,
|
||||||
|
.detail-leave-active {
|
||||||
|
transition: all 0.6s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-enter-from,
|
||||||
|
.detail-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and(max-width:600px) {
|
||||||
|
#detail {
|
||||||
|
width: 95%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 5% 0 5% 5%;
|
||||||
|
left: 0%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#detail-more {
|
||||||
|
font-size: 4vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -26,7 +26,7 @@ export default defineConfig({
|
|||||||
output: {
|
output: {
|
||||||
manualChunks: {
|
manualChunks: {
|
||||||
antdv: ['ant-design-vue', '@ant-design/icons-vue'],
|
antdv: ['ant-design-vue', '@ant-design/icons-vue'],
|
||||||
common: ['lodash', 'axios', 'lz-string', 'vue']
|
common: ['lodash', 'axios', 'lz-string']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user