@sjtdev/koishi-plugin-dota2tracker 2.0.4 → 2.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 (2) hide show
  1. package/lib/index.js +44 -31
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -780,7 +780,7 @@ var require_en_US_schema = __commonJS({
780
780
  // src/locales/en-US.template.yml
781
781
  var require_en_US_template = __commonJS({
782
782
  "src/locales/en-US.template.yml"(exports2, module2) {
783
- module2.exports = { dota2tracker: { template: { radiant: "Radiant", dire: "Dire", won: "Won", lost: "Lost", match_id_: "Match ID: {0}", game_mode_: "Mode: {0}", start_time_: "Start Time: {0}", end_time_: "End Time: {0}", pick_order: "#{0}", random: "R", hero_damage_: "Damage: {0}", building_damage_: "Building: {0}", damage_received_: "Received: {0}", lasthit_: "LastHit: {0}", deny_: "Deny: {0}", "lh/dn_": "LH/DN: {0}", GPM: "GPM", XPM: "XPM", heal_: "Heal: {0}", crowd_control_duration_: "CCD: {0}", "GPM/XPM_": "GPM/XPM: {0}", lane: "Lane", lane_: "Lane: ", lane_advantage: "Lane +", lane_disadvantage: "Lane -", lane_jungle: "Jungle", lane_stomp: "Lane+++", lane_stomped: "Lane---", lane_tie: "Lane ==", analysis_successful: "Analysis successful", analysis_incomplete: "Analysis incomplete", kill: "Kill", kill_contribution_: "KC: {0}", position: "Position", position_: "Position: ", position_1: "Carry", position_2: "Mid", position_3: "OffLane", position_4: "Softsup", position_5: "Hardsup", dire_won: "Dire Won", radiant_won: "Radiant Won", total_damage: "Damage", total_experience: "Exp.", total_gold: "Gold", region_: "Region: {0}", duration_: "Duration: {0}", position_undefined: "?", top10_: "Top 10 Heroes by Matches: ", match_count_: "Matches: ", last25matches_: "Last 25 Matches: ", winrate_: "Winrate: ", imp_: "IMP: ", lane_advantage_rate_: "Lane Advantage Rate: ", hero: "Hero", all_matches_: "All Matches: ", match_count: "Matches", winrate: "Winrate", imp: "IMP", win_count: "Wins", lose_count: "Losses", recently_heroes: "Heroes used more than once recently: ", recently_positions: "Performance in the last 25 matches across all positions: ", winning_streak: "Winning Streak", losing_streak: "Losing Streak", id: "ID", mode: "Mode", kda_kc: "KDA(KC)", time: "Time", duration: "Duration", rank: "Rank", un_parsed: "(Unparsed)", combined_win_loss_summary: "Combined Win/Loss Summary: ", yesterdays_summary: "Yesterday's Summary", last_weeks_summary: "Last Week's Summary", report_won: "W", report_lost: "L", report_winrate: "WR", anonymous_player_1: "This profile is private.", anonymous_player_2: "Background is for display purposes only. It is not {player}’s data.", rank_fun_down_message: "{avatar}<br/>Sad", rank_fun_up_message: "Hip hip hooray! Our awesome member {avatar}{name} has leveled up from {prev} to {curr}!", titles: { MVP: "MVP-#FFA500", Soul: "Soul-#66CCFF", Rich: "R-#FFD700", Wise: "W-#8888FF", Controller: "C-#FF00FF", Nuker: "N-#CC0088", Breaker: "B-#DD0000", Ghost: "G-#CCCCCC", Assister: "A-#006400", Demolisher: "D-#FEDCBA", Healer: "H-#00FF00", Tank: "T-#84A1C7", Idle: "I-#DDDDDD" }, situation: "Situation", networth: "Net Worth", experience: "Experience", OUTCOME_MAP: { RADIANT_VICTORY: "RADIANT VICTORY", RADIANT_STOMP: "RADIANT STOMP", DIRE_VICTORY: "DIRE VICTORY", DIRE_STOMP: "DIRE STOMP", TIE: "TIE" }, lane_top: "Top", lane_mid: "Mid", lane_bottom: "Bottom", empty_extra_info: "No extra info" } } };
783
+ module2.exports = { dota2tracker: { template: { radiant: "Radiant", dire: "Dire", won: "Won", lost: "Lost", match_id_: "Match ID: {0}", game_mode_: "Mode: {0}", start_time_: "Start Time: {0}", end_time_: "End Time: {0}", pick_order: "#{0}", random: "R", hero_damage_: "Damage: {0}", building_damage_: "Building: {0}", damage_received_: "Received: {0}", lasthit_: "LastHit: {0}", deny_: "Deny: {0}", "lh/dn_": "LH/DN: {0}", GPM: "GPM", XPM: "XPM", heal_: "Heal: {0}", crowd_control_duration_: "CCD: {0}", "GPM/XPM_": "GPM/XPM: {0}", lane: "Lane", lane_: "Lane: ", lane_advantage: "Lane +", lane_disadvantage: "Lane -", lane_jungle: "Jungle", lane_stomp: "Lane+++", lane_stomped: "Lane---", lane_tie: "Lane ==", analysis_successful: "Analysis successful", analysis_incomplete: "Analysis incomplete", kill: "Kill", kill_contribution_: "KC: {0}", position: "Position", position_: "Position: ", position_1: "Carry", position_2: "Mid", position_3: "OffLane", position_4: "Softsup", position_5: "Hardsup", dire_won: "Dire Won", radiant_won: "Radiant Won", total_damage: "Damage", total_experience: "Exp.", total_gold: "Gold", region_: "Region: {0}", duration_: "Duration: {0}", position_undefined: "?", top10_: "Top 10 Heroes by Matches: ", match_count_: "Matches: ", last25matches_: "Last 25 Matches: ", winrate_: "Winrate: ", imp_: "IMP: ", lane_advantage_rate_: "Lane Advantage Rate: ", hero: "Hero", all_matches_: "All Matches: ", match_count: "Matches", winrate: "Winrate", imp: "IMP", win_count: "Wins", lose_count: "Losses", recently_heroes: "Heroes used more than once recently: ", recently_positions: "Performance in the last 25 matches across all positions: ", winning_streak: "Winning Streak", losing_streak: "Losing Streak", id: "ID", mode: "Mode", kda_kc: "KDA(KC)", time: "Time", duration: "Duration", rank: "Rank", un_parsed: "(Unparsed)", combined_win_loss_summary: "Combined Win/Loss Summary: ", yesterdays_summary: "Yesterday's Summary", last_weeks_summary: "Last Week's Summary", report_won: "W", report_lost: "L", report_winrate: "WR", anonymous_player_1: "This profile is private.", anonymous_player_2: "Background is for display purposes only. It is not {player}’s data.", rank_fun_down_message: "{avatar}<br/>Sad", rank_fun_up_message: "Hip hip hooray! Our awesome member {avatar}{name} has leveled up from {prev} to {curr}!", titles: { MVP: "MVP-#FFA500", Soul: "Soul-#66CCFF", Rich: "R-#FFD700", Wise: "W-#8888FF", Controller: "C-#FF00FF", Nuker: "N-#CC0088", Breaker: "B-#DD0000", Ghost: "G-#CCCCCC", Utility: "U-#20B2AA", Assister: "A-#006400", Demolisher: "D-#FEDCBA", Healer: "H-#00FF00", Tank: "T-#84A1C7", Idle: "I-#DDDDDD" }, situation: "Situation", networth: "Net Worth", experience: "Experience", OUTCOME_MAP: { RADIANT_VICTORY: "RADIANT VICTORY", RADIANT_STOMP: "RADIANT STOMP", DIRE_VICTORY: "DIRE VICTORY", DIRE_STOMP: "DIRE STOMP", TIE: "TIE" }, lane_top: "Top", lane_mid: "Mid", lane_bottom: "Bottom", empty_extra_info: "No extra info" } } };
784
784
  }
785
785
  });
786
786
 
@@ -808,7 +808,7 @@ var require_zh_CN_schema = __commonJS({
808
808
  // src/locales/zh-CN.template.yml
809
809
  var require_zh_CN_template = __commonJS({
810
810
  "src/locales/zh-CN.template.yml"(exports2, module2) {
811
- module2.exports = { dota2tracker: { template: { radiant: "天辉", dire: "夜魇", won: "获胜", lost: "失败", match_id_: "比赛编号:{0}", game_mode_: "模式:{0}", start_time_: "起始时间:{0}", end_time_: "结束时间:{0}", pick_order: "第{0}手", random: "随机", hero_damage_: "英雄伤害:{0}", building_damage_: "建筑伤害:{0}", damage_received_: "受到伤害:{0}", lasthit_: "补刀:{0}", deny_: "反补:{0}", "lh/dn_": "补刀:{0}/{1}", GPM: "GPM", XPM: "XPM", heal_: "治疗量:{0}", crowd_control_duration_: "控制时间:{0}", "GPM/XPM_": "GPM/XPM:{0}", lane: "对线", lane_: "对线:", lane_advantage: "对线优势", lane_disadvantage: "对线劣势", lane_stomp: "对线碾压", lane_stomped: "对线被碾", lane_tie: "对线平手", lane_jungle: "野区霸主", analysis_successful: "录像分析成功", analysis_incomplete: "分析结果不完整", kill: "击杀", kill_contribution_: "参战率:{0}", position: "位置", position_: "位置:", position_1: "优势路", position_2: "中路", position_3: "烈士路", position_4: "采灵芝", position_5: "工具人", position_undefined: "?", total_damage: "总伤害", total_gold: "总经济", total_experience: "总经验", radiant_won: "天辉获胜", dire_won: "夜魇获胜", duration_: "持续时间:{0}", region_: "地区:{0}", match_count_: "场次:", last25matches_: "最近25场:", winrate_: "胜率:", imp_: "表现:", lane_advantage_rate_: "线优率:", top10_: "全期场次前十的英雄:", hero: "英雄", all_matches_: "全期场次:", match_count: "场次", winrate: "胜率", imp: "表现", win_count: "胜场", lose_count: "败场", recently_heroes: "近期使用场次大于1的英雄:", recently_positions: "近25场各个位置的表现:", winning_streak: "连胜", losing_streak: "连败", id: "ID", mode: "模式", kda_kc: "KDA(参战率)", time: "时间", duration: "时长", rank: "段位", un_parsed: "(未解析)", combined_win_loss_summary: "组合胜负情况:", yesterdays_summary: "昨日总结", last_weeks_summary: "上周总结", report_won: "胜", report_lost: "负", report_winrate: "胜率", anonymous_player_1: "数据未公开", anonymous_player_2: "背景仅供展示目的,不属于{player}的数据。", rank_fun_up_message: "热烈祝贺群友 {avatar}{name} 在天梯中再获进步,<br/>由 {prev} 升为 {curr},再接再厉,再创辉煌!", rank_fun_down_message: "{avatar}<br/>寄", titles: { MVP: "MVP-#FFA500", Soul: "魂-#66CCFF", Rich: "富-#FFD700", Wise: "睿-#8888FF", Controller: "控-#FF00FF", Nuker: "爆-#CC0088", Breaker: "破-#DD0000", Ghost: "鬼-#CCCCCC", Assister: "助-#006400", Demolisher: "拆-#FEDCBA", Healer: "奶-#00FF00", Tank: "耐-#84A1C7", Idle: "摸-#DDDDDD" }, situation: "局势", networth: "经济", experience: "经验", OUTCOME_MAP: { RADIANT_VICTORY: "天辉优势", RADIANT_STOMP: "天辉碾压", DIRE_VICTORY: "夜魇优势", DIRE_STOMP: "夜魇碾压", TIE: "势均力敌" }, lane_top: "上路", lane_mid: "中路", lane_bottom: "下路", empty_extra_info: "比赛未解析或信息缺失,无法展示更多数据。" } } };
811
+ module2.exports = { dota2tracker: { template: { radiant: "天辉", dire: "夜魇", won: "获胜", lost: "失败", match_id_: "比赛编号:{0}", game_mode_: "模式:{0}", start_time_: "起始时间:{0}", end_time_: "结束时间:{0}", pick_order: "第{0}手", random: "随机", hero_damage_: "英雄伤害:{0}", building_damage_: "建筑伤害:{0}", damage_received_: "受到伤害:{0}", lasthit_: "补刀:{0}", deny_: "反补:{0}", "lh/dn_": "补刀:{0}/{1}", GPM: "GPM", XPM: "XPM", heal_: "治疗量:{0}", crowd_control_duration_: "控制时间:{0}", "GPM/XPM_": "GPM/XPM:{0}", lane: "对线", lane_: "对线:", lane_advantage: "对线优势", lane_disadvantage: "对线劣势", lane_stomp: "对线碾压", lane_stomped: "对线被碾", lane_tie: "对线平手", lane_jungle: "野区霸主", analysis_successful: "录像分析成功", analysis_incomplete: "分析结果不完整", kill: "击杀", kill_contribution_: "参战率:{0}", position: "位置", position_: "位置:", position_1: "优势路", position_2: "中路", position_3: "烈士路", position_4: "采灵芝", position_5: "工具人", position_undefined: "?", total_damage: "总伤害", total_gold: "总经济", total_experience: "总经验", radiant_won: "天辉获胜", dire_won: "夜魇获胜", duration_: "持续时间:{0}", region_: "地区:{0}", match_count_: "场次:", last25matches_: "最近25场:", winrate_: "胜率:", imp_: "表现:", lane_advantage_rate_: "线优率:", top10_: "全期场次前十的英雄:", hero: "英雄", all_matches_: "全期场次:", match_count: "场次", winrate: "胜率", imp: "表现", win_count: "胜场", lose_count: "败场", recently_heroes: "近期使用场次大于1的英雄:", recently_positions: "近25场各个位置的表现:", winning_streak: "连胜", losing_streak: "连败", id: "ID", mode: "模式", kda_kc: "KDA(参战率)", time: "时间", duration: "时长", rank: "段位", un_parsed: "(未解析)", combined_win_loss_summary: "组合胜负情况:", yesterdays_summary: "昨日总结", last_weeks_summary: "上周总结", report_won: "胜", report_lost: "负", report_winrate: "胜率", anonymous_player_1: "数据未公开", anonymous_player_2: "背景仅供展示目的,不属于{player}的数据。", rank_fun_up_message: "热烈祝贺群友 {avatar}{name} 在天梯中再获进步,<br/>由 {prev} 升为 {curr},再接再厉,再创辉煌!", rank_fun_down_message: "{avatar}<br/>寄", titles: { MVP: "MVP-#FFA500", Soul: "魂-#66CCFF", Rich: "富-#FFD700", Wise: "睿-#8888FF", Controller: "控-#FF00FF", Nuker: "爆-#CC0088", Breaker: "破-#DD0000", Ghost: "鬼-#CCCCCC", Utility: "辅-#20B2AA", Assister: "助-#006400", Demolisher: "拆-#FEDCBA", Healer: "奶-#00FF00", Tank: "耐-#84A1C7", Idle: "摸-#DDDDDD" }, situation: "局势", networth: "经济", experience: "经验", OUTCOME_MAP: { RADIANT_VICTORY: "天辉优势", RADIANT_STOMP: "天辉碾压", DIRE_VICTORY: "夜魇优势", DIRE_STOMP: "夜魇碾压", TIE: "势均力敌" }, lane_top: "上路", lane_mid: "中路", lane_bottom: "下路", empty_extra_info: "比赛未解析或信息缺失,无法展示更多数据。" } } };
812
812
  }
813
813
  });
814
814
 
@@ -1292,7 +1292,7 @@ var ItemService = class _ItemService extends import_koishi3.Service {
1292
1292
  }
1293
1293
  static getFormattedItemListData(rawItems) {
1294
1294
  const processItemName = /* @__PURE__ */ __name((name2) => name2.replace(/^item_/i, "").replace(/^recipe_/i, "recipe_"), "processItemName");
1295
- const [recipes, items] = rawItems.reduce(
1295
+ const [recipes, items2] = rawItems.reduce(
1296
1296
  (acc, item) => {
1297
1297
  const processed = {
1298
1298
  ...item,
@@ -1306,14 +1306,14 @@ var ItemService = class _ItemService extends import_koishi3.Service {
1306
1306
  [[], []]
1307
1307
  );
1308
1308
  const itemMap = /* @__PURE__ */ new Map();
1309
- items.concat(recipes).forEach(
1309
+ items2.concat(recipes).forEach(
1310
1310
  (item) => itemMap.set(item.id, {
1311
1311
  id: item.id,
1312
1312
  name: item.name,
1313
1313
  name_loc: item.name_loc
1314
1314
  })
1315
1315
  );
1316
- const processedItems = items.map((baseItem) => {
1316
+ const processedItems = items2.map((baseItem) => {
1317
1317
  const recipe = recipes.find((r) => r.name === `recipe_${baseItem.name.replace("item_", "")}`);
1318
1318
  return {
1319
1319
  ...baseItem,
@@ -1346,19 +1346,19 @@ var ItemService = class _ItemService extends import_koishi3.Service {
1346
1346
  }))
1347
1347
  }));
1348
1348
  }
1349
- searchItems(items, keyword, languageTag, config) {
1349
+ searchItems(items2, keyword, languageTag, config) {
1350
1350
  if (!keyword) return [];
1351
1351
  const alias = this.ctx.dota2tracker.i18n.getConstantLocale(languageTag).dota2tracker.items_alias?.[keyword] ?? config.customItemAlias.filter((cia) => cia.alias == keyword).map((cia) => cia.keyword);
1352
- const exactMatch = items.filter(
1352
+ const exactMatch = items2.filter(
1353
1353
  (item) => alias?.some((a) => item.name_loc.trim().toLowerCase() == a.toLowerCase()) || item.name_loc.trim().toLowerCase() === keyword.trim().toLowerCase() || Number.isInteger(Number(keyword)) && item.id === Number(keyword)
1354
1354
  );
1355
1355
  if (exactMatch.length) return exactMatch;
1356
- return this.fuzzySearchItems(alias.length ? alias : [keyword], items);
1356
+ return this.fuzzySearchItems(alias.length ? alias : [keyword], items2);
1357
1357
  }
1358
- fuzzySearchItems(keywords, items) {
1358
+ fuzzySearchItems(keywords, items2) {
1359
1359
  const resultMap = /* @__PURE__ */ new Map();
1360
1360
  if (!keywords.length) return [];
1361
- for (const item of items) {
1361
+ for (const item of items2) {
1362
1362
  const cleanName = item.name_loc.toLowerCase().replace(/[^\p{L}\p{N}]/gu, "").trim();
1363
1363
  let matchAllKeywords = true;
1364
1364
  for (const keyword of keywords) {
@@ -1397,7 +1397,7 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1397
1397
  async getMatchResult({ matchId, requestParse }) {
1398
1398
  const matchQuery = await this.getMatchData(matchId);
1399
1399
  if (matchQuery) {
1400
- if (!this.isMatchParsed(matchQuery) && requestParse && this.ctx.cron) {
1400
+ if (!_MatchService.isMatchParsed(matchQuery) && requestParse && this.ctx.cron) {
1401
1401
  return {
1402
1402
  status: "PENDING",
1403
1403
  matchId
@@ -1424,7 +1424,7 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1424
1424
  this.ctx.dota2tracker.cache.setMatchCache(matchId, matchQuery, this.pluginVersion);
1425
1425
  } else {
1426
1426
  matchQuery = await this.ctx.dota2tracker.stratzAPI.queryMatchInfo(matchId);
1427
- if (this.isMatchParsed(matchQuery)) {
1427
+ if (_MatchService.isMatchParsed(matchQuery)) {
1428
1428
  this.ctx.dota2tracker.cache.setMatchCache(matchId, matchQuery, this.pluginVersion);
1429
1429
  }
1430
1430
  }
@@ -1471,10 +1471,11 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1471
1471
  // 对比赛数据进行补充以供生成模板函数使用
1472
1472
  static extendMatchData(matchQuery, facetData) {
1473
1473
  const match = matchQuery.match;
1474
+ const matchParsed = _MatchService.isMatchParsed(matchQuery);
1474
1475
  ["radiant", "dire"].forEach((team) => {
1475
1476
  match[team] = { killsCount: match?.[team + "Kills"]?.reduce((acc, cva) => acc + cva, 0) ?? 0, damageReceived: 0, heroDamage: 0, networth: 0, experience: 0 };
1476
1477
  });
1477
- if (!match.parsedDateTime) {
1478
+ if (!matchParsed) {
1478
1479
  match.players.reduce((acc, player) => {
1479
1480
  if (player.isRadiant) {
1480
1481
  acc.radiant.killsCount += player.kills;
@@ -1524,9 +1525,6 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1524
1525
  match[player.team].damageReceived = (match[player.team].damageReceived ?? 0) + player.damageReceived;
1525
1526
  match[player.team].networth += player.networth;
1526
1527
  match[player.team].experience += Math.floor(player.experiencePerMinute / 60 * match.durationSeconds);
1527
- player.titles = [];
1528
- player.mvpScore = // 计算MVP分数
1529
- player.kills * 5 + player.assists * 3 + (player.stats.heroDamageReport?.dealtTotal.stunDuration ?? 0) / 100 * 0.1 + (player.stats.heroDamageReport?.dealtTotal.disableDuration ?? 0) / 100 * 0.05 + (player.stats.heroDamageReport?.dealtTotal.slowDuration ?? 0) / 100 * 0.025 + player.heroDamage * 1e-3 + player.towerDamage * 0.01 + player.heroHealing * 2e-3 + player.imp * 0.25;
1530
1528
  player.order = heroOrderList[player.hero.id];
1531
1529
  if (player.partyId != null) {
1532
1530
  if (!match.party[player.partyId]) match.party[player.partyId] = party_mark[party_index++];
@@ -1565,28 +1563,40 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1565
1563
  player.laneResult = laneResult.mid[player.team];
1566
1564
  break;
1567
1565
  }
1568
- const supportItemIds = [30, 40, 42, 43, 188];
1569
- const supportItemsCount = supportItemIds.reduce((obj, key) => {
1566
+ player.utilityScore = (player.stats?.campStack?.at(-1) || 0) * 100;
1567
+ const utilityItemIds = [
1568
+ 30,
1569
+ // 真视宝石
1570
+ 40,
1571
+ // 显影之尘
1572
+ 42,
1573
+ // 侦查守卫 (假眼)
1574
+ 43,
1575
+ // 岗哨守卫 (真眼)
1576
+ 188
1577
+ // 诡计之雾
1578
+ ];
1579
+ const supportItemsCount = utilityItemIds.reduce((obj, key) => {
1570
1580
  obj[key] = 0;
1571
1581
  return obj;
1572
1582
  }, {});
1573
1583
  const purchaseTimesMap = {};
1574
1584
  if (player.stats?.itemPurchases) {
1575
1585
  for (const item of player.stats.itemPurchases) {
1576
- if (!supportItemIds.includes(item.itemId)) {
1586
+ if (!utilityItemIds.includes(item.itemId)) {
1577
1587
  if (!purchaseTimesMap[item.itemId]) {
1578
1588
  purchaseTimesMap[item.itemId] = [];
1579
1589
  }
1580
1590
  purchaseTimesMap[item.itemId].push(item.time);
1581
- }
1582
- switch (item.itemId) {
1583
- case 30:
1584
- case 40:
1585
- case 42:
1586
- case 43:
1587
- case 188:
1588
- supportItemsCount[item.itemId]++;
1589
- break;
1591
+ } else {
1592
+ const itemName = dotaconstants3.item_ids[item.itemId];
1593
+ if (itemName) {
1594
+ const itemDetails = dotaconstants3.items[itemName];
1595
+ if (itemDetails && itemDetails.cost) {
1596
+ player.utilityScore += itemDetails.cost;
1597
+ }
1598
+ }
1599
+ supportItemsCount[item.itemId]++;
1590
1600
  }
1591
1601
  }
1592
1602
  }
@@ -1627,6 +1637,9 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1627
1637
  }
1628
1638
  player.formattedNetworth = formatNumber(player.networth);
1629
1639
  player.facet = facetData[player.steamAccountId];
1640
+ player.titles = [];
1641
+ player.mvpScore = // 计算MVP分数
1642
+ player.kills * 5 + player.assists * 3 + (player.stats.heroDamageReport?.dealtTotal.stunDuration ?? 0) / 100 * 0.1 + (player.stats.heroDamageReport?.dealtTotal.disableDuration ?? 0) / 100 * 0.05 + (player.stats.heroDamageReport?.dealtTotal.slowDuration ?? 0) / 100 * 0.025 + player.heroDamage * 1e-3 + player.towerDamage * 0.01 + player.heroHealing * 2e-3 + player.imp * 0.25 + player.utilityScore * 5e-3;
1630
1643
  });
1631
1644
  let ComparisonMode;
1632
1645
  ((ComparisonMode2) => {
@@ -1659,7 +1672,7 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1659
1672
  )?.titles.push("dota2tracker.template.titles.Soul");
1660
1673
  findMaxByProperty("networth")?.titles.push("dota2tracker.template.titles.Rich");
1661
1674
  findMaxByProperty("experiencePerMinute")?.titles.push("dota2tracker.template.titles.Wise");
1662
- if (match.parsedDateTime && match.players.every((player) => player?.stats?.heroDamageReport?.dealtTotal)) {
1675
+ if (matchParsed) {
1663
1676
  match.players.reduce(
1664
1677
  (max, player) => player.stats.heroDamageReport.dealtTotal.stunDuration + player.stats.heroDamageReport.dealtTotal.disableDuration / 2 + player.stats.heroDamageReport.dealtTotal.slowDuration / 4 > max.stats.heroDamageReport.dealtTotal.stunDuration + max.stats.heroDamageReport.dealtTotal.disableDuration / 2 + max.stats.heroDamageReport.dealtTotal.slowDuration / 4 ? player : max
1665
1678
  ).titles.push("dota2tracker.template.titles.Controller");
@@ -1670,6 +1683,7 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1670
1683
  findMaxByProperty("heroDamage")?.titles.push("dota2tracker.template.titles.Nuker");
1671
1684
  findMaxByProperty("kills", "heroDamage")?.titles.push("dota2tracker.template.titles.Breaker");
1672
1685
  findMaxByProperty("deaths", "networth", void 0, void 0, "min" /* Min */)?.titles.push("dota2tracker.template.titles.Ghost");
1686
+ if (matchParsed) findMaxByProperty("utilityScore", "networth", match.players, "max" /* Max */, "min" /* Min */)?.titles.push("dota2tracker.template.titles.Utility");
1673
1687
  findMaxByProperty("assists", "heroDamage")?.titles.push("dota2tracker.template.titles.Assister");
1674
1688
  findMaxByProperty("towerDamage", "heroDamage")?.titles.push("dota2tracker.template.titles.Demolisher");
1675
1689
  findMaxByProperty("heroHealing")?.titles.push("dota2tracker.template.titles.Healer");
@@ -1692,7 +1706,7 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1692
1706
  match.durationTime = sec2time(match.durationSeconds);
1693
1707
  return match;
1694
1708
  }
1695
- isMatchParsed(match) {
1709
+ static isMatchParsed(match) {
1696
1710
  return match.match?.parsedDateTime && match.match.players.filter((player) => player?.stats?.heroDamageReport?.dealtTotal).length > 0;
1697
1711
  }
1698
1712
  };
@@ -2196,7 +2210,6 @@ function handleError(error, logger, i18n, config) {
2196
2210
  } else if (error instanceof NetworkError) {
2197
2211
  if (config.suppressStratzNetworkErrors) {
2198
2212
  logger.debug(error);
2199
- logger.info(1);
2200
2213
  } else {
2201
2214
  logger.error(error);
2202
2215
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sjtdev/koishi-plugin-dota2tracker",
3
3
  "description": "koishi插件-追踪群友的DOTA2对局",
4
- "version": "2.0.4",
4
+ "version": "2.1.0",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [