koishi-plugin-dew-bot 1.0.265 → 1.0.266
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +100 -31
- package/lib/plugin/qualityCardStyles.d.ts +1 -1
- package/lib/plugin/serverHandel/qqCommandMessage.d.ts +0 -3
- package/lib/plugin/serverHandel/qqPageMessage.d.ts +1 -3
- package/lib/plugin/serverHandel/qqRewardMessage.d.ts +2 -2
- package/lib/plugin/serverHandel/qqStoryMessage.d.ts +0 -3
- package/lib/plugin/serverHandel/qqTransactionMessage.d.ts +0 -3
- package/lib/plugin/signinCardTemplate.d.ts +0 -1
- package/lib/shared/face/index.d.ts +9 -0
- package/package.json +1 -1
- package/src/plugin/equipmentCardTemplate.ts +5 -2
- package/src/plugin/qualityCardStyles.ts +6 -0
- package/src/plugin/serverHandel/qqCommandMessage.ts +1 -8
- package/src/plugin/serverHandel/qqMessagePreview.ts +1 -0
- package/src/plugin/serverHandel/qqPageMessage.ts +1 -8
- package/src/plugin/serverHandel/qqRewardMessage.ts +12 -7
- package/src/plugin/serverHandel/qqStoryMessage.ts +1 -8
- package/src/plugin/serverHandel/qqTransactionMessage.ts +1 -8
- package/src/plugin/signinCardTemplate.ts +0 -1
- package/src/plugin/skillCardTemplate.ts +21 -2
- package/src/shared/bot/serviceProto.ts +44 -1
- package/src/shared/face/index.ts +6 -0
package/lib/index.js
CHANGED
|
@@ -67,7 +67,7 @@ var serviceProto;
|
|
|
67
67
|
var init_serviceProto = __esm({
|
|
68
68
|
"src/shared/bot/serviceProto.ts"() {
|
|
69
69
|
serviceProto = {
|
|
70
|
-
"version":
|
|
70
|
+
"version": 44,
|
|
71
71
|
"services": [
|
|
72
72
|
{
|
|
73
73
|
"id": 0,
|
|
@@ -931,6 +931,22 @@ var init_serviceProto = __esm({
|
|
|
931
931
|
"type": {
|
|
932
932
|
"type": "String"
|
|
933
933
|
}
|
|
934
|
+
},
|
|
935
|
+
{
|
|
936
|
+
"id": 15,
|
|
937
|
+
"name": "stars",
|
|
938
|
+
"type": {
|
|
939
|
+
"type": "Number"
|
|
940
|
+
},
|
|
941
|
+
"optional": true
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
"id": 16,
|
|
945
|
+
"name": "maxStars",
|
|
946
|
+
"type": {
|
|
947
|
+
"type": "Number"
|
|
948
|
+
},
|
|
949
|
+
"optional": true
|
|
934
950
|
}
|
|
935
951
|
]
|
|
936
952
|
},
|
|
@@ -1192,6 +1208,33 @@ var init_serviceProto = __esm({
|
|
|
1192
1208
|
"type": "String"
|
|
1193
1209
|
},
|
|
1194
1210
|
"optional": true
|
|
1211
|
+
},
|
|
1212
|
+
{
|
|
1213
|
+
"id": 13,
|
|
1214
|
+
"name": "randomAffixes",
|
|
1215
|
+
"type": {
|
|
1216
|
+
"type": "Array",
|
|
1217
|
+
"elementType": {
|
|
1218
|
+
"type": "Interface",
|
|
1219
|
+
"properties": [
|
|
1220
|
+
{
|
|
1221
|
+
"id": 0,
|
|
1222
|
+
"name": "name",
|
|
1223
|
+
"type": {
|
|
1224
|
+
"type": "String"
|
|
1225
|
+
}
|
|
1226
|
+
},
|
|
1227
|
+
{
|
|
1228
|
+
"id": 1,
|
|
1229
|
+
"name": "value",
|
|
1230
|
+
"type": {
|
|
1231
|
+
"type": "String"
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
]
|
|
1235
|
+
}
|
|
1236
|
+
},
|
|
1237
|
+
"optional": true
|
|
1195
1238
|
}
|
|
1196
1239
|
]
|
|
1197
1240
|
},
|
|
@@ -2768,6 +2811,12 @@ h1,h2,h3,p{margin:0}
|
|
|
2768
2811
|
.skill-type{font-size:24px;letter-spacing:3px;color:#cbcdbd}
|
|
2769
2812
|
.quality-badge{display:inline-flex;align-items:center;gap:9px;padding:6px 14px;color:#fff5de;font-size:18px;font-weight:600;border:1px solid color-mix(in srgb,var(--quality-accent) 70%,transparent);border-radius:6px;background:color-mix(in srgb,var(--quality-accent) 17%,transparent)}
|
|
2770
2813
|
.quality-badge b{color:var(--quality-end);font:700 24px Georgia,serif}
|
|
2814
|
+
.skill-stars{display:flex;align-items:center;flex-wrap:wrap;gap:3px;max-width:100%;margin-top:-8px}
|
|
2815
|
+
.skill-star{display:block;flex:0 0 40px;width:40px;height:40px;overflow:visible;filter:drop-shadow(0 1px 1px #10121780)}
|
|
2816
|
+
.star-shape{stroke:#24252b;stroke-width:2.4;stroke-linejoin:round}
|
|
2817
|
+
.star-gradient-light{stop-color:color-mix(in srgb,var(--quality-end) 55%,#fff)}.star-gradient-mid{stop-color:var(--quality-accent)}.star-gradient-shade{stop-color:var(--quality-start)}
|
|
2818
|
+
.star-facet-light{fill:#fff;opacity:.28}.star-facet-shade{fill:#151328;opacity:.18}.star-facet-glint{fill:none;stroke:#fff;stroke-width:.7;stroke-linejoin:round;opacity:.55}
|
|
2819
|
+
.skill-star.unlit .star-shape{fill:#303436;stroke:#171d22;stroke-width:2.6}
|
|
2771
2820
|
.tags{display:flex;gap:7px;flex-wrap:wrap}
|
|
2772
2821
|
.tag{font-size:20px;line-height:1.3;padding:6px 10px;border-radius:4px;overflow-wrap:anywhere;color:#bfcaed;background:#647bb434;border:1px solid #7d9cc62b}
|
|
2773
2822
|
.tag.damage{color:#f5ae94;background:#b961433d;border-color:#b4614340}.tag.shield{color:#a3d7b7;background:#5186683d;border-color:#73a48a40}.tag.heal{color:#b5deb0;background:#668e4a3b;border-color:#89a47140}.tag.passive{color:#cebbef;background:#8367a63d;border-color:#9682b540}.tag.growth{color:#ecd291;background:#b1944540;border-color:#ab944e40}
|
|
@@ -3627,6 +3676,20 @@ function tagClass(tag) {
|
|
|
3627
3676
|
return "";
|
|
3628
3677
|
}
|
|
3629
3678
|
__name(tagClass, "tagClass");
|
|
3679
|
+
function skillStars(card) {
|
|
3680
|
+
if (card.stars === void 0 && card.maxStars === void 0) return "";
|
|
3681
|
+
const maxStars = Math.min(20, Math.max(0, Math.floor(Number.isFinite(card.maxStars) ? card.maxStars : Number.isFinite(card.stars) ? card.stars : 0)));
|
|
3682
|
+
if (!maxStars) return "";
|
|
3683
|
+
const stars = Math.min(maxStars, Math.max(0, Math.floor(Number.isFinite(card.stars) ? card.stars : 0)));
|
|
3684
|
+
const outline = "20,3 25.1,13.4 36.6,15.1 28.3,23.2 30.3,34.7 20,29.3 9.7,34.7 11.7,23.2 3.4,15.1 14.9,13.4";
|
|
3685
|
+
const icons = Array.from({ length: maxStars }, (_, index) => {
|
|
3686
|
+
const lit = index < stars;
|
|
3687
|
+
const gradient = "skill-star-fill-" + index;
|
|
3688
|
+
return '<svg class="skill-star ' + (lit ? "lit" : "unlit") + '" viewBox="0 0 40 40" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg">' + (lit ? '<defs><linearGradient id="' + gradient + '" x1="0" y1="0" x2="0.7" y2="1"><stop class="star-gradient-light"/><stop offset=".48" class="star-gradient-mid"/><stop offset="1" class="star-gradient-shade"/></linearGradient></defs>' : "") + '<polygon class="star-shape" points="' + outline + '"' + (lit ? ' fill="url(#' + gradient + ')"' : "") + "/>" + (lit ? '<path class="star-facet-light" d="M20 5.7 20 20.6 5.9 16.1 15.9 14.6Z"/><path class="star-facet-shade" d="M20 20.6 28.6 32.3 26.9 22.7 34.1 16.1Z"/><path class="star-facet-glint" d="M20 6.2 20 20.6 12 31.9 13.3 23 6.5 16.6 16 15.2Z"/>' : "") + "</svg>";
|
|
3689
|
+
}).join("");
|
|
3690
|
+
return '<div class="skill-stars" role="img" aria-label="' + stars + " / " + maxStars + ' 星">' + icons + "</div>";
|
|
3691
|
+
}
|
|
3692
|
+
__name(skillStars, "skillStars");
|
|
3630
3693
|
function skillCardHtml(card, _frame = "", artwork) {
|
|
3631
3694
|
const quality = normalizeCardQuality(card.quality);
|
|
3632
3695
|
const description = card.description?.trim() || "暂无技能效果说明";
|
|
@@ -3644,13 +3707,13 @@ function skillCardHtml(card, _frame = "", artwork) {
|
|
|
3644
3707
|
<div id="capture" class="skill-sheet"><article class="detail-card skill-card quality-${quality.toLowerCase()}" style="${qualityStyle(quality)}">
|
|
3645
3708
|
<i class="card-corner corner-tl" aria-hidden="true"></i><i class="card-corner corner-tr" aria-hidden="true"></i><i class="card-corner corner-bl" aria-hidden="true"></i><i class="card-corner corner-br" aria-hidden="true"></i>
|
|
3646
3709
|
<div class="card-inner"><header class="card-titlebar"><span class="title-glyph" aria-hidden="true">◇</span><h1>${escape2(card.name)}</h1><span class="title-star" aria-hidden="true">✦</span></header>
|
|
3647
|
-
<div class="card-hero"><div class="hero-copy"><div class="hero-meta"><span class="skill-type">${card.passive ? "被动技能" : "主动技能"}</span><span class="quality-badge"><b>${quality}</b> 级</span
|
|
3710
|
+
<div class="card-hero"><div class="hero-copy"><div class="hero-meta"><span class="skill-type">${card.passive ? "被动技能" : "主动技能"}</span><span class="quality-badge"><b>${quality}</b> 级</span>${skillStars(card)}</div><div class="tags">${tags.map((tag) => `<span class="tag ${tagClass(tag)}">${escape2(tag)}</span>`).join("")}</div></div><div class="hero-icon-wrap">${qualityMagicCircle(quality)}<div class="art-fallback" aria-hidden="true">${card.passive ? "静" : "势"}</div>${artwork ? `<img class="skill-artwork" alt="${escape2(card.name)}图标" src="${escape2(artwork)}">` : ""}${qualityIconFrame(quality)}</div></div>
|
|
3648
3711
|
<div class="card-body"><div class="effect-stats">
|
|
3649
3712
|
${row("消耗", escape2(card.cost || "无消耗"), true)}
|
|
3650
3713
|
${row("冷却", cooldownValue, true)}
|
|
3651
3714
|
${power ? row("战力", escape2(power.replace(/^(?:🔥\s*)?战力\s*[::]\s*/, "")), true) : ""}
|
|
3652
3715
|
${(card.stats || []).slice(0, 3).map((stat) => row(stat.label, statValue(stat.value))).join("")}
|
|
3653
|
-
</div><section class="effect"><h2 class="section-heading"
|
|
3716
|
+
</div><section class="effect"><h2 class="section-heading">${escape2(card.mechanism || "技能效果")}</h2><p class="description">${effectText(effect)}</p></section>
|
|
3654
3717
|
${growth ? `<section class="growth-section"><h2 class="section-heading">永久成长 · 仅玩家</h2><p class="description">${effectText(growth)}</p></section>` : ""}
|
|
3655
3718
|
${otherNotes ? `<section class="note-section"><h2 class="section-heading">附加信息</h2><p class="description">${escape2(otherNotes)}</p></section>` : ""}
|
|
3656
3719
|
</div></div></article></div></body></html>`;
|
|
@@ -3668,7 +3731,8 @@ function equipmentCardHtml(card, artwork, unknownFallback = false) {
|
|
|
3668
3731
|
cardStatRow("打造者", card.authorName?.trim() || "未知"),
|
|
3669
3732
|
...card.referencePrice ? [cardStatRow("参考价格", card.referencePrice)] : []
|
|
3670
3733
|
].join("");
|
|
3671
|
-
const affixes = card.affixes?.length ? '<div class="detail-list">' + card.affixes.map((affix) => cardStatRow(affix.name, affix.value)).join("") + "</div>" : '<p class="description"
|
|
3734
|
+
const affixes = card.affixes?.length ? '<div class="detail-list">' + card.affixes.map((affix) => cardStatRow(affix.name, affix.value)).join("") + "</div>" : '<p class="description">暂无基础属性</p>';
|
|
3735
|
+
const randomAffixes = card.randomAffixes?.length ? cardSection("随机词条", '<div class="detail-list">' + card.randomAffixes.map((affix) => cardStatRow(affix.name, affix.value)).join("") + "</div>") : "";
|
|
3672
3736
|
const skills2 = card.skills?.length ? cardSection("附带技能", '<div class="detail-list">' + card.skills.map((skill) => cardStatRow(skill.name, "")).join("") + "</div>") : "";
|
|
3673
3737
|
const description = card.description?.trim() ? cardSection("装备描述", '<p class="description">' + cardEscape(card.description.trim()) + "</p>") : "";
|
|
3674
3738
|
const notes = card.notes?.filter((note) => note?.trim()).length ? cardSection("附加信息", '<p class="description">' + card.notes.filter((note) => note?.trim()).map((note) => cardEscape(note)).join("\n") + "</p>") : "";
|
|
@@ -3681,7 +3745,7 @@ function equipmentCardHtml(card, artwork, unknownFallback = false) {
|
|
|
3681
3745
|
fallbackGlyph: "?",
|
|
3682
3746
|
sheetClass: "equipment-sheet",
|
|
3683
3747
|
tags: unknownFallback || !artwork ? ["外观暂未显现"] : [],
|
|
3684
|
-
body: '<div class="effect-stats">' + details + "</div>" + cardSection("
|
|
3748
|
+
body: '<div class="effect-stats">' + details + "</div>" + cardSection("基础属性", affixes) + randomAffixes + skills2 + description + notes
|
|
3685
3749
|
});
|
|
3686
3750
|
}
|
|
3687
3751
|
__name(equipmentCardHtml, "equipmentCardHtml");
|
|
@@ -4793,28 +4857,6 @@ var AnalysisMsg = class {
|
|
|
4793
4857
|
}
|
|
4794
4858
|
};
|
|
4795
4859
|
|
|
4796
|
-
// src/plugin/serverHandel/qqMessageButtons.ts
|
|
4797
|
-
function renderQQKeyboard(data) {
|
|
4798
|
-
const rows = data.buttons;
|
|
4799
|
-
if (!rows?.length) return void 0;
|
|
4800
|
-
if (rows.length > 5 || rows.some((row) => !row.buttons.length || row.buttons.length > 5)) {
|
|
4801
|
-
throw new Error("QQ 按钮最多 5 行,每行必须有 1–5 个按钮");
|
|
4802
|
-
}
|
|
4803
|
-
return { content: { rows: rows.map((row, rowIndex) => ({
|
|
4804
|
-
buttons: row.buttons.map((button, buttonIndex) => {
|
|
4805
|
-
if (!button.label.trim() || !button.command.trim() || /[\r\n\0]/.test(button.label + button.command) || button.command.length > 4e3 || button.style !== void 0 && button.style !== "primary" && button.style !== "secondary") {
|
|
4806
|
-
throw new Error("QQ 按钮文案和指令必须是非空单行文本,样式必须为 primary 或 secondary");
|
|
4807
|
-
}
|
|
4808
|
-
return {
|
|
4809
|
-
id: "action-" + rowIndex + "-" + buttonIndex,
|
|
4810
|
-
render_data: { label: button.label, visited_label: button.label, style: button.style === "primary" ? 1 : 0 },
|
|
4811
|
-
action: { type: 2, permission: { type: 2 }, data: button.command, enter: true, reply: false, unsupport_tips: "请发送:" + button.command }
|
|
4812
|
-
};
|
|
4813
|
-
})
|
|
4814
|
-
})) } };
|
|
4815
|
-
}
|
|
4816
|
-
__name(renderQQKeyboard, "renderQQKeyboard");
|
|
4817
|
-
|
|
4818
4860
|
// src/plugin/serverHandel/qqMarkdownHelpers.ts
|
|
4819
4861
|
function escapeMarkdown(value) {
|
|
4820
4862
|
return value.replace(/[\\`*_{}\[\]()#+\-.!|>~<&]/g, "\\$&");
|
|
@@ -4890,16 +4932,20 @@ function renderRewardTitle(content) {
|
|
|
4890
4932
|
return `**${escapeMarkdown(compactDisplayText(content))}**`;
|
|
4891
4933
|
}
|
|
4892
4934
|
__name(renderRewardTitle, "renderRewardTitle");
|
|
4893
|
-
function renderRewardLine(content) {
|
|
4935
|
+
function renderRewardLine(content, command) {
|
|
4894
4936
|
return content.replace(/\r\n?/g, "\n").split("\n").filter((line) => line.trim()).map((line) => {
|
|
4895
4937
|
const text = line.trim();
|
|
4896
4938
|
const quantity = /([++\-−×xX]\s*\d+(?:\.\d+)?)$/.exec(text);
|
|
4897
|
-
const
|
|
4939
|
+
const label = quantity ? text.slice(0, quantity.index) : text;
|
|
4940
|
+
const name2 = label.trimEnd();
|
|
4941
|
+
const formattedName = command && name2 ? `[${escapeMarkdown(name2)}](${inlineCommandUrl(command)})${escapeMarkdown(label.slice(name2.length))}` : escapeMarkdown(label);
|
|
4942
|
+
const formatted = formattedName + (quantity ? `**${escapeMarkdown(quantity[1])}**` : "");
|
|
4898
4943
|
return "> " + formatted;
|
|
4899
4944
|
}).join(" \n");
|
|
4900
4945
|
}
|
|
4901
4946
|
__name(renderRewardLine, "renderRewardLine");
|
|
4902
4947
|
function renderQQMailMarkdown(data) {
|
|
4948
|
+
const commands = new Map(data.pageNav?.entries?.map((entry) => [entry.lineIndex, entry.viewCommand]) ?? []);
|
|
4903
4949
|
const sections = [];
|
|
4904
4950
|
const text = [];
|
|
4905
4951
|
const rewards = [];
|
|
@@ -4909,7 +4955,7 @@ function renderQQMailMarkdown(data) {
|
|
|
4909
4955
|
const flushRewards = /* @__PURE__ */ __name(() => {
|
|
4910
4956
|
if (rewards.length) sections.push(rewards.splice(0).join(" \n"));
|
|
4911
4957
|
}, "flushRewards");
|
|
4912
|
-
for (const item of data.line) {
|
|
4958
|
+
for (const [lineIndex, item] of data.line.entries()) {
|
|
4913
4959
|
if (item.type === 0 /* title */ || item.type === 1 /* line */ && item.mailPart === "title") {
|
|
4914
4960
|
flushText();
|
|
4915
4961
|
flushRewards();
|
|
@@ -4920,7 +4966,7 @@ function renderQQMailMarkdown(data) {
|
|
|
4920
4966
|
sections.push(item.content.replace(/\r\n?/g, "\n").split("\n").map((line) => "> " + escapeMarkdown(line)).join(" \n"));
|
|
4921
4967
|
} else if (item.type === 1 /* line */ && item.reward) {
|
|
4922
4968
|
flushText();
|
|
4923
|
-
const reward = renderRewardLine(item.content);
|
|
4969
|
+
const reward = renderRewardLine(item.content, commands.get(lineIndex));
|
|
4924
4970
|
if (reward) rewards.push(reward);
|
|
4925
4971
|
} else {
|
|
4926
4972
|
flushRewards();
|
|
@@ -5275,6 +5321,28 @@ async function sendQQMarkdown(session, markdown, keyboard) {
|
|
|
5275
5321
|
}
|
|
5276
5322
|
__name(sendQQMarkdown, "sendQQMarkdown");
|
|
5277
5323
|
|
|
5324
|
+
// src/plugin/serverHandel/qqMessageButtons.ts
|
|
5325
|
+
function renderQQKeyboard(data) {
|
|
5326
|
+
const rows = data.buttons;
|
|
5327
|
+
if (!rows?.length) return void 0;
|
|
5328
|
+
if (rows.length > 5 || rows.some((row) => !row.buttons.length || row.buttons.length > 5)) {
|
|
5329
|
+
throw new Error("QQ 按钮最多 5 行,每行必须有 1–5 个按钮");
|
|
5330
|
+
}
|
|
5331
|
+
return { content: { rows: rows.map((row, rowIndex) => ({
|
|
5332
|
+
buttons: row.buttons.map((button, buttonIndex) => {
|
|
5333
|
+
if (!button.label.trim() || !button.command.trim() || /[\r\n\0]/.test(button.label + button.command) || button.command.length > 4e3 || button.style !== void 0 && button.style !== "primary" && button.style !== "secondary") {
|
|
5334
|
+
throw new Error("QQ 按钮文案和指令必须是非空单行文本,样式必须为 primary 或 secondary");
|
|
5335
|
+
}
|
|
5336
|
+
return {
|
|
5337
|
+
id: "action-" + rowIndex + "-" + buttonIndex,
|
|
5338
|
+
render_data: { label: button.label, visited_label: button.label, style: button.style === "primary" ? 1 : 0 },
|
|
5339
|
+
action: { type: 2, permission: { type: 2 }, data: button.command, enter: true, reply: false, unsupport_tips: "请发送:" + button.command }
|
|
5340
|
+
};
|
|
5341
|
+
})
|
|
5342
|
+
})) } };
|
|
5343
|
+
}
|
|
5344
|
+
__name(renderQQKeyboard, "renderQQKeyboard");
|
|
5345
|
+
|
|
5278
5346
|
// src/plugin/serverHandel/qqCommandMessage.ts
|
|
5279
5347
|
function renderQQCommandMarkdown(data, showGreeting) {
|
|
5280
5348
|
data = withoutMessageButtonFallbacks(data);
|
|
@@ -5512,6 +5580,7 @@ function renderQQMessagePreview(data, showGreeting = false) {
|
|
|
5512
5580
|
if (hasStoryCodeBlock(data)) return native("story", renderQQStoryMarkdown(data, showGreeting));
|
|
5513
5581
|
if (data.commandHelp) return native("command", renderQQCommandMarkdown(data, showGreeting));
|
|
5514
5582
|
if (data.transaction) return native("transaction", renderQQTransactionMarkdown(data, showGreeting));
|
|
5583
|
+
if (data.mail) return native("reward", renderQQRewardMarkdown(data, showGreeting));
|
|
5515
5584
|
if (data.pageNav) return native("page", renderQQPageMarkdown(data, showGreeting));
|
|
5516
5585
|
if (isRewardMessage(data)) return native("reward", renderQQRewardMarkdown(data, showGreeting));
|
|
5517
5586
|
if (battleLogMessageLinks(data).length || data.line.some((item) => (item.type === 1 /* line */ || item.type === 2 /* error */) && hasInlineCommands(item.content))) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Shared detail-card styling; all ornaments render with JavaScript disabled. */
|
|
2
|
-
export declare const qualityCardStyles = "\n*{box-sizing:border-box}\nhtml,body{margin:0;width:760px;background:#e9e9e2;font-family:'Microsoft YaHei','Noto Sans CJK SC',sans-serif;color:#303735}\n#capture{width:760px;padding:18px;background:radial-gradient(ellipse at 70% 10%,#f9f7efb8,transparent 55%),#e9e9e2}\nh1,h2,h3,p{margin:0}\n.detail-card{position:relative;width:100%;isolation:isolate;border:3px solid color-mix(in srgb,var(--quality-accent) 50%,#454a45);border-radius:18px;box-shadow:0 8px 18px #3f47321c;background:#f5f4ed;overflow:visible;--corner-size:24px;--corner-metal:#dce1d6;--corner-cut:polygon(0 0,100% 13%,75% 50%,100% 100%,50% 75%,13% 100%)}\n.card-inner{overflow:hidden;border-radius:14px}\n.card-corner{position:absolute;width:var(--corner-size);height:var(--corner-size);z-index:5;background:linear-gradient(135deg,#faf9eb,var(--corner-metal));border:1px solid #7b8075;clip-path:var(--corner-cut);filter:drop-shadow(0 1px 2px #0009)}\n.card-corner:after{content:'';position:absolute;inset:6px;background:color-mix(in srgb,var(--quality-accent) 80%,#4e584b);clip-path:var(--corner-cut)}\n.corner-tl{top:-7px;left:-7px}.corner-tr{top:-7px;right:-7px;transform:rotate(90deg)}.corner-br{bottom:-7px;right:-7px;transform:rotate(180deg)}.corner-bl{bottom:-7px;left:-7px;transform:rotate(270deg)}\n.quality-f{--corner-size:13.5px;--corner-metal:#a6afa4;--corner-cut:polygon(0 0,100% 0,100% 30%,30% 30%,30% 100%,0 100%)}\n.quality-f .card-corner:after{display:none}\n.quality-e{--corner-size:18px;--corner-metal:#a6c1a7;--corner-cut:polygon(0 0,100% 0,85% 28%,37% 37%,28% 85%,0 100%)}\n.quality-d{--corner-size:21px;--corner-metal:#87c3b1;--corner-cut:polygon(0 0,70% 10%,100% 45%,45% 100%,10% 70%)}\n.quality-c{--corner-metal:#acd5ed}\n.quality-b{--corner-size:25.5px;--corner-metal:#c2a5dc;--corner-cut:polygon(0 0,58% 14%,100% 4%,86% 47%,100% 100%,47% 86%,4% 100%,14% 58%)}\n.quality-a{--corner-size:27px;--corner-metal:#e2ba7b}\n.quality-s{--corner-size:30px;--corner-metal:#e2ca7c;--corner-cut:polygon(0 0,70% 9%,100% 0,86% 30%,67% 45%,100% 100%,45% 67%,30% 86%,0 100%,9% 70%)}\n.quality-ss{--corner-size:30px;--corner-metal:#dea595;--corner-cut:polygon(0 0,78% 14%,100% 43%,70% 70%,43% 100%,14% 78%)}\n.quality-sss{--corner-size:34.5px;--corner-metal:#d6b575;--corner-cut:polygon(0 0,55% 14%,100% 3%,82% 30%,68% 50%,100% 100%,50% 68%,30% 82%,3% 100%,14% 55%)}\n.quality-sss .card-corner:after{background:#9d79ac}\n.card-titlebar{position:relative;isolation:isolate;display:flex;align-items:center;gap:18px;min-height:98px;padding:27px 35px;background:linear-gradient(112deg,var(--quality-start),var(--quality-end));border-bottom:4px solid var(--quality-accent);color:#fffbee}\n.card-titlebar:before{content:'';position:absolute;inset:0;z-index:-1;background-image:radial-gradient(circle,#fff7 1.5px,transparent 2.2px),linear-gradient(30deg,transparent 65%,#ffffff1a 65.2%,transparent 65.6%);background-size:118px 95px,100% 100%;opacity:.55}\n.card-titlebar h1{min-width:0;flex:1;font-size:35px;line-height:1.4;letter-spacing:1px;font-weight:600;text-shadow:0 1px 2px #2c292348;overflow-wrap:anywhere}\n.title-glyph{font-size:31px;line-height:1;color:#fff6cecc}.title-star{font:38px Georgia;opacity:.75}\n.card-hero{position:relative;isolation:isolate;display:flex;align-items:center;justify-content:space-between;gap:24px;min-height:228px;padding:30px 36px;color:#eeeedd;background:radial-gradient(ellipse at 0 0,color-mix(in srgb,var(--quality-accent) 33%,transparent),transparent 65%),#272f30}\n.card-hero:before{content:'';position:absolute;inset:0;z-index:-1;opacity:.16;background-image:radial-gradient(circle,#d3d4bd 1px,transparent 1.2px);background-size:7.5px 7.5px;mask-image:linear-gradient(to bottom,#000,transparent 74%)}\n.hero-copy{flex:1;min-width:0;align-self:stretch;display:flex;flex-direction:column;justify-content:space-between}\n.hero-meta{display:flex;flex-direction:column;align-items:flex-start;gap:15px;margin-bottom:25px}\n.skill-type{font-size:24px;letter-spacing:3px;color:#cbcdbd}\n.quality-badge{display:inline-flex;align-items:center;gap:9px;padding:6px 14px;color:#fff5de;font-size:18px;font-weight:600;border:1px solid color-mix(in srgb,var(--quality-accent) 70%,transparent);border-radius:6px;background:color-mix(in srgb,var(--quality-accent) 17%,transparent)}\n.quality-badge b{color:var(--quality-end);font:700 24px Georgia,serif}\n.tags{display:flex;gap:7px;flex-wrap:wrap}\n.tag{font-size:20px;line-height:1.3;padding:6px 10px;border-radius:4px;overflow-wrap:anywhere;color:#bfcaed;background:#647bb434;border:1px solid #7d9cc62b}\n.tag.damage{color:#f5ae94;background:#b961433d;border-color:#b4614340}.tag.shield{color:#a3d7b7;background:#5186683d;border-color:#73a48a40}.tag.heal{color:#b5deb0;background:#668e4a3b;border-color:#89a47140}.tag.passive{color:#cebbef;background:#8367a63d;border-color:#9682b540}.tag.growth{color:#ecd291;background:#b1944540;border-color:#ab944e40}\n.hero-icon-wrap{--icon-size:120px;--magic-size:calc(var(--magic-base) * 1.5px);position:relative;flex-shrink:0;width:var(--magic-size);height:var(--magic-size)}\n.magic-circle{position:absolute;width:100%;height:100%;top:50%;left:50%;transform:translate(-50%,-50%);color:var(--quality-end);pointer-events:none;overflow:visible}\n.magic-rays{stroke:currentColor;stroke-width:.9;opacity:.28}.magic-orbits{stroke:currentColor;stroke-width:1.2;opacity:.42}.magic-detail{stroke:currentColor;stroke-width:.9;opacity:.45}.magic-marks{fill:currentColor;opacity:.68}\n.magic-sss .magic-rays{stroke:#ddbc80;opacity:.49}.magic-sss .magic-detail{stroke:#bb9ccc;opacity:.64}.magic-sss .magic-marks{fill:#eed093;opacity:.88}\n.quality-s .magic-circle,.quality-ss .magic-circle,.quality-sss .magic-circle{filter:drop-shadow(0 0 4px color-mix(in srgb,var(--quality-accent) 30%,transparent))}\n.skill-artwork,.art-fallback{position:absolute;z-index:1;top:50%;left:50%;transform:translate(-50%,-50%);width:var(--icon-size);height:var(--icon-size);border:1.5px solid #bfc6b7;border-radius:50%;box-shadow:0 4px 13px #0007;object-fit:cover;object-position:center}\n.art-fallback{display:grid;place-items:center;color:var(--quality-end);font:44px 'KaiTi','SimSun',serif;background:radial-gradient(circle,#53615b,#1f2928)}\n.skill-icon-frame{position:absolute;top:50%;left:50%;width:calc(var(--icon-size) + 45px);height:calc(var(--icon-size) + 45px);transform:translate(-50%,-50%);z-index:2;color:var(--quality-accent);pointer-events:none;filter:drop-shadow(0 1px 1px #10181480)}\n.quality-sss .hero-icon-wrap{background:radial-gradient(ellipse,#ad85d525,transparent 68%)}\n.card-body{padding:32px 36px 34px;background:linear-gradient(145deg,#faf9f3,#eeeee7)}\n.effect-stats{display:grid;gap:9px;margin-bottom:27px}\n.stat-row{display:flex;align-items:center;justify-content:space-between;gap:18px;min-height:54px;padding:13px 18px;background:#e5e7de;border-radius:6px;font-size:24px}\n.stat-row>span{color:#626d57;flex:0 0 auto;max-width:45%;overflow-wrap:anywhere}\n.stat-row b{min-width:0;text-align:right;overflow-wrap:anywhere;font-size:30px;color:var(--quality-ink);font-weight:600}\n.stat-row.detail-stat b{font-size:26px;font-weight:500;color:#4f594b;background:none;-webkit-text-fill-color:currentColor}\n.stat-row .param-unit{font-size:24px;font-weight:400;color:#75816d;-webkit-text-fill-color:currentColor}\n.stat-value{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:flex-end;gap:9px}\n.stat-value .stat-unit{font-size:24px;font-weight:400;color:#737c68;-webkit-text-fill-color:currentColor}\n.section-heading{display:flex;align-items:center;gap:10px;margin:0 0 16px;font-size:24px;font-weight:500;letter-spacing:2px;color:#6f7d60}\n.section-heading:before{content:'\u25C6';font-size:10px;color:var(--quality-accent)}\n.description{font-size:28px;line-height:1.85;color:#515b4c;overflow-wrap:anywhere;white-space:pre-wrap}\n.description .number{color:var(--quality-ink);font-weight:600}.description .keyword{color:#907843;font-weight:500}\n.growth-section,.note-section{border-top:1px solid #d6dacd;margin-top:27px;padding-top:24px}\n.growth-section .description{color:#5c684f}\n.note-section .description{font-size:26px;color:#626d57}\n.quality-sss .card-titlebar{background:linear-gradient(110deg,#7c679e,#a77c95 50%,#cba770)}\n.quality-sss .quality-badge{border-color:#d3c192}\n.quality-sss .stat-number{background:linear-gradient(90deg,#936891,#ab884d);background-clip:text;-webkit-text-fill-color:transparent}\n";
|
|
2
|
+
export declare const qualityCardStyles = "\n*{box-sizing:border-box}\nhtml,body{margin:0;width:760px;background:#e9e9e2;font-family:'Microsoft YaHei','Noto Sans CJK SC',sans-serif;color:#303735}\n#capture{width:760px;padding:18px;background:radial-gradient(ellipse at 70% 10%,#f9f7efb8,transparent 55%),#e9e9e2}\nh1,h2,h3,p{margin:0}\n.detail-card{position:relative;width:100%;isolation:isolate;border:3px solid color-mix(in srgb,var(--quality-accent) 50%,#454a45);border-radius:18px;box-shadow:0 8px 18px #3f47321c;background:#f5f4ed;overflow:visible;--corner-size:24px;--corner-metal:#dce1d6;--corner-cut:polygon(0 0,100% 13%,75% 50%,100% 100%,50% 75%,13% 100%)}\n.card-inner{overflow:hidden;border-radius:14px}\n.card-corner{position:absolute;width:var(--corner-size);height:var(--corner-size);z-index:5;background:linear-gradient(135deg,#faf9eb,var(--corner-metal));border:1px solid #7b8075;clip-path:var(--corner-cut);filter:drop-shadow(0 1px 2px #0009)}\n.card-corner:after{content:'';position:absolute;inset:6px;background:color-mix(in srgb,var(--quality-accent) 80%,#4e584b);clip-path:var(--corner-cut)}\n.corner-tl{top:-7px;left:-7px}.corner-tr{top:-7px;right:-7px;transform:rotate(90deg)}.corner-br{bottom:-7px;right:-7px;transform:rotate(180deg)}.corner-bl{bottom:-7px;left:-7px;transform:rotate(270deg)}\n.quality-f{--corner-size:13.5px;--corner-metal:#a6afa4;--corner-cut:polygon(0 0,100% 0,100% 30%,30% 30%,30% 100%,0 100%)}\n.quality-f .card-corner:after{display:none}\n.quality-e{--corner-size:18px;--corner-metal:#a6c1a7;--corner-cut:polygon(0 0,100% 0,85% 28%,37% 37%,28% 85%,0 100%)}\n.quality-d{--corner-size:21px;--corner-metal:#87c3b1;--corner-cut:polygon(0 0,70% 10%,100% 45%,45% 100%,10% 70%)}\n.quality-c{--corner-metal:#acd5ed}\n.quality-b{--corner-size:25.5px;--corner-metal:#c2a5dc;--corner-cut:polygon(0 0,58% 14%,100% 4%,86% 47%,100% 100%,47% 86%,4% 100%,14% 58%)}\n.quality-a{--corner-size:27px;--corner-metal:#e2ba7b}\n.quality-s{--corner-size:30px;--corner-metal:#e2ca7c;--corner-cut:polygon(0 0,70% 9%,100% 0,86% 30%,67% 45%,100% 100%,45% 67%,30% 86%,0 100%,9% 70%)}\n.quality-ss{--corner-size:30px;--corner-metal:#dea595;--corner-cut:polygon(0 0,78% 14%,100% 43%,70% 70%,43% 100%,14% 78%)}\n.quality-sss{--corner-size:34.5px;--corner-metal:#d6b575;--corner-cut:polygon(0 0,55% 14%,100% 3%,82% 30%,68% 50%,100% 100%,50% 68%,30% 82%,3% 100%,14% 55%)}\n.quality-sss .card-corner:after{background:#9d79ac}\n.card-titlebar{position:relative;isolation:isolate;display:flex;align-items:center;gap:18px;min-height:98px;padding:27px 35px;background:linear-gradient(112deg,var(--quality-start),var(--quality-end));border-bottom:4px solid var(--quality-accent);color:#fffbee}\n.card-titlebar:before{content:'';position:absolute;inset:0;z-index:-1;background-image:radial-gradient(circle,#fff7 1.5px,transparent 2.2px),linear-gradient(30deg,transparent 65%,#ffffff1a 65.2%,transparent 65.6%);background-size:118px 95px,100% 100%;opacity:.55}\n.card-titlebar h1{min-width:0;flex:1;font-size:35px;line-height:1.4;letter-spacing:1px;font-weight:600;text-shadow:0 1px 2px #2c292348;overflow-wrap:anywhere}\n.title-glyph{font-size:31px;line-height:1;color:#fff6cecc}.title-star{font:38px Georgia;opacity:.75}\n.card-hero{position:relative;isolation:isolate;display:flex;align-items:center;justify-content:space-between;gap:24px;min-height:228px;padding:30px 36px;color:#eeeedd;background:radial-gradient(ellipse at 0 0,color-mix(in srgb,var(--quality-accent) 33%,transparent),transparent 65%),#272f30}\n.card-hero:before{content:'';position:absolute;inset:0;z-index:-1;opacity:.16;background-image:radial-gradient(circle,#d3d4bd 1px,transparent 1.2px);background-size:7.5px 7.5px;mask-image:linear-gradient(to bottom,#000,transparent 74%)}\n.hero-copy{flex:1;min-width:0;align-self:stretch;display:flex;flex-direction:column;justify-content:space-between}\n.hero-meta{display:flex;flex-direction:column;align-items:flex-start;gap:15px;margin-bottom:25px}\n.skill-type{font-size:24px;letter-spacing:3px;color:#cbcdbd}\n.quality-badge{display:inline-flex;align-items:center;gap:9px;padding:6px 14px;color:#fff5de;font-size:18px;font-weight:600;border:1px solid color-mix(in srgb,var(--quality-accent) 70%,transparent);border-radius:6px;background:color-mix(in srgb,var(--quality-accent) 17%,transparent)}\n.quality-badge b{color:var(--quality-end);font:700 24px Georgia,serif}\n.skill-stars{display:flex;align-items:center;flex-wrap:wrap;gap:3px;max-width:100%;margin-top:-8px}\n.skill-star{display:block;flex:0 0 40px;width:40px;height:40px;overflow:visible;filter:drop-shadow(0 1px 1px #10121780)}\n.star-shape{stroke:#24252b;stroke-width:2.4;stroke-linejoin:round}\n.star-gradient-light{stop-color:color-mix(in srgb,var(--quality-end) 55%,#fff)}.star-gradient-mid{stop-color:var(--quality-accent)}.star-gradient-shade{stop-color:var(--quality-start)}\n.star-facet-light{fill:#fff;opacity:.28}.star-facet-shade{fill:#151328;opacity:.18}.star-facet-glint{fill:none;stroke:#fff;stroke-width:.7;stroke-linejoin:round;opacity:.55}\n.skill-star.unlit .star-shape{fill:#303436;stroke:#171d22;stroke-width:2.6}\n.tags{display:flex;gap:7px;flex-wrap:wrap}\n.tag{font-size:20px;line-height:1.3;padding:6px 10px;border-radius:4px;overflow-wrap:anywhere;color:#bfcaed;background:#647bb434;border:1px solid #7d9cc62b}\n.tag.damage{color:#f5ae94;background:#b961433d;border-color:#b4614340}.tag.shield{color:#a3d7b7;background:#5186683d;border-color:#73a48a40}.tag.heal{color:#b5deb0;background:#668e4a3b;border-color:#89a47140}.tag.passive{color:#cebbef;background:#8367a63d;border-color:#9682b540}.tag.growth{color:#ecd291;background:#b1944540;border-color:#ab944e40}\n.hero-icon-wrap{--icon-size:120px;--magic-size:calc(var(--magic-base) * 1.5px);position:relative;flex-shrink:0;width:var(--magic-size);height:var(--magic-size)}\n.magic-circle{position:absolute;width:100%;height:100%;top:50%;left:50%;transform:translate(-50%,-50%);color:var(--quality-end);pointer-events:none;overflow:visible}\n.magic-rays{stroke:currentColor;stroke-width:.9;opacity:.28}.magic-orbits{stroke:currentColor;stroke-width:1.2;opacity:.42}.magic-detail{stroke:currentColor;stroke-width:.9;opacity:.45}.magic-marks{fill:currentColor;opacity:.68}\n.magic-sss .magic-rays{stroke:#ddbc80;opacity:.49}.magic-sss .magic-detail{stroke:#bb9ccc;opacity:.64}.magic-sss .magic-marks{fill:#eed093;opacity:.88}\n.quality-s .magic-circle,.quality-ss .magic-circle,.quality-sss .magic-circle{filter:drop-shadow(0 0 4px color-mix(in srgb,var(--quality-accent) 30%,transparent))}\n.skill-artwork,.art-fallback{position:absolute;z-index:1;top:50%;left:50%;transform:translate(-50%,-50%);width:var(--icon-size);height:var(--icon-size);border:1.5px solid #bfc6b7;border-radius:50%;box-shadow:0 4px 13px #0007;object-fit:cover;object-position:center}\n.art-fallback{display:grid;place-items:center;color:var(--quality-end);font:44px 'KaiTi','SimSun',serif;background:radial-gradient(circle,#53615b,#1f2928)}\n.skill-icon-frame{position:absolute;top:50%;left:50%;width:calc(var(--icon-size) + 45px);height:calc(var(--icon-size) + 45px);transform:translate(-50%,-50%);z-index:2;color:var(--quality-accent);pointer-events:none;filter:drop-shadow(0 1px 1px #10181480)}\n.quality-sss .hero-icon-wrap{background:radial-gradient(ellipse,#ad85d525,transparent 68%)}\n.card-body{padding:32px 36px 34px;background:linear-gradient(145deg,#faf9f3,#eeeee7)}\n.effect-stats{display:grid;gap:9px;margin-bottom:27px}\n.stat-row{display:flex;align-items:center;justify-content:space-between;gap:18px;min-height:54px;padding:13px 18px;background:#e5e7de;border-radius:6px;font-size:24px}\n.stat-row>span{color:#626d57;flex:0 0 auto;max-width:45%;overflow-wrap:anywhere}\n.stat-row b{min-width:0;text-align:right;overflow-wrap:anywhere;font-size:30px;color:var(--quality-ink);font-weight:600}\n.stat-row.detail-stat b{font-size:26px;font-weight:500;color:#4f594b;background:none;-webkit-text-fill-color:currentColor}\n.stat-row .param-unit{font-size:24px;font-weight:400;color:#75816d;-webkit-text-fill-color:currentColor}\n.stat-value{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:flex-end;gap:9px}\n.stat-value .stat-unit{font-size:24px;font-weight:400;color:#737c68;-webkit-text-fill-color:currentColor}\n.section-heading{display:flex;align-items:center;gap:10px;margin:0 0 16px;font-size:24px;font-weight:500;letter-spacing:2px;color:#6f7d60}\n.section-heading:before{content:'\u25C6';font-size:10px;color:var(--quality-accent)}\n.description{font-size:28px;line-height:1.85;color:#515b4c;overflow-wrap:anywhere;white-space:pre-wrap}\n.description .number{color:var(--quality-ink);font-weight:600}.description .keyword{color:#907843;font-weight:500}\n.growth-section,.note-section{border-top:1px solid #d6dacd;margin-top:27px;padding-top:24px}\n.growth-section .description{color:#5c684f}\n.note-section .description{font-size:26px;color:#626d57}\n.quality-sss .card-titlebar{background:linear-gradient(110deg,#7c679e,#a77c95 50%,#cba770)}\n.quality-sss .quality-badge{border-color:#d3c192}\n.quality-sss .stat-number{background:linear-gradient(90deg,#936891,#ab884d);background-clip:text;-webkit-text-fill-color:transparent}\n";
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import type { Session } from 'koishi';
|
|
2
1
|
import { type IMessage } from '../../shared/face';
|
|
3
|
-
import type { MsgMessage } from '../../shared/bot/MsgMessage';
|
|
4
2
|
/** Render command help and ordinary prose with clickable bracketed commands. */
|
|
5
3
|
export declare function renderQQCommandMarkdown(data: IMessage, showGreeting: boolean): string;
|
|
6
|
-
export declare function sendQQCommand(session: Session, data: MsgMessage): Promise<void>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Session } from 'koishi';
|
|
2
2
|
import { type IMessage, type PageNavData } from '../../shared/face';
|
|
3
3
|
import type { MsgMessage } from '../../shared/bot/MsgMessage';
|
|
4
|
-
import {
|
|
4
|
+
import type { QQKeyboard } from './qqMessageButtons';
|
|
5
5
|
export { escapeMarkdown, renderQQTitle } from './qqMarkdownHelpers';
|
|
6
6
|
export declare function inlineCommandUrl(command: string): string;
|
|
7
7
|
export declare function hasInlineCommands(content: string): boolean;
|
|
@@ -11,7 +11,5 @@ export declare function pageCommandLines(nav: PageNavData): string[];
|
|
|
11
11
|
export declare function renderQQPageMarkdown(data: IMessage, showGreeting: boolean): string;
|
|
12
12
|
/** Returns false if this is not the matching QQ session or the adapter has no native API. */
|
|
13
13
|
export declare function canSendQQPage(session: Session | undefined, data: MsgMessage): session is Session;
|
|
14
|
-
/** Send a native QQ Markdown page with inline command links. */
|
|
15
|
-
export declare function sendQQPage(session: Session, data: MsgMessage): Promise<void>;
|
|
16
14
|
/** Reuse the adapter's native reply API for structured Markdown messages. */
|
|
17
15
|
export declare function sendQQMarkdown(session: Session, markdown: string, keyboard?: QQKeyboard): Promise<void>;
|
|
@@ -3,7 +3,7 @@ export declare function hasRewardLines(data: Pick<IMessage, 'line'>): boolean;
|
|
|
3
3
|
/** The message marker also covers empty rewards and attachments already claimed. */
|
|
4
4
|
export declare function isRewardMessage(data: Pick<IMessage, 'line' | 'reward'>): boolean;
|
|
5
5
|
export declare function renderRewardTitle(content: string): string;
|
|
6
|
-
/** Reward names
|
|
7
|
-
export declare function renderRewardLine(content: string): string;
|
|
6
|
+
/** Reward names stay literal; a supplied action links the name, keeping its signed quantity emphasized. */
|
|
7
|
+
export declare function renderRewardLine(content: string, command?: string): string;
|
|
8
8
|
/** Reward cards stay compact; mail keeps its content before the attachment quote. */
|
|
9
9
|
export declare function renderQQRewardMarkdown(data: IMessage, showGreeting: boolean): string;
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import type { Session } from 'koishi';
|
|
2
1
|
import { type IMessage } from '../../shared/face';
|
|
3
|
-
import type { MsgMessage } from '../../shared/bot/MsgMessage';
|
|
4
2
|
export declare function hasStoryCodeBlock(data: Pick<IMessage, 'line'>): boolean;
|
|
5
3
|
/** Marked stories keep their complete text; settled rewards use the shared reward card. */
|
|
6
4
|
export declare function renderQQStoryMarkdown(data: IMessage, showGreeting: boolean): string;
|
|
7
|
-
export declare function sendQQStory(session: Session, data: MsgMessage): Promise<void>;
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import type { Session } from 'koishi';
|
|
2
1
|
import { type IMessage } from '../../shared/face';
|
|
3
|
-
import type { MsgMessage } from '../../shared/bot/MsgMessage';
|
|
4
2
|
/** Render only explicitly marked transactions; line content never enables this channel. */
|
|
5
3
|
export declare function renderQQTransactionMarkdown(data: IMessage, showGreeting: boolean): string;
|
|
6
|
-
export declare function sendQQTransaction(session: Session, data: MsgMessage): Promise<void>;
|
|
@@ -4,6 +4,5 @@ export interface SigninPortraitArtwork {
|
|
|
4
4
|
name: string;
|
|
5
5
|
framing: 'full-body' | 'waist-up';
|
|
6
6
|
}
|
|
7
|
-
export declare const SIGNIN_CARD_WIDTH = 760;
|
|
8
7
|
/** Pure markup shared by the real bot screenshot and the editor's chat preview. */
|
|
9
8
|
export declare function signinCardHtml(card: SigninCardData, artwork?: Array<string | undefined>, portrait?: SigninPortraitArtwork): string;
|
|
@@ -175,6 +175,11 @@ export interface EquipmentCardData {
|
|
|
175
175
|
}>;
|
|
176
176
|
notes?: string[];
|
|
177
177
|
authorName?: string;
|
|
178
|
+
/** 独立随机副词条,旧装备缺省时仅展示基础属性。 */
|
|
179
|
+
randomAffixes?: Array<{
|
|
180
|
+
name: string;
|
|
181
|
+
value: string;
|
|
182
|
+
}>;
|
|
178
183
|
}
|
|
179
184
|
export interface LeaderboardImageData {
|
|
180
185
|
backgroundUrl?: string;
|
|
@@ -217,6 +222,10 @@ export interface SkillCardData {
|
|
|
217
222
|
tags: string[];
|
|
218
223
|
sources: string[];
|
|
219
224
|
note: string;
|
|
225
|
+
/** 当前技能品质内已点亮的星数;缺省为旧版卡片。 */
|
|
226
|
+
stars?: number;
|
|
227
|
+
/** 当前品质允许的最高星数;0 表示该品质没有额外星级。 */
|
|
228
|
+
maxStars?: number;
|
|
220
229
|
}
|
|
221
230
|
/** 客户端按此字段选择发送通道;第一阶段只有文字 **/
|
|
222
231
|
export declare enum MessageHandleType {
|
package/package.json
CHANGED
|
@@ -15,7 +15,10 @@ export function equipmentCardHtml(card: EquipmentCardData, artwork?: string, unk
|
|
|
15
15
|
].join('')
|
|
16
16
|
const affixes = card.affixes?.length
|
|
17
17
|
? '<div class="detail-list">' + card.affixes.map(affix => cardStatRow(affix.name, affix.value)).join('') + '</div>'
|
|
18
|
-
: '<p class="description"
|
|
18
|
+
: '<p class="description">暂无基础属性</p>'
|
|
19
|
+
const randomAffixes = card.randomAffixes?.length
|
|
20
|
+
? cardSection('随机词条', '<div class="detail-list">' + card.randomAffixes.map(affix => cardStatRow(affix.name, affix.value)).join('') + '</div>')
|
|
21
|
+
: ''
|
|
19
22
|
const skills = card.skills?.length
|
|
20
23
|
? cardSection('附带技能', '<div class="detail-list">' + card.skills.map(skill => cardStatRow(skill.name, '')).join('') + '</div>')
|
|
21
24
|
: ''
|
|
@@ -34,6 +37,6 @@ export function equipmentCardHtml(card: EquipmentCardData, artwork?: string, unk
|
|
|
34
37
|
fallbackGlyph: '?',
|
|
35
38
|
sheetClass: 'equipment-sheet',
|
|
36
39
|
tags: unknownFallback || !artwork ? ['外观暂未显现'] : [],
|
|
37
|
-
body: '<div class="effect-stats">' + details + '</div>' + cardSection('
|
|
40
|
+
body: '<div class="effect-stats">' + details + '</div>' + cardSection('基础属性', affixes) + randomAffixes + skills + description + notes,
|
|
38
41
|
})
|
|
39
42
|
}
|
|
@@ -31,6 +31,12 @@ h1,h2,h3,p{margin:0}
|
|
|
31
31
|
.skill-type{font-size:24px;letter-spacing:3px;color:#cbcdbd}
|
|
32
32
|
.quality-badge{display:inline-flex;align-items:center;gap:9px;padding:6px 14px;color:#fff5de;font-size:18px;font-weight:600;border:1px solid color-mix(in srgb,var(--quality-accent) 70%,transparent);border-radius:6px;background:color-mix(in srgb,var(--quality-accent) 17%,transparent)}
|
|
33
33
|
.quality-badge b{color:var(--quality-end);font:700 24px Georgia,serif}
|
|
34
|
+
.skill-stars{display:flex;align-items:center;flex-wrap:wrap;gap:3px;max-width:100%;margin-top:-8px}
|
|
35
|
+
.skill-star{display:block;flex:0 0 40px;width:40px;height:40px;overflow:visible;filter:drop-shadow(0 1px 1px #10121780)}
|
|
36
|
+
.star-shape{stroke:#24252b;stroke-width:2.4;stroke-linejoin:round}
|
|
37
|
+
.star-gradient-light{stop-color:color-mix(in srgb,var(--quality-end) 55%,#fff)}.star-gradient-mid{stop-color:var(--quality-accent)}.star-gradient-shade{stop-color:var(--quality-start)}
|
|
38
|
+
.star-facet-light{fill:#fff;opacity:.28}.star-facet-shade{fill:#151328;opacity:.18}.star-facet-glint{fill:none;stroke:#fff;stroke-width:.7;stroke-linejoin:round;opacity:.55}
|
|
39
|
+
.skill-star.unlit .star-shape{fill:#303436;stroke:#171d22;stroke-width:2.6}
|
|
34
40
|
.tags{display:flex;gap:7px;flex-wrap:wrap}
|
|
35
41
|
.tag{font-size:20px;line-height:1.3;padding:6px 10px;border-radius:4px;overflow-wrap:anywhere;color:#bfcaed;background:#647bb434;border:1px solid #7d9cc62b}
|
|
36
42
|
.tag.damage{color:#f5ae94;background:#b961433d;border-color:#b4614340}.tag.shield{color:#a3d7b7;background:#5186683d;border-color:#73a48a40}.tag.heal{color:#b5deb0;background:#668e4a3b;border-color:#89a47140}.tag.passive{color:#cebbef;background:#8367a63d;border-color:#9682b540}.tag.growth{color:#ecd291;background:#b1944540;border-color:#ab944e40}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { withoutMessageButtonFallbacks } from '../../shared/bot/analysisMsg'
|
|
2
|
-
import { renderQQKeyboard } from './qqMessageButtons'
|
|
3
|
-
import type { Session } from 'koishi'
|
|
4
2
|
import { MessageType, type IMessage } from '../../shared/face'
|
|
5
|
-
import
|
|
6
|
-
import { escapeMarkdown, renderInlineCommands, renderQQPageMarkdown, renderQQTitle, sendQQMarkdown } from './qqPageMessage'
|
|
3
|
+
import { escapeMarkdown, renderInlineCommands, renderQQPageMarkdown, renderQQTitle } from './qqPageMessage'
|
|
7
4
|
import { isRewardMessage, renderRewardLine, renderRewardTitle } from './qqRewardMessage'
|
|
8
5
|
|
|
9
6
|
/** Render command help and ordinary prose with clickable bracketed commands. */
|
|
@@ -73,7 +70,3 @@ export function renderQQCommandMarkdown(data: IMessage, showGreeting: boolean):
|
|
|
73
70
|
flushRewards()
|
|
74
71
|
return sections.join('\n\n') || ' '
|
|
75
72
|
}
|
|
76
|
-
|
|
77
|
-
export async function sendQQCommand(session: Session, data: MsgMessage): Promise<void> {
|
|
78
|
-
await sendQQMarkdown(session, renderQQCommandMarkdown(data, session.event?.channel?.type === 0), renderQQKeyboard(data))
|
|
79
|
-
}
|
|
@@ -36,6 +36,7 @@ export function renderQQMessagePreview(data: IMessage, showGreeting = false): QQ
|
|
|
36
36
|
if (hasStoryCodeBlock(data)) return native('story', renderQQStoryMarkdown(data, showGreeting))
|
|
37
37
|
if (data.commandHelp) return native('command', renderQQCommandMarkdown(data, showGreeting))
|
|
38
38
|
if (data.transaction) return native('transaction', renderQQTransactionMarkdown(data, showGreeting))
|
|
39
|
+
if (data.mail) return native('reward', renderQQRewardMarkdown(data, showGreeting))
|
|
39
40
|
if (data.pageNav) return native('page', renderQQPageMarkdown(data, showGreeting))
|
|
40
41
|
if (isRewardMessage(data)) return native('reward', renderQQRewardMarkdown(data, showGreeting))
|
|
41
42
|
if (battleLogMessageLinks(data).length || data.line.some(item => (item.type === MessageType.line || item.type === MessageType.error) && hasInlineCommands(item.content))) {
|
|
@@ -2,7 +2,7 @@ import type { Session } from 'koishi'
|
|
|
2
2
|
import { MessageType, type IMessage, type PageNavData } from '../../shared/face'
|
|
3
3
|
import type { MsgMessage } from '../../shared/bot/MsgMessage'
|
|
4
4
|
import { withoutMessageButtonFallbacks } from '../../shared/bot/analysisMsg'
|
|
5
|
-
import {
|
|
5
|
+
import type { QQKeyboard } from './qqMessageButtons'
|
|
6
6
|
import { compactDisplayText, escapeMarkdown, renderQQTitle } from './qqMarkdownHelpers'
|
|
7
7
|
import { isRewardMessage, renderRewardLine, renderRewardTitle } from './qqRewardMessage'
|
|
8
8
|
import { artworkIdentity } from '../skillArtwork'
|
|
@@ -57,7 +57,6 @@ export function inlineCommandUrl(command: string): string {
|
|
|
57
57
|
return `mqqapi://aio/inlinecmd?command=${encoded}&enter=true&reply=false`
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
|
|
61
60
|
/** Bracketed commands may appear anywhere in prose, including escaped brackets. */
|
|
62
61
|
function inlineCommandSpans(content: string): InlineCommandSpan[] {
|
|
63
62
|
const spans = bracketedCommandSpans(content)
|
|
@@ -359,12 +358,6 @@ export function canSendQQPage(session: Session | undefined, data: MsgMessage): s
|
|
|
359
358
|
return !!internal?.sendMessage && !!internal.sendPrivateMessage
|
|
360
359
|
}
|
|
361
360
|
|
|
362
|
-
/** Send a native QQ Markdown page with inline command links. */
|
|
363
|
-
export async function sendQQPage(session: Session, data: MsgMessage): Promise<void> {
|
|
364
|
-
const markdown = renderQQPageMarkdown(data, session.event?.channel?.type === 0)
|
|
365
|
-
await sendQQMarkdown(session, markdown, renderQQKeyboard(data))
|
|
366
|
-
}
|
|
367
|
-
|
|
368
361
|
/** Reuse the adapter's native reply API for structured Markdown messages. */
|
|
369
362
|
export async function sendQQMarkdown(session: Session, markdown: string, keyboard?: QQKeyboard): Promise<void> {
|
|
370
363
|
const internal = (session.bot as typeof session.bot & { internal: QQInternal }).internal
|
|
@@ -2,6 +2,7 @@ import { withoutMessageButtonFallbacks } from '../../shared/bot/analysisMsg'
|
|
|
2
2
|
import { MessageType, type IMessage } from '../../shared/face'
|
|
3
3
|
import { compactDisplayText, escapeMarkdown } from './qqMarkdownHelpers'
|
|
4
4
|
import { appendMissingBattleLogLinks, renderBattleLogLinkText } from './qqBattleLogLinks'
|
|
5
|
+
import { inlineCommandUrl } from './qqPageMessage'
|
|
5
6
|
|
|
6
7
|
export function hasRewardLines(data: Pick<IMessage, 'line'>): boolean {
|
|
7
8
|
return data.line.some(item => item.type === MessageType.line && item.reward === true)
|
|
@@ -16,20 +17,24 @@ export function renderRewardTitle(content: string): string {
|
|
|
16
17
|
return `**${escapeMarkdown(compactDisplayText(content))}**`
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
/** Reward names
|
|
20
|
-
export function renderRewardLine(content: string): string {
|
|
20
|
+
/** Reward names stay literal; a supplied action links the name, keeping its signed quantity emphasized. */
|
|
21
|
+
export function renderRewardLine(content: string, command?: string): string {
|
|
21
22
|
return content.replace(/\r\n?/g, '\n').split('\n').filter(line => line.trim()).map(line => {
|
|
22
23
|
const text = line.trim()
|
|
23
24
|
const quantity = /([++\-−×xX]\s*\d+(?:\.\d+)?)$/.exec(text)
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const label = quantity ? text.slice(0, quantity.index) : text
|
|
26
|
+
const name = label.trimEnd()
|
|
27
|
+
const formattedName = command && name
|
|
28
|
+
? `[${escapeMarkdown(name)}](${inlineCommandUrl(command)})${escapeMarkdown(label.slice(name.length))}`
|
|
29
|
+
: escapeMarkdown(label)
|
|
30
|
+
const formatted = formattedName + (quantity ? `**${escapeMarkdown(quantity[1])}**` : '')
|
|
27
31
|
return '> ' + formatted
|
|
28
32
|
}).join(' \n')
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
/** Mail sections retain their order so each attachment stays with its own message. */
|
|
32
36
|
function renderQQMailMarkdown(data: IMessage): string {
|
|
37
|
+
const commands = new Map(data.pageNav?.entries?.map(entry => [entry.lineIndex, entry.viewCommand]) ?? [])
|
|
33
38
|
const sections: string[] = []
|
|
34
39
|
const text: string[] = []
|
|
35
40
|
const rewards: string[] = []
|
|
@@ -39,7 +44,7 @@ function renderQQMailMarkdown(data: IMessage): string {
|
|
|
39
44
|
const flushRewards = () => {
|
|
40
45
|
if (rewards.length) sections.push(rewards.splice(0).join(' \n'))
|
|
41
46
|
}
|
|
42
|
-
for (const item of data.line) {
|
|
47
|
+
for (const [lineIndex, item] of data.line.entries()) {
|
|
43
48
|
if (item.type === MessageType.title || (item.type === MessageType.line && item.mailPart === 'title')) {
|
|
44
49
|
flushText()
|
|
45
50
|
flushRewards()
|
|
@@ -51,7 +56,7 @@ function renderQQMailMarkdown(data: IMessage): string {
|
|
|
51
56
|
.map(line => '> ' + escapeMarkdown(line)).join(' \n'))
|
|
52
57
|
} else if (item.type === MessageType.line && item.reward) {
|
|
53
58
|
flushText()
|
|
54
|
-
const reward = renderRewardLine(item.content)
|
|
59
|
+
const reward = renderRewardLine(item.content, commands.get(lineIndex))
|
|
55
60
|
if (reward) rewards.push(reward)
|
|
56
61
|
} else {
|
|
57
62
|
flushRewards()
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { withoutMessageButtonFallbacks } from '../../shared/bot/analysisMsg'
|
|
2
|
-
import { renderQQKeyboard } from './qqMessageButtons'
|
|
3
|
-
import type { Session } from 'koishi'
|
|
4
2
|
import { MessageType, type IMessage } from '../../shared/face'
|
|
5
|
-
import
|
|
6
|
-
import { escapeMarkdown, renderInlineCommands, renderQQTitle, sendQQMarkdown } from './qqPageMessage'
|
|
3
|
+
import { escapeMarkdown, renderInlineCommands, renderQQTitle } from './qqPageMessage'
|
|
7
4
|
import { renderBattleLogLinkText } from './qqBattleLogLinks'
|
|
8
5
|
import { isRewardMessage, renderQQRewardMarkdown, renderRewardLine, renderRewardTitle } from './qqRewardMessage'
|
|
9
6
|
|
|
@@ -76,7 +73,3 @@ export function renderQQStoryMarkdown(data: IMessage, showGreeting: boolean): st
|
|
|
76
73
|
flushRewards()
|
|
77
74
|
return sections.join('\n\n') || ' '
|
|
78
75
|
}
|
|
79
|
-
|
|
80
|
-
export async function sendQQStory(session: Session, data: MsgMessage): Promise<void> {
|
|
81
|
-
await sendQQMarkdown(session, renderQQStoryMarkdown(data, session.event?.channel?.type === 0), renderQQKeyboard(data))
|
|
82
|
-
}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { withoutMessageButtonFallbacks } from '../../shared/bot/analysisMsg'
|
|
2
|
-
import { renderQQKeyboard } from './qqMessageButtons'
|
|
3
|
-
import type { Session } from 'koishi'
|
|
4
2
|
import { MessageType, type IMessage } from '../../shared/face'
|
|
5
|
-
import
|
|
6
|
-
import { escapeMarkdown, inlineCommandUrl, renderInlineCommands, renderQQTitle, sendQQMarkdown } from './qqPageMessage'
|
|
3
|
+
import { escapeMarkdown, inlineCommandUrl, renderInlineCommands, renderQQTitle } from './qqPageMessage'
|
|
7
4
|
import { isRewardMessage, renderRewardLine, renderRewardTitle } from './qqRewardMessage'
|
|
8
5
|
|
|
9
6
|
/** Render only explicitly marked transactions; line content never enables this channel. */
|
|
@@ -91,7 +88,3 @@ export function renderQQTransactionMarkdown(data: IMessage, showGreeting: boolea
|
|
|
91
88
|
flush()
|
|
92
89
|
return sections.join('\n\n') || ' '
|
|
93
90
|
}
|
|
94
|
-
|
|
95
|
-
export async function sendQQTransaction(session: Session, data: MsgMessage): Promise<void> {
|
|
96
|
-
await sendQQMarkdown(session, renderQQTransactionMarkdown(data, session.event?.channel?.type === 0), renderQQKeyboard(data))
|
|
97
|
-
}
|
|
@@ -8,7 +8,6 @@ export interface SigninPortraitArtwork {
|
|
|
8
8
|
framing: 'full-body' | 'waist-up'
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export const SIGNIN_CARD_WIDTH = 760
|
|
12
11
|
const check = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m20 6-11 11-5-5"/></svg>'
|
|
13
12
|
const progressCheck = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 11 3 3L22 4"/><path d="M21 12v1a9 9 0 1 1-5.34-8.23"/></svg>'
|
|
14
13
|
const clock = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 6v6h4"/></svg>'
|
|
@@ -24,6 +24,25 @@ function tagClass(tag: string): string {
|
|
|
24
24
|
return ''
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/** Each star is a small faceted gem; progression numbers stay in the accessible label. */
|
|
28
|
+
function skillStars(card: SkillCardData): string {
|
|
29
|
+
if (card.stars === undefined && card.maxStars === undefined) return ''
|
|
30
|
+
const maxStars = Math.min(20, Math.max(0, Math.floor(Number.isFinite(card.maxStars) ? card.maxStars! : Number.isFinite(card.stars) ? card.stars! : 0)))
|
|
31
|
+
if (!maxStars) return ''
|
|
32
|
+
const stars = Math.min(maxStars, Math.max(0, Math.floor(Number.isFinite(card.stars) ? card.stars! : 0)))
|
|
33
|
+
const outline = '20,3 25.1,13.4 36.6,15.1 28.3,23.2 30.3,34.7 20,29.3 9.7,34.7 11.7,23.2 3.4,15.1 14.9,13.4'
|
|
34
|
+
const icons = Array.from({ length: maxStars }, (_, index) => {
|
|
35
|
+
const lit = index < stars
|
|
36
|
+
const gradient = 'skill-star-fill-' + index
|
|
37
|
+
return '<svg class="skill-star ' + (lit ? 'lit' : 'unlit') + '" viewBox="0 0 40 40" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg">'
|
|
38
|
+
+ (lit ? '<defs><linearGradient id="' + gradient + '" x1="0" y1="0" x2="0.7" y2="1"><stop class="star-gradient-light"/><stop offset=".48" class="star-gradient-mid"/><stop offset="1" class="star-gradient-shade"/></linearGradient></defs>' : '')
|
|
39
|
+
+ '<polygon class="star-shape" points="' + outline + '"' + (lit ? ' fill="url(#' + gradient + ')"' : '') + '/>'
|
|
40
|
+
+ (lit ? '<path class="star-facet-light" d="M20 5.7 20 20.6 5.9 16.1 15.9 14.6Z"/><path class="star-facet-shade" d="M20 20.6 28.6 32.3 26.9 22.7 34.1 16.1Z"/><path class="star-facet-glint" d="M20 6.2 20 20.6 12 31.9 13.3 23 6.5 16.6 16 15.2Z"/>' : '')
|
|
41
|
+
+ '</svg>'
|
|
42
|
+
}).join('')
|
|
43
|
+
return '<div class="skill-stars" role="img" aria-label="' + stars + ' / ' + maxStars + ' 星">' + icons + '</div>'
|
|
44
|
+
}
|
|
45
|
+
|
|
27
46
|
/** Compact skill detail with a small existing icon and quality-specific ornaments. */
|
|
28
47
|
export function skillCardHtml(card: SkillCardData, _frame = '', artwork?: string): string {
|
|
29
48
|
const quality = normalizeCardQuality(card.quality)
|
|
@@ -42,13 +61,13 @@ export function skillCardHtml(card: SkillCardData, _frame = '', artwork?: string
|
|
|
42
61
|
<div id="capture" class="skill-sheet"><article class="detail-card skill-card quality-${quality.toLowerCase()}" style="${qualityStyle(quality)}">
|
|
43
62
|
<i class="card-corner corner-tl" aria-hidden="true"></i><i class="card-corner corner-tr" aria-hidden="true"></i><i class="card-corner corner-bl" aria-hidden="true"></i><i class="card-corner corner-br" aria-hidden="true"></i>
|
|
44
63
|
<div class="card-inner"><header class="card-titlebar"><span class="title-glyph" aria-hidden="true">◇</span><h1>${escape(card.name)}</h1><span class="title-star" aria-hidden="true">✦</span></header>
|
|
45
|
-
<div class="card-hero"><div class="hero-copy"><div class="hero-meta"><span class="skill-type">${card.passive ? '被动技能' : '主动技能'}</span><span class="quality-badge"><b>${quality}</b> 级</span
|
|
64
|
+
<div class="card-hero"><div class="hero-copy"><div class="hero-meta"><span class="skill-type">${card.passive ? '被动技能' : '主动技能'}</span><span class="quality-badge"><b>${quality}</b> 级</span>${skillStars(card)}</div><div class="tags">${tags.map(tag => `<span class="tag ${tagClass(tag)}">${escape(tag)}</span>`).join('')}</div></div><div class="hero-icon-wrap">${qualityMagicCircle(quality)}<div class="art-fallback" aria-hidden="true">${card.passive ? '静' : '势'}</div>${artwork ? `<img class="skill-artwork" alt="${escape(card.name)}图标" src="${escape(artwork)}">` : ''}${qualityIconFrame(quality)}</div></div>
|
|
46
65
|
<div class="card-body"><div class="effect-stats">
|
|
47
66
|
${row('消耗', escape(card.cost || '无消耗'), true)}
|
|
48
67
|
${row('冷却', cooldownValue, true)}
|
|
49
68
|
${power ? row('战力', escape(power.replace(/^(?:🔥\s*)?战力\s*[::]\s*/, '')), true) : ''}
|
|
50
69
|
${(card.stats || []).slice(0, 3).map(stat => row(stat.label, statValue(stat.value))).join('')}
|
|
51
|
-
</div><section class="effect"><h2 class="section-heading"
|
|
70
|
+
</div><section class="effect"><h2 class="section-heading">${escape(card.mechanism || '技能效果')}</h2><p class="description">${effectText(effect)}</p></section>
|
|
52
71
|
${growth ? `<section class="growth-section"><h2 class="section-heading">永久成长 · 仅玩家</h2><p class="description">${effectText(growth)}</p></section>` : ''}
|
|
53
72
|
${otherNotes ? `<section class="note-section"><h2 class="section-heading">附加信息</h2><p class="description">${escape(otherNotes)}</p></section>` : ''}
|
|
54
73
|
</div></div></article></div></body></html>`
|
|
@@ -25,7 +25,7 @@ export interface ServiceType {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export const serviceProto: ServiceProto<ServiceType> = {
|
|
28
|
-
"version":
|
|
28
|
+
"version": 44,
|
|
29
29
|
"services": [
|
|
30
30
|
{
|
|
31
31
|
"id": 0,
|
|
@@ -889,6 +889,22 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|
|
889
889
|
"type": {
|
|
890
890
|
"type": "String"
|
|
891
891
|
}
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
"id": 15,
|
|
895
|
+
"name": "stars",
|
|
896
|
+
"type": {
|
|
897
|
+
"type": "Number"
|
|
898
|
+
},
|
|
899
|
+
"optional": true
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
"id": 16,
|
|
903
|
+
"name": "maxStars",
|
|
904
|
+
"type": {
|
|
905
|
+
"type": "Number"
|
|
906
|
+
},
|
|
907
|
+
"optional": true
|
|
892
908
|
}
|
|
893
909
|
]
|
|
894
910
|
},
|
|
@@ -1150,6 +1166,33 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|
|
1150
1166
|
"type": "String"
|
|
1151
1167
|
},
|
|
1152
1168
|
"optional": true
|
|
1169
|
+
},
|
|
1170
|
+
{
|
|
1171
|
+
"id": 13,
|
|
1172
|
+
"name": "randomAffixes",
|
|
1173
|
+
"type": {
|
|
1174
|
+
"type": "Array",
|
|
1175
|
+
"elementType": {
|
|
1176
|
+
"type": "Interface",
|
|
1177
|
+
"properties": [
|
|
1178
|
+
{
|
|
1179
|
+
"id": 0,
|
|
1180
|
+
"name": "name",
|
|
1181
|
+
"type": {
|
|
1182
|
+
"type": "String"
|
|
1183
|
+
}
|
|
1184
|
+
},
|
|
1185
|
+
{
|
|
1186
|
+
"id": 1,
|
|
1187
|
+
"name": "value",
|
|
1188
|
+
"type": {
|
|
1189
|
+
"type": "String"
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
]
|
|
1193
|
+
}
|
|
1194
|
+
},
|
|
1195
|
+
"optional": true
|
|
1153
1196
|
}
|
|
1154
1197
|
]
|
|
1155
1198
|
},
|
package/src/shared/face/index.ts
CHANGED
|
@@ -112,6 +112,8 @@ export interface EquipmentCardData {
|
|
|
112
112
|
skills: Array<{ name: string; rank: string }>;
|
|
113
113
|
notes?: string[];
|
|
114
114
|
authorName?: string;
|
|
115
|
+
/** 独立随机副词条,旧装备缺省时仅展示基础属性。 */
|
|
116
|
+
randomAffixes?: Array<{ name: string; value: string }>;
|
|
115
117
|
}
|
|
116
118
|
export interface LeaderboardImageData {
|
|
117
119
|
backgroundUrl?: string;
|
|
@@ -139,6 +141,10 @@ export interface SkillCardData {
|
|
|
139
141
|
tags: string[];
|
|
140
142
|
sources: string[];
|
|
141
143
|
note: string;
|
|
144
|
+
/** 当前技能品质内已点亮的星数;缺省为旧版卡片。 */
|
|
145
|
+
stars?: number;
|
|
146
|
+
/** 当前品质允许的最高星数;0 表示该品质没有额外星级。 */
|
|
147
|
+
maxStars?: number;
|
|
142
148
|
}
|
|
143
149
|
/** 客户端按此字段选择发送通道;第一阶段只有文字 **/
|
|
144
150
|
export enum MessageHandleType {
|