koishi-plugin-dew-bot 1.0.264 → 1.0.265

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/README.md CHANGED
@@ -11,6 +11,5 @@
11
11
 
12
12
  ## 交流群
13
13
 
14
- 扫描下方二维码加入「达尔文进化岛」,群号:**550620904**。
14
+ 「达尔文进化岛」群号:**550620904**。
15
15
 
16
- <img src="./assets/official-qq-group.jpg" alt="达尔文进化岛,群号 550620904" width="360" />
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": 41,
70
+ "version": 42,
71
71
  "services": [
72
72
  {
73
73
  "id": 0,
@@ -1828,6 +1828,55 @@ var init_serviceProto = __esm({
1828
1828
  ]
1829
1829
  }
1830
1830
  }
1831
+ },
1832
+ {
1833
+ "id": 14,
1834
+ "name": "equipment",
1835
+ "type": {
1836
+ "type": "Array",
1837
+ "elementType": {
1838
+ "type": "Interface",
1839
+ "properties": [
1840
+ {
1841
+ "id": 0,
1842
+ "name": "id",
1843
+ "type": {
1844
+ "type": "String"
1845
+ }
1846
+ },
1847
+ {
1848
+ "id": 1,
1849
+ "name": "name",
1850
+ "type": {
1851
+ "type": "String"
1852
+ }
1853
+ },
1854
+ {
1855
+ "id": 2,
1856
+ "name": "quality",
1857
+ "type": {
1858
+ "type": "String"
1859
+ }
1860
+ },
1861
+ {
1862
+ "id": 3,
1863
+ "name": "slot",
1864
+ "type": {
1865
+ "type": "String"
1866
+ }
1867
+ },
1868
+ {
1869
+ "id": 4,
1870
+ "name": "enhancement",
1871
+ "type": {
1872
+ "type": "Number"
1873
+ },
1874
+ "optional": true
1875
+ }
1876
+ ]
1877
+ }
1878
+ },
1879
+ "optional": true
1831
1880
  }
1832
1881
  ]
1833
1882
  },
@@ -1841,6 +1890,14 @@ var init_serviceProto = __esm({
1841
1890
  {
1842
1891
  "id": 1,
1843
1892
  "value": "follower"
1893
+ },
1894
+ {
1895
+ "id": 2,
1896
+ "value": "monster"
1897
+ },
1898
+ {
1899
+ "id": 3,
1900
+ "value": "boss"
1844
1901
  }
1845
1902
  ]
1846
1903
  },
@@ -2986,6 +3043,12 @@ var companionCardStyles = `
2986
3043
  .companion-attributes{margin-top:3px;flex:1;display:flex;flex-direction:column;justify-content:center;min-width:0}.companion-attributes .ornament-heading{margin-bottom:4px;font-size:22px;gap:6px;letter-spacing:2px}.companion-radar{width:100%;height:300px;display:block;overflow:visible}.radar-grid{fill:none;stroke:var(--radar-grid);stroke-width:1.2}.radar-axis{stroke:var(--radar-grid);stroke-width:1;opacity:.8}.radar-area{fill:var(--radar-fill);stroke:var(--radar);stroke-width:2.5;stroke-linejoin:round}.radar-dot{fill:var(--flower);stroke:var(--radar);stroke-width:2}.radar-label{font:18px "Microsoft YaHei",sans-serif;fill:var(--ink)}.radar-value{font:20px Georgia,"Microsoft YaHei",serif;fill:var(--ink)}.radar-scale{font:11px Georgia,serif;fill:var(--subtle)}.empty-attributes{padding:45px 10px;color:var(--subtle);font:18px/1.6 "Microsoft YaHei",sans-serif;text-align:center}.custom-attributes{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:5px 10px;margin:6px 0 0;font:15px/1.5 "Microsoft YaHei",sans-serif;color:var(--subtle)}.custom-attributes span{overflow-wrap:anywhere}.custom-attributes b{font-weight:500;color:var(--ink)}
2987
3044
  .companion-skills{position:relative;z-index:1;padding:12px 18px 19px;margin-top:15px}.companion-skills .ornament-heading{margin-bottom:13px}.skill-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 13px}.companion-skill{position:relative;min-width:0;display:grid;grid-template-columns:47px minmax(0,1fr) auto;align-items:center;gap:10px;padding:9px 10px;border:1px solid var(--edge);border-radius:7px;box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--edge) 12%,transparent);background:color-mix(in srgb,var(--panel) 55%,transparent);min-height:65px}.skill-icon{width:47px;height:47px;border:1px solid var(--edge);border-radius:7px;display:grid;place-items:center;background:radial-gradient(ellipse at 40% 23%,color-mix(in srgb,var(--accent) 55%,var(--paper)),color-mix(in srgb,var(--paper) 72%,#282015));color:var(--flower);box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--light-edge) 20%,transparent)}.skill-icon svg{width:31px;height:31px;stroke:currentColor;stroke-width:1.7;fill:none;stroke-linecap:round;stroke-linejoin:round}.skill-name{font-size:20px;font-weight:700;overflow-wrap:anywhere;line-height:1.35}.skill-level{font:18px/1.2 Georgia,"Microsoft YaHei",serif;border:1px solid color-mix(in srgb,var(--edge) 55%,transparent);border-radius:13px;padding:5px 9px;white-space:nowrap;color:var(--ink);background:color-mix(in srgb,var(--accent) 9%,transparent)}.empty-list{margin:10px 0;color:var(--subtle);font:17px/1.6 "Microsoft YaHei",sans-serif;text-align:center}.follower-theme .companion-panel{box-shadow:inset 0 0 0 3px var(--panel),inset 0 0 0 4px color-mix(in srgb,var(--edge) 50%,transparent),0 2px 6px #00000040}.follower-theme .skill-icon{background:radial-gradient(ellipse at 40% 23%,#858585,#292929)}.follower-theme .resource-track{box-shadow:inset 0 1px 3px #00000030}.follower-theme .companion-power{color:var(--ink)}.follower-theme .resource-percent{color:#fffef7;text-shadow:0 1px 2px #242725}
2988
3045
  .skill-icon,.bloodline-crest{position:relative;overflow:hidden}.bloodline-crest.has-entry-artwork{border-radius:7px}.skill-entry-artwork,.bloodline-entry-artwork{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;border-radius:inherit;background:var(--paper);z-index:1}.follower-theme .skill-entry-artwork,.follower-theme .bloodline-entry-artwork{filter:grayscale(1)}
3046
+ .monster-theme{--ink:#e0eeea;--subtle:#a2b9b6;--accent:#9bd8c9;--edge:#668f90;--light-edge:#c3e5d7;--panel:#203f48;--panel-deep:#142d38;--paper:#183440;--flower:#d3efe6;--track:#213c46;--track-edge:#769b92;--health:#518f7f;--health-light:#96d6b5;--radar:#a2d8c9;--radar-fill:#7bb5ab55;--radar-grid:#507d80;background:radial-gradient(ellipse at 10% 9%,#81b8a840,transparent 43%),radial-gradient(ellipse at 94% 83%,#49808045,transparent 35%),repeating-linear-gradient(125deg,#d6eee608 0 1px,transparent 1px 5px),linear-gradient(155deg,#3c6269,#142a35 37%,#30515a)}
3047
+ .boss-theme{--ink:#f7e2c3;--subtle:#ceafac;--accent:#edc385;--edge:#b77c62;--light-edge:#f5dba4;--panel:#492937;--panel-deep:#281b2a;--paper:#342132;--flower:#ffe6b2;--track:#4b2837;--track-edge:#b88170;--health:#a24d59;--health-light:#eb9395;--radar:#edc385;--radar-fill:#daaa5b55;--radar-grid:#925c64;padding-top:55px;background:radial-gradient(ellipse at 48% 0%,#ecc07855,transparent 40%),radial-gradient(ellipse at 96% 83%,#c54a6245,transparent 35%),repeating-linear-gradient(125deg,#f2dfbd08 0 1px,transparent 1px 5px),linear-gradient(155deg,#773b46,#211b2c 37%,#5d2c42)}
3048
+ .boss-card-decoration{position:absolute;top:3px;left:50%;transform:translateX(-50%);width:160px;height:52px;color:var(--accent)}.boss-card-decoration svg{display:block;width:100%;height:100%}.boss-theme .companion-portrait,.boss-theme .companion-stats{box-shadow:inset 0 0 0 3px var(--panel),inset 0 0 0 4px color-mix(in srgb,var(--edge) 60%,transparent),0 0 13px #daa04e40}.boss-theme .state-badge{border-radius:5px;letter-spacing:3px;background:linear-gradient(135deg,#b6805130,#8c44502b);padding:7px 15px}.monster-theme .state-badge{letter-spacing:2px}
3049
+ .enemy-equipment{padding:13px 18px 18px;margin-top:15px}.enemy-equipment-list{display:grid;gap:8px}.enemy-equipment-row{display:grid;grid-template-columns:28px minmax(0,1fr) auto auto;align-items:center;gap:10px;padding:8px 11px;border:1px solid var(--edge);border-radius:7px;background:color-mix(in srgb,var(--panel) 55%,transparent);min-width:0}.equipment-symbol{color:var(--accent);font-size:26px}.enemy-equipment-name{font-size:20px;line-height:1.4;overflow-wrap:anywhere}.enemy-equipment-name small{color:var(--accent);font:17px Georgia,serif;white-space:nowrap}.equipment-slot{font:15px/1.4 "Microsoft YaHei",sans-serif;color:var(--subtle);max-width:120px;overflow-wrap:anywhere}
3050
+ .enemy-main{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.enemy-sheet .companion-stats{justify-content:center;padding:24px 24px 26px}.enemy-sheet .companion-name{font-size:43px;letter-spacing:2px}.enemy-sheet .companion-power-row{margin:24px 0}.enemy-sheet .companion-resource{margin-bottom:0}.enemy-attributes{padding:16px 12px 12px;display:flex;align-items:center}.enemy-attributes .companion-attributes{margin:0}.enemy-sheet>.bloodline-panel{margin-top:15px;padding:13px 18px 18px}.enemy-sheet .bloodline-list{grid-template-columns:repeat(2,minmax(0,1fr))}.enemy-sheet .bloodline-name{font-size:20px}
3051
+
2989
3052
  `;
2990
3053
 
2991
3054
  // src/plugin/companionCardAssets.ts
@@ -3018,6 +3081,7 @@ var followerPortraitPlaceholder = image(`<svg xmlns="http://www.w3.org/2000/svg"
3018
3081
  <g fill="#1d1d1d" stroke="#a7a7a7" stroke-width="2"><path d="M158 485c7-79 20-135 42-166 15-44 29-83 70-88 46 7 58 45 73 89 19 29 37 87 42 166Z"/><path d="M218 297c-4-50 14-87 52-88 39 1 58 38 52 89l-19-9-13-30-20-12-22 12-11 30Z"/><path d="m216 316 54 66 54-66M197 358l-26 117m172-117 27 117" fill="none"/><path d="m247 287 23 20 24-20-11 48h-26Z" fill="#808080" stroke="none"/></g>
3019
3082
  <text x="270" y="551" text-anchor="middle" font-family="Microsoft YaHei,sans-serif" font-size="26" letter-spacing="4" fill="#e1e0d6">暂无随从形象</text>
3020
3083
  </svg>`);
3084
+ var bossCardDecoration = '<svg viewBox="0 0 160 64" aria-hidden="true"><path d="M31 49 23 17l32 20L80 5l25 32 32-20-8 32ZM31 55h98" fill="currentColor" opacity=".7"/><path d="M9 51 26 39M134 39l17 12M5 58l19-10m112 0 19 10" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="80" cy="5" r="4" fill="currentColor"/><circle cx="23" cy="17" r="3" fill="currentColor"/><circle cx="137" cy="17" r="3" fill="currentColor"/></svg>';
3021
3085
 
3022
3086
  // src/plugin/companionCardTemplate.ts
3023
3087
  var finite2 = /* @__PURE__ */ __name((value) => Number.isFinite(value) ? value : 0, "finite");
@@ -3086,21 +3150,30 @@ function skills(card, icons) {
3086
3150
  return `<section class="companion-panel companion-skills" aria-label="技能">${corners2()}${heading("技能")}${card.skills.length ? `<div class="skill-grid">${card.skills.map((skill, index) => `<div class="companion-skill" data-skill-id="${cardEscape(skill.id)}"><span class="skill-icon" aria-hidden="true"><svg viewBox="0 0 36 36">${skill.type === "passive" ? passive : active}</svg>${icons?.skills?.[index] ? `<img class="skill-entry-artwork" data-entry-index="${index}" src="${cardEscape(icons.skills[index])}" alt="">` : ""}</span><span class="skill-name">${cardEscape(skill.name)}</span><span class="skill-level">Lv.${number3(skill.rank)}</span></div>`).join("")}</div>` : '<p class="empty-list">暂无技能</p>'}</section>`;
3087
3151
  }
3088
3152
  __name(skills, "skills");
3153
+ function equipment(card) {
3154
+ if (!card.equipment) return "";
3155
+ return `<section class="companion-panel enemy-equipment" aria-label="装备">${heading("装备")}${card.equipment.length ? '<div class="enemy-equipment-list">' + card.equipment.map((item) => `<div class="enemy-equipment-row"><span class="equipment-symbol" aria-hidden="true">✧</span><span class="enemy-equipment-name">${cardEscape(item.name)}${item.enhancement ? " <small>+" + number3(item.enhancement) + "</small>" : ""}</span><span class="equipment-slot">${cardEscape(item.slot)}</span><span class="bloodline-quality">${cardEscape(item.quality)}</span></div>`).join("") + "</div>" : '<p class="empty-list">暂无装备</p>'}</section>`;
3156
+ }
3157
+ __name(equipment, "equipment");
3089
3158
  function companionCardHtml(card, artwork, icons) {
3090
3159
  const pet = card.kind === "pet";
3160
+ const enemy = card.kind === "monster" || card.kind === "boss";
3161
+ const boss = card.kind === "boss";
3162
+ const kind = enemy ? boss ? "boss" : "monster" : pet ? "pet" : "follower";
3163
+ const typeName = enemy ? boss ? "首领" : "普通怪物" : pet ? "宠物" : "随从";
3091
3164
  const fallback = pet ? petPortraitPlaceholder : followerPortraitPlaceholder;
3092
3165
  const healthPercent = ratio2(card.hp, card.maxHp) * 100;
3093
3166
  const experience = Math.max(0, Math.min(100, finite2(card.experiencePercent ?? 0)));
3094
3167
  const state = pet ? card.state === "fallen" ? "fallen" : card.state === "resting" ? "resting" : "active" : "active";
3095
- const stateName = pet ? { active: "出战", resting: "休息", fallen: "倒下" }[state] : "自动参战";
3096
- return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><style>${companionCardStyles}</style></head><body><main id="capture" class="companion-sheet ${pet ? "pet-theme" : "follower-theme"}" data-kind="${pet ? "pet" : "follower"}"><div class="companion-main">
3097
- <div class="portrait-column"><div class="companion-panel companion-portrait">${corners2()}<div class="portrait-window"><img id="companion-image" class="companion-artwork" src="${cardEscape(artwork || fallback)}" data-fallback="${cardEscape(fallback)}" alt="${cardEscape(card.name)}的形象图"></div></div>${card.description?.trim() ? `<p class="companion-description">${cardEscape(card.description.trim())}</p>` : ""}${bloodlines(card, icons)}</div>
3098
- <section class="companion-panel companion-stats" aria-label="${pet ? "宠物" : "随从"}属性">${corners2(["tr", "br"])}<div class="companion-identity"><h1 id="companion-name" class="companion-name">${cardEscape(card.name)}</h1><p class="companion-level">Lv. ${number3(card.level)}</p><div class="state-badge state-${state}">${pet ? paw : '<span aria-hidden="true">✦</span>'}<span>${stateName}</span>${pet ? paw : '<span aria-hidden="true">✦</span>'}</div>${pet ? "" : '<p class="permanent-note">战死后永久离队</p>'}</div>
3168
+ const stateName = enemy ? typeName : pet ? { active: "出战", resting: "休息", fallen: "倒下" }[state] : "自动参战";
3169
+ return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><style>${companionCardStyles}</style></head><body><main id="capture" class="companion-sheet ${kind}-theme${enemy ? " enemy-sheet" : ""}" data-kind="${kind}">${boss ? `<div class="boss-card-decoration">${bossCardDecoration}</div>` : ""}<div class="companion-main${enemy ? " enemy-main" : ""}">
3170
+ ${enemy ? "" : `<div class="portrait-column"><div class="companion-panel companion-portrait">${corners2()}<div class="portrait-window"><img id="companion-image" class="companion-artwork" src="${cardEscape(artwork || fallback)}" data-fallback="${cardEscape(fallback)}" alt="${cardEscape(card.name)}的形象图"></div></div>${card.description?.trim() ? `<p class="companion-description">${cardEscape(card.description.trim())}</p>` : ""}${bloodlines(card, icons)}</div>`}
3171
+ <section class="companion-panel companion-stats" aria-label="${typeName}属性">${corners2(["tr", "br"])}<div class="companion-identity"><h1 id="companion-name" class="companion-name">${cardEscape(card.name)}</h1><p class="companion-level">Lv. ${number3(card.level)}</p><div class="state-badge state-${state}">${pet ? paw : '<span aria-hidden="true">✦</span>'}<span>${stateName}</span>${pet ? paw : '<span aria-hidden="true">✦</span>'}</div>${kind === "follower" ? '<p class="permanent-note">战死后永久离队</p>' : ""}</div>
3099
3172
  <div class="companion-power-row"><span class="power-icon" aria-hidden="true">${sword}</span><span class="companion-power-label">战力</span><strong id="companion-power" class="companion-power">${number3(card.power)}</strong></div>
3100
3173
  <div class="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="companion-hp" class="resource-number">${number3(card.hp)} / ${number3(card.maxHp)}</span></div><div class="resource-track" role="progressbar" aria-label="生命值" aria-valuemin="0" aria-valuemax="100" aria-valuenow="${healthPercent}"><span class="resource-fill" style="width:${healthPercent}%"></span><span class="resource-percent">${number3(healthPercent)}%</span></div></div>
3101
3174
  ${pet ? `<div class="companion-resource exp-resource"><div class="resource-heading"><span class="resource-label"><svg viewBox="0 0 32 32" aria-hidden="true"><path d="m16 2 4.5 9.1 10 1.4-7.3 7.1 1.7 10-8.9-4.7-8.9 4.7 1.7-10-7.3-7.1 10-1.4Z"/></svg>经验进度</span><span class="resource-number">${number3(experience)}%</span></div><div class="resource-track" role="progressbar" aria-label="经验进度" aria-valuemin="0" aria-valuemax="100" aria-valuenow="${experience}"><span class="resource-fill" style="width:${experience}%"></span><span class="resource-percent">${number3(experience)}%</span></div></div>` : ""}
3102
- <section class="companion-attributes" aria-label="一级属性">${heading("一级属性")}${radar2(card)}</section></section>
3103
- </div>${skills(card, icons)}</main></body></html>`;
3175
+ ${enemy ? '</section><section class="companion-panel enemy-attributes">' : ""}<section class="companion-attributes" aria-label="一级属性">${heading("一级属性")}${radar2(card)}</section></section>
3176
+ </div>${enemy ? bloodlines(card, icons) : ""}${skills(card, icons)}${equipment(card)}</main></body></html>`;
3104
3177
  }
3105
3178
  __name(companionCardHtml, "companionCardHtml");
3106
3179
 
@@ -3692,8 +3765,8 @@ function bloodlineCardHtml(card, artwork) {
3692
3765
  const nextExperience = finite4(card.nextExperience ?? 0);
3693
3766
  const experience = Math.max(0, finite4(card.experience ?? 0));
3694
3767
  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>`;
3695
- const equipment = [...card.equipmentTypes].sort((a, b) => Number(/^[a-z]/i.test(a.type)) - Number(/^[a-z]/i.test(b.type)));
3696
- 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>';
3768
+ const equipment2 = [...card.equipmentTypes].sort((a, b) => Number(/^[a-z]/i.test(a.type)) - Number(/^[a-z]/i.test(b.type)));
3769
+ const unlocks = equipment2.length ? `<div class="equipment-grid">${equipment2.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>';
3697
3770
  const perLevel = card.type === "血统道具" && card.level === 1;
3698
3771
  const customAttributes = card.attributes.filter((attribute) => !classicIds.has(attribute.id));
3699
3772
  const extraAttributes = customAttributes.length ? `<div class="bloodline-custom-attributes">${customAttributes.map((attribute) => cardStatRow(attribute.name?.trim() || attribute.id, signed(attribute.value), true)).join("")}</div>` : "";
@@ -4438,7 +4511,8 @@ async function renderUncached(ctx, card, leaderboard, itemCard, characterCard, e
4438
4511
  }, "release");
4439
4512
  try {
4440
4513
  const work = /* @__PURE__ */ __name(async () => {
4441
- const remoteAddress = signinCard ? void 0 : titleCard ? titleCard.artworkUrl : bloodlineCard ? bloodlineCard.artworkUrl : equipmentCard ? equipmentCard.artworkUrl : companionCard ? companionCard.artworkUrl : characterCard ? characterCard.artworkUrl : itemCard ? itemCard.artworkUrl : leaderboard ? leaderboard.backgroundUrl : card?.artworkUrl;
4514
+ const encounterCard = companionCard?.kind === "monster" || companionCard?.kind === "boss";
4515
+ const remoteAddress = signinCard ? void 0 : titleCard ? titleCard.artworkUrl : bloodlineCard ? bloodlineCard.artworkUrl : equipmentCard ? equipmentCard.artworkUrl : companionCard ? encounterCard ? void 0 : companionCard.artworkUrl : characterCard ? characterCard.artworkUrl : itemCard ? itemCard.artworkUrl : leaderboard ? leaderboard.backgroundUrl : card?.artworkUrl;
4442
4516
  const isEquipment = !signinCard && !titleCard && !bloodlineCard && Boolean(equipmentCard);
4443
4517
  const isCharacter = !signinCard && !titleCard && !bloodlineCard && !equipmentCard && !companionCard && Boolean(characterCard);
4444
4518
  const [remoteArt, fallbackArt, entryArtwork, characterAssets, header, signinAssets] = await Promise.all([
@@ -2,3 +2,4 @@
2
2
  export declare const companionCornerDecoration = "<svg viewBox=\"0 0 180 180\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M7 156C9 84 17 23 94 9M17 124C31 81 47 59 87 40M41 69C57 45 75 31 121 26M48 43C72 26 89 20 143 19\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"/>\n <path d=\"M15 112C-1 86 2 67 11 57c17 20 22 34 4 55ZM26 79C15 47 21 28 37 23c10 25 10 45-11 56ZM47 53C53 29 66 19 87 18c-5 20-17 32-40 35ZM79 32c19-15 35-20 56-13-12 13-31 19-56 13Z\" fill=\"currentColor\" opacity=\".6\"/>\n <path d=\"M14 133c-3-27 15-47 34-49-1 23-13 41-34 49ZM32 94c6-28 26-42 45-42-8 24-22 39-45 42ZM66 49c18-20 36-24 56-15-17 17-33 21-56 15Z\" fill=\"currentColor\" opacity=\".35\"/>\n <g transform=\"translate(39 39)\">\n <g fill=\"var(--flower)\" stroke=\"currentColor\" stroke-width=\"1.2\">\n <ellipse cx=\"0\" cy=\"-18\" rx=\"10\" ry=\"18\"/><ellipse cx=\"0\" cy=\"-18\" rx=\"10\" ry=\"18\" transform=\"rotate(72)\"/>\n <ellipse cx=\"0\" cy=\"-18\" rx=\"10\" ry=\"18\" transform=\"rotate(144)\"/><ellipse cx=\"0\" cy=\"-18\" rx=\"10\" ry=\"18\" transform=\"rotate(216)\"/><ellipse cx=\"0\" cy=\"-18\" rx=\"10\" ry=\"18\" transform=\"rotate(288)\"/>\n </g><circle r=\"7\" fill=\"currentColor\"/><circle r=\"3\" fill=\"var(--flower)\"/>\n </g>\n <g transform=\"translate(12 109) scale(.48)\"><g fill=\"var(--flower)\" stroke=\"currentColor\" stroke-width=\"2\"><ellipse cx=\"0\" cy=\"-18\" rx=\"10\" ry=\"18\"/><ellipse cx=\"0\" cy=\"-18\" rx=\"10\" ry=\"18\" transform=\"rotate(72)\"/><ellipse cx=\"0\" cy=\"-18\" rx=\"10\" ry=\"18\" transform=\"rotate(144)\"/><ellipse cx=\"0\" cy=\"-18\" rx=\"10\" ry=\"18\" transform=\"rotate(216)\"/><ellipse cx=\"0\" cy=\"-18\" rx=\"10\" ry=\"18\" transform=\"rotate(288)\"/></g><circle r=\"7\" fill=\"currentColor\"/></g>\n</svg>";
3
3
  export declare const petPortraitPlaceholder: string;
4
4
  export declare const followerPortraitPlaceholder: string;
5
+ export declare const bossCardDecoration = "<svg viewBox=\"0 0 160 64\" aria-hidden=\"true\"><path d=\"M31 49 23 17l32 20L80 5l25 32 32-20-8 32ZM31 55h98\" fill=\"currentColor\" opacity=\".7\"/><path d=\"M9 51 26 39M134 39l17 12M5 58l19-10m112 0 19 10\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"/><circle cx=\"80\" cy=\"5\" r=\"4\" fill=\"currentColor\"/><circle cx=\"23\" cy=\"17\" r=\"3\" fill=\"currentColor\"/><circle cx=\"137\" cy=\"17\" r=\"3\" fill=\"currentColor\"/></svg>";
@@ -1,2 +1,2 @@
1
1
  /** Flow layout keeps every bloodline and skill row visible in bot/editor cards. */
2
- export declare const companionCardStyles = "\n*{box-sizing:border-box}body{margin:0;width:760px}#capture{width:760px;position:relative;overflow:hidden;font-family:\"KaiTi\",\"STKaiti\",\"Microsoft YaHei\",sans-serif}\n.companion-sheet{--ink:#594322;--subtle:#79715a;--accent:#b78328;--edge:#c7a66a;--light-edge:#fff2c8;--panel:#fffaf0;--panel-deep:#f1e5cc;--paper:#e8ce9c;--flower:#fff9dc;--track:#e3e7d8;--track-edge:#9fad94;--health:#69985c;--health-light:#a4c68d;--radar:#c79539;--radar-fill:#dcb35369;--radar-grid:#c8ba94;color:var(--ink);padding:22px;background:radial-gradient(ellipse at 5% 12%,#fff8dfb0,transparent 42%),radial-gradient(ellipse at 98% 79%,#fff5d8a6,transparent 44%),repeating-linear-gradient(115deg,#f6e7c94d 0 1px,transparent 1px 5px),linear-gradient(155deg,#d5b777,#f2dfb9 37%,#c7ac76)}\n.follower-theme{--ink:#e6e5dc;--subtle:#b7b7b2;--accent:#d3d3cf;--edge:#858585;--light-edge:#e5e5de;--panel:#242424;--panel-deep:#181818;--paper:#232323;--flower:#d6d6d0;--track:#353535;--track-edge:#7c7c7c;--health:#a3a3a0;--health-light:#d5d5cf;--radar:#e3e3dc;--radar-fill:#bdbdbd51;--radar-grid:#686868;background:radial-gradient(ellipse at 10% 9%,#9f9f9f40,transparent 43%),radial-gradient(ellipse at 94% 83%,#91919145,transparent 35%),repeating-linear-gradient(125deg,#dddddd07 0 1px,transparent 1px 5px),linear-gradient(155deg,#575757,#1e1e1e 37%,#4e4e4e)}\n.companion-main{display:grid;grid-template-columns:334px minmax(0,1fr);gap:14px;align-items:stretch;position:relative;z-index:1}.portrait-column{min-width:0;display:flex;flex-direction:column;gap:14px}\n.companion-panel{position:relative;border:2px solid var(--edge);border-radius:27px;background:radial-gradient(ellipse at 22% 0%,color-mix(in srgb,var(--light-edge) 20%,transparent),transparent 51%),linear-gradient(160deg,var(--panel),var(--panel-deep));box-shadow:inset 0 0 0 3px var(--panel),inset 0 0 0 4px color-mix(in srgb,var(--edge) 50%,transparent),0 2px 6px #32290f30;min-width:0}.companion-panel:before{content:\"\";position:absolute;inset:8px;border:1px solid color-mix(in srgb,var(--edge) 55%,transparent);border-radius:20px;pointer-events:none}.panel-corner{position:absolute;width:112px;height:112px;color:var(--edge);pointer-events:none;z-index:3}.panel-corner svg{width:100%;height:100%;display:block}.corner-tl{top:-14px;left:-14px}.corner-tr{top:-14px;right:-14px;transform:rotate(90deg)}.corner-bl{bottom:-14px;left:-14px;transform:rotate(-90deg)}.corner-br{bottom:-14px;right:-14px;transform:rotate(180deg)}\n.companion-portrait{padding:10px;border-radius:18px;flex:0 0 auto;background:linear-gradient(135deg,var(--light-edge),var(--edge) 28%,var(--light-edge) 55%,var(--edge))}.companion-portrait:before{inset:5px;border-radius:12px;border-color:var(--light-edge)}.portrait-window{height:448px;border:2px solid var(--edge);border-radius:9px;overflow:hidden;background:var(--paper)}.companion-artwork{display:block;width:100%;height:100%;object-fit:contain}.follower-theme .companion-artwork{filter:grayscale(1)}.companion-portrait .panel-corner{width:97px;height:97px}.portrait-placeholder,.companion-placeholder{height:100%;display:grid;place-items:center;color:var(--subtle);font:21px \"Microsoft YaHei\",sans-serif}\n.companion-description{font:16px/1.65 \"Microsoft YaHei\",sans-serif;overflow-wrap:anywhere;color:var(--subtle);margin:0 10px}.bloodline-panel{padding:10px 16px 17px;flex:1}.ornament-heading{display:flex;align-items:center;justify-content:center;gap:10px;margin:0 0 12px;font-size:25px;font-weight:700;letter-spacing:3px;line-height:1.3;color:var(--ink)}.ornament-heading:before,.ornament-heading:after{content:\"\";height:1px;flex:1;background:linear-gradient(90deg,transparent,var(--edge))}.ornament-heading:after{transform:rotate(180deg)}.heading-star{font-size:16px;color:var(--accent);letter-spacing:0}.bloodline-list{display:grid;gap:10px}.bloodline-row{display:grid;grid-template-columns:41px minmax(0,1fr) auto;align-items:center;gap:9px;padding:8px 10px;border:1px solid var(--edge);border-radius:7px;box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--edge) 13%,transparent);background:color-mix(in srgb,var(--panel) 55%,transparent)}.bloodline-crest{width:41px;height:41px;display:grid;place-items:center;border:1px solid var(--edge);background:var(--paper);border-radius:50%;font-family:\"Microsoft YaHei\",sans-serif;font-size:27px;color:var(--ink)}.bloodline-crest svg{width:29px;height:29px}.follower-theme .bloodline-crest{filter:grayscale(1)}.bloodline-name{font-size:21px;font-weight:700;line-height:1.4;overflow-wrap:anywhere}.bloodline-quality{min-width:34px;padding:4px 6px;text-align:center;border:1px solid var(--edge);border-radius:7px;background:var(--paper);font:26px/1 Georgia,\"Microsoft YaHei\",serif;color:var(--ink)}\n.companion-stats{padding:22px 19px 14px;display:flex;flex-direction:column}.companion-identity{text-align:center;padding:6px 0 0;min-width:0}.companion-name{font-size:47px;font-weight:700;letter-spacing:4px;line-height:1.15;overflow-wrap:anywhere;margin:0 0 3px;text-shadow:0 1px 0 color-mix(in srgb,var(--panel) 70%,transparent)}.companion-level{font:30px/1.4 Georgia,\"Microsoft YaHei\",serif;margin:0;color:var(--subtle);overflow-wrap:anywhere}.state-badge{margin:6px auto 0;width:max-content;max-width:100%;display:flex;align-items:center;gap:11px;padding:5px 17px;border:1px solid var(--edge);border-radius:18px;background:color-mix(in srgb,var(--accent) 13%,transparent);color:var(--ink);font-size:19px;line-height:1}.state-badge svg{width:17px;height:17px;fill:currentColor}.state-resting{color:var(--subtle)}.state-fallen{background:color-mix(in srgb,var(--subtle) 15%,transparent);color:var(--subtle)}.permanent-note{margin:6px 0 0;color:var(--subtle);font-size:17px;line-height:1.4;letter-spacing:1px}.companion-power-row{display:flex;align-items:center;gap:10px;margin:18px 0 17px;min-width:0}.power-icon{flex:0 0 46px;height:46px;display:grid;place-items:center;border-radius:50%;border:1px solid var(--edge);box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--panel) 75%,transparent);color:var(--accent);background:color-mix(in srgb,var(--accent) 13%,transparent)}.power-icon svg{width:29px;height:29px;stroke:currentColor;fill:currentColor;stroke-width:2;stroke-linejoin:round}.companion-power-label{font-size:21px;white-space:nowrap}.companion-power{min-width:0;flex:1;text-align:right;overflow-wrap:anywhere;font:38px/1.2 Georgia,\"Microsoft YaHei\",serif;color:var(--accent);letter-spacing:-1px}\n.companion-resource{font-family:\"Microsoft YaHei\",sans-serif;margin-bottom:15px}.resource-heading{display:flex;justify-content:space-between;align-items:baseline;gap:8px;font-size:18px;color:var(--subtle);line-height:1.45}.resource-label{display:flex;align-items:center;gap:7px;font-weight:600;flex-shrink:0}.resource-label svg{width:20px;height:20px;fill:var(--health)}.resource-number{text-align:right;overflow-wrap:anywhere;min-width:0;font-size:17px}.resource-track{height:20px;position:relative;margin-top:7px;border:1px solid var(--track-edge);border-radius:11px;overflow:hidden;background:linear-gradient(var(--track),color-mix(in srgb,var(--track) 70%,var(--panel)));box-shadow:inset 0 1px 3px #30362030}.resource-fill{display:block;position:absolute;top:0;bottom:0;left:0;border-radius:10px;background:linear-gradient(var(--health-light),var(--health) 48%,color-mix(in srgb,var(--health) 75%,var(--health-light)));border-right:1px solid #fff8}.resource-percent{position:absolute;inset:0;display:grid;place-items:center;font:12px/1 \"Microsoft YaHei\",sans-serif;color:#fffef7;text-shadow:0 1px 2px #37422d}.exp-resource .resource-heading{color:#63809b}.exp-resource .resource-label svg{fill:#6f95b3}.exp-resource .resource-track{border-color:#91adc0;background:#e2e9ed}.exp-resource .resource-fill{background:linear-gradient(#b5d9e5,#74a4c0 50%,#9bc5d6)}\n.companion-attributes{margin-top:3px;flex:1;display:flex;flex-direction:column;justify-content:center;min-width:0}.companion-attributes .ornament-heading{margin-bottom:4px;font-size:22px;gap:6px;letter-spacing:2px}.companion-radar{width:100%;height:300px;display:block;overflow:visible}.radar-grid{fill:none;stroke:var(--radar-grid);stroke-width:1.2}.radar-axis{stroke:var(--radar-grid);stroke-width:1;opacity:.8}.radar-area{fill:var(--radar-fill);stroke:var(--radar);stroke-width:2.5;stroke-linejoin:round}.radar-dot{fill:var(--flower);stroke:var(--radar);stroke-width:2}.radar-label{font:18px \"Microsoft YaHei\",sans-serif;fill:var(--ink)}.radar-value{font:20px Georgia,\"Microsoft YaHei\",serif;fill:var(--ink)}.radar-scale{font:11px Georgia,serif;fill:var(--subtle)}.empty-attributes{padding:45px 10px;color:var(--subtle);font:18px/1.6 \"Microsoft YaHei\",sans-serif;text-align:center}.custom-attributes{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:5px 10px;margin:6px 0 0;font:15px/1.5 \"Microsoft YaHei\",sans-serif;color:var(--subtle)}.custom-attributes span{overflow-wrap:anywhere}.custom-attributes b{font-weight:500;color:var(--ink)}\n.companion-skills{position:relative;z-index:1;padding:12px 18px 19px;margin-top:15px}.companion-skills .ornament-heading{margin-bottom:13px}.skill-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 13px}.companion-skill{position:relative;min-width:0;display:grid;grid-template-columns:47px minmax(0,1fr) auto;align-items:center;gap:10px;padding:9px 10px;border:1px solid var(--edge);border-radius:7px;box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--edge) 12%,transparent);background:color-mix(in srgb,var(--panel) 55%,transparent);min-height:65px}.skill-icon{width:47px;height:47px;border:1px solid var(--edge);border-radius:7px;display:grid;place-items:center;background:radial-gradient(ellipse at 40% 23%,color-mix(in srgb,var(--accent) 55%,var(--paper)),color-mix(in srgb,var(--paper) 72%,#282015));color:var(--flower);box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--light-edge) 20%,transparent)}.skill-icon svg{width:31px;height:31px;stroke:currentColor;stroke-width:1.7;fill:none;stroke-linecap:round;stroke-linejoin:round}.skill-name{font-size:20px;font-weight:700;overflow-wrap:anywhere;line-height:1.35}.skill-level{font:18px/1.2 Georgia,\"Microsoft YaHei\",serif;border:1px solid color-mix(in srgb,var(--edge) 55%,transparent);border-radius:13px;padding:5px 9px;white-space:nowrap;color:var(--ink);background:color-mix(in srgb,var(--accent) 9%,transparent)}.empty-list{margin:10px 0;color:var(--subtle);font:17px/1.6 \"Microsoft YaHei\",sans-serif;text-align:center}.follower-theme .companion-panel{box-shadow:inset 0 0 0 3px var(--panel),inset 0 0 0 4px color-mix(in srgb,var(--edge) 50%,transparent),0 2px 6px #00000040}.follower-theme .skill-icon{background:radial-gradient(ellipse at 40% 23%,#858585,#292929)}.follower-theme .resource-track{box-shadow:inset 0 1px 3px #00000030}.follower-theme .companion-power{color:var(--ink)}.follower-theme .resource-percent{color:#fffef7;text-shadow:0 1px 2px #242725}\n.skill-icon,.bloodline-crest{position:relative;overflow:hidden}.bloodline-crest.has-entry-artwork{border-radius:7px}.skill-entry-artwork,.bloodline-entry-artwork{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;border-radius:inherit;background:var(--paper);z-index:1}.follower-theme .skill-entry-artwork,.follower-theme .bloodline-entry-artwork{filter:grayscale(1)}\n";
2
+ export declare const companionCardStyles = "\n*{box-sizing:border-box}body{margin:0;width:760px}#capture{width:760px;position:relative;overflow:hidden;font-family:\"KaiTi\",\"STKaiti\",\"Microsoft YaHei\",sans-serif}\n.companion-sheet{--ink:#594322;--subtle:#79715a;--accent:#b78328;--edge:#c7a66a;--light-edge:#fff2c8;--panel:#fffaf0;--panel-deep:#f1e5cc;--paper:#e8ce9c;--flower:#fff9dc;--track:#e3e7d8;--track-edge:#9fad94;--health:#69985c;--health-light:#a4c68d;--radar:#c79539;--radar-fill:#dcb35369;--radar-grid:#c8ba94;color:var(--ink);padding:22px;background:radial-gradient(ellipse at 5% 12%,#fff8dfb0,transparent 42%),radial-gradient(ellipse at 98% 79%,#fff5d8a6,transparent 44%),repeating-linear-gradient(115deg,#f6e7c94d 0 1px,transparent 1px 5px),linear-gradient(155deg,#d5b777,#f2dfb9 37%,#c7ac76)}\n.follower-theme{--ink:#e6e5dc;--subtle:#b7b7b2;--accent:#d3d3cf;--edge:#858585;--light-edge:#e5e5de;--panel:#242424;--panel-deep:#181818;--paper:#232323;--flower:#d6d6d0;--track:#353535;--track-edge:#7c7c7c;--health:#a3a3a0;--health-light:#d5d5cf;--radar:#e3e3dc;--radar-fill:#bdbdbd51;--radar-grid:#686868;background:radial-gradient(ellipse at 10% 9%,#9f9f9f40,transparent 43%),radial-gradient(ellipse at 94% 83%,#91919145,transparent 35%),repeating-linear-gradient(125deg,#dddddd07 0 1px,transparent 1px 5px),linear-gradient(155deg,#575757,#1e1e1e 37%,#4e4e4e)}\n.companion-main{display:grid;grid-template-columns:334px minmax(0,1fr);gap:14px;align-items:stretch;position:relative;z-index:1}.portrait-column{min-width:0;display:flex;flex-direction:column;gap:14px}\n.companion-panel{position:relative;border:2px solid var(--edge);border-radius:27px;background:radial-gradient(ellipse at 22% 0%,color-mix(in srgb,var(--light-edge) 20%,transparent),transparent 51%),linear-gradient(160deg,var(--panel),var(--panel-deep));box-shadow:inset 0 0 0 3px var(--panel),inset 0 0 0 4px color-mix(in srgb,var(--edge) 50%,transparent),0 2px 6px #32290f30;min-width:0}.companion-panel:before{content:\"\";position:absolute;inset:8px;border:1px solid color-mix(in srgb,var(--edge) 55%,transparent);border-radius:20px;pointer-events:none}.panel-corner{position:absolute;width:112px;height:112px;color:var(--edge);pointer-events:none;z-index:3}.panel-corner svg{width:100%;height:100%;display:block}.corner-tl{top:-14px;left:-14px}.corner-tr{top:-14px;right:-14px;transform:rotate(90deg)}.corner-bl{bottom:-14px;left:-14px;transform:rotate(-90deg)}.corner-br{bottom:-14px;right:-14px;transform:rotate(180deg)}\n.companion-portrait{padding:10px;border-radius:18px;flex:0 0 auto;background:linear-gradient(135deg,var(--light-edge),var(--edge) 28%,var(--light-edge) 55%,var(--edge))}.companion-portrait:before{inset:5px;border-radius:12px;border-color:var(--light-edge)}.portrait-window{height:448px;border:2px solid var(--edge);border-radius:9px;overflow:hidden;background:var(--paper)}.companion-artwork{display:block;width:100%;height:100%;object-fit:contain}.follower-theme .companion-artwork{filter:grayscale(1)}.companion-portrait .panel-corner{width:97px;height:97px}.portrait-placeholder,.companion-placeholder{height:100%;display:grid;place-items:center;color:var(--subtle);font:21px \"Microsoft YaHei\",sans-serif}\n.companion-description{font:16px/1.65 \"Microsoft YaHei\",sans-serif;overflow-wrap:anywhere;color:var(--subtle);margin:0 10px}.bloodline-panel{padding:10px 16px 17px;flex:1}.ornament-heading{display:flex;align-items:center;justify-content:center;gap:10px;margin:0 0 12px;font-size:25px;font-weight:700;letter-spacing:3px;line-height:1.3;color:var(--ink)}.ornament-heading:before,.ornament-heading:after{content:\"\";height:1px;flex:1;background:linear-gradient(90deg,transparent,var(--edge))}.ornament-heading:after{transform:rotate(180deg)}.heading-star{font-size:16px;color:var(--accent);letter-spacing:0}.bloodline-list{display:grid;gap:10px}.bloodline-row{display:grid;grid-template-columns:41px minmax(0,1fr) auto;align-items:center;gap:9px;padding:8px 10px;border:1px solid var(--edge);border-radius:7px;box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--edge) 13%,transparent);background:color-mix(in srgb,var(--panel) 55%,transparent)}.bloodline-crest{width:41px;height:41px;display:grid;place-items:center;border:1px solid var(--edge);background:var(--paper);border-radius:50%;font-family:\"Microsoft YaHei\",sans-serif;font-size:27px;color:var(--ink)}.bloodline-crest svg{width:29px;height:29px}.follower-theme .bloodline-crest{filter:grayscale(1)}.bloodline-name{font-size:21px;font-weight:700;line-height:1.4;overflow-wrap:anywhere}.bloodline-quality{min-width:34px;padding:4px 6px;text-align:center;border:1px solid var(--edge);border-radius:7px;background:var(--paper);font:26px/1 Georgia,\"Microsoft YaHei\",serif;color:var(--ink)}\n.companion-stats{padding:22px 19px 14px;display:flex;flex-direction:column}.companion-identity{text-align:center;padding:6px 0 0;min-width:0}.companion-name{font-size:47px;font-weight:700;letter-spacing:4px;line-height:1.15;overflow-wrap:anywhere;margin:0 0 3px;text-shadow:0 1px 0 color-mix(in srgb,var(--panel) 70%,transparent)}.companion-level{font:30px/1.4 Georgia,\"Microsoft YaHei\",serif;margin:0;color:var(--subtle);overflow-wrap:anywhere}.state-badge{margin:6px auto 0;width:max-content;max-width:100%;display:flex;align-items:center;gap:11px;padding:5px 17px;border:1px solid var(--edge);border-radius:18px;background:color-mix(in srgb,var(--accent) 13%,transparent);color:var(--ink);font-size:19px;line-height:1}.state-badge svg{width:17px;height:17px;fill:currentColor}.state-resting{color:var(--subtle)}.state-fallen{background:color-mix(in srgb,var(--subtle) 15%,transparent);color:var(--subtle)}.permanent-note{margin:6px 0 0;color:var(--subtle);font-size:17px;line-height:1.4;letter-spacing:1px}.companion-power-row{display:flex;align-items:center;gap:10px;margin:18px 0 17px;min-width:0}.power-icon{flex:0 0 46px;height:46px;display:grid;place-items:center;border-radius:50%;border:1px solid var(--edge);box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--panel) 75%,transparent);color:var(--accent);background:color-mix(in srgb,var(--accent) 13%,transparent)}.power-icon svg{width:29px;height:29px;stroke:currentColor;fill:currentColor;stroke-width:2;stroke-linejoin:round}.companion-power-label{font-size:21px;white-space:nowrap}.companion-power{min-width:0;flex:1;text-align:right;overflow-wrap:anywhere;font:38px/1.2 Georgia,\"Microsoft YaHei\",serif;color:var(--accent);letter-spacing:-1px}\n.companion-resource{font-family:\"Microsoft YaHei\",sans-serif;margin-bottom:15px}.resource-heading{display:flex;justify-content:space-between;align-items:baseline;gap:8px;font-size:18px;color:var(--subtle);line-height:1.45}.resource-label{display:flex;align-items:center;gap:7px;font-weight:600;flex-shrink:0}.resource-label svg{width:20px;height:20px;fill:var(--health)}.resource-number{text-align:right;overflow-wrap:anywhere;min-width:0;font-size:17px}.resource-track{height:20px;position:relative;margin-top:7px;border:1px solid var(--track-edge);border-radius:11px;overflow:hidden;background:linear-gradient(var(--track),color-mix(in srgb,var(--track) 70%,var(--panel)));box-shadow:inset 0 1px 3px #30362030}.resource-fill{display:block;position:absolute;top:0;bottom:0;left:0;border-radius:10px;background:linear-gradient(var(--health-light),var(--health) 48%,color-mix(in srgb,var(--health) 75%,var(--health-light)));border-right:1px solid #fff8}.resource-percent{position:absolute;inset:0;display:grid;place-items:center;font:12px/1 \"Microsoft YaHei\",sans-serif;color:#fffef7;text-shadow:0 1px 2px #37422d}.exp-resource .resource-heading{color:#63809b}.exp-resource .resource-label svg{fill:#6f95b3}.exp-resource .resource-track{border-color:#91adc0;background:#e2e9ed}.exp-resource .resource-fill{background:linear-gradient(#b5d9e5,#74a4c0 50%,#9bc5d6)}\n.companion-attributes{margin-top:3px;flex:1;display:flex;flex-direction:column;justify-content:center;min-width:0}.companion-attributes .ornament-heading{margin-bottom:4px;font-size:22px;gap:6px;letter-spacing:2px}.companion-radar{width:100%;height:300px;display:block;overflow:visible}.radar-grid{fill:none;stroke:var(--radar-grid);stroke-width:1.2}.radar-axis{stroke:var(--radar-grid);stroke-width:1;opacity:.8}.radar-area{fill:var(--radar-fill);stroke:var(--radar);stroke-width:2.5;stroke-linejoin:round}.radar-dot{fill:var(--flower);stroke:var(--radar);stroke-width:2}.radar-label{font:18px \"Microsoft YaHei\",sans-serif;fill:var(--ink)}.radar-value{font:20px Georgia,\"Microsoft YaHei\",serif;fill:var(--ink)}.radar-scale{font:11px Georgia,serif;fill:var(--subtle)}.empty-attributes{padding:45px 10px;color:var(--subtle);font:18px/1.6 \"Microsoft YaHei\",sans-serif;text-align:center}.custom-attributes{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:5px 10px;margin:6px 0 0;font:15px/1.5 \"Microsoft YaHei\",sans-serif;color:var(--subtle)}.custom-attributes span{overflow-wrap:anywhere}.custom-attributes b{font-weight:500;color:var(--ink)}\n.companion-skills{position:relative;z-index:1;padding:12px 18px 19px;margin-top:15px}.companion-skills .ornament-heading{margin-bottom:13px}.skill-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 13px}.companion-skill{position:relative;min-width:0;display:grid;grid-template-columns:47px minmax(0,1fr) auto;align-items:center;gap:10px;padding:9px 10px;border:1px solid var(--edge);border-radius:7px;box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--edge) 12%,transparent);background:color-mix(in srgb,var(--panel) 55%,transparent);min-height:65px}.skill-icon{width:47px;height:47px;border:1px solid var(--edge);border-radius:7px;display:grid;place-items:center;background:radial-gradient(ellipse at 40% 23%,color-mix(in srgb,var(--accent) 55%,var(--paper)),color-mix(in srgb,var(--paper) 72%,#282015));color:var(--flower);box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--light-edge) 20%,transparent)}.skill-icon svg{width:31px;height:31px;stroke:currentColor;stroke-width:1.7;fill:none;stroke-linecap:round;stroke-linejoin:round}.skill-name{font-size:20px;font-weight:700;overflow-wrap:anywhere;line-height:1.35}.skill-level{font:18px/1.2 Georgia,\"Microsoft YaHei\",serif;border:1px solid color-mix(in srgb,var(--edge) 55%,transparent);border-radius:13px;padding:5px 9px;white-space:nowrap;color:var(--ink);background:color-mix(in srgb,var(--accent) 9%,transparent)}.empty-list{margin:10px 0;color:var(--subtle);font:17px/1.6 \"Microsoft YaHei\",sans-serif;text-align:center}.follower-theme .companion-panel{box-shadow:inset 0 0 0 3px var(--panel),inset 0 0 0 4px color-mix(in srgb,var(--edge) 50%,transparent),0 2px 6px #00000040}.follower-theme .skill-icon{background:radial-gradient(ellipse at 40% 23%,#858585,#292929)}.follower-theme .resource-track{box-shadow:inset 0 1px 3px #00000030}.follower-theme .companion-power{color:var(--ink)}.follower-theme .resource-percent{color:#fffef7;text-shadow:0 1px 2px #242725}\n.skill-icon,.bloodline-crest{position:relative;overflow:hidden}.bloodline-crest.has-entry-artwork{border-radius:7px}.skill-entry-artwork,.bloodline-entry-artwork{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;border-radius:inherit;background:var(--paper);z-index:1}.follower-theme .skill-entry-artwork,.follower-theme .bloodline-entry-artwork{filter:grayscale(1)}\n.monster-theme{--ink:#e0eeea;--subtle:#a2b9b6;--accent:#9bd8c9;--edge:#668f90;--light-edge:#c3e5d7;--panel:#203f48;--panel-deep:#142d38;--paper:#183440;--flower:#d3efe6;--track:#213c46;--track-edge:#769b92;--health:#518f7f;--health-light:#96d6b5;--radar:#a2d8c9;--radar-fill:#7bb5ab55;--radar-grid:#507d80;background:radial-gradient(ellipse at 10% 9%,#81b8a840,transparent 43%),radial-gradient(ellipse at 94% 83%,#49808045,transparent 35%),repeating-linear-gradient(125deg,#d6eee608 0 1px,transparent 1px 5px),linear-gradient(155deg,#3c6269,#142a35 37%,#30515a)}\n.boss-theme{--ink:#f7e2c3;--subtle:#ceafac;--accent:#edc385;--edge:#b77c62;--light-edge:#f5dba4;--panel:#492937;--panel-deep:#281b2a;--paper:#342132;--flower:#ffe6b2;--track:#4b2837;--track-edge:#b88170;--health:#a24d59;--health-light:#eb9395;--radar:#edc385;--radar-fill:#daaa5b55;--radar-grid:#925c64;padding-top:55px;background:radial-gradient(ellipse at 48% 0%,#ecc07855,transparent 40%),radial-gradient(ellipse at 96% 83%,#c54a6245,transparent 35%),repeating-linear-gradient(125deg,#f2dfbd08 0 1px,transparent 1px 5px),linear-gradient(155deg,#773b46,#211b2c 37%,#5d2c42)}\n.boss-card-decoration{position:absolute;top:3px;left:50%;transform:translateX(-50%);width:160px;height:52px;color:var(--accent)}.boss-card-decoration svg{display:block;width:100%;height:100%}.boss-theme .companion-portrait,.boss-theme .companion-stats{box-shadow:inset 0 0 0 3px var(--panel),inset 0 0 0 4px color-mix(in srgb,var(--edge) 60%,transparent),0 0 13px #daa04e40}.boss-theme .state-badge{border-radius:5px;letter-spacing:3px;background:linear-gradient(135deg,#b6805130,#8c44502b);padding:7px 15px}.monster-theme .state-badge{letter-spacing:2px}\n.enemy-equipment{padding:13px 18px 18px;margin-top:15px}.enemy-equipment-list{display:grid;gap:8px}.enemy-equipment-row{display:grid;grid-template-columns:28px minmax(0,1fr) auto auto;align-items:center;gap:10px;padding:8px 11px;border:1px solid var(--edge);border-radius:7px;background:color-mix(in srgb,var(--panel) 55%,transparent);min-width:0}.equipment-symbol{color:var(--accent);font-size:26px}.enemy-equipment-name{font-size:20px;line-height:1.4;overflow-wrap:anywhere}.enemy-equipment-name small{color:var(--accent);font:17px Georgia,serif;white-space:nowrap}.equipment-slot{font:15px/1.4 \"Microsoft YaHei\",sans-serif;color:var(--subtle);max-width:120px;overflow-wrap:anywhere}\n.enemy-main{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.enemy-sheet .companion-stats{justify-content:center;padding:24px 24px 26px}.enemy-sheet .companion-name{font-size:43px;letter-spacing:2px}.enemy-sheet .companion-power-row{margin:24px 0}.enemy-sheet .companion-resource{margin-bottom:0}.enemy-attributes{padding:16px 12px 12px;display:flex;align-items:center}.enemy-attributes .companion-attributes{margin:0}.enemy-sheet>.bloodline-panel{margin-top:15px;padding:13px 18px 18px}.enemy-sheet .bloodline-list{grid-template-columns:repeat(2,minmax(0,1fr))}.enemy-sheet .bloodline-name{font-size:20px}\n\n";
@@ -4,5 +4,5 @@ export interface CardEntryArtwork {
4
4
  skills?: ReadonlyArray<string | undefined>;
5
5
  bloodlines?: ReadonlyArray<string | undefined>;
6
6
  }
7
- /** Opaque portraits stay framed. Bloodline and skill lists grow in normal document flow. */
7
+ /** Pets/followers keep portraits; encounters show fixed combat data without disposable artwork. */
8
8
  export declare function companionCardHtml(card: CompanionCardData, artwork?: string, icons?: CardEntryArtwork): string;
@@ -5,7 +5,7 @@ export interface ReqStatistics extends BaseRequest {
5
5
  export interface ResStatistics extends BaseResponse {
6
6
  /** 统计快照生成时间,Unix 毫秒。 */
7
7
  generatedAt: number;
8
- /** 普通玩家最近游戏消息的在线窗口;处理指令、自动探索可延续在线。 */
8
+ /** 普通玩家最近游戏消息的在线窗口;处理指令可延续在线。 */
9
9
  onlineWindowMs: number;
10
10
  /** 服务端快照缓存时长。 */
11
11
  cacheTtlMs: number;
@@ -83,7 +83,9 @@ export interface CharacterCardData {
83
83
  }
84
84
  export declare enum CompanionCardKind {
85
85
  pet = "pet",
86
- follower = "follower"
86
+ follower = "follower",
87
+ monster = "monster",
88
+ boss = "boss"
87
89
  }
88
90
  export declare enum CompanionCardState {
89
91
  active = "active",
@@ -94,7 +96,7 @@ export declare enum CompanionSkillType {
94
96
  active = "active",
95
97
  passive = "passive"
96
98
  }
97
- /** 宠物与随从的属性图片;完整技能与血统由服务端按当前构筑提供。 */
99
+ /** 伙伴与探索敌人的属性图片;探索详情读取本次已冻结的实际参战快照。 */
98
100
  export interface CompanionCardData {
99
101
  kind: CompanionCardKind;
100
102
  /** 已保存形象的临时 HTTPS 链接;缺图时由客户端显示伙伴占位。 */
@@ -129,6 +131,14 @@ export interface CompanionCardData {
129
131
  type?: CompanionSkillType;
130
132
  artworkUrl?: string;
131
133
  }>;
134
+ /** 本场怪物实际生效的装备;伙伴详情可省略。字段追加,保留既有协议编号。 */
135
+ equipment?: Array<{
136
+ id: string;
137
+ name: string;
138
+ quality: string;
139
+ slot: string;
140
+ enhancement?: number;
141
+ }>;
132
142
  }
133
143
  export interface ItemCardData {
134
144
  artworkUrl?: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-dew-bot",
3
3
  "description": "基于《无限恐怖》小说改编的 RPG 机器人。踏入主神空间,与伙伴迎接轮回试炼,书写属于你的无限冒险。",
4
- "version": "1.0.264",
4
+ "version": "1.0.265",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -31,3 +31,5 @@ export const followerPortraitPlaceholder = image(`<svg xmlns="http://www.w3.org/
31
31
  <g fill="#1d1d1d" stroke="#a7a7a7" stroke-width="2"><path d="M158 485c7-79 20-135 42-166 15-44 29-83 70-88 46 7 58 45 73 89 19 29 37 87 42 166Z"/><path d="M218 297c-4-50 14-87 52-88 39 1 58 38 52 89l-19-9-13-30-20-12-22 12-11 30Z"/><path d="m216 316 54 66 54-66M197 358l-26 117m172-117 27 117" fill="none"/><path d="m247 287 23 20 24-20-11 48h-26Z" fill="#808080" stroke="none"/></g>
32
32
  <text x="270" y="551" text-anchor="middle" font-family="Microsoft YaHei,sans-serif" font-size="26" letter-spacing="4" fill="#e1e0d6">暂无随从形象</text>
33
33
  </svg>`)
34
+
35
+ export const bossCardDecoration = '<svg viewBox="0 0 160 64" aria-hidden="true"><path d="M31 49 23 17l32 20L80 5l25 32 32-20-8 32ZM31 55h98" fill="currentColor" opacity=".7"/><path d="M9 51 26 39M134 39l17 12M5 58l19-10m112 0 19 10" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="80" cy="5" r="4" fill="currentColor"/><circle cx="23" cy="17" r="3" fill="currentColor"/><circle cx="137" cy="17" r="3" fill="currentColor"/></svg>'
@@ -12,4 +12,10 @@ export const companionCardStyles = `
12
12
  .companion-attributes{margin-top:3px;flex:1;display:flex;flex-direction:column;justify-content:center;min-width:0}.companion-attributes .ornament-heading{margin-bottom:4px;font-size:22px;gap:6px;letter-spacing:2px}.companion-radar{width:100%;height:300px;display:block;overflow:visible}.radar-grid{fill:none;stroke:var(--radar-grid);stroke-width:1.2}.radar-axis{stroke:var(--radar-grid);stroke-width:1;opacity:.8}.radar-area{fill:var(--radar-fill);stroke:var(--radar);stroke-width:2.5;stroke-linejoin:round}.radar-dot{fill:var(--flower);stroke:var(--radar);stroke-width:2}.radar-label{font:18px "Microsoft YaHei",sans-serif;fill:var(--ink)}.radar-value{font:20px Georgia,"Microsoft YaHei",serif;fill:var(--ink)}.radar-scale{font:11px Georgia,serif;fill:var(--subtle)}.empty-attributes{padding:45px 10px;color:var(--subtle);font:18px/1.6 "Microsoft YaHei",sans-serif;text-align:center}.custom-attributes{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:5px 10px;margin:6px 0 0;font:15px/1.5 "Microsoft YaHei",sans-serif;color:var(--subtle)}.custom-attributes span{overflow-wrap:anywhere}.custom-attributes b{font-weight:500;color:var(--ink)}
13
13
  .companion-skills{position:relative;z-index:1;padding:12px 18px 19px;margin-top:15px}.companion-skills .ornament-heading{margin-bottom:13px}.skill-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 13px}.companion-skill{position:relative;min-width:0;display:grid;grid-template-columns:47px minmax(0,1fr) auto;align-items:center;gap:10px;padding:9px 10px;border:1px solid var(--edge);border-radius:7px;box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--edge) 12%,transparent);background:color-mix(in srgb,var(--panel) 55%,transparent);min-height:65px}.skill-icon{width:47px;height:47px;border:1px solid var(--edge);border-radius:7px;display:grid;place-items:center;background:radial-gradient(ellipse at 40% 23%,color-mix(in srgb,var(--accent) 55%,var(--paper)),color-mix(in srgb,var(--paper) 72%,#282015));color:var(--flower);box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--light-edge) 20%,transparent)}.skill-icon svg{width:31px;height:31px;stroke:currentColor;stroke-width:1.7;fill:none;stroke-linecap:round;stroke-linejoin:round}.skill-name{font-size:20px;font-weight:700;overflow-wrap:anywhere;line-height:1.35}.skill-level{font:18px/1.2 Georgia,"Microsoft YaHei",serif;border:1px solid color-mix(in srgb,var(--edge) 55%,transparent);border-radius:13px;padding:5px 9px;white-space:nowrap;color:var(--ink);background:color-mix(in srgb,var(--accent) 9%,transparent)}.empty-list{margin:10px 0;color:var(--subtle);font:17px/1.6 "Microsoft YaHei",sans-serif;text-align:center}.follower-theme .companion-panel{box-shadow:inset 0 0 0 3px var(--panel),inset 0 0 0 4px color-mix(in srgb,var(--edge) 50%,transparent),0 2px 6px #00000040}.follower-theme .skill-icon{background:radial-gradient(ellipse at 40% 23%,#858585,#292929)}.follower-theme .resource-track{box-shadow:inset 0 1px 3px #00000030}.follower-theme .companion-power{color:var(--ink)}.follower-theme .resource-percent{color:#fffef7;text-shadow:0 1px 2px #242725}
14
14
  .skill-icon,.bloodline-crest{position:relative;overflow:hidden}.bloodline-crest.has-entry-artwork{border-radius:7px}.skill-entry-artwork,.bloodline-entry-artwork{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:contain;border-radius:inherit;background:var(--paper);z-index:1}.follower-theme .skill-entry-artwork,.follower-theme .bloodline-entry-artwork{filter:grayscale(1)}
15
+ .monster-theme{--ink:#e0eeea;--subtle:#a2b9b6;--accent:#9bd8c9;--edge:#668f90;--light-edge:#c3e5d7;--panel:#203f48;--panel-deep:#142d38;--paper:#183440;--flower:#d3efe6;--track:#213c46;--track-edge:#769b92;--health:#518f7f;--health-light:#96d6b5;--radar:#a2d8c9;--radar-fill:#7bb5ab55;--radar-grid:#507d80;background:radial-gradient(ellipse at 10% 9%,#81b8a840,transparent 43%),radial-gradient(ellipse at 94% 83%,#49808045,transparent 35%),repeating-linear-gradient(125deg,#d6eee608 0 1px,transparent 1px 5px),linear-gradient(155deg,#3c6269,#142a35 37%,#30515a)}
16
+ .boss-theme{--ink:#f7e2c3;--subtle:#ceafac;--accent:#edc385;--edge:#b77c62;--light-edge:#f5dba4;--panel:#492937;--panel-deep:#281b2a;--paper:#342132;--flower:#ffe6b2;--track:#4b2837;--track-edge:#b88170;--health:#a24d59;--health-light:#eb9395;--radar:#edc385;--radar-fill:#daaa5b55;--radar-grid:#925c64;padding-top:55px;background:radial-gradient(ellipse at 48% 0%,#ecc07855,transparent 40%),radial-gradient(ellipse at 96% 83%,#c54a6245,transparent 35%),repeating-linear-gradient(125deg,#f2dfbd08 0 1px,transparent 1px 5px),linear-gradient(155deg,#773b46,#211b2c 37%,#5d2c42)}
17
+ .boss-card-decoration{position:absolute;top:3px;left:50%;transform:translateX(-50%);width:160px;height:52px;color:var(--accent)}.boss-card-decoration svg{display:block;width:100%;height:100%}.boss-theme .companion-portrait,.boss-theme .companion-stats{box-shadow:inset 0 0 0 3px var(--panel),inset 0 0 0 4px color-mix(in srgb,var(--edge) 60%,transparent),0 0 13px #daa04e40}.boss-theme .state-badge{border-radius:5px;letter-spacing:3px;background:linear-gradient(135deg,#b6805130,#8c44502b);padding:7px 15px}.monster-theme .state-badge{letter-spacing:2px}
18
+ .enemy-equipment{padding:13px 18px 18px;margin-top:15px}.enemy-equipment-list{display:grid;gap:8px}.enemy-equipment-row{display:grid;grid-template-columns:28px minmax(0,1fr) auto auto;align-items:center;gap:10px;padding:8px 11px;border:1px solid var(--edge);border-radius:7px;background:color-mix(in srgb,var(--panel) 55%,transparent);min-width:0}.equipment-symbol{color:var(--accent);font-size:26px}.enemy-equipment-name{font-size:20px;line-height:1.4;overflow-wrap:anywhere}.enemy-equipment-name small{color:var(--accent);font:17px Georgia,serif;white-space:nowrap}.equipment-slot{font:15px/1.4 "Microsoft YaHei",sans-serif;color:var(--subtle);max-width:120px;overflow-wrap:anywhere}
19
+ .enemy-main{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.enemy-sheet .companion-stats{justify-content:center;padding:24px 24px 26px}.enemy-sheet .companion-name{font-size:43px;letter-spacing:2px}.enemy-sheet .companion-power-row{margin:24px 0}.enemy-sheet .companion-resource{margin-bottom:0}.enemy-attributes{padding:16px 12px 12px;display:flex;align-items:center}.enemy-attributes .companion-attributes{margin:0}.enemy-sheet>.bloodline-panel{margin-top:15px;padding:13px 18px 18px}.enemy-sheet .bloodline-list{grid-template-columns:repeat(2,minmax(0,1fr))}.enemy-sheet .bloodline-name{font-size:20px}
20
+
15
21
  `
@@ -1,7 +1,7 @@
1
1
  import type { CompanionCardData } from '../shared/face'
2
2
  import { cardEscape } from './detailCardTemplate'
3
3
  import { companionCardStyles } from './companionCardStyles'
4
- import { companionCornerDecoration, followerPortraitPlaceholder, petPortraitPlaceholder } from './companionCardAssets'
4
+ import { bossCardDecoration, companionCornerDecoration, followerPortraitPlaceholder, petPortraitPlaceholder } from './companionCardAssets'
5
5
 
6
6
  /** Only renderer-loaded data URLs or editor-approved URLs, aligned with entry indices. */
7
7
  export interface CardEntryArtwork {
@@ -69,20 +69,29 @@ function skills(card: CompanionCardData, icons?: CardEntryArtwork): string {
69
69
  return `<section class="companion-panel companion-skills" aria-label="技能">${corners()}${heading('技能')}${card.skills.length ? `<div class="skill-grid">${card.skills.map((skill, index) => `<div class="companion-skill" data-skill-id="${cardEscape(skill.id)}"><span class="skill-icon" aria-hidden="true"><svg viewBox="0 0 36 36">${skill.type === 'passive' ? passive : active}</svg>${icons?.skills?.[index] ? `<img class="skill-entry-artwork" data-entry-index="${index}" src="${cardEscape(icons.skills[index])}" alt="">` : ''}</span><span class="skill-name">${cardEscape(skill.name)}</span><span class="skill-level">Lv.${number(skill.rank)}</span></div>`).join('')}</div>` : '<p class="empty-list">暂无技能</p>'}</section>`
70
70
  }
71
71
 
72
- /** Opaque portraits stay framed. Bloodline and skill lists grow in normal document flow. */
72
+ function equipment(card: CompanionCardData): string {
73
+ if (!card.equipment) return ''
74
+ return `<section class="companion-panel enemy-equipment" aria-label="装备">${heading('装备')}${card.equipment.length ? '<div class="enemy-equipment-list">' + card.equipment.map(item => `<div class="enemy-equipment-row"><span class="equipment-symbol" aria-hidden="true">✧</span><span class="enemy-equipment-name">${cardEscape(item.name)}${item.enhancement ? ' <small>+' + number(item.enhancement) + '</small>' : ''}</span><span class="equipment-slot">${cardEscape(item.slot)}</span><span class="bloodline-quality">${cardEscape(item.quality)}</span></div>`).join('') + '</div>' : '<p class="empty-list">暂无装备</p>'}</section>`
75
+ }
76
+
77
+ /** Pets/followers keep portraits; encounters show fixed combat data without disposable artwork. */
73
78
  export function companionCardHtml(card: CompanionCardData, artwork?: string, icons?: CardEntryArtwork): string {
74
79
  const pet = card.kind === 'pet'
80
+ const enemy = card.kind === 'monster' || card.kind === 'boss'
81
+ const boss = card.kind === 'boss'
82
+ const kind = enemy ? boss ? 'boss' : 'monster' : pet ? 'pet' : 'follower'
83
+ const typeName = enemy ? boss ? '首领' : '普通怪物' : pet ? '宠物' : '随从'
75
84
  const fallback = pet ? petPortraitPlaceholder : followerPortraitPlaceholder
76
85
  const healthPercent = ratio(card.hp, card.maxHp) * 100
77
86
  const experience = Math.max(0, Math.min(100, finite(card.experiencePercent ?? 0)))
78
87
  const state = pet ? card.state === 'fallen' ? 'fallen' : card.state === 'resting' ? 'resting' : 'active' : 'active'
79
- const stateName = pet ? { active: '出战', resting: '休息', fallen: '倒下' }[state] : '自动参战'
80
- return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><style>${companionCardStyles}</style></head><body><main id="capture" class="companion-sheet ${pet ? 'pet-theme' : 'follower-theme'}" data-kind="${pet ? 'pet' : 'follower'}"><div class="companion-main">
81
- <div class="portrait-column"><div class="companion-panel companion-portrait">${corners()}<div class="portrait-window"><img id="companion-image" class="companion-artwork" src="${cardEscape(artwork || fallback)}" data-fallback="${cardEscape(fallback)}" alt="${cardEscape(card.name)}的形象图"></div></div>${card.description?.trim() ? `<p class="companion-description">${cardEscape(card.description.trim())}</p>` : ''}${bloodlines(card, icons)}</div>
82
- <section class="companion-panel companion-stats" aria-label="${pet ? '宠物' : '随从'}属性">${corners(['tr', 'br'])}<div class="companion-identity"><h1 id="companion-name" class="companion-name">${cardEscape(card.name)}</h1><p class="companion-level">Lv. ${number(card.level)}</p><div class="state-badge state-${state}">${pet ? paw : '<span aria-hidden="true">✦</span>'}<span>${stateName}</span>${pet ? paw : '<span aria-hidden="true">✦</span>'}</div>${pet ? '' : '<p class="permanent-note">战死后永久离队</p>'}</div>
88
+ const stateName = enemy ? typeName : pet ? { active: '出战', resting: '休息', fallen: '倒下' }[state] : '自动参战'
89
+ return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><style>${companionCardStyles}</style></head><body><main id="capture" class="companion-sheet ${kind}-theme${enemy ? ' enemy-sheet' : ''}" data-kind="${kind}">${boss ? `<div class="boss-card-decoration">${bossCardDecoration}</div>` : ''}<div class="companion-main${enemy ? ' enemy-main' : ''}">
90
+ ${enemy ? '' : `<div class="portrait-column"><div class="companion-panel companion-portrait">${corners()}<div class="portrait-window"><img id="companion-image" class="companion-artwork" src="${cardEscape(artwork || fallback)}" data-fallback="${cardEscape(fallback)}" alt="${cardEscape(card.name)}的形象图"></div></div>${card.description?.trim() ? `<p class="companion-description">${cardEscape(card.description.trim())}</p>` : ''}${bloodlines(card, icons)}</div>`}
91
+ <section class="companion-panel companion-stats" aria-label="${typeName}属性">${corners(['tr', 'br'])}<div class="companion-identity"><h1 id="companion-name" class="companion-name">${cardEscape(card.name)}</h1><p class="companion-level">Lv. ${number(card.level)}</p><div class="state-badge state-${state}">${pet ? paw : '<span aria-hidden="true">✦</span>'}<span>${stateName}</span>${pet ? paw : '<span aria-hidden="true">✦</span>'}</div>${kind === 'follower' ? '<p class="permanent-note">战死后永久离队</p>' : ''}</div>
83
92
  <div class="companion-power-row"><span class="power-icon" aria-hidden="true">${sword}</span><span class="companion-power-label">战力</span><strong id="companion-power" class="companion-power">${number(card.power)}</strong></div>
84
93
  <div class="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="companion-hp" class="resource-number">${number(card.hp)} / ${number(card.maxHp)}</span></div><div class="resource-track" role="progressbar" aria-label="生命值" aria-valuemin="0" aria-valuemax="100" aria-valuenow="${healthPercent}"><span class="resource-fill" style="width:${healthPercent}%"></span><span class="resource-percent">${number(healthPercent)}%</span></div></div>
85
94
  ${pet ? `<div class="companion-resource exp-resource"><div class="resource-heading"><span class="resource-label"><svg viewBox="0 0 32 32" aria-hidden="true"><path d="m16 2 4.5 9.1 10 1.4-7.3 7.1 1.7 10-8.9-4.7-8.9 4.7 1.7-10-7.3-7.1 10-1.4Z"/></svg>经验进度</span><span class="resource-number">${number(experience)}%</span></div><div class="resource-track" role="progressbar" aria-label="经验进度" aria-valuemin="0" aria-valuemax="100" aria-valuenow="${experience}"><span class="resource-fill" style="width:${experience}%"></span><span class="resource-percent">${number(experience)}%</span></div></div>` : ''}
86
- <section class="companion-attributes" aria-label="一级属性">${heading('一级属性')}${radar(card)}</section></section>
87
- </div>${skills(card, icons)}</main></body></html>`
95
+ ${enemy ? '</section><section class="companion-panel enemy-attributes">' : ''}<section class="companion-attributes" aria-label="一级属性">${heading('一级属性')}${radar(card)}</section></section>
96
+ </div>${enemy ? bloodlines(card, icons) : ''}${skills(card, icons)}${equipment(card)}</main></body></html>`
88
97
  }
@@ -135,7 +135,8 @@ async function renderUncached(ctx: Context, card?: SkillCardData, leaderboard?:
135
135
  const release = () => { const next = waiting.shift(); if (next) next(); else running-- }
136
136
  try {
137
137
  const work = async () => {
138
- const remoteAddress = signinCard ? undefined : titleCard ? titleCard.artworkUrl : bloodlineCard ? bloodlineCard.artworkUrl : equipmentCard ? equipmentCard.artworkUrl : companionCard ? companionCard.artworkUrl : characterCard ? characterCard.artworkUrl : itemCard ? itemCard.artworkUrl : leaderboard ? leaderboard.backgroundUrl : card?.artworkUrl
138
+ const encounterCard = companionCard?.kind === 'monster' || companionCard?.kind === 'boss'
139
+ const remoteAddress = signinCard ? undefined : titleCard ? titleCard.artworkUrl : bloodlineCard ? bloodlineCard.artworkUrl : equipmentCard ? equipmentCard.artworkUrl : companionCard ? encounterCard ? undefined : companionCard.artworkUrl : characterCard ? characterCard.artworkUrl : itemCard ? itemCard.artworkUrl : leaderboard ? leaderboard.backgroundUrl : card?.artworkUrl
139
140
  const isEquipment = !signinCard && !titleCard && !bloodlineCard && Boolean(equipmentCard)
140
141
  const isCharacter = !signinCard && !titleCard && !bloodlineCard && !equipmentCard && !companionCard && Boolean(characterCard)
141
142
  // Download independent artwork and open the browser together. A cold portrait
@@ -6,7 +6,7 @@ export interface ReqStatistics extends BaseRequest {}
6
6
  export interface ResStatistics extends BaseResponse {
7
7
  /** 统计快照生成时间,Unix 毫秒。 */
8
8
  generatedAt: number;
9
- /** 普通玩家最近游戏消息的在线窗口;处理指令、自动探索可延续在线。 */
9
+ /** 普通玩家最近游戏消息的在线窗口;处理指令可延续在线。 */
10
10
  onlineWindowMs: number;
11
11
  /** 服务端快照缓存时长。 */
12
12
  cacheTtlMs: number;
@@ -25,7 +25,7 @@ export interface ServiceType {
25
25
  }
26
26
 
27
27
  export const serviceProto: ServiceProto<ServiceType> = {
28
- "version": 41,
28
+ "version": 42,
29
29
  "services": [
30
30
  {
31
31
  "id": 0,
@@ -1786,6 +1786,55 @@ export const serviceProto: ServiceProto<ServiceType> = {
1786
1786
  ]
1787
1787
  }
1788
1788
  }
1789
+ },
1790
+ {
1791
+ "id": 14,
1792
+ "name": "equipment",
1793
+ "type": {
1794
+ "type": "Array",
1795
+ "elementType": {
1796
+ "type": "Interface",
1797
+ "properties": [
1798
+ {
1799
+ "id": 0,
1800
+ "name": "id",
1801
+ "type": {
1802
+ "type": "String"
1803
+ }
1804
+ },
1805
+ {
1806
+ "id": 1,
1807
+ "name": "name",
1808
+ "type": {
1809
+ "type": "String"
1810
+ }
1811
+ },
1812
+ {
1813
+ "id": 2,
1814
+ "name": "quality",
1815
+ "type": {
1816
+ "type": "String"
1817
+ }
1818
+ },
1819
+ {
1820
+ "id": 3,
1821
+ "name": "slot",
1822
+ "type": {
1823
+ "type": "String"
1824
+ }
1825
+ },
1826
+ {
1827
+ "id": 4,
1828
+ "name": "enhancement",
1829
+ "type": {
1830
+ "type": "Number"
1831
+ },
1832
+ "optional": true
1833
+ }
1834
+ ]
1835
+ }
1836
+ },
1837
+ "optional": true
1789
1838
  }
1790
1839
  ]
1791
1840
  },
@@ -1799,6 +1848,14 @@ export const serviceProto: ServiceProto<ServiceType> = {
1799
1848
  {
1800
1849
  "id": 1,
1801
1850
  "value": "follower"
1851
+ },
1852
+ {
1853
+ "id": 2,
1854
+ "value": "monster"
1855
+ },
1856
+ {
1857
+ "id": 3,
1858
+ "value": "boss"
1802
1859
  }
1803
1860
  ]
1804
1861
  },
@@ -52,6 +52,8 @@ export interface CharacterCardData {
52
52
  export enum CompanionCardKind {
53
53
  pet = 'pet',
54
54
  follower = 'follower',
55
+ monster = 'monster',
56
+ boss = 'boss',
55
57
  }
56
58
  export enum CompanionCardState {
57
59
  active = 'active',
@@ -62,7 +64,7 @@ export enum CompanionSkillType {
62
64
  active = 'active',
63
65
  passive = 'passive',
64
66
  }
65
- /** 宠物与随从的属性图片;完整技能与血统由服务端按当前构筑提供。 */
67
+ /** 伙伴与探索敌人的属性图片;探索详情读取本次已冻结的实际参战快照。 */
66
68
  export interface CompanionCardData {
67
69
  kind: CompanionCardKind;
68
70
  /** 已保存形象的临时 HTTPS 链接;缺图时由客户端显示伙伴占位。 */
@@ -81,6 +83,8 @@ export interface CompanionCardData {
81
83
  attributes: Array<{ id: string; name: string; value: number }>;
82
84
  bloodlines: Array<{ name: string; quality: string; emoji?: string; artworkUrl?: string }>;
83
85
  skills: Array<{ id: string; name: string; rank: number; quality?: string; type?: CompanionSkillType; artworkUrl?: string }>;
86
+ /** 本场怪物实际生效的装备;伙伴详情可省略。字段追加,保留既有协议编号。 */
87
+ equipment?: Array<{ id: string; name: string; quality: string; slot: string; enhancement?: number }>;
84
88
  }
85
89
  export interface ItemCardData {
86
90
  artworkUrl?: string;