mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-05-24 23:05:49 +08:00
feat: 千星脚本添加html遮罩 (#3081)
* feat: 版本检测工具 * feat: 千星脚本添加html遮罩 * 添加存档 * feat: 版本检测
This commit is contained in:
@@ -24,7 +24,7 @@
|
|||||||
自己发布的千星奇域的地图也可以用来增长经验,但是并不需要发布成功,仅需要点击一下发布再预览详情,即可在弹窗中进行收藏。
|
自己发布的千星奇域的地图也可以用来增长经验,但是并不需要发布成功,仅需要点击一下发布再预览详情,即可在弹窗中进行收藏。
|
||||||
这就意味着可以自行制作秒刷图,然后“发布”进行收藏,在收藏中使用自己实际上并未真正发布的地图进行秒刷。
|
这就意味着可以自行制作秒刷图,然后“发布”进行收藏,在收藏中使用自己实际上并未真正发布的地图进行秒刷。
|
||||||
最新版脚本进行了重构,优化了点击速度,秒刷图一周刷完仅需8分45秒。
|
最新版脚本进行了重构,优化了点击速度,秒刷图一周刷完仅需8分45秒。
|
||||||
地图制作请自行学习。
|
焚诀存档地图已存放至BetterGI/User/JsScript/WeeklyThousandStarRealm/map目录下,可自行在游戏中导入。
|
||||||
|
|
||||||
## 🌟 功能特点
|
## 🌟 功能特点
|
||||||
|
|
||||||
|
|||||||
4682
repo/js/WeeklyThousandStarRealm/assets/disclaimer-mask.html
Normal file
4682
repo/js/WeeklyThousandStarRealm/assets/disclaimer-mask.html
Normal file
File diff suppressed because it is too large
Load Diff
4712
repo/js/WeeklyThousandStarRealm/assets/progress-mask.html
Normal file
4712
repo/js/WeeklyThousandStarRealm/assets/progress-mask.html
Normal file
File diff suppressed because it is too large
Load Diff
10
repo/js/WeeklyThousandStarRealm/disclaimer-mask/index.html
Normal file
10
repo/js/WeeklyThousandStarRealm/disclaimer-mask/index.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
18
repo/js/WeeklyThousandStarRealm/disclaimer-mask/package.json
Normal file
18
repo/js/WeeklyThousandStarRealm/disclaimer-mask/package.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "disclaimer-mask",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build && node ../../build/rename.js dist/index.html dist/disclaimer-mask.html",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"gsap": "^3.12.7",
|
||||||
|
"vue": "^3.5.30"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^6.0.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
229
repo/js/WeeklyThousandStarRealm/disclaimer-mask/src/App.vue
Normal file
229
repo/js/WeeklyThousandStarRealm/disclaimer-mask/src/App.vue
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
<template>
|
||||||
|
<div class="overlay">
|
||||||
|
<div class="scan-lines"></div>
|
||||||
|
<div class="panel" ref="panel">
|
||||||
|
<div class="panel-inner">
|
||||||
|
<div class="icon-wrap" ref="icon">
|
||||||
|
<div class="icon-ring"></div>
|
||||||
|
<span class="icon-text">!</span>
|
||||||
|
</div>
|
||||||
|
<div class="title" ref="title">WARNING</div>
|
||||||
|
<div class="divider" ref="divider"></div>
|
||||||
|
<div class="message" ref="message">请先同意免责声明后再运行此脚本!</div>
|
||||||
|
<div class="reason-block" ref="reasonBlock">
|
||||||
|
<div class="reason-line" v-for="(line, i) in reasonTexts" :key="i" ref="reasonLineEls">{{ line }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="instruction" ref="instruction">
|
||||||
|
请在脚本的 <span class="highlight">自定义 JS 配置</span> 中手动勾选「我已阅读说明中的免责声明」
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import gsap from 'gsap'
|
||||||
|
|
||||||
|
const panel = ref(null)
|
||||||
|
const icon = ref(null)
|
||||||
|
const title = ref(null)
|
||||||
|
const divider = ref(null)
|
||||||
|
const message = ref(null)
|
||||||
|
const reasonBlock = ref(null)
|
||||||
|
const reasonLineEls = ref([])
|
||||||
|
const instruction = ref(null)
|
||||||
|
|
||||||
|
const reasonTexts = [
|
||||||
|
'本脚本依赖「删除奇域地图存档」来实现重复获取成就经验。',
|
||||||
|
'当脚本执行删除存档时,可能会误删你正常游玩的关卡数据。',
|
||||||
|
'请务必确认你能承担潜在损失后再继续使用。',
|
||||||
|
]
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const tl = gsap.timeline({defaults: {ease: 'power3.out'}})
|
||||||
|
|
||||||
|
tl.from(panel.value, {
|
||||||
|
scale: 0, opacity: 0, rotation: -8,
|
||||||
|
duration: 0.6, ease: 'back.out(1.4)'
|
||||||
|
})
|
||||||
|
.from(icon.value, {
|
||||||
|
scale: 0, rotation: -360, opacity: 0,
|
||||||
|
duration: 0.6, ease: 'elastic.out(1, 0.5)'
|
||||||
|
}, '-=0.2')
|
||||||
|
.from(title.value, {
|
||||||
|
y: -20, opacity: 0, duration: 0.3
|
||||||
|
}, '-=0.1')
|
||||||
|
.from(divider.value, {
|
||||||
|
scaleX: 0, duration: 0.4
|
||||||
|
}, '-=0.1')
|
||||||
|
.from(message.value, {
|
||||||
|
y: 20, opacity: 0, duration: 0.4
|
||||||
|
}, '-=0.1')
|
||||||
|
.from(reasonBlock.value, {
|
||||||
|
opacity: 0, duration: 0.3
|
||||||
|
})
|
||||||
|
.from(reasonLineEls.value, {
|
||||||
|
x: -30, opacity: 0,
|
||||||
|
duration: 0.4, stagger: 0.5
|
||||||
|
}, '-=0.1')
|
||||||
|
.from(instruction.value, {
|
||||||
|
y: 15, opacity: 0, duration: 0.5
|
||||||
|
})
|
||||||
|
|
||||||
|
// 持续脉冲
|
||||||
|
gsap.to(panel.value, {
|
||||||
|
boxShadow: '0 0 60px rgba(255,50,50,0.5), 0 0 120px rgba(255,50,50,0.2)',
|
||||||
|
duration: 1.5, repeat: -1, yoyo: true, ease: 'sine.inOut'
|
||||||
|
})
|
||||||
|
gsap.to('.icon-ring', {
|
||||||
|
scale: 1.2, opacity: 0.3,
|
||||||
|
duration: 1.5, repeat: -1, yoyo: true, ease: 'sine.inOut'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@property --border-angle {
|
||||||
|
syntax: '<angle>';
|
||||||
|
initial-value: 0deg;
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body { background: transparent; }
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scan-lines {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: repeating-linear-gradient(
|
||||||
|
0deg,
|
||||||
|
transparent, transparent 2px,
|
||||||
|
rgba(255, 50, 50, 0.03) 2px,
|
||||||
|
rgba(255, 50, 50, 0.03) 4px
|
||||||
|
);
|
||||||
|
pointer-events: none;
|
||||||
|
animation: scan 8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scan {
|
||||||
|
from { transform: translateY(0); }
|
||||||
|
to { transform: translateY(4px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
--border-angle: 0deg;
|
||||||
|
position: relative;
|
||||||
|
padding: 2px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: conic-gradient(from var(--border-angle), transparent 60%, #ff4444, #ff2222, #ff4444, transparent 40%) border-box;
|
||||||
|
animation: rotate-border 3s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotate-border {
|
||||||
|
to { --border-angle: 360deg; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-inner {
|
||||||
|
background: rgba(8, 0, 0, 0.9);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 44px 60px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 22px;
|
||||||
|
max-width: 700px;
|
||||||
|
box-shadow:
|
||||||
|
0 0 30px rgba(255, 50, 50, 0.2),
|
||||||
|
0 0 60px rgba(255, 50, 50, 0.1),
|
||||||
|
inset 0 0 40px rgba(255, 50, 50, 0.03);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-wrap {
|
||||||
|
position: relative;
|
||||||
|
width: 70px;
|
||||||
|
height: 70px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-ring {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border: 3px solid rgba(255, 80, 80, 0.7);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-text {
|
||||||
|
font-size: 46px;
|
||||||
|
font-weight: 900;
|
||||||
|
color: #ff4444;
|
||||||
|
text-shadow: 0 0 20px rgba(255, 68, 68, 0.8), 0 0 40px rgba(255, 68, 68, 0.4);
|
||||||
|
font-family: 'Arial Black', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: 900;
|
||||||
|
letter-spacing: 14px;
|
||||||
|
color: #ff4444;
|
||||||
|
text-shadow: 0 0 20px rgba(255, 68, 68, 0.6), 0 0 40px rgba(255, 68, 68, 0.3);
|
||||||
|
font-family: 'Arial Black', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background: linear-gradient(90deg, transparent, #ff4444, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
font-size: 20px;
|
||||||
|
color: #ffcccc;
|
||||||
|
text-align: center;
|
||||||
|
text-shadow: 0 0 10px rgba(255, 68, 68, 0.4);
|
||||||
|
letter-spacing: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reason-block {
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-left: 3px solid #ff4444;
|
||||||
|
background: rgba(255, 50, 50, 0.06);
|
||||||
|
border-radius: 0 8px 8px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reason-line {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #ddaaaa;
|
||||||
|
line-height: 1.6;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instruction {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #cc8888;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instruction .highlight {
|
||||||
|
color: #ff9999;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { createApp } from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
|
||||||
|
createApp(App).mount('#app')
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { createConfig } from '../../vite.base.config.js'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
|
export default createConfig([vue()])
|
||||||
@@ -4,7 +4,8 @@ import {
|
|||||||
findImgAndClick,
|
findImgAndClick,
|
||||||
waitUntilTextAppear,
|
waitUntilTextAppear,
|
||||||
waitUntilImgDisappear,
|
waitUntilImgDisappear,
|
||||||
waitUntilImgAppear, findImg
|
waitUntilImgAppear,
|
||||||
|
findImg
|
||||||
} from "../../../packages/utils/tool";
|
} from "../../../packages/utils/tool";
|
||||||
|
|
||||||
import fold_triangle from "assets/fold_triangle.png";
|
import fold_triangle from "assets/fold_triangle.png";
|
||||||
@@ -12,6 +13,7 @@ import check_box from "assets/check_box.png";
|
|||||||
import exit_room from "assets/exit_room.png";
|
import exit_room from "assets/exit_room.png";
|
||||||
import room_ready from "assets/room_ready.png";
|
import room_ready from "assets/room_ready.png";
|
||||||
import paimon from "../../../packages/assets/imgs/paimon_menu.png";
|
import paimon from "../../../packages/assets/imgs/paimon_menu.png";
|
||||||
|
import { checkVersion } from "../../../packages/utils/tool";
|
||||||
|
|
||||||
const duration = 1000; // 默认点击等待延时
|
const duration = 1000; // 默认点击等待延时
|
||||||
|
|
||||||
@@ -26,6 +28,19 @@ const useFixedAttempts = userAttempts > 0;
|
|||||||
const weekMaxExp = Number(settings.weekMaxExp || "4000");
|
const weekMaxExp = Number(settings.weekMaxExp || "4000");
|
||||||
const singleExp = Number(settings.singleExp || "270");
|
const singleExp = Number(settings.singleExp || "270");
|
||||||
let weekTotal = initWeekTotal();
|
let weekTotal = initWeekTotal();
|
||||||
|
let progressWinId = null;
|
||||||
|
let useMask = false;
|
||||||
|
|
||||||
|
function sendProgress(pct, text, cur, tot) {
|
||||||
|
if (!progressWinId) return;
|
||||||
|
htmlMask.send(progressWinId, "/progress", JSON.stringify({
|
||||||
|
title: "运行进度",
|
||||||
|
progress: pct,
|
||||||
|
current: cur || 0,
|
||||||
|
total: tot || 0,
|
||||||
|
status: text
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
// 读取存档
|
// 读取存档
|
||||||
function loadWeekData() {
|
function loadWeekData() {
|
||||||
@@ -85,8 +100,8 @@ function initWeekTotal() {
|
|||||||
|
|
||||||
// 配置变化 -> 重算
|
// 配置变化 -> 重算
|
||||||
if (
|
if (
|
||||||
stored.weekMaxExp !== weekMaxExp ||
|
stored.weekMaxExp !== weekMaxExp ||
|
||||||
stored.singleExp !== singleExp
|
stored.singleExp !== singleExp
|
||||||
) {
|
) {
|
||||||
stored.weekMaxExp = weekMaxExp;
|
stored.weekMaxExp = weekMaxExp;
|
||||||
stored.singleExp = singleExp;
|
stored.singleExp = singleExp;
|
||||||
@@ -315,6 +330,9 @@ async function playMap() {
|
|||||||
|
|
||||||
await findTextAndClick("开始游戏", 960, 540, 960, 540, 5, 50, 50);
|
await findTextAndClick("开始游戏", 960, 540, 960, 540, 5, 50, 50);
|
||||||
log.info("开始执行第{i}/{total}次奇域挑战", 1, total);
|
log.info("开始执行第{i}/{total}次奇域挑战", 1, total);
|
||||||
|
if (useMask) {
|
||||||
|
sendProgress(0, `正在执行第1/${total}次挑战`, 1, total);
|
||||||
|
}
|
||||||
let firstOutputCount = 0;
|
let firstOutputCount = 0;
|
||||||
await waitUntilTextAppear(
|
await waitUntilTextAppear(
|
||||||
"返回大厅",
|
"返回大厅",
|
||||||
@@ -337,6 +355,9 @@ async function playMap() {
|
|||||||
decreaseWeekTotal();
|
decreaseWeekTotal();
|
||||||
}
|
}
|
||||||
log.info("本次关卡结束");
|
log.info("本次关卡结束");
|
||||||
|
if (useMask) {
|
||||||
|
sendProgress(Math.round(1 / total * 100), `第1/${total}次挑战完成`, 1, total);
|
||||||
|
}
|
||||||
|
|
||||||
await deleteSource();
|
await deleteSource();
|
||||||
|
|
||||||
@@ -348,6 +369,9 @@ async function playMap() {
|
|||||||
await sleep(duration);
|
await sleep(duration);
|
||||||
await findTextAndClick("开始游戏", 960, 540, 960, 540, 20, 50, 50);
|
await findTextAndClick("开始游戏", 960, 540, 960, 540, 20, 50, 50);
|
||||||
log.info("开始执行第{i}/{total}次奇域挑战", i + 1, total);
|
log.info("开始执行第{i}/{total}次奇域挑战", i + 1, total);
|
||||||
|
if (useMask) {
|
||||||
|
sendProgress(Math.round(i / total * 100), `正在执行第${i + 1}/${total}次挑战`, i + 1, total);
|
||||||
|
}
|
||||||
let outputCount = 0;
|
let outputCount = 0;
|
||||||
await waitUntilTextAppear(
|
await waitUntilTextAppear(
|
||||||
"返回大厅",
|
"返回大厅",
|
||||||
@@ -369,6 +393,9 @@ async function playMap() {
|
|||||||
if (!useFixedAttempts) {
|
if (!useFixedAttempts) {
|
||||||
decreaseWeekTotal();
|
decreaseWeekTotal();
|
||||||
}
|
}
|
||||||
|
if (useMask) {
|
||||||
|
sendProgress(Math.round((i + 1) / total * 100), `第${i + 1}/${total}次挑战完成`, i + 1, total);
|
||||||
|
}
|
||||||
await deleteSource();
|
await deleteSource();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -386,21 +413,43 @@ async function exitToTeyvat() {
|
|||||||
await waitUntilImgAppear(paimon);
|
await waitUntilImgAppear(paimon);
|
||||||
// 有镜头拉近动画
|
// 有镜头拉近动画
|
||||||
await sleep(duration);
|
await sleep(duration);
|
||||||
|
log.info("运行结束");
|
||||||
}
|
}
|
||||||
|
|
||||||
(async function () {
|
(async function () {
|
||||||
|
const version = getVersion();
|
||||||
|
const minVersion = '0.60.2-alpha.3';
|
||||||
|
|
||||||
|
useMask = checkVersion(version, minVersion);
|
||||||
|
|
||||||
if (!runJS) {
|
if (!runJS) {
|
||||||
log.error("您未同意此脚本的免责声明,请先同意后重新运行此脚本!");
|
log.error("您未同意此脚本的免责声明,请先同意后重新运行此脚本!");
|
||||||
|
if (useMask) {
|
||||||
|
htmlMask.show("assets/disclaimer-mask.html");
|
||||||
|
await sleep(10000);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (useMask) {
|
||||||
|
const showSkill = roomID === "37135473336";
|
||||||
|
progressWinId = htmlMask.show("assets/progress-mask.html");
|
||||||
|
await sleep(duration);
|
||||||
|
sendProgress(0, "准备中...");
|
||||||
|
if (showSkill && progressWinId) {
|
||||||
|
htmlMask.request(progressWinId, "/showskill", JSON.stringify({
|
||||||
|
show: showSkill
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await genshin.returnMainUi();
|
await genshin.returnMainUi();
|
||||||
|
|
||||||
if (useFixedAttempts) {
|
if (useFixedAttempts) {
|
||||||
// 手动模式:忽略本周计数
|
// 手动模式:忽略本周计数
|
||||||
log.info(
|
log.info(
|
||||||
"已进入指定次数模式,本次将执行{count}次挑战(不计入周进度)",
|
"已进入指定次数模式,本次将执行{count}次挑战(不计入周进度)",
|
||||||
userAttempts
|
userAttempts
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// 每周模式
|
// 每周模式
|
||||||
@@ -409,11 +458,16 @@ async function exitToTeyvat() {
|
|||||||
const done = Math.ceil(weekMaxExp / singleExp) - leave;
|
const done = Math.ceil(weekMaxExp / singleExp) - leave;
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
"本周共需刷取 {total} 次,已刷 {done} 次,剩余 {leave} 次",
|
"本周共需刷取 {total} 次,已刷 {done} 次,剩余 {leave} 次",
|
||||||
Math.ceil(weekMaxExp / singleExp),
|
Math.ceil(weekMaxExp / singleExp),
|
||||||
done,
|
done,
|
||||||
leave
|
leave
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (leave < 1) {
|
||||||
|
log.info("本周任务已完成,结束运行");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (starMode) {
|
if (starMode) {
|
||||||
@@ -424,4 +478,8 @@ async function exitToTeyvat() {
|
|||||||
}
|
}
|
||||||
await playMap();
|
await playMap();
|
||||||
await exitToTeyvat();
|
await exitToTeyvat();
|
||||||
|
if (useMask) {
|
||||||
|
sendProgress(100, "全部完成!");
|
||||||
|
}
|
||||||
|
await sleep(3000);
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 1,
|
"manifest_version": 1,
|
||||||
"name": "千星奇域每周成就经验刷取",
|
"name": "千星奇域每周成就经验刷取",
|
||||||
"version": "3.4",
|
"version": "3.5",
|
||||||
"bgi_version": "0.57.0",
|
"bgi_version": "0.60.0",
|
||||||
"description": "无需自己找图,可用于利用成就高经验值刷取经验,默认配置每周刷满需要22分钟,秒刷图仅需9分钟",
|
"description": "无需自己找图,可用于利用成就高经验值刷取经验,默认配置每周刷满需要22分钟,秒刷图仅需9分钟",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
|||||||
BIN
repo/js/WeeklyThousandStarRealm/map/焚诀.gil
Normal file
BIN
repo/js/WeeklyThousandStarRealm/map/焚诀.gil
Normal file
Binary file not shown.
10
repo/js/WeeklyThousandStarRealm/progress-mask/index.html
Normal file
10
repo/js/WeeklyThousandStarRealm/progress-mask/index.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
18
repo/js/WeeklyThousandStarRealm/progress-mask/package.json
Normal file
18
repo/js/WeeklyThousandStarRealm/progress-mask/package.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "progress-mask",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build && node ../../build/rename.js dist/index.html dist/progress-mask.html",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"gsap": "^3.12.7",
|
||||||
|
"vue": "^3.5.30"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^6.0.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
318
repo/js/WeeklyThousandStarRealm/progress-mask/src/App.vue
Normal file
318
repo/js/WeeklyThousandStarRealm/progress-mask/src/App.vue
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
<template>
|
||||||
|
<div class="overlay">
|
||||||
|
<canvas ref="canvas" class="particle-canvas"></canvas>
|
||||||
|
<div class="content" ref="content">
|
||||||
|
<div class="title" ref="titleEl">{{ title }}</div>
|
||||||
|
<div class="fraction" ref="fractionWrap">
|
||||||
|
<span class="frac-current">{{ current }}</span>
|
||||||
|
<span class="frac-sep">/</span>
|
||||||
|
<span class="frac-total">{{ total }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="bar-area" ref="barArea">
|
||||||
|
<div class="bar-glow"></div>
|
||||||
|
<div class="bar-track">
|
||||||
|
<div class="bar-fill" ref="barFill">
|
||||||
|
<div class="bar-shine"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="percent-wrap" ref="percentWrap">
|
||||||
|
<span class="percent-value">{{ displayProgress }}</span>
|
||||||
|
<span class="percent-unit">%</span>
|
||||||
|
</div>
|
||||||
|
<div class="status" ref="statusEl">{{ status }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="showSkill" class="special-skill">
|
||||||
|
<span>如需使用秒刷图,请查看脚本说明中的焚诀</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, onUnmounted } from 'vue'
|
||||||
|
import gsap from 'gsap'
|
||||||
|
|
||||||
|
const canvas = ref(null)
|
||||||
|
const content = ref(null)
|
||||||
|
const titleEl = ref(null)
|
||||||
|
const fractionWrap = ref(null)
|
||||||
|
const barArea = ref(null)
|
||||||
|
const barFill = ref(null)
|
||||||
|
const percentWrap = ref(null)
|
||||||
|
const statusEl = ref(null)
|
||||||
|
const showSkill = ref(false)
|
||||||
|
|
||||||
|
const title = ref('')
|
||||||
|
const status = ref('等待中...')
|
||||||
|
const progress = ref(0)
|
||||||
|
const displayProgress = ref(0)
|
||||||
|
const current = ref(0)
|
||||||
|
const total = ref(0)
|
||||||
|
|
||||||
|
let animId = null
|
||||||
|
let particles = []
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
showSkill.value = false
|
||||||
|
}, 60000)
|
||||||
|
|
||||||
|
window.htmlMask.onMessage = (msg) => {
|
||||||
|
if (msg.url === '/progress') {
|
||||||
|
if (msg.data.title !== undefined) title.value = msg.data.title
|
||||||
|
if (msg.data.status) status.value = msg.data.status
|
||||||
|
if (msg.data.current !== undefined) current.value = msg.data.current
|
||||||
|
if (msg.data.total !== undefined) total.value = msg.data.total
|
||||||
|
if (msg.data.progress !== undefined) {
|
||||||
|
const pct = Math.min(100, Math.max(0, msg.data.progress))
|
||||||
|
progress.value = pct
|
||||||
|
gsap.to(displayProgress, { value: pct, duration: 0.5, snap: { value: 1 } })
|
||||||
|
gsap.to(barFill.value, { height: pct + '%', duration: 2, ease: 'power2.out' })
|
||||||
|
}
|
||||||
|
} else if (msg.url === '/showskill') {
|
||||||
|
showSkill.value = msg.data.show;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tl = gsap.timeline({ defaults: { ease: 'power3.out' } })
|
||||||
|
tl.from(content.value, { opacity: 0, x: 40, duration: 0.5 })
|
||||||
|
.from(titleEl.value, { y: -15, opacity: 0, duration: 0.3 }, '-=0.2')
|
||||||
|
.from(fractionWrap.value, { scale: 0.5, opacity: 0, duration: 0.4, ease: 'back.out(1.7)' }, '-=0.1')
|
||||||
|
.from(barArea.value, { scaleY: 0, opacity: 0, duration: 0.4 }, '-=0.1')
|
||||||
|
.from(percentWrap.value, { scale: 0.5, opacity: 0, duration: 0.4, ease: 'back.out(1.7)' }, '-=0.1')
|
||||||
|
.from(statusEl.value, { y: 10, opacity: 0, duration: 0.3 }, '-=0.1')
|
||||||
|
|
||||||
|
initParticles()
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.htmlMask.onMessage = null
|
||||||
|
if (animId) cancelAnimationFrame(animId)
|
||||||
|
})
|
||||||
|
|
||||||
|
function initParticles() {
|
||||||
|
const cvs = canvas.value
|
||||||
|
cvs.width = window.innerWidth
|
||||||
|
cvs.height = window.innerHeight
|
||||||
|
const ctx = cvs.getContext('2d')
|
||||||
|
|
||||||
|
const COUNT = 35
|
||||||
|
particles = Array.from({ length: COUNT }, () => spawn(cvs))
|
||||||
|
|
||||||
|
;(function loop() {
|
||||||
|
ctx.clearRect(0, 0, cvs.width, cvs.height)
|
||||||
|
for (const p of particles) {
|
||||||
|
p.x += p.vx
|
||||||
|
p.y += p.vy
|
||||||
|
p.life -= p.decay
|
||||||
|
if (p.life <= 0) Object.assign(p, spawn(cvs))
|
||||||
|
|
||||||
|
ctx.save()
|
||||||
|
ctx.globalAlpha = p.life * p.alpha
|
||||||
|
ctx.shadowBlur = p.size * 6
|
||||||
|
ctx.shadowColor = p.color
|
||||||
|
ctx.fillStyle = p.color
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2)
|
||||||
|
ctx.fill()
|
||||||
|
ctx.restore()
|
||||||
|
}
|
||||||
|
animId = requestAnimationFrame(loop)
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
|
||||||
|
function spawn(cvs) {
|
||||||
|
// 粒子从右侧进度条区域生成
|
||||||
|
const rx = cvs.width - 70
|
||||||
|
const cy = cvs.height / 2
|
||||||
|
return {
|
||||||
|
x: rx + (Math.random() - 0.5) * 60,
|
||||||
|
y: cy + (Math.random() - 0.5) * 280,
|
||||||
|
vx: (Math.random() - 0.5) * 0.5 + 0.3,
|
||||||
|
vy: -(Math.random() * 0.8 + 0.2),
|
||||||
|
size: Math.random() * 2.5 + 0.5,
|
||||||
|
life: 1,
|
||||||
|
decay: Math.random() * 0.008 + 0.004,
|
||||||
|
alpha: Math.random() * 0.5 + 0.2,
|
||||||
|
color: Math.random() > 0.3 ? '#00ff88' : '#88ffcc',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body { background: transparent; font-family: 'Segoe UI', system-ui, sans-serif; }
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
padding-right: 50px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.particle-canvas {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 标题 */
|
||||||
|
.title {
|
||||||
|
font-size: 15px;
|
||||||
|
letter-spacing: 6px;
|
||||||
|
color: rgba(0, 255, 136, 0.85);
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分数 3/15 */
|
||||||
|
.fraction {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 4px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frac-current {
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 0 0 20px rgba(0, 255, 136, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.frac-sep {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 300;
|
||||||
|
color: rgba(0, 255, 136, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.frac-total {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 300;
|
||||||
|
color: rgba(255, 255, 255, 0.75);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 竖向进度条 */
|
||||||
|
.bar-area {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-glow {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 400%;
|
||||||
|
height: 130%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background: radial-gradient(ellipse, rgba(0, 255, 136, 0.08), transparent 60%);
|
||||||
|
pointer-events: none;
|
||||||
|
filter: blur(20px);
|
||||||
|
animation: glow-pulse 2.5s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes glow-pulse {
|
||||||
|
0%, 100% { opacity: 0.7; }
|
||||||
|
50% { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-track {
|
||||||
|
width: 14px;
|
||||||
|
height: 260px;
|
||||||
|
background: rgba(0, 0, 0, 0.55);
|
||||||
|
border-radius: 7px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow:
|
||||||
|
inset 2px 3px 6px rgba(0, 0, 0, 0.6),
|
||||||
|
inset -1px 0 2px rgba(255, 255, 255, 0.04),
|
||||||
|
1px 0 0 rgba(255, 255, 255, 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-fill {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 0%;
|
||||||
|
border-radius: 7px;
|
||||||
|
background: linear-gradient(90deg,
|
||||||
|
rgba(255,255,255,0.2) 0%,
|
||||||
|
#00ff88 15%,
|
||||||
|
#00dd70 45%,
|
||||||
|
#00aa55 80%,
|
||||||
|
#008844 100%
|
||||||
|
);
|
||||||
|
box-shadow:
|
||||||
|
0 0 12px rgba(0, 255, 136, 0.4),
|
||||||
|
0 0 28px rgba(0, 255, 136, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3D 高光 */
|
||||||
|
.bar-shine {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 40%;
|
||||||
|
background: linear-gradient(90deg, rgba(255,255,255,0.35), transparent);
|
||||||
|
border-radius: 7px 0 0 7px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 百分比 */
|
||||||
|
.percent-wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percent-value {
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: 200;
|
||||||
|
color: #fff;
|
||||||
|
text-shadow:
|
||||||
|
0 0 20px rgba(0, 255, 136, 0.3),
|
||||||
|
0 0 40px rgba(0, 255, 136, 0.1);
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percent-unit {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 300;
|
||||||
|
color: rgba(0, 255, 136, 0.7);
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 状态文字 */
|
||||||
|
.status {
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
letter-spacing: 1px;
|
||||||
|
max-width: 100px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.special-skill {
|
||||||
|
display: flex;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 10px;
|
||||||
|
color: #0aff96;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-shadow: 5px 0 5px rgba(0, 255, 136, 0.4),
|
||||||
|
0 5px 5px rgba(0, 255, 136, 0.4),
|
||||||
|
5px 5px 5px rgba(0, 255, 136, 0.4);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { createApp } from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
|
||||||
|
createApp(App).mount('#app')
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { createConfig } from '../../vite.base.config.js'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
|
export default createConfig([vue()])
|
||||||
Reference in New Issue
Block a user