@sjtdev/koishi-plugin-dota2tracker 1.2.8-pre.2 → 1.2.9-pre

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/changelog.md CHANGED
@@ -1,17 +1,42 @@
1
+ ### 1.2.9-pre
2
+ **修复**:
3
+ - `查询英雄`:尝试修复DOTA2 7.37版本更新后API变动导致部分英雄查询报错。
4
+
5
+ **改进**:
6
+ - `查询英雄`:命石技能的技能名栏位添加对应命石图标与背景色用于标识。
7
+
8
+ # 1.2.8
9
+ **新增**:
10
+ - 新增周报功能,效果等同日报。
11
+ - 日报与周报中新增可关闭总结中显示组合的功能。
12
+
13
+ **改进**:
14
+ - 现在`查询玩家`与`查询最近比赛`指令可在私聊状态下使用,必须提供SteamID参数。
15
+ - 将战报中的播报评语由随机选取改为固定种子:比赛ID+玩家SteamID+玩家位置,确保在不同调用时刻、次数及平台下,对同一场比赛中的玩家评语保持一致。
16
+ - `查询玩家`指令图片中,玩家近期比赛表中未解析的场次参战率由"?%"改为估算值,显示为"≈xx%"。
17
+ - `查询英雄`指令图片中,由于命石带来的属性数值无法确定作用方式(增加或是替换等),去除命石属性前的“+”,请结合命石说明自行判断。(7.37版本更新带来的API变动,导致使用指令查询某些英雄报错问题,暂无法解决)
18
+ - 比赛图片模板`match_2`中,现在冠绝排名数字位置更准确了。
19
+ - 比赛图片模板`match_2`中,比赛段位可以显示星级了。
20
+
21
+ <details>
22
+ <summary>为什么未解析的比赛需要“估算”?</summary>
23
+ 比赛未解析无法获取“团队击杀数”,若是将己方所有玩家的击杀数相加,则会漏掉那些由小兵、防御塔等非玩家单位击杀数;若是将敌方所有玩家的死亡数相加,又会多出送野、自杀等不应算在己方战果中的计数。<br>目前程序采用将己方所有击杀数累加的方式来估算参战率,可能会略高于实际值。
24
+ </details>
25
+
26
+ <details>
27
+ <summary><b>1.2.8-pre更新日志</b></summary>
28
+
1
29
  ### 1.2.8-pre
2
30
  **改进**:
3
31
  - 现在`查询玩家`可在私聊状态使用,必须提供SteamID参数。
4
32
  - 将战报中的播报评语由随机选取改为固定种子:比赛ID+玩家SteamID,确保在不同调用时刻、次数及平台下,对同一场比赛中的玩家评语保持一致。
5
33
  - `查询玩家`指令图片中,玩家近期比赛表中未解析的场次参战率由"?%"改为估算值,显示为"≈xx%"
6
- <details>
7
- <summary>为什么未解析的比赛需要“估算”?</summary>
8
- 比赛未解析无法获取“团队击杀数”,若是将己方所有玩家的击杀数相加,则会漏掉那些由小兵、防御塔等非玩家单位击杀数;若是将敌方所有玩家的死亡数相加,又会多出送野、自杀等不应算在己方战果中的计数。<br>目前程序采用将己方所有击杀数累加的方式来估算参战率,可能会略高于实际值
9
- </details>
10
34
 
11
35
  ##### pre.2
12
36
  **改进**:
13
37
  - 比赛图片模板`match_2`中,现在冠绝排名数字位置更准确了。
14
38
  - 比赛图片模板`match_2`中,比赛段位可以显示星级了。
39
+ </details>
15
40
 
16
41
  # 1.2.7
17
42
  ##### 于1.2.7-beta中尝试修复的功能均已正常工作,正式发布1.2.7
package/lib/index.js CHANGED
@@ -117,6 +117,7 @@ function MATCH_INFO(matchId) {
117
117
  leaverStatus
118
118
  partyId
119
119
  position
120
+ playerSlot
120
121
  lane
121
122
  imp
122
123
  kills
@@ -1213,7 +1214,19 @@ var Config = import_koishi.Schema.intersect([
1213
1214
  import_koishi.Schema.union([
1214
1215
  import_koishi.Schema.object({
1215
1216
  dailyReportSwitch: import_koishi.Schema.const(true).required(),
1216
- dailyReportHours: import_koishi.Schema.number().min(0).max(23).default(6).description("日报时间小时")
1217
+ dailyReportHours: import_koishi.Schema.number().min(0).max(23).default(6).description("日报时间小时"),
1218
+ dailyReportShowCombi: import_koishi.Schema.boolean().default(true).description("日报是否显示组合")
1219
+ }),
1220
+ import_koishi.Schema.object({})
1221
+ ]),
1222
+ import_koishi.Schema.object({
1223
+ weeklyReportSwitch: import_koishi.Schema.boolean().default(false).description("周报功能").experimental()
1224
+ }),
1225
+ import_koishi.Schema.union([
1226
+ import_koishi.Schema.object({
1227
+ weeklyReportSwitch: import_koishi.Schema.const(true).required(),
1228
+ weeklyReportDayHours: import_koishi.Schema.tuple([import_koishi.Schema.number().min(1).max(7), import_koishi.Schema.number().min(0).max(23)]).default([1, 10]).description("周报发布于周(几)的(几)点"),
1229
+ weeklyReportShowCombi: import_koishi.Schema.boolean().default(true).description("周报是否显示组合")
1217
1230
  }),
1218
1231
  import_koishi.Schema.object({})
1219
1232
  ]),
@@ -1397,7 +1410,7 @@ async function apply(ctx, config) {
1397
1410
  queryMatchAndSend(session, match_id);
1398
1411
  });
1399
1412
  ctx.command("查询最近比赛 [input_data]", "查询玩家的最近比赛").usage("查询指定玩家的最近一场比赛的比赛数据,生成图片发布。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID").example("查询最近比赛 123456789").example("查询最近比赛 张三").action(async ({ session }, input_data) => {
1400
- if (session.guild) {
1413
+ if (session.guild || !session.guild && input_data) {
1401
1414
  let sessionPlayer;
1402
1415
  if (!input_data) {
1403
1416
  sessionPlayer = (await ctx.database.get("dt_subscribed_players", { guildId: session.event.channel.id, platform: session.event.platform, userId: session.event.user.id }))[0];
@@ -1420,6 +1433,8 @@ async function apply(ctx, config) {
1420
1433
  return;
1421
1434
  }
1422
1435
  queryMatchAndSend(session, lastMatchId);
1436
+ } else {
1437
+ session.send("<p>指令调用失败。</p><p>当前不属于群聊状态,必须提供指定玩家的SteamID。</p>");
1423
1438
  }
1424
1439
  });
1425
1440
  ctx.command("查询玩家 <input_data>", "查询玩家信息,可指定英雄").usage("查询指定玩家的个人信息与最近战绩,生成图片发布。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID").option("hero", "-o <value:string> 查询玩家指定英雄使用情况(同其他英雄查询,可用简称与ID)").example("查询玩家 123456789").example("查询玩家 张三").example("查询玩家 张三 hero 敌法师").action(async ({ session, options }, input_data) => {
@@ -1516,6 +1531,7 @@ async function apply(ctx, config) {
1516
1531
  else
1517
1532
  hero.facets[i].description_loc = formatHeroDesc(hero.facets[i].description_loc, ab.special_values, "facet" /* Facet */);
1518
1533
  ab.ability_is_facet = true;
1534
+ ab.facet = hero.facets[i];
1519
1535
  hero.abilities.push(ab);
1520
1536
  });
1521
1537
  }
@@ -1523,6 +1539,9 @@ async function apply(ctx, config) {
1523
1539
  const all_special_values = [...hero.abilities.flatMap((ab) => ab.special_values), ...hero.facet_abilities.flatMap((fas) => fas.abilities.flatMap((fa) => fa.special_values))];
1524
1540
  hero.abilities.forEach((ab) => {
1525
1541
  ab.facets_loc.forEach((facet, i) => {
1542
+ i = i + (hero.facets.length - ab.facets_loc.length);
1543
+ if (i < 0)
1544
+ return;
1526
1545
  if (facet) {
1527
1546
  if (!hero.facets[i].abilities)
1528
1547
  hero.facets[i].abilities = [];
@@ -1663,81 +1682,13 @@ async function apply(ctx, config) {
1663
1682
  if (config.dailyReportSwitch) {
1664
1683
  ctx.cron(`0 ${config.dailyReportHours} * * *`, async function() {
1665
1684
  const oneDayAgo = (0, import_moment.default)().subtract(1, "days").unix();
1666
- const subscribedGuilds = await ctx.database.get("dt_subscribed_guilds", void 0);
1667
- const subscribedPlayersInGuild = (await ctx.database.get("dt_subscribed_players", void 0)).filter((player) => subscribedGuilds.some((guild) => guild.guildId == player.guildId));
1668
- const players = (await query(
1669
- MATCHES_FOR_DAILY(
1670
- subscribedPlayersInGuild.map((player) => player.steamId).filter((value, index, self) => self.indexOf(value) === index),
1671
- oneDayAgo
1672
- )
1673
- )).data.players.filter((player) => player.matches.length > 0);
1674
- const matches = players.map((player) => player.matches.map((match) => match)).flat().filter((item, index, self) => index === self.findIndex((t) => t.id === item.id));
1675
- for (let subPlayer of subscribedPlayersInGuild) {
1676
- let player = players.find((player2) => subPlayer.steamId == player2.steamAccount.id);
1677
- if (!player)
1678
- continue;
1679
- let guildMember;
1680
- try {
1681
- guildMember = await ctx.bots.find((bot) => bot.platform == subPlayer.platform)?.getGuildMember(subPlayer.guildId, subPlayer.userId);
1682
- } catch (error) {
1683
- ctx.logger.error("获取群组信息失败。" + error);
1684
- }
1685
- subPlayer.name = subPlayer.nickName || (guildMember?.nick ?? players.find((player2) => player2.steamAccount.id == subPlayer.steamId)?.steamAccount.name);
1686
- player.winCount = player.matches.filter((match) => match.didRadiantWin == match.players.find((innerPlayer) => innerPlayer.steamAccount.id == player.steamAccount.id).isRadiant).length;
1687
- player.loseCount = player.matches.length - player.winCount;
1688
- player.avgKills = roundToDecimalPlaces(player.matches.reduce((acc, match) => acc + match.players.find((innerPlayer) => innerPlayer.steamAccount.id == player.steamAccount.id).kills, 0) / player.matches.length, 2);
1689
- player.avgDeaths = roundToDecimalPlaces(player.matches.reduce((acc, match) => acc + match.players.find((innerPlayer) => innerPlayer.steamAccount.id == player.steamAccount.id).deaths, 0) / player.matches.length, 2);
1690
- player.avgAssists = roundToDecimalPlaces(
1691
- player.matches.reduce((acc, match) => acc + match.players.find((innerPlayer) => innerPlayer.steamAccount.id == player.steamAccount.id).assists, 0) / player.matches.length,
1692
- 2
1693
- );
1694
- player.avgKDA = roundToDecimalPlaces((player.avgKills + player.avgAssists) / (player.avgDeaths || 1), 2);
1695
- player.avgImp = roundToDecimalPlaces(player.matches.reduce((acc, match) => acc + match.players.find((innerPlayer) => innerPlayer.steamAccount.id == player.steamAccount.id).imp, 0) / player.matches.length, 0);
1696
- subPlayer = Object.assign(subPlayer, player);
1697
- }
1698
- for (let guild of subscribedGuilds) {
1699
- const currentsubscribedPlayers = subscribedPlayersInGuild.filter((player) => player.platform == guild.platform && player.guildId == guild.guildId && player.matches?.length);
1700
- if (currentsubscribedPlayers.length) {
1701
- const currentsubscribedPlayersIds = currentsubscribedPlayers.map((player) => player.steamId);
1702
- const combinationsMap = /* @__PURE__ */ new Map();
1703
- matches.forEach((match) => {
1704
- const sortedPlayerIds = match.players.map((player) => player.steamAccount.id).filter((id) => currentsubscribedPlayersIds.includes(id)).sort((a, b) => a - b);
1705
- const key = sortedPlayerIds.join(",");
1706
- if (!combinationsMap.has(key)) {
1707
- const players2 = currentsubscribedPlayers.filter((subPlayer) => sortedPlayerIds.includes(subPlayer.steamId));
1708
- if (players2.length > 0) {
1709
- const name2 = players2.map((subPlayer) => subPlayer.name).join("/");
1710
- combinationsMap.set(key, {
1711
- players: players2,
1712
- name: name2,
1713
- winCount: match.didRadiantWin == match.players.find((innerPlayer) => innerPlayer.steamAccount.id == players2[0].steamId).isRadiant ? 1 : 0,
1714
- matches: [match]
1715
- });
1716
- }
1717
- } else {
1718
- const combi = combinationsMap.get(key);
1719
- combi.matches.push(match);
1720
- combi.winCount += match.didRadiantWin == match.players.find((innerPlayer) => innerPlayer.steamAccount.id == combi.players[0].steamId).isRadiant ? 1 : 0;
1721
- }
1722
- });
1723
- const combinations = Array.from(combinationsMap.values());
1724
- try {
1725
- await ctx.broadcast(
1726
- [`${guild.platform}:${guild.guildId}`],
1727
- `昨日总结:
1728
- ${currentsubscribedPlayers.map(
1729
- (player) => `${player.name}: ${player.winCount}胜${player.loseCount}负 胜率${Math.round(player.winCount / player.matches.length * 100)}%,平均KDA: [${player.avgKills}/${player.avgDeaths}/${player.avgAssists}](${player.avgKDA}),平均表现: ${player.avgImp > 0 ? "+" : ""}${player.avgImp}`
1730
- ).join("\n")}
1731
- ${combinations.map((combi) => `组合[${combi.name}]: ${combi.winCount}胜${combi.matches.length - combi.winCount}负 胜率${Math.round(combi.winCount / combi.matches.length * 100)}%`).join("\n")}`.replace(
1732
- /\s*\n\s*/g,
1733
- "\n"
1734
- )
1735
- );
1736
- } catch (error) {
1737
- ctx.logger.error(error);
1738
- }
1739
- }
1740
- }
1685
+ await report(oneDayAgo, "昨日总结", config.dailyReportShowCombi);
1686
+ });
1687
+ }
1688
+ if (config.weeklyReportSwitch) {
1689
+ ctx.cron(`0 ${config.weeklyReportDayHours[1]} * * ${config.weeklyReportDayHours[0]}`, async function() {
1690
+ const oneWeekAgo = (0, import_moment.default)().subtract(1, "weeks").unix();
1691
+ await report(oneWeekAgo, "上周总结", config.weeklyReportShowCombi);
1741
1692
  });
1742
1693
  }
1743
1694
  ctx.cron("* * * * *", async function() {
@@ -1786,7 +1737,7 @@ async function apply(ctx, config) {
1786
1737
  let idsToFind = commingGuild.players.map((player) => player.steamId);
1787
1738
  let broadPlayers = match.players.filter((item) => idsToFind.includes(item.steamAccountId));
1788
1739
  for (let player of broadPlayers) {
1789
- const random2 = new import_koishi2.Random(() => simpleHashToSeed(match.id, player.steamAccountId));
1740
+ const random2 = new import_koishi2.Random(() => simpleHashToSeed(`${match.id}-${player.steamAccountId}-${player.playerSlot}`));
1790
1741
  let broadPlayerMessage = `${player.steamAccount.name}的${random2.pick(HEROES_CHINESE[player.hero.id])}`;
1791
1742
  if (player.isRadiant == match.didRadiantWin) {
1792
1743
  if (player.deathContribution < 0.2 || player.killContribution > 0.75 || player.heroDamage / player.networth > 1.5 || player.towerDamage > 1e4 || player.imp > 0)
@@ -1794,7 +1745,7 @@ async function apply(ctx, config) {
1794
1745
  else
1795
1746
  broadPlayerMessage += random2.pick(WIN_NEGATIVE);
1796
1747
  } else {
1797
- if (player.deathContribution < 0.25 || player.killContribution > 0.75 || player.heroDamage / player.networth > 1.25 || player.towerDamage > 5e3 || player.imp > 0)
1748
+ if (player.deathContribution < 0.25 || player.killContribution > 0.75 || player.heroDamage / player.networth > 1 || player.towerDamage > 5e3 || player.imp > 0)
1798
1749
  broadPlayerMessage += random2.pick(LOSE_POSITIVE);
1799
1750
  else
1800
1751
  broadPlayerMessage += random2.pick(LOSE_NEGATIVE);
@@ -1804,7 +1755,7 @@ KDA:${((player.kills + player.assists) / (player.deaths || 1)).toFixed(2)} [${
1804
1755
  broadMatchMessage += broadPlayerMessage + "\n";
1805
1756
  }
1806
1757
  await ctx.broadcast([`${commingGuild.platform}:${commingGuild.guildId}`], broadMatchMessage + (ctx.config.urlInMessageType.some((type) => type == "match") ? "https://stratz.com/matches/" + match.id : "") + img);
1807
- ctx.logger.info(`${match.id}${match.parsedDateTime ? "已解析," : "已结束超过1小时仍未被解析,放弃解析直接"}生成图片并发布于${commingGuild.platform}:${commingGuild.guildId}。`);
1758
+ ctx.logger.info(`${match.id}${match.parsedDateTime ? "已解析," : "已结束超过1小时仍未被解析,放弃等待解析直接"}生成图片并发布于${commingGuild.platform}:${commingGuild.guildId}。`);
1808
1759
  }
1809
1760
  if (match.parsedDateTime)
1810
1761
  ctx.database.upsert("dt_previous_query_results", (row) => [{ matchId: match.id, data: match, queryTime: /* @__PURE__ */ new Date() }]);
@@ -1818,6 +1769,79 @@ KDA:${((player.kills + player.assists) / (player.deaths || 1)).toFixed(2)} [${
1818
1769
  }
1819
1770
  });
1820
1771
  });
1772
+ async function report(timeAgo, title, showCombi) {
1773
+ const subscribedGuilds = await ctx.database.get("dt_subscribed_guilds", void 0);
1774
+ const subscribedPlayersInGuild = (await ctx.database.get("dt_subscribed_players", void 0)).filter((player) => subscribedGuilds.some((guild) => guild.guildId == player.guildId));
1775
+ const players = (await query(
1776
+ MATCHES_FOR_DAILY(
1777
+ subscribedPlayersInGuild.map((player) => player.steamId).filter((value, index, self) => self.indexOf(value) === index),
1778
+ timeAgo
1779
+ )
1780
+ )).data.players.filter((player) => player.matches.length > 0);
1781
+ const matches = players.map((player) => player.matches.map((match) => match)).flat().filter((item, index, self) => index === self.findIndex((t) => t.id === item.id));
1782
+ for (let subPlayer of subscribedPlayersInGuild) {
1783
+ let player = players.find((player2) => subPlayer.steamId == player2.steamAccount.id);
1784
+ if (!player)
1785
+ continue;
1786
+ let guildMember;
1787
+ try {
1788
+ guildMember = await ctx.bots.find((bot) => bot.platform == subPlayer.platform)?.getGuildMember(subPlayer.guildId, subPlayer.userId);
1789
+ } catch (error) {
1790
+ ctx.logger.error("获取群组信息失败。" + error);
1791
+ }
1792
+ subPlayer.name = subPlayer.nickName || (guildMember?.nick ?? players.find((player2) => player2.steamAccount.id == subPlayer.steamId)?.steamAccount.name);
1793
+ player.winCount = player.matches.filter((match) => match.didRadiantWin == match.players.find((innerPlayer) => innerPlayer.steamAccount.id == player.steamAccount.id).isRadiant).length;
1794
+ player.loseCount = player.matches.length - player.winCount;
1795
+ player.avgKills = roundToDecimalPlaces(player.matches.reduce((acc, match) => acc + match.players.find((innerPlayer) => innerPlayer.steamAccount.id == player.steamAccount.id).kills, 0) / player.matches.length, 2);
1796
+ player.avgDeaths = roundToDecimalPlaces(player.matches.reduce((acc, match) => acc + match.players.find((innerPlayer) => innerPlayer.steamAccount.id == player.steamAccount.id).deaths, 0) / player.matches.length, 2);
1797
+ player.avgAssists = roundToDecimalPlaces(player.matches.reduce((acc, match) => acc + match.players.find((innerPlayer) => innerPlayer.steamAccount.id == player.steamAccount.id).assists, 0) / player.matches.length, 2);
1798
+ player.avgKDA = roundToDecimalPlaces((player.avgKills + player.avgAssists) / (player.avgDeaths || 1), 2);
1799
+ player.avgImp = roundToDecimalPlaces(player.matches.reduce((acc, match) => acc + match.players.find((innerPlayer) => innerPlayer.steamAccount.id == player.steamAccount.id).imp, 0) / player.matches.length, 0);
1800
+ subPlayer = Object.assign(subPlayer, player);
1801
+ }
1802
+ for (let guild of subscribedGuilds) {
1803
+ const currentsubscribedPlayers = subscribedPlayersInGuild.filter((player) => player.platform == guild.platform && player.guildId == guild.guildId && player.matches?.length);
1804
+ if (currentsubscribedPlayers.length) {
1805
+ const currentsubscribedPlayersIds = currentsubscribedPlayers.map((player) => player.steamId);
1806
+ const combinationsMap = /* @__PURE__ */ new Map();
1807
+ matches.forEach((match) => {
1808
+ const sortedPlayerIds = match.players.map((player) => player.steamAccount.id).filter((id) => currentsubscribedPlayersIds.includes(id)).sort((a, b) => a - b);
1809
+ const key = sortedPlayerIds.join(",");
1810
+ if (!combinationsMap.has(key)) {
1811
+ const players2 = currentsubscribedPlayers.filter((subPlayer) => sortedPlayerIds.includes(subPlayer.steamId));
1812
+ if (players2.length > 0) {
1813
+ const name2 = players2.map((subPlayer) => subPlayer.name).join("/");
1814
+ combinationsMap.set(key, {
1815
+ players: players2,
1816
+ name: name2,
1817
+ winCount: match.didRadiantWin == match.players.find((innerPlayer) => innerPlayer.steamAccount.id == players2[0].steamId).isRadiant ? 1 : 0,
1818
+ matches: [match]
1819
+ });
1820
+ }
1821
+ } else {
1822
+ const combi = combinationsMap.get(key);
1823
+ combi.matches.push(match);
1824
+ combi.winCount += match.didRadiantWin == match.players.find((innerPlayer) => innerPlayer.steamAccount.id == combi.players[0].steamId).isRadiant ? 1 : 0;
1825
+ }
1826
+ });
1827
+ const combinations = Array.from(combinationsMap.values());
1828
+ try {
1829
+ await ctx.broadcast(
1830
+ [`${guild.platform}:${guild.guildId}`],
1831
+ `${title}:
1832
+ ${currentsubscribedPlayers.map(
1833
+ (player) => `${player.name}: ${player.winCount}胜${player.loseCount}负 胜率${Math.round(player.winCount / player.matches.length * 100)}%,平均KDA: [${player.avgKills}/${player.avgDeaths}/${player.avgAssists}](${player.avgKDA}),平均表现: ${player.avgImp > 0 ? "+" : ""}${player.avgImp}`
1834
+ ).join("\n")}
1835
+ ${showCombi ? combinations.map((combi) => `组合[${combi.name}]: ${combi.winCount}胜${combi.matches.length - combi.winCount}负 胜率${Math.round(combi.winCount / combi.matches.length * 100)}%`).join("\n") : ""}`.replace(/\s*\n\s*/g, "\n")
1836
+ );
1837
+ ctx.logger.info(`发布日报于${guild.platform}:${guild.guildId}`);
1838
+ } catch (error) {
1839
+ ctx.logger.error(error);
1840
+ }
1841
+ }
1842
+ }
1843
+ }
1844
+ __name(report, "report");
1821
1845
  ctx.on("dispose", async () => {
1822
1846
  });
1823
1847
  }
@@ -1844,9 +1868,8 @@ function genImageHTML(data, template, type) {
1844
1868
  return result;
1845
1869
  }
1846
1870
  __name(genImageHTML, "genImageHTML");
1847
- function simpleHashToSeed(matchId, playerId) {
1848
- const input = `${matchId}-${playerId}`;
1849
- const encoded = btoa(input);
1871
+ function simpleHashToSeed(inputString) {
1872
+ const encoded = btoa(inputString);
1850
1873
  let total = 0;
1851
1874
  for (let i = 0; i < encoded.length; i++) {
1852
1875
  total += encoded.charCodeAt(i);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sjtdev/koishi-plugin-dota2tracker",
3
3
  "description": "koishi插件-追踪群友的DOTA2对局",
4
- "version": "1.2.8-pre.2",
4
+ "version": "1.2.9-pre",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -26,7 +26,7 @@
26
26
  "dota2"
27
27
  ],
28
28
  "dependencies": {
29
- "dotaconstants": "^8.8.0",
29
+ "dotaconstants": "^8.10.0",
30
30
  "ejs": "^3.1.10",
31
31
  "moment": "^2.30.1"
32
32
  },
package/readme.md CHANGED
@@ -12,6 +12,8 @@ DOTA2Bot插件-提供自动追踪群友的最新对局的功能(需群友绑
12
12
  在希望推送战报信息的群组(或频道)使用指令`订阅本群`,玩家可使用指令`绑定`来将自身账号与Steam账号绑定,bot会尝试追踪已订阅群组(或频道)中的绑定玩家的最新对局信息。
13
13
  其他查询功能见下方指令说明。
14
14
  **直接调用help指令可获取更详细的说明,调用【指令 -h】还会有用法示例。(例如:订阅本群 -h)**
15
+ **本插件使用的所有SteamID均为SteamID3类型(即DOTA2游戏内个人页面显示的好友ID与stratz登录后个人页面链接中显示的ID),有关SteamID类型见 https://steamid.tatlead.com/ (由[issue](../../issues/1)提供,感谢这位用户)**
16
+
15
17
  **更新日志见[changelog](changelog.md)**
16
18
 
17
19
  ### 指令
@@ -204,7 +204,8 @@
204
204
  gap: 10px; /* 可选:设置项目之间的间距 */
205
205
  }
206
206
 
207
- .facet {
207
+ .facets > .facet ,
208
+ .skill > .facet {
208
209
  flex: 1 1 calc(50% - 10px); /* 每行两个项目 */
209
210
  box-sizing: border-box; /* 包含padding和border在宽度和高度的计算中 */
210
211
  background-color: #181f24;
@@ -212,10 +213,11 @@
212
213
  border: 1px solid #2b2f33;
213
214
  }
214
215
 
215
- .facet:nth-child(odd):last-child {
216
+ .facets > .facet:nth-child(odd):last-child {
216
217
  flex-basis: 100%; /* 最后一个奇数项目占据整行 */
217
218
  }
218
- .facet > .name_back {
219
+ .facets > .facet > .name_back ,
220
+ .skill > .facet > .name_back {
219
221
  position: absolute;
220
222
  height: 50px;
221
223
  width: 100%;
@@ -343,6 +345,8 @@
343
345
  background-color: #1f272b;
344
346
  padding: 8px;
345
347
  font-weight: 100;
348
+ height: auto;
349
+ width: auto;
346
350
  }
347
351
  .skill > .title > .name {
348
352
  font-family: "KaiTi", "楷体", "楷体_GB2312", "STKaiti", serif;
@@ -357,6 +361,10 @@
357
361
  background-color: #5b93d1;
358
362
  }
359
363
 
364
+ .skill > .title.name_back > img{
365
+ width: 16px;
366
+ }
367
+
360
368
  .skill img.scepter,
361
369
  .skill img.shard {
362
370
  position: absolute;
@@ -683,10 +691,11 @@
683
691
  `).join("")}
684
692
  </div>
685
693
  <div class="skills">
686
- ${hero.abilities//.filter((item) => dotaconstants.abilities[item.name].behavior != "Hidden")
694
+ ${hero.abilities//.filter((item) => dotaconstants.abilities[item.name]?.behavior != "Hidden")
687
695
  .map((item) => `
688
- <div class="skill" data-innate="${item.ability_is_innate&&!item.ability_is_facet}">
689
- <p class="title">
696
+ <div class="skill${item.facet?' facet':''}" data-innate="${item.ability_is_innate&&!item.ability_is_facet}">
697
+ <p class="title${item.facet?(' name_back type_' + item.facet?.color):''}">
698
+ ${item.facet?`<img src="${utils.getImageUrl(item.facet?.icon, ImageType.IconsFacets)}">`:""}
690
699
  <span class="name">${item.name_loc}</span>
691
700
  ${item.ability_is_innate&&!item.ability_is_facet?`<span class="is_innate">先天技能</span>`:""}
692
701
  ${item.ability_is_granted_by_scepter ?`<img src="${utils.getImageUrl("scepter")}" class="scepter">`:""}
@@ -695,30 +704,29 @@
695
704
  <div class="img_stats">
696
705
  <img src="${utils.getImageUrl(item.name, ImageType.Abilities)}" onerror="this.onerror=null; this.src='${utils.getImageUrl(`innate_icon`,ImageType.Icons)}';"/>
697
706
  <div class="stats">
698
- <p class="behavior">技能:${(Array.isArray(dotaconstants.abilities[item.name].behavior) ? dotaconstants.abilities[item.name].behavior : [dotaconstants.abilities[item.name].behavior])
707
+ <p class="behavior">技能:${[].concat(dotaconstants.abilities[item.name]?.behavior)
699
708
  .filter((beh) => beh !== "Hidden" || !(item.ability_is_granted_by_shard || item.ability_is_granted_by_scepter))
700
- .map((beh) => d2a.behavior[beh])
701
- .join("/")}</p>
702
- ${dotaconstants.abilities[item.name].target_team
703
- ? `<p class="target_team">影响:${(Array.isArray(dotaconstants.abilities[item.name].target_team)
704
- ? dotaconstants.abilities[item.name].target_team
705
- : [dotaconstants.abilities[item.name].target_team])
706
- .map((tt) => d2a.target_team[tt])
707
- .join("/")}</p>`
708
- : ""}
709
- ${!Array.isArray(dotaconstants.abilities[item.name].dmg_type) && dotaconstants.abilities[item.name].dmg_type
710
- ? `<p class="dmg_type ${dotaconstants.abilities[item.name].dmg_type}">伤害类型:</p>`
711
- : ""}
712
- ${dotaconstants.abilities[item.name].dispellable
713
- ? `<p class="dispellable ${dotaconstants.abilities[item.name].dispellable == "Strong Dispels Only" ? "Strong" : dotaconstants.abilities[item.name].dispellable}">能否驱散:</p>`
714
- : ""}
715
- ${!Array.isArray(dotaconstants.abilities[item.name].bkbpierce) && dotaconstants.abilities[item.name].bkbpierce
716
- ? `<p class="bkbpierce">无视减益免疫: ${dotaconstants.abilities[item.name].bkbpierce == "Yes" ? "是" : "否"}</p>`
717
- : ""}
709
+ .map((beh) => d2a.behavior[beh]).join("/")}
710
+ </p>
711
+ ${dotaconstants.abilities[item.name]?.target_team ?
712
+ `<p class="target_team">影响:${[].concat(dotaconstants.abilities[item.name]?.target_team)
713
+ .map((tt) => d2a.target_team[tt]).join("/")}
714
+ </p>` : ""}
715
+ ${!Array.isArray(dotaconstants.abilities[item.name]?.dmg_type) && dotaconstants.abilities[item.name]?.dmg_type ?
716
+ `<p class="dmg_type ${dotaconstants.abilities[item.name]?.dmg_type}">伤害类型:</p>` : ""}
717
+ ${dotaconstants.abilities[item.name]?.dispellable ?
718
+ `<p class="dispellable ${dotaconstants.abilities[item.name]?.dispellable == "Strong Dispels Only" ? "Strong" : dotaconstants.abilities[item.name]?.dispellable}">能否驱散:</p>` : ""}
719
+ ${!Array.isArray(dotaconstants.abilities[item.name]?.bkbpierce) && dotaconstants.abilities[item.name]?.bkbpierce ?
720
+ `<p class="bkbpierce">无视减益免疫: ${dotaconstants.abilities[item.name]?.bkbpierce == "Yes" ? "是" : ""}</p>` : ""}
718
721
  </div>
719
722
  </div>
720
723
  <p class="description">${item.desc_loc}</p>
721
- ${item.facets_loc.map((facet_loc,index)=>(facet_loc!=""?`
724
+ ${item.facets_loc
725
+ .reduce((acc, facet_loc, index) => {
726
+ index = index + (hero.facets.length - item.facets_loc.length);
727
+ if (index >= 0) acc.push(facet_loc);
728
+ return acc;},[])
729
+ .map((facet_loc,index)=>(facet_loc!=""?`
722
730
  <div class="facet">
723
731
  <div class="name_back type_${hero.facets[index].color}"></div>
724
732
  <div class="name_line type_${hero.facets[index].color}"></div>
@@ -733,12 +741,12 @@
733
741
  </div>
734
742
  </div>
735
743
  `:"")).join("")}
736
- ${item.ability_has_scepter&&!item.ability_is_granted_by_scepter
744
+ ${item.ability_has_scepter&&!item.ability_is_granted_by_scepter&&item.scepter_loc
737
745
  ? `<p class="aghanim_description">
738
746
  <span class="title"><img src="${utils.getImageUrl("scepter")}"class="scepter">阿哈利姆神杖</span>
739
747
  <span class="desc">${item.scepter_loc}</span>
740
748
  </p>` : ""}
741
- ${item.ability_has_shard&&!item.ability_is_granted_by_shard
749
+ ${item.ability_has_shard&&!item.ability_is_granted_by_shard&&item.shard_loc
742
750
  ? `<p class="aghanim_description">
743
751
  <span class="title"><img src="${utils.getImageUrl("shard")}"class="shard">阿哈利姆魔晶</span>
744
752
  <span class="desc">${item.shard_loc}</span>
@@ -766,9 +774,9 @@
766
774
  `<span class="alternative shard">
767
775
  <img src="${utils.getImageUrl("shard")}"/>${sv.values_shard.map(value => (value > 0 ? '<span class="plus">+</span>' : "") + value + (sv.is_percentage ? "%" : "")).join(" / ")}
768
776
  </span>` : "" }
769
- ${sv.facet_bonus.name ?
777
+ ${sv.facet_bonus.name && hero.facets.some(facet=>facet.name==sv.facet_bonus.name) ?
770
778
  `<span class="alternative facet">
771
- <span class="facet"><span class="name_back type_${hero.facets.find(facet=>facet.name==sv.facet_bonus.name).color}"><img src="${utils.getImageUrl(hero.facets.find(facet=>facet.name==sv.facet_bonus.name).icon, ImageType.IconsFacets)}" />${sv.facet_bonus.values.map(value => (value > 0 ? '<span class="plus">+</span>' : "") + value + (sv.is_percentage ? "%" : "")).join(" / ")}</span></span>
779
+ <span class="facet"><span class="name_back type_${hero.facets.find(facet=>facet.name==sv.facet_bonus.name).color}"><img src="${utils.getImageUrl(hero.facets.find(facet=>facet.name==sv.facet_bonus.name).icon, ImageType.IconsFacets)}" />${sv.facet_bonus.values.map(value => value + (sv.is_percentage ? "%" : "")).join(" / ")}</span></span>
772
780
  </span>` : "" }
773
781
  ${sv.bonuses.length ?
774
782
  `<span class="alternative talent">
@@ -244,9 +244,9 @@
244
244
  .player > .rank > p {
245
245
  position: absolute;
246
246
  width: 100%;
247
- bottom: 2px;
247
+ bottom: 1.5px;
248
248
  text-align: center;
249
- font-size: 9px;
249
+ font-size: 8px;
250
250
  color: #fff;
251
251
  text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; /* 文字描边 */
252
252
  }