148 lines
4.7 KiB
JavaScript
148 lines
4.7 KiB
JavaScript
// src/index.ts
|
|
async function mouseSmoothMove(sx, sy, ex, ey, duration) {
|
|
const steps = Math.max(Math.floor(duration / (1e3 / 60)), 20);
|
|
const points = [];
|
|
points.push([sx, sy]);
|
|
for (let i = 1; i < steps - 1; i++) {
|
|
const t = i / (steps - 1);
|
|
const x = (1 - t) * sx + t * ex;
|
|
const y = (1 - t) * sy + t * ey;
|
|
points.push([x, y]);
|
|
}
|
|
points.push([ex, ey]);
|
|
const interval = duration / steps;
|
|
for (const [x, y] of points) {
|
|
moveMouseTo(Math.floor(x), Math.floor(y));
|
|
await sleep(Math.floor(interval));
|
|
}
|
|
}
|
|
async function mouseSmoothDrag(sx, sy, ex, ey, duration) {
|
|
moveMouseTo(sx, sy);
|
|
leftButtonDown();
|
|
await sleep(50);
|
|
await mouseSmoothMove(sx, sy, ex, ey, duration - 300);
|
|
await sleep(250);
|
|
leftButtonUp();
|
|
}
|
|
|
|
// 最多尝试 2 次拖动屏幕
|
|
const DRAG_SCREEN_MAX = 2;
|
|
// 宠物与模板的对应关系
|
|
const PETS = [
|
|
// TODO: 作者未拥有(lll¬ω¬),待有缘人补充
|
|
// { name: "迷你仙灵·薄红", file: "" },
|
|
// { name: "迷你仙灵·露草", file: "" },
|
|
// { name: "嫣朵拉", file: "" },
|
|
{ name: '迷你仙灵·苔绿', file: 'assets/moss.png' },
|
|
{ name: '迷你仙灵·紫苑', file: 'assets/viola.png' },
|
|
{ name: '迷你仙灵·郁金', file: 'assets/curcuma.png' },
|
|
{ name: '迷你仙灵·璨光', file: 'assets/brilliance.png' },
|
|
{ name: '魔瓶镇灵·利露帕尔', file: 'assets/liloupar.png' },
|
|
{ name: '斯露莎', file: 'assets/sorush.png' },
|
|
{ name: '初诞灵焰', file: 'assets/firstborn_firesprite.png' },
|
|
{ name: '柔柔小章', file: 'assets/itty_bitty_octobaby.png' },
|
|
{ name: '缥锦机关·留云', file: 'assets/damasked_device.png' },
|
|
{ name: '「式小将」', file: 'assets/shiki_koshou.png' },
|
|
];
|
|
/**
|
|
* 装备宠物
|
|
* @param pet 宠物
|
|
*/
|
|
async function equipPet(pet) {
|
|
// 宠物识别 低精度
|
|
const petRo = RecognitionObject.templateMatch(file.readImageMatSync(pet.file));
|
|
petRo.threshold = 0.9;
|
|
// 开启 3 通道识别区分 迷你仙灵 系列
|
|
petRo.use3Channels = true;
|
|
for (let i = 0; i < DRAG_SCREEN_MAX; i++) {
|
|
// 移开鼠标
|
|
moveMouseTo(0, 0);
|
|
await sleep(100);
|
|
const gameRegion = captureGameRegion();
|
|
const petRegion = gameRegion.find(petRo);
|
|
if (!petRegion.isExist()) {
|
|
// 未找到宠物,尝试拖动屏幕
|
|
await mouseSmoothDrag(1200, 890, 1200, 186, 2000);
|
|
continue;
|
|
}
|
|
petRegion.click();
|
|
await sleep(1000);
|
|
// 提升精度
|
|
petRo.threshold = 0.97;
|
|
const equipRegion = gameRegion.find(petRo);
|
|
if (!equipRegion.isExist()) {
|
|
// 装备宠物
|
|
click(1690, 1015);
|
|
await sleep(1000);
|
|
}
|
|
return log.info(`已装备:${pet.name}`);
|
|
}
|
|
throw new Error(`未识别到宠物:${pet.name}`);
|
|
}
|
|
/**
|
|
* 卸下宠物
|
|
*/
|
|
async function removePet() {
|
|
const pets = PETS.map((pet) => {
|
|
const ro = RecognitionObject.templateMatch(file.readImageMatSync(pet.file));
|
|
ro.threshold = 0.97;
|
|
ro.use3Channels = true;
|
|
return { ...pet, ro };
|
|
});
|
|
for (let i = 0; i < DRAG_SCREEN_MAX; i++) {
|
|
// 移开鼠标
|
|
moveMouseTo(0, 0);
|
|
await sleep(100);
|
|
const gameRegion = captureGameRegion();
|
|
for (const pet of pets) {
|
|
const petRegion = gameRegion.find(pet.ro);
|
|
if (!petRegion.isExist()) {
|
|
continue;
|
|
}
|
|
petRegion.click();
|
|
await sleep(1000);
|
|
click(1690, 1015);
|
|
await sleep(1000);
|
|
return log.info(`已卸下宠物:${pet.name}`);
|
|
}
|
|
await mouseSmoothDrag(1200, 890, 1200, 186, 2000);
|
|
}
|
|
log.warn('未找到装备中的宠物');
|
|
}
|
|
(async () => {
|
|
try {
|
|
const name = settings.name;
|
|
const mode = settings.mode;
|
|
if (!name && mode === '装备') {
|
|
throw new Error('请先设置宠物名称');
|
|
}
|
|
if (mode === '装备') {
|
|
log.info(`尝试装备:${name}`);
|
|
}
|
|
else if (mode === '卸下') {
|
|
log.info('尝试卸下宠物');
|
|
}
|
|
// 切回主界面
|
|
await genshin.returnMainUi();
|
|
// 打开背包
|
|
keyPress('VK_B');
|
|
await sleep(1000);
|
|
// 移动到小道具栏
|
|
moveMouseTo(1055, 50);
|
|
leftButtonClick();
|
|
await sleep(1000);
|
|
if (mode === '装备') {
|
|
await equipPet(PETS.find(pet => pet.name === name));
|
|
}
|
|
else if (mode === '卸下') {
|
|
await removePet();
|
|
}
|
|
}
|
|
catch (error) {
|
|
log.error(error.message);
|
|
}
|
|
finally {
|
|
await genshin.returnMainUi();
|
|
}
|
|
})();
|