@sjtdev/koishi-plugin-dota2tracker 1.0.3 → 1.1.0

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.
Files changed (37) hide show
  1. package/lib/index.js +152 -323
  2. package/package.json +3 -2
  3. package/readme.md +5 -2
  4. package/template/images/logo_dire.png +0 -0
  5. package/template/images/logo_radiant.png +0 -0
  6. package/template/images/scepter_0.png +0 -0
  7. package/template/images/scepter_1.png +0 -0
  8. package/template/images/shard_0.png +0 -0
  9. package/template/images/shard_1.png +0 -0
  10. package/template/match/match_1.ejs +996 -0
  11. package/template/match/match_2.ejs +438 -0
  12. package/template/{match.html → match_old.html} +3 -1
  13. /package/{images → template/images}/flag_dire.png +0 -0
  14. /package/{images → template/images}/flag_radiant.png +0 -0
  15. /package/{images → template/images}/hero_badge_1.png +0 -0
  16. /package/{images → template/images}/hero_badge_2.png +0 -0
  17. /package/{images → template/images}/hero_badge_3.png +0 -0
  18. /package/{images → template/images}/hero_badge_4.png +0 -0
  19. /package/{images → template/images}/hero_badge_5.png +0 -0
  20. /package/{images → template/images}/hero_badge_6.png +0 -0
  21. /package/{images → template/images}/medal_0.png +0 -0
  22. /package/{images → template/images}/medal_1.png +0 -0
  23. /package/{images → template/images}/medal_2.png +0 -0
  24. /package/{images → template/images}/medal_3.png +0 -0
  25. /package/{images → template/images}/medal_4.png +0 -0
  26. /package/{images → template/images}/medal_5.png +0 -0
  27. /package/{images → template/images}/medal_6.png +0 -0
  28. /package/{images → template/images}/medal_7.png +0 -0
  29. /package/{images → template/images}/medal_8.png +0 -0
  30. /package/{images → template/images}/medal_8b.png +0 -0
  31. /package/{images → template/images}/medal_8c.png +0 -0
  32. /package/{images → template/images}/star_0.png +0 -0
  33. /package/{images → template/images}/star_1.png +0 -0
  34. /package/{images → template/images}/star_2.png +0 -0
  35. /package/{images → template/images}/star_3.png +0 -0
  36. /package/{images → template/images}/star_4.png +0 -0
  37. /package/{images → template/images}/star_5.png +0 -0
package/lib/index.js CHANGED
@@ -40,6 +40,14 @@ module.exports = __toCommonJS(src_exports);
40
40
  var import_koishi = require("koishi");
41
41
 
42
42
  // src/utils.ts
43
+ var utils_exports = {};
44
+ __export(utils_exports, {
45
+ CONFIGS: () => CONFIGS,
46
+ ImageType: () => ImageType,
47
+ getFormattedMatchData: () => getFormattedMatchData,
48
+ getImageUrl: () => getImageUrl,
49
+ query: () => query
50
+ });
43
51
  var import_axios = __toESM(require("axios"));
44
52
  var import_fs = __toESM(require("fs"));
45
53
  var dotaconstants = __toESM(require("dotaconstants"));
@@ -53,10 +61,19 @@ async function query(query_str) {
53
61
  });
54
62
  }
55
63
  __name(query, "query");
64
+ var ImageType = /* @__PURE__ */ ((ImageType2) => {
65
+ ImageType2["Icons"] = "icons";
66
+ ImageType2["Heroes"] = "heroes";
67
+ ImageType2["HeroIcons"] = "heroes/icons";
68
+ ImageType2["Items"] = "items";
69
+ ImageType2["Abilities"] = "abilities";
70
+ ImageType2["Local"] = "local";
71
+ return ImageType2;
72
+ })(ImageType || {});
56
73
  function getImageUrl(image, type = "local" /* Local */) {
57
74
  if (type === "local" /* Local */) {
58
75
  try {
59
- const imageData = import_fs.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-dota2tracker/images/${image}.png`);
76
+ const imageData = import_fs.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-dota2tracker/template/images/${image}.png`);
60
77
  const base64Data = imageData.toString("base64");
61
78
  return `data:image/png;base64,${base64Data}`;
62
79
  } catch (error) {
@@ -68,8 +85,9 @@ function getImageUrl(image, type = "local" /* Local */) {
68
85
  }
69
86
  __name(getImageUrl, "getImageUrl");
70
87
  function getFormattedMatchData(match) {
71
- match.radiantKillsCount = match.radiantKills ? match.radiantKills.reduce((acc, cva) => acc + cva, 0) : 0;
72
- match.direKillsCount = match.direKills ? match.direKills.reduce((acc, cva) => acc + cva, 0) : 0;
88
+ ["radiant", "dire"].forEach((team) => {
89
+ match[team] = { killsCount: match[team + "Kills"]?.reduce((acc, cva) => acc + cva, 0) ?? 0, damageReceived: 0, heroDamage: 0, networth: 0, experience: 0 };
90
+ });
73
91
  match.party = {};
74
92
  let party_index = 0;
75
93
  const party_mark = ["I", "II", "III", "IV"];
@@ -97,8 +115,20 @@ function getFormattedMatchData(match) {
97
115
  laneResult.mid = processLaneOutcome(match.midLaneOutcome);
98
116
  laneResult.bottom = processLaneOutcome(match.bottomLaneOutcome);
99
117
  match.players.forEach((player) => {
100
- player.killContribution = (player.kills + player.assists) / (player.isRadiant ? match.radiantKillsCount : match.direKillsCount);
101
- player.deathContribution = player.deaths / (player.isRadiant ? match.direKillsCount : match.radiantKillsCount);
118
+ player.team = player.isRadiant ? "radiant" : "dire";
119
+ player.rank = {
120
+ medal: parseInt(player.steamAccount.seasonRank?.toString().split("")[0] ?? 0),
121
+ star: parseInt(player.steamAccount.seasonRank?.toString().split("")[1] ?? 0),
122
+ leaderboard: player.steamAccount.seasonLeaderboardRank,
123
+ inTop100: player.steamAccount.seasonLeaderboardRank ? player.steamAccount.seasonLeaderboardRank <= 10 ? "8c" : player.steamAccount.seasonLeaderboardRank <= 100 ? "8b" : void 0 : void 0
124
+ };
125
+ player.killContribution = (player.kills + player.assists) / match[player.team].killsCount;
126
+ player.deathContribution = player.deaths / match[player.team === "radiant" ? "dire" : player.team].killsCount;
127
+ player.damageReceived = player.stats?.heroDamageReport?.receivedTotal.physicalDamage + player.stats?.heroDamageReport?.receivedTotal.magicalDamage + player.stats?.heroDamageReport?.receivedTotal.pureDamage;
128
+ match[player.team].heroDamage = (match[player.team].heroDamage ?? 0) + player.heroDamage;
129
+ match[player.team].damageReceived = (match[player.team].damageReceived ?? 0) + player.damageReceived;
130
+ match[player.team].networth += player.networth;
131
+ match[player.team].experience += Math.floor(player.experiencePerMinute / 60 * match.durationSeconds);
102
132
  player.titles = [];
103
133
  player.mvpScore = // 计算MVP分数
104
134
  player.kills * 5 + player.assists * 3 + player.stats.heroDamageReport.dealtTotal.stunDuration / 100 * 0.1 + (player.stats.heroDamageReport.dealtTotal.slowDuration + player.stats.heroDamageReport.dealtTotal.disableDuration) / 100 * 0.05 + player.heroDamage * 1e-3 + player.towerDamage * 0.01 + player.heroHealing * 2e-3 + player.imp * 0.25;
@@ -117,13 +147,13 @@ function getFormattedMatchData(match) {
117
147
  player.stats.matchPlayerBuffEvent.splice(0, player.stats.matchPlayerBuffEvent.length, ...Object.values(maxStackCountsByAbilityOrItem));
118
148
  switch (player.lane) {
119
149
  case "SAFE_LANE":
120
- player.laneResult = laneResult[player.isRadiant ? "bottom" : "top"][player.isRadiant ? "radiant" : "dire"];
150
+ player.laneResult = laneResult[player.isRadiant ? "bottom" : "top"][player.team];
121
151
  break;
122
152
  case "OFF_LANE":
123
- player.laneResult = laneResult[!player.isRadiant ? "bottom" : "top"][player.isRadiant ? "radiant" : "dire"];
153
+ player.laneResult = laneResult[!player.isRadiant ? "bottom" : "top"][player.team];
124
154
  break;
125
155
  default:
126
- player.laneResult = laneResult.mid[player.isRadiant ? "radiant" : "dire"];
156
+ player.laneResult = laneResult.mid[player.team];
127
157
  break;
128
158
  }
129
159
  let items_timelist = {};
@@ -272,8 +302,8 @@ function getFormattedMatchData(match) {
272
302
  (max, player) => player.stats.heroDamageReport.receivedTotal.physicalDamage + player.stats.heroDamageReport.receivedTotal.magicalDamage + player.stats.heroDamageReport.receivedTotal.pureDamage > max.stats.heroDamageReport.receivedTotal.physicalDamage + max.stats.heroDamageReport.receivedTotal.magicalDamage + max.stats.heroDamageReport.receivedTotal.pureDamage ? player : max
273
303
  ).titles.push({ name: "耐", color: "#84A1C7" });
274
304
  match.players.reduce((lowest, player) => {
275
- const currentContribution = (player.kills + player.assists) / (player.isRadiant ? match.radiantKillsCount : match.direKillsCount);
276
- const lowestContribution = (lowest.kills + lowest.assists) / (lowest.isRadiant ? match.radiantKillsCount : match.direKillsCount);
305
+ const currentContribution = (player.kills + player.assists) / match[player.team].KillsCount;
306
+ const lowestContribution = (lowest.kills + lowest.assists) / match[lowest.team].KillsCount;
277
307
  if (currentContribution < lowestContribution) {
278
308
  return player;
279
309
  } else if (currentContribution === lowestContribution) {
@@ -658,6 +688,24 @@ var import_moment = __toESM(require("moment"));
658
688
  var dotaconstants3 = __toESM(require("dotaconstants"));
659
689
 
660
690
  // src/dotaconstants_add.json
691
+ var dotaconstants_add_exports = {};
692
+ __export(dotaconstants_add_exports, {
693
+ HEROES_CHINESE: () => HEROES_CHINESE,
694
+ LOSE_NEGATIVE: () => LOSE_NEGATIVE,
695
+ LOSE_POSITIVE: () => LOSE_POSITIVE,
696
+ WIN_NEGATIVE: () => WIN_NEGATIVE,
697
+ WIN_POSITIVE: () => WIN_POSITIVE,
698
+ behavior: () => behavior,
699
+ default: () => dotaconstants_add_default,
700
+ gameMode: () => gameMode,
701
+ lobbyTypes: () => lobbyTypes,
702
+ position: () => position,
703
+ primary_attrs: () => primary_attrs,
704
+ rank: () => rank,
705
+ region: () => region,
706
+ roles: () => roles,
707
+ target_team: () => target_team
708
+ });
661
709
  var gameMode = {
662
710
  NONE: "",
663
711
  ALL_PICK: "全英雄选择",
@@ -732,6 +780,17 @@ var position = {
732
780
  "4": "采灵芝",
733
781
  "5": "工具人"
734
782
  };
783
+ var rank = {
784
+ "0": "未知",
785
+ "1": "先锋",
786
+ "2": "卫士",
787
+ "3": "中军",
788
+ "4": "统帅",
789
+ "5": "传奇",
790
+ "6": "万古流芳",
791
+ "7": "超凡入圣",
792
+ "8": "冠绝一世"
793
+ };
735
794
  var roles = { CARRY: "核心", ESCAPE: "逃生", NUKER: "爆发", INITIATOR: "先手", DURABLE: "耐久", DISABLER: "控制", JUNGLER: "打野", SUPPORT: "辅助", PUSHER: "推进" };
736
795
  var primary_attrs = { all: "hero_universal", str: "hero_strength", agi: "hero_agility", int: "hero_intelligence" };
737
796
  var behavior = {
@@ -877,14 +936,33 @@ var WIN_NEGATIVE = ["侥幸赢得了比赛", "走狗屎运赢得了比赛", "躺
877
936
  var WIN_POSITIVE = ["带领团队走向了胜利", "暴打对面后赢得了胜利", " CARRY全场赢得了胜利", "把对面当猪宰了, 赢得了胜利", "又赢了, 这游戏就是这么枯燥, 且乏味", "直接进行一个比赛的赢"];
878
937
  var LOSE_NEGATIVE = ["被人按在地上摩擦, 输掉了这场比赛", "悲惨地输掉了比赛", "头都被打歪了, 心态爆炸地输掉了比赛", "捕鱼被鱼吃了, 输掉了比赛", "打的是个几把", "直接进行一个比赛的输"];
879
938
  var LOSE_POSITIVE = ["无力回天输掉了比赛", "尽力了, 但还是输了比赛", "背靠世界树, 虽败犹荣", "带不动队友, 输了比赛", "又输了, 很难受, 宁愿输的是我"];
939
+ var dotaconstants_add_default = {
940
+ gameMode,
941
+ lobbyTypes,
942
+ region,
943
+ position,
944
+ rank,
945
+ roles,
946
+ primary_attrs,
947
+ behavior,
948
+ target_team,
949
+ HEROES_CHINESE,
950
+ WIN_NEGATIVE,
951
+ WIN_POSITIVE,
952
+ LOSE_NEGATIVE,
953
+ LOSE_POSITIVE
954
+ };
880
955
 
881
956
  // src/index.ts
882
957
  var import_koishi2 = require("koishi");
958
+ var ejs = __toESM(require("ejs"));
959
+ var import_path = __toESM(require("path"));
883
960
  var name = "dota2tracker";
884
961
  var usage = "DOTA2Bot插件-提供自动追踪群友的最新对局的功能(需群友绑定),以及一系列查询功能。";
885
962
  var inject = ["database", "puppeteer", "cron"];
886
963
  var Config = import_koishi.Schema.object({
887
- STRATZ_API_TOKEN: import_koishi.Schema.string().required().description("※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取")
964
+ STRATZ_API_TOKEN: import_koishi.Schema.string().required().description("※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取"),
965
+ template_match: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/match`)]).default("match_1").description("生成比赛图片使用的模板,见 https://github.com/sjtdev/koishi-plugin-dota2tracker/wiki 有模板展示。")
888
966
  });
889
967
  var pendingMatches = [];
890
968
  var random = new import_koishi2.Random(() => Math.random());
@@ -977,39 +1055,45 @@ async function apply(ctx, config) {
977
1055
  session.send("开发中,未来此功能会重写。\n" + queryRes.map((item) => `${item.nickName ?? ""},ID:${item.userId},SteamID:${item.steamId}`).join("\n"));
978
1056
  }
979
1057
  });
980
- ctx.command("查询比赛 <match_id>", "查询比赛ID").usage("查询指定比赛ID的比赛数据,生成图片发布。").example("-查询比赛 1234567890").action(async ({ session }, match_id) => {
981
- if (!match_id) {
982
- session.send("请输入比赛ID。");
983
- return;
984
- }
985
- if (!/^\d{10}$/.test(match_id)) {
986
- session.send("比赛ID无效。");
987
- return;
988
- }
989
- session.send("正在搜索对局详情,请稍后...");
1058
+ async function queryAndDisplayMatch(session, matchId) {
990
1059
  try {
991
1060
  let match;
992
- let queryLocal = await ctx.database.get("dt_previous_query_results", match_id, ["data"]);
1061
+ let queryLocal = await ctx.database.get("dt_previous_query_results", matchId, ["data"]);
993
1062
  if (queryLocal.length > 0) {
994
1063
  match = queryLocal[0].data;
995
1064
  ctx.database.set("dt_previous_query_results", match.id, { queryTime: /* @__PURE__ */ new Date() });
996
1065
  } else {
997
- let queryRes = await query(MATCH_INFO(match_id));
1066
+ let queryRes = await query(MATCH_INFO(matchId));
998
1067
  if (queryRes.status == 200) {
999
1068
  match = getFormattedMatchData(queryRes.data.data.match);
1000
1069
  }
1001
1070
  }
1002
- if (match.parsedDateTime) {
1003
- session.send(await ctx.puppeteer.render(genMatchImageHTML(match)));
1071
+ if (match && match.parsedDateTime) {
1072
+ session.send(await ctx.puppeteer.render(newGenMatchImageHTML(match, config.template_match)));
1004
1073
  ctx.database.upsert("dt_previous_query_results", (row) => [{ matchId: match.id, data: match, queryTime: /* @__PURE__ */ new Date() }]);
1005
1074
  } else {
1006
- pendingMatches.push({ matchId: match_id, platform: session.event.platform, guildId: session.event.guild.id });
1075
+ pendingMatches.push({ matchId, platform: session.event.platform, guildId: session.event.guild.id });
1007
1076
  session.send("比赛尚未解析,将在解析完成后发布。");
1008
1077
  }
1009
1078
  } catch (error) {
1010
1079
  console.error(error);
1011
1080
  session.send("获取比赛信息失败。");
1081
+ ctx.database.remove("dt_previous_query_results", { matchId: parseInt(matchId) });
1082
+ }
1083
+ }
1084
+ __name(queryAndDisplayMatch, "queryAndDisplayMatch");
1085
+ ctx.command("查询比赛 <match_id>", "查询比赛ID").usage("查询指定比赛ID的比赛数据,生成图片发布。").example("-查询比赛 1234567890").action(async ({ session }, match_id) => {
1086
+ if (!match_id) {
1087
+ session.send("请输入比赛ID。");
1088
+ return;
1012
1089
  }
1090
+ JSON.stringify;
1091
+ if (!/^\d{10}$/.test(match_id)) {
1092
+ session.send("比赛ID无效。");
1093
+ return;
1094
+ }
1095
+ session.send("正在搜索对局详情,请稍后...");
1096
+ queryAndDisplayMatch(session, match_id);
1013
1097
  });
1014
1098
  ctx.command("查询最近比赛 [input_data]", "查询玩家的最近比赛").usage("查询指定玩家的最近一场比赛的比赛数据,生成图片发布。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID").example("-查询最近比赛 123456789").example("-查询最近比赛 张三").action(async ({ session }, input_data) => {
1015
1099
  if (session.guild) {
@@ -1035,28 +1119,7 @@ async function apply(ctx, config) {
1035
1119
  session.send("获取玩家最近比赛失败。");
1036
1120
  return;
1037
1121
  }
1038
- try {
1039
- let match;
1040
- let queryLocal = await ctx.database.get("dt_previous_query_results", lastMatchId, ["data"]);
1041
- if (queryLocal.length > 0) {
1042
- match = queryLocal[0].data;
1043
- } else {
1044
- let queryRes = await query(MATCH_INFO(lastMatchId));
1045
- if (queryRes.status == 200) {
1046
- match = getFormattedMatchData(queryRes.data.data.match);
1047
- }
1048
- }
1049
- if (match.parsedDateTime) {
1050
- session.send(await ctx.puppeteer.render(genMatchImageHTML(match)));
1051
- ctx.database.upsert("dt_previous_query_results", (row) => [{ matchId: match.id, data: match, queryTime: /* @__PURE__ */ new Date() }]);
1052
- } else {
1053
- pendingMatches.push({ matchId: lastMatchId, platform: session.event.platform, guildId: session.event.guild.id });
1054
- session.send("比赛尚未解析,将在解析完成后发布。");
1055
- }
1056
- } catch (error) {
1057
- console.error(error);
1058
- session.send("获取比赛信息失败。");
1059
- }
1122
+ queryAndDisplayMatch(session, lastMatchId);
1060
1123
  }
1061
1124
  });
1062
1125
  ctx.command("查询玩家 <input_data>", "查询玩家信息").usage("查询指定玩家的个人信息与最近战绩,生成图片发布。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID").example("-查询玩家 123456789").example("-查询玩家 张三").action(async ({ session }, input_data) => {
@@ -1292,7 +1355,7 @@ async function apply(ctx, config) {
1292
1355
  const commingMatches = scanningMatches.filter((item) => item.matchId == match.id);
1293
1356
  const realCommingMatches = commingMatches.filter((commingMatch, index, self) => index === self.findIndex((t) => t.guildId === commingMatch.guildId && t.platform === commingMatch.platform));
1294
1357
  let broadMatchMessage = "";
1295
- const img = await ctx.puppeteer.render(genMatchImageHTML(match));
1358
+ const img = await ctx.puppeteer.render(newGenMatchImageHTML(match, config.template_match));
1296
1359
  for (let comming of realCommingMatches) {
1297
1360
  let commingSubscribedPlayers = subscribedPlayersInGuild.filter((item) => item.platform == comming.platform && item.guildId == comming.guildId);
1298
1361
  let idsToFind = commingSubscribedPlayers.map((item) => item.steamId);
@@ -1311,7 +1374,7 @@ async function apply(ctx, config) {
1311
1374
  broadPlayerMessage += random.pick(LOSE_NEGATIVE);
1312
1375
  }
1313
1376
  broadPlayerMessage += `。
1314
- KDA:${((player.kills + player.assists) / Math.max(1, player.deaths)).toFixed(2)} [${player.kills}/${player.deaths}/${player.assists}],GPM/XPM:${player.goldPerMinute}/${player.experiencePerMinute},补刀数:${player.numLastHits}/${player.numDenies},伤害/塔伤:${player.heroDamage}/${player.towerDamage},参战/参葬率:${(player.killContribution * 100).toFixed(2)}%/${(player.deathContribution * 100).toFixed(2)}%`;
1377
+ KDA:${((player.kills + player.assists) / (player.deaths || 1)).toFixed(2)} [${player.kills}/${player.deaths}/${player.assists}],GPM/XPM:${player.goldPerMinute}/${player.experiencePerMinute},补刀数:${player.numLastHits}/${player.numDenies},伤害/塔伤:${player.heroDamage}/${player.towerDamage},参战/参葬率:${(player.killContribution * 100).toFixed(2)}%/${(player.deathContribution * 100).toFixed(2)}%`;
1315
1378
  broadMatchMessage += broadPlayerMessage + "\n";
1316
1379
  }
1317
1380
  await ctx.broadcast([`${comming.platform}:${comming.guildId}`], broadMatchMessage + img);
@@ -1322,6 +1385,7 @@ KDA:${((player.kills + player.assists) / Math.max(1, player.deaths)).toFixed(2
1322
1385
  ctx.logger.info("比赛 %d 尚未解析完成,继续等待。", match.id);
1323
1386
  } catch (error) {
1324
1387
  console.error(error);
1388
+ ctx.database.remove("dt_previous_query_results", { matchId: pendingMatch.matchId });
1325
1389
  }
1326
1390
  }
1327
1391
  });
@@ -1330,268 +1394,30 @@ KDA:${((player.kills + player.assists) / Math.max(1, player.deaths)).toFixed(2
1330
1394
  });
1331
1395
  }
1332
1396
  __name(apply, "apply");
1333
- function genMatchImageHTML(match) {
1334
- let $ = cheerio.load(import_fs2.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/match.html`, "utf-8"));
1335
- let kcndcStyle = {
1336
- kc: function(num) {
1337
- let red = (255 - num * 255 / 100).toFixed(2);
1338
- return `rgb(255,${red},${red})`;
1339
- },
1340
- dc: function(num) {
1341
- let gray = ((50 - Math.min(num, 50)) * (255 / 50)).toFixed(2);
1342
- return `rgb(${gray},${gray},${gray})`;
1343
- }
1344
- };
1345
- const laneSVG = {
1346
- stomp: `<svg viewBox="0 0 24 24" class="hitagi__sc-1apuy4g-0 hmhZOG"><path d="M8.05731 22.3674L9.60454 22.8002L11.5974 21.6551L12.043 20.0773L13.5902 20.51L15.583 19.3649L16.0287 17.7871L17.5759 18.2199L19.5687 17.0748L20.0143 15.4969L21.5615 15.9297L23.5544 14.7846L24 13.2068L23.4492 12.2014L7.50651 21.3621L8.05731 22.3674ZM12.1328 3.50265L11.0312 1.49196C10.8798 1.21549 10.5316 1.11811 10.2576 1.27556L0.29345 7.00098C0.0194354 7.15843 -0.0808273 7.51346 0.0706444 7.78993L1.44766 10.3033L11.91 4.29159C12.184 4.13414 12.2843 3.77912 12.1328 3.50265ZM18.3935 8.4063L14.1658 9.60458L12.4221 10.6065C12.2851 10.6853 12.111 10.6366 12.0353 10.4983L11.7599 9.99565C11.6842 9.85742 11.7343 9.6799 11.8713 9.60118L13.615 8.59924L13.0642 7.59389L11.3205 8.59584C11.1835 8.67456 11.0094 8.62587 10.9337 8.48765L10.6583 7.98497C10.5826 7.84673 10.6327 7.66922 10.7697 7.5905L12.5134 6.58855L11.9626 5.58321L1.99846 11.3086L6.9557 20.3567L22.8984 11.196L22.2615 10.0336C21.5024 8.64813 19.9073 7.97847 18.3935 8.4063Z"></path></svg>`,
1347
- victory: `<svg viewBox="0 0 512 512"><path d="M198.844 64.75c-.985 0-1.974.03-2.97.094-15.915 1.015-32.046 11.534-37.78 26.937-34.072 91.532-51.085 128.865-61.5 222.876 14.633 13.49 31.63 26.45 50.25 38.125l66.406-196.467 17.688 5.968L163.28 362.5c19.51 10.877 40.43 20.234 62 27.28l75.407-201.53 17.5 6.53-74.937 200.282c19.454 5.096 39.205 8.2 58.78 8.875L381.345 225.5l17.094 7.594-75.875 170.656c21.82-1.237 43.205-5.768 63.437-14.28 43.317-53.844 72.633-109.784 84.5-172.69 5.092-26.992-14.762-53.124-54.22-54.81l-6.155-.282-2.188-5.75c-8.45-22.388-19.75-30.093-31.5-32.47-11.75-2.376-25.267 1.535-35.468 7.376l-13.064 7.47-.906-15c-.99-16.396-10.343-29.597-24.313-35.626-13.97-6.03-33.064-5.232-54.812 9.906l-10.438 7.25-3.812-12.125c-6.517-20.766-20.007-27.985-34.78-27.97zM103.28 188.344C71.143 233.448 47.728 299.56 51.407 359.656c27.54 21.84 54.61 33.693 80.063 35.438 14.155.97 27.94-1.085 41.405-6.438-35.445-17.235-67.36-39.533-92.594-63.53l-3.343-3.157.5-4.595c5.794-54.638 13.946-91.5 25.844-129.03z"/></svg>`,
1348
- fail: `<svg viewBox="0 0 36 36"><path fill="#ff6961" d="M36 32a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4h28a4 4 0 0 1 4 4v28z"></path><circle fill="#FFF" cx="27" cy="7" r="3"></circle><path fill="#FFF" d="M13.06 13.06l2.367-2.366l3.859 1.158l-2.635 2.847a10.018 10.018 0 0 1 4.392 3.379l5.017-5.017a1.5 1.5 0 0 0-.63-2.497l-9.999-3a1.495 1.495 0 0 0-1.492.376l-3 3a1.5 1.5 0 1 0 2.121 2.12zm16.065 4.949a1.496 1.496 0 0 0-1.262-.503l-6.786.617a9.966 9.966 0 0 1 1.464 2.879l3.548-.322l-1.554 6.995a1.499 1.499 0 1 0 2.928.65l2-9a1.5 1.5 0 0 0-.338-1.316zM13 16a8 8 0 1 0 0 16a8 8 0 0 0 0-16zm0 14a6 6 0 1 1 .002-12.002A6 6 0 0 1 13 30z"></path></svg>`,
1349
- stomped: `<svg viewBox="-1 0 19 19"><path d="M16.417 9.579A7.917 7.917 0 1 1 8.5 1.662a7.917 7.917 0 0 1 7.917 7.917zm-2.458 2.96a.396.396 0 0 0-.396-.397h-.667a1.527 1.527 0 0 0-1.249-1.114.777.777 0 0 0 .014-.145V9.378a.794.794 0 0 0-.792-.792H8.201a2.984 2.984 0 0 0-1.682-.516l-.11.002V7.42h2.997a.396.396 0 1 0 0-.792H6.41v-1.3a.396.396 0 0 0-.396-.397H4.891a.396.396 0 0 0 0 .792h.727V8.21a2.997 2.997 0 1 0 3.836 3.466h.71a1.526 1.526 0 1 0 2.732 1.26h.667a.396.396 0 0 0 .396-.397zM8.078 9.507a2.205 2.205 0 1 1-1.559-.646 2.19 2.19 0 0 1 1.559.646zm4.078 3.03a.734.734 0 1 1-.733-.734.735.735 0 0 1 .733.733z"/></svg>`,
1350
- tie: `<svg fill="#fff" viewBox="0 0 512.001 512.001"><g><g><path d="M120.988,239.868c-4.496,10.625-5.122,20.183-5.157,20.811c-0.267,4.607,3.243,8.547,7.849,8.829 c4.618,0.29,8.574-3.228,8.873-7.833c0.265-4.771,2.339-13.092,5.884-19.44C137.421,242.113,141.397,242.649,120.988,239.868z"/></g></g><g><g><path d="M391.178,255.418c-0.211,8.054-2.458,17.62-6.74,28.398c-1.708,4.299,0.393,9.168,4.692,10.875 c4.293,1.708,9.167-0.39,10.875-4.692c5.103-12.842,7.74-24.392,7.943-34.581H391.178z"/></g></g><g><g><path d="M164.769,210.51c1.046,3.339,1.397,6.953,0.893,10.65c-0.293,2.146-0.857,4.188-1.648,6.1c0,0,51.266,3.416,198.065,3.949 c-0.086-6.331,2.19-12.199,6.244-16.732C217.627,214.046,164.769,210.51,164.769,210.51z"/></g></g><g><g><circle cx="37.179" cy="128.669" r="29.491"/></g></g><g><g><path d="M510.146,391.511l-37.916-66.985c14.35-49.173,20.678-68.137,20.678-68.137l8.949-67.014 c1.502-10.977-6.248-21.075-17.235-22.468l-18.183-2.305c-10.984-1.393-20.996,6.445-22.293,17.431l-1.884,15.955l28.718-21.317 l-37.91,42.278h-46.432c-6.571,0-11.898,5.328-11.898,11.898c0,6.57,5.328,11.898,11.898,11.898h51.744 c3.381,0,6.601-1.438,8.859-3.956l41.456-46.234l-32.023,54.694c-5.28,9.018-14.374,8.169-18.293,8.167c-1.959,0-3.31,0-5.295,0 c-0.399,0.898,3.152-7.399-24.44,57.181c-0.548,1.284-0.907,2.642-1.06,4.031l-8.934,80.338 c-0.939,8.447,5.667,15.857,14.208,15.857c7.179,0,13.361-5.401,14.172-12.701l8.702-78.244l21.512-50.353l-14.121,50.463 c-1.158,3.756-0.718,7.823,1.218,11.243l40.949,72.345c3.885,6.864,12.596,9.276,19.459,5.392 C511.615,407.085,514.03,398.373,510.146,391.511z"/></g></g><g><g><circle cx="464.865" cy="128.702" r="29.491"/></g></g><g><g><path d="M142.923,206.051l-59.556-8.118l-39.135-18.451l13.626,2.292c-1.422-10.945-11.411-18.577-22.254-17.202l-18.182,2.305 C6.43,168.271-1.315,178.374,0.186,189.345l9.12,68.689l21.865,70.857l5.829,70.795c0.646,7.848,7.527,13.705,15.401,13.057 c7.859-0.647,13.705-7.542,13.058-15.401l-5.956-72.345c-0.084-1.031-0.281-2.05-0.585-3.039l-14.123-50.463l21.514,50.353 l8.702,78.244c0.873,7.86,7.96,13.486,15.768,12.612c7.838-0.871,13.483-7.931,12.612-15.768l-8.934-80.338 c-0.154-1.388-0.511-2.747-1.06-4.032l-27.336-61.43l-2.945-24.951l-29.029-25.179l40.79,19.231 c1.097,0.517,2.266,0.862,3.468,1.027l61.369,8.365c6.521,0.887,12.509-3.68,13.396-10.183 C153.994,212.936,149.435,206.939,142.923,206.051z"/></g></g></svg>`
1397
+ function newGenMatchImageHTML(match, template = "match_1") {
1398
+ const templatePath = import_path.default.join(`./node_modules/@sjtdev/koishi-plugin-${name}/template/match`, template + ".ejs");
1399
+ const data = {
1400
+ match,
1401
+ utils: utils_exports,
1402
+ ImageType,
1403
+ d2a: dotaconstants_add_exports,
1404
+ dotaconstants: dotaconstants3,
1405
+ moment: import_moment.default,
1406
+ sec2time,
1407
+ formatNumber
1351
1408
  };
1352
- let matchInfo_html = `
1353
- <img src="${getImageUrl("flag_radiant")}" alt="" class="flag radiant${match.didRadiantWin ? " won" : ""}" style="order: 1" />
1354
- <img src="${getImageUrl("flag_dire")}" alt="" class="flag dire${match.didRadiantWin ? "" : " won"}" style="order: 3" />
1355
- <p class="won${match.didRadiantWin ? " radiant" : ""}">获胜</p>
1356
- <div class="details" style="order: 2">
1357
- <p>比赛编号:<span class="match_id">${match.id}</span></p>
1358
- <p>模式:<span class="mode">${lobbyTypes[match.lobbyType] || match.lobbyType}/${gameMode[match.gameMode] || match.gameMode}</span></p>
1359
- <p>服务器:<span class="server">${region[match.regionId]}</span></p>
1360
- <p>起始时间:<span class="start_time">${(0, import_moment.default)(new Date(match.startDateTime * 1e3)).format("YYYY-MM-DD HH:mm:ss").slice(2)}</span></p>
1361
- <img src="${getImageUrl("star_" + match.rank?.toString().split("")[1])}" alt="" class="star">
1362
- <img src="${getImageUrl("medal_" + match.rank?.toString().split("")[0])}" alt="" class="rank">
1363
- <p>结束时间:<span class="end_time">${(0, import_moment.default)(new Date(match.endDateTime * 1e3)).format("YYYY-MM-DD HH:mm:ss").slice(2)}</span></p>
1364
- <div class="score">
1365
- <p class="score radiant">${match.radiantKillsCount}</p>
1366
- <p class="time">${sec2time(match.durationSeconds)}</p>
1367
- <p class="score dire">${match.direKillsCount}</p>
1368
- </div>
1369
- </div>
1370
- `;
1371
- $(".match_info").html(matchInfo_html);
1372
- let players_html = { radiant: "", dire: "" };
1373
- match.players.forEach((player) => {
1374
- players_html[player.isRadiant ? "radiant" : "dire"] += sanitizeHTML`
1375
- <div class="player${player.hero.id == 80 ? " bear" : ""}${player.leaverStatus != "NONE" && player.leaverStatus != "DISCONNECTED" ? " giveup" : ""}" style="order:${player.position?.slice(-1)}">
1376
- <div class="hero">
1377
- <div class="player_avatar">
1378
- <img alt="" src="${getImageUrl(player.hero.shortName, "heroes" /* Heroes */)}" />
1379
- <p class="party_line${player.partyId != null ? " party_" + match.party[player.partyId] : ""}"></p>
1380
- <p class="party_mark${player.partyId != null ? " party_" + match.party[player.partyId] : ""}"></p>
1381
- <p class="position p${Math.floor(player.order / 4) + 1}">${player.isRandom ? "随机" : `第<span>${player.order ? player.order + 1 : "-"}</span>手`}<br/>${position[player.position?.slice(-1)]}</p>
1382
- <p class="level">${player.level}</p>
1383
- </div>
1384
- <div class="player_info">
1385
- <summary class="player_name">${player.steamAccount.name}</summary>
1386
- <summary class="player_performance">
1387
- <span class="kda">${player.kills}/${player.deaths}/${player.assists}</span>&nbsp;&nbsp;
1388
- <span class="kc" style="color:${kcndcStyle.kc(player.killContribution * 100)}">${Math.floor(player.killContribution * 100)}%</span>&nbsp;&nbsp;
1389
- <span class="dc" style="color:${kcndcStyle.dc(player.deathContribution * 100)}">${Math.floor(player.deathContribution * 100)}%</span></summary>
1390
- <summary class="player_net"><span class="networth">${player.networth}</span>&emsp;<span class="score">${(player.heroDamage / player.networth)?.toFixed(2)}</span></summary>
1391
- </div>
1392
- <div class="player_lane ${player.laneResult}">
1393
- ${laneSVG[player.laneResult]}
1394
- </div>
1395
- <div class="player_rank">
1396
- ${player.steamAccount.seasonRank ? `
1397
- <div class="rank">
1398
- <img class="medal" src="${getImageUrl(
1399
- "medal_" + (player.steamAccount.seasonLeaderboardRank ? player.steamAccount.seasonLeaderboardRank <= 100 ? player.steamAccount.seasonLeaderboardRank <= 10 ? "8c" : "8b" : player.steamAccount.seasonRank.toString().split("")[0] : player.steamAccount.seasonRank.toString().split("")[0])
1400
- )}" alt="" />
1401
- ${!player.steamAccount.seasonLeaderboardRank ? `
1402
- <img class="star" src="${getImageUrl("star_" + player.steamAccount.seasonRank.toString().split("")[1])}" alt="" />` : `
1403
- <p>${player.steamAccount.seasonLeaderboardRank}</p>`}
1404
- </div>` : `
1405
- <div class="norank">
1406
- <img class="medal" src="${getImageUrl("medal_0")}" alt="" />
1407
- </div>`}
1408
- <div class="dotaPlusLevel"${!player.dotaPlus ? ` style="display:none"` : ""}>
1409
- <img src="${getImageUrl("hero_badge_" + (player.dotaPlus ? Math.ceil((player.dotaPlus?.level + 1) / 6) : 1))}" alt="" class="badge">
1410
- <p class="level">${player.dotaPlus?.level}</p>
1411
- </div>
1412
- </div>
1413
- </div>
1414
- <div class="titles">
1415
- ${player.titles.map((item) => `<span style="color: ${item.color};">${item.name}</span>`).join("&nbsp;")}
1416
- </div>
1417
- ${player.hero.id != 80 ? `
1418
- <div class="items">
1419
- <div class="items_normal">
1420
- ${player.items.map(
1421
- (item) => item ? `
1422
- <div class="item${item.isRecipe ? " recipe" : ""}">
1423
- <img src="${getImageUrl(item.name, "items" /* Items */)}" alt="" />
1424
- <p class="time">${sec2time(item.time)}</p>
1425
- </div>` : `
1426
- <div class="item" style="visibility:hidden"}">
1427
- <img src="${getImageUrl("blink", "items" /* Items */)}" alt="" />
1428
- <p class="time">--:--</p>
1429
- </div>`
1430
- ).join("")}
1431
- </div>
1432
- <div class="items_backpack">
1433
- ${player.backpacks.map(
1434
- (item) => item ? `
1435
- <div class="item back${item.isRecipe ? " recipe" : ""}">
1436
- <img src="${getImageUrl(item.name, "items" /* Items */)}" alt="" />
1437
- <p class="time">${sec2time(item.time)}</p>
1438
- </div>` : `
1439
- <div class="item back" style="visibility:hidden"}">
1440
- <img src="${getImageUrl("blink", "items" /* Items */)}" alt="" />
1441
- <p class="time">--:--</p>
1442
- </div>`
1443
- ).join("")}
1444
- </div>
1445
- <div class="item neutral" style="background-image: url(${getImageUrl(dotaconstants3.item_ids[player.neutral0Id], "items" /* Items */)})"></div>
1446
- </div>
1447
- <div class="buffs">
1448
- <section>
1449
- ${player.stats?.matchPlayerBuffEvent?.map(
1450
- (buff) => `
1451
- <div class="buff">
1452
- <img src="${getImageUrl(dotaconstants3[buff.abilityId ? "ability_ids" : "item_ids"][buff.abilityId ?? buff.itemId], buff.abilityId ? "abilities" /* Abilities */ : "items" /* Items */)}" alt="" />
1453
- <p>${buff.stackCount ?? ""}</p>
1454
- </div>`
1455
- ).join("")}
1456
- </section>
1457
- <section>
1458
- <div class="support_item"${player.supportItemsCount[30] > 0 ? "" : ' style="display:none"'}>
1459
- <img src="${getImageUrl("gem", "items" /* Items */)}" alt="" />
1460
- <p>${player.supportItemsCount[30]}</p>
1461
- </div>
1462
- <div class="support_item"${player.supportItemsCount[40] > 0 ? "" : ' style="display:none"'}>
1463
- <img src="${getImageUrl("dust", "items" /* Items */)}" alt="" />
1464
- <p>${player.supportItemsCount[40]}</p>
1465
- </div>
1466
- <div class="support_item"${player.supportItemsCount[42] > 0 ? "" : ' style="display:none"'}>
1467
- <img src="${getImageUrl("ward_observer", "items" /* Items */)}" alt="" />
1468
- <p>${player.supportItemsCount[42]}</p>
1469
- </div>
1470
- <div class="support_item"${player.supportItemsCount[43] > 0 ? "" : ' style="display:none"'}>
1471
- <img src="${getImageUrl("ward_sentry", "items" /* Items */)}" alt="" />
1472
- <p>${player.supportItemsCount[43]}</p>
1473
- </div>
1474
- <div class="support_item"${player.supportItemsCount[188] > 0 ? "" : ' style="display:none"'}>
1475
- <img src="${getImageUrl("smoke_of_deceit", "items" /* Items */)}" alt="" />
1476
- <p>${player.supportItemsCount[188]}</p>
1477
- </div>
1478
- </section>
1479
- </div>` : `
1480
- <div class="items_buffs master">
1481
- <div class="items master">
1482
- ${player.items.map(
1483
- (item) => item ? `
1484
- <div class="item${item.isRecipe ? " recipe" : ""}">
1485
- <img src="${getImageUrl(item.name, "items" /* Items */)}" alt="" />
1486
- <p class="time">${sec2time(item.time)}</p>
1487
- </div>` : `
1488
- <div class="item" style="visibility:hidden"}">
1489
- <img src="${getImageUrl("blink", "items" /* Items */)}" alt="" />>
1490
- <p class="time">--:--</p>
1491
- </div>`
1492
- ).join("")}
1493
- ${player.backpacks.map(
1494
- (item) => item ? `
1495
- <div class="item back${item.isRecipe ? " recipe" : ""}">
1496
- <img src="${getImageUrl(item.name, "items" /* Items */)}" alt="" />
1497
- <p class="time">${sec2time(item.time)}</p>
1498
- </div>` : `
1499
- <div class="item back" style="visibility:hidden"}">
1500
- <img src="${getImageUrl("blink", "items" /* Items */)}" alt="" />
1501
- <p class="time">--:--</p>
1502
- </div>`
1503
- ).join("")}
1504
- <div class="item neutral">
1505
- <img src="${getImageUrl(dotaconstants3.item_ids[player.neutral0Id], "items" /* Items */)}" alt="" />
1506
- </div>
1507
- </div>
1508
- <div class="buffs master">
1509
- ${player.stats?.matchPlayerBuffEvent?.map(
1510
- (buff) => `
1511
- <div class="buff">
1512
- <img src="${getImageUrl(dotaconstants3[buff.abilityId ? "ability_ids" : "item_ids"][buff.abilityId ?? buff.itemId], buff.abilityId ? "abilities" /* Abilities */ : "items" /* Items */)}" alt="" />
1513
- <p>${buff.stackCount ?? ""}</p>
1514
- </div>`
1515
- ).join("")}
1516
- </div>
1517
- </div>
1518
- <div class="items_buffs slave">
1519
- <div class="items slave">
1520
- ${player.unitItems.map(
1521
- (item) => item ? `
1522
- <div class="item${item.isRecipe ? " recipe" : ""}">
1523
- <img src="${getImageUrl(item.name, "items" /* Items */)}" alt="" />
1524
- <p class="time">${sec2time(item.time)}</p>
1525
- </div>` : `
1526
- <div class="item" style="visibility:hidden"}">
1527
- <img src="${getImageUrl("blink", "items" /* Items */)}" alt="" />>
1528
- <p class="time">--:--</p>
1529
- </div>`
1530
- ).join("")}
1531
- ${player.unitBackpacks.map(
1532
- (item) => item ? `
1533
- <div class="item back${item.isRecipe ? " recipe" : ""}">
1534
- <img src="${getImageUrl(item.name, "items" /* Items */)}" alt="" />
1535
- <p class="time">${sec2time(item.time)}</p>
1536
- </div>` : `
1537
- <div class="item back" style="visibility:hidden"}">
1538
- <img src="${getImageUrl("blink", "items" /* Items */)}" alt="" />
1539
- <p class="time">--:--</p>
1540
- </div>`
1541
- ).join("")}
1542
- <div class="item neutral">
1543
- <img src="${getImageUrl(dotaconstants3.item_ids[player.additionalUnit.neutral0Id], "items" /* Items */)}" alt="" />
1544
- </div>
1545
- </div>
1546
- <div class="buffs_supportItems slave">
1547
- <div class="buffs">
1548
- <!-- 无有效API获取熊灵buff -->
1549
- </div>
1550
- <div class="support_items">
1551
- <div class="support_item"${player.supportItemsCount[30] > 0 ? "" : ' style="display:none"'}>
1552
- <img src="${getImageUrl("gem", "items" /* Items */)}" alt="" />
1553
- <p>${player.supportItemsCount[30]}</p>
1554
- </div>
1555
- <div class="support_item"${player.supportItemsCount[40] > 0 ? "" : ' style="display:none"'}>
1556
- <img src="${getImageUrl("dust", "items" /* Items */)}" alt="" />
1557
- <p>${player.supportItemsCount[40]}</p>
1558
- </div>
1559
- <div class="support_item"${player.supportItemsCount[42] > 0 ? "" : ' style="display:none"'}>
1560
- <img src="${getImageUrl("ward_observer", "items" /* Items */)}" alt="" />
1561
- <p>${player.supportItemsCount[42]}</p>
1562
- </div>
1563
- <div class="support_item"${player.supportItemsCount[43] > 0 ? "" : ' style="display:none"'}>
1564
- <img src="${getImageUrl("ward_sentry", "items" /* Items */)}" alt="" />
1565
- <p>${player.supportItemsCount[43]}</p>
1566
- </div>
1567
- <div class="support_item"${player.supportItemsCount[188] > 0 ? "" : ' style="display:none"'}>
1568
- <img src="${getImageUrl("smoke_of_deceit", "items" /* Items */)}" alt="" />
1569
- <p>${player.supportItemsCount[188]}</p>
1570
- </div>
1571
- </div>
1572
- </div>
1573
- </div>`}
1574
- <div class="details">
1575
- <section>英雄伤害:<span class="hero_damage">${player.heroDamage}</span></section>
1576
- <section>建筑伤害:<span class="building_damage">${player.towerDamage}</span></section>
1577
- <section>受到伤害(减免后):<span class="tak">${player.stats?.heroDamageReport?.receivedTotal.physicalDamage + player.stats?.heroDamageReport?.receivedTotal.magicalDamage + player.stats?.heroDamageReport?.receivedTotal.pureDamage}</span></section>
1578
- <section>补刀:<span class="lh">${player.numLastHits}</span>/<span class="dn">${player.numDenies}</span></section>
1579
- <section>GPM/XPM:<span class="gpm">${player.goldPerMinute}</span>/<span class="xpm">${player.experiencePerMinute}</span></section>
1580
- <section>治疗量:<span class="heal">${player.heroHealing}</span></section>
1581
- <section>控制时间:<span class="building_damage">${(player.stats?.heroDamageReport?.dealtTotal.stunDuration / 100).toFixed(2)}/${(player.stats?.heroDamageReport?.dealtTotal.slowDuration / 100).toFixed(2)}/${(player.stats?.heroDamageReport?.dealtTotal.disableDuration / 100).toFixed(2)}</span>s</section>
1582
- </div>
1583
- </div>`;
1409
+ let result = "";
1410
+ ejs.renderFile(templatePath, data, (err, html) => {
1411
+ if (err)
1412
+ throw err;
1413
+ else
1414
+ result = html;
1584
1415
  });
1585
- $(".radiant_players").html(players_html.radiant);
1586
- $(".dire_players").html(players_html.dire);
1587
- $(".ban_list").html(
1588
- match.pickBans.filter((hero) => !hero.isPick).map((hero) => `<div class="ban_hero"><img src="${getImageUrl(/^npc_dota_hero_(?<name>.+)$/.exec(dotaconstants3.heroes[hero.bannedHeroId].name)[1], "heroes" /* Heroes */)}" alt="" /></div>`).join("")
1589
- );
1590
1416
  if (process.env.NODE_ENV === "development")
1591
- import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.html", $.html());
1592
- return $.html();
1417
+ import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.html", result);
1418
+ return result;
1593
1419
  }
1594
- __name(genMatchImageHTML, "genMatchImageHTML");
1420
+ __name(newGenMatchImageHTML, "newGenMatchImageHTML");
1595
1421
  function genHeroHTML(hero) {
1596
1422
  let $ = cheerio.load(import_fs2.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/hero.html`, "utf-8"));
1597
1423
  let html = `
@@ -1832,18 +1658,13 @@ function genPlayerHTML(player) {
1832
1658
  (outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.tie / 2) / (outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.tie + outcomeCounts.fail + outcomeCounts.stomped)
1833
1659
  )};">${((outcomeCounts.victory + outcomeCounts.stomp) / (outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.fail + outcomeCounts.stomped) * 100).toFixed(2)}%</span></span></p>
1834
1660
  </div>
1835
- ${player.steamAccount.seasonRank ? `
1836
1661
  <div class="rank">
1837
1662
  <img class="medal" src="${getImageUrl(
1838
- "medal_" + (player.steamAccount.seasonLeaderboardRank ? player.steamAccount.seasonLeaderboardRank <= 100 ? player.steamAccount.seasonLeaderboardRank <= 10 ? "8c" : "8b" : player.steamAccount.seasonRank.toString().split("")[0] : player.steamAccount.seasonRank.toString().split("")[0])
1663
+ "medal_" + ((player.steamAccount.seasonLeaderboardRank ? player.steamAccount.seasonLeaderboardRank <= 100 ? player.steamAccount.seasonLeaderboardRank <= 10 ? "8c" : "8b" : player.steamAccount.seasonRank?.toString().split("")[0] : player.steamAccount.seasonRank?.toString().split("")[0]) ?? "0")
1839
1664
  )}" alt="" />
1840
- ${!player.steamAccount.seasonLeaderboardRank ? `
1841
- <img class="star" src="${getImageUrl("star_" + player.steamAccount.seasonRank.toString().split("")[1])}" alt="" />` : `
1842
- <p>${player.steamAccount.seasonLeaderboardRank}</p>`}
1843
- </div>` : `
1844
- <div class="rank">
1845
- <img class="medal" src="${getImageUrl("medal_0")}" alt="" />
1846
- </div>`}`;
1665
+ <img class="star" src="${getImageUrl("star_" + (player.steamAccount.seasonRank?.toString().split("")[1] ?? "0"))}" alt="" />
1666
+ <p>${player.steamAccount.seasonLeaderboardRank ?? ""}</p>
1667
+ </div>`;
1847
1668
  const heroesCountPixels = 800 - ($(".tip:not(.row):not(.win_count):not(.lose_count)").length + 1) * 40;
1848
1669
  const highestCountsTotal = {
1849
1670
  winCount: Math.max(...player.heroesPerformanceTop10.map((hero) => hero.winCount)),
@@ -1955,13 +1776,21 @@ function winRateColor(value) {
1955
1776
  return `#${toHex(red)}${toHex(green)}${toHex(blue)}`;
1956
1777
  }
1957
1778
  __name(winRateColor, "winRateColor");
1958
- function sanitizeHTML(strings, ...values) {
1959
- return strings.reduce((result, string, i) => {
1960
- let value = values[i] ?? "--";
1961
- return result + string + (i < values.length ? value : "");
1962
- }, "");
1779
+ function formatNumber(num) {
1780
+ return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
1781
+ }
1782
+ __name(formatNumber, "formatNumber");
1783
+ function readDirectoryFilesSync(directoryPath) {
1784
+ try {
1785
+ const files = import_fs2.default.readdirSync(directoryPath);
1786
+ const fileNames = files.map((file) => import_path.default.basename(file, import_path.default.extname(file)));
1787
+ return fileNames;
1788
+ } catch (error) {
1789
+ console.error("Error reading directory:", error);
1790
+ return [];
1791
+ }
1963
1792
  }
1964
- __name(sanitizeHTML, "sanitizeHTML");
1793
+ __name(readDirectoryFilesSync, "readDirectoryFilesSync");
1965
1794
  // Annotate the CommonJS export names for ESM import in node:
1966
1795
  0 && (module.exports = {
1967
1796
  Config,