koishi-plugin-dew-bot 1.0.256 → 1.0.258
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 +432 -52
- package/lib/plugin/characterCardStyles.d.ts +1 -1
- package/lib/plugin/serverHandel/titleCardMessage.d.ts +6 -0
- package/lib/plugin/skillCard.d.ts +2 -1
- package/lib/plugin/titleCardStyles.d.ts +2 -0
- package/lib/plugin/titleCardTemplate.d.ts +3 -0
- package/lib/shared/face/index.d.ts +17 -1
- package/package.json +1 -1
- package/src/plugin/cardLayout.ts +9 -0
- package/src/plugin/characterCardStyles.ts +1 -1
- package/src/plugin/characterCardTemplate.ts +2 -2
- package/src/plugin/serverHandel/image.ts +23 -2
- package/src/plugin/serverHandel/qqPageMessage.ts +15 -9
- package/src/plugin/serverHandel/qqTransactionMessage.ts +21 -3
- package/src/plugin/serverHandel/titleCardMessage.ts +25 -0
- package/src/plugin/skillCard.ts +41 -21
- package/src/plugin/titleCardStyles.ts +121 -0
- package/src/plugin/titleCardTemplate.ts +85 -0
- package/src/shared/bot/analysisMsg.ts +1 -1
- package/src/shared/bot/serviceProto.ts +85 -1
- package/src/shared/face/index.ts +14 -2
package/lib/index.js
CHANGED
|
@@ -319,7 +319,7 @@ var characterCardStyles = `
|
|
|
319
319
|
.character-sheet .companion-portrait:before{inset:5px;border-radius:12px;border-color:#fffdf1cf;box-shadow:0 0 0 1px color-mix(in srgb,var(--accent) 43%,transparent)}.character-sheet .companion-portrait:after{inset:2px;border-radius:15px;border-color:#fffefa9c}.character-sheet .companion-portrait .panel-corner{width:var(--portrait-ornament-size);height:var(--portrait-ornament-size)}
|
|
320
320
|
.character-sheet .portrait-window{height:auto;border:2px solid var(--edge);border-radius:6px;overflow:hidden;background:var(--paper)}.character-artwork{display:block;width:100%;height:auto;object-fit:contain}.character-sheet .portrait-placeholder,.character-sheet .placeholder{height:100%;width:100%;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:12px;color:var(--subtle);font:21px/1.5 "Microsoft YaHei",sans-serif}.character-sheet .placeholder small{font-size:16px}.character-sheet .portrait-window>.placeholder{height:448px}
|
|
321
321
|
.character-stats{padding:17px 18px 15px;display:flex;flex-direction:column}.character-stats>.character-identity,.character-stats>.combat-row,.character-stats>.resource,.character-stats>.attribute-panel{position:relative;z-index:4}
|
|
322
|
-
.character-identity{text-align:center;min-width:0}.title-image-slot{
|
|
322
|
+
.character-identity{text-align:center;min-width:0}.title-image-slot{position:absolute;inset:12px;display:flex;align-items:center;justify-content:center;min-width:0;z-index:4;pointer-events:none}.title-artwork{display:block;width:auto;height:auto;max-width:100%;max-height:min(110px,100%);object-fit:contain;filter:drop-shadow(0 2px 3px #17213a70)}.title-artwork[alt="称号图片占位"]{max-width:min(244px,100%);max-height:min(44px,100%)}
|
|
323
323
|
.character-name{font-size:43px;line-height:1.17;font-weight:700;letter-spacing:3px;margin:0 0 3px;overflow-wrap:anywhere;color:var(--ink);text-shadow:0 1px 0 #ffffff}.character-level{font:27px/1.25 Georgia,"Microsoft YaHei",serif;margin:0;color:var(--subtle);display:flex;align-items:baseline;justify-content:center;gap:7px;min-width:0}.character-level strong{font-size:28px;font-weight:500;overflow-wrap:anywhere;min-width:0}
|
|
324
324
|
.gene-panel{position:relative;margin:8px auto 0;padding:4px 12px 4px 7px;display:flex;align-items:center;justify-content:center;gap:6px;width:fit-content;max-width:100%;border:1px solid color-mix(in srgb,var(--edge) 80%,#ffffff);border-radius:7px;background:linear-gradient(#ffffffd6,color-mix(in srgb,var(--paper) 75%,#ffffff));box-shadow:inset 0 0 0 2px #ffffffaa,0 1px 2px #54628210}
|
|
325
325
|
.gene-panel:before,.gene-panel:after{content:"";position:absolute;top:50%;width:6px;height:6px;background:var(--light-edge);border:1px solid var(--edge);transform:translateY(-50%) rotate(45deg)}.gene-panel:before{left:-4px}.gene-panel:after{right:-4px}.gene-crest{flex:0 0 26px;height:29px;color:var(--accent)}.gene-crest svg{display:block;width:100%;height:100%}.gene-rank{font-size:18px;line-height:1.35;letter-spacing:1px;overflow-wrap:anywhere;font-weight:700;text-align:center;min-width:0;color:var(--ink)}
|
|
@@ -440,8 +440,8 @@ function characterCardHtml(card, artwork, _frame, defaultArtwork, titleArtwork,
|
|
|
440
440
|
const experience = Math.max(0, Math.min(100, finite(card.experiencePercent)));
|
|
441
441
|
const geneRank = card.geneLockRankName || "基因锁未开启";
|
|
442
442
|
return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><style>${characterCardStyles}</style></head><body><main id="capture" class="companion-sheet character-adventure character-sheet gene-tier-${tier}" data-gene-lock-tier="${tier}" data-decoration-level="${tier}"><span class="character-ambient" aria-hidden="true">${characterFloralWatermark}</span><div class="character-card companion-main">
|
|
443
|
-
<div class="portrait-column"><div class="companion-panel companion-portrait character-portrait">${corners(tier)}<div class="portrait-window portrait">${portrait ? `<img id="character-image" class="character-artwork" src="${cardEscape(portrait)}" data-fallback="${cardEscape(defaultArtwork ?? "")}" alt="${cardEscape(card.name)}的形象图">` : '<div class="placeholder"><span>形象尚未生成</span><small>角色形象</small></div>'}</div
|
|
444
|
-
<div class="title-image-slot character-title-
|
|
443
|
+
<div class="portrait-column"><div class="companion-panel companion-portrait character-portrait">${corners(tier)}<div class="portrait-window portrait">${portrait ? `<img id="character-image" class="character-artwork" src="${cardEscape(portrait)}" data-fallback="${cardEscape(defaultArtwork ?? "")}" alt="${cardEscape(card.name)}的形象图">` : '<div class="placeholder"><span>形象尚未生成</span><small>角色形象</small></div>'}</div>
|
|
444
|
+
<div class="title-image-slot character-title-centered"><img id="title-image" class="title-artwork" src="${cardEscape(titleArtwork || characterTitlePlaceholder)}" data-fallback="${cardEscape(characterTitlePlaceholder)}" alt="${titleArtwork ? "称号图片" : "称号图片占位"}"></div></div></div>
|
|
445
445
|
<section class="companion-panel companion-stats character-stats" aria-label="角色属性"><span class="character-paper-pattern" aria-hidden="true">${characterFloralWatermark}</span>${corners(tier, ["tr", "br"])}<div class="identity character-identity"><h1 id="character-name" class="character-name" title="${cardEscape(card.name)}">${cardEscape(card.name)}</h1><p class="level character-level"><span>Lv.</span><strong id="character-level">${number2(card.level)}</strong></p><div class="gene-panel"><span class="gene-crest" aria-hidden="true">${characterGeneCrest(tier)}</span><div id="gene-rank" class="gene-rank" title="${cardEscape(geneRank)}">${cardEscape(geneRank)}</div></div></div>
|
|
446
446
|
<div class="combat-row companion-power-row"><span class="power-emblem power-icon" aria-hidden="true"><svg viewBox="0 0 42 42"><path d="m9 5 5 1 16 21-4 4L9 11Zm24 0-5 1L12 27l4 4L33 11ZM14 27l14 10m0-10L14 37M9 35l4-4m20 4-4-4"/></svg></span><span class="power-label companion-power-label">战力</span><strong id="combat-power" class="power-value companion-power">${number2(card.power)}</strong></div>
|
|
447
447
|
<div class="resource companion-resource hp-resource"><div class="resource-heading"><span class="resource-label"><svg viewBox="0 0 32 32" aria-hidden="true"><path d="M16 28C6 21 2 17 2 10a7 7 0 0 1 14-2 7 7 0 0 1 14 2c0 7-4 11-14 18Z"/></svg>生命值</span><span id="hp-numbers" class="resource-number">${number2(card.hp)} / ${number2(card.maxHp)}</span></div><div class="resource-track" role="progressbar" aria-label="生命值" aria-valuemin="0" aria-valuemax="100" aria-valuenow="${hpPercent}"><span class="resource-fill fill" style="width:${hpPercent}%"></span><span class="bar-percent resource-percent">${number2(hpPercent)}%</span></div></div>
|
|
@@ -583,12 +583,226 @@ function companionCardHtml(card, artwork, icons) {
|
|
|
583
583
|
}
|
|
584
584
|
__name(companionCardHtml, "companionCardHtml");
|
|
585
585
|
|
|
586
|
+
// src/plugin/titleCardStyles.ts
|
|
587
|
+
var titleCardStyles = `
|
|
588
|
+
.title-sheet {
|
|
589
|
+
--dew-paper: light-dark(#fffaf0, #252721);
|
|
590
|
+
--dew-panel: light-dark(#f5f7f3, #2c302a);
|
|
591
|
+
--dew-ink: light-dark(#25382f, #e4eae3);
|
|
592
|
+
--dew-muted: light-dark(#737e74, #aeb8ac);
|
|
593
|
+
--dew-line: light-dark(#e5e9df, #40483c);
|
|
594
|
+
--dew-accent: light-dark(#2d7c69, #7dc6b1);
|
|
595
|
+
--dew-fill: light-dark(#2d7c6926, #7dc6b129);
|
|
596
|
+
--dew-link: light-dark(#1685df, #85bffa);
|
|
597
|
+
--dew-frame: light-dark(#b79c62, #a48a50);
|
|
598
|
+
--dew-frame-shadow: light-dark(#4a39251c, #00000042);
|
|
599
|
+
--dew-paper-top: light-dark(#fff7e5, #30362c);
|
|
600
|
+
--dew-paper-bottom: light-dark(#f7f2e8, #18231e);
|
|
601
|
+
--dew-gold-light: light-dark(#ead4a1, #dec58a);
|
|
602
|
+
--dew-gold-dark: light-dark(#94713d, #786136);
|
|
603
|
+
--dew-hero-glow: light-dark(#d4a64d20, #d4a64d19);
|
|
604
|
+
--dew-grid: light-dark(#b8bfae70, #9eaf8d26);
|
|
605
|
+
--dew-axis-ink: light-dark(#7c714e, #c4b68d);
|
|
606
|
+
padding: 52px 32px 48px; box-sizing: border-box;
|
|
607
|
+
display: flex; justify-content: center; align-items: flex-start;
|
|
608
|
+
font: 28px/1.6 'Microsoft YaHei', 'PingFang SC', system-ui, sans-serif;
|
|
609
|
+
color: var(--dew-ink);
|
|
610
|
+
}
|
|
611
|
+
.title-sheet .dew-preview { width: min(100%, 748px); }
|
|
612
|
+
.title-sheet .dew-card { position: relative; background: linear-gradient(155deg, var(--dew-paper-top), var(--dew-paper-bottom) 74%); border: 2.8px solid var(--dew-frame); border-radius: var(--dew-card-radius, 32px); overflow: hidden; box-shadow: 0 36px 64px var(--dew-frame-shadow), inset 0 0 0 4px var(--dew-paper), inset 0 0 0 6px color-mix(in srgb, var(--dew-gold-light) 38%, transparent); }
|
|
613
|
+
.title-sheet .dew-card::before { content: ''; position: absolute; inset: 16px; border: 2px solid color-mix(in srgb, var(--dew-frame) 60%, transparent); border-radius: max(0px, calc(var(--dew-card-radius, 32px) - 16px)); pointer-events: none; }
|
|
614
|
+
.title-sheet .dew-card::after { content: ''; position: absolute; inset: 18px; border-radius: max(0px, calc(var(--dew-card-radius, 32px) - 18px)); pointer-events: none; background: repeating-linear-gradient(0deg, transparent 0, transparent 6px, light-dark(#977b3810, #e9dbaa06) 6px, light-dark(#977b3810, #e9dbaa06) 8px); opacity: .6; }
|
|
615
|
+
.title-sheet .dew-corner { position: absolute; width: 38px; height: 38px; color: var(--dew-gold-light); pointer-events: none; }
|
|
616
|
+
.title-sheet .dew-corner::after { content: ''; position: absolute; inset: 10px; border: inherit; color: var(--dew-frame); opacity: .6; }
|
|
617
|
+
.title-sheet .dew-corner.tl { left: 24px; top: 24px; border-left: 3px solid; border-top: 3px solid; }
|
|
618
|
+
.title-sheet .dew-corner.tr { right: 24px; top: 24px; border-right: 3px solid; border-top: 3px solid; }
|
|
619
|
+
.title-sheet .dew-corner.bl { left: 24px; bottom: 24px; border-left: 3px solid; border-bottom: 3px solid; }
|
|
620
|
+
.title-sheet .dew-corner.br { right: 24px; bottom: 24px; border-right: 3px solid; border-bottom: 3px solid; }
|
|
621
|
+
.title-sheet .dew-head { display: flex; justify-content: flex-end; align-items: center; gap: 32px; padding: 52px 58px 0; }
|
|
622
|
+
.title-sheet .dew-section { font-size: 26px; letter-spacing: .28em; color: var(--dew-axis-ink); }
|
|
623
|
+
.title-sheet .dew-section::after { content: ''; display: block; width: 36px; height: 2px; margin-top: 14px; background: var(--dew-frame); }
|
|
624
|
+
.title-sheet .dew-quality { position: relative; display: flex; align-items: center; gap: 16px; font-size: 22px; padding: 0; }
|
|
625
|
+
.title-sheet .dew-quality b { display: grid; place-items: center; width: 68px; height: 76px; clip-path: polygon(50% 0, 100% 24%, 100% 76%, 50% 100%, 0 76%, 0 24%); background: linear-gradient(145deg, var(--dew-gold-light), var(--dew-frame) 54%, var(--dew-gold-dark)); font: 500 46px/1 Georgia, serif; color: light-dark(#4c391f, #342a19); }
|
|
626
|
+
.title-sheet .dew-quality span { color: var(--dew-axis-ink); writing-mode: vertical-rl; letter-spacing: .15em; }
|
|
627
|
+
.title-sheet .dew-banner { position: relative; height: 278px; display: flex; align-items: center; justify-content: center; padding: 0 34px; background: radial-gradient(ellipse at 50% 52%, var(--dew-hero-glow), transparent 67%); }
|
|
628
|
+
.title-sheet .dew-banner img { position: relative; width: 94%; height: auto; object-fit: contain; display: block; filter: drop-shadow(0 8px 18px light-dark(#9b773620, #0000004d)); }
|
|
629
|
+
.title-sheet .dew-divider { position: relative; height: 20px; margin: 0 58px; }
|
|
630
|
+
.title-sheet .dew-divider::before, .title-sheet .dew-divider::after { content: ''; position: absolute; top: 10px; width: calc(50% - 28px); height: 2px; background: linear-gradient(90deg, transparent, var(--dew-frame)); }
|
|
631
|
+
.title-sheet .dew-divider::before { left: 0; }
|
|
632
|
+
.title-sheet .dew-divider::after { right: 0; transform: rotate(180deg); }
|
|
633
|
+
.title-sheet .dew-divider span { position: absolute; left: calc(50% - 6px); top: 4px; width: 12px; height: 12px; transform: rotate(45deg); border: 2px solid var(--dew-gold-light); background: color-mix(in srgb, var(--dew-frame) 25%, transparent); box-sizing: border-box; }
|
|
634
|
+
.title-sheet .dew-divider span::after { content: ''; position: absolute; inset: -8px; border: 2px solid color-mix(in srgb, var(--dew-frame) 32%, transparent); }
|
|
635
|
+
.title-sheet .dew-radar-heading { margin: 36px 0 0; text-align: center; font-size: 22px; letter-spacing: .24em; color: var(--dew-axis-ink); }
|
|
636
|
+
.title-sheet .dew-radar { display: block; width: 100%; height: 606px; }
|
|
637
|
+
.title-sheet .dew-radar text { font-family: 'Microsoft YaHei', 'PingFang SC', system-ui, sans-serif; }
|
|
638
|
+
.title-sheet .dew-radar .dew-grid { fill: none; stroke: var(--dew-grid); stroke-width: 1; }
|
|
639
|
+
.title-sheet .dew-radar .dew-spoke { stroke: var(--dew-grid); stroke-width: 1; }
|
|
640
|
+
.title-sheet .dew-radar .dew-area { fill: url(#dew-title-radar-fill); stroke: var(--dew-accent); stroke-width: 1.8; stroke-linejoin: round; }
|
|
641
|
+
.title-sheet .dew-radar .dew-dot { fill: var(--dew-accent); stroke: var(--dew-paper-bottom); stroke-width: .7; }
|
|
642
|
+
.title-sheet .dew-radar .dew-glow { fill: var(--dew-accent); opacity: .12; }
|
|
643
|
+
.title-sheet .dew-radar .dew-axis { fill: var(--dew-axis-ink); font-size: 24px; }
|
|
644
|
+
.title-sheet .dew-radar .dew-value { fill: var(--dew-ink); font-size: 36px; font-weight: 500; letter-spacing: .01em; }
|
|
645
|
+
.title-sheet .dew-chart-space { padding: 0 38px 44px; }
|
|
646
|
+
.title-sheet .dew-actions { display: flex; align-items: center; gap: 24px; padding: 32px 14px 8px; flex-wrap: wrap; }
|
|
647
|
+
.title-sheet .dew-reset { background: transparent; border: 0; padding: 0; font: inherit; color: var(--dew-link); }
|
|
648
|
+
.title-sheet .dew-action-description { color: var(--dew-muted); font-size: 24px; }
|
|
649
|
+
.title-sheet .dew-notice { margin: 0 0 24px 14px; color: var(--dew-accent); font-size: 24px; }
|
|
650
|
+
.title-sheet .dew-crest { position: absolute; top: 34px; left: calc(50% - 6px); width: 12px; height: 12px; transform: rotate(45deg); border: 2px solid var(--dew-frame); pointer-events: none; }
|
|
651
|
+
.title-sheet .dew-quality .dew-quality-crown { display: none; position: absolute; top: -20px; left: 10px; width: 56px; height: 26px; background: linear-gradient(130deg, var(--dew-gold-light), var(--dew-frame)); clip-path: polygon(0 100%, 0 23%, 23% 58%, 50% 0, 77% 58%, 100% 23%, 100% 100%); }
|
|
652
|
+
.title-sheet .dew-quality-wings { display: none; position: absolute; left: -30px; right: 24px; top: 24px; height: 44px; pointer-events: none; }
|
|
653
|
+
.title-sheet .dew-quality-wings::before, .title-sheet .dew-quality-wings::after { content: ''; position: absolute; width: 36px; height: 36px; background: linear-gradient(130deg, var(--dew-gold-light), var(--dew-gold-dark)); clip-path: polygon(0 0, 100% 35%, 100% 100%, 30% 78%, 55% 57%, 15% 37%); opacity: .8; }
|
|
654
|
+
.title-sheet .dew-quality-wings::before { left: 0; }
|
|
655
|
+
.title-sheet .dew-quality-wings::after { right: 0; transform: scaleX(-1); }
|
|
656
|
+
.title-sheet .dew-aura { display: none; position: absolute; width: 360px; height: 220px; top: 50%; left: 50%; transform: translate(-50%, -50%); border: 2px solid color-mix(in srgb, var(--dew-frame) 24%, transparent); border-radius: 50%; pointer-events: none; }
|
|
657
|
+
.title-sheet .dew-orbit { fill: none; stroke: var(--dew-frame); stroke-width: .7; opacity: .25; }
|
|
658
|
+
.title-sheet .dew-tick { stroke: var(--dew-frame); stroke-width: 1; opacity: .35; }
|
|
659
|
+
.title-sheet .dew-constellation { fill: var(--dew-gold-light); opacity: .65; }
|
|
660
|
+
.title-sheet[data-quality="F"] .dew-card { background: var(--dew-paper); box-shadow: 0 8px 24px var(--dew-frame-shadow); }
|
|
661
|
+
.title-sheet[data-quality="F"] .dew-card::before, .title-sheet[data-quality="F"] .dew-corner, .title-sheet[data-quality="F"] .dew-crest, .title-sheet[data-quality="F"] .dew-section::after { display: none; }
|
|
662
|
+
.title-sheet[data-quality="F"] .dew-card::after { opacity: .16; }
|
|
663
|
+
.title-sheet[data-quality="F"] .dew-quality b { width: 56px; height: 56px; clip-path: none; border-radius: 8px; background: var(--dew-panel); color: var(--dew-ink); }
|
|
664
|
+
.title-sheet[data-quality="F"] .dew-banner { background: none; }
|
|
665
|
+
.title-sheet[data-quality="F"] .dew-banner img { filter: none; }
|
|
666
|
+
.title-sheet[data-quality="F"] .dew-divider span::after, .title-sheet[data-quality="F"] .dew-glow { display: none; }
|
|
667
|
+
.title-sheet[data-quality="E"] .dew-card { box-shadow: 0 12px 30px var(--dew-frame-shadow), inset 0 0 0 4px var(--dew-paper); }
|
|
668
|
+
.title-sheet[data-quality="E"] .dew-card::before, .title-sheet[data-quality="E"] .dew-corner.tr, .title-sheet[data-quality="E"] .dew-corner.bl, .title-sheet[data-quality="E"] .dew-crest { display: none; }
|
|
669
|
+
.title-sheet[data-quality="E"] .dew-corner { width: 24px; height: 24px; }
|
|
670
|
+
.title-sheet[data-quality="E"] .dew-corner::after { display: none; }
|
|
671
|
+
.title-sheet[data-quality="E"] .dew-quality b { width: 60px; height: 64px; clip-path: polygon(10px 0, calc(100% - 10px) 0, 100% 10px, 100% calc(100% - 10px), calc(100% - 10px) 100%, 10px 100%, 0 calc(100% - 10px), 0 10px); }
|
|
672
|
+
.title-sheet[data-quality="E"] .dew-banner { background: none; }
|
|
673
|
+
.title-sheet[data-quality="D"] .dew-corner::after { display: none; }
|
|
674
|
+
.title-sheet[data-quality="D"] .dew-card::after { opacity: .22; }
|
|
675
|
+
.title-sheet[data-quality="C"] .dew-quality b { clip-path: polygon(0 0, 100% 0, 100% 66%, 50% 100%, 0 66%); }
|
|
676
|
+
.title-sheet[data-quality="C"] .dew-corner { width: 40px; height: 40px; }
|
|
677
|
+
.title-sheet[data-quality="B"] .dew-quality b { clip-path: polygon(50% 0, 100% 28%, 90% 72%, 50% 100%, 10% 72%, 0 28%); }
|
|
678
|
+
.title-sheet[data-quality="B"] .dew-card::after { background: repeating-linear-gradient(45deg, transparent 0, transparent 60px, color-mix(in srgb, var(--dew-frame) 7%, transparent) 60px, color-mix(in srgb, var(--dew-frame) 7%, transparent) 62px), repeating-linear-gradient(-45deg, transparent 0, transparent 60px, color-mix(in srgb, var(--dew-frame) 7%, transparent) 60px, color-mix(in srgb, var(--dew-frame) 7%, transparent) 62px); }
|
|
679
|
+
.title-sheet[data-quality="A"] .dew-quality-wings, .title-sheet[data-quality="S"] .dew-quality-wings, .title-sheet[data-quality="SS"] .dew-quality-wings, .title-sheet[data-quality="SSS"] .dew-quality-wings { display: block; }
|
|
680
|
+
.title-sheet[data-quality="A"] .dew-corner, .title-sheet[data-quality="S"] .dew-corner { width: 46px; height: 46px; }
|
|
681
|
+
.title-sheet[data-quality="A"] .dew-crest { box-shadow: 16px -16px 0 -4px var(--dew-frame), -16px 16px 0 -4px var(--dew-frame); }
|
|
682
|
+
.title-sheet[data-quality="S"] .dew-card { box-shadow: 0 36px 70px var(--dew-frame-shadow), 0 0 36px color-mix(in srgb, var(--dew-frame) 12%, transparent), inset 0 0 0 4px var(--dew-paper), inset 0 0 0 8px color-mix(in srgb, var(--dew-gold-light) 38%, transparent); }
|
|
683
|
+
.title-sheet[data-quality="S"] .dew-aura, .title-sheet[data-quality="SS"] .dew-aura, .title-sheet[data-quality="SSS"] .dew-aura { display: block; }
|
|
684
|
+
.title-sheet[data-quality="S"] .dew-corner { border-width: 4px; }
|
|
685
|
+
.title-sheet[data-quality="SS"] .dew-quality .dew-quality-crown, .title-sheet[data-quality="SSS"] .dew-quality .dew-quality-crown { display: block; }
|
|
686
|
+
.title-sheet[data-quality="SS"] .dew-card::before { border-color: var(--dew-gold-light); opacity: .6; }
|
|
687
|
+
.title-sheet[data-quality="SS"] .dew-card::after { background: radial-gradient(circle at 18% 14%, var(--dew-gold-light) 0 2px, transparent 3px), radial-gradient(circle at 80% 21%, var(--dew-gold-light) 0 2px, transparent 3px), radial-gradient(circle at 14% 70%, var(--dew-gold-light) 0 2px, transparent 3px), radial-gradient(circle at 84% 84%, var(--dew-gold-light) 0 2px, transparent 3px); opacity: .55; }
|
|
688
|
+
.title-sheet[data-quality="SS"] .dew-aura { width: 392px; height: 232px; transform: translate(-50%, -50%) rotate(-12deg); box-shadow: 0 0 0 12px color-mix(in srgb, var(--dew-frame) 4%, transparent); }
|
|
689
|
+
.title-sheet[data-quality="SSS"] .dew-card { box-shadow: 0 40px 76px var(--dew-frame-shadow), 0 0 46px color-mix(in srgb, var(--dew-frame) 15%, transparent), inset 0 0 0 4px var(--dew-paper), inset 0 0 0 8px var(--dew-gold-dark), inset 0 0 0 10px color-mix(in srgb, var(--dew-gold-light) 70%, transparent); }
|
|
690
|
+
.title-sheet[data-quality="SSS"] .dew-card::before { inset: 20px; border-color: var(--dew-gold-light); opacity: .8; }
|
|
691
|
+
.title-sheet[data-quality="SSS"] .dew-card::after { background: repeating-linear-gradient(60deg, transparent 0, transparent 78px, color-mix(in srgb, var(--dew-frame) 7%, transparent) 78px, color-mix(in srgb, var(--dew-frame) 7%, transparent) 80px), repeating-linear-gradient(-60deg, transparent 0, transparent 78px, color-mix(in srgb, var(--dew-frame) 7%, transparent) 78px, color-mix(in srgb, var(--dew-frame) 7%, transparent) 80px); opacity: .6; }
|
|
692
|
+
.title-sheet[data-quality="SSS"] .dew-corner { width: 52px; height: 52px; color: var(--dew-gold-light); border-width: 4px; }
|
|
693
|
+
.title-sheet[data-quality="SSS"] .dew-corner::after { inset: 12px; color: var(--dew-frame); }
|
|
694
|
+
.title-sheet[data-quality="SSS"] .dew-crest { width: 16px; height: 16px; left: calc(50% - 8px); background: color-mix(in srgb, var(--dew-frame) 22%, transparent); box-shadow: 18px -18px 0 -4px var(--dew-frame), -18px 18px 0 -4px var(--dew-frame); }
|
|
695
|
+
.title-sheet[data-quality="SSS"] .dew-aura { width: 372px; height: 252px; border-color: color-mix(in srgb, var(--dew-frame) 40%, transparent); box-shadow: 0 0 0 12px color-mix(in srgb, var(--dew-frame) 5%, transparent), 0 0 0 26px color-mix(in srgb, var(--dew-frame) 3%, transparent); }
|
|
696
|
+
|
|
697
|
+
html,body { margin:0; padding:0; width:760px; background:#17232b; }
|
|
698
|
+
* { box-sizing:border-box; }
|
|
699
|
+
.title-sheet { color-scheme:dark; width:760px; padding:6px; display:block; background:#17232b; --dew-ink:#edf1e9; --dew-axis-ink:color-mix(in srgb,var(--dew-gold-light) 45%,var(--dew-ink)); --dew-grid:color-mix(in srgb,var(--dew-frame) 22%,transparent); --dew-panel:color-mix(in srgb,var(--dew-paper-top) 86%,var(--dew-frame)); --dew-hero-glow:color-mix(in srgb,var(--dew-frame) 16%,transparent); }
|
|
700
|
+
.title-sheet .dew-banner img { max-height:230px; }
|
|
701
|
+
.title-sheet .title-fallback { color:var(--dew-gold-light); font-size:48px; font-weight:600; line-height:1.4; text-align:center; overflow-wrap:anywhere; max-width:100%; margin:0; padding:16px; }
|
|
702
|
+
.title-sheet [hidden] { display:none !important; }
|
|
703
|
+
/* SVG coordinates already scale with its viewBox. */
|
|
704
|
+
.title-sheet .dew-radar .dew-axis { font-size:12px; }
|
|
705
|
+
.title-sheet .dew-radar .dew-value { font-size:18px; }
|
|
706
|
+
`;
|
|
707
|
+
|
|
708
|
+
// src/plugin/titleCardTemplate.ts
|
|
709
|
+
var qualities = ["F", "E", "D", "C", "B", "A", "S", "SS", "SSS"];
|
|
710
|
+
var themes = [
|
|
711
|
+
{ radius: 10, border: 1, colors: ["#2b302c", "#222824", "#7c877a", "#b7c0ad", "#5e695d", "#a4baa9"] },
|
|
712
|
+
{ radius: 10, border: 1.1, colors: ["#2a372c", "#1e2c24", "#799b7d", "#bbc9ac", "#546f50", "#a0c599"] },
|
|
713
|
+
{ radius: 13, border: 1.25, colors: ["#2a3b40", "#1b2b32", "#83a9b4", "#d1e4e6", "#5d7e8b", "#a0d5dc"] },
|
|
714
|
+
{ radius: 14, border: 1.3, colors: ["#263a48", "#17283b", "#6d9ec7", "#c5e2f4", "#506d93", "#9dd0f5"] },
|
|
715
|
+
{ radius: 15, border: 1.45, colors: ["#3b2f48", "#241d38", "#a387ca", "#e6d2f0", "#735485", "#c8a6ec"] },
|
|
716
|
+
{ radius: 16, border: 1.5, colors: ["#3b3529", "#28261f", "#bba363", "#eed7a0", "#816335", "#ddc58c"] },
|
|
717
|
+
{ radius: 17, border: 1.8, colors: ["#432f26", "#2b211f", "#d9a45d", "#ffe0a0", "#9b682f", "#f0c580"] },
|
|
718
|
+
{ radius: 18, border: 1.9, colors: ["#30334e", "#1c233d", "#9aa7e2", "#f0dfb0", "#8b733b", "#bcccf9"] },
|
|
719
|
+
{ radius: 19, border: 2, colors: ["#344852", "#1c303a", "#c9dbdb", "#f6e6b7", "#a58b55", "#bcdfe1"] }
|
|
720
|
+
];
|
|
721
|
+
var axes = [
|
|
722
|
+
["intelligence", "智力"],
|
|
723
|
+
["spirit", "精神力"],
|
|
724
|
+
["constitution", "体质"],
|
|
725
|
+
["agility", "敏捷"],
|
|
726
|
+
["strength", "力量"],
|
|
727
|
+
["resistance", "抗性"]
|
|
728
|
+
];
|
|
729
|
+
var finite3 = /* @__PURE__ */ __name((value) => Number.isFinite(value) ? value : 0, "finite");
|
|
730
|
+
var number4 = /* @__PURE__ */ __name((value) => finite3(value).toLocaleString("zh-CN", { maximumFractionDigits: 2 }), "number");
|
|
731
|
+
function radar3(card, tier) {
|
|
732
|
+
const attributes = axes.map(([id, name2]) => {
|
|
733
|
+
const attribute = card.attributes.find((value) => value.id === id);
|
|
734
|
+
return { id, name: attribute?.name?.trim() || name2, value: finite3(attribute?.value ?? 0) };
|
|
735
|
+
});
|
|
736
|
+
const ceiling = Math.max(1, finite3(card.attributeLimit));
|
|
737
|
+
const cx = 166, cy = 151.5, radius = 91;
|
|
738
|
+
const point = /* @__PURE__ */ __name((index, distance) => {
|
|
739
|
+
const angle = -Math.PI / 2 + index * Math.PI / 3;
|
|
740
|
+
return [cx + Math.cos(angle) * distance, cy + Math.sin(angle) * distance];
|
|
741
|
+
}, "point");
|
|
742
|
+
const polygon = /* @__PURE__ */ __name((distance) => axes.map((_, index) => point(index, distance).join(",")).join(" "), "polygon");
|
|
743
|
+
const dots = attributes.map((attribute, index) => point(index, radius * Math.max(0, Math.min(1, attribute.value / ceiling))));
|
|
744
|
+
const ticks = tier >= 8 ? 48 : tier >= 6 ? 36 : 24;
|
|
745
|
+
return `<svg id="title-radar" class="dew-radar" viewBox="0 0 332 303" xmlns="http://www.w3.org/2000/svg" role="img" data-ceiling="${ceiling}" aria-label="${cardEscape(attributes.map((attribute) => attribute.name + " +" + number4(attribute.value) + "%").join(","))}">
|
|
746
|
+
<title>称号的六维属性加成</title>
|
|
747
|
+
<defs><radialGradient id="dew-title-radar-fill" cx="48%" cy="45%" r="70%"><stop offset="0%" stop-color="var(--dew-accent)" stop-opacity="${0.1 + tier * 0.03}"/><stop offset="100%" stop-color="var(--dew-accent)" stop-opacity="${tier < 3 ? ".04" : ".08"}"/></radialGradient></defs>
|
|
748
|
+
${tier >= 3 ? `<circle cx="${cx}" cy="${cy}" r="${radius + 7}" class="dew-orbit"/>` : ""}
|
|
749
|
+
${tier >= 4 ? Array.from({ length: ticks }, (_, index) => {
|
|
750
|
+
const angle = index * Math.PI * 2 / ticks, distance = radius + 7;
|
|
751
|
+
const length = index % (ticks / 6) === 0 ? 4 : 2;
|
|
752
|
+
return `<line x1="${cx + Math.cos(angle) * distance}" y1="${cy + Math.sin(angle) * distance}" x2="${cx + Math.cos(angle) * (distance + length)}" y2="${cy + Math.sin(angle) * (distance + length)}" class="dew-tick"/>`;
|
|
753
|
+
}).join("") : ""}
|
|
754
|
+
${tier >= 8 ? `<ellipse cx="${cx}" cy="${cy}" rx="${radius + 11}" ry="${radius + 3}" transform="rotate(-18 ${cx} ${cy})" class="dew-orbit"/>` + [0.6, 1.7, 2.6, 3.7, 4.6, 5.7].map((index) => {
|
|
755
|
+
const [x, y] = point(index, radius + 9);
|
|
756
|
+
return `<circle cx="${x}" cy="${y}" r="${tier === 9 ? 1.7 : 1.1}" class="dew-constellation"/>`;
|
|
757
|
+
}).join("") : ""}
|
|
758
|
+
${[0.25, 0.5, 0.75, 1].map((scale) => `<polygon points="${polygon(radius * scale)}" class="dew-grid"/>`).join("")}
|
|
759
|
+
${axes.map((_, index) => {
|
|
760
|
+
const [x, y] = point(index, radius);
|
|
761
|
+
return `<line x1="${cx}" y1="${cy}" x2="${x}" y2="${y}" class="dew-spoke"/>`;
|
|
762
|
+
}).join("")}
|
|
763
|
+
<polygon points="${dots.map((dot) => dot.join(",")).join(" ")}" class="dew-area"/>
|
|
764
|
+
${attributes.map((attribute, index) => {
|
|
765
|
+
const [x, y] = dots[index], [lx, ly] = point(index, radius + 35);
|
|
766
|
+
const value = "+" + number4(attribute.value) + "%";
|
|
767
|
+
return `<circle cx="${x}" cy="${y}" r="6" class="dew-glow"/>` + (tier >= 5 ? `<polygon points="${x},${y - 3.5} ${x + 3.5},${y} ${x},${y + 3.5} ${x - 3.5},${y}" class="dew-dot"/>` : `<circle cx="${x}" cy="${y}" r="3.1" class="dew-dot"/>`) + `<text x="${lx}" y="${ly - 3}" text-anchor="middle" class="dew-axis"${attribute.name.length > 5 ? ' textLength="66" lengthAdjust="spacingAndGlyphs"' : ""}>${cardEscape(attribute.name)}</text><text x="${lx}" y="${ly + 19}" text-anchor="middle" class="dew-value" data-attribute="${attribute.id}"${value.length > 7 ? ' textLength="76" lengthAdjust="spacingAndGlyphs"' : ""}>${cardEscape(value)}</text>`;
|
|
768
|
+
}).join("")}
|
|
769
|
+
</svg>`;
|
|
770
|
+
}
|
|
771
|
+
__name(radar3, "radar");
|
|
772
|
+
function titleCardHtml(card, artwork) {
|
|
773
|
+
const index = qualities.indexOf(card.quality);
|
|
774
|
+
const theme = themes[Math.max(0, index)], tier = index + 1;
|
|
775
|
+
const variables = ["paper-top", "paper-bottom", "frame", "gold-light", "gold-dark", "accent"].map((name2, position) => `--dew-${name2}:${theme.colors[position]}`).join(";");
|
|
776
|
+
return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><style>${titleCardStyles}</style></head><body><main id="capture" class="title-sheet" data-quality="${cardEscape(card.quality)}" data-decoration-level="${tier}" style="${variables};--dew-paper:${theme.colors[1]}">
|
|
777
|
+
<article class="dew-card" style="--dew-card-radius:${theme.radius * 2}px;border-width:${theme.border * 2}px">
|
|
778
|
+
<span class="dew-crest" aria-hidden="true"></span>
|
|
779
|
+
${["tl", "tr", "bl", "br"].map((position) => `<span class="dew-corner ${position}" aria-hidden="true"></span>`).join("")}
|
|
780
|
+
<header class="dew-head"><div class="dew-quality" aria-hidden="true"><i class="dew-quality-wings"></i><b>✦</b><span class="dew-quality-crown"></span></div></header>
|
|
781
|
+
<div class="dew-banner"><span class="dew-aura" aria-hidden="true"></span>${artwork ? `<img class="title-banner-artwork" src="${cardEscape(artwork)}" alt="${cardEscape(card.name)}称号">` : ""}<h1 class="title-fallback"${artwork ? " hidden" : ""}>${cardEscape(card.name)}</h1></div>
|
|
782
|
+
<div class="dew-divider" aria-hidden="true"><span></span></div><p class="dew-radar-heading">属性加成</p>
|
|
783
|
+
<div class="dew-chart-space">${radar3(card, tier)}</div>
|
|
784
|
+
</article>
|
|
785
|
+
</main></body></html>`;
|
|
786
|
+
}
|
|
787
|
+
__name(titleCardHtml, "titleCardHtml");
|
|
788
|
+
|
|
586
789
|
// src/plugin/skillCard.ts
|
|
587
790
|
var import_node_crypto = require("node:crypto");
|
|
588
791
|
|
|
589
792
|
// src/plugin/cardLayout.ts
|
|
590
793
|
async function layoutCard(document2 = globalThis.document) {
|
|
591
794
|
await document2.fonts.ready;
|
|
795
|
+
const titleBanner = document2.querySelector(".title-banner-artwork");
|
|
796
|
+
if (titleBanner) {
|
|
797
|
+
try {
|
|
798
|
+
await titleBanner.decode();
|
|
799
|
+
} catch {
|
|
800
|
+
titleBanner.remove();
|
|
801
|
+
const fallback = document2.querySelector(".title-fallback");
|
|
802
|
+
if (fallback) fallback.hidden = false;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
if (document2.getElementById("capture")?.classList.contains("title-sheet")) return;
|
|
592
806
|
for (const icon of document2.querySelectorAll(".skill-entry-artwork,.bloodline-entry-artwork")) {
|
|
593
807
|
try {
|
|
594
808
|
await icon.decode();
|
|
@@ -843,12 +1057,12 @@ function equipmentCardHtml(card, artwork, unknownFallback = false) {
|
|
|
843
1057
|
__name(equipmentCardHtml, "equipmentCardHtml");
|
|
844
1058
|
|
|
845
1059
|
// src/plugin/bloodlineCardTemplate.ts
|
|
846
|
-
var
|
|
847
|
-
var
|
|
848
|
-
const display =
|
|
1060
|
+
var finite4 = /* @__PURE__ */ __name((value) => Number.isFinite(value) ? value : 0, "finite");
|
|
1061
|
+
var number5 = /* @__PURE__ */ __name((value) => {
|
|
1062
|
+
const display = finite4(value).toLocaleString("en-US", { useGrouping: false, maximumFractionDigits: 2 });
|
|
849
1063
|
return display === "-0" ? "0" : display;
|
|
850
1064
|
}, "number");
|
|
851
|
-
var signed = /* @__PURE__ */ __name((value) => (
|
|
1065
|
+
var signed = /* @__PURE__ */ __name((value) => (finite4(value) >= 0 ? "+" : "") + number5(value), "signed");
|
|
852
1066
|
var primaryAttributes3 = [
|
|
853
1067
|
["strength", "力量"],
|
|
854
1068
|
["agility", "敏捷"],
|
|
@@ -858,10 +1072,10 @@ var primaryAttributes3 = [
|
|
|
858
1072
|
["resistance", "抗性"]
|
|
859
1073
|
];
|
|
860
1074
|
var classicIds = new Set(primaryAttributes3.map(([id]) => id));
|
|
861
|
-
function
|
|
1075
|
+
function radar4(card) {
|
|
862
1076
|
const attributes = primaryAttributes3.map(([id, name2]) => {
|
|
863
1077
|
const attribute = card.attributes.find((value) => value.id === id);
|
|
864
|
-
return { name: attribute?.name?.trim() || name2, value:
|
|
1078
|
+
return { name: attribute?.name?.trim() || name2, value: finite4(attribute?.value ?? 0) };
|
|
865
1079
|
});
|
|
866
1080
|
const max = Math.max(1, ...attributes.map((attribute) => Math.max(0, attribute.value)));
|
|
867
1081
|
const magnitude = 10 ** Math.floor(Math.log10(max));
|
|
@@ -885,9 +1099,9 @@ function radar3(card) {
|
|
|
885
1099
|
const nameFontSize = Math.max(14, Math.min(22, Math.floor(180 / attribute.name.length)));
|
|
886
1100
|
return `<g transform="translate(${x} ${y})"><text text-anchor="middle" y="-3" font-size="${nameFontSize}" fill="#626d57">${cardEscape(attribute.name)}</text><text text-anchor="middle" y="27" font-size="${fontSize}" font-weight="600" fill="var(--quality-ink)">${cardEscape(value)}</text></g>`;
|
|
887
1101
|
}).join("")}
|
|
888
|
-
</svg><p class="radar-scale">各轴同尺度 · 满刻度 ${
|
|
1102
|
+
</svg><p class="radar-scale">各轴同尺度 · 满刻度 ${number5(ceiling)}</p></div>`;
|
|
889
1103
|
}
|
|
890
|
-
__name(
|
|
1104
|
+
__name(radar4, "radar");
|
|
891
1105
|
var equipmentIcons = {
|
|
892
1106
|
weapon: '<path d="M8 16 18 6l2-2 4 4-2 2-10 10M7 15l10 10M7 25l5-5M5 27l2-2"/>',
|
|
893
1107
|
armor: '<path d="M11 5 5 9l-2 7 6 2v10h16V18l6-2-2-7-6-4c-2 5-10 5-12 0Z"/>',
|
|
@@ -920,15 +1134,15 @@ var bloodlineStyles = `
|
|
|
920
1134
|
.equipment-tile b{font-size:26px;line-height:1.35;color:var(--quality-ink);font-weight:600;overflow-wrap:anywhere}
|
|
921
1135
|
`;
|
|
922
1136
|
function bloodlineCardHtml(card, artwork) {
|
|
923
|
-
const nextExperience =
|
|
924
|
-
const experience = Math.max(0,
|
|
925
|
-
const experienceHtml = card.experience === void 0 ? "" : nextExperience > 0 ? `<div class="experience-block"><div class="experience-label"><span>血统经验</span><b>${
|
|
1137
|
+
const nextExperience = finite4(card.nextExperience ?? 0);
|
|
1138
|
+
const experience = Math.max(0, finite4(card.experience ?? 0));
|
|
1139
|
+
const experienceHtml = card.experience === void 0 ? "" : nextExperience > 0 ? `<div class="experience-block"><div class="experience-label"><span>血统经验</span><b>${number5(experience)}<small> / ${number5(nextExperience)}</small></b></div><div class="experience-track"><i style="width:${Math.max(0, Math.min(100, experience / nextExperience * 100))}%"></i></div>${card.nextQuality ? `<div class="experience-next">下一级品质 <b>${cardEscape(card.nextQuality.replace(/\s*级$/, ""))} 级</b></div>` : ""}</div>` : `<div class="experience-block"><div class="experience-label"><span>血统经验</span><b>${number5(experience)}</b></div><div class="experience-next"><b>已达最高品质</b></div></div>`;
|
|
926
1140
|
const equipment = [...card.equipmentTypes].sort((a, b) => Number(/^[a-z]/i.test(a.type)) - Number(/^[a-z]/i.test(b.type)));
|
|
927
|
-
const unlocks = equipment.length ? `<div class="equipment-grid">${equipment.map((rule) => `<div class="equipment-tile">${equipmentIcon(rule.type)}<span>${cardEscape(rule.type)}</span><b>× ${
|
|
1141
|
+
const unlocks = equipment.length ? `<div class="equipment-grid">${equipment.map((rule) => `<div class="equipment-tile">${equipmentIcon(rule.type)}<span>${cardEscape(rule.type)}</span><b>× ${number5(rule.count)}</b></div>`).join("")}</div>` : '<p class="empty-line">当前品质暂无解锁装备</p>';
|
|
928
1142
|
const perLevel = card.type === "血统道具" && card.level === 1;
|
|
929
1143
|
const customAttributes = card.attributes.filter((attribute) => !classicIds.has(attribute.id));
|
|
930
1144
|
const extraAttributes = customAttributes.length ? `<div class="bloodline-custom-attributes">${customAttributes.map((attribute) => cardStatRow(attribute.name?.trim() || attribute.id, signed(attribute.value), true)).join("")}</div>` : "";
|
|
931
|
-
const body = `<div class="bloodline-facts">${cardStatRow(perLevel ? "血统战力(Lv.1)" : "血统战力", formatCombatPower(
|
|
1145
|
+
const body = `<div class="bloodline-facts">${cardStatRow(perLevel ? "血统战力(Lv.1)" : "血统战力", formatCombatPower(finite4(card.power)), true)}${experienceHtml}${card.count ? cardStatRow("拥有数量", card.count) : ""}${card.referencePrice ? cardStatRow("参考价格", card.referencePrice) : ""}</div>` + cardSection("血统描述", `<p class="description">${cardEscape(card.description?.trim() || "暂无血统描述")}</p>`) + cardSection("属性加成", `<p class="attribute-context">当前品质 · ${perLevel ? "每级属性加成" : "按角色 Lv." + number5(card.level) + " 计算"}</p>${radar4(card)}${extraAttributes}`) + cardSection("解锁装备", unlocks) + (card.useDescription?.trim() ? cardSection("使用说明", `<p class="description">${cardEscape(card.useDescription.trim())}</p>`) : "");
|
|
932
1146
|
return detailCardHtml({ name: card.name, quality: card.quality, type: card.type, artwork, artworkClass: "skill-artwork", fallbackGlyph: "血", tags: card.tags, body, sheetClass: "bloodline-sheet" }).replace("</style>", bloodlineStyles + "</style>");
|
|
933
1147
|
}
|
|
934
1148
|
__name(bloodlineCardHtml, "bloodlineCardHtml");
|
|
@@ -1132,10 +1346,10 @@ var RENDER_CACHE_TTL_MS = 10 * 60 * 1e3;
|
|
|
1132
1346
|
var renderedCards = /* @__PURE__ */ new Map();
|
|
1133
1347
|
var pendingCards = /* @__PURE__ */ new Map();
|
|
1134
1348
|
var renderedBytes = 0;
|
|
1135
|
-
function renderKey(card, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, normalizeArtwork = true) {
|
|
1136
|
-
const source = bloodlineCard ?? equipmentCard ?? companionCard ?? characterCard ?? itemCard ?? card;
|
|
1349
|
+
function renderKey(card, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, titleCard, normalizeArtwork = true) {
|
|
1350
|
+
const source = titleCard ?? bloodlineCard ?? equipmentCard ?? companionCard ?? characterCard ?? itemCard ?? card;
|
|
1137
1351
|
if (!source) return void 0;
|
|
1138
|
-
const kind = bloodlineCard ? "bloodline" : equipmentCard ? "equipment" : companionCard ? "companion" : characterCard ? "character" : itemCard ? "item" : "skill";
|
|
1352
|
+
const kind = titleCard ? "title" : bloodlineCard ? "bloodline" : equipmentCard ? "equipment" : companionCard ? "companion" : characterCard ? "character" : itemCard ? "item" : "skill";
|
|
1139
1353
|
const entryCard = kind === "companion" ? companionCard : void 0;
|
|
1140
1354
|
const entryAddress = /* @__PURE__ */ __name((address) => normalizeArtwork ? artworkIdentity(address) ?? address : address, "entryAddress");
|
|
1141
1355
|
const data = {
|
|
@@ -1179,17 +1393,17 @@ function rememberRender(key, image2) {
|
|
|
1179
1393
|
}
|
|
1180
1394
|
}
|
|
1181
1395
|
__name(rememberRender, "rememberRender");
|
|
1182
|
-
async function renderSkillCard(ctx, card, leaderboard, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard) {
|
|
1396
|
+
async function renderSkillCard(ctx, card, leaderboard, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, titleCard) {
|
|
1183
1397
|
if (!ctx.puppeteer) throw new Error("Puppeteer 未启用");
|
|
1184
|
-
if (JSON.stringify(bloodlineCard ?? equipmentCard ?? companionCard ?? characterCard ?? itemCard ?? card ?? leaderboard ?? {}).length > 24e3) throw new Error("卡片内容过长");
|
|
1185
|
-
const key = leaderboard && !bloodlineCard && !equipmentCard && !companionCard ? void 0 : renderKey(card, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard);
|
|
1186
|
-
if (!key) return (await renderUncached(ctx, card, leaderboard, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard)).image;
|
|
1398
|
+
if (JSON.stringify(titleCard ?? bloodlineCard ?? equipmentCard ?? companionCard ?? characterCard ?? itemCard ?? card ?? leaderboard ?? {}).length > 24e3) throw new Error("卡片内容过长");
|
|
1399
|
+
const key = leaderboard && !titleCard && !bloodlineCard && !equipmentCard && !companionCard ? void 0 : renderKey(card, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, titleCard);
|
|
1400
|
+
if (!key) return (await renderUncached(ctx, card, leaderboard, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, titleCard)).image;
|
|
1187
1401
|
const hit = cachedRender(key);
|
|
1188
1402
|
if (hit) return hit;
|
|
1189
|
-
const pendingKey = renderKey(card, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, false);
|
|
1403
|
+
const pendingKey = renderKey(card, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, titleCard, false);
|
|
1190
1404
|
const active = pendingCards.get(pendingKey);
|
|
1191
1405
|
if (active) return active;
|
|
1192
|
-
const work = renderUncached(ctx, card, leaderboard, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard).then(({ image: image2, cacheable }) => {
|
|
1406
|
+
const work = renderUncached(ctx, card, leaderboard, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, titleCard).then(({ image: image2, cacheable }) => {
|
|
1193
1407
|
if (cacheable) rememberRender(key, image2);
|
|
1194
1408
|
return image2;
|
|
1195
1409
|
}).finally(() => {
|
|
@@ -1199,7 +1413,7 @@ async function renderSkillCard(ctx, card, leaderboard, itemCard, characterCard,
|
|
|
1199
1413
|
return work;
|
|
1200
1414
|
}
|
|
1201
1415
|
__name(renderSkillCard, "renderSkillCard");
|
|
1202
|
-
async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard) {
|
|
1416
|
+
async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, equipmentCard, bloodlineCard, companionCard, titleCard) {
|
|
1203
1417
|
if (running >= 2) {
|
|
1204
1418
|
if (waiting.length >= 16) throw new Error("绘图繁忙");
|
|
1205
1419
|
await new Promise((resolve) => waiting.push(resolve));
|
|
@@ -1215,15 +1429,18 @@ async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, e
|
|
|
1215
1429
|
}, "release");
|
|
1216
1430
|
try {
|
|
1217
1431
|
const work = /* @__PURE__ */ __name(async () => {
|
|
1218
|
-
const entryArtworkPromise = loadCardEntryArtwork(!bloodlineCard && !equipmentCard ? companionCard : void 0);
|
|
1219
|
-
const remoteAddress = bloodlineCard ? bloodlineCard.artworkUrl : equipmentCard ? equipmentCard.artworkUrl : companionCard ? companionCard.artworkUrl : characterCard ? characterCard.artworkUrl : itemCard ? itemCard.artworkUrl : leaderboard ? leaderboard.backgroundUrl : card?.artworkUrl;
|
|
1220
|
-
const dedicatedArt = !bloodlineCard && equipmentCard ? await loadSkillArtwork(equipmentCard.artworkUrl) : void 0;
|
|
1221
|
-
const unknownArt = !bloodlineCard && equipmentCard && !dedicatedArt ? await equipmentFallback() : void 0;
|
|
1222
|
-
const art = !bloodlineCard && equipmentCard ? dedicatedArt ?? unknownArt : await loadSkillArtwork(remoteAddress);
|
|
1432
|
+
const entryArtworkPromise = loadCardEntryArtwork(!titleCard && !bloodlineCard && !equipmentCard ? companionCard : void 0);
|
|
1433
|
+
const remoteAddress = titleCard ? titleCard.artworkUrl : bloodlineCard ? bloodlineCard.artworkUrl : equipmentCard ? equipmentCard.artworkUrl : companionCard ? companionCard.artworkUrl : characterCard ? characterCard.artworkUrl : itemCard ? itemCard.artworkUrl : leaderboard ? leaderboard.backgroundUrl : card?.artworkUrl;
|
|
1434
|
+
const dedicatedArt = !titleCard && !bloodlineCard && equipmentCard ? await loadSkillArtwork(equipmentCard.artworkUrl) : void 0;
|
|
1435
|
+
const unknownArt = !titleCard && !bloodlineCard && equipmentCard && !dedicatedArt ? await equipmentFallback() : void 0;
|
|
1436
|
+
const art = !titleCard && !bloodlineCard && equipmentCard ? dedicatedArt ?? unknownArt : await loadSkillArtwork(remoteAddress);
|
|
1223
1437
|
const entryArtwork = await entryArtworkPromise;
|
|
1224
1438
|
let html;
|
|
1439
|
+
let loadedCharacterTitle;
|
|
1225
1440
|
let localAssetsReady = true;
|
|
1226
|
-
if (
|
|
1441
|
+
if (titleCard) {
|
|
1442
|
+
html = titleCardHtml(titleCard, art);
|
|
1443
|
+
} else if (bloodlineCard) {
|
|
1227
1444
|
html = bloodlineCardHtml(bloodlineCard, art);
|
|
1228
1445
|
} else if (equipmentCard) {
|
|
1229
1446
|
localAssetsReady = Boolean(art);
|
|
@@ -1235,6 +1452,7 @@ async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, e
|
|
|
1235
1452
|
characterAsset(),
|
|
1236
1453
|
loadSkillArtwork(characterCard.titleImageUrl)
|
|
1237
1454
|
]);
|
|
1455
|
+
loadedCharacterTitle = titleArtwork;
|
|
1238
1456
|
localAssetsReady = Boolean(art || defaultArtwork) && (!characterCard.titleImageUrl || Boolean(titleArtwork));
|
|
1239
1457
|
html = characterCardHtml(characterCard, art, void 0, defaultArtwork, titleArtwork, entryArtwork.icons);
|
|
1240
1458
|
} else if (itemCard) {
|
|
@@ -1251,7 +1469,7 @@ async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, e
|
|
|
1251
1469
|
page = void 0;
|
|
1252
1470
|
throw new Error("绘图超时");
|
|
1253
1471
|
}
|
|
1254
|
-
await page.setViewport({ width: 760, height: 1107, deviceScaleFactor: (companionCard || characterCard) && !bloodlineCard && !equipmentCard ? 2 : 1 });
|
|
1472
|
+
await page.setViewport({ width: 760, height: 1107, deviceScaleFactor: titleCard || (companionCard || characterCard) && !bloodlineCard && !equipmentCard ? 2 : 1 });
|
|
1255
1473
|
await page.setJavaScriptEnabled(false);
|
|
1256
1474
|
await page.setRequestInterception(true);
|
|
1257
1475
|
page.on("request", (req) => {
|
|
@@ -1260,13 +1478,27 @@ async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, e
|
|
|
1260
1478
|
});
|
|
1261
1479
|
await page.setContent(html, { waitUntil: "load", timeout: 1e4 });
|
|
1262
1480
|
await page.evaluate(layoutCard);
|
|
1481
|
+
let titleDecoded = true;
|
|
1482
|
+
if (titleCard && art) {
|
|
1483
|
+
titleDecoded = await page.evaluate((expected) => {
|
|
1484
|
+
const image2 = document.querySelector(".title-banner-artwork");
|
|
1485
|
+
return Boolean(image2 && image2.naturalWidth > 0 && image2.getAttribute("src") === expected);
|
|
1486
|
+
}, art);
|
|
1487
|
+
if (!titleDecoded) discardSkillArtwork(titleCard.artworkUrl, art);
|
|
1488
|
+
} else if (loadedCharacterTitle && characterCard) {
|
|
1489
|
+
titleDecoded = await page.evaluate((expected) => {
|
|
1490
|
+
const image2 = document.querySelector(".title-artwork");
|
|
1491
|
+
return Boolean(image2 && image2.naturalWidth > 0 && image2.getAttribute("src") === expected && image2.getAttribute("src") !== image2.dataset.fallback);
|
|
1492
|
+
}, loadedCharacterTitle);
|
|
1493
|
+
if (!titleDecoded) discardSkillArtwork(characterCard.titleImageUrl, loadedCharacterTitle);
|
|
1494
|
+
}
|
|
1263
1495
|
const expectedIcons = (entryArtwork.icons.skills?.filter(Boolean).length ?? 0) + (entryArtwork.icons.bloodlines?.filter(Boolean).length ?? 0);
|
|
1264
1496
|
const decodedEntries = expectedIcons ? await page.evaluate(() => ({
|
|
1265
1497
|
skills: [...document.querySelectorAll(".skill-entry-artwork")].map((icon) => Number(icon.dataset.entryIndex)),
|
|
1266
1498
|
bloodlines: [...document.querySelectorAll(".bloodline-entry-artwork")].map((icon) => Number(icon.dataset.entryIndex))
|
|
1267
1499
|
})) : { skills: [], bloodlines: [] };
|
|
1268
1500
|
const decodedIcons = decodedEntries.skills.length + decodedEntries.bloodlines.length;
|
|
1269
|
-
const activeEntries = !bloodlineCard && !equipmentCard ? companionCard : void 0;
|
|
1501
|
+
const activeEntries = !titleCard && !bloodlineCard && !equipmentCard ? companionCard : void 0;
|
|
1270
1502
|
for (const kind of ["skills", "bloodlines"]) {
|
|
1271
1503
|
entryArtwork.icons[kind]?.forEach((image2, index) => {
|
|
1272
1504
|
if (image2 && !decodedEntries[kind].includes(index)) discardSkillArtwork(activeEntries?.[kind]?.[index].artworkUrl, image2);
|
|
@@ -1276,7 +1508,7 @@ async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, e
|
|
|
1276
1508
|
if (!target) throw new Error("卡片元素缺失");
|
|
1277
1509
|
const bounds = await target.boundingBox();
|
|
1278
1510
|
if (!bounds || bounds.height > 1e4) throw new Error("卡片内容过长");
|
|
1279
|
-
return { image: Buffer.from(await target.screenshot({ type: "jpeg", quality: 90 })), cacheable: localAssetsReady && entryArtwork.complete && decodedIcons === expectedIcons && (!remoteAddress || Boolean(!bloodlineCard && equipmentCard ? dedicatedArt : art)) };
|
|
1511
|
+
return { image: Buffer.from(await target.screenshot({ type: "jpeg", quality: 90 })), cacheable: localAssetsReady && titleDecoded && entryArtwork.complete && decodedIcons === expectedIcons && (!remoteAddress || Boolean(!titleCard && !bloodlineCard && equipmentCard ? dedicatedArt : art)) };
|
|
1280
1512
|
}, "work");
|
|
1281
1513
|
workPromise = work();
|
|
1282
1514
|
return await Promise.race([workPromise, new Promise((_, reject) => {
|
|
@@ -1481,10 +1713,12 @@ function compactListLabel(value) {
|
|
|
1481
1713
|
return /[📖📚]/u.test(label) ? label.replace(/技能书(?=$|×\d+(?:\.\d+)?(?:||$)||)/g, "") : label;
|
|
1482
1714
|
}
|
|
1483
1715
|
__name(compactListLabel, "compactListLabel");
|
|
1484
|
-
function renderEntryArtwork(address) {
|
|
1716
|
+
function renderEntryArtwork(address, layout) {
|
|
1485
1717
|
if (!artworkIdentity(address)) return "";
|
|
1486
1718
|
const url = new URL(address).href.replace(/[()]/g, (character) => "%" + character.charCodeAt(0).toString(16).toUpperCase());
|
|
1487
|
-
return `
|
|
1720
|
+
|
|
1721
|
+
` : ` `;
|
|
1488
1722
|
}
|
|
1489
1723
|
__name(renderEntryArtwork, "renderEntryArtwork");
|
|
1490
1724
|
function inlineCommandUrl(command) {
|
|
@@ -1505,7 +1739,7 @@ function inlineCommandSpans(content) {
|
|
|
1505
1739
|
} else if (content[index] === "]" && depth > 0 && --depth === 0) {
|
|
1506
1740
|
const label = content.slice(labelStart, index).replace(/\\$/, "");
|
|
1507
1741
|
if (!label.trim() || /[\[\]\r\n]/.test(label) || /^\d+$/.test(label.trim())) continue;
|
|
1508
|
-
const command = label.split(/[++]/, 1)[0].trim();
|
|
1742
|
+
const command = label.split(/[++]/, 1)[0].trim().replace(/^🔄\s*/u, "");
|
|
1509
1743
|
if (command) spans.push({ start, end: index + 1, label, command });
|
|
1510
1744
|
}
|
|
1511
1745
|
}
|
|
@@ -1613,7 +1847,7 @@ __name(renderInventoryFilters, "renderInventoryFilters");
|
|
|
1613
1847
|
function renderQQInventoryMarkdown(data, showGreeting) {
|
|
1614
1848
|
const nav = data.pageNav;
|
|
1615
1849
|
const entryCommands = new Map(nav.entries?.map((entry) => [entry.lineIndex, entry.viewCommand]) ?? []);
|
|
1616
|
-
const entryArtwork = new Map(nav.entries?.map((entry) => [entry.lineIndex, renderEntryArtwork(entry.artworkUrl)]) ?? []);
|
|
1850
|
+
const entryArtwork = new Map(nav.entries?.map((entry) => [entry.lineIndex, renderEntryArtwork(entry.artworkUrl, entry.artworkLayout)]) ?? []);
|
|
1617
1851
|
const sections = [];
|
|
1618
1852
|
const items = [];
|
|
1619
1853
|
const flushItems = /* @__PURE__ */ __name(() => {
|
|
@@ -1658,7 +1892,8 @@ function renderQQPageMarkdown(data, showGreeting) {
|
|
|
1658
1892
|
row.push(entry);
|
|
1659
1893
|
labeledEntries.set(entry.lineIndex, row);
|
|
1660
1894
|
}
|
|
1661
|
-
const entryArtwork = new Map(nav?.entries?.map((entry) => [entry.lineIndex, renderEntryArtwork(entry.artworkUrl)]) ?? []);
|
|
1895
|
+
const entryArtwork = new Map(nav?.entries?.map((entry) => [entry.lineIndex, renderEntryArtwork(entry.artworkUrl, entry.artworkLayout)]) ?? []);
|
|
1896
|
+
const titleArtworkLines = new Set(nav?.entries?.filter((entry) => entry.artworkLayout === "title" && artworkIdentity(entry.artworkUrl)).map((entry) => entry.lineIndex) ?? []);
|
|
1662
1897
|
const listPattern = /^\[(\d+)\]\s*([^\r\n]+)$/;
|
|
1663
1898
|
const pagePattern = /^第\s*\d+\s*\/\s*\d+\s*页(?:\s*[||]\s*共\s*(\d+)\s*([项条]))?$/;
|
|
1664
1899
|
const title = data.line.find((item) => item.type === 0 /* title */);
|
|
@@ -1698,7 +1933,7 @@ function renderQQPageMarkdown(data, showGreeting) {
|
|
|
1698
1933
|
if (labeledRow) {
|
|
1699
1934
|
flushList();
|
|
1700
1935
|
flushRewards();
|
|
1701
|
-
bodyLines.push(labeledRow.map((entry) => renderEntryArtwork(entry.artworkUrl) + `[${escapeMarkdown(entry.label)}](${inlineCommandUrl(entry.viewCommand)})` + (entry.description ? " " + escapeMarkdown(entry.description) : "")).join("
|
|
1936
|
+
bodyLines.push(labeledRow.map((entry) => renderEntryArtwork(entry.artworkUrl, entry.artworkLayout) + `[${escapeMarkdown(entry.label)}](${inlineCommandUrl(entry.viewCommand)})` + (entry.description ? " " + escapeMarkdown(entry.description) : "")).join(""));
|
|
1702
1937
|
break;
|
|
1703
1938
|
}
|
|
1704
1939
|
if (item.reward) {
|
|
@@ -1713,9 +1948,9 @@ function renderQQPageMarkdown(data, showGreeting) {
|
|
|
1713
1948
|
if (listEntry) {
|
|
1714
1949
|
flushBody();
|
|
1715
1950
|
const command2 = entryCommands.get(lineIndex);
|
|
1716
|
-
const
|
|
1717
|
-
const label = escapeMarkdown(
|
|
1718
|
-
const name2 = command2 ? `[${label}](${inlineCommandUrl(command2)})` : renderInlineCommands(
|
|
1951
|
+
const content2 = compactListLabel(listEntry[2]);
|
|
1952
|
+
const label = escapeMarkdown(content2);
|
|
1953
|
+
const name2 = command2 ? `[${label}](${inlineCommandUrl(command2)})` : renderInlineCommands(content2);
|
|
1719
1954
|
listLines.push(`${listEntry[1]}. ${entryArtwork.get(lineIndex) ?? ""}${name2}`);
|
|
1720
1955
|
break;
|
|
1721
1956
|
}
|
|
@@ -1737,7 +1972,11 @@ function renderQQPageMarkdown(data, showGreeting) {
|
|
|
1737
1972
|
break;
|
|
1738
1973
|
}
|
|
1739
1974
|
const command = entryCommands.get(lineIndex);
|
|
1740
|
-
|
|
1975
|
+
const content = command ? (entryArtwork.get(lineIndex) ?? "") + `[${escapeMarkdown(compactListLabel(item.content))}](${inlineCommandUrl(command)})` : renderInlineCommands(item.content);
|
|
1976
|
+
if (command && titleArtworkLines.has(lineIndex)) {
|
|
1977
|
+
flushBody();
|
|
1978
|
+
sections.push(content);
|
|
1979
|
+
} else bodyLines.push(content);
|
|
1741
1980
|
break;
|
|
1742
1981
|
}
|
|
1743
1982
|
case 2 /* error */:
|
|
@@ -1814,7 +2053,7 @@ var AnalysisMsg = class {
|
|
|
1814
2053
|
break;
|
|
1815
2054
|
case 1 /* line */:
|
|
1816
2055
|
const labeledRow = labeledEntries.get(lineIndex);
|
|
1817
|
-
const content = labeledRow ? labeledRow.map((entry) => entry.label + (entry.description ? " · " + entry.description : "") + ` [${entry.viewCommand}]`).join("
|
|
2056
|
+
const content = labeledRow ? labeledRow.map((entry) => entry.label + (entry.description ? " · " + entry.description : "") + ` [${entry.viewCommand}]`).join("") : withCommandHint(item.content, commands.get(lineIndex));
|
|
1818
2057
|
msg += `${content}
|
|
1819
2058
|
`;
|
|
1820
2059
|
break;
|
|
@@ -1897,12 +2136,15 @@ __name(renderQQCommandMarkdown, "renderQQCommandMarkdown");
|
|
|
1897
2136
|
// src/plugin/serverHandel/qqTransactionMessage.ts
|
|
1898
2137
|
function renderQQTransactionMarkdown(data, showGreeting) {
|
|
1899
2138
|
const rewardMessage = isRewardMessage(data);
|
|
2139
|
+
const shortageMessage = data.transaction === true && data.line.some((item) => item.type === 0 /* title */ && item.content === "❌材料不足");
|
|
1900
2140
|
const sections = [];
|
|
1901
2141
|
const bodyLines = [];
|
|
1902
2142
|
const actions = [];
|
|
1903
2143
|
const rewardLines = [];
|
|
2144
|
+
let quotingItems = false;
|
|
1904
2145
|
const flushBody = /* @__PURE__ */ __name(() => {
|
|
1905
2146
|
if (bodyLines.length) sections.push(bodyLines.splice(0).join(" \n"));
|
|
2147
|
+
quotingItems = false;
|
|
1906
2148
|
}, "flushBody");
|
|
1907
2149
|
const flushActions = /* @__PURE__ */ __name(() => {
|
|
1908
2150
|
if (actions.length) sections.push(actions.splice(0).join(" · "));
|
|
@@ -1915,11 +2157,12 @@ function renderQQTransactionMarkdown(data, showGreeting) {
|
|
|
1915
2157
|
flushActions();
|
|
1916
2158
|
flushRewards();
|
|
1917
2159
|
}, "flush");
|
|
1918
|
-
if (showGreeting && !data.reward) sections.push(escapeMarkdown("Ciallo~(∠・ω< )"));
|
|
2160
|
+
if (showGreeting && !data.reward && !shortageMessage) sections.push(escapeMarkdown("Ciallo~(∠・ω< )"));
|
|
1919
2161
|
for (const item of data.line) {
|
|
1920
2162
|
if (item.type === 0 /* title */) {
|
|
1921
2163
|
flush();
|
|
1922
|
-
if (
|
|
2164
|
+
if (shortageMessage) sections.push(renderRewardTitle(item.content));
|
|
2165
|
+
else if (rewardMessage) bodyLines.push(renderRewardTitle(item.content));
|
|
1923
2166
|
else sections.push(renderQQTitle(item.content));
|
|
1924
2167
|
continue;
|
|
1925
2168
|
}
|
|
@@ -1929,6 +2172,10 @@ function renderQQTransactionMarkdown(data, showGreeting) {
|
|
|
1929
2172
|
continue;
|
|
1930
2173
|
}
|
|
1931
2174
|
if (item.type !== 1 /* line */) continue;
|
|
2175
|
+
if (shortageMessage && (item.content === "【还缺】" || item.content === "本次未扣除任何道具")) {
|
|
2176
|
+
flushBody();
|
|
2177
|
+
continue;
|
|
2178
|
+
}
|
|
1932
2179
|
if (item.reward) {
|
|
1933
2180
|
flushBody();
|
|
1934
2181
|
flushActions();
|
|
@@ -1949,11 +2196,18 @@ function renderQQTransactionMarkdown(data, showGreeting) {
|
|
|
1949
2196
|
continue;
|
|
1950
2197
|
}
|
|
1951
2198
|
const section = /^┄━═(.+)═━┄$/.exec(item.content);
|
|
2199
|
+
if (section?.[1] === "💰交易记录") {
|
|
2200
|
+
flushBody();
|
|
2201
|
+
continue;
|
|
2202
|
+
}
|
|
1952
2203
|
if (section || item.content === "【还缺】") {
|
|
1953
2204
|
flushBody();
|
|
1954
2205
|
sections.push(`**${escapeMarkdown(section?.[1] ?? "还缺")}**`);
|
|
1955
2206
|
} else {
|
|
1956
|
-
|
|
2207
|
+
const quotedItem = data.transaction === true && (/^.+ -\d+(?:\.\d+)?(?:(拥有\d+(?:\.\d+)?))?$/.test(item.content) || shortageMessage && /^.+ ×\d+(?:\.\d+)?(拥有\d+(?:\.\d+)?/需要\d+(?:\.\d+)?)$/.test(item.content));
|
|
2208
|
+
if (quotedItem !== quotingItems) flushBody();
|
|
2209
|
+
quotingItems = quotedItem;
|
|
2210
|
+
bodyLines.push(`${quotedItem ? "> " : ""}${renderInlineCommands(item.content)}`);
|
|
1957
2211
|
}
|
|
1958
2212
|
}
|
|
1959
2213
|
flush();
|
|
@@ -2075,6 +2329,30 @@ ${commands.join("\n")}` : content);
|
|
|
2075
2329
|
}
|
|
2076
2330
|
};
|
|
2077
2331
|
|
|
2332
|
+
// src/plugin/serverHandel/titleCardMessage.ts
|
|
2333
|
+
function titleCardFollowup(data) {
|
|
2334
|
+
const card = data.titleCard;
|
|
2335
|
+
if (!card) return void 0;
|
|
2336
|
+
const detail = `${card.quality} · ${card.name}`;
|
|
2337
|
+
const lines = data.line.flatMap((item) => {
|
|
2338
|
+
if (item.type === 0 /* title */) return [];
|
|
2339
|
+
return item.content.replace(/\r\n?/g, "\n").split("\n").flatMap((line) => {
|
|
2340
|
+
const content = line.trim();
|
|
2341
|
+
if (!content || content === card.name || content === detail) return [];
|
|
2342
|
+
const bonus = /^(.*?)\s+\+[\d.,]+%$/u.exec(content);
|
|
2343
|
+
if (bonus && card.attributes.some((attribute) => {
|
|
2344
|
+
if (!bonus[1].endsWith(attribute.name)) return false;
|
|
2345
|
+
const prefix = bonus[1].slice(0, -attribute.name.length);
|
|
2346
|
+
return !/[\p{L}\p{N}]/u.test(prefix);
|
|
2347
|
+
})) return [];
|
|
2348
|
+
return [item.type === 2 /* error */ ? `❌ ${content}` : content];
|
|
2349
|
+
});
|
|
2350
|
+
});
|
|
2351
|
+
if (!lines.length) return void 0;
|
|
2352
|
+
return { text: lines.join("\n"), markdown: lines.map(renderInlineCommands).join(" \n") };
|
|
2353
|
+
}
|
|
2354
|
+
__name(titleCardFollowup, "titleCardFollowup");
|
|
2355
|
+
|
|
2078
2356
|
// src/plugin/serverHandel/image.ts
|
|
2079
2357
|
var ImageHandler = class extends handel_base {
|
|
2080
2358
|
static {
|
|
@@ -2085,8 +2363,8 @@ var ImageHandler = class extends handel_base {
|
|
|
2085
2363
|
let rendered = false;
|
|
2086
2364
|
const renderStartedAt = this.timing ? performance.now() : 0;
|
|
2087
2365
|
try {
|
|
2088
|
-
if (!data.companionCard && !data.characterCard && !data.itemCard && !data.card && !data.leaderboard && !data.equipmentCard && !data.bloodlineCard) throw new Error("缺少卡片数据");
|
|
2089
|
-
const image2 = await renderSkillCard(this.ctx, data.card, data.leaderboard, data.itemCard, data.characterCard, data.equipmentCard, data.bloodlineCard, data.companionCard);
|
|
2366
|
+
if (!data.titleCard && !data.companionCard && !data.characterCard && !data.itemCard && !data.card && !data.leaderboard && !data.equipmentCard && !data.bloodlineCard) throw new Error("缺少卡片数据");
|
|
2367
|
+
const image2 = await renderSkillCard(this.ctx, data.card, data.leaderboard, data.itemCard, data.characterCard, data.equipmentCard, data.bloodlineCard, data.companionCard, data.titleCard);
|
|
2090
2368
|
if (this.timing) this.timing.imageBytes = image2.length;
|
|
2091
2369
|
content = import_koishi.h.image(image2, "image/jpeg").toString();
|
|
2092
2370
|
rendered = true;
|
|
@@ -2103,7 +2381,25 @@ var ImageHandler = class extends handel_base {
|
|
|
2103
2381
|
await fallback.start(data);
|
|
2104
2382
|
return;
|
|
2105
2383
|
}
|
|
2384
|
+
const sendStartedAt = this.timing ? performance.now() : 0;
|
|
2106
2385
|
await this.send(data, content, "image");
|
|
2386
|
+
const followup = titleCardFollowup(data);
|
|
2387
|
+
if (!followup) return;
|
|
2388
|
+
const session = sessions_default.get(sessionKey(data.botId, data.userId, data.channelId));
|
|
2389
|
+
let sentMarkdown = false;
|
|
2390
|
+
if (canSendQQPage(session, data)) {
|
|
2391
|
+
try {
|
|
2392
|
+
await sendQQMarkdown(session, followup.markdown);
|
|
2393
|
+
sentMarkdown = true;
|
|
2394
|
+
} catch (error) {
|
|
2395
|
+
this.ctx.logger.warn("称号操作 Markdown 发送失败,改用普通文字", error instanceof Error ? error.message : error);
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
if (!sentMarkdown) await this.send({ ...data, notification: true }, followup.text);
|
|
2399
|
+
if (this.timing) {
|
|
2400
|
+
if (this.timing.delivery !== "missing-session") this.timing.delivery = "image";
|
|
2401
|
+
this.timing.sendMs = performance.now() - sendStartedAt;
|
|
2402
|
+
}
|
|
2107
2403
|
}
|
|
2108
2404
|
};
|
|
2109
2405
|
|
|
@@ -2171,7 +2467,7 @@ var import_tsrpc = require("tsrpc");
|
|
|
2171
2467
|
|
|
2172
2468
|
// src/shared/bot/serviceProto.ts
|
|
2173
2469
|
var serviceProto = {
|
|
2174
|
-
"version":
|
|
2470
|
+
"version": 35,
|
|
2175
2471
|
"services": [
|
|
2176
2472
|
{
|
|
2177
2473
|
"id": 0,
|
|
@@ -2382,6 +2678,15 @@ var serviceProto = {
|
|
|
2382
2678
|
"target": "messageFace/CompanionCardData"
|
|
2383
2679
|
},
|
|
2384
2680
|
"optional": true
|
|
2681
|
+
},
|
|
2682
|
+
{
|
|
2683
|
+
"id": 16,
|
|
2684
|
+
"name": "titleCard",
|
|
2685
|
+
"type": {
|
|
2686
|
+
"type": "Reference",
|
|
2687
|
+
"target": "messageFace/TitleCardData"
|
|
2688
|
+
},
|
|
2689
|
+
"optional": true
|
|
2385
2690
|
}
|
|
2386
2691
|
]
|
|
2387
2692
|
},
|
|
@@ -3465,6 +3770,14 @@ var serviceProto = {
|
|
|
3465
3770
|
"type": "String"
|
|
3466
3771
|
},
|
|
3467
3772
|
"optional": true
|
|
3773
|
+
},
|
|
3774
|
+
{
|
|
3775
|
+
"id": 5,
|
|
3776
|
+
"name": "artworkLayout",
|
|
3777
|
+
"type": {
|
|
3778
|
+
"type": "String"
|
|
3779
|
+
},
|
|
3780
|
+
"optional": true
|
|
3468
3781
|
}
|
|
3469
3782
|
]
|
|
3470
3783
|
}
|
|
@@ -3903,6 +4216,73 @@ var serviceProto = {
|
|
|
3903
4216
|
}
|
|
3904
4217
|
]
|
|
3905
4218
|
},
|
|
4219
|
+
"messageFace/TitleCardData": {
|
|
4220
|
+
"type": "Interface",
|
|
4221
|
+
"properties": [
|
|
4222
|
+
{
|
|
4223
|
+
"id": 0,
|
|
4224
|
+
"name": "name",
|
|
4225
|
+
"type": {
|
|
4226
|
+
"type": "String"
|
|
4227
|
+
}
|
|
4228
|
+
},
|
|
4229
|
+
{
|
|
4230
|
+
"id": 1,
|
|
4231
|
+
"name": "quality",
|
|
4232
|
+
"type": {
|
|
4233
|
+
"type": "String"
|
|
4234
|
+
}
|
|
4235
|
+
},
|
|
4236
|
+
{
|
|
4237
|
+
"id": 2,
|
|
4238
|
+
"name": "artworkUrl",
|
|
4239
|
+
"type": {
|
|
4240
|
+
"type": "String"
|
|
4241
|
+
},
|
|
4242
|
+
"optional": true
|
|
4243
|
+
},
|
|
4244
|
+
{
|
|
4245
|
+
"id": 3,
|
|
4246
|
+
"name": "attributeLimit",
|
|
4247
|
+
"type": {
|
|
4248
|
+
"type": "Number"
|
|
4249
|
+
}
|
|
4250
|
+
},
|
|
4251
|
+
{
|
|
4252
|
+
"id": 4,
|
|
4253
|
+
"name": "attributes",
|
|
4254
|
+
"type": {
|
|
4255
|
+
"type": "Array",
|
|
4256
|
+
"elementType": {
|
|
4257
|
+
"type": "Interface",
|
|
4258
|
+
"properties": [
|
|
4259
|
+
{
|
|
4260
|
+
"id": 0,
|
|
4261
|
+
"name": "id",
|
|
4262
|
+
"type": {
|
|
4263
|
+
"type": "String"
|
|
4264
|
+
}
|
|
4265
|
+
},
|
|
4266
|
+
{
|
|
4267
|
+
"id": 1,
|
|
4268
|
+
"name": "name",
|
|
4269
|
+
"type": {
|
|
4270
|
+
"type": "String"
|
|
4271
|
+
}
|
|
4272
|
+
},
|
|
4273
|
+
{
|
|
4274
|
+
"id": 2,
|
|
4275
|
+
"name": "value",
|
|
4276
|
+
"type": {
|
|
4277
|
+
"type": "Number"
|
|
4278
|
+
}
|
|
4279
|
+
}
|
|
4280
|
+
]
|
|
4281
|
+
}
|
|
4282
|
+
}
|
|
4283
|
+
}
|
|
4284
|
+
]
|
|
4285
|
+
},
|
|
3906
4286
|
"PtlMessage/ReqMessage": {
|
|
3907
4287
|
"type": "Interface",
|
|
3908
4288
|
"extends": [
|