@sjtdev/koishi-plugin-dota2tracker 1.2.20-pre.3 → 1.3.0-pre.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/lib/index.js CHANGED
@@ -5,6 +5,11 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __getProtoOf = Object.getPrototypeOf;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
7
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
+ var __glob = (map) => (path3) => {
9
+ var fn = map[path3];
10
+ if (fn) return fn();
11
+ throw new Error("Module not found in bundle: " + path3);
12
+ };
8
13
  var __commonJS = (cb, mod) => function __require() {
9
14
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
15
  };
@@ -30,17 +35,571 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
35
  ));
31
36
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
37
 
33
- // src/locales/zh-CN.yml
34
- var require_zh_CN = __commonJS({
35
- "src/locales/zh-CN.yml"(exports2, module2) {
36
- module2.exports = { dota2tracker: { position: { "1": "优势路", "2": "中路", "3": "烈士路", "4": "采灵芝", "5": "工具人" }, heroes: { "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": '"凯", "鸟人"' } } };
38
+ // src/locales/en-US.constants.json
39
+ var require_en_US_constants = __commonJS({
40
+ "src/locales/en-US.constants.json"(exports2, module2) {
41
+ module2.exports = {
42
+ dota2tracker: {
43
+ template: {
44
+ game_modes: {
45
+ NONE: "None",
46
+ ALL_PICK: "All Pick",
47
+ CAPTAINS_MODE: "Captains Mode",
48
+ RANDOM_DRAFT: "Random Draft",
49
+ SINGLE_DRAFT: "Single Draft",
50
+ ALL_RANDOM: "All Random",
51
+ INTRO: "Intro",
52
+ THE_DIRETIDE: "The Diretide",
53
+ REVERSE_CAPTAINS_MODE: "Reverse Captains Mode",
54
+ THE_GREEVILING: "The Greeviling",
55
+ TUTORIAL: "Tutorial",
56
+ MID_ONLY: "Mid Only",
57
+ LEAST_PLAYED: "Least Played",
58
+ NEW_PLAYER_POOL: "New Player Pool",
59
+ COMPENDIUM_MATCHMAKING: "Compendium Matchmaking",
60
+ CUSTOM: "Custom",
61
+ CAPTAINS_DRAFT: "Captains Draft",
62
+ BALANCED_DRAFT: "Balanced Draft",
63
+ ABILITY_DRAFT: "Ability Draft",
64
+ EVENT: "Event",
65
+ ALL_RANDOM_DEATH_MATCH: "All Random Death Match",
66
+ SOLO_MID: "Solo Mid",
67
+ ALL_PICK_RANKED: "All Pick",
68
+ TURBO: "Turbo",
69
+ MUTATION: "Mutation",
70
+ UNKNOWN: "Unknown"
71
+ },
72
+ lobby_types: {
73
+ INVALID: "Invalid",
74
+ UNRANKED: "Unranked",
75
+ PRACTICE: "Practice",
76
+ TOURNAMENT: "Tournament",
77
+ TUTORIAL: "Tutorial",
78
+ COOP_VS_BOTS: "Coop Vs Bots",
79
+ TEAM_MATCH: "Team Match",
80
+ SOLO_QUEUE: "Solo Queue",
81
+ RANKED: "Ranked",
82
+ SOLO_MID: "Solo Mid",
83
+ BATTLE_CUP: "Battle Cup",
84
+ EVENT: "Event",
85
+ NEW_PLAYER_POOL: "New Player Pool"
86
+ },
87
+ regions: {
88
+ "1": "US West",
89
+ "2": "US East",
90
+ "3": "Europe West",
91
+ "5": "SE Asia",
92
+ "6": "Dubai",
93
+ "7": "Australia",
94
+ "8": "Russia",
95
+ "9": "EU East",
96
+ "10": "South America",
97
+ "11": "South Africa",
98
+ "12": "China",
99
+ "13": "China",
100
+ "14": "Chile",
101
+ "15": "Peru",
102
+ "16": "India",
103
+ "17": "China",
104
+ "18": "China",
105
+ "19": "Japan",
106
+ "20": "China",
107
+ "25": "China",
108
+ "37": "Taiwan",
109
+ "38": "Argentina"
110
+ },
111
+ ranks: {
112
+ "0": "Unknown",
113
+ "1": "Herald",
114
+ "2": "Guardian",
115
+ "3": "Crusader",
116
+ "4": "Archon",
117
+ "5": "Legend",
118
+ "6": "Ancient",
119
+ "7": "Divine",
120
+ "8": "Immortal"
121
+ },
122
+ roles: {
123
+ "0": "Carry",
124
+ "1": "Support",
125
+ "2": "Nuker",
126
+ "3": "Disabler",
127
+ "4": "Jungler",
128
+ "5": "Durable",
129
+ "6": "Escape",
130
+ "7": "Pusher",
131
+ "8": "Initiator"
132
+ },
133
+ hero_names: {
134
+ "1": "Anti-Mage",
135
+ "2": "Axe",
136
+ "3": "Bane",
137
+ "4": "Bloodseeker",
138
+ "5": "Crystal Maiden",
139
+ "6": "Drow Ranger",
140
+ "7": "Earthshaker",
141
+ "8": "Juggernaut",
142
+ "9": "Mirana",
143
+ "10": "Morphling",
144
+ "11": "Shadow Fiend",
145
+ "12": "Phantom Lancer",
146
+ "13": "Puck",
147
+ "14": "Pudge",
148
+ "15": "Razor",
149
+ "16": "Sand King",
150
+ "17": "Storm Spirit",
151
+ "18": "Sven",
152
+ "19": "Tiny",
153
+ "20": "Vengeful Spirit",
154
+ "21": "Windranger",
155
+ "22": "Zeus",
156
+ "23": "Kunkka",
157
+ "25": "Lina",
158
+ "26": "Lion",
159
+ "27": "Shadow Shaman",
160
+ "28": "Slardar",
161
+ "29": "Tidehunter",
162
+ "30": "Witch Doctor",
163
+ "31": "Lich",
164
+ "32": "Riki",
165
+ "33": "Enigma",
166
+ "34": "Tinker",
167
+ "35": "Sniper",
168
+ "36": "Necrophos",
169
+ "37": "Warlock",
170
+ "38": "Beastmaster",
171
+ "39": "Queen of Pain",
172
+ "40": "Venomancer",
173
+ "41": "Faceless Void",
174
+ "42": "Wraith King",
175
+ "43": "Death Prophet",
176
+ "44": "Phantom Assassin",
177
+ "45": "Pugna",
178
+ "46": "Templar Assassin",
179
+ "47": "Viper",
180
+ "48": "Luna",
181
+ "49": "Dragon Knight",
182
+ "50": "Dazzle",
183
+ "51": "Clockwerk",
184
+ "52": "Leshrac",
185
+ "53": "Nature's Prophet",
186
+ "54": "Lifestealer",
187
+ "55": "Dark Seer",
188
+ "56": "Clinkz",
189
+ "57": "Omniknight",
190
+ "58": "Enchantress",
191
+ "59": "Huskar",
192
+ "60": "Night Stalker",
193
+ "61": "Broodmother",
194
+ "62": "Bounty Hunter",
195
+ "63": "Weaver",
196
+ "64": "Jakiro",
197
+ "65": "Batrider",
198
+ "66": "Chen",
199
+ "67": "Spectre",
200
+ "68": "Ancient Apparition",
201
+ "69": "Doom",
202
+ "70": "Ursa",
203
+ "71": "Spirit Breaker",
204
+ "72": "Gyrocopter",
205
+ "73": "Alchemist",
206
+ "74": "Invoker",
207
+ "75": "Silencer",
208
+ "76": "Outworld Devourer",
209
+ "77": "Lycan",
210
+ "78": "Brewmaster",
211
+ "79": "Shadow Demon",
212
+ "80": "Lone Druid",
213
+ "81": "Chaos Knight",
214
+ "82": "Meepo",
215
+ "83": "Treant Protector",
216
+ "84": "Ogre Magi",
217
+ "85": "Undying",
218
+ "86": "Rubick",
219
+ "87": "Disruptor",
220
+ "88": "Nyx Assassin",
221
+ "89": "Naga Siren",
222
+ "90": "Keeper of the Light",
223
+ "91": "Io",
224
+ "92": "Visage",
225
+ "93": "Slark",
226
+ "94": "Medusa",
227
+ "95": "Troll Warlord",
228
+ "96": "Centaur Warrunner",
229
+ "97": "Magnus",
230
+ "98": "Timbersaw",
231
+ "99": "Bristleback",
232
+ "100": "Tusk",
233
+ "101": "Skywrath Mage",
234
+ "102": "Abaddon",
235
+ "103": "Elder Titan",
236
+ "104": "Legion Commander",
237
+ "105": "Techies",
238
+ "106": "Ember Spirit",
239
+ "107": "Earth Spirit",
240
+ "108": "Underlord",
241
+ "109": "Terrorblade",
242
+ "110": "Phoenix",
243
+ "111": "Oracle",
244
+ "112": "Winter Wyvern",
245
+ "113": "Arc Warden",
246
+ "114": "Monkey King",
247
+ "119": "Dark Willow",
248
+ "120": "Pangolier",
249
+ "121": "Grimstroke",
250
+ "123": "Hoodwink",
251
+ "126": "Void Spirit",
252
+ "128": "Snapfire",
253
+ "129": "Mars",
254
+ "131": "Ring Master",
255
+ "135": "Dawnbreaker",
256
+ "136": "Marci",
257
+ "137": "Primal Beast",
258
+ "138": "Muerta",
259
+ "145": "Kez"
260
+ },
261
+ behavior: {
262
+ "Unit Target": "Unit Target",
263
+ Channeled: "Channeled",
264
+ Hidden: "Hidden",
265
+ Passive: "Passive",
266
+ "No Target": "No Target",
267
+ Autocast: "Autocast",
268
+ "Instant Cast": "Instant Cast",
269
+ "Point Target": "Point Target",
270
+ "Attack Modifier": "Attack Modifier",
271
+ AOE: "AOE"
272
+ },
273
+ target_team: {
274
+ Enemy: "Enemy",
275
+ Both: "Both",
276
+ Friendly: "Friendly"
277
+ },
278
+ ability: "Ability: ",
279
+ affects: "Affects:",
280
+ damage_type: "Damage Type: ",
281
+ damage_type_Physical: "Physical",
282
+ damage_type_Magical: "Magical",
283
+ damage_type_Pure: "Pure",
284
+ dispellable: "Dispellable: ",
285
+ Yes: "Yes",
286
+ No: "No",
287
+ dispellable_Strong: "Strong Dispels Only",
288
+ bkbpierce: "Pierces Debuff Imminity: ",
289
+ innate: "Innate",
290
+ scepter: "Aghanim's Scepter",
291
+ shard: "Aghanim's Shard",
292
+ attack: "ATTACK",
293
+ defense: "DEFENSE",
294
+ mobility: "MOBILITY"
295
+ }
296
+ }
297
+ };
298
+ }
299
+ });
300
+
301
+ // src/locales/zh-CN.constants.json
302
+ var require_zh_CN_constants = __commonJS({
303
+ "src/locales/zh-CN.constants.json"(exports2, module2) {
304
+ module2.exports = {
305
+ dota2tracker: {
306
+ template: {
307
+ game_modes: {
308
+ NONE: "",
309
+ ALL_PICK: "全英雄选择",
310
+ CAPTAINS_MODE: "队长模式",
311
+ RANDOM_DRAFT: "随机征召",
312
+ SINGLE_DRAFT: "单一征召",
313
+ ALL_RANDOM: "全英雄随机",
314
+ INTRO: "",
315
+ THE_DIRETIDE: "",
316
+ REVERSE_CAPTAINS_MODE: "",
317
+ THE_GREEVILING: "",
318
+ TUTORIAL: "教程模式",
319
+ MID_ONLY: "",
320
+ LEAST_PLAYED: "",
321
+ NEW_PLAYER_POOL: "",
322
+ COMPENDIUM_MATCHMAKING: "",
323
+ CUSTOM: "",
324
+ CAPTAINS_DRAFT: "",
325
+ BALANCED_DRAFT: "",
326
+ ABILITY_DRAFT: "",
327
+ EVENT: "",
328
+ ALL_RANDOM_DEATH_MATCH: "",
329
+ SOLO_MID: "",
330
+ ALL_PICK_RANKED: "全英雄选择",
331
+ TURBO: "加速模式",
332
+ MUTATION: "",
333
+ UNKNOWN: ""
334
+ },
335
+ lobby_types: {
336
+ INVALID: "",
337
+ UNRANKED: "非天梯",
338
+ PRACTICE: "",
339
+ TOURNAMENT: "",
340
+ TUTORIAL: "",
341
+ COOP_VS_BOTS: "",
342
+ TEAM_MATCH: "",
343
+ SOLO_QUEUE: "",
344
+ RANKED: "天梯比赛",
345
+ SOLO_MID: "",
346
+ BATTLE_CUP: "",
347
+ EVENT: "",
348
+ NEW_PLAYER_POOL: ""
349
+ },
350
+ regions: {
351
+ "1": "US WEST",
352
+ "2": "US EAST",
353
+ "3": "EUROPE",
354
+ "5": "新加坡",
355
+ "6": "DUBAI",
356
+ "7": "AUSTRALIA",
357
+ "8": "STOCKHOLM",
358
+ "9": "AUSTRIA",
359
+ "10": "BRAZIL",
360
+ "11": "SOUTHAFRICA",
361
+ "12": "电信(上海)",
362
+ "13": "联通(一)",
363
+ "14": "CHILE",
364
+ "15": "PERU",
365
+ "16": "INDIA",
366
+ "17": "电信(广东)",
367
+ "18": "电信(浙江)",
368
+ "19": "日本",
369
+ "20": "电信(华中)",
370
+ "25": "联通(二)",
371
+ "37": "TAIWAN",
372
+ "38": "ARGENTINA"
373
+ },
374
+ ranks: {
375
+ "0": "未知",
376
+ "1": "先锋",
377
+ "2": "卫士",
378
+ "3": "中军",
379
+ "4": "统帅",
380
+ "5": "传奇",
381
+ "6": "万古流芳",
382
+ "7": "超凡入圣",
383
+ "8": "冠绝一世"
384
+ },
385
+ roles: {
386
+ "0": "核心",
387
+ "1": "辅助",
388
+ "2": "爆发",
389
+ "3": "控制",
390
+ "4": "打野",
391
+ "5": "耐久",
392
+ "6": "逃生",
393
+ "7": "推进",
394
+ "8": "先手"
395
+ },
396
+ hero_names: {
397
+ "1": "敌法师",
398
+ "2": "斧王",
399
+ "3": "祸乱之源",
400
+ "4": "血魔",
401
+ "5": "水晶室女",
402
+ "6": "卓尔游侠",
403
+ "7": "撼地者",
404
+ "8": "主宰",
405
+ "9": "米拉娜",
406
+ "10": "变体精灵",
407
+ "11": "影魔",
408
+ "12": "幻影长矛手",
409
+ "13": "帕克",
410
+ "14": "帕吉",
411
+ "15": "雷泽",
412
+ "16": "沙王",
413
+ "17": "风暴之灵",
414
+ "18": "斯温",
415
+ "19": "小小",
416
+ "20": "复仇之魂",
417
+ "21": "风行者",
418
+ "22": "宙斯",
419
+ "23": "昆卡",
420
+ "25": "莉娜",
421
+ "26": "莱恩",
422
+ "27": "暗影萨满",
423
+ "28": "斯拉达",
424
+ "29": "潮汐猎人",
425
+ "30": "巫医",
426
+ "31": "巫妖",
427
+ "32": "力丸",
428
+ "33": "谜团",
429
+ "34": "修补匠",
430
+ "35": "狙击手",
431
+ "36": "瘟疫法师",
432
+ "37": "术士",
433
+ "38": "兽王",
434
+ "39": "痛苦女王",
435
+ "40": "剧毒术士",
436
+ "41": "虚空假面",
437
+ "42": "冥魂大帝",
438
+ "43": "死亡先知",
439
+ "44": "幻影刺客",
440
+ "45": "帕格纳",
441
+ "46": "圣堂刺客",
442
+ "47": "冥界亚龙",
443
+ "48": "露娜",
444
+ "49": "龙骑士",
445
+ "50": "戴泽",
446
+ "51": "发条技师",
447
+ "52": "拉席克",
448
+ "53": "先知",
449
+ "54": "噬魂鬼",
450
+ "55": "黑暗贤者",
451
+ "56": "克林克兹",
452
+ "57": "全能骑士",
453
+ "58": "魅惑魔女",
454
+ "59": "哈斯卡",
455
+ "60": "暗夜魔王",
456
+ "61": "育母蜘蛛",
457
+ "62": "赏金猎人",
458
+ "63": "编织者",
459
+ "64": "杰奇洛",
460
+ "65": "蝙蝠骑士",
461
+ "66": "陈",
462
+ "67": "幽鬼",
463
+ "68": "远古冰魄",
464
+ "69": "末日使者",
465
+ "70": "熊战士",
466
+ "71": "裂魂人",
467
+ "72": "矮人直升机",
468
+ "73": "炼金术士",
469
+ "74": "祈求者",
470
+ "75": "沉默术士",
471
+ "76": "殁境神蚀者",
472
+ "77": "狼人",
473
+ "78": "酒仙",
474
+ "79": "暗影恶魔",
475
+ "80": "德鲁伊",
476
+ "81": "混沌骑士",
477
+ "82": "米波",
478
+ "83": "树精卫士",
479
+ "84": "食人魔魔法师",
480
+ "85": "不朽尸王",
481
+ "86": "拉比克",
482
+ "87": "干扰者",
483
+ "88": "司夜刺客",
484
+ "89": "娜迦海妖",
485
+ "90": "光之守卫",
486
+ "91": "艾欧",
487
+ "92": "维萨吉",
488
+ "93": "斯拉克",
489
+ "94": "美杜莎",
490
+ "95": "巨魔战将",
491
+ "96": "半人马战行者",
492
+ "97": "马格纳斯",
493
+ "98": "伐木机",
494
+ "99": "钢背兽",
495
+ "100": "巨牙海民",
496
+ "101": "天怒法师",
497
+ "102": "亚巴顿",
498
+ "103": "上古巨神",
499
+ "104": "军团指挥官",
500
+ "105": "工程师",
501
+ "106": "灰烬之灵",
502
+ "107": "大地之灵",
503
+ "108": "孽主",
504
+ "109": "恐怖利刃",
505
+ "110": "凤凰",
506
+ "111": "神谕者",
507
+ "112": "寒冬飞龙",
508
+ "113": "天穹守望者",
509
+ "114": "齐天大圣",
510
+ "119": "邪影芳灵",
511
+ "120": "石鳞剑士",
512
+ "121": "天涯墨客",
513
+ "123": "森海飞霞",
514
+ "126": "虚无之灵",
515
+ "128": "电炎绝手",
516
+ "129": "玛尔斯",
517
+ "131": "百戏大王",
518
+ "135": "破晓辰星",
519
+ "136": "玛西",
520
+ "137": "獸",
521
+ "138": "琼英碧灵",
522
+ "145": "凯"
523
+ },
524
+ behavior: {
525
+ "Unit Target": "单位目标",
526
+ Channeled: "持续施法",
527
+ Hidden: "默认隐藏",
528
+ Passive: "被动",
529
+ "No Target": "无目标",
530
+ Autocast: "自动施法",
531
+ "Instant Cast": "即时施法",
532
+ "Point Target": "点目标",
533
+ "Attack Modifier": "攻击特效",
534
+ AOE: "范围生效"
535
+ },
536
+ target_team: {
537
+ Enemy: "敌方单位",
538
+ Both: "单位",
539
+ Friendly: "友方单位"
540
+ },
541
+ ability: "技能:",
542
+ affects: "影响:",
543
+ damage_type: "伤害类型:",
544
+ damage_type_Physical: "物理",
545
+ damage_type_Magical: "魔法",
546
+ damage_type_Pure: "纯粹",
547
+ dispellable: "能否驱散:",
548
+ Yes: "是",
549
+ No: "否",
550
+ dispellable_Strong: "仅强驱散",
551
+ bkbpierce: "无视减益免疫:",
552
+ innate: "先天技能",
553
+ scepter: "阿哈利姆神杖",
554
+ shard: "阿哈利姆魔晶",
555
+ attack: "进攻",
556
+ defense: "防守",
557
+ mobility: "机动"
558
+ }
559
+ }
560
+ };
561
+ }
562
+ });
563
+
564
+ // src/locales/en-US.command.yml
565
+ var require_en_US_command = __commonJS({
566
+ "src/locales/en-US.command.yml"(exports2, module2) {
567
+ module2.exports = { commands: { subscribe: { description: "After subscribing, players need to bind their Steam ID to this group.", usage: "After subscribing, players need to bind their Steam ID to this group. BOT will subscribe to the new game data of bound players in this group. After the STRATZ game analysis is completed, the game data will be generated into a picture battle report and published to this group.", messages: { subscribe_success: "Subscription successful.", subscribed: "This Channel has been subscribed, no need to subscribe again." } }, unsubscribe: { description: "Unsubscribe from this group.", messages: { unsubscribe_success: "Unsubscription successful.", not_subscribed: "This Channel has not been subscribed yet, so there is no need to unsubscribe." } } } };
568
+ }
569
+ });
570
+
571
+ // src/locales/en-US.template.yml
572
+ var require_en_US_template = __commonJS({
573
+ "src/locales/en-US.template.yml"(exports2, module2) {
574
+ 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)" } } };
37
575
  }
38
576
  });
39
577
 
40
578
  // src/locales/en-US.yml
41
579
  var require_en_US = __commonJS({
42
580
  "src/locales/en-US.yml"(exports2, module2) {
43
- module2.exports = { dota2tracker: { position: { "1": "Safe Lane", "2": "Mid Lane", "3": "Off Lane", "4": "Soft Support", "5": "Hard Support" }, heroes: { "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"' } } };
581
+ 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}" } } };
582
+ }
583
+ });
584
+
585
+ // src/locales/zh-CN.command.yml
586
+ var require_zh_CN_command = __commonJS({
587
+ "src/locales/zh-CN.command.yml"(exports2, module2) {
588
+ module2.exports = { commands: { subscribe: { description: "订阅后还需玩家在本群绑定SteamID", usage: "订阅后还需玩家在本群绑定SteamID,BOT将订阅本群中已绑定玩家的新比赛数据,在STRATZ比赛解析完成后将比赛数据生成为图片战报发布至本群中。", messages: { subscribed: "本群已订阅,无需重复订阅。", subscribe_success: "订阅成功。" } }, unsubscribe: { description: "取消订阅本群。", messages: { unsubscribe_success: "取消订阅成功。", not_subscribed: "本群尚未订阅,无需取消订阅。" } } } };
589
+ }
590
+ });
591
+
592
+ // src/locales/zh-CN.template.yml
593
+ var require_zh_CN_template = __commonJS({
594
+ "src/locales/zh-CN.template.yml"(exports2, module2) {
595
+ 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: "(未解析)" } } };
596
+ }
597
+ });
598
+
599
+ // src/locales/zh-CN.yml
600
+ var require_zh_CN = __commonJS({
601
+ "src/locales/zh-CN.yml"(exports2, module2) {
602
+ 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}" } } };
44
603
  }
45
604
  });
46
605
 
@@ -82,9 +641,10 @@ var import_path = __toESM(require("path"));
82
641
  var CONFIGS = { STRATZ_API: { URL: "https://api.stratz.com/graphql", TOKEN: "" } };
83
642
  var http = null;
84
643
  var setTimeout;
85
- function init(newHttp, newSetTimeout) {
644
+ function init(newHttp, newSetTimeout, APIKEY) {
86
645
  http = newHttp;
87
646
  setTimeout = newSetTimeout;
647
+ CONFIGS.STRATZ_API.TOKEN = APIKEY;
88
648
  }
89
649
  __name(init, "init");
90
650
  async function fetchData(query2) {
@@ -148,6 +708,7 @@ var ImageType = /* @__PURE__ */ ((ImageType2) => {
148
708
  ImageType2["IconsFacets"] = "icons/facets";
149
709
  ImageType2["Heroes"] = "heroes";
150
710
  ImageType2["HeroIcons"] = "heroes/icons";
711
+ ImageType2["HeroStats"] = "heroes/stats";
151
712
  ImageType2["Items"] = "items";
152
713
  ImageType2["Abilities"] = "abilities";
153
714
  ImageType2["Local"] = "local";
@@ -172,11 +733,11 @@ function getImageUrl(image, type = "local" /* Local */, format = "png" /* png */
172
733
  } else return `https://cdn.cloudflare.steamstatic.com/apps/dota2/images/dota_react/${type}/${image}.${format}`;
173
734
  }
174
735
  __name(getImageUrl, "getImageUrl");
175
- function getFormattedMatchData(data) {
176
- const match = data.match;
177
- const constants = data.constants;
736
+ function getFormattedMatchData(matchQuery, constantsQuery) {
737
+ const match = matchQuery.match;
738
+ const constants = constantsQuery.constants;
178
739
  ["radiant", "dire"].forEach((team) => {
179
- match[team] = { killsCount: match[team + "Kills"]?.reduce((acc, cva) => acc + cva, 0) ?? 0, damageReceived: 0, heroDamage: 0, networth: 0, experience: 0 };
740
+ match[team] = { killsCount: match?.[team + "Kills"]?.reduce((acc, cva) => acc + cva, 0) ?? 0, damageReceived: 0, heroDamage: 0, networth: 0, experience: 0 };
180
741
  });
181
742
  if (!match.parsedDateTime) {
182
743
  match.players.reduce((acc, player) => {
@@ -198,11 +759,11 @@ function getFormattedMatchData(data) {
198
759
  let processLaneOutcome = /* @__PURE__ */ __name(function(outcome) {
199
760
  switch (outcome) {
200
761
  case "RADIANT_VICTORY":
201
- return { radiant: "victory", dire: "fail" };
762
+ return { radiant: "advantage", dire: "disadvantage" };
202
763
  case "RADIANT_STOMP":
203
764
  return { radiant: "stomp", dire: "stomped" };
204
765
  case "DIRE_VICTORY":
205
- return { radiant: "fail", dire: "victory" };
766
+ return { radiant: "disadvantage", dire: "advantage" };
206
767
  case "DIRE_STOMP":
207
768
  return { radiant: "stomped", dire: "stomp" };
208
769
  default:
@@ -222,7 +783,7 @@ function getFormattedMatchData(data) {
222
783
  inTop100: player.steamAccount.seasonLeaderboardRank ? player.steamAccount.seasonLeaderboardRank <= 10 ? "8c" : player.steamAccount.seasonLeaderboardRank <= 100 ? "8b" : void 0 : void 0
223
784
  };
224
785
  player.killContribution = (player.kills + player.assists) / match[player.team].killsCount;
225
- player.deathContribution = player.deaths / match[player.team === "radiant" ? "dire" : player.team].killsCount;
786
+ player.deathContribution = player.deaths / match[player.team === "radiant" ? "dire" : "radiant"].killsCount;
226
787
  player.damageReceived = (player.stats?.heroDamageReport?.receivedTotal?.physicalDamage ?? 0) + (player.stats?.heroDamageReport?.receivedTotal?.magicalDamage ?? 0) + (player.stats?.heroDamageReport?.receivedTotal?.pureDamage ?? 0);
227
788
  match[player.team].heroDamage = (match[player.team].heroDamage ?? 0) + player.heroDamage;
228
789
  match[player.team].damageReceived = (match[player.team].damageReceived ?? 0) + player.damageReceived;
@@ -419,7 +980,7 @@ function getFormattedMatchData(data) {
419
980
  )?.titles.push({ name: "魂", color: "#6cf" });
420
981
  findMaxByProperty("networth")?.titles.push({ name: "富", color: "#FFD700" });
421
982
  findMaxByProperty("experiencePerMinute")?.titles.push({ name: "睿", color: "#8888FF" });
422
- if (match.parsedDateTime) {
983
+ if (match.parsedDateTime && match.players.every((player) => player?.stats?.heroDamageReport?.dealtTotal)) {
423
984
  match.players.reduce(
424
985
  (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
425
986
  ).titles.push({ name: "控", color: "#FF00FF" });
@@ -546,417 +1107,47 @@ var import_fs2 = __toESM(require("fs"));
546
1107
  var import_path2 = __toESM(require("path"));
547
1108
  var import_moment = __toESM(require("moment"));
548
1109
  var dotaconstants2 = __toESM(require("dotaconstants"));
1110
+ var import_koishi2 = require("koishi");
1111
+ var ejs = __toESM(require("ejs"));
549
1112
 
550
- // src/data/dotaconstants_add.json
551
- var dotaconstants_add_exports = {};
552
- __export(dotaconstants_add_exports, {
553
- HEROES_NAMES: () => HEROES_NAMES,
554
- LOSE_NEGATIVE: () => LOSE_NEGATIVE,
555
- LOSE_POSITIVE: () => LOSE_POSITIVE,
556
- WIN_NEGATIVE: () => WIN_NEGATIVE,
557
- WIN_POSITIVE: () => WIN_POSITIVE,
558
- behavior: () => behavior,
559
- default: () => dotaconstants_add_default,
560
- gameMode: () => gameMode,
561
- lobbyTypes: () => lobbyTypes,
562
- position: () => position,
563
- primary_attrs: () => primary_attrs,
564
- rank: () => rank,
565
- region: () => region,
566
- roles: () => roles,
567
- target_team: () => target_team
1113
+ // require("./locales/**/*.constants.json") in src/index.ts
1114
+ var globRequire_locales_constants_json = __glob({
1115
+ "./locales/en-US.constants.json": () => require_en_US_constants(),
1116
+ "./locales/zh-CN.constants.json": () => require_zh_CN_constants()
1117
+ });
1118
+
1119
+ // require("./locales/**/*.yml") in src/index.ts
1120
+ var globRequire_locales_yml = __glob({
1121
+ "./locales/en-US.command.yml": () => require_en_US_command(),
1122
+ "./locales/en-US.template.yml": () => require_en_US_template(),
1123
+ "./locales/en-US.yml": () => require_en_US(),
1124
+ "./locales/zh-CN.command.yml": () => require_zh_CN_command(),
1125
+ "./locales/zh-CN.template.yml": () => require_zh_CN_template(),
1126
+ "./locales/zh-CN.yml": () => require_zh_CN()
1127
+ });
1128
+
1129
+ // require("./locales/**/*.command.yml") in src/index.ts
1130
+ var globRequire_locales_command_yml = __glob({
1131
+ "./locales/en-US.command.yml": () => require_en_US_command(),
1132
+ "./locales/zh-CN.command.yml": () => require_zh_CN_command()
1133
+ });
1134
+
1135
+ // require("./locales/**/*.template.yml") in src/index.ts
1136
+ var globRequire_locales_template_yml = __glob({
1137
+ "./locales/en-US.template.yml": () => require_en_US_template(),
1138
+ "./locales/zh-CN.template.yml": () => require_zh_CN_template()
568
1139
  });
569
- var gameMode = {
570
- NONE: "",
571
- ALL_PICK: "全英雄选择",
572
- CAPTAINS_MODE: "队长模式",
573
- RANDOM_DRAFT: "随机征召",
574
- SINGLE_DRAFT: "单一征召",
575
- ALL_RANDOM: "全英雄随机",
576
- INTRO: "",
577
- THE_DIRETIDE: "",
578
- REVERSE_CAPTAINS_MODE: "",
579
- THE_GREEVILING: "",
580
- TUTORIAL: "教程模式",
581
- MID_ONLY: "",
582
- LEAST_PLAYED: "",
583
- NEW_PLAYER_POOL: "",
584
- COMPENDIUM_MATCHMAKING: "",
585
- CUSTOM: "",
586
- CAPTAINS_DRAFT: "",
587
- BALANCED_DRAFT: "",
588
- ABILITY_DRAFT: "",
589
- EVENT: "",
590
- ALL_RANDOM_DEATH_MATCH: "",
591
- SOLO_MID: "",
592
- ALL_PICK_RANKED: "全英雄选择",
593
- TURBO: "加速模式",
594
- MUTATION: "",
595
- UNKNOWN: ""
596
- };
597
- var lobbyTypes = {
598
- INVALID: "",
599
- UNRANKED: "非天梯",
600
- PRACTICE: "",
601
- TOURNAMENT: "",
602
- TUTORIAL: "",
603
- COOP_VS_BOTS: "",
604
- TEAM_MATCH: "",
605
- SOLO_QUEUE: "",
606
- RANKED: "天梯比赛",
607
- SOLO_MID: "",
608
- BATTLE_CUP: "",
609
- EVENT: "",
610
- NEW_PLAYER_POOL: ""
611
- };
612
- var region = {
613
- "1": "US WEST",
614
- "2": "US EAST",
615
- "3": "EUROPE",
616
- "5": "新加坡",
617
- "6": "DUBAI",
618
- "7": "AUSTRALIA",
619
- "8": "STOCKHOLM",
620
- "9": "AUSTRIA",
621
- "10": "BRAZIL",
622
- "11": "SOUTHAFRICA",
623
- "12": "电信(上海)",
624
- "13": "联通(一)",
625
- "14": "CHILE",
626
- "15": "PERU",
627
- "16": "INDIA",
628
- "17": "电信(广东)",
629
- "18": "电信(浙江)",
630
- "19": "日本",
631
- "20": "电信(华中)",
632
- "25": "联通(二)",
633
- "37": "TAIWAN",
634
- "38": "ARGENTINA"
635
- };
636
- var position = {
637
- "1": "优势路",
638
- "2": "中路",
639
- "3": "烈士路",
640
- "4": "采灵芝",
641
- "5": "工具人"
642
- };
643
- var rank = {
644
- "0": "未知",
645
- "1": "先锋",
646
- "2": "卫士",
647
- "3": "中军",
648
- "4": "统帅",
649
- "5": "传奇",
650
- "6": "万古流芳",
651
- "7": "超凡入圣",
652
- "8": "冠绝一世"
653
- };
654
- var roles = ["核心", "辅助", "爆发", "控制", "打野", "耐久", "逃生", "推进", "先手"];
655
- var primary_attrs = { "3": "hero_universal", "0": "hero_strength", "1": "hero_agility", "2": "hero_intelligence" };
656
- var behavior = {
657
- "Unit Target": "单位目标",
658
- Channeled: "持续施法",
659
- Hidden: "默认隐藏",
660
- Passive: "被动",
661
- "No Target": "无目标",
662
- Autocast: "自动施法",
663
- "Instant Cast": "即时施法",
664
- "Point Target": "点目标",
665
- "Attack Modifier": "攻击特效",
666
- AOE: "范围生效"
667
- };
668
- var target_team = { Enemy: "敌方单位", Both: "单位", Friendly: "友方单位" };
669
- var HEROES_NAMES = {
670
- "zh-CN": {
671
- "1": "敌法师",
672
- "2": "斧王",
673
- "3": "祸乱之源",
674
- "4": "血魔",
675
- "5": "水晶室女",
676
- "6": "卓尔游侠",
677
- "7": "撼地者",
678
- "8": "主宰",
679
- "9": "米拉娜",
680
- "10": "变体精灵",
681
- "11": "影魔",
682
- "12": "幻影长矛手",
683
- "13": "帕克",
684
- "14": "帕吉",
685
- "15": "雷泽",
686
- "16": "沙王",
687
- "17": "风暴之灵",
688
- "18": "斯温",
689
- "19": "小小",
690
- "20": "复仇之魂",
691
- "21": "风行者",
692
- "22": "宙斯",
693
- "23": "昆卡",
694
- "25": "莉娜",
695
- "26": "莱恩",
696
- "27": "暗影萨满",
697
- "28": "斯拉达",
698
- "29": "潮汐猎人",
699
- "30": "巫医",
700
- "31": "巫妖",
701
- "32": "力丸",
702
- "33": "谜团",
703
- "34": "修补匠",
704
- "35": "狙击手",
705
- "36": "瘟疫法师",
706
- "37": "术士",
707
- "38": "兽王",
708
- "39": "痛苦女王",
709
- "40": "剧毒术士",
710
- "41": "虚空假面",
711
- "42": "冥魂大帝",
712
- "43": "死亡先知",
713
- "44": "幻影刺客",
714
- "45": "帕格纳",
715
- "46": "圣堂刺客",
716
- "47": "冥界亚龙",
717
- "48": "露娜",
718
- "49": "龙骑士",
719
- "50": "戴泽",
720
- "51": "发条技师",
721
- "52": "拉席克",
722
- "53": "先知",
723
- "54": "噬魂鬼",
724
- "55": "黑暗贤者",
725
- "56": "克林克兹",
726
- "57": "全能骑士",
727
- "58": "魅惑魔女",
728
- "59": "哈斯卡",
729
- "60": "暗夜魔王",
730
- "61": "育母蜘蛛",
731
- "62": "赏金猎人",
732
- "63": "编织者",
733
- "64": "杰奇洛",
734
- "65": "蝙蝠骑士",
735
- "66": "陈",
736
- "67": "幽鬼",
737
- "68": "远古冰魄",
738
- "69": "末日使者",
739
- "70": "熊战士",
740
- "71": "裂魂人",
741
- "72": "矮人直升机",
742
- "73": "炼金术士",
743
- "74": "祈求者",
744
- "75": "沉默术士",
745
- "76": "殁境神蚀者",
746
- "77": "狼人",
747
- "78": "酒仙",
748
- "79": "暗影恶魔",
749
- "80": "德鲁伊",
750
- "81": "混沌骑士",
751
- "82": "米波",
752
- "83": "树精卫士",
753
- "84": "食人魔魔法师",
754
- "85": "不朽尸王",
755
- "86": "拉比克",
756
- "87": "干扰者",
757
- "88": "司夜刺客",
758
- "89": "娜迦海妖",
759
- "90": "光之守卫",
760
- "91": "艾欧",
761
- "92": "维萨吉",
762
- "93": "斯拉克",
763
- "94": "美杜莎",
764
- "95": "巨魔战将",
765
- "96": "半人马战行者",
766
- "97": "马格纳斯",
767
- "98": "伐木机",
768
- "99": "钢背兽",
769
- "100": "巨牙海民",
770
- "101": "天怒法师",
771
- "102": "亚巴顿",
772
- "103": "上古巨神",
773
- "104": "军团指挥官",
774
- "105": "工程师",
775
- "106": "灰烬之灵",
776
- "107": "大地之灵",
777
- "108": "孽主",
778
- "109": "恐怖利刃",
779
- "110": "凤凰",
780
- "111": "神谕者",
781
- "112": "寒冬飞龙",
782
- "113": "天穹守望者",
783
- "114": "齐天大圣",
784
- "119": "邪影芳灵",
785
- "120": "石鳞剑士",
786
- "121": "天涯墨客",
787
- "123": "森海飞霞",
788
- "126": "虚无之灵",
789
- "128": "电炎绝手",
790
- "129": "玛尔斯",
791
- "131": "百戏大王",
792
- "135": "破晓辰星",
793
- "136": "玛西",
794
- "137": "獸",
795
- "138": "琼英碧灵",
796
- "145": "凯"
797
- },
798
- "en-US": {
799
- "1": "Anti-Mage",
800
- "2": "Axe",
801
- "3": "Bane",
802
- "4": "Bloodseeker",
803
- "5": "Crystal Maiden",
804
- "6": "Drow Ranger",
805
- "7": "Earthshaker",
806
- "8": "Juggernaut",
807
- "9": "Mirana",
808
- "10": "Morphling",
809
- "11": "Shadow Fiend",
810
- "12": "Phantom Lancer",
811
- "13": "Puck",
812
- "14": "Pudge",
813
- "15": "Razor",
814
- "16": "Sand King",
815
- "17": "Storm Spirit",
816
- "18": "Sven",
817
- "19": "Tiny",
818
- "20": "Vengeful Spirit",
819
- "21": "Windranger",
820
- "22": "Zeus",
821
- "23": "Kunkka",
822
- "25": "Lina",
823
- "26": "Lion",
824
- "27": "Shadow Shaman",
825
- "28": "Slardar",
826
- "29": "Tidehunter",
827
- "30": "Witch Doctor",
828
- "31": "Lich",
829
- "32": "Riki",
830
- "33": "Enigma",
831
- "34": "Tinker",
832
- "35": "Sniper",
833
- "36": "Necrophos",
834
- "37": "Warlock",
835
- "38": "Beastmaster",
836
- "39": "Queen of Pain",
837
- "40": "Venomancer",
838
- "41": "Faceless Void",
839
- "42": "Wraith King",
840
- "43": "Death Prophet",
841
- "44": "Phantom Assassin",
842
- "45": "Pugna",
843
- "46": "Templar Assassin",
844
- "47": "Viper",
845
- "48": "Luna",
846
- "49": "Dragon Knight",
847
- "50": "Dazzle",
848
- "51": "Clockwerk",
849
- "52": "Leshrac",
850
- "53": "Nature's Prophet",
851
- "54": "Lifestealer",
852
- "55": "Dark Seer",
853
- "56": "Clinkz",
854
- "57": "Omniknight",
855
- "58": "Enchantress",
856
- "59": "Huskar",
857
- "60": "Night Stalker",
858
- "61": "Broodmother",
859
- "62": "Bounty Hunter",
860
- "63": "Weaver",
861
- "64": "Jakiro",
862
- "65": "Batrider",
863
- "66": "Chen",
864
- "67": "Spectre",
865
- "68": "Ancient Apparition",
866
- "69": "Doom",
867
- "70": "Ursa",
868
- "71": "Spirit Breaker",
869
- "72": "Gyrocopter",
870
- "73": "Alchemist",
871
- "74": "Invoker",
872
- "75": "Silencer",
873
- "76": "Outworld Devourer",
874
- "77": "Lycan",
875
- "78": "Brewmaster",
876
- "79": "Shadow Demon",
877
- "80": "Lone Druid",
878
- "81": "Chaos Knight",
879
- "82": "Meepo",
880
- "83": "Treant Protector",
881
- "84": "Ogre Magi",
882
- "85": "Undying",
883
- "86": "Rubick",
884
- "87": "Disruptor",
885
- "88": "Nyx Assassin",
886
- "89": "Naga Siren",
887
- "90": "Keeper of the Light",
888
- "91": "Io",
889
- "92": "Visage",
890
- "93": "Slark",
891
- "94": "Medusa",
892
- "95": "Troll Warlord",
893
- "96": "Centaur Warrunner",
894
- "97": "Magnus",
895
- "98": "Timbersaw",
896
- "99": "Bristleback",
897
- "100": "Tusk",
898
- "101": "Skywrath Mage",
899
- "102": "Abaddon",
900
- "103": "Elder Titan",
901
- "104": "Legion Commander",
902
- "105": "Techies",
903
- "106": "Ember Spirit",
904
- "107": "Earth Spirit",
905
- "108": "Underlord",
906
- "109": "Terrorblade",
907
- "110": "Phoenix",
908
- "111": "Oracle",
909
- "112": "Winter Wyvern",
910
- "113": "Arc Warden",
911
- "114": "Monkey King",
912
- "119": "Dark Willow",
913
- "120": "Pangolier",
914
- "121": "Grimstroke",
915
- "123": "Hoodwink",
916
- "126": "Void Spirit",
917
- "128": "Snapfire",
918
- "129": "Mars",
919
- "131": "Ring Master",
920
- "135": "Dawnbreaker",
921
- "136": "Marci",
922
- "137": "Primal Beast",
923
- "138": "Muerta",
924
- "145": "Kez"
925
- }
926
- };
927
- var WIN_NEGATIVE = ["侥幸赢得了比赛", "走狗屎运赢得了比赛", "躺赢了比赛", "打团都没来, 队友4V5赢得了比赛"];
928
- var WIN_POSITIVE = ["带领团队走向了胜利", "暴打对面后赢得了胜利", " CARRY全场赢得了胜利", "把对面当猪宰了, 赢得了胜利", "又赢了, 这游戏就是这么枯燥, 且乏味", "直接进行一个比赛的赢"];
929
- var LOSE_NEGATIVE = ["被人按在地上摩擦, 输掉了这场比赛", "悲惨地输掉了比赛", "头都被打歪了, 心态爆炸地输掉了比赛", "捕鱼被鱼吃了, 输掉了比赛", "打的是个几把", "直接进行一个比赛的输"];
930
- var LOSE_POSITIVE = ["无力回天输掉了比赛", "尽力了, 但还是输了比赛", "背靠世界树, 虽败犹荣", "带不动队友, 输了比赛", "又输了, 很难受, 宁愿输的是我"];
931
- var dotaconstants_add_default = {
932
- gameMode,
933
- lobbyTypes,
934
- region,
935
- position,
936
- rank,
937
- roles,
938
- primary_attrs,
939
- behavior,
940
- target_team,
941
- HEROES_NAMES,
942
- WIN_NEGATIVE,
943
- WIN_POSITIVE,
944
- LOSE_NEGATIVE,
945
- LOSE_POSITIVE
946
- };
947
1140
 
948
1141
  // src/index.ts
949
- var import_koishi2 = require("koishi");
950
- var ejs = __toESM(require("ejs"));
951
1142
  var name = "dota2tracker";
952
1143
  var usage = `
953
1144
  DOTA2Bot插件-提供自动追踪群友的最新对局的功能(需群友绑定),以及一系列查询功能。
954
- [本地化/dota2tracker](../../locales/dota2tracker)可以自定义英雄别名和位置代称
1145
+ [本地化/dota2tracker](../../locales/dota2tracker)可以自定义英雄别名和位置代称等文本内容
955
1146
  **更多信息请进入[插件主页](https://github.com/sjtdev/koishi-plugin-dota2tracker)与[更新日志](https://github.com/sjtdev/koishi-plugin-dota2tracker/blob/master/changelog.md)查看。**`;
956
- var inject = ["http", "database", "cron", "puppeteer"];
1147
+ var inject = ["http", "database", "cron", "puppeteer", "cache"];
957
1148
  var Config = import_koishi.Schema.intersect([
958
1149
  import_koishi.Schema.object({
959
- STRATZ_API_TOKEN: import_koishi.Schema.string().required().description("※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取。"),
1150
+ STRATZ_API_TOKEN: import_koishi.Schema.string().required().role("secret").description("※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取。"),
960
1151
  dataParsingTimeoutMinutes: import_koishi.Schema.number().default(60).min(0).max(1440).description("等待比赛数据解析的时间(单位:分钟)。如果数据解析时间超过等待时间,将直接生成战报而不再等待解析完成。"),
961
1152
  urlInMessageType: import_koishi.Schema.array(
962
1153
  import_koishi.Schema.union([
@@ -1012,36 +1203,56 @@ var Config = import_koishi.Schema.intersect([
1012
1203
  ]);
1013
1204
  var pendingMatches = [];
1014
1205
  var random = new import_koishi2.Random(() => Math.random());
1206
+ var days_30 = 2592e6;
1207
+ var GraphqlLanguageEnum = /* @__PURE__ */ ((GraphqlLanguageEnum2) => {
1208
+ GraphqlLanguageEnum2["en-US"] = "ENGLISH";
1209
+ GraphqlLanguageEnum2["zh-CN"] = "S_CHINESE";
1210
+ return GraphqlLanguageEnum2;
1211
+ })(GraphqlLanguageEnum || {});
1212
+ var constantLocales = {};
1015
1213
  async function apply(ctx, config) {
1016
- CONFIGS.STRATZ_API.TOKEN = config.STRATZ_API_TOKEN;
1017
- init(ctx.http, ctx.setTimeout);
1018
- ctx.i18n.define("zh-CN", require_zh_CN());
1019
- ctx.i18n.define("en-US", require_en_US());
1020
- const koishiLanguageTag = ctx.i18n.fallback(void 0).at(2);
1021
- const getLanguageTag = /* @__PURE__ */ __name(async function(session, channel) {
1022
- if (!session && !channel) return koishiLanguageTag;
1023
- const resolvedChannel = channel ?? await session?.getChannel(session.event.channel.id);
1024
- return resolvedChannel?.locales?.at(0) ?? koishiLanguageTag;
1214
+ init(ctx.http, ctx.setTimeout, config.STRATZ_API_TOKEN);
1215
+ for (const supportLanguageTag of Object.keys(GraphqlLanguageEnum)) {
1216
+ constantLocales[supportLanguageTag] = globRequire_locales_constants_json(`./locales/${supportLanguageTag}.constants.json`);
1217
+ ctx.i18n.define(supportLanguageTag, globRequire_locales_yml(`./locales/${supportLanguageTag}.yml`));
1218
+ ctx.i18n.define(supportLanguageTag, globRequire_locales_command_yml(`./locales/${supportLanguageTag}.command.yml`));
1219
+ ctx.i18n.define(supportLanguageTag, globRequire_locales_template_yml(`./locales/${supportLanguageTag}.template.yml`));
1220
+ }
1221
+ const getLanguageTag = /* @__PURE__ */ __name(async function(session, channel, channelId) {
1222
+ const resolvedChannel = channel ?? (await ctx.database.get("channel", { id: session?.event.channel.id ?? channelId }))?.at(0);
1223
+ return ctx.i18n.fallback((resolvedChannel?.locales ?? []).concat(Object.values(ctx.i18n.locales).map((locale) => Object.keys(locale).at(0)))).find((locale) => Object.keys(GraphqlLanguageEnum).some((language) => locale == language));
1025
1224
  }, "getLanguageTag");
1026
- ctx.command("订阅本群", "订阅后还需玩家在本群绑定SteamID").usage("订阅后还需玩家在本群绑定SteamID,BOT将订阅本群中已绑定玩家的新比赛数据,在STRATZ比赛解析完成后将比赛数据生成为图片战报发布至本群中。").action(async ({ session }) => {
1225
+ ctx.command("subscribe").alias("订阅本群").action(async ({ session }) => {
1027
1226
  if (session.guild) {
1028
- let currentGuild = (await ctx.database.get("dt_subscribed_guilds", { guildId: session.event.channel.id, platform: session.event.platform }))[0];
1029
- if (currentGuild) session.send("本群已订阅,无需重复订阅。");
1227
+ let currentGuild = (await ctx.database.get("dt_subscribed_guilds", {
1228
+ guildId: session.event.channel.id,
1229
+ platform: session.event.platform
1230
+ }))[0];
1231
+ if (currentGuild) session.send(session.text(".subscribed"));
1030
1232
  else {
1031
- ctx.database.create("dt_subscribed_guilds", { guildId: session.event.channel.id, platform: session.event.platform });
1032
- session.send("订阅成功。");
1233
+ ctx.database.create("dt_subscribed_guilds", {
1234
+ guildId: session.event.channel.id,
1235
+ platform: session.event.platform
1236
+ });
1237
+ session.send(session.text(".subscribe_success"));
1033
1238
  }
1034
1239
  }
1035
1240
  });
1036
- ctx.command("取消订阅", "取消订阅本群").action(async ({ session }) => {
1241
+ ctx.command("unsubscribe").alias("取消订阅").action(async ({ session }) => {
1037
1242
  if (session.guild) {
1038
- let cancelingGuild = (await ctx.database.get("dt_subscribed_guilds", { guildId: session.event.channel.id, platform: session.event.platform }))[0];
1243
+ let cancelingGuild = (await ctx.database.get("dt_subscribed_guilds", {
1244
+ guildId: session.event.channel.id,
1245
+ platform: session.event.platform
1246
+ }))[0];
1039
1247
  if (cancelingGuild) {
1040
- ctx.database.remove("dt_subscribed_guilds", { guildId: session.event.channel.id, platform: session.event.platform });
1041
- session.send("取消订阅成功。");
1248
+ ctx.database.remove("dt_subscribed_guilds", {
1249
+ guildId: session.event.channel.id,
1250
+ platform: session.event.platform
1251
+ });
1252
+ session.send(session.text(".cancel_success"));
1042
1253
  return;
1043
1254
  }
1044
- } else session.send("本群尚未订阅,无需取消订阅。");
1255
+ } else session.send(session.text(".not_subscribed"));
1045
1256
  });
1046
1257
  ctx.command("绑定 <steam_id> [nick_name]", "绑定SteamID,并起一个别名(也可以不起)").usage("将你的SteamID与你的账号绑定,若本群已订阅将会实时获取你的新比赛数据发布至群中。").example("绑定 123456789").example("绑定 123456789 张三").action(async ({ session }, steam_id, nick_name) => {
1047
1258
  if (session.guild) {
@@ -1049,7 +1260,11 @@ async function apply(ctx, config) {
1049
1260
  session.send("SteamID无效。");
1050
1261
  return;
1051
1262
  }
1052
- let sessionPlayer = (await ctx.database.get("dt_subscribed_players", { guildId: session.event.channel.id, platform: session.event.platform, userId: session.event.user.id }))[0];
1263
+ let sessionPlayer = (await ctx.database.get("dt_subscribed_players", {
1264
+ guildId: session.event.channel.id,
1265
+ platform: session.event.platform,
1266
+ userId: session.event.user.id
1267
+ }))[0];
1053
1268
  if (sessionPlayer) {
1054
1269
  session.send(
1055
1270
  `
@@ -1077,12 +1292,22 @@ async function apply(ctx, config) {
1077
1292
  别名:${nick_name || ""}
1078
1293
  SteamID:${steam_id}`.replace(/\n\s+/g, " ")
1079
1294
  );
1080
- ctx.database.create("dt_subscribed_players", { userId: session.event.user.id, guildId: session.event.channel.id, platform: session.event.platform, steamId: parseInt(steam_id), nickName: nick_name || null });
1295
+ ctx.database.create("dt_subscribed_players", {
1296
+ userId: session.event.user.id,
1297
+ guildId: session.event.channel.id,
1298
+ platform: session.event.platform,
1299
+ steamId: parseInt(steam_id),
1300
+ nickName: nick_name || null
1301
+ });
1081
1302
  }
1082
1303
  });
1083
1304
  ctx.command("取消绑定", "取消绑定你的个人信息").action(async ({ session }) => {
1084
1305
  if (session.guild) {
1085
- let sessionPlayer = (await ctx.database.get("dt_subscribed_players", { guildId: session.event.channel.id, platform: session.event.platform, userId: session.event.user.id }))[0];
1306
+ let sessionPlayer = (await ctx.database.get("dt_subscribed_players", {
1307
+ guildId: session.event.channel.id,
1308
+ platform: session.event.platform,
1309
+ userId: session.event.user.id
1310
+ }))[0];
1086
1311
  if (sessionPlayer) {
1087
1312
  await ctx.database.remove("dt_subscribed_players", sessionPlayer.id);
1088
1313
  session.send("取消绑定成功。");
@@ -1091,7 +1316,11 @@ async function apply(ctx, config) {
1091
1316
  });
1092
1317
  ctx.command("改名 <nick_name>", "修改绑定时设定的别名").example("改名 李四").action(async ({ session }, nick_name) => {
1093
1318
  if (session.guild) {
1094
- let sessionPlayer = (await ctx.database.get("dt_subscribed_players", { guildId: session.event.channel.id, platform: session.event.platform, userId: session.event.user.id }))[0];
1319
+ let sessionPlayer = (await ctx.database.get("dt_subscribed_players", {
1320
+ guildId: session.event.channel.id,
1321
+ platform: session.event.platform,
1322
+ userId: session.event.user.id
1323
+ }))[0];
1095
1324
  if (sessionPlayer) {
1096
1325
  if (!nick_name) {
1097
1326
  session.send("请输入你的别名。");
@@ -1111,7 +1340,11 @@ async function apply(ctx, config) {
1111
1340
  });
1112
1341
  ctx.command("查询群友", "查询本群已绑定的玩家").action(async ({ session }) => {
1113
1342
  if (session.guild) {
1114
- const subscribedPlayers = await ctx.database.get("dt_subscribed_players", { guildId: session.event.channel.id, platform: session.platform });
1343
+ const languageTag = await getLanguageTag(session);
1344
+ const subscribedPlayers = await ctx.database.get("dt_subscribed_players", {
1345
+ guildId: session.event.channel.id,
1346
+ platform: session.platform
1347
+ });
1115
1348
  if (!subscribedPlayers.length) {
1116
1349
  session.send("本群尚无绑定玩家。");
1117
1350
  return;
@@ -1124,20 +1357,26 @@ async function apply(ctx, config) {
1124
1357
  } catch (error) {
1125
1358
  }
1126
1359
  async function getUsers(subscribedPlayers2, memberList2) {
1127
- const playerSteamIds = { steamAccountIds: subscribedPlayers2.map((player) => player.steamId) };
1360
+ const playerSteamIds = {
1361
+ steamAccountIds: subscribedPlayers2.map((player) => player.steamId)
1362
+ };
1128
1363
  const queryResult = await query("PlayersInfoWith10MatchesForGuild", playerSteamIds);
1129
1364
  const playersInfo = queryResult.players;
1130
1365
  const users2 = [];
1131
1366
  for (const subscribedPlayer of subscribedPlayers2) {
1132
1367
  const queryPlayer = playersInfo.find((player) => player.steamAccount.id == subscribedPlayer.steamId);
1133
1368
  const queryMember = memberList2?.data.find((member) => member.user?.id == subscribedPlayer.userId);
1134
- users2.push({ ...subscribedPlayer, ...queryPlayer, ...queryMember });
1369
+ users2.push({
1370
+ ...subscribedPlayer,
1371
+ ...queryPlayer,
1372
+ ...queryMember
1373
+ });
1135
1374
  }
1136
1375
  return users2;
1137
1376
  }
1138
1377
  __name(getUsers, "getUsers");
1139
1378
  const users = await getUsers(subscribedPlayers, memberList);
1140
- session.send(await ctx.puppeteer.render(genImageHTML(users, "guild_member" /* GuildMember */, "guild_member" /* GuildMember */)));
1379
+ session.send(await ctx.puppeteer.render(await genImageHTML(users, "guild_member" /* GuildMember */, "guild_member" /* GuildMember */, ctx, languageTag)));
1141
1380
  } catch (error) {
1142
1381
  ctx.logger.error(error);
1143
1382
  session.send("查询群友失败。");
@@ -1145,53 +1384,118 @@ async function apply(ctx, config) {
1145
1384
  }
1146
1385
  }
1147
1386
  });
1148
- async function queryMatchAndSend(session, matchId) {
1387
+ async function queryMatchData(matchId) {
1149
1388
  try {
1389
+ let queryLocal = await ctx.cache.get("dt_previous_query_results", String(matchId));
1150
1390
  let matchQuery;
1151
- let queryLocal = await ctx.database.get("dt_previous_query_results", matchId, ["data"]);
1152
- if (queryLocal.length > 0) {
1153
- matchQuery = queryLocal[0].data;
1154
- ctx.database.set("dt_previous_query_results", matchQuery.match.id, { queryTime: /* @__PURE__ */ new Date() });
1155
- } else matchQuery = await query("MatchInfo", { matchId });
1156
- if (matchQuery.match.parsedDateTime)
1157
- ctx.database.upsert("dt_previous_query_results", (row) => [{ matchId: matchQuery.match.id, data: matchQuery, queryTime: /* @__PURE__ */ new Date() }]);
1158
- let match = getFormattedMatchData(matchQuery);
1159
- if (match && (match.parsedDateTime || import_moment.default.unix(match.endDateTime).isBefore((0, import_moment.default)().subtract(config.dataParsingTimeoutMinutes, "minutes")))) {
1160
- session.send((ctx.config.urlInMessageType.some((type) => type == "match") ? "https://stratz.com/matches/" + matchId : "") + await ctx.puppeteer.render(genImageHTML(match, config.template_match, "match" /* Match */)));
1391
+ if (queryLocal) {
1392
+ matchQuery = queryLocal;
1393
+ ctx.cache.set("dt_previous_query_results", String(matchQuery.match.id), queryLocal, days_30);
1161
1394
  } else {
1162
- pendingMatches.push({ matchId, guilds: [{ platform: session.event.platform, guildId: session.event.channel.id, players: [] }] });
1163
- session.send("比赛尚未解析,将在解析完成后发布。");
1395
+ matchQuery = await query("MatchInfo", { matchId });
1396
+ if (matchQuery.match?.parsedDateTime && matchQuery.match.players.filter((player) => player?.stats?.heroDamageReport?.dealtTotal).length > 0)
1397
+ ctx.cache.set("dt_previous_query_results", String(matchQuery.match.id), matchQuery, days_30);
1164
1398
  }
1399
+ return matchQuery;
1165
1400
  } catch (error) {
1166
- ctx.logger.error(error);
1167
- session.send("获取比赛信息失败。");
1168
- await ctx.database.remove("dt_previous_query_results", { matchId });
1401
+ await ctx.cache.delete("dt_previous_query_results", String(matchId));
1402
+ throw new Error("比赛数据查询阶段出错:", { cause: error });
1169
1403
  }
1170
1404
  }
1171
- __name(queryMatchAndSend, "queryMatchAndSend");
1172
- ctx.command("查询比赛 <match_id>", "查询比赛ID").usage("查询指定比赛ID的比赛数据,生成图片发布。").example("查询比赛 1234567890").action(async ({ session }, match_id) => {
1405
+ __name(queryMatchData, "queryMatchData");
1406
+ async function formatMatchData(matchQuery, languageTag) {
1407
+ try {
1408
+ let constantsQuery = await ctx.cache.get("dt_facets_constants", languageTag);
1409
+ if (!constantsQuery || // 缓存中没有 constants
1410
+ !matchQuery.constants.gameVersions?.[0]?.id || // 当前版本信息无效
1411
+ !constantsQuery.constants.gameVersions?.[0]?.id || // 缓存版本信息无效
1412
+ matchQuery.constants.gameVersions[0].id !== constantsQuery.constants.gameVersions[0].id)
1413
+ constantsQuery = await query("Constants", { language: GraphqlLanguageEnum[languageTag] });
1414
+ ctx.cache.set("dt_facets_constants", languageTag, constantsQuery, days_30);
1415
+ const match = getFormattedMatchData(matchQuery, constantsQuery);
1416
+ return match;
1417
+ } catch (error) {
1418
+ await ctx.cache.delete("dt_previous_query_results", String(matchQuery.match.id));
1419
+ throw new Error("比赛数据扩展阶段出错:", { cause: error });
1420
+ }
1421
+ }
1422
+ __name(formatMatchData, "formatMatchData");
1423
+ async function generateMatchMessage(match, languageTag, guild) {
1424
+ let broadMatchMessage = "";
1425
+ let idsToFind = guild.players.map((player) => player.steamId);
1426
+ let broadPlayers = match.players.filter((item) => idsToFind.includes(item.steamAccountId));
1427
+ for (let player of broadPlayers) {
1428
+ const random2 = new import_koishi2.Random(() => enhancedSimpleHashToSeed(`${match.id}-${player.steamAccountId}-${player.playerSlot}`));
1429
+ let comment;
1430
+ if (player.isRadiant == match.didRadiantWin) {
1431
+ if (player.deathContribution < 0.2 || player.killContribution > 0.75 || player.heroDamage / player.networth > 1.5 || player.towerDamage > 1e4 || player.imp > 0)
1432
+ comment = random2.pick(customConvertArrayOfString($t(languageTag, "dota2tracker.broadcast.WIN_POSITIVE")));
1433
+ else comment = random2.pick(customConvertArrayOfString($t(languageTag, "dota2tracker.broadcast.WIN_NEGATIVE")));
1434
+ } else {
1435
+ if (player.deathContribution < 0.25 || player.killContribution > 0.75 || player.heroDamage / player.networth > 1 || player.towerDamage > 5e3 || player.imp > 0)
1436
+ comment = random2.pick(customConvertArrayOfString($t(languageTag, "dota2tracker.broadcast.LOSE_NEGATIVE")));
1437
+ else comment = random2.pick(customConvertArrayOfString($t(languageTag, "dota2tracker.broadcast.LOSE_NEGATIVE")));
1438
+ }
1439
+ let broadPlayerMessage = $t(languageTag, "dota2tracker.broadcast.message", {
1440
+ name: player.steamAccount.name,
1441
+ hero_name: random2.pick(getHeroNicknames(player.hero.id, languageTag)),
1442
+ comment,
1443
+ kda: `${((player.kills + player.assists) / (player.deaths || 1)).toFixed(2)} [${player.kills}/${player.deaths}/${player.assists}]`,
1444
+ GPM_XPM: `${player.goldPerMinute}/${player.experiencePerMinute}`,
1445
+ lh_dn: `${player.numLastHits}/${player.numDenies}`,
1446
+ damage: `${player.heroDamage}/${player.towerDamage}`,
1447
+ kc_dc: `${(player.killContribution * 100).toFixed(2)}%/${(player.deathContribution * 100).toFixed(2)}%`
1448
+ });
1449
+ broadMatchMessage += broadPlayerMessage + "\n";
1450
+ }
1451
+ return broadMatchMessage;
1452
+ }
1453
+ __name(generateMatchMessage, "generateMatchMessage");
1454
+ async function generateMatchImage(match, languageTag) {
1455
+ const imageHTML = await genImageHTML(match, ctx.config.template_match, "match" /* Match */, ctx, languageTag);
1456
+ return await ctx.puppeteer.render(imageHTML);
1457
+ }
1458
+ __name(generateMatchImage, "generateMatchImage");
1459
+ ctx.command("查询比赛 <match_id>", "查询比赛ID").alias("querymatch").usage("查询指定比赛ID的比赛数据,生成图片发布。").example("查询比赛 1234567890").action(async ({ session }, match_id) => {
1173
1460
  if (!match_id) {
1174
1461
  session.send("请输入比赛ID。");
1175
1462
  return;
1176
1463
  }
1177
- if (!/^\d{10}$/.test(match_id)) {
1464
+ if (!/^\d{1,11}$/.test(match_id)) {
1178
1465
  session.send("比赛ID无效。");
1179
1466
  return;
1180
1467
  }
1181
- session.send("正在搜索对局详情,请稍后...");
1182
- queryMatchAndSend(session, match_id);
1468
+ await session.send("正在搜索对局详情,请稍后...");
1469
+ try {
1470
+ const languageTag = await getLanguageTag(session);
1471
+ const matchQuery = await queryMatchData(Number(match_id));
1472
+ const match = await formatMatchData(matchQuery, languageTag);
1473
+ const image = await generateMatchImage(match, languageTag);
1474
+ session.send((ctx.config.urlInMessageType.some((type) => type == "match") ? "https://stratz.com/matches/" + match.id : "") + image);
1475
+ } catch (error) {
1476
+ session.send("获取比赛信息失败。");
1477
+ ctx.logger.error(error);
1478
+ }
1183
1479
  });
1184
1480
  ctx.command("查询最近比赛 [input_data]", "查询玩家的最近比赛").usage("查询指定玩家的最近一场比赛的比赛数据,生成图片发布。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID").example("查询最近比赛 123456789").example("查询最近比赛 张三").action(async ({ session }, input_data) => {
1185
1481
  if (session.guild || !session.guild && input_data) {
1186
1482
  let sessionPlayer;
1187
1483
  if (!input_data) {
1188
- sessionPlayer = (await ctx.database.get("dt_subscribed_players", { guildId: session.event.channel.id, platform: session.event.platform, userId: session.event.user.id }))[0];
1484
+ sessionPlayer = (await ctx.database.get("dt_subscribed_players", {
1485
+ guildId: session.event.channel.id,
1486
+ platform: session.event.platform,
1487
+ userId: session.event.user.id
1488
+ }))[0];
1189
1489
  if (!sessionPlayer) {
1190
1490
  session.send("无参数时默认从已绑定SteamID玩家中寻找你的信息,但你似乎并没有绑定。\n请在本群绑定SteamID。(可输入【-绑定 -h】获取帮助)\n或在指令后跟上希望查询的SteamID或已绑定玩家的别名。");
1191
1491
  return;
1192
1492
  }
1193
1493
  }
1194
- let flagBindedPlayer = sessionPlayer || (await ctx.database.get("dt_subscribed_players", { guildId: session.event.channel.id, platform: session.event.platform, nickName: input_data }))[0];
1494
+ let flagBindedPlayer = sessionPlayer || (await ctx.database.get("dt_subscribed_players", {
1495
+ guildId: session.event.channel.id,
1496
+ platform: session.event.platform,
1497
+ nickName: input_data
1498
+ }))[0];
1195
1499
  if (!(flagBindedPlayer || /^\d{1,11}$/.test(input_data))) {
1196
1500
  session.send("SteamID不合法并且未在本群找到此玩家。");
1197
1501
  return;
@@ -1199,13 +1503,19 @@ async function apply(ctx, config) {
1199
1503
  let lastMatchId = 0;
1200
1504
  try {
1201
1505
  session.send("正在搜索对局详情,请稍后...");
1202
- lastMatchId = (await query("PlayersLastmatchRankinfo", { steamAccountIds: [parseInt(flagBindedPlayer?.steamId ?? input_data)] })).players[0].matches[0].id;
1506
+ lastMatchId = (await query("PlayersLastmatchRankinfo", {
1507
+ steamAccountIds: [parseInt(flagBindedPlayer?.steamId ?? input_data)]
1508
+ })).players[0].matches[0].id;
1203
1509
  } catch (error) {
1204
1510
  session.send("获取玩家最近比赛失败。");
1205
1511
  ctx.logger.error(error);
1206
1512
  return;
1207
1513
  }
1208
- queryMatchAndSend(session, lastMatchId);
1514
+ const languageTag = await getLanguageTag(session);
1515
+ const matchQuery = await queryMatchData(lastMatchId);
1516
+ const match = await formatMatchData(matchQuery, languageTag);
1517
+ const image = await generateMatchImage(match, languageTag);
1518
+ session.send((ctx.config.urlInMessageType.some((type) => type == "match") ? "https://stratz.com/matches/" + match.id : "") + image);
1209
1519
  } else {
1210
1520
  session.send("<p>指令调用失败。</p><p>当前不属于群聊状态,必须提供指定玩家的SteamID。</p>");
1211
1521
  }
@@ -1213,14 +1523,23 @@ async function apply(ctx, config) {
1213
1523
  ctx.command("查询玩家 <input_data>", "查询玩家信息,可指定英雄").usage("查询指定玩家的个人信息与最近战绩,生成图片发布。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID").option("hero", "-o <value:string> 查询玩家指定英雄使用情况(同其他英雄查询,可用简称与ID)").example("查询玩家 123456789").example("查询玩家 张三").example("查询玩家 张三 hero 敌法师").action(async ({ session, options }, input_data) => {
1214
1524
  if (session.guild || !session.guild && input_data) {
1215
1525
  let sessionPlayer;
1526
+ const languageTag = await getLanguageTag(session);
1216
1527
  if (!input_data) {
1217
- sessionPlayer = (await ctx.database.get("dt_subscribed_players", { guildId: session.event.channel.id, platform: session.event.platform, userId: session.event.user.id }))[0];
1528
+ sessionPlayer = (await ctx.database.get("dt_subscribed_players", {
1529
+ guildId: session.event.channel.id,
1530
+ platform: session.event.platform,
1531
+ userId: session.event.user.id
1532
+ }))[0];
1218
1533
  if (!sessionPlayer) {
1219
1534
  session.send("无参数时默认从已绑定SteamID玩家中寻找你的信息,但你似乎并没有绑定。\n请在本群绑定SteamID。(可输入【-绑定 -h】获取帮助)\n或在指令后跟上希望查询的SteamID或已绑定玩家的别名。");
1220
1535
  return;
1221
1536
  }
1222
1537
  }
1223
- let flagBindedPlayer = sessionPlayer || (await ctx.database.get("dt_subscribed_players", { guildId: session.event.channel.id, platform: session.event.platform, nickName: input_data }))[0];
1538
+ let flagBindedPlayer = sessionPlayer || (await ctx.database.get("dt_subscribed_players", {
1539
+ guildId: session.event.channel.id,
1540
+ platform: session.event.platform,
1541
+ nickName: input_data
1542
+ }))[0];
1224
1543
  if (!(flagBindedPlayer || /^\d{1,11}$/.test(input_data))) {
1225
1544
  session.send("SteamID不合法并且未在本群找到此玩家。");
1226
1545
  return;
@@ -1230,7 +1549,10 @@ async function apply(ctx, config) {
1230
1549
  let steamId = flagBindedPlayer?.steamId ?? input_data;
1231
1550
  let player;
1232
1551
  try {
1233
- player = (await query("PlayerInfoWith25Matches", { steamAccountId: steamId, heroIds: heroId })).player;
1552
+ player = (await query("PlayerInfoWith25Matches", {
1553
+ steamAccountId: steamId,
1554
+ heroIds: heroId
1555
+ })).player;
1234
1556
  let playerExtra = (await query("PlayerExtraInfo", {
1235
1557
  steamAccountId: steamId,
1236
1558
  matchCount: player.matchCount,
@@ -1273,10 +1595,12 @@ async function apply(ctx, config) {
1273
1595
  player.winCount = winCount;
1274
1596
  player.performance.imp = imp;
1275
1597
  player.dotaPlus = player.dotaPlus.filter((dpHero) => dpHero.heroId == heroId);
1598
+ player.genHero = {
1599
+ name: constantLocales[languageTag].dota2tracker.template.hero_names[heroId]
1600
+ };
1276
1601
  }
1277
- player.genHero = { name: HEROES_NAMES[(await session.getChannel(session.event.channel.id)).locales?.at(0) ?? "zh-CN"][heroId] };
1278
1602
  session.send(
1279
- (ctx.config.urlInMessageType.some((type) => type == "player") ? "https://stratz.com/players/" + player.steamAccount.id : "") + await ctx.puppeteer.render(genImageHTML(player, config.template_player, "player" /* Player */))
1603
+ (ctx.config.urlInMessageType.some((type) => type == "player") ? "https://stratz.com/players/" + player.steamAccount.id : "") + await ctx.puppeteer.render(await genImageHTML(player, config.template_player, "player" /* Player */, ctx, languageTag))
1280
1604
  );
1281
1605
  } catch (error) {
1282
1606
  ctx.logger.error(error);
@@ -1288,7 +1612,7 @@ async function apply(ctx, config) {
1288
1612
  });
1289
1613
  ctx.command("查询英雄 <input_data>", "查询英雄技能/面板信息").usage("查询英雄的技能说明与各项数据,生成图片发布。\n参数可输入英雄ID、英雄名、英雄常用别名").option("random", "-r 随机选择英雄").example("查询英雄 15").example("查询英雄 雷泽").example("查询英雄 电魂").action(async ({ session, options }, input_data) => {
1290
1614
  const languageTag = await getLanguageTag(session);
1291
- if (options.random) input_data = random.pick(Object.keys(HEROES_NAMES[languageTag]));
1615
+ if (options.random) input_data = random.pick(Object.keys(dotaconstants2.heroes));
1292
1616
  if (input_data) {
1293
1617
  let heroId = findingHero(input_data);
1294
1618
  if (!heroId) {
@@ -1303,7 +1627,12 @@ async function apply(ctx, config) {
1303
1627
  fa.abilities.forEach((ab) => {
1304
1628
  if (!hero.facets[i].abilities) hero.facets[i].abilities = [];
1305
1629
  if (hero.facets[i].description_loc !== ab.desc_loc)
1306
- hero.facets[i].abilities.push({ id: ab.id, name: ab.name, name_loc: ab.name_loc, description_ability_loc: formatHeroDesc(ab.desc_loc, ab.special_values, "facet" /* Facet */) });
1630
+ hero.facets[i].abilities.push({
1631
+ id: ab.id,
1632
+ name: ab.name,
1633
+ name_loc: ab.name_loc,
1634
+ description_ability_loc: formatHeroDesc(ab.desc_loc, ab.special_values, "facet" /* Facet */)
1635
+ });
1307
1636
  else hero.facets[i].description_loc = formatHeroDesc(hero.facets[i].description_loc, ab.special_values, "facet" /* Facet */);
1308
1637
  ab.ability_is_facet = true;
1309
1638
  ab.facet = hero.facets[i];
@@ -1318,7 +1647,13 @@ async function apply(ctx, config) {
1318
1647
  if (i < 0) return;
1319
1648
  if (facet) {
1320
1649
  if (!hero.facets[i].abilities) hero.facets[i].abilities = [];
1321
- hero.facets[i].abilities.push({ id: ab.id, name: ab.name, name_loc: ab.name_loc, description_ability_loc: formatHeroDesc(facet, ab.special_values, "facet" /* Facet */), attributes: [] });
1650
+ hero.facets[i].abilities.push({
1651
+ id: ab.id,
1652
+ name: ab.name,
1653
+ name_loc: ab.name_loc,
1654
+ description_ability_loc: formatHeroDesc(facet, ab.special_values, "facet" /* Facet */),
1655
+ attributes: []
1656
+ });
1322
1657
  }
1323
1658
  });
1324
1659
  hero.facets.forEach((facet) => {
@@ -1326,7 +1661,11 @@ async function apply(ctx, config) {
1326
1661
  svs.forEach((sv) => {
1327
1662
  if (sv.heading_loc) {
1328
1663
  if (!facet.abilities) facet.abilities = [];
1329
- facet.abilities.find((ability) => ab.id == ability.id)?.attributes.push({ heading_loc: sv.heading_loc, values: [...sv.facet_bonus.values], is_percentage: sv.is_percentage });
1664
+ facet.abilities.find((ability) => ab.id == ability.id)?.attributes.push({
1665
+ heading_loc: sv.heading_loc,
1666
+ values: [...sv.facet_bonus.values],
1667
+ is_percentage: sv.is_percentage
1668
+ });
1330
1669
  }
1331
1670
  });
1332
1671
  facet.description_loc = formatHeroDesc(facet.description_loc, svs, "facet" /* Facet */);
@@ -1355,7 +1694,10 @@ async function apply(ctx, config) {
1355
1694
  const specialValue = specialValues.find((sv) => sv.name === String(match2[1]));
1356
1695
  const replacement = specialValue?.bonuses.find((bonus) => bonus.name === talent.name)?.value;
1357
1696
  if (replacement !== void 0) {
1358
- replacements.push({ original: match2[0], replacement });
1697
+ replacements.push({
1698
+ original: match2[0],
1699
+ replacement
1700
+ });
1359
1701
  }
1360
1702
  }
1361
1703
  replacements.forEach(({ original, replacement }) => {
@@ -1366,7 +1708,7 @@ async function apply(ctx, config) {
1366
1708
  }
1367
1709
  });
1368
1710
  await session.send(
1369
- (ctx.config.urlInMessageType.some((type) => type == "hero") ? `https://wiki.dota2.com.cn/hero/${hero.shortName}.html` : "") + await ctx.puppeteer.render(genImageHTML(hero, config.template_hero, "hero" /* Hero */))
1711
+ (ctx.config.urlInMessageType.some((type) => type == "hero") ? `https://wiki.dota2.com.cn/hero/${hero["name"].match(/^npc_dota_hero_(.+)$/)[1]}.html` : "") + await ctx.puppeteer.render(await genImageHTML(hero, config.template_hero, "hero" /* Hero */, ctx, languageTag))
1370
1712
  );
1371
1713
  } catch (error) {
1372
1714
  ctx.logger.error(error);
@@ -1376,55 +1718,18 @@ async function apply(ctx, config) {
1376
1718
  session.send("请输入参数。");
1377
1719
  }
1378
1720
  });
1379
- ctx.command("查询英雄对战 <input_data:string>", "查询英雄近一周的最佳搭档与最佳克星英雄").usage("根据输入英雄查询最近一周比赛数据(传奇~万古分段)中与该英雄组合胜率最高英雄和与该英雄对抗胜率最低英雄。\n参数可输入英雄ID、英雄名、英雄常用别名").option("limit", "-l <value:number> 返回英雄个数(默认值 5)", { fallback: 5 }).option("filter", "-f <value:number> 过滤场数过低的组合(单位:%,默认值0.75)", { fallback: 0.5 }).example("查询英雄对战 敌法师 (无额外参数默认返回5个英雄,过滤舍弃场次占比0.75%以下)").example("查询英雄对战 敌法师 -l=10 -f=1 (返回10个英雄,过滤舍弃场次占比1%以下)").example("查询英雄对战 敌法师 -l 10 -f 1 (等同于上例,参数接空格也可使用)").action(async ({ session, options }, input_data) => {
1380
- if (input_data) {
1381
- const languageTag = await getLanguageTag(session);
1382
- let heroId = findingHero(input_data);
1383
- if (!heroId) {
1384
- session.send("未找到输入的英雄,请确认后重新输入。");
1385
- return;
1386
- }
1387
- try {
1388
- let heroStats = (await query("HeroMatchupWinrate", { heroId, take: Object.keys(dotaconstants2.heroes).length - 1 })).heroStats;
1389
- let withTopFive = heroStats.matchUp[0].with.filter((item) => item.matchCount / heroStats.matchUp[0].matchCountWith > Math.max(0, Math.min(5, options.filter)) / 100).map((item) => {
1390
- const winRate = item.winCount / item.matchCount;
1391
- return { ...item, winRate: winRate.toFixed(3) };
1392
- }).sort((a, b) => b.winRate - a.winRate).slice(0, Math.max(1, Math.min(Object.keys(dotaconstants2.heroes).length - 1, options.limit)));
1393
- let vsBottomFive = heroStats.matchUp[0].vs.filter((item) => item.matchCount / heroStats.matchUp[0].matchCountVs > Math.max(0, Math.min(5, options.filter)) / 100).map((item) => {
1394
- const winRate = item.winCount / item.matchCount;
1395
- return { ...item, winRate: winRate.toFixed(3) };
1396
- }).sort((a, b) => a.winRate - b.winRate).slice(0, Math.max(1, Math.min(Object.keys(dotaconstants2.heroes).length - 1, options.limit)));
1397
- session.send(
1398
- `你查询的英雄是${HEROES_NAMES[heroStats.matchUp[0].heroId][0]}(ID:${heroStats.matchUp[0].heroId}),
1399
- 以下是7天内传奇-万古分段比赛数据总结而来的搭档与克制关系
1400
- 最佳搭档(组合胜率前${options.limit}):${withTopFive.map((item) => `${HEROES_NAMES[languageTag][item.heroId2][0]}(胜率${(item.winRate * 100).toFixed(1)}%)`).join("、")}
1401
- 最佳克星(对抗胜率倒${options.limit}):${vsBottomFive.map((item) => `${HEROES_NAMES[languageTag][item.heroId2][0]}(胜率${(item.winRate * 100).toFixed(1)}%)`).join("、")}`
1402
- );
1403
- } catch (error) {
1404
- ctx.logger.error(error);
1405
- session.send("获取数据失败");
1406
- return;
1407
- }
1408
- }
1409
- });
1410
1721
  function findingHero(input) {
1411
1722
  const heroIds = Object.keys(dotaconstants2.heroes).map((id) => parseInt(id));
1412
1723
  let tid;
1413
- for (const loc of Object.keys(HEROES_NAMES)) {
1724
+ for (const loc of Object.keys(GraphqlLanguageEnum)) {
1414
1725
  for (const id_nicknames of getHeroNicknames(heroIds, loc)) {
1415
1726
  for (const [id, nicknames] of Object.entries(id_nicknames)) {
1416
- try {
1417
- for (const nickname of nicknames) {
1418
- if (input == nickname) return Number(id);
1419
- }
1420
- } catch {
1421
- continue;
1727
+ for (const nickname of nicknames) {
1728
+ if (input == nickname) return Number(id);
1422
1729
  }
1423
1730
  }
1424
1731
  }
1425
- }
1426
- for (const names of Object.values(HEROES_NAMES)) {
1427
- for (const [id, name2] of Object.entries(names)) {
1732
+ for (const [id, name2] of Object.entries(constantLocales[loc].dota2tracker.template.hero_names)) {
1428
1733
  if (input == name2) return Number(id);
1429
1734
  if (input == id) tid = input;
1430
1735
  }
@@ -1432,34 +1737,41 @@ async function apply(ctx, config) {
1432
1737
  return tid;
1433
1738
  }
1434
1739
  __name(findingHero, "findingHero");
1435
- function getHeroNicknames(heroIds, languageTag = koishiLanguageTag) {
1740
+ function getHeroNicknames(heroIds, languageTag) {
1436
1741
  if (heroIds === void 0) return [];
1437
1742
  const heroIdArray = Array.isArray(heroIds) ? heroIds : [heroIds];
1438
1743
  const result = [];
1439
1744
  for (const heroId of heroIdArray) {
1440
1745
  let content = [];
1441
1746
  try {
1442
- const rawContent = ctx.i18n.render([languageTag], [`dota2tracker.heroes.${heroId}`], {}).at(0)?.attrs?.content ?? "";
1747
+ const rawContent = ctx.i18n.render([languageTag], [`dota2tracker.heroes_nicknames.${heroId}`], {}).at(0)?.attrs?.content ?? "";
1443
1748
  content = JSON.parse(`[${rawContent}]`);
1444
1749
  } catch (error) {
1445
1750
  ctx.logger.error(`Failed to parse heroId ${heroId} content: ${error.message}`);
1446
1751
  content = [];
1447
1752
  }
1448
- result.push({ [heroId]: content });
1753
+ result.push({
1754
+ [heroId]: Array.from(/* @__PURE__ */ new Set([$t(languageTag, "dota2tracker.template.hero_names." + heroId), ...content]))
1755
+ });
1449
1756
  }
1450
1757
  return Array.isArray(heroIds) ? result : result[0][heroIds];
1451
1758
  }
1452
1759
  __name(getHeroNicknames, "getHeroNicknames");
1453
1760
  ctx.on("ready", async () => {
1454
1761
  ctx.model.extend("dt_subscribed_guilds", { id: "unsigned", guildId: "string", platform: "string" }, { autoInc: true });
1455
- ctx.model.extend("dt_subscribed_players", { id: "unsigned", userId: "string", guildId: "string", platform: "string", steamId: "integer", nickName: "string", rank: "json" }, { autoInc: true });
1456
- ctx.model.extend("dt_sended_match_id", { matchId: "unsigned", sendTime: "timestamp" }, { primary: "matchId" });
1457
- ctx.model.extend("dt_previous_query_results", { matchId: "unsigned", data: "json", queryTime: "timestamp" }, { primary: "matchId" });
1458
- ctx.cron("0 */6 * * *", () => {
1459
- const oneMonthAgo = (0, import_moment.default)().subtract(1, "months").toDate();
1460
- ctx.database.remove("dt_sended_match_id", { sendTime: { $lt: oneMonthAgo } });
1461
- ctx.database.remove("dt_previous_query_results", { queryTime: { $lt: oneMonthAgo } });
1462
- });
1762
+ ctx.model.extend(
1763
+ "dt_subscribed_players",
1764
+ {
1765
+ id: "unsigned",
1766
+ userId: "string",
1767
+ guildId: "string",
1768
+ platform: "string",
1769
+ steamId: "integer",
1770
+ nickName: "string",
1771
+ rank: "json"
1772
+ },
1773
+ { autoInc: true }
1774
+ );
1463
1775
  if (config.dailyReportSwitch) {
1464
1776
  ctx.cron(`0 ${config.dailyReportHours} * * *`, async function() {
1465
1777
  const oneDayAgo = (0, import_moment.default)().subtract(1, "days").unix();
@@ -1479,30 +1791,64 @@ async function apply(ctx, config) {
1479
1791
  const subscribedPlayersSteamIds = subscribedPlayersInGuild.map((player) => player.steamId).filter(function(value, index, self) {
1480
1792
  return self.indexOf(value) === index;
1481
1793
  });
1482
- const players = (await query("PlayersLastmatchRankinfo", { steamAccountIds: subscribedPlayersSteamIds })).players;
1794
+ const players = (await query("PlayersLastmatchRankinfo", {
1795
+ steamAccountIds: subscribedPlayersSteamIds
1796
+ })).players;
1483
1797
  const lastMatches = players.map((player) => player.matches[0]).filter((item, index, self) => index === self.findIndex((t) => t.id === item.id)).filter((match) => import_moment.default.unix(match.startDateTime).isAfter((0, import_moment.default)().subtract(1, "days"))).filter((match) => !pendingMatches.some((pendingMatch) => pendingMatch.matchId == match.id));
1484
- const sendedMatchesIds = (await ctx.database.get("dt_sended_match_id", { matchId: lastMatches.map((match) => match.id) }, ["matchId"])).map((match) => match.matchId);
1485
- lastMatches.filter((match) => !sendedMatchesIds.includes(match.id)).forEach((match) => {
1486
- const tempGuilds = [];
1487
- match.players.forEach((player) => {
1488
- subscribedPlayersInGuild.filter((subscribedPlayer) => subscribedPlayer.steamId === player.steamAccount.id).forEach((subscribedPlayer) => {
1489
- if (subscribedPlayer) {
1490
- const tempGuild = tempGuilds.find((guild) => guild.guildId == subscribedPlayer.guildId && guild.platform == subscribedPlayer.platform);
1491
- if (tempGuild) tempGuild.players.push(subscribedPlayer);
1492
- else tempGuilds.push({ guildId: subscribedPlayer.guildId, platform: subscribedPlayer.platform, players: [subscribedPlayer] });
1493
- }
1798
+ const sendedMatchesIds = [];
1799
+ for await (const sendedMatchesId of ctx.cache.keys("dt_sended_match_id")) {
1800
+ sendedMatchesIds.push(Number(sendedMatchesId));
1801
+ }
1802
+ await Promise.all(
1803
+ lastMatches.filter((match) => !sendedMatchesIds.includes(match.id)).map(async (match) => {
1804
+ const tempGuildsByLanguage = {};
1805
+ for (const player of match.players) {
1806
+ const subscribedPlayers = subscribedPlayersInGuild.filter((subscribedPlayer) => subscribedPlayer.steamId === player.steamAccount.id);
1807
+ await Promise.all(
1808
+ subscribedPlayers.map(async (subscribedPlayer) => {
1809
+ if (subscribedPlayer) {
1810
+ const languageTag = await getLanguageTag(void 0, void 0, subscribedPlayer.guildId);
1811
+ if (!tempGuildsByLanguage[languageTag]) {
1812
+ tempGuildsByLanguage[languageTag] = [];
1813
+ }
1814
+ const tempGuild = tempGuildsByLanguage[languageTag].find((guild) => guild.guildId === subscribedPlayer.guildId && guild.platform === subscribedPlayer.platform);
1815
+ if (tempGuild) {
1816
+ tempGuild.players.push(subscribedPlayer);
1817
+ } else {
1818
+ tempGuildsByLanguage[languageTag].push({
1819
+ guildId: subscribedPlayer.guildId,
1820
+ platform: subscribedPlayer.platform,
1821
+ players: [subscribedPlayer]
1822
+ });
1823
+ }
1824
+ }
1825
+ })
1826
+ );
1827
+ }
1828
+ pendingMatches.push({
1829
+ matchId: match.id,
1830
+ guilds: tempGuildsByLanguage,
1831
+ queryTime: /* @__PURE__ */ new Date()
1494
1832
  });
1495
- });
1496
- pendingMatches.push({ matchId: match.id, guilds: tempGuilds });
1497
- query("RequestMatchDataAnalysis", { matchId: match.id }).then(
1498
- (response) => ctx.logger.info(response.stratz.matchRetry ? "解析请求已成功发送至服务器。" : "解析请求发送失败。")
1499
- );
1500
- ctx.logger.info(
1501
- tempGuilds.map((guild) => `追踪到来自群组${guild.platform}:${guild.guildId}的用户${guild.players.map((player) => `[${player.nickName ?? ""}(${player.steamId})]`).join("、")}的尚未播报过的最新比赛 ${match.id}。`).join("")
1502
- );
1503
- });
1833
+ Object.entries(tempGuildsByLanguage).forEach(([languageTag, guilds]) => {
1834
+ ctx.logger.info(
1835
+ guilds.map(
1836
+ (guild) => `追踪到来自语言 ${languageTag} 群组 ${guild.platform}:${guild.guildId} 的用户 ${guild.players.map((player) => `[${player.nickName ?? ""}(${player.steamId})]`).join("、")} 的尚未播报过的最新比赛 ${match.id}。`
1837
+ ).join("")
1838
+ );
1839
+ });
1840
+ if (!match.parsedDateTime) {
1841
+ query("RequestMatchDataAnalysis", {
1842
+ matchId: match.id
1843
+ }).then((response) => ctx.logger.info(`比赛 ${match.id} 的` + (response.stratz.matchRetry ? "解析请求已成功发送至STRATZ服务器。" : "解析请求发送失败。")));
1844
+ }
1845
+ })
1846
+ );
1504
1847
  const rankMap = players.reduce((map, player) => {
1505
- map[player.steamAccount.id] = { rank: player.steamAccount.seasonRank, leader: player.steamAccount.seasonLeaderboardRank };
1848
+ map[player.steamAccount.id] = {
1849
+ rank: player.steamAccount.seasonRank,
1850
+ leader: player.steamAccount.seasonLeaderboardRank
1851
+ };
1506
1852
  return map;
1507
1853
  }, {});
1508
1854
  for (let subPlayer of subscribedPlayersInGuild) {
@@ -1524,9 +1870,10 @@ async function apply(ctx, config) {
1524
1870
  if (prevRank.medal !== currRank.medal || prevRank.star !== currRank.star && config.rankBroadStar || prevRank.leader !== currRank.leader && config.rankBroadLeader) {
1525
1871
  const guildMember = await ctx.bots.find((bot) => bot.platform == subPlayer.platform)?.getGuildMember?.(subPlayer.guildId, subPlayer.userId);
1526
1872
  const name2 = subPlayer.nickName ?? guildMember?.nick ?? players.find((player) => player.steamAccount.id == subPlayer.steamId)?.steamAccount.name ?? subPlayer.steamId;
1873
+ const languageTag = await getLanguageTag(void 0, void 0, subPlayer.guildId);
1527
1874
  if (config.rankBroadFun === true) {
1528
1875
  const img = await ctx.puppeteer.render(
1529
- genImageHTML(
1876
+ await genImageHTML(
1530
1877
  {
1531
1878
  name: name2,
1532
1879
  avatar: guildMember?.avatar ?? players.find((player) => subPlayer.steamId == player.steamAccount.id).steamAccount.avatar,
@@ -1535,13 +1882,15 @@ async function apply(ctx, config) {
1535
1882
  currRank
1536
1883
  },
1537
1884
  "rank" + (config.rankBroadFun ? "_fun" : ""),
1538
- "rank" /* Rank */
1885
+ "rank" /* Rank */,
1886
+ ctx,
1887
+ languageTag
1539
1888
  )
1540
1889
  );
1541
1890
  await ctx.broadcast([`${subPlayer.platform}:${subPlayer.guildId}`], img);
1542
1891
  } else {
1543
- const message = `群友 ${name2} 段位变动:${rank[prevRank.medal]}${prevRank.star} → ${rank[currRank.medal]}${currRank.star} `;
1544
- const img = await ctx.puppeteer.render(genImageHTML(currRank, "rank" + (config.rankBroadFun ? "2" : ""), "rank" /* Rank */));
1892
+ const message = `群友 ${name2} 段位变动:${$t(languageTag, "dota2tracker.template.ranks." + prevRank.medal)}${prevRank.star} → ${$t(languageTag, "dota2tracker.template.ranks." + currRank.medal)}${currRank.star} `;
1893
+ const img = await ctx.puppeteer.render(await genImageHTML(currRank, "rank" + (config.rankBroadFun ? "2" : ""), "rank" /* Rank */, ctx, languageTag));
1545
1894
  await ctx.broadcast([`${subPlayer.platform}:${subPlayer.guildId}`], message + img);
1546
1895
  }
1547
1896
  ctx.logger.info(`向 ${subPlayer.platform}:${subPlayer.guildId} 发布段位变动播报信息。`);
@@ -1556,47 +1905,26 @@ async function apply(ctx, config) {
1556
1905
  const now = (0, import_moment.default)();
1557
1906
  const pendingMatch = pendingMatches[(now.hours() * 60 + now.minutes()) % pendingMatches.length];
1558
1907
  try {
1559
- const languageTag = await getLanguageTag();
1560
- let matchQuery;
1561
- let queryLocal = await ctx.database.get("dt_previous_query_results", pendingMatch.matchId, ["data"]);
1562
- if (queryLocal.length > 0) {
1563
- matchQuery = queryLocal[0].data;
1564
- ctx.database.set("dt_previous_query_results", matchQuery.match.id, { queryTime: /* @__PURE__ */ new Date() });
1565
- } else matchQuery = await query("MatchInfo", { matchId: pendingMatch.matchId });
1566
- if (matchQuery.match.parsedDateTime || import_moment.default.unix(matchQuery.match.endDateTime).isBefore(now.subtract(config.dataParsingTimeoutMinutes, "minutes"))) {
1567
- if (matchQuery.match.parsedDateTime)
1568
- ctx.database.upsert("dt_previous_query_results", (row) => [{ matchId: matchQuery.match.id, data: matchQuery, queryTime: /* @__PURE__ */ new Date() }]);
1569
- let match = getFormattedMatchData(matchQuery);
1570
- pendingMatches = pendingMatches.filter((item) => item.matchId != match.id);
1571
- const img = await ctx.puppeteer.render(genImageHTML(match, config.template_match, "match" /* Match */));
1572
- for (let commingGuild of pendingMatch.guilds) {
1573
- let broadMatchMessage = "";
1574
- let idsToFind = commingGuild.players.map((player) => player.steamId);
1575
- let broadPlayers = match.players.filter((item) => idsToFind.includes(item.steamAccountId));
1576
- for (let player of broadPlayers) {
1577
- const random2 = new import_koishi2.Random(() => enhancedSimpleHashToSeed(`${match.id}-${player.steamAccountId}-${player.playerSlot}`));
1578
- let broadPlayerMessage = `${player.steamAccount.name}的${random2.pick(getHeroNicknames(player.hero.id, languageTag))}`;
1579
- if (player.isRadiant == match.didRadiantWin) {
1580
- if (player.deathContribution < 0.2 || player.killContribution > 0.75 || player.heroDamage / player.networth > 1.5 || player.towerDamage > 1e4 || player.imp > 0)
1581
- broadPlayerMessage += random2.pick(WIN_POSITIVE);
1582
- else broadPlayerMessage += random2.pick(WIN_NEGATIVE);
1583
- } else {
1584
- if (player.deathContribution < 0.25 || player.killContribution > 0.75 || player.heroDamage / player.networth > 1 || player.towerDamage > 5e3 || player.imp > 0)
1585
- broadPlayerMessage += random2.pick(LOSE_POSITIVE);
1586
- else broadPlayerMessage += random2.pick(LOSE_NEGATIVE);
1587
- }
1588
- broadPlayerMessage += `。
1589
- 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)}%`;
1590
- broadMatchMessage += broadPlayerMessage + "\n";
1908
+ let matchQuery = await queryMatchData(pendingMatch.matchId);
1909
+ if (matchQuery.match.parsedDateTime && matchQuery.match.players.filter((player) => player?.stats?.heroDamageReport?.dealtTotal).length > 0 || import_moment.default.unix(matchQuery.match.endDateTime).isBefore(now.subtract(config.dataParsingTimeoutMinutes, "minutes"))) {
1910
+ for (const languageTag of Object.keys(pendingMatch.guilds)) {
1911
+ let match = await formatMatchData(matchQuery, languageTag);
1912
+ const img = await generateMatchImage(match, languageTag);
1913
+ for (let commingGuild of pendingMatch.guilds[languageTag]) {
1914
+ let broadMatchMessage = await generateMatchMessage(match, languageTag, commingGuild);
1915
+ await ctx.broadcast(
1916
+ [`${commingGuild.platform}:${commingGuild.guildId}`],
1917
+ broadMatchMessage + (ctx.config.urlInMessageType.some((type) => type == "match") ? "https://stratz.com/matches/" + match.id : "") + img
1918
+ );
1919
+ ctx.logger.info(`比赛 ${match.id} ${match.parsedDateTime ? "已解析," : "已结束超过1小时仍未被解析,放弃等待解析直接"}生成图片并发布于${commingGuild.platform}:${commingGuild.guildId}。`);
1591
1920
  }
1592
- await ctx.broadcast([`${commingGuild.platform}:${commingGuild.guildId}`], broadMatchMessage + (ctx.config.urlInMessageType.some((type) => type == "match") ? "https://stratz.com/matches/" + match.id : "") + img);
1593
- ctx.logger.info(`${match.id}${match.parsedDateTime ? "已解析," : "已结束超过1小时仍未被解析,放弃等待解析直接"}生成图片并发布于${commingGuild.platform}:${commingGuild.guildId}。`);
1594
1921
  }
1595
- ctx.database.create("dt_sended_match_id", { matchId: match.id, sendTime: /* @__PURE__ */ new Date() });
1922
+ ctx.cache.set("dt_sended_match_id", String(pendingMatch.matchId), void 0, days_30);
1923
+ pendingMatches = pendingMatches.filter((item) => item.matchId != pendingMatch.matchId);
1596
1924
  } else ctx.logger.info("比赛 %d 尚未解析完成,继续等待。", matchQuery.match.id);
1597
1925
  } catch (error) {
1598
1926
  ctx.logger.error(error);
1599
- ctx.database.remove("dt_previous_query_results", { matchId: pendingMatch.matchId });
1927
+ await ctx.cache.delete("dt_previous_query_results", String(pendingMatch.matchId));
1600
1928
  }
1601
1929
  }
1602
1930
  });
@@ -1658,7 +1986,7 @@ KDA:${((player.kills + player.assists) / (player.deaths || 1)).toFixed(2)} [${
1658
1986
  await ctx.broadcast(
1659
1987
  [`${guild.platform}:${guild.guildId}`],
1660
1988
  await ctx.puppeteer.render(
1661
- genImageHTML(
1989
+ await genImageHTML(
1662
1990
  {
1663
1991
  title,
1664
1992
  players: currentsubscribedPlayers.sort((a, b) => {
@@ -1670,7 +1998,9 @@ KDA:${((player.kills + player.assists) / (player.deaths || 1)).toFixed(2)} [${
1670
1998
  showCombi
1671
1999
  },
1672
2000
  "daily",
1673
- "report" /* Report */
2001
+ "report" /* Report */,
2002
+ ctx,
2003
+ await getLanguageTag(void 0, void 0, guild.guildId)
1674
2004
  )
1675
2005
  )
1676
2006
  );
@@ -1684,41 +2014,58 @@ KDA:${((player.kills + player.assists) / (player.deaths || 1)).toFixed(2)} [${
1684
2014
  __name(report, "report");
1685
2015
  ctx.on("dispose", async () => {
1686
2016
  });
1687
- }
1688
- __name(apply, "apply");
1689
- function genImageHTML(data, template, type) {
1690
- const templatePath = import_path2.default.join(`./node_modules/@sjtdev/koishi-plugin-${name}/template/${type}`, template + ".ejs");
1691
- const templateData = {
1692
- data,
1693
- utils: utils_exports,
1694
- ImageType,
1695
- ImageFormat,
1696
- d2a: dotaconstants_add_exports,
1697
- dotaconstants: dotaconstants2,
1698
- moment: import_moment.default,
1699
- escapeHTML: /* @__PURE__ */ __name(function escapeHTML(str) {
1700
- if (str == null) return "";
1701
- return str.replace(/[&<>"']/g, function(match) {
1702
- const escape = {
1703
- "&": "&amp;",
1704
- "<": "&lt;",
1705
- ">": "&gt;",
1706
- '"': "&quot;",
1707
- "'": "&#39;"
1708
- };
1709
- return escape[match];
2017
+ function $t(languageTag, key, param) {
2018
+ const keys = Array.isArray(key) ? key : key.split(".");
2019
+ const params = Array.isArray(param) ? param : [param];
2020
+ const constantTranslation = keys.reduce((result2, k) => {
2021
+ return result2?.[k] ?? null;
2022
+ }, constantLocales[languageTag] || {});
2023
+ if (constantTranslation) {
2024
+ if (Array.isArray(params)) {
2025
+ return constantTranslation.replace(/\{(\d+)\}/g, (_, index) => params[+index] || "");
2026
+ }
2027
+ if (typeof params === "object" && params !== null) {
2028
+ return constantTranslation.replace(/\{(\w+)\}/g, (_, key2) => params[key2] || "");
2029
+ }
2030
+ return constantTranslation;
2031
+ }
2032
+ const originalKey = Array.isArray(key) ? key : [key];
2033
+ const result = ctx.i18n.render([languageTag], originalKey, param ?? {}).map((element) => element?.attrs?.content).join("") ?? "";
2034
+ if (result == key) return;
2035
+ return result;
2036
+ }
2037
+ __name($t, "$t");
2038
+ async function genImageHTML(data, template, type, ctx2, languageTag) {
2039
+ const templatePath = import_path2.default.join(`./node_modules/@sjtdev/koishi-plugin-${name}/template/${type}`, template + ".ejs");
2040
+ const templateData = {
2041
+ data,
2042
+ utils: utils_exports,
2043
+ ImageType,
2044
+ ImageFormat,
2045
+ dotaconstants: dotaconstants2,
2046
+ moment: import_moment.default,
2047
+ eh: escapeHTML,
2048
+ $t: templateI18nHelper,
2049
+ languageTag
2050
+ };
2051
+ function templateI18nHelper(key, param) {
2052
+ return $t(languageTag, key, param);
2053
+ }
2054
+ __name(templateI18nHelper, "templateI18nHelper");
2055
+ try {
2056
+ const html = await ejs.renderFile(templatePath, templateData, {
2057
+ strict: false
1710
2058
  });
1711
- }, "escapeHTML")
1712
- };
1713
- let result = "";
1714
- ejs.renderFile(templatePath, templateData, { strict: false }, (err, html) => {
1715
- if (err) throw err;
1716
- else result = html;
1717
- });
1718
- if (process.env.NODE_ENV === "development") import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.html", result);
1719
- return result;
2059
+ if (process.env.NODE_ENV === "development") import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.html", html);
2060
+ return html;
2061
+ } catch (err) {
2062
+ ctx2.logger.error("Error rendering EJS template:", err);
2063
+ throw err;
2064
+ }
2065
+ }
2066
+ __name(genImageHTML, "genImageHTML");
1720
2067
  }
1721
- __name(genImageHTML, "genImageHTML");
2068
+ __name(apply, "apply");
1722
2069
  function enhancedSimpleHashToSeed(inputString) {
1723
2070
  const encoded = btoa(inputString);
1724
2071
  let total = 0;
@@ -1732,6 +2079,28 @@ function enhancedSimpleHashToSeed(inputString) {
1732
2079
  return total % 1e3 / 1e3;
1733
2080
  }
1734
2081
  __name(enhancedSimpleHashToSeed, "enhancedSimpleHashToSeed");
2082
+ function escapeHTML(str) {
2083
+ if (str == null) return "";
2084
+ return str.replace(/[&<>"']/g, function(match) {
2085
+ const escape = {
2086
+ "&": "&amp;",
2087
+ "<": "&lt;",
2088
+ ">": "&gt;",
2089
+ '"': "&quot;",
2090
+ "'": "&#39;"
2091
+ };
2092
+ return escape[match];
2093
+ });
2094
+ }
2095
+ __name(escapeHTML, "escapeHTML");
2096
+ function customConvertArrayOfString(str) {
2097
+ try {
2098
+ return JSON.parse(`[${str}]`);
2099
+ } catch (error) {
2100
+ throw error;
2101
+ }
2102
+ }
2103
+ __name(customConvertArrayOfString, "customConvertArrayOfString");
1735
2104
  // Annotate the CommonJS export names for ESM import in node:
1736
2105
  0 && (module.exports = {
1737
2106
  Config,