mirror of
https://github.com/Shu-Ying/noname-shuying.git
synced 2026-11-14 00:40:03 +08:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a3d26b6a6 |
@@ -15,7 +15,11 @@ tools/*.mjs
|
|||||||
/Slay the Spire 2
|
/Slay the Spire 2
|
||||||
|
|
||||||
*.mjs
|
*.mjs
|
||||||
|
!tools/test_skill_teardown.mjs
|
||||||
|
!tools/test_battle_lifecycle.mjs
|
||||||
*.cjs
|
*.cjs
|
||||||
|
!mengsan/tools/check-sts2-relics.mjs
|
||||||
|
!mengsan/tools/write-sts2-relics-report.mjs
|
||||||
|
|
||||||
/.update_tmp/
|
/.update_tmp/
|
||||||
/.planning/
|
/.planning/
|
||||||
|
|||||||
Vendored
+37
-47
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"version": "2.0.2.3-rc.5",
|
"version": "2.0.2.3-rc.4",
|
||||||
"generated_at": "2026-10-14T10:45:26.004470+00:00",
|
"generated_at": "2026-10-13T10:12:31.027219+00:00",
|
||||||
"algorithm": "sha256",
|
"algorithm": "sha256",
|
||||||
"update_channels": true,
|
"update_channels": true,
|
||||||
"file_count": 288,
|
"file_count": 287,
|
||||||
"size_bytes": 48045889,
|
"size_bytes": 48033536,
|
||||||
"folder_sha256": "4b5186b4b1631ac4010776aacf6fd0366b5a7ae5a650e8c57757b073a4592cd7",
|
"folder_sha256": "ba438ead95317df5229d801e1433f6c1ad66d9708b17f4d6c055b363c3e5ba16",
|
||||||
"core": [
|
"core": [
|
||||||
"extension.js",
|
"extension.js",
|
||||||
"menu.js",
|
"menu.js",
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
"tianshu/config.js",
|
"tianshu/config.js",
|
||||||
"tianshu/directDamage.js",
|
"tianshu/directDamage.js",
|
||||||
"tianshu/skillRecover.js",
|
"tianshu/skillRecover.js",
|
||||||
"tianshu/skillCard.js",
|
|
||||||
"pve/boss/index.js",
|
"pve/boss/index.js",
|
||||||
"pve/boss/card.js",
|
"pve/boss/card.js",
|
||||||
"pve/boss/character.js",
|
"pve/boss/character.js",
|
||||||
@@ -438,16 +437,16 @@
|
|||||||
"sha256": "0907c22921f33d3180378dfcec4cdea793227d325c281d5f3a3f698c83b42b85"
|
"sha256": "0907c22921f33d3180378dfcec4cdea793227d325c281d5f3a3f698c83b42b85"
|
||||||
},
|
},
|
||||||
"extension.js": {
|
"extension.js": {
|
||||||
"size": 15731,
|
"size": 15923,
|
||||||
"sha256": "8fc4b551aa0fa833cc7412869f5ab0677679c70780153f1b06d8c0969d613e7a"
|
"sha256": "6adcb14ef054c1e3bb5f8f7ed892f3d87dd975dabc8516135d76035ce3d1b752"
|
||||||
},
|
},
|
||||||
"function.js": {
|
"function.js": {
|
||||||
"size": 38588,
|
"size": 37769,
|
||||||
"sha256": "da9d2fc1a6ed1a03d84d90d0047039ed1855dafb6c6d7b30d44de2f3ccc71538"
|
"sha256": "08b075a5347c097a2ee202d9b049ff2b313afb5d1b3c0df8fb423902c7d8e9ad"
|
||||||
},
|
},
|
||||||
"menu.js": {
|
"menu.js": {
|
||||||
"size": 30914,
|
"size": 30884,
|
||||||
"sha256": "3d008230b037806462b33529d3b6969e458031c55715cef34537a0d623cba518"
|
"sha256": "22e837db0373eed9f7d5beb4fdd1d985fb8dc3791ba1f3174b858de943830e39"
|
||||||
},
|
},
|
||||||
"pve/audio/dead/十二生肖/chenlong.mp3": {
|
"pve/audio/dead/十二生肖/chenlong.mp3": {
|
||||||
"size": 68757,
|
"size": 68757,
|
||||||
@@ -1326,32 +1325,28 @@
|
|||||||
"sha256": "da23eb0fd107b05d2cfb6c6e8e8864cca60044f9d0f94340f5f48af474f24aae"
|
"sha256": "da23eb0fd107b05d2cfb6c6e8e8864cca60044f9d0f94340f5f48af474f24aae"
|
||||||
},
|
},
|
||||||
"tianshu/config.js": {
|
"tianshu/config.js": {
|
||||||
"size": 32634,
|
"size": 31361,
|
||||||
"sha256": "450bbc669efc2a5c2d157b197d23b52054a82f995e07c25a47c3046183b48ef2"
|
"sha256": "1bfd6a5bfecc2464f66d9ce87776ed6d4615519147e5006b322199a9cdcf5ac1"
|
||||||
},
|
},
|
||||||
"tianshu/directDamage.js": {
|
"tianshu/directDamage.js": {
|
||||||
"size": 1295,
|
"size": 1190,
|
||||||
"sha256": "aced905fba4e2d23f88ddb76d09ea570c7c4ed1aa33a322d73c0fdb55012012e"
|
"sha256": "7eea5d094905eb84e611cf4dc3da2aebd83e326b908a6482ecde469acf17277c"
|
||||||
},
|
},
|
||||||
"tianshu/extension.js": {
|
"tianshu/extension.js": {
|
||||||
"size": 93305,
|
"size": 87300,
|
||||||
"sha256": "37c684b6193e01424fb9492a6722aa7dee6d40b7bcf6b4b559ad4a6aca334944"
|
"sha256": "025c07a177e564b84b59c982b1f6cf5ecf208c750a9f16994b6af7c286c21e83"
|
||||||
},
|
},
|
||||||
"tianshu/shuYing_Skill_Xvxiang1.mp3": {
|
"tianshu/shuYing_Skill_Xvxiang1.mp3": {
|
||||||
"size": 15451,
|
"size": 15451,
|
||||||
"sha256": "41914d7d542ddfb93c89aefffc245869d63a9fb2f52293df8e6667009832afd8"
|
"sha256": "41914d7d542ddfb93c89aefffc245869d63a9fb2f52293df8e6667009832afd8"
|
||||||
},
|
},
|
||||||
"tianshu/skillCard.js": {
|
|
||||||
"size": 2680,
|
|
||||||
"sha256": "ff92fbb7784a6ae2b701e6caa028fb29421b8b1679716752f33f070e334356d2"
|
|
||||||
},
|
|
||||||
"tianshu/skillRecover.js": {
|
"tianshu/skillRecover.js": {
|
||||||
"size": 2675,
|
"size": 2570,
|
||||||
"sha256": "bd89818b8f535c19b51f107ca2c75dec669852e4a604ed55f6fa945ecec8e6d6"
|
"sha256": "a888d0b72988ff49406017234c56771631e8760e3a578d6d715d97b7bfdb5442"
|
||||||
},
|
},
|
||||||
"update.js": {
|
"update.js": {
|
||||||
"size": 77454,
|
"size": 75926,
|
||||||
"sha256": "f2693e030c0008c788c3e1785e0d6b41dc1df1251624efc003ff0b51d4c2a9f0"
|
"sha256": "5b62cf2771f188e7fe5ed2c31095afd55494883117e50555530997a2d060c783"
|
||||||
},
|
},
|
||||||
"update.txt": {
|
"update.txt": {
|
||||||
"size": 4962,
|
"size": 4962,
|
||||||
@@ -1695,18 +1690,18 @@
|
|||||||
},
|
},
|
||||||
"extension.js": {
|
"extension.js": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"size": 15731,
|
"size": 15923,
|
||||||
"sha256": "8fc4b551aa0fa833cc7412869f5ab0677679c70780153f1b06d8c0969d613e7a"
|
"sha256": "6adcb14ef054c1e3bb5f8f7ed892f3d87dd975dabc8516135d76035ce3d1b752"
|
||||||
},
|
},
|
||||||
"function.js": {
|
"function.js": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"size": 38588,
|
"size": 37769,
|
||||||
"sha256": "da9d2fc1a6ed1a03d84d90d0047039ed1855dafb6c6d7b30d44de2f3ccc71538"
|
"sha256": "08b075a5347c097a2ee202d9b049ff2b313afb5d1b3c0df8fb423902c7d8e9ad"
|
||||||
},
|
},
|
||||||
"menu.js": {
|
"menu.js": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"size": 30914,
|
"size": 30884,
|
||||||
"sha256": "3d008230b037806462b33529d3b6969e458031c55715cef34537a0d623cba518"
|
"sha256": "22e837db0373eed9f7d5beb4fdd1d985fb8dc3791ba1f3174b858de943830e39"
|
||||||
},
|
},
|
||||||
"pve": {
|
"pve": {
|
||||||
"type": "directory",
|
"type": "directory",
|
||||||
@@ -2933,40 +2928,35 @@
|
|||||||
},
|
},
|
||||||
"config.js": {
|
"config.js": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"size": 32634,
|
"size": 31361,
|
||||||
"sha256": "450bbc669efc2a5c2d157b197d23b52054a82f995e07c25a47c3046183b48ef2"
|
"sha256": "1bfd6a5bfecc2464f66d9ce87776ed6d4615519147e5006b322199a9cdcf5ac1"
|
||||||
},
|
},
|
||||||
"directDamage.js": {
|
"directDamage.js": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"size": 1295,
|
"size": 1190,
|
||||||
"sha256": "aced905fba4e2d23f88ddb76d09ea570c7c4ed1aa33a322d73c0fdb55012012e"
|
"sha256": "7eea5d094905eb84e611cf4dc3da2aebd83e326b908a6482ecde469acf17277c"
|
||||||
},
|
},
|
||||||
"extension.js": {
|
"extension.js": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"size": 93305,
|
"size": 87300,
|
||||||
"sha256": "37c684b6193e01424fb9492a6722aa7dee6d40b7bcf6b4b559ad4a6aca334944"
|
"sha256": "025c07a177e564b84b59c982b1f6cf5ecf208c750a9f16994b6af7c286c21e83"
|
||||||
},
|
},
|
||||||
"shuYing_Skill_Xvxiang1.mp3": {
|
"shuYing_Skill_Xvxiang1.mp3": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"size": 15451,
|
"size": 15451,
|
||||||
"sha256": "41914d7d542ddfb93c89aefffc245869d63a9fb2f52293df8e6667009832afd8"
|
"sha256": "41914d7d542ddfb93c89aefffc245869d63a9fb2f52293df8e6667009832afd8"
|
||||||
},
|
},
|
||||||
"skillCard.js": {
|
|
||||||
"type": "file",
|
|
||||||
"size": 2680,
|
|
||||||
"sha256": "ff92fbb7784a6ae2b701e6caa028fb29421b8b1679716752f33f070e334356d2"
|
|
||||||
},
|
|
||||||
"skillRecover.js": {
|
"skillRecover.js": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"size": 2675,
|
"size": 2570,
|
||||||
"sha256": "bd89818b8f535c19b51f107ca2c75dec669852e4a604ed55f6fa945ecec8e6d6"
|
"sha256": "a888d0b72988ff49406017234c56771631e8760e3a578d6d715d97b7bfdb5442"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"update.js": {
|
"update.js": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"size": 77454,
|
"size": 75926,
|
||||||
"sha256": "f2693e030c0008c788c3e1785e0d6b41dc1df1251624efc003ff0b51d4c2a9f0"
|
"sha256": "5b62cf2771f188e7fe5ed2c31095afd55494883117e50555530997a2d060c783"
|
||||||
},
|
},
|
||||||
"update.txt": {
|
"update.txt": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "2.0.2.3-rc.5",
|
"version": "2.0.2.3-rc.4",
|
||||||
"generated_at": "2026-10-14T10:45:26.006244+00:00",
|
"generated_at": "2026-10-13T10:12:31.028545+00:00",
|
||||||
"algorithm": "sha256",
|
"algorithm": "sha256",
|
||||||
"update_channels": true,
|
"update_channels": true,
|
||||||
"file_count": 764,
|
"file_count": 764,
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "2.0.2.3-rc.5",
|
"version": "2.0.2.3-rc.4",
|
||||||
"module_id": "mengsan",
|
"module_id": "mengsan",
|
||||||
"snapshot": "legacy",
|
"snapshot": "legacy",
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
+11
-1
@@ -6,7 +6,7 @@ import { configureDiagnostics } from "./diagnostics/index.js";
|
|||||||
|
|
||||||
export const type = "extension";
|
export const type = "extension";
|
||||||
export let shuYing = new Object();
|
export let shuYing = new Object();
|
||||||
const shuYingLocalVersion = "2.0.2.3-rc.5";
|
const shuYingLocalVersion = "2.0.2.3-rc.4";
|
||||||
|
|
||||||
shuYing.name = "术樱包";
|
shuYing.name = "术樱包";
|
||||||
shuYing.editable = false;
|
shuYing.editable = false;
|
||||||
@@ -291,6 +291,16 @@ shuYing.help = () => {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//本地资源修复
|
||||||
|
shuYing.RepairBug = () => {
|
||||||
|
updater.repairCoreFiles(shuYing);
|
||||||
|
};
|
||||||
|
|
||||||
|
//重新下载重要js文件
|
||||||
|
shuYing.RepairBugGo = () => {
|
||||||
|
updater.repairCoreFiles(shuYing);
|
||||||
|
};
|
||||||
|
|
||||||
shuYing.Diuse_downText = function () {
|
shuYing.Diuse_downText = function () {
|
||||||
time = setTimeout(() => {
|
time = setTimeout(() => {
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
|||||||
-14
@@ -1,6 +1,5 @@
|
|||||||
import { getDirectDamageSkillCount } from "./tianshu/directDamage.js";
|
import { getDirectDamageSkillCount } from "./tianshu/directDamage.js";
|
||||||
import { getSkillRecoverCount } from "./tianshu/skillRecover.js";
|
import { getSkillRecoverCount } from "./tianshu/skillRecover.js";
|
||||||
import { getSkillCardCount } from "./tianshu/skillCard.js";
|
|
||||||
|
|
||||||
export default function initFunction(lib, game, ui, get, ai, _status, shuYing = {}) {
|
export default function initFunction(lib, game, ui, get, ai, _status, shuYing = {}) {
|
||||||
game.shuying_getDiscardNamesNum = function () {
|
game.shuying_getDiscardNamesNum = function () {
|
||||||
@@ -398,10 +397,6 @@ export default function initFunction(lib, game, ui, get, ai, _status, shuYing =
|
|||||||
return getSkillRecoverCount(player, currentSkills, lib)
|
return getSkillRecoverCount(player, currentSkills, lib)
|
||||||
>= Math.max(1, Number(condition.count) || 1);
|
>= Math.max(1, Number(condition.count) || 1);
|
||||||
}
|
}
|
||||||
if (condition.type == "skillCard") {
|
|
||||||
return getSkillCardCount(player, currentSkills, lib)
|
|
||||||
>= Math.max(1, Number(condition.count) || 1);
|
|
||||||
}
|
|
||||||
if (condition.type == "skill") return currentSkills.includes(condition.skill);
|
if (condition.type == "skill") return currentSkills.includes(condition.skill);
|
||||||
if (condition.type == "skillName") return currentSkills.some(skill => lib.translate[skill] == condition.name);
|
if (condition.type == "skillName") return currentSkills.some(skill => lib.translate[skill] == condition.name);
|
||||||
if (condition.type == "skills") {
|
if (condition.type == "skills") {
|
||||||
@@ -450,9 +445,6 @@ export default function initFunction(lib, game, ui, get, ai, _status, shuYing =
|
|||||||
if (condition.type == "skillRecover") {
|
if (condition.type == "skillRecover") {
|
||||||
return getSkillRecoverCount(player, currentSkills, lib) > 0;
|
return getSkillRecoverCount(player, currentSkills, lib) > 0;
|
||||||
}
|
}
|
||||||
if (condition.type == "skillCard") {
|
|
||||||
return getSkillCardCount(player, currentSkills, lib) > 0;
|
|
||||||
}
|
|
||||||
if (condition.type == "skill") return currentSkills.includes(condition.skill);
|
if (condition.type == "skill") return currentSkills.includes(condition.skill);
|
||||||
if (condition.type == "skillName") return currentSkills.some(skill => lib.translate[skill] == condition.name);
|
if (condition.type == "skillName") return currentSkills.some(skill => lib.translate[skill] == condition.name);
|
||||||
if (condition.type == "skills") return [...(condition.all || []), ...(condition.any || [])].some(skill => currentSkills.includes(skill));
|
if (condition.type == "skills") return [...(condition.all || []), ...(condition.any || [])].some(skill => currentSkills.includes(skill));
|
||||||
@@ -490,12 +482,6 @@ export default function initFunction(lib, game, ui, get, ai, _status, shuYing =
|
|||||||
return `已实际回复体力的奖励技能 ${Math.min(count, need)}`
|
return `已实际回复体力的奖励技能 ${Math.min(count, need)}`
|
||||||
+ `/${need};首次有效技能回复后登记`;
|
+ `/${need};首次有效技能回复后登记`;
|
||||||
}
|
}
|
||||||
if (condition.type == "skillCard") {
|
|
||||||
const count = getSkillCardCount(player, currentSkills, lib);
|
|
||||||
const need = Math.max(1, Number(condition.count) || 1);
|
|
||||||
return `已实际视为或转化牌的奖励技能 ${Math.min(count, need)}`
|
|
||||||
+ `/${need};首次使用或打出后登记`;
|
|
||||||
}
|
|
||||||
if (condition.type == "skill") return `${currentSkills.includes(condition.skill) ? "已" : "未"}选择【${get.translation(condition.skill)}】`;
|
if (condition.type == "skill") return `${currentSkills.includes(condition.skill) ? "已" : "未"}选择【${get.translation(condition.skill)}】`;
|
||||||
if (condition.type == "skillName") return `${currentSkills.some(skill => lib.translate[skill] == condition.name) ? "已" : "未"}选择任意版本的【${condition.name}】`;
|
if (condition.type == "skillName") return `${currentSkills.some(skill => lib.translate[skill] == condition.name) ? "已" : "未"}选择任意版本的【${condition.name}】`;
|
||||||
if (condition.type == "skills") {
|
if (condition.type == "skills") {
|
||||||
|
|||||||
@@ -78,9 +78,6 @@ export default function initShuYingMenu({ lib, game, ui, shuYing, updater }) {
|
|||||||
if (condition.type == "skillRecover") {
|
if (condition.type == "skillRecover") {
|
||||||
return ["直接回复体力的过关技能"];
|
return ["直接回复体力的过关技能"];
|
||||||
}
|
}
|
||||||
if (condition.type == "skillCard") {
|
|
||||||
return ["视为打出牌或转化牌的过关技能"];
|
|
||||||
}
|
|
||||||
if (condition.type == "skill") return condition.skill ? [get.translation(condition.skill)] : [];
|
if (condition.type == "skill") return condition.skill ? [get.translation(condition.skill)] : [];
|
||||||
if (condition.type == "skillName") return condition.name ? [condition.name] : [];
|
if (condition.type == "skillName") return condition.name ? [condition.name] : [];
|
||||||
if (condition.type == "skills") {
|
if (condition.type == "skills") {
|
||||||
@@ -111,11 +108,6 @@ export default function initShuYingMenu({ lib, game, ui, shuYing, updater }) {
|
|||||||
+ "按当前仍持有的不同技能译名统计,新等级从后续回复生效;"
|
+ "按当前仍持有的不同技能译名统计,新等级从后续回复生效;"
|
||||||
+ "二级追加回复不会再次触发桃园,三级溢出只增加体力上限";
|
+ "二级追加回复不会再次触发桃园,三级溢出只增加体力上限";
|
||||||
}
|
}
|
||||||
if (condition.type == "skillCard") {
|
|
||||||
return "奖励技能首次实际使用或打出视为牌、转化牌后登记,子技能归到主技能;"
|
|
||||||
+ "按当前仍持有的不同技能译名统计,新等级从后续用牌生效;"
|
|
||||||
+ "响应打出只登记;目标调整至少保留1个,三级对全部指定目标再次结算";
|
|
||||||
}
|
|
||||||
if (!condition.type && [...(condition.all || []), ...(condition.any || [])].some(item => item?.type == "skillNames")) {
|
if (!condition.type && [...(condition.all || []), ...(condition.any || [])].some(item => item?.type == "skillNames")) {
|
||||||
return "按不同译名统计;同译名的不同技能 ID 只计 1 种过关技能";
|
return "按不同译名统计;同译名的不同技能 ID 只计 1 种过关技能";
|
||||||
}
|
}
|
||||||
@@ -480,12 +472,25 @@ export default function initShuYingMenu({ lib, game, ui, shuYing, updater }) {
|
|||||||
};
|
};
|
||||||
void shuYing.updateMengsanModuleMenu();
|
void shuYing.updateMengsanModuleMenu();
|
||||||
|
|
||||||
|
menu.repairBug = {
|
||||||
|
name: "本地资源修复",
|
||||||
|
clear: true,
|
||||||
|
onclick() {
|
||||||
|
if (confirm("点击确定会检测本地资源,并尝试修复。") && shuYing.m_bIsDownload) {
|
||||||
|
shuYing.m_bIsDownload = false;
|
||||||
|
shuYing.RepairBug();
|
||||||
|
} else if (!shuYing.m_bIsDownload) {
|
||||||
|
alert("有其他文件正在下载,请稍后再试吧。");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
menu.filling = {
|
menu.filling = {
|
||||||
name: "查漏补缺",
|
name: "查漏补缺 <--补齐丢失资源 建议更新后必点",
|
||||||
clear: true,
|
clear: true,
|
||||||
onclick() {
|
onclick() {
|
||||||
if (
|
if (
|
||||||
confirm("检查当前已安装版本的核心文件、图片和配音,修复缺失或损坏的文件。立绘为静态资源,动态立绘需手动下载。请注意流量使用,建议在 WiFi 下执行。") &&
|
confirm("点击确定会检测本地丢失资源,并开始修补;若是武将立绘则是静态,若需动态请手动下载(请注意流量使用情况!务必在WIFI状态下修补)") &&
|
||||||
shuYing.m_bIsDownload
|
shuYing.m_bIsDownload
|
||||||
) {
|
) {
|
||||||
shuYing.m_bIsDownload = false;
|
shuYing.m_bIsDownload = false;
|
||||||
|
|||||||
@@ -214,35 +214,6 @@ const tianshuConfig = {
|
|||||||
banned: ["huoxin", "jueqing", "qinqing", "beige", "huashen", "drlt_zhiti", "olzhiti", "xinfu_pdgyingshi", "rebeige"],
|
banned: ["huoxin", "jueqing", "qinqing", "beige", "huashen", "drlt_zhiti", "olzhiti", "xinfu_pdgyingshi", "rebeige"],
|
||||||
},
|
},
|
||||||
bonds: [
|
bonds: [
|
||||||
{
|
|
||||||
id: "yinpai",
|
|
||||||
name: "印牌",
|
|
||||||
condition: { type: "skillCard" },
|
|
||||||
levels: [
|
|
||||||
{
|
|
||||||
level: 1,
|
|
||||||
count: 1,
|
|
||||||
skills: ["shuYing_Tianshu_BondYinpai1"],
|
|
||||||
text: "你使用技能视为牌或转化牌时,可以增加或减少1个合法目标,"
|
|
||||||
+ "至少保留1个目标",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
level: 2,
|
|
||||||
count: 2,
|
|
||||||
skills: ["shuYing_Tianshu_BondYinpai2"],
|
|
||||||
text: "你使用技能视为牌或转化牌时,可以增加或减少1个合法目标,"
|
|
||||||
+ "至少保留1个目标,且此牌无法被响应",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
level: 3,
|
|
||||||
count: 3,
|
|
||||||
skills: ["shuYing_Tianshu_BondYinpai3"],
|
|
||||||
text: "你使用技能视为牌或转化牌时,可以增加或减少1个合法目标,"
|
|
||||||
+ "至少保留1个目标,且此牌无法被响应,"
|
|
||||||
+ "并对全部指定目标额外结算一次,不重新选择目标",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "taoyuan",
|
id: "taoyuan",
|
||||||
name: "桃园",
|
name: "桃园",
|
||||||
|
|||||||
@@ -7,9 +7,6 @@ export function getDirectDamageOrigin(event, lib, get) {
|
|||||||
const visited = new Set();
|
const visited = new Set();
|
||||||
while (current && !visited.has(current)) {
|
while (current && !visited.has(current)) {
|
||||||
visited.add(current);
|
visited.add(current);
|
||||||
if (["card", "precard", "postcard"].includes(current.type)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (["useCard", "respond", "damage", "_lianhuan", "_lianhuan2"]
|
if (["useCard", "respond", "damage", "_lianhuan", "_lianhuan2"]
|
||||||
.includes(current.name) || current.name?.endsWith("_cost")) {
|
.includes(current.name) || current.name?.endsWith("_cost")) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+6
-128
@@ -4,8 +4,6 @@ import { directDamageStorage, getDirectDamageOrigin,
|
|||||||
getDirectDamageSkillCount } from "./directDamage.js";
|
getDirectDamageSkillCount } from "./directDamage.js";
|
||||||
import { skillRecoverStorage, getSkillRecoverOrigin, getSkillRecoverCount,
|
import { skillRecoverStorage, getSkillRecoverOrigin, getSkillRecoverCount,
|
||||||
wrapSkillRecoverEvent } from "./skillRecover.js";
|
wrapSkillRecoverEvent } from "./skillRecover.js";
|
||||||
import { skillCardStorage, getSkillCardOrigin, getSkillCardCount,
|
|
||||||
getSkillCardTargetOptions, applySkillCardEffects } from "./skillCard.js";
|
|
||||||
import { lib, game, ui, get, ai, _status } from "../../../noname.js";
|
import { lib, game, ui, get, ai, _status } from "../../../noname.js";
|
||||||
|
|
||||||
export default function initTianshu(lib, game, ui, get, ai, _status, shuYing) {
|
export default function initTianshu(lib, game, ui, get, ai, _status, shuYing) {
|
||||||
@@ -758,10 +756,6 @@ export default function initTianshu(lib, game, ui, get, ai, _status, shuYing) {
|
|||||||
return getSkillRecoverCount(player, owned, lib)
|
return getSkillRecoverCount(player, owned, lib)
|
||||||
>= Math.max(1, Number(condition.count) || 1);
|
>= Math.max(1, Number(condition.count) || 1);
|
||||||
}
|
}
|
||||||
if (condition.type == "skillCard") {
|
|
||||||
return getSkillCardCount(player, owned, lib)
|
|
||||||
>= Math.max(1, Number(condition.count) || 1);
|
|
||||||
}
|
|
||||||
if (condition.type == "keyword") {
|
if (condition.type == "keyword") {
|
||||||
if (!condition.keyword) return false;
|
if (!condition.keyword) return false;
|
||||||
const marker = `【${condition.keyword}】`;
|
const marker = `【${condition.keyword}】`;
|
||||||
@@ -842,9 +836,6 @@ export default function initTianshu(lib, game, ui, get, ai, _status, shuYing) {
|
|||||||
if (condition.type == "skillRecover") {
|
if (condition.type == "skillRecover") {
|
||||||
return getSkillRecoverCount(player, [skill], lib) > 0;
|
return getSkillRecoverCount(player, [skill], lib) > 0;
|
||||||
}
|
}
|
||||||
if (condition.type == "skillCard") {
|
|
||||||
return getSkillCardCount(player, [skill], lib) > 0;
|
|
||||||
}
|
|
||||||
if (condition.type == "keyword") {
|
if (condition.type == "keyword") {
|
||||||
if (!condition.keyword) return false;
|
if (!condition.keyword) return false;
|
||||||
const info = typeof get.skillInfoTranslation == "function" ? get.skillInfoTranslation(skill, player) : lib.translate[`${skill}_info`];
|
const info = typeof get.skillInfoTranslation == "function" ? get.skillInfoTranslation(skill, player) : lib.translate[`${skill}_info`];
|
||||||
@@ -1373,7 +1364,6 @@ export default function initTianshu(lib, game, ui, get, ai, _status, shuYing) {
|
|||||||
game.addGlobalSkill("shuYing_Tianshu_DirectDamageCapture");
|
game.addGlobalSkill("shuYing_Tianshu_DirectDamageCapture");
|
||||||
game.addGlobalSkill("shuYing_Tianshu_DirectDamageSettle");
|
game.addGlobalSkill("shuYing_Tianshu_DirectDamageSettle");
|
||||||
game.addGlobalSkill("shuYing_Tianshu_SkillRecoverCapture");
|
game.addGlobalSkill("shuYing_Tianshu_SkillRecoverCapture");
|
||||||
game.addGlobalSkill("shuYing_Tianshu_SkillCardCapture");
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
shuYing_Tianshu_DefendingControl: {
|
shuYing_Tianshu_DefendingControl: {
|
||||||
@@ -1412,15 +1402,9 @@ export default function initTianshu(lib, game, ui, get, ai, _status, shuYing) {
|
|||||||
game.getGlobalHistory().isRound = true;
|
game.getGlobalHistory().isRound = true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
shuYing_Tianshu_BondDirectDamage1: {
|
shuYing_Tianshu_BondDirectDamage1: { charlotte: true, popup: false },
|
||||||
charlotte: true, popup: false, nopop: true,
|
shuYing_Tianshu_BondDirectDamage2: { charlotte: true, popup: false },
|
||||||
},
|
shuYing_Tianshu_BondDirectDamage3: { charlotte: true, popup: false },
|
||||||
shuYing_Tianshu_BondDirectDamage2: {
|
|
||||||
charlotte: true, popup: false, nopop: true,
|
|
||||||
},
|
|
||||||
shuYing_Tianshu_BondDirectDamage3: {
|
|
||||||
charlotte: true, popup: false, nopop: true,
|
|
||||||
},
|
|
||||||
shuYing_Tianshu_DirectDamageCapture: {
|
shuYing_Tianshu_DirectDamageCapture: {
|
||||||
mode: ["boss"],
|
mode: ["boss"],
|
||||||
trigger: { global: "damageBegin1" },
|
trigger: { global: "damageBegin1" },
|
||||||
@@ -1499,15 +1483,9 @@ export default function initTianshu(lib, game, ui, get, ai, _status, shuYing) {
|
|||||||
if (level >= 2 && player.isIn()) await player.draw(num);
|
if (level >= 2 && player.isIn()) await player.draw(num);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
shuYing_Tianshu_BondTaoyuan1: {
|
shuYing_Tianshu_BondTaoyuan1: { charlotte: true, popup: false },
|
||||||
charlotte: true, popup: false, nopop: true,
|
shuYing_Tianshu_BondTaoyuan2: { charlotte: true, popup: false },
|
||||||
},
|
shuYing_Tianshu_BondTaoyuan3: { charlotte: true, popup: false },
|
||||||
shuYing_Tianshu_BondTaoyuan2: {
|
|
||||||
charlotte: true, popup: false, nopop: true,
|
|
||||||
},
|
|
||||||
shuYing_Tianshu_BondTaoyuan3: {
|
|
||||||
charlotte: true, popup: false, nopop: true,
|
|
||||||
},
|
|
||||||
shuYing_Tianshu_SkillRecoverCapture: {
|
shuYing_Tianshu_SkillRecoverCapture: {
|
||||||
mode: ["boss"],
|
mode: ["boss"],
|
||||||
trigger: { global: "recoverBegin" },
|
trigger: { global: "recoverBegin" },
|
||||||
@@ -1531,95 +1509,6 @@ export default function initTianshu(lib, game, ui, get, ai, _status, shuYing) {
|
|||||||
if (record.level >= 1) trigger.num++;
|
if (record.level >= 1) trigger.num++;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
shuYing_Tianshu_BondYinpai1: {
|
|
||||||
charlotte: true, popup: false, nopop: true,
|
|
||||||
},
|
|
||||||
shuYing_Tianshu_BondYinpai2: {
|
|
||||||
charlotte: true, popup: false, nopop: true,
|
|
||||||
},
|
|
||||||
shuYing_Tianshu_BondYinpai3: {
|
|
||||||
charlotte: true, popup: false, nopop: true,
|
|
||||||
},
|
|
||||||
shuYing_Tianshu_SkillCardCapture: {
|
|
||||||
mode: ["boss"],
|
|
||||||
trigger: { global: ["useCard2", "respond"] },
|
|
||||||
forced: true,
|
|
||||||
silent: true,
|
|
||||||
charlotte: true,
|
|
||||||
firstDo: true,
|
|
||||||
priority: 1000,
|
|
||||||
filter(event) {
|
|
||||||
const player = event.player;
|
|
||||||
if (!state.running || event.shuYing_tianshu_yinpaiHandled
|
|
||||||
|| !player?.isIn() || !isCapturedPlayerSide(player)
|
|
||||||
|| (isVirtualIdol(player)
|
|
||||||
&& !canVirtualIdolReceiveRewards())) return false;
|
|
||||||
return Boolean(getSkillCardOrigin(event, lib, get));
|
|
||||||
},
|
|
||||||
async content(event, trigger) {
|
|
||||||
if (trigger.shuYing_tianshu_yinpaiHandled) return;
|
|
||||||
const origin = getSkillCardOrigin(trigger, lib, get);
|
|
||||||
if (!origin) return;
|
|
||||||
trigger.shuYing_tianshu_yinpaiHandled = true;
|
|
||||||
const player = trigger.player;
|
|
||||||
const level = player.storage.shuYing_tianshu_bondLevels
|
|
||||||
?.yinpai || 0;
|
|
||||||
const rewardSkill = getTianshuRewardSkills(player)
|
|
||||||
.find(current => get.sourceSkillFor(current)
|
|
||||||
== origin.skill);
|
|
||||||
if (rewardSkill) {
|
|
||||||
const recorded = player.storage[skillCardStorage] || [];
|
|
||||||
if (!recorded.includes(rewardSkill)) {
|
|
||||||
recorded.push(rewardSkill);
|
|
||||||
player.storage[skillCardStorage] = recorded;
|
|
||||||
game.broadcast((current, key, value) => {
|
|
||||||
current.storage[key] = value;
|
|
||||||
}, player, skillCardStorage, recorded);
|
|
||||||
player.syncStorage?.(skillCardStorage);
|
|
||||||
refreshTianshuBonds(player);
|
|
||||||
game.log(player, "登记印牌技能",
|
|
||||||
`【${get.translation(rewardSkill)}】`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!level || trigger.name != "useCard") return;
|
|
||||||
const options = getSkillCardTargetOptions(
|
|
||||||
trigger, lib, game, get);
|
|
||||||
const candidates = options.add.concat(options.remove);
|
|
||||||
if (candidates.length) {
|
|
||||||
const result = await player.chooseTarget(
|
|
||||||
"印牌:增加或减少1个合法目标(至少保留1个)",
|
|
||||||
(card, current, target) => target.isIn()
|
|
||||||
&& candidates.includes(target))
|
|
||||||
.set("ai", target => {
|
|
||||||
const effect = get.effect(target, trigger.card,
|
|
||||||
player, player);
|
|
||||||
return options.remove.includes(target)
|
|
||||||
? -effect : effect;
|
|
||||||
}).forResult();
|
|
||||||
const target = result.targets?.[0];
|
|
||||||
if (result.bool && target?.isIn()) {
|
|
||||||
const valid = getSkillCardTargetOptions(
|
|
||||||
trigger, lib, game, get);
|
|
||||||
if (options.remove.includes(target)
|
|
||||||
&& valid.remove.includes(target)) {
|
|
||||||
trigger.targets.splice(
|
|
||||||
trigger.targets.indexOf(target), 1);
|
|
||||||
game.log(player, "移除", trigger.card,
|
|
||||||
"的目标", target);
|
|
||||||
} else if (options.add.includes(target)
|
|
||||||
&& valid.add.includes(target)) {
|
|
||||||
trigger.targets.push(target);
|
|
||||||
game.log(player, "为", trigger.card,
|
|
||||||
"增加目标", target);
|
|
||||||
}
|
|
||||||
player.line(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
applySkillCardEffects(trigger, level, game.players);
|
|
||||||
if (level >= 3) game.log(trigger.card,
|
|
||||||
"对全部指定目标额外结算一次");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
shuYing_Tianshu_BondManager: {
|
shuYing_Tianshu_BondManager: {
|
||||||
mode: ["boss"],
|
mode: ["boss"],
|
||||||
trigger: { global: "changeSkillsAfter" },
|
trigger: { global: "changeSkillsAfter" },
|
||||||
@@ -1720,17 +1609,6 @@ export default function initTianshu(lib, game, ui, get, ai, _status, shuYing) {
|
|||||||
shuYing_Skill_Tianshu_intro5: { nobracket: true },
|
shuYing_Skill_Tianshu_intro5: { nobracket: true },
|
||||||
};
|
};
|
||||||
tianshu.translate = {
|
tianshu.translate = {
|
||||||
shuYing_Tianshu_BondYinpai1: "印牌·壹",
|
|
||||||
shuYing_Tianshu_BondYinpai1_info:
|
|
||||||
"你使用技能视为牌或转化牌时,可以增加或减少1个合法目标,至少保留1个目标。",
|
|
||||||
shuYing_Tianshu_BondYinpai2: "印牌·贰",
|
|
||||||
shuYing_Tianshu_BondYinpai2_info:
|
|
||||||
"你使用技能视为牌或转化牌时,可以增加或减少1个合法目标,"
|
|
||||||
+ "至少保留1个目标,且此牌无法被响应。",
|
|
||||||
shuYing_Tianshu_BondYinpai3: "印牌·叁",
|
|
||||||
shuYing_Tianshu_BondYinpai3_info:
|
|
||||||
"你使用技能视为牌或转化牌时,可以增加或减少1个合法目标,"
|
|
||||||
+ "至少保留1个目标,且此牌无法被响应,并对全部指定目标额外结算一次。",
|
|
||||||
shuYing_Tianshu_BondTaoyuan1: "桃园·壹",
|
shuYing_Tianshu_BondTaoyuan1: "桃园·壹",
|
||||||
shuYing_Tianshu_BondTaoyuan1_info: "你通过技能回复体力时,回复值+1。",
|
shuYing_Tianshu_BondTaoyuan1_info: "你通过技能回复体力时,回复值+1。",
|
||||||
shuYing_Tianshu_BondTaoyuan2: "桃园·贰",
|
shuYing_Tianshu_BondTaoyuan2: "桃园·贰",
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
export const skillCardStorage = "shuYing_tianshu_skillCardSkills";
|
|
||||||
|
|
||||||
export function getSkillCardOrigin(event, lib, get) {
|
|
||||||
if (!["useCard", "respond"].includes(event?.name) || !event.card) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const virtual = get.is.virtualCard(event.card)
|
|
||||||
&& (!event.card.isCard || !event.cards?.length);
|
|
||||||
if (!virtual && !get.is.convertedCard(event.card)) return null;
|
|
||||||
if (event.skill && lib.skill[event.skill]) {
|
|
||||||
return { skill: get.sourceSkillFor(event.skill), player: event.player };
|
|
||||||
}
|
|
||||||
let current = event.getParent?.(1, true);
|
|
||||||
const visited = new Set();
|
|
||||||
while (current && !visited.has(current)) {
|
|
||||||
visited.add(current);
|
|
||||||
if (["useCard", "respond"].includes(current.name)
|
|
||||||
|| ["card", "precard", "postcard"].includes(current.type)
|
|
||||||
|| current.name?.endsWith("_cost")) return null;
|
|
||||||
const skill = lib.skill[current.name] ? current.name : current.skill;
|
|
||||||
if (skill && lib.skill[skill]) {
|
|
||||||
if (current.player != event.player) return null;
|
|
||||||
return { skill: get.sourceSkillFor(skill), player: current.player };
|
|
||||||
}
|
|
||||||
current = current.getParent?.(1, true);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getSkillCardCount(player, skills, lib) {
|
|
||||||
const recorded = player?.storage?.[skillCardStorage];
|
|
||||||
if (!Array.isArray(recorded)) return 0;
|
|
||||||
return new Set(skills.filter(skill => recorded.includes(skill))
|
|
||||||
.map(skill => lib.translate[skill] || skill)).size;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getSkillCardTargetOptions(event, lib, game, get) {
|
|
||||||
const options = { add: [], remove: [] };
|
|
||||||
const info = get.info(event.card);
|
|
||||||
if (!info || !event.targets?.length || info.notarget || info.toself
|
|
||||||
|| info.complexTarget || info.singleCard
|
|
||||||
|| info.filterAddedTarget) return options;
|
|
||||||
if (event.targets.length > 1) {
|
|
||||||
options.remove = event.targets.filter(target => target.isIn());
|
|
||||||
}
|
|
||||||
if (info.allowMultiple !== false) {
|
|
||||||
options.add = game.players.filter(target => target.isIn()
|
|
||||||
&& !event.targets.includes(target)
|
|
||||||
&& lib.filter.targetEnabled2(event.card, event.player, target)
|
|
||||||
&& lib.filter.targetInRange(event.card, event.player, target));
|
|
||||||
}
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function applySkillCardEffects(event, level, players) {
|
|
||||||
if (level >= 2) {
|
|
||||||
if (!Array.isArray(event.directHit)) event.directHit = [];
|
|
||||||
for (const player of players) {
|
|
||||||
if (!event.directHit.includes(player)) event.directHit.push(player);
|
|
||||||
}
|
|
||||||
event.nowuxie = true;
|
|
||||||
}
|
|
||||||
if (level >= 3) event.effectCount = (Number(event.effectCount) || 1) + 1;
|
|
||||||
}
|
|
||||||
@@ -8,9 +8,6 @@ export function getSkillRecoverOrigin(event, lib, get) {
|
|||||||
const visited = new Set();
|
const visited = new Set();
|
||||||
while (current && !visited.has(current)) {
|
while (current && !visited.has(current)) {
|
||||||
visited.add(current);
|
visited.add(current);
|
||||||
if (["card", "precard", "postcard"].includes(current.type)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (["useCard", "respond", "recover", "damage"]
|
if (["useCard", "respond", "recover", "damage"]
|
||||||
.includes(current.name) || current.name?.endsWith("_cost")) {
|
.includes(current.name) || current.name?.endsWith("_cost")) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"tianshu/config.js",
|
"tianshu/config.js",
|
||||||
"tianshu/directDamage.js",
|
"tianshu/directDamage.js",
|
||||||
"tianshu/skillRecover.js",
|
"tianshu/skillRecover.js",
|
||||||
"tianshu/skillCard.js",
|
|
||||||
"pve/boss/index.js",
|
"pve/boss/index.js",
|
||||||
"pve/boss/card.js",
|
"pve/boss/card.js",
|
||||||
"pve/boss/character.js",
|
"pve/boss/character.js",
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ const githubRawBase = "https://raw.githubusercontent.com/Shu-Ying/noname-shuying
|
|||||||
const coreTempDir = "extension/术樱包/.update_tmp";
|
const coreTempDir = "extension/术樱包/.update_tmp";
|
||||||
let fileMutationUncertain = false;
|
let fileMutationUncertain = false;
|
||||||
const verifiedCacheKey = "shuYing_update_verified_files";
|
const verifiedCacheKey = "shuYing_update_verified_files";
|
||||||
const installedManifestKey = "shuYing_update_installation";
|
|
||||||
let verifiedFiles = new Map();
|
let verifiedFiles = new Map();
|
||||||
let sessionVerified = new Set();
|
let sessionVerified = new Set();
|
||||||
let verificationContext = null;
|
let verificationContext = null;
|
||||||
@@ -1013,6 +1012,13 @@ async function removeManifestOldPaths(shuYing, manifest) {
|
|||||||
await removeManifestDirectories(shuYing, manifest);
|
await removeManifestDirectories(shuYing, manifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function downloadCoreFiles(shuYing, manifest) {
|
||||||
|
manifest = manifest || await getManifest();
|
||||||
|
const files = getManifestCoreFiles(manifest);
|
||||||
|
if (!files.length) throw new Error("校验清单缺少 core 核心文件列表");
|
||||||
|
await updateAllFiles(shuYing, manifest, files);
|
||||||
|
}
|
||||||
|
|
||||||
async function getChangedFiles(manifest, shuYing) {
|
async function getChangedFiles(manifest, shuYing) {
|
||||||
if (typeof game.readFile != "function") throw new Error("当前环境不支持校验本地文件");
|
if (typeof game.readFile != "function") throw new Error("当前环境不支持校验本地文件");
|
||||||
const files = getManifestFileKeys(manifest);
|
const files = getManifestFileKeys(manifest);
|
||||||
@@ -1033,49 +1039,6 @@ async function getChangedFiles(manifest, shuYing) {
|
|||||||
return results.filter(Boolean);
|
return results.filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
function installationManifest(manifest) {
|
|
||||||
const { version, algorithm, core, assets, files, modules, module_id,
|
|
||||||
tag_name, source } = manifest;
|
|
||||||
return { version, algorithm, core, assets, files, modules, module_id,
|
|
||||||
tag_name, source, remove: [], removeDirectories: [] };
|
|
||||||
}
|
|
||||||
|
|
||||||
function installedBaseline(record, version, moduleId = "") {
|
|
||||||
if (record?.status != "installed" || !record.manifest
|
|
||||||
|| record.manifest.version != version) return null;
|
|
||||||
try {
|
|
||||||
return validateManifest(record.manifest, version, moduleId);
|
|
||||||
}
|
|
||||||
catch { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getUpdateFiles(manifest, baseline, shuYing) {
|
|
||||||
if (!baseline) {
|
|
||||||
await addLog(shuYing, "没有可信安装清单,执行一次完整检查");
|
|
||||||
return getChangedFiles(manifest, shuYing);
|
|
||||||
}
|
|
||||||
const changed = getManifestFileKeys(manifest).filter(file => {
|
|
||||||
const previous = baseline.files[file];
|
|
||||||
return !previous || previous.sha256 != manifest.files[file].sha256
|
|
||||||
|| previous.size != manifest.files[file].size;
|
|
||||||
});
|
|
||||||
const core = getManifestCoreFiles(manifest);
|
|
||||||
const invalidCore = await getChangedFiles({ ...manifest,
|
|
||||||
files: Object.fromEntries(core.map(file => [file, manifest.files[file]])),
|
|
||||||
}, shuYing);
|
|
||||||
await addLog(shuYing, `清单差异:${changed.length} 个文件;未变化资源不检查`);
|
|
||||||
return uniqueManifestList([...changed, ...invalidCore]);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function saveMainInstallation(manifest) {
|
|
||||||
await saveUpdaterConfig({
|
|
||||||
[installedManifestKey]: { schema: 1, status: "installed",
|
|
||||||
manifest: installationManifest(manifest) },
|
|
||||||
shuYing_local_version: manifest.version,
|
|
||||||
shuYing_online_version: manifest.version,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeLegacyModuleManifest(manifest, moduleId) {
|
function makeLegacyModuleManifest(manifest, moduleId) {
|
||||||
const prefix = `${moduleId}/`;
|
const prefix = `${moduleId}/`;
|
||||||
const files = Object.fromEntries(Object.entries(manifest.files || {})
|
const files = Object.fromEntries(Object.entries(manifest.files || {})
|
||||||
@@ -1128,7 +1091,6 @@ async function getLegacyModuleManifest(moduleId, rootManifest) {
|
|||||||
|
|
||||||
const mengsanRecordKey = "shuYing_mengsan_installation";
|
const mengsanRecordKey = "shuYing_mengsan_installation";
|
||||||
const mengsanVersionKey = "shuYing_mengsan_installed_version";
|
const mengsanVersionKey = "shuYing_mengsan_installed_version";
|
||||||
const mengsanPendingUpdateKey = "shuYing_mengsan_update_pending";
|
|
||||||
|
|
||||||
function getMengsanRecord() {
|
function getMengsanRecord() {
|
||||||
const record = lib.config[mengsanRecordKey];
|
const record = lib.config[mengsanRecordKey];
|
||||||
@@ -1145,11 +1107,7 @@ function getMengsanRecord() {
|
|||||||
|
|
||||||
async function saveMengsanRecord(record) {
|
async function saveMengsanRecord(record) {
|
||||||
const version = record.status == "disabled" ? "disabled" : record.version || "legacy";
|
const version = record.status == "disabled" ? "disabled" : record.version || "legacy";
|
||||||
const values = { [mengsanRecordKey]: record, [mengsanVersionKey]: version };
|
await saveUpdaterConfig({ [mengsanRecordKey]: record, [mengsanVersionKey]: version });
|
||||||
if (["installed", "disabled"].includes(record.status)) {
|
|
||||||
values[mengsanPendingUpdateKey] = null;
|
|
||||||
}
|
|
||||||
await saveUpdaterConfig(values);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getMengsanModuleStatus() {
|
async function getMengsanModuleStatus() {
|
||||||
@@ -1250,8 +1208,7 @@ async function getPreviousMengsanManifest(rootManifest = null) {
|
|||||||
return previous;
|
return previous;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function installMengsanFiles(shuYing, manifest, files, previousManifest = null,
|
async function installMengsanFiles(shuYing, manifest, files, previousManifest = null) {
|
||||||
verifyAll = true) {
|
|
||||||
assertMutationReady();
|
assertMutationReady();
|
||||||
const previousRecord = getMengsanRecord();
|
const previousRecord = getMengsanRecord();
|
||||||
const currentFiles = getManifestFileKeys(manifest);
|
const currentFiles = getManifestFileKeys(manifest);
|
||||||
@@ -1267,14 +1224,10 @@ async function installMengsanFiles(shuYing, manifest, files, previousManifest =
|
|||||||
try {
|
try {
|
||||||
await updateAllFiles(shuYing, manifest, files, operationRoot);
|
await updateAllFiles(shuYing, manifest, files, operationRoot);
|
||||||
filesApplied = true;
|
filesApplied = true;
|
||||||
const verification = verifyAll ? manifest : { ...manifest,
|
const invalid = await getChangedFiles(manifest, shuYing);
|
||||||
files: Object.fromEntries(files.map(file => [file, manifest.files[file]])),
|
|
||||||
};
|
|
||||||
const invalid = await getChangedFiles(verification, shuYing);
|
|
||||||
if (invalid.length) throw new Error(`梦三模块校验失败:${invalid.slice(0, 5).join("、")}`);
|
if (invalid.length) throw new Error(`梦三模块校验失败:${invalid.slice(0, 5).join("、")}`);
|
||||||
await saveMengsanRecord({ status: "installed", version: manifest.version,
|
await saveMengsanRecord({ status: "installed", version: manifest.version,
|
||||||
source: manifest.source, files: currentFiles,
|
source: manifest.source, files: currentFiles });
|
||||||
manifest: installationManifest(manifest) });
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
let recovery = { ...pending, status: "repair", recoveryDirectory: error.recoveryDirectory || null };
|
let recovery = { ...pending, status: "repair", recoveryDirectory: error.recoveryDirectory || null };
|
||||||
@@ -1499,38 +1452,12 @@ async function checkVersion(shuYing, options = {}) {
|
|||||||
const onlineVersion = await getOnlineVersion(options.channel, options.source);
|
const onlineVersion = await getOnlineVersion(options.channel, options.source);
|
||||||
const localVersion = lib.config.shuYing_local_version || "0.0.0.0";
|
const localVersion = lib.config.shuYing_local_version || "0.0.0.0";
|
||||||
const manifest = onlineVersion.manifest;
|
const manifest = onlineVersion.manifest;
|
||||||
const installation = lib.config[installedManifestKey];
|
|
||||||
const moduleRecord = getMengsanRecord();
|
|
||||||
const modulePending = !!lib.config[mengsanPendingUpdateKey]
|
|
||||||
|| (moduleRecord && ["installing", "repair"].includes(moduleRecord.status));
|
|
||||||
const moduleVersion = moduleRecord?.version || lib.config[mengsanVersionKey];
|
|
||||||
const moduleEnabled = !["disabled", "uninstalling"].includes(moduleRecord?.status)
|
|
||||||
&& moduleVersion != "disabled";
|
|
||||||
const moduleNeedsUpdate = manifest.modules?.mengsan && moduleEnabled
|
|
||||||
&& (modulePending || (parseVersion(moduleVersion || "")
|
|
||||||
&& moduleVersion != manifest.version));
|
|
||||||
if (!options.switchChannel && parseVersion(localVersion)
|
if (!options.switchChannel && parseVersion(localVersion)
|
||||||
&& compareVersions(onlineVersion.online_version, localVersion) < 0) {
|
&& compareVersions(onlineVersion.online_version, localVersion) < 0) {
|
||||||
throw new Error("目标更新源的版本落后于本地版本,请稍后重试");
|
throw new Error("目标更新源的版本落后于本地版本,请稍后重试");
|
||||||
}
|
}
|
||||||
if (localVersion == manifest.version
|
let previousManifest = null;
|
||||||
&& installation?.status != "updating"
|
if (parseVersion(localVersion) && localVersion != manifest.version) {
|
||||||
&& !moduleNeedsUpdate) {
|
|
||||||
game.saveConfig("shuYing_online_version", manifest.version);
|
|
||||||
await addLog(shuYing, "版本一致,跳过本地资源检查;资源异常请使用查漏补缺");
|
|
||||||
alert("本地版本为最新版");
|
|
||||||
return manifest.version;
|
|
||||||
}
|
|
||||||
const message = localVersion == manifest.version
|
|
||||||
? "有未完成的更新,是否继续同步版本?"
|
|
||||||
: `检测到最新版本为:${manifest.version}, 本地版本为:${localVersion},是否更新?`;
|
|
||||||
if (!options.switchChannel && !confirm(message)) return null;
|
|
||||||
|
|
||||||
const baseline = installation?.schema == 1
|
|
||||||
? installedBaseline(installation, localVersion) : null;
|
|
||||||
let previousManifest = baseline;
|
|
||||||
if (!previousManifest && parseVersion(localVersion)
|
|
||||||
&& localVersion != manifest.version) {
|
|
||||||
previousManifest = await getManifestFromTag({
|
previousManifest = await getManifestFromTag({
|
||||||
name: `v${localVersion}`, version: localVersion,
|
name: `v${localVersion}`, version: localVersion,
|
||||||
}, false, manifest.source).catch(error => {
|
}, false, manifest.source).catch(error => {
|
||||||
@@ -1542,9 +1469,6 @@ async function checkVersion(shuYing, options = {}) {
|
|||||||
const installedMengsan = await isMengsanInstalled(
|
const installedMengsan = await isMengsanInstalled(
|
||||||
localVersion, previousManifest, manifest
|
localVersion, previousManifest, manifest
|
||||||
);
|
);
|
||||||
if (installedMengsan && manifest.modules?.mengsan) {
|
|
||||||
await saveUpdaterConfig({ [mengsanPendingUpdateKey]: manifest.version });
|
|
||||||
}
|
|
||||||
if (previousManifest) {
|
if (previousManifest) {
|
||||||
const retainedModuleFiles = manifest.modules?.mengsan
|
const retainedModuleFiles = manifest.modules?.mengsan
|
||||||
? getManifestFileKeys(previousManifest)
|
? getManifestFileKeys(previousManifest)
|
||||||
@@ -1557,11 +1481,8 @@ async function checkVersion(shuYing, options = {}) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateMain = localVersion != manifest.version
|
const changed = await getChangedFiles(manifest, shuYing);
|
||||||
|| installation?.status == "updating";
|
const obsolete = await getObsoleteFiles(manifest);
|
||||||
const changed = updateMain
|
|
||||||
? await getUpdateFiles(manifest, baseline, shuYing) : [];
|
|
||||||
const obsolete = updateMain ? await getObsoleteFiles(manifest) : [];
|
|
||||||
let mengsanManifest = null;
|
let mengsanManifest = null;
|
||||||
let mengsanChanged = [];
|
let mengsanChanged = [];
|
||||||
let mengsanObsolete = [];
|
let mengsanObsolete = [];
|
||||||
@@ -1579,12 +1500,7 @@ async function checkVersion(shuYing, options = {}) {
|
|||||||
getManifestFileKeys(previousMengsan)
|
getManifestFileKeys(previousMengsan)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const moduleBaseline = installedBaseline(
|
mengsanChanged = await getChangedFiles(mengsanManifest, shuYing);
|
||||||
moduleRecord, moduleRecord?.version, "mengsan"
|
|
||||||
);
|
|
||||||
mengsanChanged = await getUpdateFiles(
|
|
||||||
mengsanManifest, moduleBaseline, shuYing
|
|
||||||
);
|
|
||||||
mengsanObsolete = await getObsoleteFiles(mengsanManifest);
|
mengsanObsolete = await getObsoleteFiles(mengsanManifest);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
@@ -1596,23 +1512,35 @@ async function checkVersion(shuYing, options = {}) {
|
|||||||
const allObsoleteCount = obsolete.length + mengsanObsolete.length;
|
const allObsoleteCount = obsolete.length + mengsanObsolete.length;
|
||||||
await addLog(shuYing, `更新源:${manifest.source};标签:${manifest.tag_name};待更新文件:${allChangedCount};待删除文件:${allObsoleteCount}`);
|
await addLog(shuYing, `更新源:${manifest.source};标签:${manifest.tag_name};待更新文件:${allChangedCount};待删除文件:${allObsoleteCount}`);
|
||||||
|
|
||||||
if (updateMain) {
|
if (localVersion == onlineVersion.online_version
|
||||||
await saveUpdaterConfig({ [installedManifestKey]: {
|
&& !allChangedCount && !allObsoleteCount && !mengsanUpdateError) {
|
||||||
schema: 1, status: "updating", manifest: baseline,
|
if (mengsanManifest && getMengsanRecord()?.status != "installed") {
|
||||||
} });
|
await installMengsanFiles(shuYing, mengsanManifest, [], previousMengsan);
|
||||||
await updateAllFiles(shuYing, manifest, changed);
|
}
|
||||||
await saveMainInstallation(manifest);
|
game.saveConfig("shuYing_online_version", onlineVersion.online_version);
|
||||||
|
alert("本地版本为最新版");
|
||||||
|
return onlineVersion.online_version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const message = localVersion == onlineVersion.online_version
|
||||||
|
? `当前版本有 ${allChangedCount} 个文件需修复、${allObsoleteCount} 个旧文件需删除,是否继续?`
|
||||||
|
: `检测到最新版本为:${onlineVersion.online_version}, 本地版本为:${localVersion},是否更新?`;
|
||||||
|
if (!options.switchChannel && !confirm(message)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
await updateAllFiles(shuYing, manifest, changed);
|
||||||
if (mengsanManifest && !mengsanUpdateError) {
|
if (mengsanManifest && !mengsanUpdateError) {
|
||||||
try {
|
try {
|
||||||
await installMengsanFiles(shuYing, mengsanManifest,
|
await installMengsanFiles(shuYing, mengsanManifest, mengsanChanged, previousMengsan);
|
||||||
mengsanChanged, previousMengsan, false);
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
mengsanUpdateError = error;
|
mengsanUpdateError = error;
|
||||||
await addLog(shuYing, `梦三模块更新失败:${getErrorMessage(error)}`);
|
await addLog(shuYing, `梦三模块更新失败:${getErrorMessage(error)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
game.saveConfig("shuYing_local_version", onlineVersion.online_version);
|
||||||
|
game.saveConfig("shuYing_online_version", onlineVersion.online_version);
|
||||||
await addLog(shuYing, "版本更新完成");
|
await addLog(shuYing, "版本更新完成");
|
||||||
alert(mengsanUpdateError
|
alert(mengsanUpdateError
|
||||||
? "主包更新完成;梦三模块未完成更新,可稍后重试。"
|
? "主包更新完成;梦三模块未完成更新,可稍后重试。"
|
||||||
@@ -1647,25 +1575,35 @@ async function repairMissingFiles(shuYing) {
|
|||||||
await addLog(shuYing, "查漏补缺开始");
|
await addLog(shuYing, "查漏补缺开始");
|
||||||
ensureProgressNode(shuYing);
|
ensureProgressNode(shuYing);
|
||||||
setProgress(shuYing, { title: "查漏补缺", status: "获取校验清单", current: 0, total: 1 });
|
setProgress(shuYing, { title: "查漏补缺", status: "获取校验清单", current: 0, total: 1 });
|
||||||
const localVersion = lib.config.shuYing_local_version || "0.0.0.0";
|
const manifest = await getManifest();
|
||||||
if (!parseVersion(localVersion)) {
|
|
||||||
throw new Error("无法确认本地版本,请先执行版本检测完成安装");
|
|
||||||
}
|
|
||||||
const manifest = await getManifestFromTag({
|
|
||||||
name: `v${localVersion}`, version: localVersion,
|
|
||||||
}, false);
|
|
||||||
const files = getManifestDownloadFiles(manifest);
|
const files = getManifestDownloadFiles(manifest);
|
||||||
|
const localVersion = lib.config.shuYing_local_version || "0.0.0.0";
|
||||||
|
let previousManifest = null;
|
||||||
|
if (parseVersion(localVersion) && localVersion != manifest.version) {
|
||||||
|
previousManifest = await getManifestFromTag({
|
||||||
|
name: `v${localVersion}`, version: localVersion,
|
||||||
|
}, false, manifest.source).catch(() => null);
|
||||||
|
if (previousManifest) {
|
||||||
|
const retainedModuleFiles = manifest.modules?.mengsan
|
||||||
|
? getManifestFileKeys(previousManifest)
|
||||||
|
.filter(file => file.startsWith("mengsan/"))
|
||||||
|
: [];
|
||||||
|
mergeRemovedFiles(
|
||||||
|
manifest,
|
||||||
|
getManifestFileKeys(previousManifest),
|
||||||
|
retainedModuleFiles
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
const installedMengsan = await isMengsanInstalled(
|
const installedMengsan = await isMengsanInstalled(
|
||||||
localVersion, null, manifest
|
localVersion, previousManifest, manifest
|
||||||
);
|
);
|
||||||
let mengsanManifest = null;
|
let mengsanManifest = null;
|
||||||
let previousMengsan = null;
|
let previousMengsan = null;
|
||||||
if (installedMengsan) {
|
if (installedMengsan && manifest.modules?.mengsan) {
|
||||||
const record = getMengsanRecord();
|
mengsanManifest = await getModuleManifest({
|
||||||
const moduleVersion = record?.version || lib.config[mengsanVersionKey];
|
name: manifest.tag_name, version: manifest.version,
|
||||||
mengsanManifest = await getInstalledModuleManifest("mengsan",
|
}, manifest, "mengsan");
|
||||||
parseVersion(moduleVersion || "") ? moduleVersion : localVersion,
|
|
||||||
manifest.source);
|
|
||||||
previousMengsan = await getPreviousMengsanManifest(manifest);
|
previousMengsan = await getPreviousMengsanManifest(manifest);
|
||||||
if (previousMengsan) {
|
if (previousMengsan) {
|
||||||
mergeRemovedFiles(
|
mergeRemovedFiles(
|
||||||
@@ -1681,11 +1619,7 @@ async function repairMissingFiles(shuYing) {
|
|||||||
|
|
||||||
await createFolders("extension/术樱包/", files, shuYing);
|
await createFolders("extension/术樱包/", files, shuYing);
|
||||||
|
|
||||||
await saveUpdaterConfig({ [installedManifestKey]: {
|
|
||||||
schema: 1, status: "updating", manifest: null,
|
|
||||||
} });
|
|
||||||
await downloadList(shuYing, files, manifest);
|
await downloadList(shuYing, files, manifest);
|
||||||
await saveMainInstallation(manifest);
|
|
||||||
if (mengsanManifest) {
|
if (mengsanManifest) {
|
||||||
const moduleChanged = await getChangedFiles(mengsanManifest, shuYing);
|
const moduleChanged = await getChangedFiles(mengsanManifest, shuYing);
|
||||||
await installMengsanFiles(shuYing, mengsanManifest, moduleChanged, previousMengsan);
|
await installMengsanFiles(shuYing, mengsanManifest, moduleChanged, previousMengsan);
|
||||||
@@ -1785,12 +1719,45 @@ async function manageMengsanModule(shuYing) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function repairCoreFiles(shuYing) {
|
||||||
|
try {
|
||||||
|
beginUpdate(shuYing, true);
|
||||||
|
ensureProgressNode(shuYing);
|
||||||
|
await addLog(shuYing, "核心文件修复开始");
|
||||||
|
const manifest = await getManifest();
|
||||||
|
const files = getManifestCoreFiles(manifest);
|
||||||
|
if (!files.length) throw new Error("校验清单缺少核心文件");
|
||||||
|
const coreManifest = { ...manifest, files: Object.fromEntries(files.map(file => [file, manifest.files[file]])) };
|
||||||
|
const changed = await getChangedFiles(coreManifest, shuYing);
|
||||||
|
const message = changed.length ? `有 ${changed.length} 个核心文件需修复,是否重新下载核心文件?`
|
||||||
|
: "核心文件校验通过,是否仍重新下载核心文件?";
|
||||||
|
if (!confirm(message)) return;
|
||||||
|
await downloadCoreFiles(shuYing, manifest);
|
||||||
|
await addLog(shuYing, "核心文件修复完成");
|
||||||
|
alert("下载完成,重启生效");
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
recordUpdateError(shuYing, "core.repair.failed", error);
|
||||||
|
await addLog(shuYing, `核心文件修复失败:${getErrorMessage(error)}`);
|
||||||
|
alert("核心文件下载或校验失败,请检查服务器文件与 manifest.json 是否一致。");
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
try { await finishUpdate(shuYing); }
|
||||||
|
finally {
|
||||||
|
removeProgressNode(shuYing);
|
||||||
|
setBusy(shuYing, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getOnlineVersion,
|
getOnlineVersion,
|
||||||
getUpdateChannel,
|
getUpdateChannel,
|
||||||
getUpdateSource,
|
getUpdateSource,
|
||||||
checkVersion,
|
checkVersion,
|
||||||
repairMissingFiles,
|
repairMissingFiles,
|
||||||
|
repairCoreFiles,
|
||||||
manageMengsanModule,
|
manageMengsanModule,
|
||||||
getMengsanModuleStatus,
|
getMengsanModuleStatus,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user