js: GeniusInvokationTCGQuickProficiency: 七圣召唤卡牌熟练度速刷 (#1282)
This commit is contained in:
45
repo/js/GeniusInvokationTCGQuickProficiency/README.md
Normal file
45
repo/js/GeniusInvokationTCGQuickProficiency/README.md
Normal file
@@ -0,0 +1,45 @@
|
||||
你是否也曾为了收集卡牌特效,周旋于各个智障NPC牌局中?
|
||||
|
||||
你是否也曾看着拖拖拉拉的打牌动画而感慨生命的浪费?
|
||||
|
||||
来了,它来了,它在BetterGI的加持下向我们走来了!
|
||||
|
||||
## 使用说明
|
||||
|
||||
此脚本利用联机对局快速提升卡牌的好感度。需要你有两个游戏账号,其中待提升熟练度的号以下称为**大号**,用来在对局中投降的号以下称为**小号**。
|
||||
|
||||
可以[点击这个链接查看使用效果视频](https://github.com/babalae/bettergi-scripts-list/pull/1282)(如果你能打开网页的话)
|
||||
|
||||
**注意: 通过投降来刷熟练度,会产生连续的对局记录。如果你担心重复投降会带来账号风险,请不要使用。**
|
||||
|
||||
> 在运行脚本前,最好确保你已在Better GI的`快捷键`设置中设置了用于`停止当前脚本`的快捷键
|
||||
|
||||
1. 用小号申请加入大号的世界,进入双人联机模式。
|
||||
|
||||
2. **可选**:如果你有两台电脑,那可以在登录了小号的电脑上运行此脚本,运行模式选择`作为辅助账号:快速投降`。
|
||||
|
||||
如果你只有一台电脑,则需要用手机或者平板等设备登录小号,每次收到大号的打牌邀请时手动点击同意,并在进入牌局后快速投降。
|
||||
|
||||
3. 在登录了大号的电脑上运行此脚本,首次运行建议先选择`扫描当前账号卡牌熟练度`模式,扫描的数据将用于为后续刷熟练度的角色规划提供建议。
|
||||
|
||||
4. 在登录了大号的电脑上,以`作为主账号:速刷熟练度`模式运行脚本。
|
||||
|
||||
## 常见问题
|
||||
|
||||
- **如果只有一台电脑怎么办?**
|
||||
|
||||
原神不允许在同一台物理设备上多开,即使多个Windows账号也不行(曾经有短暂的时间段开放了多开,但是很快又关闭了并直到现在)。
|
||||
|
||||
这种情况只能手动操作小号投降(见[使用说明](#使用说明))。由于发起邀请的角色(大号)操作会更复杂,建议用脚本来发起邀请。
|
||||
|
||||
- **只有一台电脑,能不能运行一个原神,运行一个云原神?**
|
||||
|
||||
Better GI在检测到已经有运行中的实例时不会再启动第二份,但并不像原神那样针对同一台物理设备。我也尝试过通过创建多个Windows账号,以双开Better GI,但是后启动的截图器会报错,可能是无法同时运行多个截图器。
|
||||
|
||||
因此目前来看也是不行的(如果你找到了解决方法,欢迎[来Github反馈 😊](https://github.com/babalae/bettergi-scripts-list/issues),最好@一下我 `@Patrick-Ze`)
|
||||
|
||||
- **能不能在当前队伍角色的熟练度刷满后,自动切换熟练度未满的角色?**
|
||||
|
||||
七圣召唤的牌组编辑界面不显示卡牌名,下方的卡牌槽不随详情页切换卡牌而滚动,换卡必须拖拽到目标位置。要实现自动切换角色,必须图像识别所有角色卡牌,过于离谱了。因此目前不支持此功能。
|
||||
|
||||
考虑到原神大概率也不会改进七圣召唤的UI和UX,未来也不会支持此功能。
|
||||
@@ -0,0 +1,2 @@
|
||||
{"macroEvents":[{"type":0,"keyCode":164,"mouseX":0,"mouseY":0,"time":100}],
|
||||
"info":{"name":"","description":"","x":0,"y":0,"width":1920,"height":1080,"recordDpi":1}}
|
||||
@@ -0,0 +1,2 @@
|
||||
{"macroEvents":[{"type":1,"keyCode":164,"mouseX":0,"mouseY":0,"time":100}],
|
||||
"info":{"name":"","description":"","x":0,"y":0,"width":1920,"height":1080,"recordDpi":1}}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
97
repo/js/GeniusInvokationTCGQuickProficiency/lib/ocr.js
Normal file
97
repo/js/GeniusInvokationTCGQuickProficiency/lib/ocr.js
Normal file
@@ -0,0 +1,97 @@
|
||||
const defaultReplacementMap = {
|
||||
监: "盐",
|
||||
卵: "卯",
|
||||
};
|
||||
|
||||
async function waitForTextAppear(targetText, ocrRegion, timeout = 5000, retryInterval = 50, replacementMap = defaultReplacementMap) {
|
||||
let x, y, width, height;
|
||||
|
||||
if (Array.isArray(ocrRegion)) {
|
||||
[x, y, width, height] = ocrRegion;
|
||||
} else if (typeof ocrRegion === "object" && ocrRegion !== null) {
|
||||
({ x, y, width, height } = ocrRegion);
|
||||
} else {
|
||||
throw new Error("Invalid parameter 'ocrRegion'");
|
||||
}
|
||||
|
||||
const debugThreshold = timeout / retryInterval / 3;
|
||||
let startTime = Date.now();
|
||||
let retryCount = 0; // 重试计数
|
||||
while (Date.now() - startTime < timeout) {
|
||||
let captureRegion = captureGameRegion();
|
||||
try {
|
||||
// 尝试 OCR 识别
|
||||
let resList = captureRegion.findMulti(RecognitionObject.ocr(x, y, width, height)); // 指定识别区域
|
||||
// 遍历识别结果,检查是否找到目标文本
|
||||
for (let res of resList) {
|
||||
// 后处理:根据替换映射表检查和替换错误识别的字符
|
||||
let correctedText = res.text;
|
||||
for (let [wrongChar, correctChar] of Object.entries(replacementMap)) {
|
||||
correctedText = correctedText.replace(new RegExp(wrongChar, "g"), correctChar);
|
||||
}
|
||||
|
||||
if (correctedText.includes(targetText)) {
|
||||
return { success: true, wait_time: Date.now() - startTime };
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
log.warn(`页面标志识别失败,正在进行第 ${retryCount} 次重试...`);
|
||||
}
|
||||
retryCount++; // 增加重试计数
|
||||
if (retryCount > debugThreshold) {
|
||||
let region = captureRegion.DeriveCrop(x, y, width, height);
|
||||
region.DrawSelf("debug");
|
||||
}
|
||||
await sleep(retryInterval);
|
||||
}
|
||||
return { success: false };
|
||||
}
|
||||
|
||||
async function recognizeTextAndClick(targetText, ocrRegion, timeout = 5000, retryInterval = 50, replacementMap = defaultReplacementMap) {
|
||||
let x, y, width, height;
|
||||
|
||||
if (Array.isArray(ocrRegion)) {
|
||||
[x, y, width, height] = ocrRegion;
|
||||
} else if (typeof ocrRegion === "object" && ocrRegion !== null) {
|
||||
({ x, y, width, height } = ocrRegion);
|
||||
} else {
|
||||
throw new Error("Invalid parameter 'ocrRegion'");
|
||||
}
|
||||
|
||||
const debugThreshold = timeout / retryInterval / 3;
|
||||
let startTime = Date.now();
|
||||
let retryCount = 0; // 重试计数
|
||||
while (Date.now() - startTime < timeout) {
|
||||
let captureRegion = captureGameRegion();
|
||||
try {
|
||||
// 尝试 OCR 识别
|
||||
let resList = captureRegion.findMulti(RecognitionObject.ocr(x, y, width, height)); // 指定识别区域
|
||||
// 遍历识别结果,检查是否找到目标文本
|
||||
for (let res of resList) {
|
||||
// 后处理:根据替换映射表检查和替换错误识别的字符
|
||||
let correctedText = res.text;
|
||||
for (let [wrongChar, correctChar] of Object.entries(replacementMap)) {
|
||||
correctedText = correctedText.replace(new RegExp(wrongChar, "g"), correctChar);
|
||||
}
|
||||
|
||||
if (correctedText.includes(targetText)) {
|
||||
// 如果找到目标文本,计算并点击文字的中心坐标
|
||||
let centerX = Math.round(res.x + res.width / 2);
|
||||
let centerY = Math.round(res.y + res.height / 2);
|
||||
await click(centerX, centerY);
|
||||
await sleep(50);
|
||||
return { success: true, x: centerX, y: centerY };
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
log.warn(`页面标志识别失败,正在进行第 ${retryCount} 次重试...`);
|
||||
}
|
||||
retryCount++; // 增加重试计数
|
||||
if (retryCount > debugThreshold) {
|
||||
let region = captureRegion.DeriveCrop(x, y, width, height);
|
||||
region.DrawSelf("debug");
|
||||
}
|
||||
await sleep(retryInterval);
|
||||
}
|
||||
return { success: false };
|
||||
}
|
||||
326
repo/js/GeniusInvokationTCGQuickProficiency/main.js
Normal file
326
repo/js/GeniusInvokationTCGQuickProficiency/main.js
Normal file
@@ -0,0 +1,326 @@
|
||||
eval(file.readTextSync("lib/ocr.js"));
|
||||
|
||||
const rewardIcon = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RewardIcon.png"), 1430, 760, 100, 70);
|
||||
const tavernRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/TavernIcon.png"), 800, 450, 500, 330);
|
||||
const adventurersRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/AdventurersGuild.png"), 800, 450, 500, 330);
|
||||
|
||||
const outFile = "卡牌熟练度.json";
|
||||
let currentProficiencys = {};
|
||||
try {
|
||||
currentProficiencys = JSON.parse(file.readTextSync(outFile));
|
||||
} catch (error) {
|
||||
log.debug("历史熟练度文件不存在");
|
||||
}
|
||||
|
||||
(async function () {
|
||||
setGameMetrics(1920, 1080, 1.25);
|
||||
log.info("首次运行前请阅读脚本说明");
|
||||
log.info("请确保已进入双人联机模式");
|
||||
await sleep(1000);
|
||||
|
||||
let runMode = settings.runMode;
|
||||
if (!runMode) {
|
||||
runMode = "作为主账号:速刷熟练度";
|
||||
log.info("未配置运行模式,默认以{0}模式运行", runMode);
|
||||
}
|
||||
|
||||
if (runMode === "作为主账号:速刷熟练度") {
|
||||
await runAsMain(settings.targetProficiency);
|
||||
} else if (runMode === "作为辅助账号:快速投降") {
|
||||
await runAsPartner();
|
||||
} else if (runMode === "扫描当前账号卡牌熟练度") {
|
||||
await scanCardsProficiency();
|
||||
} else {
|
||||
log.error("不支持的运行模式: {0}", runMode);
|
||||
}
|
||||
})();
|
||||
|
||||
// 需要刷熟练度的角色的执行逻辑
|
||||
async function runAsMain(targetProficiency) {
|
||||
log.info("主账号开始工作,如需停止请按下你设置的BetterGI停止按键");
|
||||
if (!targetProficiency) {
|
||||
targetProficiency = 30;
|
||||
}
|
||||
let loopCount = -1;
|
||||
await genshin.returnMainUi();
|
||||
log.info("前往猫尾酒馆");
|
||||
await teleportToTheCatsTail();
|
||||
do {
|
||||
await waitTpFinish();
|
||||
await gotoInvitationBoard();
|
||||
await waitForTextAppear("邀请队友", [1332, 886, 130, 49]);
|
||||
if (loopCount < 0) {
|
||||
log.info("获取当前熟练度信息");
|
||||
loopCount = await calcRepeatTimes(targetProficiency);
|
||||
if (loopCount <= 0) {
|
||||
recommendNextTeam(targetProficiency);
|
||||
return;
|
||||
}
|
||||
log.info("需重复执行{0}次以达成{1}熟练度", loopCount, targetProficiency);
|
||||
}
|
||||
|
||||
// 循环次数为0时已经无需再打牌,只是再走到位置然后领取奖励
|
||||
if (loopCount === 0) {
|
||||
await calcRepeatTimes(targetProficiency, true);
|
||||
break;
|
||||
}
|
||||
|
||||
log.info("邀请队友");
|
||||
for (let i = 0; i < 60; i++) {
|
||||
await recognizeTextAndClick("邀请队友", [1332, 886, 130, 49]);
|
||||
let r = await waitForTextAppear("正在匹配对局", [870, 385, 184, 42], 500);
|
||||
if (r.success) {
|
||||
break;
|
||||
}
|
||||
await sleep(500);
|
||||
}
|
||||
|
||||
log.info("等待对方同意");
|
||||
await recognizeTextAndClick("正在匹配对局", [871, 386, 182, 39], 30000);
|
||||
|
||||
log.info("等待加载");
|
||||
await waitForTextAppear("七圣召唤", [902, 870, 119, 46]);
|
||||
|
||||
await waitForTextAppear("请选择要替换的手牌", [847, 232, 229, 39], 30000);
|
||||
log.info("选择初始手牌");
|
||||
await recognizeTextAndClick("确定", [937, 922, 82, 54], 30000);
|
||||
|
||||
log.info("等待对方认输");
|
||||
await waitForTextAppear("退出挑战", [913, 893, 130, 43], 60000);
|
||||
await sleep(300);
|
||||
await recognizeTextAndClick("退出挑战", [913, 893, 130, 43]);
|
||||
|
||||
try {
|
||||
await sleep(10);
|
||||
} catch (error) {
|
||||
log.info("用户停止运行");
|
||||
break;
|
||||
}
|
||||
|
||||
loopCount--;
|
||||
log.info(`对局结束,当前熟练度 ${targetProficiency - loopCount}/${targetProficiency}`);
|
||||
} while (loopCount >= 0);
|
||||
}
|
||||
|
||||
// 小号的执行逻辑
|
||||
async function runAsPartner() {
|
||||
log.info("辅助账号开始工作,如需停止请按下你设置的BetterGI停止按键");
|
||||
await genshin.tp(-575.60, 1859.34);
|
||||
await waitTpFinish();
|
||||
while (true) {
|
||||
log.info("等待对局邀请");
|
||||
await waitForTextAppear("点击进行准备", [820, 70, 296, 31], 180000);
|
||||
keyPress("Y");
|
||||
await recognizeTextAndClick("接受", [1177, 713, 82, 55]);
|
||||
|
||||
log.info("等待加载");
|
||||
await waitForTextAppear("七圣召唤", [902, 870, 119, 46]);
|
||||
|
||||
await waitForTextAppear("请选择要替换的手牌", [847, 232, 229, 39], 30000);
|
||||
log.info("选择初始手牌");
|
||||
await recognizeTextAndClick("确定", [937, 922, 82, 54], 30000);
|
||||
|
||||
log.info("等待进入牌桌界面");
|
||||
await waitForTextAppear("出战角色", [1766, 850, 118, 43]);
|
||||
|
||||
log.info("认输");
|
||||
click(1864, 46);
|
||||
await sleep(500);
|
||||
await recognizeTextAndClick("放弃对局", [1543, 172, 112, 43]);
|
||||
await waitForTextAppear("确定要放弃", [785, 497, 339, 39]);
|
||||
await recognizeTextAndClick("确认", [1142, 732, 78, 51]);
|
||||
|
||||
await waitForTextAppear("退出挑战", [913, 893, 130, 43], 60000);
|
||||
await sleep(300);
|
||||
await recognizeTextAndClick("退出挑战", [913, 893, 130, 43]);
|
||||
log.info("退出挑战");
|
||||
|
||||
try {
|
||||
await sleep(3000);
|
||||
} catch (error) {
|
||||
log.info("用户停止运行");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function gotoInvitationBoard() {
|
||||
keyDown("MBUTTON");
|
||||
await sleep(500);
|
||||
|
||||
keyDown("A");
|
||||
await sleep(1500);
|
||||
keyUp("A");
|
||||
|
||||
await sleep(1000);
|
||||
await keyMouseScript.runFile(`assets/ALT点击.json`);
|
||||
await sleep(500);
|
||||
await recognizeTextAndClick("联机对局", [1217, 411, 220, 280]);
|
||||
await sleep(500);
|
||||
await keyMouseScript.runFile(`assets/ALT释放.json`);
|
||||
}
|
||||
|
||||
function recommendNextTeam(targetProficiency) {
|
||||
log.info("当前牌组中卡牌已达成熟练度目标,请更换牌组内角色");
|
||||
const nextTeam = Object.fromEntries(
|
||||
Object.entries(currentProficiencys)
|
||||
.filter(([_, v]) => v < targetProficiency)
|
||||
.slice(0, 3)
|
||||
);
|
||||
if (Object.keys(nextTeam).length > 0) {
|
||||
let text = JSON.stringify(nextTeam).replace(/[{}"]/g, '');
|
||||
log.info("熟练度未满的角色推荐: {0}", text);
|
||||
}
|
||||
}
|
||||
|
||||
async function calcRepeatTimes(targetProficiency, taskFinished = false) {
|
||||
// 需要在选择“我方出战牌组”的界面执行
|
||||
await waitForTextAppear("我方出战牌组", [1248, 688, 156, 36]);
|
||||
|
||||
click(1306, 747);
|
||||
log.info("等待进入牌组界面");
|
||||
await recognizeTextAndClick("编辑牌组", [733, 997, 129, 48]);
|
||||
|
||||
await waitForTextAppear("更改牌组外观", [1592, 186, 139, 35]);
|
||||
click(700, 276); // +257
|
||||
|
||||
await waitForTextAppear("卡牌", [867, 266, 68, 47]);
|
||||
|
||||
let characterProficiencys = {};
|
||||
for (let i = 0; i < 3; i++) {
|
||||
let captureRegion = captureGameRegion();
|
||||
if (taskFinished) {
|
||||
const icon = captureRegion.find(rewardIcon);
|
||||
if (icon.isExist()) {
|
||||
icon.click();
|
||||
await sleep(100);
|
||||
icon.click();
|
||||
await sleep(100);
|
||||
}
|
||||
}
|
||||
let ch_result = captureRegion.find(RecognitionObject.ocr(851, 326, 398, 65));
|
||||
let proficiencyResult = captureRegion.find(RecognitionObject.ocr(855, 780, 210, 40));
|
||||
if (ch_result.text && proficiencyResult.text) {
|
||||
let character = ch_result.text.trim();
|
||||
const match = proficiencyResult.text.match(/(\d+)/);
|
||||
let proficiency = parseInt(match[0]);
|
||||
characterProficiencys[character] = proficiency;
|
||||
click(1635, 538);
|
||||
await sleep(500);
|
||||
}
|
||||
}
|
||||
Object.assign(currentProficiencys, characterProficiencys);
|
||||
file.writeTextSync(outFile, JSON.stringify(currentProficiencys, null, 2));
|
||||
log.info("当前熟练度: {0}", JSON.stringify(characterProficiencys).replace(/[{}"]/g, ''));
|
||||
if (taskFinished) {
|
||||
recommendNextTeam(targetProficiency);
|
||||
return;
|
||||
}
|
||||
const loopCount = targetProficiency - Math.min(...Object.values(characterProficiencys));
|
||||
|
||||
// 返回对战页面
|
||||
keyPress("VK_ESCAPE");
|
||||
await waitForTextAppear("更改牌组外观", [1592, 186, 139, 35]);
|
||||
keyPress("VK_ESCAPE");
|
||||
await waitForTextAppear("编辑牌组", [733, 997, 129, 48]);
|
||||
keyPress("VK_ESCAPE");
|
||||
await waitForTextAppear("我方出战牌组", [1248, 688, 156, 36]);
|
||||
return loopCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待传送结束
|
||||
* @param {Int} timeout 单位为ms
|
||||
* @note 参考了七圣召唤七日历练脚本
|
||||
*/
|
||||
async function waitTpFinish(timeout=30000) {
|
||||
const region = RecognitionObject.ocr(1690, 230, 75, 350); // 队伍名称区域
|
||||
const startTime = new Date();
|
||||
|
||||
await sleep(1000); //点击传送后等待一段时间避免误判
|
||||
while (new Date() - startTime < timeout) {
|
||||
let res = captureGameRegion().find(region);
|
||||
if (!res.isEmpty()) {
|
||||
await sleep(600); //传送结束后有僵直
|
||||
return;
|
||||
}
|
||||
await sleep(100);
|
||||
}
|
||||
throw new Error("传送时间超时");
|
||||
}
|
||||
|
||||
/** 传送到猫尾酒馆 */
|
||||
async function teleportToTheCatsTail() {
|
||||
await genshin.moveMapTo(-867, 2281, "蒙德");
|
||||
await genshin.setBigMapZoomLevel(1.0);
|
||||
let clickIcon = null;
|
||||
for (let i = 0; i < 5; i ++) {
|
||||
const region = captureGameRegion();
|
||||
const tarvern = region.find(tavernRo);
|
||||
clickIcon = tarvern.isExist() ? tarvern : region.find(adventurersRo);
|
||||
if (clickIcon.isExist()) {
|
||||
clickIcon.click();
|
||||
await sleep(500);
|
||||
break;
|
||||
}
|
||||
await sleep(500);
|
||||
}
|
||||
if (!(clickIcon && clickIcon.isExist())) {
|
||||
throw new Error("找不到猫尾酒馆,如果2P标志遮挡了酒馆图标,请将2P玩家传送至别处");
|
||||
}
|
||||
await recognizeTextAndClick("猫尾酒馆", [1320, 560, 300, 410])
|
||||
await recognizeTextAndClick("传送至", [1580,980,225,59])
|
||||
await waitTpFinish();
|
||||
}
|
||||
|
||||
async function scanCardsProficiency() {
|
||||
await genshin.returnMainUi();
|
||||
log.info("前往猫尾酒馆");
|
||||
await teleportToTheCatsTail();
|
||||
await gotoInvitationBoard();
|
||||
await waitForTextAppear("我方出战牌组", [1248, 688, 156, 36]);
|
||||
|
||||
click(1306, 747);
|
||||
log.info("等待进入牌组界面");
|
||||
await recognizeTextAndClick("编辑牌组", [733, 997, 129, 48]);
|
||||
|
||||
await waitForTextAppear("更改牌组外观", [1592, 186, 139, 35]);
|
||||
click(198, 717);
|
||||
|
||||
let characterProficiencys = {};
|
||||
let last_char = null;
|
||||
let retry = 0;
|
||||
for (let i = 0; i < 300; i++) {
|
||||
let captureRegion = captureGameRegion();
|
||||
let ch_result = captureRegion.find(RecognitionObject.ocr(851, 326, 398, 65));
|
||||
let proficiencyResult = captureRegion.find(RecognitionObject.ocr(855, 780, 210, 40));
|
||||
if (ch_result.text && proficiencyResult.text) {
|
||||
let character = ch_result.text.trim().replace("t", "七");
|
||||
const match = proficiencyResult.text.match(/(\d+)/);
|
||||
let proficiency = parseInt(match[0]);
|
||||
characterProficiencys[character] = proficiency;
|
||||
log.info("{ch} = {v}", character, proficiency);
|
||||
if (last_char === character) {
|
||||
log.info("已到达角色列表末尾");
|
||||
break;
|
||||
}
|
||||
click(1635, 538);
|
||||
retry = 0;
|
||||
last_char = character;
|
||||
} else {
|
||||
retry++;
|
||||
if (retry >= 3) {
|
||||
log.warn("OCR无法识别当前角色名称,跳过");
|
||||
click(1635, 538);
|
||||
retry = 0;
|
||||
}
|
||||
}
|
||||
await sleep(500);
|
||||
}
|
||||
|
||||
const sortedProficiencys = Object.entries(characterProficiencys).sort((a, b) => b[1] - a[1]);
|
||||
currentProficiencys = Object.fromEntries(sortedProficiencys);
|
||||
file.writeTextSync(outFile, JSON.stringify(currentProficiencys, null, 2));
|
||||
|
||||
log.info("卡牌熟练度数据已写入{0}", outFile);
|
||||
}
|
||||
15
repo/js/GeniusInvokationTCGQuickProficiency/manifest.json
Normal file
15
repo/js/GeniusInvokationTCGQuickProficiency/manifest.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"name": "七圣召唤卡牌熟练度速刷",
|
||||
"version": "1.0",
|
||||
"bgi_version": "0.45.0",
|
||||
"description": "七圣召唤卡牌熟练度速刷",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ayaka-Main",
|
||||
"link": "https://github.com/Patrick-Ze"
|
||||
}
|
||||
],
|
||||
"settings_ui": "settings.json",
|
||||
"main": "main.js"
|
||||
}
|
||||
17
repo/js/GeniusInvokationTCGQuickProficiency/settings.json
Normal file
17
repo/js/GeniusInvokationTCGQuickProficiency/settings.json
Normal file
@@ -0,0 +1,17 @@
|
||||
[
|
||||
{
|
||||
"name": "runMode",
|
||||
"type": "select",
|
||||
"label": "运行模式",
|
||||
"options": [
|
||||
"作为主账号:速刷熟练度",
|
||||
"作为辅助账号:快速投降",
|
||||
"扫描当前账号卡牌熟练度"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "targetProficiency",
|
||||
"type": "input-text",
|
||||
"label": "目标熟练度 (未设置时默认刷到30)"
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user