@sjtdev/koishi-plugin-dota2tracker 2.3.1 → 2.3.2

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,5 +1,19 @@
1
1
  # 更新日志
2
2
 
3
+ ### [2.3.2](https://github.com/sjtdev/koishi-plugin-dota2tracker/compare/v2.3.1...v2.3.2) (2025-12-18)
4
+
5
+ ### 🚀 功能优化
6
+
7
+ * **templates/match_2+:** 更换至`7.40`版地图,并调整了建筑坐标使位置更合理;修复了部分近战/远程兵营位置错乱的问题。 ([cb88644](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/cb88644d0f519d44bc983f975d62c8aea33879eb))
8
+
9
+ ### 🐛 Bug 修复
10
+
11
+ * **locale:** 补充新英雄在`本地化`词典中的词条。 ([8a72813](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/8a728134e15ca1f570d06dd8c215c25fcab23286))
12
+
13
+ ### 📝 文档
14
+
15
+ * 更新图片构建、补充对`match_2+`的说明。 ([9193c21](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/9193c21981c5ced74f6c759c82f137871efd163c))
16
+
3
17
  ### [2.3.1](https://github.com/sjtdev/koishi-plugin-dota2tracker/compare/v2.3.0...v2.3.1) (2025-12-17)
4
18
 
5
19
  ### 🐛 Bug 修复
package/lib/index.js CHANGED
@@ -789,7 +789,7 @@ var require_en_US_template = __commonJS({
789
789
  // src/locales/en-US.yml
790
790
  var require_en_US = __commonJS({
791
791
  "src/locales/en-US.yml"(exports2, module2) {
792
- module2.exports = { dota2tracker: { heroes_nicknames: { "0": 'Please strictly follow the format of "", "" when filling out, if the format is incorrect, only the default name of the hero will be used. The default name of the hero may be omitted.', "1": '"Anti-Mage"', "2": '"Axe"', "3": '"Bane"', "4": '"Bloodseeker"', "5": '"Crystal Maiden"', "6": '"Drow Ranger"', "7": '"Earthshaker"', "8": '"Juggernaut"', "9": '"Mirana"', "10": '"Morphling"', "11": '"Shadow Fiend"', "12": '"Phantom Lancer"', "13": '"Puck"', "14": '"Pudge"', "15": '"Razor"', "16": '"Sand King"', "17": '"Storm Spirit"', "18": '"Sven"', "19": '"Tiny"', "20": '"Vengeful Spirit"', "21": '"Windranger"', "22": '"Zeus"', "23": '"Kunkka"', "25": '"Lina"', "26": '"Lion"', "27": '"Shadow Shaman"', "28": '"Slardar"', "29": '"Tidehunter"', "30": '"Witch Doctor"', "31": '"Lich"', "32": '"Riki"', "33": '"Enigma"', "34": '"Tinker"', "35": '"Sniper"', "36": '"Necrophos"', "37": '"Warlock"', "38": '"Beastmaster"', "39": '"Queen of Pain"', "40": '"Venomancer"', "41": '"Faceless Void"', "42": '"Wraith King"', "43": '"Death Prophet"', "44": '"Phantom Assassin"', "45": '"Pugna"', "46": '"Templar Assassin"', "47": '"Viper"', "48": '"Luna"', "49": '"Dragon Knight"', "50": '"Dazzle"', "51": '"Clockwerk"', "52": '"Leshrac"', "53": `"Nature's Prophet"`, "54": '"Lifestealer"', "55": '"Dark Seer"', "56": '"Clinkz"', "57": '"Omniknight"', "58": '"Enchantress"', "59": '"Huskar"', "60": '"Night Stalker"', "61": '"Broodmother"', "62": '"Bounty Hunter"', "63": '"Weaver"', "64": '"Jakiro"', "65": '"Batrider"', "66": '"Chen"', "67": '"Spectre"', "68": '"Ancient Apparition"', "69": '"Doom"', "70": '"Ursa"', "71": '"Spirit Breaker"', "72": '"Gyrocopter"', "73": '"Alchemist"', "74": '"Invoker"', "75": '"Silencer"', "76": '"Outworld Devourer"', "77": '"Lycan"', "78": '"Brewmaster"', "79": '"Shadow Demon"', "80": '"Lone Druid"', "81": '"Chaos Knight"', "82": '"Meepo"', "83": '"Treant Protector"', "84": '"Ogre Magi"', "85": '"Undying"', "86": '"Rubick"', "87": '"Disruptor"', "88": '"Nyx Assassin"', "89": '"Naga Siren"', "90": '"Keeper of the Light"', "91": '"Io"', "92": '"Visage"', "93": '"Slark"', "94": '"Medusa"', "95": '"Troll Warlord"', "96": '"Centaur Warrunner"', "97": '"Magnus"', "98": '"Timbersaw"', "99": '"Bristleback"', "100": '"Tusk"', "101": '"Skywrath Mage"', "102": '"Abaddon"', "103": '"Elder Titan"', "104": '"Legion Commander"', "105": '"Techies"', "106": '"Ember Spirit"', "107": '"Earth Spirit"', "108": '"Underlord"', "109": '"Terrorblade"', "110": '"Phoenix"', "111": '"Oracle"', "112": '"Winter Wyvern"', "113": '"Arc Warden"', "114": '"Monkey King"', "119": '"Dark Willow"', "120": '"Pangolier"', "121": '"Grimstroke"', "123": '"Hoodwink"', "126": '"Void Spirit"', "128": '"Snapfire"', "129": '"Mars"', "131": '"Ring Master"', "135": '"Dawnbreaker"', "136": '"Marci"', "137": '"Primal Beast"', "138": '"Muerta"', "145": '"Kez"' }, broadcast: { WIN_NEGATIVE: `"Won the match by sheer luck", "Won the match by a stroke of bad luck", "Coasted to victory", "Didn't even show up for the team fight, but my teammates won 4v5"`, WIN_POSITIVE: '"Led the team to victory", "Dominated the opponents and secured the win", "Carried the game to victory", "Treated the opponents like pigs and won", "Won again; this game is just so monotonous and dull", "Simply achieved a win in the match"', LOSE_NEGATIVE: '"Got crushed and lost the match", "Lost the match miserably", "Got my head knocked sideways and lost the match with a blown mindset", "Went fishing but got eaten by the fish, lost the match", "Played terribly", "Simply suffered a loss in the match"', LOSE_POSITIVE: `"Lost the match with no way to turn it around", "Gave it my all, but still lost the match", "Though we lost, we still have honor", "Couldn't carry my teammates, lost the match", "Lost again, it hurts; I'd rather it be me losing"`, message: "{name}'s {hero_name} {comment}.\nKDA: {kda}, GPM/XPM: {gpm_xpm}, Last Hits/Denies: {lh_dn}, Damage/Tower Damage: {damage}, Kill/Death Contribution Rate: {kc_dc}", rank_changed: "Player {name} rank changed: {prev.medal} {prev.star} → {curr.medal} {curr.star}" }, logger: { fetch_guilds_failed: "Failed to fetch guild information.", match_tracked: "Tracked new match {match.id} from {#each messageToLogger as item}users in guild {item.platform}:{item.guildId} [{#each item.players as player}{player.nickname}({player.steamId}){#if player !== item.players[item.players.length - 1]}, {/if}{/each}]{#if item !== messageToLogger[messageToLogger.length - 1]}, {/if}{/each}.", parse_request_sent: "The parsing request for match {matchId} has been successfully sent to the STRATZ server.", parse_request_failed: "The parsing request for match {matchId} failed to send.", match_parsed: "Match {matchId} has been parsed{#if odParsed} by OpenDota{/if}, an image was generated and published to {#each guilds as guild}{guild.platform}:{guild.guildId}{#if guild !== guilds[guilds.length - 1]}, {/if}{/each}.", match_unparsed: "Match {matchId} exceeded the waiting time [{timeout}] and remains unparsed, an image was generated and published to {#each guilds as guild}{guild.platform}:{guild.guildId}{#if guild !== guilds[guilds.length - 1]}, {/if}{/each}.", waiting_for_parse: "Match {matchId} has not been parsed yet, has been waiting for {time} minutes.", report_sent: "Posted {title} on {platform}:{guildId}.", rank_sent: "Posted rank change information of {player.nickName} ({player.steamId}) on {platform}:{guildId}.", ejs_error: "Error rendering EJS template: {error}", cron_not_enabled: "Cron service is not enabled; match report tracking cannot run.", stratz_token_banned: "Stratz API request rejected (403). This usually means your token or IP has been temporarily restricted due to unusual activity. For details, see the documentation: http://sjtdev.github.io/koishi-plugin-dota2tracker/en-US/api-403.html", opendota_token_banned: "OpenDota API request rejected (403). Please check if the access limit has been exceeded.", stratz_api_query_error: "Stratz API returned partial data with errors: {cause}", opendota_parse_request_sent: "Parse request for match {matchId} has been sent to OpenDota servers successfully.", opendota_parse_request_failed: "Failed to send parse request for match {matchId} to OpenDota servers." }, time: { years_months_ago: "{years} years and {months} months ago", years_ago: "{years} years ago" } } };
792
+ module2.exports = { dota2tracker: { heroes_nicknames: { "0": 'Please strictly follow the format of "", "" when filling out, if the format is incorrect, only the default name of the hero will be used. The default name of the hero may be omitted.', "1": '"Anti-Mage"', "2": '"Axe"', "3": '"Bane"', "4": '"Bloodseeker"', "5": '"Crystal Maiden"', "6": '"Drow Ranger"', "7": '"Earthshaker"', "8": '"Juggernaut"', "9": '"Mirana"', "10": '"Morphling"', "11": '"Shadow Fiend"', "12": '"Phantom Lancer"', "13": '"Puck"', "14": '"Pudge"', "15": '"Razor"', "16": '"Sand King"', "17": '"Storm Spirit"', "18": '"Sven"', "19": '"Tiny"', "20": '"Vengeful Spirit"', "21": '"Windranger"', "22": '"Zeus"', "23": '"Kunkka"', "25": '"Lina"', "26": '"Lion"', "27": '"Shadow Shaman"', "28": '"Slardar"', "29": '"Tidehunter"', "30": '"Witch Doctor"', "31": '"Lich"', "32": '"Riki"', "33": '"Enigma"', "34": '"Tinker"', "35": '"Sniper"', "36": '"Necrophos"', "37": '"Warlock"', "38": '"Beastmaster"', "39": '"Queen of Pain"', "40": '"Venomancer"', "41": '"Faceless Void"', "42": '"Wraith King"', "43": '"Death Prophet"', "44": '"Phantom Assassin"', "45": '"Pugna"', "46": '"Templar Assassin"', "47": '"Viper"', "48": '"Luna"', "49": '"Dragon Knight"', "50": '"Dazzle"', "51": '"Clockwerk"', "52": '"Leshrac"', "53": `"Nature's Prophet"`, "54": '"Lifestealer"', "55": '"Dark Seer"', "56": '"Clinkz"', "57": '"Omniknight"', "58": '"Enchantress"', "59": '"Huskar"', "60": '"Night Stalker"', "61": '"Broodmother"', "62": '"Bounty Hunter"', "63": '"Weaver"', "64": '"Jakiro"', "65": '"Batrider"', "66": '"Chen"', "67": '"Spectre"', "68": '"Ancient Apparition"', "69": '"Doom"', "70": '"Ursa"', "71": '"Spirit Breaker"', "72": '"Gyrocopter"', "73": '"Alchemist"', "74": '"Invoker"', "75": '"Silencer"', "76": '"Outworld Devourer"', "77": '"Lycan"', "78": '"Brewmaster"', "79": '"Shadow Demon"', "80": '"Lone Druid"', "81": '"Chaos Knight"', "82": '"Meepo"', "83": '"Treant Protector"', "84": '"Ogre Magi"', "85": '"Undying"', "86": '"Rubick"', "87": '"Disruptor"', "88": '"Nyx Assassin"', "89": '"Naga Siren"', "90": '"Keeper of the Light"', "91": '"Io"', "92": '"Visage"', "93": '"Slark"', "94": '"Medusa"', "95": '"Troll Warlord"', "96": '"Centaur Warrunner"', "97": '"Magnus"', "98": '"Timbersaw"', "99": '"Bristleback"', "100": '"Tusk"', "101": '"Skywrath Mage"', "102": '"Abaddon"', "103": '"Elder Titan"', "104": '"Legion Commander"', "105": '"Techies"', "106": '"Ember Spirit"', "107": '"Earth Spirit"', "108": '"Underlord"', "109": '"Terrorblade"', "110": '"Phoenix"', "111": '"Oracle"', "112": '"Winter Wyvern"', "113": '"Arc Warden"', "114": '"Monkey King"', "119": '"Dark Willow"', "120": '"Pangolier"', "121": '"Grimstroke"', "123": '"Hoodwink"', "126": '"Void Spirit"', "128": '"Snapfire"', "129": '"Mars"', "131": '"Ring Master"', "135": '"Dawnbreaker"', "136": '"Marci"', "137": '"Primal Beast"', "138": '"Muerta"', "145": '"Kez"', "155": '"Largo"' }, broadcast: { WIN_NEGATIVE: `"Won the match by sheer luck", "Won the match by a stroke of bad luck", "Coasted to victory", "Didn't even show up for the team fight, but my teammates won 4v5"`, WIN_POSITIVE: '"Led the team to victory", "Dominated the opponents and secured the win", "Carried the game to victory", "Treated the opponents like pigs and won", "Won again; this game is just so monotonous and dull", "Simply achieved a win in the match"', LOSE_NEGATIVE: '"Got crushed and lost the match", "Lost the match miserably", "Got my head knocked sideways and lost the match with a blown mindset", "Went fishing but got eaten by the fish, lost the match", "Played terribly", "Simply suffered a loss in the match"', LOSE_POSITIVE: `"Lost the match with no way to turn it around", "Gave it my all, but still lost the match", "Though we lost, we still have honor", "Couldn't carry my teammates, lost the match", "Lost again, it hurts; I'd rather it be me losing"`, message: "{name}'s {hero_name} {comment}.\nKDA: {kda}, GPM/XPM: {gpm_xpm}, Last Hits/Denies: {lh_dn}, Damage/Tower Damage: {damage}, Kill/Death Contribution Rate: {kc_dc}", rank_changed: "Player {name} rank changed: {prev.medal} {prev.star} → {curr.medal} {curr.star}" }, logger: { fetch_guilds_failed: "Failed to fetch guild information.", match_tracked: "Tracked new match {match.id} from {#each messageToLogger as item}users in guild {item.platform}:{item.guildId} [{#each item.players as player}{player.nickname}({player.steamId}){#if player !== item.players[item.players.length - 1]}, {/if}{/each}]{#if item !== messageToLogger[messageToLogger.length - 1]}, {/if}{/each}.", parse_request_sent: "The parsing request for match {matchId} has been successfully sent to the STRATZ server.", parse_request_failed: "The parsing request for match {matchId} failed to send.", match_parsed: "Match {matchId} has been parsed{#if odParsed} by OpenDota{/if}, an image was generated and published to {#each guilds as guild}{guild.platform}:{guild.guildId}{#if guild !== guilds[guilds.length - 1]}, {/if}{/each}.", match_unparsed: "Match {matchId} exceeded the waiting time [{timeout}] and remains unparsed, an image was generated and published to {#each guilds as guild}{guild.platform}:{guild.guildId}{#if guild !== guilds[guilds.length - 1]}, {/if}{/each}.", waiting_for_parse: "Match {matchId} has not been parsed yet, has been waiting for {time} minutes.", report_sent: "Posted {title} on {platform}:{guildId}.", rank_sent: "Posted rank change information of {player.nickName} ({player.steamId}) on {platform}:{guildId}.", ejs_error: "Error rendering EJS template: {error}", cron_not_enabled: "Cron service is not enabled; match report tracking cannot run.", stratz_token_banned: "Stratz API request rejected (403). This usually means your token or IP has been temporarily restricted due to unusual activity. For details, see the documentation: http://sjtdev.github.io/koishi-plugin-dota2tracker/en-US/api-403.html", opendota_token_banned: "OpenDota API request rejected (403). Please check if the access limit has been exceeded.", stratz_api_query_error: "Stratz API returned partial data with errors: {cause}", opendota_parse_request_sent: "Parse request for match {matchId} has been sent to OpenDota servers successfully.", opendota_parse_request_failed: "Failed to send parse request for match {matchId} to OpenDota servers." }, time: { years_months_ago: "{years} years and {months} months ago", years_ago: "{years} years ago" } } };
793
793
  }
794
794
  });
795
795
 
@@ -817,7 +817,7 @@ var require_zh_CN_template = __commonJS({
817
817
  // src/locales/zh-CN.yml
818
818
  var require_zh_CN = __commonJS({
819
819
  "src/locales/zh-CN.yml"(exports2, module2) {
820
- module2.exports = { dota2tracker: { heroes_nicknames: { "0": '请严格遵循 "", "" 格式填写(如下方默认数据,注意是英文半角符号),如果格式有误将仅使用英雄默认名称。可以不包含英雄默认名称。', "1": '"敌法师", "敌法", "AM"', "2": '"斧王"', "3": '"祸乱之源", "祸乱", "水桶腰"', "4": '"血魔"', "5": '"水晶室女", "冰女", "CM"', "6": '"卓尔游侠", "小黑"', "7": '"撼地者", "小牛", "牛头"', "8": '"主宰", "剑圣", "jugg", "奶棒人"', "9": '"米拉娜", "白虎", "pom"', "10": '"变体精灵", "水人"', "11": '"影魔", "影魔王", "SF", "影儿魔儿"', "12": '"幻影长矛手", "PL"', "13": '"帕克"', "14": '"帕吉", "屠夫", "扒鸡", "啪唧"', "15": '"雷泽", "电魂", "电棍"', "16": '"沙王", "SK"', "17": '"风暴之灵", "蓝猫"', "18": '"斯温", "流浪剑客", "流浪"', "19": '"小小"', "20": '"复仇之魂", "复仇", "VS"', "21": '"风行者", "风行", "WR"', "22": '"宙斯"', "23": '"昆卡", "船长"', "25": '"莉娜", "火女"', "26": '"莱恩", "恶魔巫师", "Lion"', "27": '"暗影萨满", "小Y", "小歪"', "28": '"斯拉达", "大鱼", "大鱼人"', "29": '"潮汐猎人", "潮汐", "西瓜皮"', "30": '"巫医"', "31": '"巫妖"', "32": '"力丸", "隐形刺客", "隐刺"', "33": '"谜团"', "34": '"修补匠", "TK", "Tinker"', "35": '"狙击手", "矮人火枪手", "火枪", "传说哥"', "36": '"瘟疫法师", "死灵法", "NEC"', "37": '"术士", "Warlock"', "38": '"兽王"', "39": '"痛苦女王", "女王", "QOP"', "40": '"剧毒术士", "剧毒"', "41": '"虚空假面", "虚空", "JB脸"', "42": '"冥魂大帝", "骷髅王"', "43": '"死亡先知", "DP"', "44": '"幻影刺客", "幻刺", "PA"', "45": '"帕格纳", "骨法", "湮灭法师"', "46": '"圣堂刺客", "圣堂", "TA"', "47": '"冥界亚龙", "毒龙", "Viper"', "48": '"露娜", "月骑", "Luna"', "49": '"龙骑士", "龙骑"', "50": '"戴泽", "暗影牧师", "暗牧"', "51": '"发条技师", "发条"', "52": '"拉席克", "老鹿"', "53": '"先知"', "54": '"噬魂鬼", "小狗"', "55": '"黑暗贤者", "黑贤"', "56": '"克林克兹", "小骷髅"', "57": '"全能骑士", "全能"', "58": '"魅惑魔女", "小鹿"', "59": '"哈斯卡", "神灵", "神灵武士"', "60": '"暗夜魔王", "夜魔"', "61": '"育母蜘蛛", "蜘蛛"', "62": '"赏金猎人", "赏金"', "63": '"编织者", "蚂蚁"', "64": '"杰奇洛", "双头龙"', "65": '"蝙蝠骑士", "蝙蝠"', "66": '"陈", "老陈"', "67": '"幽鬼", "SPE", "UG"', "68": '"远古冰魄", "冰魂"', "69": '"末日使者", "末日", "Doom"', "70": '"熊战士", "拍拍", "拍拍熊"', "71": '"裂魂人", "白牛", "sb"', "72": '"矮人直升机", "飞机"', "73": '"炼金术士", "炼金"', "74": '"祈求者", "卡尔"', "75": '"沉默术士", "沉默"', "76": '"殁境神蚀者", "黑鸟"', "77": '"狼人"', "78": '"酒仙", "熊猫", "熊猫酒仙"', "79": '"暗影恶魔", "毒狗"', "80": '"德鲁伊", "熊德"', "81": '"混沌骑士", "混沌", "CK"', "82": '"米波"', "83": '"树精卫士", "大树", "树精"', "84": '"食人魔魔法师", "蓝胖"', "85": '"不朽尸王", "尸王"', "86": '"拉比克"', "87": '"干扰者", "萨尔"', "88": '"司夜刺客", "小强"', "89": '"娜迦海妖", "小娜迦"', "90": '"光之守卫", "光法"', "91": '"艾欧", "小精灵", "精灵", "IO"', "92": '"维萨吉", "死灵龙", "死灵飞龙"', "93": '"斯拉克", "小鱼", "小鱼人"', "94": '"美杜莎", "一姐", "美杜莎"', "95": '"巨魔战将", "巨魔", "巨馍蘸酱"', "96": '"半人马战行者", "人马", "半人马"', "97": '"马格纳斯", "猛犸"', "98": '"伐木机", "花母鸡"', "99": '"钢背兽", "钢背"', "100": '"巨牙海民", "海民"', "101": '"天怒法师", "天怒"', "102": '"亚巴顿"', "103": '"上古巨神", "大牛"', "104": '"军团指挥官", "军团"', "105": '"工程师", "炸弹", "炸弹人"', "106": '"灰烬之灵", "火猫"', "107": '"大地之灵", "土猫"', "108": '"孽主", "大屁股"', "109": '"恐怖利刃", "TB"', "110": '"凤凰", "烧鸡"', "111": '"神谕者", "神谕"', "112": '"寒冬飞龙", "冰龙"', "113": '"天穹守望者", "电狗"', "114": '"齐天大圣", "大圣"', "119": '"邪影芳灵", "小仙女", "花仙子"', "120": '"石鳞剑士", "滚滚"', "121": '"天涯墨客", "墨客"', "123": '"森海飞霞", "松鼠", "小松鼠", "小松许"', "126": '"虚无之灵", "紫猫"', "128": '"电炎绝手", "老奶奶"', "129": '"玛尔斯"', "131": '"百戏大王"', "135": '"破晓辰星", "大锤"', "136": '"玛西"', "137": '"獸", "畜"', "138": '"琼英碧灵", "奶绿", "绿奶奶"', "145": '"凯", "鸟人"' }, broadcast: { WIN_NEGATIVE: '"侥幸赢得了比赛", "走狗屎运赢得了比赛", "躺赢了比赛", "打团都没来, 队友4V5赢得了比赛"', WIN_POSITIVE: '"带领团队走向了胜利", "暴打对面后赢得了胜利", " CARRY全场赢得了胜利", "把对面当猪宰了, 赢得了胜利", "又赢了, 这游戏就是这么枯燥, 且乏味", "直接进行一个比赛的赢"', LOSE_NEGATIVE: '"被人按在地上摩擦, 输掉了这场比赛", "悲惨地输掉了比赛", "头都被打歪了, 心态爆炸地输掉了比赛", "捕鱼被鱼吃了, 输掉了比赛", "打的是个几把", "直接进行一个比赛的输"', LOSE_POSITIVE: '"无力回天输掉了比赛", "尽力了, 但还是输了比赛", "背靠世界树, 虽败犹荣", "带不动队友, 输了比赛", "又输了, 很难受, 宁愿输的是我"', message: "{name}的{hero_name}{comment}。\nKDA:{kda},GPM/XPM:{gpm_xpm},补刀/反补:{lh_dn},伤害/塔伤:{damage},参战/参葬率:{kc_dc}", rank_changed: "群友 {name} 段位变动:{prev.medal}{prev.star} → {curr.medal}{curr.star}" }, logger: { fetch_guilds_failed: "获取群组信息失败,将继续后续步骤。", match_tracked: "追踪到最新比赛 {match.id} 来自{#each messageToLogger as item}群组 {item.platform}:{item.guildId} 的玩家 [{#each item.players as player}{player.nickname}({player.steamId}){#if player !== item.players[item.players.length - 1]}、{/if}{/each}]{#if item !== messageToLogger[messageToLogger.length - 1]}、{/if}{/each}。", parse_request_sent: "比赛 {matchId} 解析请求已成功发送至STRATZ服务器。", parse_request_failed: "比赛 {matchId} 解析请求发送失败。", match_parsed: "比赛 {matchId} 已{#if odParsed}由 OpenDota {/if}解析,生成图片并发布于{#each guilds as guild}{guild.platform}:{guild.guildId}{#if guild !== guilds[guilds.length - 1]}、{/if}{/each}。", match_unparsed: "比赛 {matchId} 超过等待时间[{timeout}分钟]仍未解析,生成图片并发布于{#each guilds as guild}{guild.platform}:{guild.guildId}{#if guild !== guilds[guilds.length - 1]}、{/if}{/each}。", waiting_for_parse: "比赛 {matchId} 尚未解析完成,已等待{time}分钟。", report_sent: "发布{title}于{platform}:{guildId}。", rank_sent: "向{platform}:{guildId}发布{player.nickName}({player.steamId})的段位变动信息。", ejs_error: "EJS模板渲染错误:{error}", cron_not_enabled: "未启用cron服务,无法运行战报追踪等定时任务。", stratz_token_banned: "Stratz API 请求被拒绝(403),若频繁发生很有可能意味着您的Token或IP因异常使用被临时限制访问。有关此报错请见文档:http://sjtdev.github.io/koishi-plugin-dota2tracker/api-403.html", opendota_token_banned: "OpenDota API 请求被拒绝(403),请注意访问次数是否超限。", stratz_api_query_error: "Stratz API 返回了有效数据,但同时也返回了查询报错。错误信息: {cause}", opendota_parse_request_sent: "比赛 {matchId} 解析请求已成功发送至 OpenDota 服务器。", opendota_parse_request_failed: "比赛 {matchId} 解析请求向 OpenDota 服务器发送失败。" }, time: { years_months_ago: "{years}年{months}个月前", years_ago: "{years}年前" } } };
820
+ module2.exports = { dota2tracker: { heroes_nicknames: { "0": '请严格遵循 "", "" 格式填写(如下方默认数据,注意是英文半角符号),如果格式有误将仅使用英雄默认名称。可以不包含英雄默认名称。', "1": '"敌法师", "敌法", "AM"', "2": '"斧王"', "3": '"祸乱之源", "祸乱", "水桶腰"', "4": '"血魔"', "5": '"水晶室女", "冰女", "CM"', "6": '"卓尔游侠", "小黑"', "7": '"撼地者", "小牛", "牛头"', "8": '"主宰", "剑圣", "jugg", "奶棒人"', "9": '"米拉娜", "白虎", "pom"', "10": '"变体精灵", "水人"', "11": '"影魔", "影魔王", "SF", "影儿魔儿"', "12": '"幻影长矛手", "PL"', "13": '"帕克"', "14": '"帕吉", "屠夫", "扒鸡", "啪唧"', "15": '"雷泽", "电魂", "电棍"', "16": '"沙王", "SK"', "17": '"风暴之灵", "蓝猫"', "18": '"斯温", "流浪剑客", "流浪"', "19": '"小小"', "20": '"复仇之魂", "复仇", "VS"', "21": '"风行者", "风行", "WR"', "22": '"宙斯"', "23": '"昆卡", "船长"', "25": '"莉娜", "火女"', "26": '"莱恩", "恶魔巫师", "Lion"', "27": '"暗影萨满", "小Y", "小歪"', "28": '"斯拉达", "大鱼", "大鱼人"', "29": '"潮汐猎人", "潮汐", "西瓜皮"', "30": '"巫医"', "31": '"巫妖"', "32": '"力丸", "隐形刺客", "隐刺"', "33": '"谜团"', "34": '"修补匠", "TK", "Tinker"', "35": '"狙击手", "矮人火枪手", "火枪", "传说哥"', "36": '"瘟疫法师", "死灵法", "NEC"', "37": '"术士", "Warlock"', "38": '"兽王"', "39": '"痛苦女王", "女王", "QOP"', "40": '"剧毒术士", "剧毒"', "41": '"虚空假面", "虚空", "JB脸"', "42": '"冥魂大帝", "骷髅王"', "43": '"死亡先知", "DP"', "44": '"幻影刺客", "幻刺", "PA"', "45": '"帕格纳", "骨法", "湮灭法师"', "46": '"圣堂刺客", "圣堂", "TA"', "47": '"冥界亚龙", "毒龙", "Viper"', "48": '"露娜", "月骑", "Luna"', "49": '"龙骑士", "龙骑"', "50": '"戴泽", "暗影牧师", "暗牧"', "51": '"发条技师", "发条"', "52": '"拉席克", "老鹿"', "53": '"先知"', "54": '"噬魂鬼", "小狗"', "55": '"黑暗贤者", "黑贤"', "56": '"克林克兹", "小骷髅"', "57": '"全能骑士", "全能"', "58": '"魅惑魔女", "小鹿"', "59": '"哈斯卡", "神灵", "神灵武士"', "60": '"暗夜魔王", "夜魔"', "61": '"育母蜘蛛", "蜘蛛"', "62": '"赏金猎人", "赏金"', "63": '"编织者", "蚂蚁"', "64": '"杰奇洛", "双头龙"', "65": '"蝙蝠骑士", "蝙蝠"', "66": '"陈", "老陈"', "67": '"幽鬼", "SPE", "UG"', "68": '"远古冰魄", "冰魂"', "69": '"末日使者", "末日", "Doom"', "70": '"熊战士", "拍拍", "拍拍熊"', "71": '"裂魂人", "白牛", "sb"', "72": '"矮人直升机", "飞机"', "73": '"炼金术士", "炼金"', "74": '"祈求者", "卡尔"', "75": '"沉默术士", "沉默"', "76": '"殁境神蚀者", "黑鸟"', "77": '"狼人"', "78": '"酒仙", "熊猫", "熊猫酒仙"', "79": '"暗影恶魔", "毒狗"', "80": '"德鲁伊", "熊德"', "81": '"混沌骑士", "混沌", "CK"', "82": '"米波"', "83": '"树精卫士", "大树", "树精"', "84": '"食人魔魔法师", "蓝胖"', "85": '"不朽尸王", "尸王"', "86": '"拉比克"', "87": '"干扰者", "萨尔"', "88": '"司夜刺客", "小强"', "89": '"娜迦海妖", "小娜迦"', "90": '"光之守卫", "光法"', "91": '"艾欧", "小精灵", "精灵", "IO"', "92": '"维萨吉", "死灵龙", "死灵飞龙"', "93": '"斯拉克", "小鱼", "小鱼人"', "94": '"美杜莎", "一姐", "美杜莎"', "95": '"巨魔战将", "巨魔", "巨馍蘸酱"', "96": '"半人马战行者", "人马", "半人马"', "97": '"马格纳斯", "猛犸"', "98": '"伐木机", "花母鸡"', "99": '"钢背兽", "钢背"', "100": '"巨牙海民", "海民"', "101": '"天怒法师", "天怒"', "102": '"亚巴顿"', "103": '"上古巨神", "大牛"', "104": '"军团指挥官", "军团"', "105": '"工程师", "炸弹", "炸弹人"', "106": '"灰烬之灵", "火猫"', "107": '"大地之灵", "土猫"', "108": '"孽主", "大屁股"', "109": '"恐怖利刃", "TB"', "110": '"凤凰", "烧鸡"', "111": '"神谕者", "神谕"', "112": '"寒冬飞龙", "冰龙"', "113": '"天穹守望者", "电狗"', "114": '"齐天大圣", "大圣"', "119": '"邪影芳灵", "小仙女", "花仙子"', "120": '"石鳞剑士", "滚滚"', "121": '"天涯墨客", "墨客"', "123": '"森海飞霞", "松鼠", "小松鼠", "小松许"', "126": '"虚无之灵", "紫猫"', "128": '"电炎绝手", "老奶奶"', "129": '"玛尔斯"', "131": '"百戏大王"', "135": '"破晓辰星", "大锤"', "136": '"玛西"', "137": '"獸", "畜"', "138": '"琼英碧灵", "奶绿", "绿奶奶"', "145": '"凯", "鸟人"', "155": '"朗戈"' }, broadcast: { WIN_NEGATIVE: '"侥幸赢得了比赛", "走狗屎运赢得了比赛", "躺赢了比赛", "打团都没来, 队友4V5赢得了比赛"', WIN_POSITIVE: '"带领团队走向了胜利", "暴打对面后赢得了胜利", " CARRY全场赢得了胜利", "把对面当猪宰了, 赢得了胜利", "又赢了, 这游戏就是这么枯燥, 且乏味", "直接进行一个比赛的赢"', LOSE_NEGATIVE: '"被人按在地上摩擦, 输掉了这场比赛", "悲惨地输掉了比赛", "头都被打歪了, 心态爆炸地输掉了比赛", "捕鱼被鱼吃了, 输掉了比赛", "打的是个几把", "直接进行一个比赛的输"', LOSE_POSITIVE: '"无力回天输掉了比赛", "尽力了, 但还是输了比赛", "背靠世界树, 虽败犹荣", "带不动队友, 输了比赛", "又输了, 很难受, 宁愿输的是我"', message: "{name}的{hero_name}{comment}。\nKDA:{kda},GPM/XPM:{gpm_xpm},补刀/反补:{lh_dn},伤害/塔伤:{damage},参战/参葬率:{kc_dc}", rank_changed: "群友 {name} 段位变动:{prev.medal}{prev.star} → {curr.medal}{curr.star}" }, logger: { fetch_guilds_failed: "获取群组信息失败,将继续后续步骤。", match_tracked: "追踪到最新比赛 {match.id} 来自{#each messageToLogger as item}群组 {item.platform}:{item.guildId} 的玩家 [{#each item.players as player}{player.nickname}({player.steamId}){#if player !== item.players[item.players.length - 1]}、{/if}{/each}]{#if item !== messageToLogger[messageToLogger.length - 1]}、{/if}{/each}。", parse_request_sent: "比赛 {matchId} 解析请求已成功发送至STRATZ服务器。", parse_request_failed: "比赛 {matchId} 解析请求发送失败。", match_parsed: "比赛 {matchId} 已{#if odParsed}由 OpenDota {/if}解析,生成图片并发布于{#each guilds as guild}{guild.platform}:{guild.guildId}{#if guild !== guilds[guilds.length - 1]}、{/if}{/each}。", match_unparsed: "比赛 {matchId} 超过等待时间[{timeout}分钟]仍未解析,生成图片并发布于{#each guilds as guild}{guild.platform}:{guild.guildId}{#if guild !== guilds[guilds.length - 1]}、{/if}{/each}。", waiting_for_parse: "比赛 {matchId} 尚未解析完成,已等待{time}分钟。", report_sent: "发布{title}于{platform}:{guildId}。", rank_sent: "向{platform}:{guildId}发布{player.nickName}({player.steamId})的段位变动信息。", ejs_error: "EJS模板渲染错误:{error}", cron_not_enabled: "未启用cron服务,无法运行战报追踪等定时任务。", stratz_token_banned: "Stratz API 请求被拒绝(403),若频繁发生很有可能意味着您的Token或IP因异常使用被临时限制访问。有关此报错请见文档:http://sjtdev.github.io/koishi-plugin-dota2tracker/api-403.html", opendota_token_banned: "OpenDota API 请求被拒绝(403),请注意访问次数是否超限。", stratz_api_query_error: "Stratz API 返回了有效数据,但同时也返回了查询报错。错误信息: {cause}", opendota_parse_request_sent: "比赛 {matchId} 解析请求已成功发送至 OpenDota 服务器。", opendota_parse_request_failed: "比赛 {matchId} 解析请求向 OpenDota 服务器发送失败。" }, time: { years_months_ago: "{years}年{months}个月前", years_ago: "{years}年前" } } };
821
821
  }
822
822
  });
823
823
 
@@ -926,9 +926,14 @@ var LanguageTags = {
926
926
  "zh-CN": { graphqlTag: "S_CHINESE", valveTag: "schinese" }
927
927
  };
928
928
  var I18NService = class extends import_koishi.Service {
929
- constructor(ctx, dotaconstants) {
929
+ static {
930
+ __name(this, "I18NService");
931
+ }
932
+ constantLocales = {};
933
+ i18n;
934
+ globalLanguageTag;
935
+ constructor(ctx) {
930
936
  super(ctx, "dota2tracker.i18n", true);
931
- this.dotaconstants = dotaconstants;
932
937
  this.config = ctx.config;
933
938
  this.i18n = this.ctx.i18n;
934
939
  for (const supportLanguageTag of Object.keys(LanguageTags)) {
@@ -939,12 +944,6 @@ var I18NService = class extends import_koishi.Service {
939
944
  }
940
945
  this.globalLanguageTag = this.i18n.fallback(Object.values(this.i18n.locales).map((locale) => Object.keys(locale).at(0))).find((locale) => Object.keys(LanguageTags).includes(locale));
941
946
  }
942
- static {
943
- __name(this, "I18NService");
944
- }
945
- constantLocales = {};
946
- i18n;
947
- globalLanguageTag;
948
947
  getGraphqlLanguageTag(languageTag) {
949
948
  return LanguageTags[languageTag].graphqlTag;
950
949
  }
@@ -1050,7 +1049,7 @@ var I18NService = class extends import_koishi.Service {
1050
1049
  */
1051
1050
  _buildNicknameMap(languageTag) {
1052
1051
  this.logger.debug(`Building nickname map for ${languageTag}...`);
1053
- const heroIds = Object.keys(this.dotaconstants.heroes).map(Number);
1052
+ const heroIds = Object.keys(this.ctx.dota2tracker.dotaconstants.heroes).map(Number);
1054
1053
  const nicknameMap = /* @__PURE__ */ new Map();
1055
1054
  for (const heroId of heroIds) {
1056
1055
  const allNames = this._getAllHeroNames(heroId, languageTag);
@@ -1065,7 +1064,7 @@ var I18NService = class extends import_koishi.Service {
1065
1064
  const inputStr = String(input).toLowerCase();
1066
1065
  if (/^\d+$/.test(inputStr)) {
1067
1066
  const heroId = Number(inputStr);
1068
- if (this.dotaconstants.heroes[heroId]) {
1067
+ if (this.ctx.dota2tracker.dotaconstants.heroes[heroId]) {
1069
1068
  return heroId;
1070
1069
  }
1071
1070
  }
@@ -1099,13 +1098,12 @@ var RANK_BRACKETS = ["UNCALIBRATED", "HERALD", "GUARDIAN", "CRUSADER", "ARCHON",
1099
1098
 
1100
1099
  // src/app/core/hero.service.ts
1101
1100
  var HeroService = class _HeroService extends import_koishi2.Service {
1102
- constructor(ctx, dotaconstants) {
1103
- super(ctx, "dota2tracker.hero", true);
1104
- this.dotaconstants = dotaconstants;
1105
- }
1106
1101
  static {
1107
1102
  __name(this, "HeroService");
1108
1103
  }
1104
+ constructor(ctx) {
1105
+ super(ctx, "dota2tracker.hero", true);
1106
+ }
1109
1107
  async getWeeklyHeroMeta(rank) {
1110
1108
  const MINIMUM_PICK_RATE = 0.02;
1111
1109
  const RECOMMENDATION_COUNT = 3;
@@ -1140,7 +1138,7 @@ var HeroService = class _HeroService extends import_koishi2.Service {
1140
1138
  return weeklyHeroMeta;
1141
1139
  }
1142
1140
  async getHeroDetails(input, languageTag, isRandom = false) {
1143
- const heroId = this.ctx.dota2tracker.i18n.findHeroIdInLocale(isRandom ? import_koishi2.Random.pick(Object.keys(this.dotaconstants.heroes)) : input);
1141
+ const heroId = this.ctx.dota2tracker.i18n.findHeroIdInLocale(isRandom ? import_koishi2.Random.pick(Object.keys(this.ctx.dota2tracker.dotaconstants.heroes)) : input);
1144
1142
  if (!heroId) return;
1145
1143
  return _HeroService.formatHeroDetails(await this.ctx.dota2tracker.valveAPI.queryHeroDetailsFromValve(heroId, languageTag));
1146
1144
  }
@@ -1521,10 +1519,9 @@ __name(handleError, "handleError");
1521
1519
 
1522
1520
  // src/app/core/match.service.ts
1523
1521
  var MatchService = class _MatchService extends import_koishi4.Service {
1524
- constructor(ctx, pluginVersion, dotaconstants) {
1522
+ constructor(ctx, pluginVersion) {
1525
1523
  super(ctx, "dota2tracker.match", true);
1526
1524
  this.pluginVersion = pluginVersion;
1527
- this.dotaconstants = dotaconstants;
1528
1525
  }
1529
1526
  static {
1530
1527
  __name(this, "MatchService");
@@ -1629,7 +1626,7 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1629
1626
  }
1630
1627
  const facetData = await _MatchService.constantsInjectFacetData(constantsQuery, matchQuery, languageTag, this.ctx.dota2tracker.hero);
1631
1628
  this.ctx.dota2tracker.cache.setFacetConstantsCache(languageTag, constantsQuery);
1632
- const match = _MatchService.extendMatchData(matchQuery, facetData, this.dotaconstants);
1629
+ const match = _MatchService.extendMatchData(matchQuery, facetData, this.ctx.dota2tracker.dotaconstants);
1633
1630
  return match;
1634
1631
  } catch (error) {
1635
1632
  this.ctx.dota2tracker.cache.deleteFacetConstantsCache(languageTag);
@@ -1923,14 +1920,13 @@ __name(createItemObject, "createItemObject");
1923
1920
  var import_koishi5 = require("koishi");
1924
1921
  var import_luxon3 = require("luxon");
1925
1922
  var PlayerService = class _PlayerService extends import_koishi5.Service {
1926
- constructor(ctx, dotaconstants) {
1927
- super(ctx, "dota2tracker.player", true);
1928
- this.dotaconstants = dotaconstants;
1929
- this.config = ctx.config;
1930
- }
1931
1923
  static {
1932
1924
  __name(this, "PlayerService");
1933
1925
  }
1926
+ constructor(ctx) {
1927
+ super(ctx, "dota2tracker.player", true);
1928
+ this.config = ctx.config;
1929
+ }
1934
1930
  async getHeroRecommendation(steamId, player) {
1935
1931
  const RECENT_IMP_WEIGHT = 0.1;
1936
1932
  const LIFETIME_WIN_LOG_WEIGHT = 5;
@@ -2058,7 +2054,7 @@ var PlayerService = class _PlayerService extends import_koishi5.Service {
2058
2054
  genHero: heroId ? { heroId, name: this.ctx.dota2tracker.i18n.getConstantLocale(languageTag).dota2tracker.template.hero_names[heroId] } : null,
2059
2055
  estimateRank: this.config.playerRankEstimate
2060
2056
  },
2061
- this.dotaconstants
2057
+ this.ctx.dota2tracker.dotaconstants
2062
2058
  );
2063
2059
  return player;
2064
2060
  }
@@ -2671,16 +2667,15 @@ var ImageFormat = /* @__PURE__ */ ((ImageFormat2) => {
2671
2667
  // src/app/presentation/image.renderer.ts
2672
2668
  var import_luxon5 = require("luxon");
2673
2669
  var ImageRenderer = class extends import_koishi10.Service {
2674
- constructor(ctx, currentDir, dotaconstants) {
2675
- super(ctx, "dota2tracker.image", true);
2676
- this.dotaconstants = dotaconstants;
2677
- this.config = ctx.config;
2678
- this.templateDir = import_path2.default.join(currentDir, "templates");
2679
- }
2680
2670
  static {
2681
2671
  __name(this, "ImageRenderer");
2682
2672
  }
2683
2673
  templateDir;
2674
+ constructor(ctx, currentDir) {
2675
+ super(ctx, "dota2tracker.image", true);
2676
+ this.config = ctx.config;
2677
+ this.templateDir = import_path2.default.join(currentDir, "templates");
2678
+ }
2684
2679
  async renderToImageByFile(data, templateName, type, languageTag) {
2685
2680
  const html = await this.generateHTML(data, { source: "FILE", templateName, type }, languageTag);
2686
2681
  return this.ctx.puppeteer.render(html);
@@ -2697,7 +2692,7 @@ var ImageRenderer = class extends import_koishi10.Service {
2697
2692
  data,
2698
2693
  ImageType,
2699
2694
  ImageFormat,
2700
- dotaconstants: this.dotaconstants,
2695
+ dotaconstants: this.ctx.dota2tracker.dotaconstants,
2701
2696
  DateTime: import_luxon5.DateTime,
2702
2697
  $t: /* @__PURE__ */ __name((key, params) => this.ctx.dota2tracker.i18n.$t(languageTag, key, params), "$t"),
2703
2698
  languageTag,
@@ -3773,13 +3768,12 @@ var OpenDotaAPI = class extends import_koishi15.Service {
3773
3768
  // src/app/core/opendota.adapter.ts
3774
3769
  var import_koishi16 = require("koishi");
3775
3770
  var OpenDotaAdapter = class extends import_koishi16.Service {
3776
- constructor(ctx, dotaconstants) {
3777
- super(ctx, "dota2tracker.opendota-adapter", true);
3778
- this.dotaconstants = dotaconstants;
3779
- }
3780
3771
  static {
3781
3772
  __name(this, "OpenDotaAdapter");
3782
3773
  }
3774
+ constructor(ctx) {
3775
+ super(ctx, "dota2tracker.opendota-adapter", true);
3776
+ }
3783
3777
  transform(_match) {
3784
3778
  determinePlayerPositions(_match);
3785
3779
  const players = [];
@@ -3827,9 +3821,9 @@ var OpenDotaAdapter = class extends import_koishi16.Service {
3827
3821
  steamAccount: { name: _player.personaname, seasonRank: _player.rank_tier, seasonLeaderboardRank: null },
3828
3822
  hero: {
3829
3823
  id: _player.hero_id,
3830
- name: this.dotaconstants.heroes[_player.hero_id].name,
3831
- shortName: this.dotaconstants.heroes[_player.hero_id].name.match(/^npc_dota_hero_(.+)$/)[1],
3832
- facets: [...this.dotaconstants.hero_abilities[this.dotaconstants.heroes[_player.hero_id].name].facets.map((f) => ({ id: -1, name: f.name }))]
3824
+ name: this.ctx.dota2tracker.dotaconstants.heroes[_player.hero_id].name,
3825
+ shortName: this.ctx.dota2tracker.dotaconstants.heroes[_player.hero_id].name.match(/^npc_dota_hero_(.+)$/)[1],
3826
+ facets: [...this.ctx.dota2tracker.dotaconstants.hero_abilities[this.ctx.dota2tracker.dotaconstants.heroes[_player.hero_id].name].facets.map((f) => ({ id: -1, name: f.name }))]
3833
3827
  },
3834
3828
  dotaPlus: null,
3835
3829
  stats: {
@@ -3860,7 +3854,7 @@ var OpenDotaAdapter = class extends import_koishi16.Service {
3860
3854
  disableCount: 0
3861
3855
  }
3862
3856
  },
3863
- itemPurchases: _player.purchase_log.map((p) => ({ time: p.time, itemId: this.dotaconstants.items[p.key].id }))
3857
+ itemPurchases: _player.purchase_log.map((p) => ({ time: p.time, itemId: this.ctx.dota2tracker.dotaconstants.items[p.key].id }))
3864
3858
  },
3865
3859
  additionalUnit: null
3866
3860
  };
@@ -3889,8 +3883,8 @@ var OpenDotaAdapter = class extends import_koishi16.Service {
3889
3883
  const match = {
3890
3884
  id: _match.match_id,
3891
3885
  didRadiantWin: _match.radiant_win,
3892
- lobbyType: convertLobbyType(_match.lobby_type, this.dotaconstants),
3893
- gameMode: convertGameMode(_match.game_mode, this.dotaconstants),
3886
+ lobbyType: convertLobbyType(_match.lobby_type, this.ctx.dota2tracker.dotaconstants),
3887
+ gameMode: convertGameMode(_match.game_mode, this.ctx.dota2tracker.dotaconstants),
3894
3888
  regionId: _match.region,
3895
3889
  parsedDateTime: _match.start_time + _match.duration,
3896
3890
  startDateTime: _match.start_time,
@@ -4328,11 +4322,12 @@ async function apply(ctx, config) {
4328
4322
  const currentDir = import_path5.default.resolve(__dirname);
4329
4323
  const pluginVersion = require(import_path5.default.join(currentDir, "..", "package.json")).version;
4330
4324
  ctx.dota2tracker = {};
4331
- ctx.dota2tracker.i18n = new I18NService(ctx, dotaconstants);
4332
- ctx.dota2tracker.image = new ImageRenderer(ctx, currentDir, dotaconstants);
4325
+ ctx.dota2tracker.dotaconstants = dotaconstants;
4326
+ ctx.dota2tracker.i18n = new I18NService(ctx);
4327
+ ctx.dota2tracker.image = new ImageRenderer(ctx, currentDir);
4333
4328
  ctx.dota2tracker.messageBuilder = new MessageBuilder(ctx);
4334
- ctx.dota2tracker.match = new MatchService(ctx, pluginVersion, dotaconstants);
4335
- ctx.dota2tracker.player = new PlayerService(ctx, dotaconstants);
4329
+ ctx.dota2tracker.match = new MatchService(ctx, pluginVersion);
4330
+ ctx.dota2tracker.player = new PlayerService(ctx);
4336
4331
  if (ctx.cron) {
4337
4332
  ctx.dota2tracker.matchWatcher = new MatchWatcherTask(ctx);
4338
4333
  ctx.dota2tracker.parsePolling = new ParsePollingTask(ctx);
@@ -4344,7 +4339,7 @@ async function apply(ctx, config) {
4344
4339
  } else {
4345
4340
  logger.info(ctx.dota2tracker.i18n.gt("dota2tracker.logger.cron_not_enabled"));
4346
4341
  }
4347
- ctx.dota2tracker.hero = new HeroService(ctx, dotaconstants);
4342
+ ctx.dota2tracker.hero = new HeroService(ctx);
4348
4343
  ctx.dota2tracker.item = new ItemService(ctx);
4349
4344
  ctx.dota2tracker.cache = new CacheService(ctx);
4350
4345
  ctx.dota2tracker.database = new DatabaseService(ctx);
@@ -4352,7 +4347,7 @@ async function apply(ctx, config) {
4352
4347
  ctx.dota2tracker.stratzAPI = new StratzAPI(ctx, currentDir);
4353
4348
  if (config.enableOpenDotaFallback) {
4354
4349
  ctx.dota2tracker.opendotaAPI = new OpenDotaAPI(ctx);
4355
- ctx.dota2tracker.opendotaAdapter = new OpenDotaAdapter(ctx, dotaconstants);
4350
+ ctx.dota2tracker.opendotaAdapter = new OpenDotaAdapter(ctx);
4356
4351
  }
4357
4352
  ctx.dota2tracker = ctx.dota2tracker;
4358
4353
  usage = await ctx.dota2tracker.i18n.generateUsage();
@@ -1 +1 @@
1
- html{overflow:visible}body{display:flex;flex-direction:column;overflow:visible}#regular{width:800px}#extra{font-size:10px;width:100%;>.tip{width:100%;line-height:4;text-align:center;color:#ccc}#charts{display:flex;>*{width:50%}}.container{height:300px;display:flex;.lane_outcome{position:relative;display:flex;flex-direction:column;width:500px;margin-right:20px;>.title{width:100%;text-align:center;padding:0;margin:0;line-height:50px}.panel{display:flex;flex-direction:column;height:100%;justify-content:space-evenly;.lane{display:flex;flex-direction:column;border-radius:10px;border:#ccc solid 1px;padding:2px;>.title{width:100%;text-align:center;height:32px;>p:nth-child(1){font-size:12px}>p:nth-child(2){font-size:14px}}img.hero{width:24px;height:24px}.kda{height:100%;line-height:32px;text-align:center;font-size:10px}.graph{height:32px;display:flex;align-items:center;justify-content:center;svg{shape-rendering:crispEdges}text{dominant-baseline:middle;white-space:nowrap}}}.details{display:grid;grid-template-columns:24px 32px 44px auto 44px 32px 24px;grid-template-rows:1fr;gap:1px;font-size:12px;height:32px;line-height:32px;align-items:center}}.subtitle{position:absolute;inset:36px 0 0;text-align:center;color:#ccc;font-size:12px;margin:0;z-index:1}}.map{box-sizing:border-box;width:300px;padding:25px;font-size:8px;pointer-events:none;text-shadow:0px 1px 1px rgba(0,0,0,.8);use{&.radiant{color:#95cc4b}&.dire{color:#ca4633}&.dead{color:#555}}}}}
1
+ html{overflow:visible}body{display:flex;flex-direction:column;overflow:visible}#regular{width:800px}#extra{font-size:10px;width:100%;>.tip{width:100%;line-height:4;text-align:center;color:#ccc}#charts{display:flex;>*{width:50%}}.container{height:300px;display:flex;.lane_outcome{position:relative;display:flex;flex-direction:column;width:500px;margin-right:20px;>.title{width:100%;text-align:center;padding:0;margin:0;line-height:50px}.panel{display:flex;flex-direction:column;height:100%;justify-content:space-evenly;.lane{display:flex;flex-direction:column;border-radius:10px;border:#ccc solid 1px;padding:2px;>.title{width:100%;text-align:center;height:32px;>p:nth-child(1){font-size:12px}>p:nth-child(2){font-size:14px}}img.hero{width:24px;height:24px}.kda{height:100%;line-height:32px;text-align:center;font-size:10px}.graph{height:32px;display:flex;align-items:center;justify-content:center;svg{shape-rendering:crispEdges}text{dominant-baseline:middle;white-space:nowrap}}}.details{display:grid;grid-template-columns:24px 32px 44px auto 44px 32px 24px;grid-template-rows:1fr;gap:1px;font-size:12px;height:32px;line-height:32px;align-items:center}}.subtitle{position:absolute;inset:36px 0 0;text-align:center;color:#ccc;font-size:12px;margin:0;z-index:1}}.map{box-sizing:border-box;width:300px;padding:25px;font-size:8px;pointer-events:none;text-shadow:0px 1px 1px rgba(0,0,0,.8);image{clip-path:inset(2% round 12px);opacity:.88;object-fit:contain}use{&.radiant{color:#95cc4b}&.dire{color:#ca4633}&.dead{color:#555}}}}}
@@ -2,67 +2,67 @@
2
2
  const BUILDINGS = [
3
3
  // ================= 天辉 Radiant (左下) =================
4
4
  // 上路
5
- { id: 16, name: 'Rad Top T1', type: 'tower', lane: "top", bit: 0, team: 'radiant', x: 25, y: 93 },
6
- { id: 19, name: 'Rad Top T2', type: 'tower', lane: "top", bit: 1, team: 'radiant', x: 23, y: 135 },
7
- { id: 22, name: 'Rad Top T3', type: 'tower', lane: "top", bit: 2, team: 'radiant', x: 21, y: 174 },
8
- { id: 38, name: 'Rad Top Melee', type: 'rax', lane: "top", bit: 0, team: 'radiant', x: 18, y: 181 },
9
- { id: 41, name: 'Rad Top Range', type: 'rax', lane: "top", bit: 1, team: 'radiant', x: 26, y: 181 },
10
- { id: 38, name: 'Rad Top HG Time', type: 'rax_time', lane: "top", bit: 0, team: 'radiant', x: 27, y: 184 },
5
+ { id: 16, name: 'Rad Top T1', type: 'tower', lane: "top", bit: 0, team: 'radiant', x: 35.8, y: 96.5 },
6
+ { id: 19, name: 'Rad Top T2', type: 'tower', lane: "top", bit: 1, team: 'radiant', x: 33.7, y: 133.8 },
7
+ { id: 22, name: 'Rad Top T3', type: 'tower', lane: "top", bit: 2, team: 'radiant', x: 32.5, y: 168.4 },
8
+ { id: 38, name: 'Rad Top Melee', type: 'rax', lane: "top", bit: 0, team: 'radiant', x: 36.8, y: 174.5 },
9
+ { id: 41, name: 'Rad Top Range', type: 'rax', lane: "top", bit: 1, team: 'radiant', x: 30, y: 174.5 },
10
+ { id: 38, name: 'Rad Top HG Time', type: 'rax_time', lane: "top", bit: 0, team: 'radiant', x: 38.6, y: 180 },
11
11
 
12
12
  // 中路
13
- { id: 17, name: 'Rad Mid T1', type: 'tower', lane: "mid", bit: 3, team: 'radiant', x: 98, y: 143 },
14
- { id: 20, name: 'Rad Mid T2', type: 'tower', lane: "mid", bit: 4, team: 'radiant', x: 73, y: 166 },
15
- { id: 23, name: 'Rad Mid T3', type: 'tower', lane: "mid", bit: 5, team: 'radiant', x: 51, y: 185 },
16
- { id: 39, name: 'Rad Mid Melee', type: 'rax', lane: "mid", bit: 2, team: 'radiant', x: 46, y: 187 },
17
- { id: 42, name: 'Rad Mid Range', type: 'rax', lane: "mid", bit: 3, team: 'radiant', x: 52, y: 193 },
18
- { id: 39, name: 'Rad Mid HG Time', type: 'rax_time', lane: "mid", bit: 2, team: 'radiant', x: 54, y: 194 },
13
+ { id: 17, name: 'Rad Mid T1', type: 'tower', lane: "mid", bit: 3, team: 'radiant', x: 101.2, y: 141 },
14
+ { id: 20, name: 'Rad Mid T2', type: 'tower', lane: "mid", bit: 4, team: 'radiant', x: 78.7, y: 161.8 },
15
+ { id: 23, name: 'Rad Mid T3', type: 'tower', lane: "mid", bit: 5, team: 'radiant', x: 59, y: 178.3 },
16
+ { id: 39, name: 'Rad Mid Melee', type: 'rax', lane: "mid", bit: 2, team: 'radiant', x: 59.8, y: 185.1 },
17
+ { id: 42, name: 'Rad Mid Range', type: 'rax', lane: "mid", bit: 3, team: 'radiant', x: 54.5, y: 180.5 },
18
+ { id: 39, name: 'Rad Mid HG Time', type: 'rax_time', lane: "mid", bit: 2, team: 'radiant', x: 64, y: 187 },
19
19
 
20
20
  // 下路
21
- { id: 18, name: 'Rad Bot T1', type: 'tower', lane: "bot", bit: 6, team: 'radiant', x: 197, y: 217 },
22
- { id: 21, name: 'Rad Bot T2', type: 'tower', lane: "bot", bit: 7, team: 'radiant', x: 116, y: 218 },
23
- { id: 24, name: 'Rad Bot T3', type: 'tower', lane: "bot", bit: 8, team: 'radiant', x: 61, y: 215 },
24
- { id: 40, name: 'Rad Bot Melee', type: 'rax', lane: "bot", bit: 4, team: 'radiant', x: 58, y: 220 },
25
- { id: 43, name: 'Rad Bot Range', type: 'rax', lane: "bot", bit: 5, team: 'radiant', x: 58, y: 212 },
26
- { id: 40, name: 'Rad Bot HG Time', type: 'rax_time', lane: "bot", bit: 4, team: 'radiant', x: 61, y: 220 },
21
+ { id: 18, name: 'Rad Bot T1', type: 'tower', lane: "bot", bit: 6, team: 'radiant', x: 189.3, y: 206.2 },
22
+ { id: 21, name: 'Rad Bot T2', type: 'tower', lane: "bot", bit: 7, team: 'radiant', x: 117.5, y: 207.2 },
23
+ { id: 24, name: 'Rad Bot T3', type: 'tower', lane: "bot", bit: 8, team: 'radiant', x: 68.7, y: 205 },
24
+ { id: 40, name: 'Rad Bot Melee', type: 'rax', lane: "bot", bit: 4, team: 'radiant', x: 65, y: 210 },
25
+ { id: 43, name: 'Rad Bot Range', type: 'rax', lane: "bot", bit: 5, team: 'radiant', x: 65, y: 202.7 },
26
+ { id: 40, name: 'Rad Bot HG Time', type: 'rax_time', lane: "bot", bit: 4, team: 'radiant', x: 70, y: 211 },
27
27
 
28
28
  // 门牙 & 基地
29
- { id: 25, name: 'Rad T4 Left', type: 'tower', lane: "mid", bit: 9, team: 'radiant', x: 34, y: 197 },
30
- { id: 25, name: 'Rad T4 Right', type: 'tower', lane: "mid", bit: 10, team: 'radiant', x: 39, y: 201 },
31
- { id: 25, name: 'Rad T4 Time', type: 't4_time', lane: "mid", bit: [9,10], team: 'radiant', x: 43, y: 204 },
32
- { id: 50, name: 'Rad Ancient', type: 'fort', lane: "", bit: -1, team: 'radiant', x: 29, y: 202 },
33
- { id: 50, name: 'Rad Ancient Time', type: 'fort_time', lane: "", bit: -1, team: 'radiant', x: 35, y: 213 },
29
+ { id: 25, name: 'Rad T4 Left', type: 'tower', lane: "mid", bit: 9, team: 'radiant', x: 44.7, y: 188.7 },
30
+ { id: 25, name: 'Rad T4 Right', type: 'tower', lane: "mid", bit: 10, team: 'radiant', x: 50, y: 193.1 },
31
+ { id: 25, name: 'Rad T4 Time', type: 't4_time', lane: "mid", bit: [9,10], team: 'radiant', x: 53, y: 196 },
32
+ { id: 50, name: 'Rad Ancient', type: 'fort', lane: "", bit: -1, team: 'radiant', x: 39.5, y: 193.5 },
33
+ { id: 50, name: 'Rad Ancient Time', type: 'fort_time', lane: "", bit: -1, team: 'radiant', x: 42, y: 207 },
34
34
 
35
35
  // ================= 夜魔 Dire (右上) =================
36
36
  // 上路
37
- { id: 26, name: 'Dire Top T1', type: 'tower', lane: "top", bit: 0, team: 'dire', x: 41, y: 32 },
38
- { id: 29, name: 'Dire Top T2', type: 'tower', lane: "top", bit: 1, team: 'dire', x: 120, y: 31 },
39
- { id: 32, name: 'Dire Top T3', type: 'tower', lane: "top", bit: 2, team: 'dire', x: 176, y: 34 },
40
- { id: 44, name: 'Dire Top Melee', type: 'rax', lane: "top", bit: 0, team: 'dire', x: 182, y: 40 },
41
- { id: 47, name: 'Dire Top Range', type: 'rax', lane: "top", bit: 1, team: 'dire', x: 182, y: 32 },
42
- { id: 44, name: 'Dire Top HG Time', type: 'rax_time', lane: "top", bit: 0, team: 'dire', x: 185, y: 40 },
37
+ { id: 26, name: 'Dire Top T1', type: 'tower', lane: "top", bit: 0, team: 'dire', x: 50.4, y: 41 },
38
+ { id: 29, name: 'Dire Top T2', type: 'tower', lane: "top", bit: 1, team: 'dire', x: 120.7, y: 39.8 },
39
+ { id: 32, name: 'Dire Top T3', type: 'tower', lane: "top", bit: 2, team: 'dire', x: 170.7, y: 42.9 },
40
+ { id: 44, name: 'Dire Top Melee', type: 'rax', lane: "top", bit: 0, team: 'dire', x: 176.5, y: 48.5 },
41
+ { id: 47, name: 'Dire Top Range', type: 'rax', lane: "top", bit: 1, team: 'dire', x: 176.5, y: 40.8 },
42
+ { id: 44, name: 'Dire Top HG Time', type: 'rax_time', lane: "top", bit: 0, team: 'dire', x: 181.5, y: 49 },
43
43
 
44
44
  // 中路
45
- { id: 27, name: 'Dire Mid T1', type: 'tower', lane: "mid", bit: 3, team: 'dire', x: 130, y: 112 },
46
- { id: 30, name: 'Dire Mid T2', type: 'tower', lane: "mid", bit: 4, team: 'dire', x: 160, y: 90 },
47
- { id: 33, name: 'Dire Mid T3', type: 'tower', lane: "mid", bit: 5, team: 'dire', x: 187, y: 65 },
48
- { id: 45, name: 'Dire Mid Melee', type: 'rax', lane: "mid", bit: 2, team: 'dire', x: 189, y: 60 },
49
- { id: 48, name: 'Dire Mid Range', type: 'rax', lane: "mid", bit: 3, team: 'dire', x: 195, y: 64 },
50
- { id: 45, name: 'Dire Mid HG Time', type: 'rax_time', lane: "mid", bit: 2, team: 'dire', x: 196, y: 68 },
45
+ { id: 27, name: 'Dire Mid T1', type: 'tower', lane: "mid", bit: 3, team: 'dire', x: 129.4, y: 112.7 },
46
+ { id: 30, name: 'Dire Mid T2', type: 'tower', lane: "mid", bit: 4, team: 'dire', x: 156.4, y: 92.8 },
47
+ { id: 33, name: 'Dire Mid T3', type: 'tower', lane: "mid", bit: 5, team: 'dire', x: 180.6, y: 70.5 },
48
+ { id: 45, name: 'Dire Mid Melee', type: 'rax', lane: "mid", bit: 2, team: 'dire', x: 187.5, y: 70.5 },
49
+ { id: 48, name: 'Dire Mid Range', type: 'rax', lane: "mid", bit: 3, team: 'dire', x: 182.7, y: 65.6 },
50
+ { id: 45, name: 'Dire Mid HG Time', type: 'rax_time', lane: "mid", bit: 2, team: 'dire', x: 187, y: 74 },
51
51
 
52
52
  // 下路
53
- { id: 28, name: 'Dire Bot T1', type: 'tower', lane: "bot", bit: 6, team: 'dire', x: 218, y: 157 },
54
- { id: 31, name: 'Dire Bot T2', type: 'tower', lane: "bot", bit: 7, team: 'dire', x: 220, y: 117 },
55
- { id: 34, name: 'Dire Bot T3', type: 'tower', lane: "bot", bit: 8, team: 'dire', x: 219, y: 76 },
56
- { id: 46, name: 'Dire Bot Melee', type: 'rax', lane: "bot", bit: 4, team: 'dire', x: 224, y: 72 },
57
- { id: 49, name: 'Dire Bot Range', type: 'rax', lane: "bot", bit: 5, team: 'dire', x: 216, y: 72 },
58
- { id: 46, name: 'Dire Bot HG Time', type: 'rax_time', lane: "bot", bit: 4, team: 'dire', x: 225, y: 78 },
53
+ { id: 28, name: 'Dire Bot T1', type: 'tower', lane: "bot", bit: 6, team: 'dire', x: 207.8, y: 152.2 },
54
+ { id: 31, name: 'Dire Bot T2', type: 'tower', lane: "bot", bit: 7, team: 'dire', x: 209.75, y: 116.6 },
55
+ { id: 34, name: 'Dire Bot T3', type: 'tower', lane: "bot", bit: 8, team: 'dire', x: 208.7, y: 80.5 },
56
+ { id: 46, name: 'Dire Bot Melee', type: 'rax', lane: "bot", bit: 4, team: 'dire', x: 213.2, y: 76.8 },
57
+ { id: 49, name: 'Dire Bot Range', type: 'rax', lane: "bot", bit: 5, team: 'dire', x: 206.2, y: 76.8 },
58
+ { id: 46, name: 'Dire Bot HG Time', type: 'rax_time', lane: "bot", bit: 4, team: 'dire', x: 214.5, y: 82 },
59
59
 
60
60
  // 门牙 & 基地
61
- { id: 35, name: 'Dire T4 Left', type: 'tower', lane: "mid", bit: 9, team: 'dire', x: 197, y: 49 },
62
- { id: 35, name: 'Dire T4 Right', type: 'tower', lane: "mid", bit: 10, team: 'dire', x: 203, y: 54 },
63
- { id: 35, name: 'Dire T4 Time', type: 't4_time', lane: "mid", bit: 10, team: 'dire', x: 207, y: 57 },
64
- { id: 51, name: 'Dire Ancient', type: 'fort', lane: "", bit: -1, team: 'dire', x: 204, y: 44 },
65
- { id: 51, name: 'Dire Ancient Time', type: 'fort_time', lane: "", bit: -1, team: 'dire', x: 215, y: 48 },
61
+ { id: 35, name: 'Dire T4 Left', type: 'tower', lane: "mid", bit: 9, team: 'dire', x: 189.7, y: 56.4 },
62
+ { id: 35, name: 'Dire T4 Right', type: 'tower', lane: "mid", bit: 10, team: 'dire', x: 194.4, y: 60.2 },
63
+ { id: 35, name: 'Dire T4 Time', type: 't4_time', lane: "mid", bit: 10, team: 'dire', x: 198, y: 63 },
64
+ { id: 51, name: 'Dire Ancient', type: 'fort', lane: "", bit: -1, team: 'dire', x: 195.7, y: 49 },
65
+ { id: 51, name: 'Dire Ancient Time', type: 'fort_time', lane: "", bit: -1, team: 'dire', x: 210, y: 52 },
66
66
  ];
67
67
  %> <%
68
68
  // 1. 算法:提取摧毁时间 (Last Event Algorithm)
@@ -124,7 +124,7 @@ const BUILDINGS = [
124
124
  };
125
125
 
126
126
  const getProps = (type) => buildingProps[type] || buildingProps._default;
127
- %> <% const images = { minimapBase: "7.38_simple_minimap" } %> <section class="map"> <%- include("../../common/components/building_icons") %> <svg id="map" viewBox="0 0 255 255" width="250" height="250"><rect x="0" y="0" width="255" height="255" fill="#f5f5f5" rx="12" ry="12"/><image href="<%= getImageUrl(images.minimapBase) %>" width="255" height="255"/> <%
127
+ %> <% const images = { minimapBase: "dotamap_7.40" } %> <section class="map"> <%- include("../../common/components/building_icons") %> <svg id="map" viewBox="0 0 255 255" width="250" height="250"><rect x="0" y="0" width="255" height="255" fill="#f5f5f5" rx="12" ry="12"/><image href="<%= getImageUrl(images.minimapBase) %>" width="255" height="255"/> <%
128
128
  [...BUILDINGS].sort((a, b) => {
129
129
  return getProps(a.type).z - getProps(b.type).z;
130
130
  }).forEach(b => {
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.3.1",
4
+ "version": "2.3.2",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [