@sjtdev/koishi-plugin-dota2tracker 1.5.0-pre.4 → 1.5.0-pre.5
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 +381 -21
- package/package.json +2 -2
- package/readme.md +1 -4
- package/template/hero/hero_1.ejs +3 -3
- package/template/item/item/recipe.ejs +51 -0
- package/template/item/item/style.css +243 -0
- package/template/item/item.ejs +137 -0
- package/template/item/itemlist.ejs +93 -0
- package/template/match/match_1.ejs +1 -1
- package/template/match/match_2/original.ejs +1 -1
- package/template/match/match_2+/charts.ejs +1 -1
- package/template/match/match_2+/lane_outcome.ejs +1 -1
- package/template/match/match_2+.ejs +1 -1
package/lib/index.js
CHANGED
|
@@ -38,14 +38,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
38
38
|
// src/locales/en-US.schema.yml
|
|
39
39
|
var require_en_US_schema = __commonJS({
|
|
40
40
|
"src/locales/en-US.schema.yml"(exports2, module2) {
|
|
41
|
-
module2.exports = { _config: { base: { $desc: "Basic Settings", STRATZ_API_TOKEN: "Required. API TOKEN from stratz.com, available at https://stratz.com/api.", dataParsingTimeoutMinutes: "Time to wait for match data parsing (in minutes). If the data parsing time exceeds the waiting time, the report will be generated directly without waiting for the parsing to complete.", urlInMessageType: { $desc: "Include links in messages, <br/>please select the message type:", $inner: ["Include stratz match page link in match query and report messages", "Include stratz player page link in player information query messages", "Include Dota Encyclopedia hero page link in hero data query messages"] },
|
|
41
|
+
module2.exports = { _config: { base: { $desc: "Basic Settings", STRATZ_API_TOKEN: "Required. API TOKEN from stratz.com, available at https://stratz.com/api.", dataParsingTimeoutMinutes: "Time to wait for match data parsing (in minutes). If the data parsing time exceeds the waiting time, the report will be generated directly without waiting for the parsing to complete.", proxyAddress: "Proxy address. Leave blank to disable the proxy." }, message: { $desc: "Message Settings", urlInMessageType: { $desc: "Include links in messages, <br/>please select the message type:", $inner: ["Include stratz match page link in match query and report messages", "Include stratz player page link in player information query messages", "Include Dota Encyclopedia hero page link in hero data query messages"] }, rankBroadSwitch: "Rank change broadcast", rankBroadStar: "Star change broadcast", rankBroadLeader: "Leaderboard rank change broadcast", rankBroadFun: "Fun broadcast template", maxSendItemCount: "Maximum number of item images to send<br/>When exceeded, the following option determines whether to send the item list", showItemListAtTooMuchItems: "Send item list when exceeding max count<br/>Controls whether to send the item list image when search results exceed maxSendItemCount", customItemAlias: { $desc: "Custom item aliases<br/>\nAdd additional aliases when built-in list is insufficient. \nFor widely-used missing aliases, please submit issues/pull requests to the source repository.<br/>\n(Example **Keyword**: Blink Dagger,**Alias**: Blink)", keyword: "Keyword", alias: "Alias" } }, report: { $desc: "Summary Settings", dailyReportSwitch: "Daily Report Function", dailyReportHours: "Daily report time in hours", dailyReportShowCombi: "Show combinations in daily report", weeklyReportSwitch: "Weekly Report Function", weeklyReportDayHours: "Weekly report published on (day) at (hour)", weeklyReportShowCombi: "Show combinations in weekly report" }, template: { $desc: "Template Settings", template_match: "Template used to generate match information images, see https://sjtdev.github.io/koishi-plugin-dota2tracker/template-match.html for template display.", template_player: "Template used to generate player information images. (Currently only one template available)", template_hero: "Template used to generate hero information images. (Currently only one template available)", playerRankEstimate: "Estimate the rank of players without a rank in the player template <br>Estimated rank will be displayed as a gray image" } } };
|
|
42
42
|
}
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
// src/locales/zh-CN.schema.yml
|
|
46
46
|
var require_zh_CN_schema = __commonJS({
|
|
47
47
|
"src/locales/zh-CN.schema.yml"(exports2, module2) {
|
|
48
|
-
module2.exports = { _config: { base: { $desc: "基础设置", STRATZ_API_TOKEN: "※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取。", dataParsingTimeoutMinutes: "等待比赛数据解析的时间(单位:分钟)。如果数据解析时间超过等待时间,将直接生成战报而不再等待解析完成。", urlInMessageType: { $desc: "在消息中附带链接,<br/>请选择消息类型:", $inner: ["在查询比赛与战报消息中附带stratz比赛页面链接", "在查询玩家信息消息中附带stratz玩家页面链接", "在查询英雄数据消息中附带刀塔百科对应英雄页面链接"] },
|
|
48
|
+
module2.exports = { _config: { base: { $desc: "基础设置", STRATZ_API_TOKEN: "※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取。", dataParsingTimeoutMinutes: "等待比赛数据解析的时间(单位:分钟)。如果数据解析时间超过等待时间,将直接生成战报而不再等待解析完成。", proxyAddress: "代理地址,留空时不使用代理" }, message: { $desc: "消息设置", urlInMessageType: { $desc: "在消息中附带链接,<br/>请选择消息类型:", $inner: ["在查询比赛与战报消息中附带stratz比赛页面链接", "在查询玩家信息消息中附带stratz玩家页面链接", "在查询英雄数据消息中附带刀塔百科对应英雄页面链接"] }, rankBroadSwitch: "段位变动播报", rankBroadStar: "星级变动播报", rankBroadLeader: "冠绝名次变动播报", rankBroadFun: "整活播报模板", maxSendItemCount: "最大发送物品图片数量,<br/> 当超过指定数量时将由下方选项决定是否发送查询结果的物品列表图片", showItemListAtTooMuchItems: "在查询结果的物品数量超过指定数量时,是否发送查询结果的物品列表图片", customItemAlias: { $desc: "额外物品别名设置<br/>当插件内置的[物品别名列表](https://github.com/sjtdev/koishi-plugin-dota2tracker/blob/master/src/locales/zh-CN.constants.json#L304-L407)中没有想要的物品别名可在此处追加,如果是插件疏漏的广为人知的物品别名推荐到源码仓库提交issue或pull request完善列表。<br/>(例如 **关键词**: 闪烁匕首,**别名**: 跳刀)", keyword: "关键词", alias: "别名" } }, report: { $desc: "总结设置", dailyReportSwitch: "日报功能", dailyReportHours: "日报时间小时", dailyReportShowCombi: "日报是否显示组合", weeklyReportSwitch: "周报功能", weeklyReportDayHours: "周报发布于周(几)的(几)点", weeklyReportShowCombi: "周报是否显示组合" }, template: { $desc: "模板设置", template_match: "生成比赛信息图片使用的模板,见 https://sjtdev.github.io/koishi-plugin-dota2tracker/template-match.html 有模板展示。", template_player: "生成玩家信息图片使用的模板。(目前仅有一张模板)", template_hero: "生成英雄信息图片使用的模板。(目前仅有一张模板)", playerRankEstimate: "在player模板中对没有段位的玩家进行段位估算 <br>估算的段位将以灰色图片显示" } } };
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
51
|
|
|
@@ -307,7 +307,53 @@ var require_en_US_constants = __commonJS({
|
|
|
307
307
|
shard: "Aghanim's Shard",
|
|
308
308
|
attack: "ATTACK",
|
|
309
309
|
defense: "DEFENSE",
|
|
310
|
-
mobility: "MOBILITY"
|
|
310
|
+
mobility: "MOBILITY",
|
|
311
|
+
item_token: {
|
|
312
|
+
health: "Health",
|
|
313
|
+
mana: "Mana",
|
|
314
|
+
armor: "Armor",
|
|
315
|
+
damage: "Damage",
|
|
316
|
+
str: "Strength",
|
|
317
|
+
int: "Intelligence",
|
|
318
|
+
agi: "Agility",
|
|
319
|
+
all: "All Attributes",
|
|
320
|
+
primary_attribute: "Primary Attribute",
|
|
321
|
+
attack: "Attack Speed",
|
|
322
|
+
attack_pct: "Base Attack Speed Percentage",
|
|
323
|
+
hp_regen: "Health Regeneration",
|
|
324
|
+
lifesteal: "Lifesteal",
|
|
325
|
+
mana_regen: "Mana Regeneration",
|
|
326
|
+
mana_regen_aura: "Mana Regeneration Aura",
|
|
327
|
+
spell_amp: "Spell Damage",
|
|
328
|
+
debuff_amp: "Debuff Duration",
|
|
329
|
+
move_speed: "Movement Speed",
|
|
330
|
+
evasion: "Evasion",
|
|
331
|
+
spell_resist: "Magic Resistance",
|
|
332
|
+
spell_lifesteal: "Spell Lifesteal",
|
|
333
|
+
spell_lifesteal_hero_attacks: "Attacks on Heroes",
|
|
334
|
+
spell_lifesteal_hero_spells: "Abilities on Heroes",
|
|
335
|
+
spell_lifesteal_creep_attacks: "Attacks on Creeps",
|
|
336
|
+
spell_lifesteal_creep_spells: "Abilities on Creeps",
|
|
337
|
+
lifesteal_hero_attacks: "Attacks on Heroes",
|
|
338
|
+
lifesteal_hero_spells: "Abilities on Heroes",
|
|
339
|
+
lifesteal_creep_attacks: "Attacks on Creeps",
|
|
340
|
+
lifesteal_creep_spells: "Abilities on Creeps",
|
|
341
|
+
selected_attrib: "Selected Attribute",
|
|
342
|
+
attack_range: "Attack Range <font color='#7d7d7d'>(Ranged Only)</font>",
|
|
343
|
+
attack_range_melee: "Attack Range <font color='#7d7d7d'>(Melee Only)</font>",
|
|
344
|
+
attack_range_all: "Attack Range <font color='#7d7d7d'>(Melee & Ranged)</font>",
|
|
345
|
+
cast_range: "Cast Range",
|
|
346
|
+
status_resist: "Status Resistance",
|
|
347
|
+
projectile_speed: "Projectile Speed",
|
|
348
|
+
manacost_reduction: "Manacost Reduction",
|
|
349
|
+
cooldown_reduction: "Cooldown Reduction",
|
|
350
|
+
max_mana_percentage: "Max Mana Bonus",
|
|
351
|
+
slow_resistance: "Slow Resistance",
|
|
352
|
+
aoe_bonus: "AoE Bonus",
|
|
353
|
+
exclusive_movespeed: "Boot Movement Speed",
|
|
354
|
+
healing_amp: "Outgoing Heal Amplification"
|
|
355
|
+
},
|
|
356
|
+
recipe: "Recipe"
|
|
311
357
|
}
|
|
312
358
|
}
|
|
313
359
|
};
|
|
@@ -572,7 +618,157 @@ var require_zh_CN_constants = __commonJS({
|
|
|
572
618
|
shard: "阿哈利姆魔晶",
|
|
573
619
|
attack: "进攻",
|
|
574
620
|
defense: "防守",
|
|
575
|
-
mobility: "机动"
|
|
621
|
+
mobility: "机动",
|
|
622
|
+
item_token: {
|
|
623
|
+
health: "生命值",
|
|
624
|
+
mana: "魔法值",
|
|
625
|
+
armor: "护甲",
|
|
626
|
+
damage: "攻击力",
|
|
627
|
+
str: "力量",
|
|
628
|
+
int: "智力",
|
|
629
|
+
agi: "敏捷",
|
|
630
|
+
all: "全属性",
|
|
631
|
+
primary_attribute: "主属性",
|
|
632
|
+
attack: "攻击速度",
|
|
633
|
+
attack_pct: "基础攻击速度",
|
|
634
|
+
hp_regen: "生命恢复",
|
|
635
|
+
lifesteal: "吸血",
|
|
636
|
+
mana_regen: "魔法恢复",
|
|
637
|
+
mana_regen_aura: "魔法恢复光环",
|
|
638
|
+
spell_amp: "技能伤害",
|
|
639
|
+
debuff_amp: "负面状态持续时间",
|
|
640
|
+
move_speed: "移动速度",
|
|
641
|
+
evasion: "闪避",
|
|
642
|
+
spell_resist: "魔法抗性",
|
|
643
|
+
spell_lifesteal: "技能吸血",
|
|
644
|
+
spell_lifesteal_hero_attacks: "对英雄的攻击",
|
|
645
|
+
spell_lifesteal_hero_spells: "对英雄的技能",
|
|
646
|
+
spell_lifesteal_creep_attacks: "对非英雄的攻击",
|
|
647
|
+
spell_lifesteal_creep_spells: "对非英雄的技能",
|
|
648
|
+
lifesteal_hero_attacks: "对英雄的攻击",
|
|
649
|
+
lifesteal_hero_spells: "对英雄的技能",
|
|
650
|
+
lifesteal_creep_attacks: "对非英雄的攻击",
|
|
651
|
+
lifesteal_creep_spells: "对非英雄的技能",
|
|
652
|
+
selected_attrib: "所选属性",
|
|
653
|
+
attack_range: "攻击距离<font color='#7d7d7d'>(仅对远程有效)</font>",
|
|
654
|
+
attack_range_melee: "攻击距离<font color='#7d7d7d'>(仅对近战有效)</font>",
|
|
655
|
+
attack_range_all: "攻击距离<font color='#7d7d7d'>(近战和远程)</font>",
|
|
656
|
+
cast_range: "施法距离",
|
|
657
|
+
status_resist: "状态抗性",
|
|
658
|
+
projectile_speed: "弹道速度",
|
|
659
|
+
manacost_reduction: "魔法消耗降低",
|
|
660
|
+
cooldown_reduction: "冷却时间减少",
|
|
661
|
+
max_mana_percentage: "额外最大魔法值",
|
|
662
|
+
slow_resistance: "减速抗性",
|
|
663
|
+
aoe_bonus: "作用范围加成",
|
|
664
|
+
exclusive_movespeed: "移动速度加成",
|
|
665
|
+
healing_amp: "对外治疗增强"
|
|
666
|
+
},
|
|
667
|
+
recipe: "图纸"
|
|
668
|
+
},
|
|
669
|
+
items_alias: {
|
|
670
|
+
"3800": ["圣者遗物"],
|
|
671
|
+
跳刀: ["闪烁匕首"],
|
|
672
|
+
力量跳刀: ["盛势闪光"],
|
|
673
|
+
敏捷跳刀: ["迅疾闪光"],
|
|
674
|
+
智力跳刀: ["秘奥闪光"],
|
|
675
|
+
补刀斧: ["压制之刃"],
|
|
676
|
+
仙草: ["仙灵之火"],
|
|
677
|
+
仙火: ["仙灵之火"],
|
|
678
|
+
魂泪: ["凝魂之露"],
|
|
679
|
+
鞋垫: ["风灵之纹"],
|
|
680
|
+
银月: ["银月之晶"],
|
|
681
|
+
树枝: ["铁树枝干"],
|
|
682
|
+
草鞋: ["速度之靴"],
|
|
683
|
+
魔棒: ["魔棒", "魔杖"],
|
|
684
|
+
大魔棒: ["魔杖"],
|
|
685
|
+
绿杖: ["幽魂权杖"],
|
|
686
|
+
小蓝: ["净化药水"],
|
|
687
|
+
蓝瓶: ["净化药水"],
|
|
688
|
+
大药: ["治疗药膏"],
|
|
689
|
+
粉: ["显影之尘"],
|
|
690
|
+
瓶子: ["魔瓶"],
|
|
691
|
+
假眼: ["侦察守卫"],
|
|
692
|
+
真眼: ["岗哨守卫"],
|
|
693
|
+
吃树: ["树之祭祀"],
|
|
694
|
+
TP: ["回城卷轴"],
|
|
695
|
+
飞鞋: ["远行鞋"],
|
|
696
|
+
相位: ["相位鞋"],
|
|
697
|
+
鹰角弓: ["鹰歌弓"],
|
|
698
|
+
大斧: ["掠夺者之斧"],
|
|
699
|
+
回5: ["治疗指环"],
|
|
700
|
+
假腿: ["动力鞋"],
|
|
701
|
+
点金: ["迈达斯之手"],
|
|
702
|
+
系带: ["怨灵系带"],
|
|
703
|
+
挂件: ["空灵挂件"],
|
|
704
|
+
骨灰: ["影之灵龛", "魂之灵瓮"],
|
|
705
|
+
羊刀: ["邪恶镰刀"],
|
|
706
|
+
紫苑: ["紫怨", "血棘"],
|
|
707
|
+
大紫怨: ["血棘"],
|
|
708
|
+
大紫苑: ["血棘"],
|
|
709
|
+
紫怨: ["血棘"],
|
|
710
|
+
血辣: ["血棘"],
|
|
711
|
+
连击刀: ["回音战刃"],
|
|
712
|
+
吹风: ["Eul的神圣法杖", "风之杖"],
|
|
713
|
+
大吹风: ["风之杖"],
|
|
714
|
+
以太: ["以太透镜"],
|
|
715
|
+
推推: ["原力法杖", "飓风长戟"],
|
|
716
|
+
推推棒: ["原力法杖", "飓风长戟"],
|
|
717
|
+
大推推: ["飓风长戟"],
|
|
718
|
+
大根: ["达贡之神力"],
|
|
719
|
+
A杖: ["阿哈利姆神杖"],
|
|
720
|
+
刷新: ["刷新球"],
|
|
721
|
+
强袭: ["强袭胸甲"],
|
|
722
|
+
龙心: ["恐鳌之心"],
|
|
723
|
+
BKB: ["黑皇杖"],
|
|
724
|
+
不朽盾: ["不朽之守护"],
|
|
725
|
+
冰甲: ["希瓦的守护"],
|
|
726
|
+
莲花: ["清莲宝珠"],
|
|
727
|
+
盘子: ["永恒之盘"],
|
|
728
|
+
大骨灰: ["魂之灵瓮"],
|
|
729
|
+
法式泳衣: ["永世法衣"],
|
|
730
|
+
MKB: ["金箍棒"],
|
|
731
|
+
大炮: ["代达罗斯之殇"],
|
|
732
|
+
晕锤: ["碎颅锤", "深渊之刃"],
|
|
733
|
+
分身: ["幻影斧"],
|
|
734
|
+
隐刀: ["影刃", "白银之锋"],
|
|
735
|
+
大隐刀: ["白银之锋"],
|
|
736
|
+
大电锤: ["雷神之锤"],
|
|
737
|
+
电锤: ["雷神之锤", "漩涡"],
|
|
738
|
+
冰眼: ["斯嘉蒂之眼"],
|
|
739
|
+
大支配: ["统御头盔"],
|
|
740
|
+
支配: ["统御头盔"],
|
|
741
|
+
雷托斯: ["缚灵索"],
|
|
742
|
+
暗灭: ["黯灭"],
|
|
743
|
+
疯脸: ["疯狂面具"],
|
|
744
|
+
散失: ["净魂之刃", "散魂剑"],
|
|
745
|
+
大散失: ["散魂剑"],
|
|
746
|
+
虚灵刀: ["虚灵之刃"],
|
|
747
|
+
魂戒: ["灵魂之戒"],
|
|
748
|
+
秘法鞋: ["奥术鞋"],
|
|
749
|
+
毒球: ["淬毒之珠"],
|
|
750
|
+
减甲球: ["枯萎之珠"],
|
|
751
|
+
大毒球: ["腐蚀之球"],
|
|
752
|
+
冰球: ["冰霜之珠"],
|
|
753
|
+
骗钱刀: ["猎鹰战刃"],
|
|
754
|
+
法克: ["法师克星"],
|
|
755
|
+
战鼓: ["韧鼓"],
|
|
756
|
+
大绿鞋: ["宽容之靴"],
|
|
757
|
+
勋章: ["勇气勋章", "炎阳纹章"],
|
|
758
|
+
大勋章: ["炎阳纹章"],
|
|
759
|
+
雾: ["诡计之雾"],
|
|
760
|
+
大鞋: ["卫士胫甲"],
|
|
761
|
+
阿托斯: ["阿托斯之棍"],
|
|
762
|
+
打野爪: ["寒铁钢爪"],
|
|
763
|
+
大晕锤: ["深渊之刃"],
|
|
764
|
+
天堂: ["天堂之戟"],
|
|
765
|
+
天鹰戒: ["天鹰之戒"],
|
|
766
|
+
绿鞋: ["静谧之鞋"],
|
|
767
|
+
微光: ["微光披风"],
|
|
768
|
+
工资球: ["贤者石"],
|
|
769
|
+
推推鞋: ["原力鞋"],
|
|
770
|
+
大暗灭: ["寂灭"],
|
|
771
|
+
铲子: ["可靠铁铲"]
|
|
576
772
|
}
|
|
577
773
|
}
|
|
578
774
|
};
|
|
@@ -582,14 +778,14 @@ var require_zh_CN_constants = __commonJS({
|
|
|
582
778
|
// src/locales/en-US.command.yml
|
|
583
779
|
var require_en_US_command = __commonJS({
|
|
584
780
|
"src/locales/en-US.command.yml"(exports2, module2) {
|
|
585
|
-
module2.exports = { commands: { dota2tracker: { 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." } }, bind: { description: "Bind your SteamID and optionally set a nickname.", usage: "Bind your SteamID to your account. If the group is subscribed, your new match data will be posted in the group in real-time.", examples: 'bind 123456789\nbind 123456789 John\nbind 123456789 "John Doe"', messages: { steam_id_invalid: "Invalid SteamID.", bind_success: "Binding successful,\nID: {userId}\nNickname: {nickName}\nSteamID: {steamId}", bind_failed: "Binding failed, {0}", reason_without_match: "Invalid SteamID or no matches found.", reason_fetch_failed: "Poor network conditions or other reasons prevented the verification of the SteamID. Please try again later.", already_binded: "You are already bound, no need to bind again.\nHere is your personal information:\nID: {userId}\nNickname: {nickName}\nSteamID: {steamId}", nick_name_too_long: "Nickname is too long, please limit it to 20 characters or less. (It can also be left blank)", is_anonymous: 'Please note: Your Steam player data is not public, and you will not be able to use the main functions of the BOT, such as "battle report tracking," "query-recent-match commands," etc.\nIf you need to make data public, please set it to public in the DOTA2 game settings.' } }, unbind: { description: "Unbind your personal information.", messages: { unbind_success: "Unbinding successful.", not_binded: "Not bound, no need to unbind." } }, rename: { description: "Change the nickname set during binding.", examples: 'rename John\nrename "John Doe"', messages: { rename_success: "Rename successful, now you are called {nick_name}.", empty_input: "Please enter your nickname.", not_binded: "Please bind first, you can set a nickname during binding.", nick_name_too_long: "Nickname is too long, please limit it to 20 characters." } }, "query-members": { description: "Query the players bound in this group.", messages: { no_members: "No players bound in this group.", query_failed: "Failed to query group members." } }, "query-match": { description: "Query the match data of the specified match ID and generate a picture.", options: { parse: "Whether to wait for match data parsing" }, examples: "query-match 1234567890\nquery-match 1234567890 -p\nquery-match 1234567890 --parse", messages: { empty_input: "Please enter the match ID.", match_id_invalid: "Invalid match ID.", querying_match: "Searching for match details, please wait...", query_failed: "Failed to get match data.", waiting_for_parse: "Match data has not been parsed yet, a parse request has been sent to the server. The battle report will be sent once parsing is complete or times out." } }, "query-recent-match": { description: "Query the most recent match data and generate a picture.", options: { parse: "Whether to wait for match data parsing" }, usage: "Query the most recent match data of the specified player and generate a picture.\nThe parameter can be the player's SteamID or the nickname of a player bound in this group. If no parameter is provided, it will try to query the SteamID of the command caller.", examples: "query-recent-match\nquery-recent-match 123456789\nquery-recent-match John\nquery-recent-match 123456789 -p\nquery-recent-match John --parse", messages: { not_binded: "By default, it tries to find your information from the bound SteamID players, but it seems you are not bound.\nPlease bind your SteamID in this group. (You can enter [-bind -h] for help)\nOr follow the command with the SteamID or nickname of the player you want to query.", steam_id_invalid: "Invalid SteamID and the player was not found in this group.", querying_match: "Searching for match details, please wait...", query_failed: "Failed to get the player's recent match.", not_in_group: "Command failed.\nCurrently not in a group chat, you must provide the specified player's SteamID.", is_anonymous: "Your player data is not public, and recent match data cannot be obtained.\nIf you need to make data public, please set it to public in the DOTA2 game settings." } }, "query-player": { description: "Query the player's personal information, optionally specify a hero.", options: { hero: "Query the player's usage of the specified hero (same as querying a hero, can use nickname or ID)" }, usage: "Query the personal information of the specified player and generate a picture, optionally specify a hero.\nThe parameter can be the player's SteamID or the nickname of a player bound in this group. If no parameter is provided, it will try to query the SteamID of the command caller.", examples: "query-player\nquery-player 123456789\nquery-player John\nquery-player John --hero Anti-Mage\nquery-player John -o Anti-Mage", messages: { not_binded: "By default, it tries to find your information from the bound SteamID players, but it seems you are not bound.\nPlease bind your SteamID in this group. (You can enter [bind -h] for help)\nOr follow the command with the SteamID or nickname of the player you want to query.", steam_id_invalid: "Invalid SteamID and the player was not found in this group.", querying_player: "Retrieving player data, please wait...", query_failed: "Failed to get player information.", not_in_group: "Command failed.\nCurrently not in a group chat, you must provide the specified player's SteamID." } }, "query-hero": { description: "Query hero skills/stats information.", options: { random: "Randomly select a hero." }, usage: "Query the hero's skill descriptions and various stats, generate a picture.\nThe parameter can be the hero's ID, name, or common nickname.", examples: "query-hero 15\nquery-hero Razor\nquery-hero -r", messages: { not_found: "Hero not found, please confirm and re-enter.", querying_hero: "Retrieving hero data, please wait...", query_failed: "Failed to get hero data.", empty_input: "Please enter a parameter." } } } } };
|
|
781
|
+
module2.exports = { commands: { dota2tracker: { 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." } }, bind: { description: "Bind your SteamID and optionally set a nickname.", usage: "Bind your SteamID to your account. If the group is subscribed, your new match data will be posted in the group in real-time.", examples: 'bind 123456789\nbind 123456789 John\nbind 123456789 "John Doe"', messages: { steam_id_invalid: "Invalid SteamID.", bind_success: "Binding successful,\nID: {userId}\nNickname: {nickName}\nSteamID: {steamId}", bind_failed: "Binding failed, {0}", reason_without_match: "Invalid SteamID or no matches found.", reason_fetch_failed: "Poor network conditions or other reasons prevented the verification of the SteamID. Please try again later.", already_binded: "You are already bound, no need to bind again.\nHere is your personal information:\nID: {userId}\nNickname: {nickName}\nSteamID: {steamId}", nick_name_too_long: "Nickname is too long, please limit it to 20 characters or less. (It can also be left blank)", is_anonymous: 'Please note: Your Steam player data is not public, and you will not be able to use the main functions of the BOT, such as "battle report tracking," "query-recent-match commands," etc.\nIf you need to make data public, please set it to public in the DOTA2 game settings.' } }, unbind: { description: "Unbind your personal information.", messages: { unbind_success: "Unbinding successful.", not_binded: "Not bound, no need to unbind." } }, rename: { description: "Change the nickname set during binding.", examples: 'rename John\nrename "John Doe"', messages: { rename_success: "Rename successful, now you are called {nick_name}.", empty_input: "Please enter your nickname.", not_binded: "Please bind first, you can set a nickname during binding.", nick_name_too_long: "Nickname is too long, please limit it to 20 characters." } }, "query-members": { description: "Query the players bound in this group.", messages: { no_members: "No players bound in this group.", query_failed: "Failed to query group members." } }, "query-match": { description: "Query the match data of the specified match ID and generate a picture.", options: { parse: "Whether to wait for match data parsing" }, examples: "query-match 1234567890\nquery-match 1234567890 -p\nquery-match 1234567890 --parse", messages: { empty_input: "Please enter the match ID.", match_id_invalid: "Invalid match ID.", querying_match: "Searching for match details, please wait...", query_failed: "Failed to get match data.", waiting_for_parse: "Match data has not been parsed yet, a parse request has been sent to the server. The battle report will be sent once parsing is complete or times out." } }, "query-recent-match": { description: "Query the most recent match data and generate a picture.", options: { parse: "Whether to wait for match data parsing" }, usage: "Query the most recent match data of the specified player and generate a picture.\nThe parameter can be the player's SteamID or the nickname of a player bound in this group. If no parameter is provided, it will try to query the SteamID of the command caller.", examples: "query-recent-match\nquery-recent-match 123456789\nquery-recent-match John\nquery-recent-match 123456789 -p\nquery-recent-match John --parse", messages: { not_binded: "By default, it tries to find your information from the bound SteamID players, but it seems you are not bound.\nPlease bind your SteamID in this group. (You can enter [-bind -h] for help)\nOr follow the command with the SteamID or nickname of the player you want to query.", steam_id_invalid: "Invalid SteamID and the player was not found in this group.", querying_match: "Searching for match details, please wait...", query_failed: "Failed to get the player's recent match.", not_in_group: "Command failed.\nCurrently not in a group chat, you must provide the specified player's SteamID.", is_anonymous: "Your player data is not public, and recent match data cannot be obtained.\nIf you need to make data public, please set it to public in the DOTA2 game settings." } }, "query-player": { description: "Query the player's personal information, optionally specify a hero.", options: { hero: "Query the player's usage of the specified hero (same as querying a hero, can use nickname or ID)" }, usage: "Query the personal information of the specified player and generate a picture, optionally specify a hero.\nThe parameter can be the player's SteamID or the nickname of a player bound in this group. If no parameter is provided, it will try to query the SteamID of the command caller.", examples: "query-player\nquery-player 123456789\nquery-player John\nquery-player John --hero Anti-Mage\nquery-player John -o Anti-Mage", messages: { not_binded: "By default, it tries to find your information from the bound SteamID players, but it seems you are not bound.\nPlease bind your SteamID in this group. (You can enter [bind -h] for help)\nOr follow the command with the SteamID or nickname of the player you want to query.", steam_id_invalid: "Invalid SteamID and the player was not found in this group.", querying_player: "Retrieving player data, please wait...", query_failed: "Failed to get player information.", not_in_group: "Command failed.\nCurrently not in a group chat, you must provide the specified player's SteamID." } }, "query-hero": { description: "Query hero skills/stats information.", options: { random: "Randomly select a hero." }, usage: "Query the hero's skill descriptions and various stats, generate a picture.\nThe parameter can be the hero's ID, name, or common nickname.", examples: "query-hero 15\nquery-hero Razor\nquery-hero -r", messages: { not_found: "Hero not found, please confirm and re-enter.", querying_hero: "Retrieving hero data, please wait...", query_failed: "Failed to get hero data.", empty_input: "Please enter a parameter." } }, "query-item": { description: "Query item information", usage: "Query item descriptions and attributes, then generate and publish an image report.\nParameters can be item name (supports fuzzy search), item alias, or item ID.", examples: "query-item Vanguard", messages: { query_list_failed: "Failed to retrieve item list data", query_item_failed: "Failed to retrieve data for item '{0}'", querying_item: "Querying item data, please wait...", cache_building: "Initializing or rebuilding item cache for the current version, please wait...", empty_input: "No keywords provided. \n{#if show}Displaying full item list per current configuration\n{:else}No content available\n{/if}", not_found: "No items found matching the keywords, please verify and retry", too_many_items: "Found {count} items, exceeding maximum display limit ({max} items)\n{#if show}(Displaying item list){/if}", finded_items: "Matching items: \n{#each items as item}\n{item.name_loc}{#if item !== items[items.length - 1]}, {/if}\n{/each}" } } } } };
|
|
586
782
|
}
|
|
587
783
|
});
|
|
588
784
|
|
|
589
785
|
// src/locales/en-US.template.yml
|
|
590
786
|
var require_en_US_template = __commonJS({
|
|
591
787
|
"src/locales/en-US.template.yml"(exports2, module2) {
|
|
592
|
-
module2.exports = { dota2tracker: { template: { radiant: "Radiant", dire: "Dire", won: "Won", lost: "Lost", match_id_: "Match ID: {0}", game_mode_: "Mode: {0}", start_time_: "Start Time: {0}", end_time_: "End Time: {0}", pick_order: "#{0}", random: "R", hero_damage_: "Damage: {0}", building_damage_: "Building: {0}", damage_received_: "Received: {0}", lasthit_: "LastHit: {0}", deny_: "Deny: {0}", "lh/dn_": "LH/DN: {0}", GPM: "GPM", XPM: "XPM", heal_: "Heal: {0}", crowd_control_duration_: "CCD: {0}", "GPM/XPM_": "GPM/XPM: {0}", lane: "Lane", lane_: "Lane: ", lane_advantage: "Lane +", lane_disadvantage: "Lane -", lane_jungle: "Jungle", lane_stomp: "Lane+++", lane_stomped: "Lane---", lane_tie: "Lane ==", analysis_successful: "Analysis successful", analysis_incomplete: "Analysis incomplete", kill: "Kill", kill_contribution_: "KC: {0}", position: "Position", position_: "Position: ", position_1: "Carry", position_2: "Mid", position_3: "OffLane", position_4: "Softsup", position_5: "Hardsup", dire_won: "Dire Won", radiant_won: "Radiant Won", total_damage: "Damage", total_experience: "Exp.", total_gold: "Gold", region_: "Region: {0}", duration_: "Duration: {0}", position_undefined: "?", top10_: "Top 10 Heroes by Matches: ", match_count_: "Matches: ", last25matches_: "Last 25 Matches: ", winrate_: "Winrate: ", imp_: "IMP: ", lane_advantage_rate_: "Lane Advantage Rate: ", hero: "Hero", all_matches_: "All Matches: ", match_count: "Matches", winrate: "Winrate", imp: "IMP", win_count: "Wins", lose_count: "Losses", recently_heroes: "Heroes used more than once recently: ", recently_positions: "Performance in the last 25 matches across all positions: ", winning_streak: "Winning Streak", losing_streak: "Losing Streak", id: "ID", mode: "Mode", kda_kc: "KDA(KC)", time: "Time", duration: "Duration", rank: "Rank", un_parsed: "(Unparsed)", combined_win_loss_summary: "Combined Win/Loss Summary: ", yesterdays_summary: "Yesterday's Summary", last_weeks_summary: "Last Week's Summary", report_won: "W", report_lost: "L", report_winrate: "WR", anonymous_player_1: "This profile is private.", anonymous_player_2: "Background is for display purposes only. It is not {player}’s data.", rank_fun_down_message: "{avatar}<br/>Sad", rank_fun_up_message: "Hip hip hooray! Our awesome member {avatar}{name} has leveled up from {prev} to {curr}!", titles: { MVP: "MVP-#FFA500", Soul: "Soul-#66CCFF", Rich: "R-#FFD700", Wise: "W-#8888FF", Controller: "C-#FF00FF", Nuker: "N-#CC0088", Breaker: "B-#DD0000", Ghost: "G-#CCCCCC", Assister: "A-#006400", Demolisher: "D-#FEDCBA", Healer: "H-#00FF00", Tank: "T-#84A1C7", Idle: "I-#DDDDDD" }, situation: "Situation", networth: "Net Worth", experience: "Experience" } } };
|
|
788
|
+
module2.exports = { dota2tracker: { template: { radiant: "Radiant", dire: "Dire", won: "Won", lost: "Lost", match_id_: "Match ID: {0}", game_mode_: "Mode: {0}", start_time_: "Start Time: {0}", end_time_: "End Time: {0}", pick_order: "#{0}", random: "R", hero_damage_: "Damage: {0}", building_damage_: "Building: {0}", damage_received_: "Received: {0}", lasthit_: "LastHit: {0}", deny_: "Deny: {0}", "lh/dn_": "LH/DN: {0}", GPM: "GPM", XPM: "XPM", heal_: "Heal: {0}", crowd_control_duration_: "CCD: {0}", "GPM/XPM_": "GPM/XPM: {0}", lane: "Lane", lane_: "Lane: ", lane_advantage: "Lane +", lane_disadvantage: "Lane -", lane_jungle: "Jungle", lane_stomp: "Lane+++", lane_stomped: "Lane---", lane_tie: "Lane ==", analysis_successful: "Analysis successful", analysis_incomplete: "Analysis incomplete", kill: "Kill", kill_contribution_: "KC: {0}", position: "Position", position_: "Position: ", position_1: "Carry", position_2: "Mid", position_3: "OffLane", position_4: "Softsup", position_5: "Hardsup", dire_won: "Dire Won", radiant_won: "Radiant Won", total_damage: "Damage", total_experience: "Exp.", total_gold: "Gold", region_: "Region: {0}", duration_: "Duration: {0}", position_undefined: "?", top10_: "Top 10 Heroes by Matches: ", match_count_: "Matches: ", last25matches_: "Last 25 Matches: ", winrate_: "Winrate: ", imp_: "IMP: ", lane_advantage_rate_: "Lane Advantage Rate: ", hero: "Hero", all_matches_: "All Matches: ", match_count: "Matches", winrate: "Winrate", imp: "IMP", win_count: "Wins", lose_count: "Losses", recently_heroes: "Heroes used more than once recently: ", recently_positions: "Performance in the last 25 matches across all positions: ", winning_streak: "Winning Streak", losing_streak: "Losing Streak", id: "ID", mode: "Mode", kda_kc: "KDA(KC)", time: "Time", duration: "Duration", rank: "Rank", un_parsed: "(Unparsed)", combined_win_loss_summary: "Combined Win/Loss Summary: ", yesterdays_summary: "Yesterday's Summary", last_weeks_summary: "Last Week's Summary", report_won: "W", report_lost: "L", report_winrate: "WR", anonymous_player_1: "This profile is private.", anonymous_player_2: "Background is for display purposes only. It is not {player}’s data.", rank_fun_down_message: "{avatar}<br/>Sad", rank_fun_up_message: "Hip hip hooray! Our awesome member {avatar}{name} has leveled up from {prev} to {curr}!", titles: { MVP: "MVP-#FFA500", Soul: "Soul-#66CCFF", Rich: "R-#FFD700", Wise: "W-#8888FF", Controller: "C-#FF00FF", Nuker: "N-#CC0088", Breaker: "B-#DD0000", Ghost: "G-#CCCCCC", Assister: "A-#006400", Demolisher: "D-#FEDCBA", Healer: "H-#00FF00", Tank: "T-#84A1C7", Idle: "I-#DDDDDD" }, situation: "Situation", networth: "Net Worth", experience: "Experience", OUTCOME_MAP: { RADIANT_VICTORY: "RADIANT VICTORY", RADIANT_STOMP: "RADIANT STOMP", DIRE_VICTORY: "DIRE VICTORY", DIRE_STOMP: "DIRE STOMP", TIE: "TIE" }, lane_top: "Top", lane_mid: "Mid", lane_bottom: "Bottom", empty_extra_info: "No extra info" } } };
|
|
593
789
|
}
|
|
594
790
|
});
|
|
595
791
|
|
|
@@ -603,14 +799,14 @@ var require_en_US = __commonJS({
|
|
|
603
799
|
// src/locales/zh-CN.command.yml
|
|
604
800
|
var require_zh_CN_command = __commonJS({
|
|
605
801
|
"src/locales/zh-CN.command.yml"(exports2, module2) {
|
|
606
|
-
module2.exports = { commands: { dota2tracker: { subscribe: { description: "订阅本群。", usage: "订阅后还需玩家在本群绑定SteamID,BOT将订阅本群中已绑定玩家的新比赛数据,在STRATZ比赛解析完成后将比赛数据生成为图片战报发布至本群中。", messages: { subscribed: "本群已订阅,无需重复订阅。", subscribe_success: "订阅成功。" } }, unsubscribe: { description: "取消订阅本群。", messages: { unsubscribe_success: "取消订阅成功。", not_subscribed: "本群尚未订阅,无需取消订阅。" } }, bind: { description: "绑定SteamID,并起一个别名(也可以不起)。", usage: "将你的SteamID与你的账号绑定,若本群已订阅将会实时获取你的新比赛数据发布至群中。", examples: '绑定 123456789\n绑定 123456789 张三\n绑定 123456789 "张 三"', messages: { steam_id_invalid: "SteamID无效。", bind_success: "绑定成功,\nID:{userId}\n别名:{nickName}\nSteamID:{steamId}", bind_failed: "绑定失败,{0}", reason_without_match: "SteamID无效或无任何场次。", reason_fetch_failed: "网络状况不佳或其他原因无法验证SteamID,请稍后重试。", already_binded: "你已绑定,无需重复绑定。\n以下是你的个人信息:\nID:{userId}\n别名:{nickName}\nSteamID:{steamId}", nick_name_too_long: "别名过长,请限制在20个字符以内。(也可以留空)", is_anonymous: "请注意:你的Steam玩家数据并未公开,将无法使用BOT的主要功能,如“战报追踪”、“查询最近指令”等。\n如需公开数据,请在DOTA2游戏内设置中公开。" } }, unbind: { description: "取消绑定你的个人信息。", messages: { unbind_success: "取消绑定成功。", not_binded: "尚未绑定,无需取消绑定。" } }, rename: { description: "修改绑定时设定的别名。", examples: '改名 李四\n改名 "李 四"', messages: { rename_success: "改名成功,现在你叫{nick_name}了。", empty_input: "请输入你的别名。", not_binded: "请先绑定,绑定时即可设定别名。", nick_name_too_long: "别名过长,请限制在20个字符以内。" } }, "query-members": { description: "查询本群已绑定的玩家。", messages: { no_members: "本群尚无绑定玩家。", query_failed: "查询群友失败。" } }, "query-match": { description: "查询指定比赛ID的比赛数据,生成图片发布。", options: { parse: "-p 是否等待解析比赛数据" }, examples: "查询比赛 1234567890\n查询比赛 1234567890 -p\n查询比赛 1234567890 --parse", messages: { empty_input: "请输入比赛ID。", match_id_invalid: "比赛ID无效。", querying_match: "正在搜索对局详情,请稍后……", query_failed: "获取比赛数据失败。", waiting_for_parse: "比赛数据尚未解析,已发送解析请求到服务器,战报将在解析完成或超时后发送。" } }, "query-recent-match": { description: "查询最近的比赛数据,生成图片发布。", options: { parse: "-p 是否等待解析比赛数据" }, usage: "查询指定玩家的最近一场比赛的比赛数据,生成图片发布。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID。", examples: "查询最近比赛\n查询最近比赛 123456789\n查询最近比赛 张三\n查询最近比赛 123456789 -p\n查询最近比赛 张三 --parse", messages: { not_binded: "无参数时默认从已绑定SteamID玩家中寻找你的信息,但你似乎并没有绑定。\n请在本群绑定SteamID。(可输入【绑定 -h】获取帮助)\n或在指令后跟上希望查询的SteamID或已绑定玩家的别名。", steam_id_invalid: "SteamID无效并且未在本群找到此玩家。", querying_match: "正在搜索对局详情,请稍后……", query_failed: "获取玩家最近比赛失败。", not_in_group: "指令调用失败。\n当前不属于群聊状态,必须提供指定玩家的SteamID。", is_anonymous: "你的比赛数据未公开,无法获取最近比赛数据。\n如需公开数据,请在DOTA2游戏内设置中公开。" } }, "query-player": { description: "查询玩家的个人信息,可指定英雄。", options: { hero: "-o 查询玩家指定英雄使用情况(同查询英雄,可用别名或ID)" }, usage: "查询指定玩家的个人信息,生成图片发布,可指定英雄。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID。", examples: "查询玩家\n查询玩家 123456789\n查询玩家 张三\n查询玩家 张三 --hero 敌法师\n查询玩家 张三 -o 15", messages: { not_binded: "无参数时默认从已绑定SteamID玩家中寻找你的信息,但你似乎并没有绑定。\n请在本群绑定SteamID。(可输入【绑定 -h】获取帮助)\n或在指令后跟上希望查询的SteamID或已绑定玩家的别名。", steam_id_invalid: "SteamID无效并且未在本群找到此玩家。", querying_player: "正在获取玩家数据,请稍后……", query_failed: "获取玩家信息失败。", not_in_group: "指令调用失败。\n当前不属于群聊状态,必须提供指定玩家的SteamID。" } }, "query-hero": { description: "查询英雄技能/面板信息。", options: { random: "-r 随机选择英雄" }, usage: "查询英雄的技能说明与各项数据,生成图片发布。\n参数可输入英雄ID、英雄名、英雄常用别名。", examples: "查询英雄 15\n查询英雄 雷泽\n查询英雄 电魂", messages: { not_found: "未找到输入的英雄,请确认后重新输入。", querying_hero: "正在获取英雄数据,请稍后……", query_failed: "获取英雄数据失败。", empty_input: "请输入参数。" } } } } };
|
|
802
|
+
module2.exports = { commands: { dota2tracker: { subscribe: { description: "订阅本群。", usage: "订阅后还需玩家在本群绑定SteamID,BOT将订阅本群中已绑定玩家的新比赛数据,在STRATZ比赛解析完成后将比赛数据生成为图片战报发布至本群中。", messages: { subscribed: "本群已订阅,无需重复订阅。", subscribe_success: "订阅成功。" } }, unsubscribe: { description: "取消订阅本群。", messages: { unsubscribe_success: "取消订阅成功。", not_subscribed: "本群尚未订阅,无需取消订阅。" } }, bind: { description: "绑定SteamID,并起一个别名(也可以不起)。", usage: "将你的SteamID与你的账号绑定,若本群已订阅将会实时获取你的新比赛数据发布至群中。", examples: '绑定 123456789\n绑定 123456789 张三\n绑定 123456789 "张 三"', messages: { steam_id_invalid: "SteamID无效。", bind_success: "绑定成功,\nID:{userId}\n别名:{nickName}\nSteamID:{steamId}", bind_failed: "绑定失败,{0}", reason_without_match: "SteamID无效或无任何场次。", reason_fetch_failed: "网络状况不佳或其他原因无法验证SteamID,请稍后重试。", already_binded: "你已绑定,无需重复绑定。\n以下是你的个人信息:\nID:{userId}\n别名:{nickName}\nSteamID:{steamId}", nick_name_too_long: "别名过长,请限制在20个字符以内。(也可以留空)", is_anonymous: "请注意:你的Steam玩家数据并未公开,将无法使用BOT的主要功能,如“战报追踪”、“查询最近指令”等。\n如需公开数据,请在DOTA2游戏内设置中公开。" } }, unbind: { description: "取消绑定你的个人信息。", messages: { unbind_success: "取消绑定成功。", not_binded: "尚未绑定,无需取消绑定。" } }, rename: { description: "修改绑定时设定的别名。", examples: '改名 李四\n改名 "李 四"', messages: { rename_success: "改名成功,现在你叫{nick_name}了。", empty_input: "请输入你的别名。", not_binded: "请先绑定,绑定时即可设定别名。", nick_name_too_long: "别名过长,请限制在20个字符以内。" } }, "query-members": { description: "查询本群已绑定的玩家。", messages: { no_members: "本群尚无绑定玩家。", query_failed: "查询群友失败。" } }, "query-match": { description: "查询指定比赛ID的比赛数据,生成图片发布。", options: { parse: "-p 是否等待解析比赛数据" }, examples: "查询比赛 1234567890\n查询比赛 1234567890 -p\n查询比赛 1234567890 --parse", messages: { empty_input: "请输入比赛ID。", match_id_invalid: "比赛ID无效。", querying_match: "正在搜索对局详情,请稍后……", query_failed: "获取比赛数据失败。", waiting_for_parse: "比赛数据尚未解析,已发送解析请求到服务器,战报将在解析完成或超时后发送。" } }, "query-recent-match": { description: "查询最近的比赛数据,生成图片发布。", options: { parse: "-p 是否等待解析比赛数据" }, usage: "查询指定玩家的最近一场比赛的比赛数据,生成图片发布。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID。", examples: "查询最近比赛\n查询最近比赛 123456789\n查询最近比赛 张三\n查询最近比赛 123456789 -p\n查询最近比赛 张三 --parse", messages: { not_binded: "无参数时默认从已绑定SteamID玩家中寻找你的信息,但你似乎并没有绑定。\n请在本群绑定SteamID。(可输入【绑定 -h】获取帮助)\n或在指令后跟上希望查询的SteamID或已绑定玩家的别名。", steam_id_invalid: "SteamID无效并且未在本群找到此玩家。", querying_match: "正在搜索对局详情,请稍后……", query_failed: "获取玩家最近比赛失败。", not_in_group: "指令调用失败。\n当前不属于群聊状态,必须提供指定玩家的SteamID。", is_anonymous: "你的比赛数据未公开,无法获取最近比赛数据。\n如需公开数据,请在DOTA2游戏内设置中公开。" } }, "query-player": { description: "查询玩家的个人信息,可指定英雄。", options: { hero: "-o 查询玩家指定英雄使用情况(同查询英雄,可用别名或ID)" }, usage: "查询指定玩家的个人信息,生成图片发布,可指定英雄。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID。", examples: "查询玩家\n查询玩家 123456789\n查询玩家 张三\n查询玩家 张三 --hero 敌法师\n查询玩家 张三 -o 15", messages: { not_binded: "无参数时默认从已绑定SteamID玩家中寻找你的信息,但你似乎并没有绑定。\n请在本群绑定SteamID。(可输入【绑定 -h】获取帮助)\n或在指令后跟上希望查询的SteamID或已绑定玩家的别名。", steam_id_invalid: "SteamID无效并且未在本群找到此玩家。", querying_player: "正在获取玩家数据,请稍后……", query_failed: "获取玩家信息失败。", not_in_group: "指令调用失败。\n当前不属于群聊状态,必须提供指定玩家的SteamID。" } }, "query-hero": { description: "查询英雄技能/面板信息。", options: { random: "-r 随机选择英雄" }, usage: "查询英雄的技能说明与各项数据,生成图片发布。\n参数可输入英雄ID、英雄名、英雄常用别名。", examples: "查询英雄 15\n查询英雄 雷泽\n查询英雄 电魂", messages: { not_found: "未找到输入的英雄,请确认后重新输入。", querying_hero: "正在获取英雄数据,请稍后……", query_failed: "获取英雄数据失败。", empty_input: "请输入参数。" } }, "query-item": { description: "查询物品信息。", usage: "查询物品的描述与各项数据,生成图片发布。\n参数可输入物品名(可模糊查找)、物品别名、物品ID。", examples: "查询物品 先锋盾", messages: { query_list_failed: "获取物品列表数据失败。", query_item_failed: "获取物品「{0}」数据失败", querying_item: "正在查询物品数据,请稍候…", cache_building: "初次使用或缓存已过期,正在生成当前版本的物品缓存,请稍后……", empty_input: "未输入关键字参数。根据当前配置{#if show},将返回全部物品列表{:else}无内容可发送{/if}。", not_found: "未找到与关键字匹配的物品,请确认后重试。", too_many_items: "找到{count}个物品,超过最大发送限制({max}个){#if show},将发送物品列表{/if}。", finded_items: "找到以下物品:{#each items as item}{item.name_loc}{#if item !== items[items.length - 1]}、{/if}{/each}" } } } } };
|
|
607
803
|
}
|
|
608
804
|
});
|
|
609
805
|
|
|
610
806
|
// src/locales/zh-CN.template.yml
|
|
611
807
|
var require_zh_CN_template = __commonJS({
|
|
612
808
|
"src/locales/zh-CN.template.yml"(exports2, module2) {
|
|
613
|
-
module2.exports = { dota2tracker: { template: { radiant: "天辉", dire: "夜魇", won: "获胜", lost: "失败", match_id_: "比赛编号:{0}", game_mode_: "模式:{0}", start_time_: "起始时间:{0}", end_time_: "结束时间:{0}", pick_order: "第{0}手", random: "随机", hero_damage_: "英雄伤害:{0}", building_damage_: "建筑伤害:{0}", damage_received_: "受到伤害:{0}", lasthit_: "补刀:{0}", deny_: "反补:{0}", "lh/dn_": "补刀:{0}/{1}", GPM: "GPM", XPM: "XPM", heal_: "治疗量:{0}", crowd_control_duration_: "控制时间:{0}", "GPM/XPM_": "GPM/XPM:{0}", lane: "对线", lane_: "对线:", lane_advantage: "对线优势", lane_disadvantage: "对线劣势", lane_stomp: "对线碾压", lane_stomped: "对线被碾", lane_tie: "对线平手", lane_jungle: "野区霸主", analysis_successful: "录像分析成功", analysis_incomplete: "分析结果不完整", kill: "击杀", kill_contribution_: "参战率:{0}", position: "位置", position_: "位置:", position_1: "优势路", position_2: "中路", position_3: "烈士路", position_4: "采灵芝", position_5: "工具人", position_undefined: "?", total_damage: "总伤害", total_gold: "总经济", total_experience: "总经验", radiant_won: "天辉获胜", dire_won: "夜魇获胜", duration_: "持续时间:{0}", region_: "地区:{0}", match_count_: "场次:", last25matches_: "最近25场:", winrate_: "胜率:", imp_: "表现:", lane_advantage_rate_: "线优率:", top10_: "全期场次前十的英雄:", hero: "英雄", all_matches_: "全期场次:", match_count: "场次", winrate: "胜率", imp: "表现", win_count: "胜场", lose_count: "败场", recently_heroes: "近期使用场次大于1的英雄:", recently_positions: "近25场各个位置的表现:", winning_streak: "连胜", losing_streak: "连败", id: "ID", mode: "模式", kda_kc: "KDA(参战率)", time: "时间", duration: "时长", rank: "段位", un_parsed: "(未解析)", combined_win_loss_summary: "组合胜负情况:", yesterdays_summary: "昨日总结", last_weeks_summary: "上周总结", report_won: "胜", report_lost: "负", report_winrate: "胜率", anonymous_player_1: "数据未公开", anonymous_player_2: "背景仅供展示目的,不属于{player}的数据。", rank_fun_up_message: "热烈祝贺群友 {avatar}{name} 在天梯中再获进步,<br/>由 {prev} 升为 {curr},再接再厉,再创辉煌!", rank_fun_down_message: "{avatar}<br/>寄", titles: { MVP: "MVP-#FFA500", Soul: "魂-#66CCFF", Rich: "富-#FFD700", Wise: "睿-#8888FF", Controller: "控-#FF00FF", Nuker: "爆-#CC0088", Breaker: "破-#DD0000", Ghost: "鬼-#CCCCCC", Assister: "助-#006400", Demolisher: "拆-#FEDCBA", Healer: "奶-#00FF00", Tank: "耐-#84A1C7", Idle: "摸-#DDDDDD" }, situation: "局势", networth: "
|
|
809
|
+
module2.exports = { dota2tracker: { template: { radiant: "天辉", dire: "夜魇", won: "获胜", lost: "失败", match_id_: "比赛编号:{0}", game_mode_: "模式:{0}", start_time_: "起始时间:{0}", end_time_: "结束时间:{0}", pick_order: "第{0}手", random: "随机", hero_damage_: "英雄伤害:{0}", building_damage_: "建筑伤害:{0}", damage_received_: "受到伤害:{0}", lasthit_: "补刀:{0}", deny_: "反补:{0}", "lh/dn_": "补刀:{0}/{1}", GPM: "GPM", XPM: "XPM", heal_: "治疗量:{0}", crowd_control_duration_: "控制时间:{0}", "GPM/XPM_": "GPM/XPM:{0}", lane: "对线", lane_: "对线:", lane_advantage: "对线优势", lane_disadvantage: "对线劣势", lane_stomp: "对线碾压", lane_stomped: "对线被碾", lane_tie: "对线平手", lane_jungle: "野区霸主", analysis_successful: "录像分析成功", analysis_incomplete: "分析结果不完整", kill: "击杀", kill_contribution_: "参战率:{0}", position: "位置", position_: "位置:", position_1: "优势路", position_2: "中路", position_3: "烈士路", position_4: "采灵芝", position_5: "工具人", position_undefined: "?", total_damage: "总伤害", total_gold: "总经济", total_experience: "总经验", radiant_won: "天辉获胜", dire_won: "夜魇获胜", duration_: "持续时间:{0}", region_: "地区:{0}", match_count_: "场次:", last25matches_: "最近25场:", winrate_: "胜率:", imp_: "表现:", lane_advantage_rate_: "线优率:", top10_: "全期场次前十的英雄:", hero: "英雄", all_matches_: "全期场次:", match_count: "场次", winrate: "胜率", imp: "表现", win_count: "胜场", lose_count: "败场", recently_heroes: "近期使用场次大于1的英雄:", recently_positions: "近25场各个位置的表现:", winning_streak: "连胜", losing_streak: "连败", id: "ID", mode: "模式", kda_kc: "KDA(参战率)", time: "时间", duration: "时长", rank: "段位", un_parsed: "(未解析)", combined_win_loss_summary: "组合胜负情况:", yesterdays_summary: "昨日总结", last_weeks_summary: "上周总结", report_won: "胜", report_lost: "负", report_winrate: "胜率", anonymous_player_1: "数据未公开", anonymous_player_2: "背景仅供展示目的,不属于{player}的数据。", rank_fun_up_message: "热烈祝贺群友 {avatar}{name} 在天梯中再获进步,<br/>由 {prev} 升为 {curr},再接再厉,再创辉煌!", rank_fun_down_message: "{avatar}<br/>寄", titles: { MVP: "MVP-#FFA500", Soul: "魂-#66CCFF", Rich: "富-#FFD700", Wise: "睿-#8888FF", Controller: "控-#FF00FF", Nuker: "爆-#CC0088", Breaker: "破-#DD0000", Ghost: "鬼-#CCCCCC", Assister: "助-#006400", Demolisher: "拆-#FEDCBA", Healer: "奶-#00FF00", Tank: "耐-#84A1C7", Idle: "摸-#DDDDDD" }, situation: "局势", networth: "经济", experience: "经验", OUTCOME_MAP: { RADIANT_VICTORY: "天辉优势", RADIANT_STOMP: "天辉碾压", DIRE_VICTORY: "夜魇优势", DIRE_STOMP: "夜魇碾压", TIE: "势均力敌" }, lane_top: "上路", lane_mid: "中路", lane_bottom: "下路", empty_extra_info: "比赛未解析或信息缺失,无法展示更多数据。" } } };
|
|
614
810
|
}
|
|
615
811
|
});
|
|
616
812
|
|
|
@@ -645,13 +841,17 @@ __export(utils_exports, {
|
|
|
645
841
|
formatHeroDesc: () => formatHeroDesc,
|
|
646
842
|
formatNumber: () => formatNumber,
|
|
647
843
|
getFormattedHeroData: () => getFormattedHeroData,
|
|
844
|
+
getFormattedItemListData: () => getFormattedItemListData,
|
|
648
845
|
getFormattedMatchData: () => getFormattedMatchData,
|
|
649
846
|
getFormattedPlayerData: () => getFormattedPlayerData,
|
|
650
847
|
getImageUrl: () => getImageUrl,
|
|
651
848
|
init: () => init,
|
|
652
849
|
playerisValid: () => playerisValid,
|
|
653
850
|
query: () => query,
|
|
654
|
-
|
|
851
|
+
queryHeroDetailsFromValve: () => queryHeroDetailsFromValve,
|
|
852
|
+
queryItemDetailsFromValve: () => queryItemDetailsFromValve,
|
|
853
|
+
queryItemListFromValve: () => queryItemListFromValve,
|
|
854
|
+
queryLastPatchNumber: () => queryLastPatchNumber,
|
|
655
855
|
readDirectoryFilesSync: () => readDirectoryFilesSync,
|
|
656
856
|
roundToDecimalPlaces: () => roundToDecimalPlaces,
|
|
657
857
|
sec2time: () => sec2time,
|
|
@@ -710,15 +910,27 @@ function loadGraphqlFile(queryName) {
|
|
|
710
910
|
return import_fs.default.readFileSync(import_path.default.join(pluginDir, "queries", `${queryName}.graphql`), { encoding: "utf-8" }).replace(/[\r\n]+/g, " ");
|
|
711
911
|
}
|
|
712
912
|
__name(loadGraphqlFile, "loadGraphqlFile");
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
return (await http.get(`https://www.dota2.com/datafeed/herodata?language=${
|
|
913
|
+
var valveLanguageTag = /* @__PURE__ */ ((valveLanguageTag2) => {
|
|
914
|
+
valveLanguageTag2["zh-CN"] = "schinese";
|
|
915
|
+
valveLanguageTag2["en-US"] = "english";
|
|
916
|
+
return valveLanguageTag2;
|
|
917
|
+
})(valveLanguageTag || {});
|
|
918
|
+
async function queryHeroDetailsFromValve(heroId, languageTag = "zh-CN") {
|
|
919
|
+
return (await http.get(`https://www.dota2.com/datafeed/herodata?language=${valveLanguageTag[languageTag]}&hero_id=${heroId}`)).result.data.heroes[0];
|
|
920
|
+
}
|
|
921
|
+
__name(queryHeroDetailsFromValve, "queryHeroDetailsFromValve");
|
|
922
|
+
async function queryItemListFromValve(languageTag = "zh-CN") {
|
|
923
|
+
return (await http.get(`https://www.dota2.com/datafeed/itemlist?language=${valveLanguageTag[languageTag]}`)).result.data.itemabilities;
|
|
720
924
|
}
|
|
721
|
-
__name(
|
|
925
|
+
__name(queryItemListFromValve, "queryItemListFromValve");
|
|
926
|
+
async function queryItemDetailsFromValve(itemId, languageTag = "zh-CN") {
|
|
927
|
+
return (await http.get(`https://www.dota2.com/datafeed/itemdata?language=${valveLanguageTag[languageTag]}&item_id=${itemId}`)).result.data.items[0];
|
|
928
|
+
}
|
|
929
|
+
__name(queryItemDetailsFromValve, "queryItemDetailsFromValve");
|
|
930
|
+
async function queryLastPatchNumber() {
|
|
931
|
+
return (await http.get("https://www.dota2.com/datafeed/patchnoteslist")).patches.at(-1).patch_number;
|
|
932
|
+
}
|
|
933
|
+
__name(queryLastPatchNumber, "queryLastPatchNumber");
|
|
722
934
|
var HeroDescType = /* @__PURE__ */ ((HeroDescType3) => {
|
|
723
935
|
HeroDescType3["Normal"] = "normal";
|
|
724
936
|
HeroDescType3["Facet"] = "facet";
|
|
@@ -753,7 +965,7 @@ function getImageUrl(image, type = "local" /* Local */, format = "png" /* png */
|
|
|
753
965
|
console.error(error);
|
|
754
966
|
return "";
|
|
755
967
|
}
|
|
756
|
-
} else return `https://cdn.
|
|
968
|
+
} else return `https://cdn.akamai.steamstatic.com/apps/dota2/images/dota_react/${type}/${image}.${format}`;
|
|
757
969
|
}
|
|
758
970
|
__name(getImageUrl, "getImageUrl");
|
|
759
971
|
function getFormattedMatchData(matchQuery, constantsQuery) {
|
|
@@ -1234,6 +1446,64 @@ function getFormattedHeroData(rawHero) {
|
|
|
1234
1446
|
return hero;
|
|
1235
1447
|
}
|
|
1236
1448
|
__name(getFormattedHeroData, "getFormattedHeroData");
|
|
1449
|
+
async function getFormattedItemListData(languageTag) {
|
|
1450
|
+
const rawItems = await queryItemListFromValve(languageTag);
|
|
1451
|
+
const processItemName = /* @__PURE__ */ __name((name2) => name2.replace(/^item_/i, "").replace(/^recipe_/i, "recipe_"), "processItemName");
|
|
1452
|
+
const [recipes, items] = rawItems.reduce(
|
|
1453
|
+
(acc, item) => {
|
|
1454
|
+
const processed = {
|
|
1455
|
+
...item,
|
|
1456
|
+
name: processItemName(item.name),
|
|
1457
|
+
name_loc: item.name_loc,
|
|
1458
|
+
name_english_loc: item.name_english_loc
|
|
1459
|
+
};
|
|
1460
|
+
item.name.includes("_recipe_") ? acc[0].push(processed) : acc[1].push(processed);
|
|
1461
|
+
return acc;
|
|
1462
|
+
},
|
|
1463
|
+
[[], []]
|
|
1464
|
+
);
|
|
1465
|
+
const itemMap = /* @__PURE__ */ new Map();
|
|
1466
|
+
items.concat(recipes).forEach(
|
|
1467
|
+
(item) => itemMap.set(item.id, {
|
|
1468
|
+
id: item.id,
|
|
1469
|
+
name: item.name,
|
|
1470
|
+
name_loc: item.name_loc
|
|
1471
|
+
})
|
|
1472
|
+
);
|
|
1473
|
+
const processedItems = items.map((baseItem) => {
|
|
1474
|
+
const recipe = recipes.find((r) => r.name === `recipe_${baseItem.name.replace("item_", "")}`);
|
|
1475
|
+
return {
|
|
1476
|
+
...baseItem,
|
|
1477
|
+
recipes: (recipe?.recipes || baseItem.recipes).map((recipe2) => ({
|
|
1478
|
+
...recipe2,
|
|
1479
|
+
// 转换ID数组为对象数组
|
|
1480
|
+
items: recipe2.items.map((id) => itemMap.get(id)).filter(Boolean)
|
|
1481
|
+
})),
|
|
1482
|
+
required_recipe: recipe ? !!recipe.name_loc.trim() : false,
|
|
1483
|
+
builds_into: []
|
|
1484
|
+
};
|
|
1485
|
+
});
|
|
1486
|
+
const buildsIntoMap = /* @__PURE__ */ new Map();
|
|
1487
|
+
processedItems.forEach((item) => {
|
|
1488
|
+
item.recipes.forEach((recipe) => {
|
|
1489
|
+
recipe.items.forEach((material) => {
|
|
1490
|
+
if (!buildsIntoMap.has(material.id)) {
|
|
1491
|
+
buildsIntoMap.set(material.id, []);
|
|
1492
|
+
}
|
|
1493
|
+
buildsIntoMap.get(material.id).push(itemMap.get(item.id));
|
|
1494
|
+
});
|
|
1495
|
+
});
|
|
1496
|
+
});
|
|
1497
|
+
return processedItems.map((item) => ({
|
|
1498
|
+
...item,
|
|
1499
|
+
builds_into: (buildsIntoMap.get(item.id) || []).map((target) => ({
|
|
1500
|
+
id: target.id,
|
|
1501
|
+
name: target.name,
|
|
1502
|
+
name_loc: target.name_loc
|
|
1503
|
+
}))
|
|
1504
|
+
}));
|
|
1505
|
+
}
|
|
1506
|
+
__name(getFormattedItemListData, "getFormattedItemListData");
|
|
1237
1507
|
function sec2time(sec) {
|
|
1238
1508
|
return sec ? (sec < 0 ? "-" : "") + Math.floor(Math.abs(sec) / 60) + ":" + ("00" + Math.abs(sec) % 60).slice(-2) : "--:--";
|
|
1239
1509
|
}
|
|
@@ -1398,11 +1668,19 @@ var Config = import_koishi2.Schema.intersect([
|
|
|
1398
1668
|
import_koishi2.Schema.object({
|
|
1399
1669
|
STRATZ_API_TOKEN: import_koishi2.Schema.string().required().role("secret"),
|
|
1400
1670
|
dataParsingTimeoutMinutes: import_koishi2.Schema.number().default(60).min(0).max(1440),
|
|
1401
|
-
urlInMessageType: import_koishi2.Schema.array(import_koishi2.Schema.union([import_koishi2.Schema.const("match"), import_koishi2.Schema.const("player"), import_koishi2.Schema.const("hero")])).role("checkbox"),
|
|
1402
1671
|
proxyAddress: import_koishi2.Schema.string()
|
|
1403
1672
|
}).i18n(Object.keys(GraphqlLanguageEnum).reduce((acc, cur) => (acc[cur] = globRequire_locales_schema_yml(`./locales/${cur}.schema.yml`)._config.base, acc), {})),
|
|
1404
1673
|
import_koishi2.Schema.intersect([
|
|
1405
1674
|
import_koishi2.Schema.object({
|
|
1675
|
+
urlInMessageType: import_koishi2.Schema.array(import_koishi2.Schema.union([import_koishi2.Schema.const("match"), import_koishi2.Schema.const("player"), import_koishi2.Schema.const("hero")])).role("checkbox"),
|
|
1676
|
+
maxSendItemCount: import_koishi2.Schema.number().default(5).min(1).max(10),
|
|
1677
|
+
showItemListAtTooMuchItems: import_koishi2.Schema.boolean().default(true),
|
|
1678
|
+
customItemAlias: import_koishi2.Schema.array(
|
|
1679
|
+
import_koishi2.Schema.object({
|
|
1680
|
+
keyword: import_koishi2.Schema.string().required(),
|
|
1681
|
+
alias: import_koishi2.Schema.string().required()
|
|
1682
|
+
})
|
|
1683
|
+
).default([]).role("table"),
|
|
1406
1684
|
rankBroadSwitch: import_koishi2.Schema.boolean().default(false)
|
|
1407
1685
|
}),
|
|
1408
1686
|
import_koishi2.Schema.union([
|
|
@@ -1414,7 +1692,7 @@ var Config = import_koishi2.Schema.intersect([
|
|
|
1414
1692
|
}),
|
|
1415
1693
|
import_koishi2.Schema.object({})
|
|
1416
1694
|
])
|
|
1417
|
-
]).i18n(Object.keys(GraphqlLanguageEnum).reduce((acc, cur) => (acc[cur] = globRequire_locales_schema_yml(`./locales/${cur}.schema.yml`)._config.
|
|
1695
|
+
]).i18n(Object.keys(GraphqlLanguageEnum).reduce((acc, cur) => (acc[cur] = globRequire_locales_schema_yml(`./locales/${cur}.schema.yml`)._config.message, acc), {})),
|
|
1418
1696
|
import_koishi2.Schema.intersect([
|
|
1419
1697
|
import_koishi2.Schema.object({
|
|
1420
1698
|
dailyReportSwitch: import_koishi2.Schema.boolean().default(false)
|
|
@@ -1835,7 +2113,7 @@ async function apply(ctx, config) {
|
|
|
1835
2113
|
}
|
|
1836
2114
|
await session.send(session.text(".querying_hero"));
|
|
1837
2115
|
try {
|
|
1838
|
-
let hero = await
|
|
2116
|
+
let hero = await queryHeroDetailsFromValve(heroId, languageTag);
|
|
1839
2117
|
hero = getFormattedHeroData(hero);
|
|
1840
2118
|
await session.send(
|
|
1841
2119
|
(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))
|
|
@@ -1887,6 +2165,88 @@ async function apply(ctx, config) {
|
|
|
1887
2165
|
return Array.isArray(heroIds) ? result : result[0][heroIds];
|
|
1888
2166
|
}
|
|
1889
2167
|
__name(getHeroNicknames, "getHeroNicknames");
|
|
2168
|
+
ctx.command("dota2tracker.query-item").alias("查询物品").action(async ({ session }, input_data) => {
|
|
2169
|
+
if (!input_data && !config.showItemListAtTooMuchItems) {
|
|
2170
|
+
await session.send(session.text(".empty_input"));
|
|
2171
|
+
return;
|
|
2172
|
+
}
|
|
2173
|
+
await session.send(session.text(".querying_item"));
|
|
2174
|
+
const languageTag = await getLanguageTag({ session });
|
|
2175
|
+
const currentGameVersion = await queryLastPatchNumber();
|
|
2176
|
+
let itemList;
|
|
2177
|
+
const cache = await ctx.cache.get("dt_itemlist_constants", languageTag);
|
|
2178
|
+
try {
|
|
2179
|
+
if (!cache || cache.gameVersion != currentGameVersion) {
|
|
2180
|
+
await session.send(session.text(".cache_building"));
|
|
2181
|
+
itemList = await getFormattedItemListData(languageTag);
|
|
2182
|
+
await ctx.cache.set("dt_itemlist_constants", languageTag, {
|
|
2183
|
+
gameVersion: currentGameVersion,
|
|
2184
|
+
itemList
|
|
2185
|
+
});
|
|
2186
|
+
} else {
|
|
2187
|
+
itemList = cache.itemList;
|
|
2188
|
+
}
|
|
2189
|
+
} catch (error) {
|
|
2190
|
+
ctx.logger.error(error);
|
|
2191
|
+
await session.send(session.text(".query_list_failed"));
|
|
2192
|
+
return;
|
|
2193
|
+
}
|
|
2194
|
+
const matchedItemList = searchItems(itemList, input_data, languageTag);
|
|
2195
|
+
if (!input_data || matchedItemList.length > config.maxSendItemCount || !matchedItemList.length) {
|
|
2196
|
+
if (!input_data) await session.send(session.text(".empty_input", { show: config.showItemListAtTooMuchItems }));
|
|
2197
|
+
if (matchedItemList.length > config.maxSendItemCount) await session.send(session.text(".too_many_items", { count: matchedItemList.length, max: config.maxSendItemCount, show: config.showItemListAtTooMuchItems }));
|
|
2198
|
+
if (input_data && matchedItemList.length === 0) await session.send(session.text(".not_found"));
|
|
2199
|
+
if (config.showItemListAtTooMuchItems && (matchedItemList.length || !input_data))
|
|
2200
|
+
await session.send(await ctx.puppeteer.render(await genImageHTML(matchedItemList.length ? matchedItemList : itemList, "itemlist", "item" /* Item */, ctx, languageTag)));
|
|
2201
|
+
} else {
|
|
2202
|
+
await session.send(session.text(".finded_items", { items: matchedItemList }));
|
|
2203
|
+
for (const litem of matchedItemList) {
|
|
2204
|
+
try {
|
|
2205
|
+
const item = Object.assign(await queryItemDetailsFromValve(litem.id, languageTag), litem);
|
|
2206
|
+
await session.send(await ctx.puppeteer.render(await genImageHTML(item, "item", "item" /* Item */, ctx, languageTag)));
|
|
2207
|
+
} catch (error) {
|
|
2208
|
+
ctx.logger.error(error);
|
|
2209
|
+
await session.send(session.text(".query_item_failed", [litem.name_loc]));
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
});
|
|
2214
|
+
function searchItems(items, keyword, languageTag) {
|
|
2215
|
+
if (!keyword) return [];
|
|
2216
|
+
const alias = constantLocales[languageTag].dota2tracker.items_alias[keyword];
|
|
2217
|
+
const exactMatch = items.filter(
|
|
2218
|
+
(item) => alias?.some((a) => item.name_loc.trim().toLowerCase() == a.toLowerCase()) || item.name_loc.trim().toLowerCase() === keyword.trim().toLowerCase() || Number.isInteger(Number(keyword)) && item.id === Number(keyword)
|
|
2219
|
+
);
|
|
2220
|
+
if (exactMatch.length) return exactMatch;
|
|
2221
|
+
return fuzzySearchItems([...alias ?? keyword], items);
|
|
2222
|
+
}
|
|
2223
|
+
__name(searchItems, "searchItems");
|
|
2224
|
+
function fuzzySearchItems(keywords, items) {
|
|
2225
|
+
const resultMap = /* @__PURE__ */ new Map();
|
|
2226
|
+
for (const item of items) {
|
|
2227
|
+
const cleanName = item.name_loc.toLowerCase().replace(/[^\p{L}\p{N}]/gu, "").trim();
|
|
2228
|
+
let matchAllKeywords = true;
|
|
2229
|
+
for (const keyword of keywords) {
|
|
2230
|
+
const cleanKeyword = keyword.toLowerCase().replace(/[^\p{L}\p{N}]/gu, "").trim();
|
|
2231
|
+
if (cleanKeyword.length === 0) continue;
|
|
2232
|
+
const keywordChars = Array.from(cleanKeyword);
|
|
2233
|
+
const isMatched = (
|
|
2234
|
+
// 完全连续匹配(如"水剑")
|
|
2235
|
+
cleanName.includes(cleanKeyword) || // 包含所有字符(如同时有"水"和"剑")
|
|
2236
|
+
keywordChars.every((c) => cleanName.includes(c))
|
|
2237
|
+
);
|
|
2238
|
+
if (!isMatched) {
|
|
2239
|
+
matchAllKeywords = false;
|
|
2240
|
+
break;
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
if (matchAllKeywords) {
|
|
2244
|
+
resultMap.set(item.id, item);
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
return Array.from(resultMap.values());
|
|
2248
|
+
}
|
|
2249
|
+
__name(fuzzySearchItems, "fuzzySearchItems");
|
|
1890
2250
|
ctx.on("ready", async () => {
|
|
1891
2251
|
ctx.model.extend("dt_subscribed_guilds", { id: "unsigned", guildId: "string", platform: "string" }, { autoInc: true });
|
|
1892
2252
|
ctx.model.extend(
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjtdev/koishi-plugin-dota2tracker",
|
|
3
3
|
"description": "koishi插件-追踪群友的DOTA2对局",
|
|
4
|
-
"version": "1.5.0-pre.
|
|
4
|
+
"version": "1.5.0-pre.5",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"dota2"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"dotaconstants": "^9.
|
|
30
|
+
"dotaconstants": "^9.4.0",
|
|
31
31
|
"ejs": "^3.1.10",
|
|
32
32
|
"moment": "^2.30.1"
|
|
33
33
|
},
|
package/readme.md
CHANGED
|
@@ -3,11 +3,8 @@
|
|
|
3
3
|
### 完整使用文档
|
|
4
4
|
[中文文档](https://sjtdev.github.io/koishi-plugin-dota2tracker/) | [English Documentation](https://sjtdev.github.io/koishi-plugin-dota2tracker/en-US/)
|
|
5
5
|
|
|
6
|
-
[](https://www.npmjs.com/package/@sjtdev/koishi-plugin-dota2tracker)
|
|
6
|
+
[](https://github.com/{username}/{repository}/releases/latest)
|
|
8
7
|
[](https://www.npmjs.com/package/@sjtdev/koishi-plugin-dota2tracker)
|
|
9
|
-
> [!TIP]
|
|
10
|
-
> 两个标签取版本号最高为最新版本
|
|
11
8
|
|
|
12
9
|
DOTA2Bot插件-提供自动追踪群友的最新对局的功能(需群友绑定),以及一系列查询功能。
|
|
13
10
|
### 安装
|
package/template/hero/hero_1.ejs
CHANGED
|
@@ -103,15 +103,15 @@
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
.hero .info .attrs > span.str::before {
|
|
106
|
-
background-image: url("
|
|
106
|
+
background-image: url("<%= utils.getImageUrl('hero_strength', ImageType.Icons) %>");
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
.hero .info .attrs > span.agi::before {
|
|
110
|
-
background-image: url("
|
|
110
|
+
background-image: url("<%= utils.getImageUrl('hero_agility', ImageType.Icons) %>");
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
.hero .info .attrs > span.int::before {
|
|
114
|
-
background-image: url("
|
|
114
|
+
background-image: url("<%= utils.getImageUrl('hero_intelligence', ImageType.Icons) %>");
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
.details {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<% const item = data; %>
|
|
2
|
+
<% (item.recipes.length ? item.recipes : [undefined]).forEach(recipe => { %>
|
|
3
|
+
<div class="recipes">
|
|
4
|
+
<% if (item.builds_into.length) { %>
|
|
5
|
+
<% const multiple = item.builds_into.length > 1 ? " multiple" : ""; %>
|
|
6
|
+
<div class="upper<%= multiple %>">
|
|
7
|
+
<% item.builds_into.forEach(item => { %>
|
|
8
|
+
<div class="item">
|
|
9
|
+
<img src="<%= utils.getImageUrl(item.name.startsWith("recipe_") ? "recipe" : item.name, ImageType.Items) %>">
|
|
10
|
+
<p><%= item.name_loc %></p>
|
|
11
|
+
</div>
|
|
12
|
+
<% }) %>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<div class="vline<%= multiple %>">
|
|
16
|
+
<% for( let index = 0; index < item.builds_into.length; index++ ) { %>
|
|
17
|
+
<div class="item line"></div>
|
|
18
|
+
<% } %>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="hline<%= multiple %>"></div>
|
|
21
|
+
<div class="vline<%= multiple ? " direct" : "" %>"><div class="item line"></div></div>
|
|
22
|
+
<% } %>
|
|
23
|
+
<div class="middle">
|
|
24
|
+
<div class="item">
|
|
25
|
+
<img src="<%= utils.getImageUrl(item.name.startsWith("recipe_") ? "recipe" : item.name, ImageType.Items) %>">
|
|
26
|
+
<p><%= item.name_loc %></p>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
<% if (item.recipes.length) { %>
|
|
30
|
+
<% if (item.required_recipe) {
|
|
31
|
+
recipe.items = recipe.items.concat((item.required_recipe ? [{name:"recipe",name_loc:$t("dota2tracker.template.recipe")}] : []))
|
|
32
|
+
} %>
|
|
33
|
+
<% const multiple = recipe.items.length > 1 ? " multiple" : ""; %>
|
|
34
|
+
<div class="vline<%= multiple ? " direct" : "" %>"><div class="item line"></div></div>
|
|
35
|
+
<div class="hline<%= multiple %>"></div>
|
|
36
|
+
<div class="vline<%= multiple %>">
|
|
37
|
+
<% for( let index = 0; index < recipe.items.length; index++ ) { %>
|
|
38
|
+
<div class="item line"></div>
|
|
39
|
+
<% } %>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="lower<%= multiple %>">
|
|
42
|
+
<% recipe.items.forEach(item => { %>
|
|
43
|
+
<div class="item">
|
|
44
|
+
<img src="<%= utils.getImageUrl(item.name.startsWith("recipe_") ? "recipe" : item.name, ImageType.Items) %>">
|
|
45
|
+
<p><%= item.name_loc %></p>
|
|
46
|
+
</div>
|
|
47
|
+
<% }) %>
|
|
48
|
+
</div>
|
|
49
|
+
<% } %>
|
|
50
|
+
</div>
|
|
51
|
+
<% }) %>
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
* {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 0;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
html,
|
|
7
|
+
body {
|
|
8
|
+
background-color: #000;
|
|
9
|
+
font-size: 16px;
|
|
10
|
+
width: 404px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.container {
|
|
14
|
+
border: #000 2px solid;
|
|
15
|
+
background-color: #222d35;
|
|
16
|
+
width: 400px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.container > * {
|
|
20
|
+
padding: 10px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.container > *.empty {
|
|
24
|
+
padding: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.header {
|
|
28
|
+
position: relative;
|
|
29
|
+
background-color: #32424e;
|
|
30
|
+
color: #fff;
|
|
31
|
+
display: flex;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.header > img {
|
|
35
|
+
width: 70px;
|
|
36
|
+
height: auto;
|
|
37
|
+
vertical-align: middle;
|
|
38
|
+
position: relative;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.header div {
|
|
42
|
+
margin-left: 10px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.header .name {
|
|
46
|
+
font-family: "KaiTi", "楷体", "楷体_GB2312", "STKaiti", serif;
|
|
47
|
+
text-shadow: 1px 1px 2px #111;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.header .name .item_id {
|
|
51
|
+
color: #999;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.header .cost {
|
|
55
|
+
display: flex;
|
|
56
|
+
color: #f4d652;
|
|
57
|
+
align-items: center;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.stats {
|
|
61
|
+
padding: 5px;
|
|
62
|
+
color: #667e9b;
|
|
63
|
+
font-size: 14px;
|
|
64
|
+
margin: 0 10px;
|
|
65
|
+
border-block: 1px solid #405159;
|
|
66
|
+
white-space: nowrap;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.stats p {
|
|
70
|
+
display: flex;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.stats .dmg_type span.Physical {
|
|
74
|
+
color: #ae2f28;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.stats .dmg_type span.Magical {
|
|
78
|
+
color: #5b93d1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.stats .dmg_type span.Pure {
|
|
82
|
+
color: #c29c4a;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.stats .dispellable span.Yes {
|
|
86
|
+
/* color: #c29c4a; */
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.stats .dispellable span.No {
|
|
90
|
+
color: #f00;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.stats .dispellable span.Strong {
|
|
94
|
+
color: #9828ae;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.stats .bkbpierce span.Yes {
|
|
98
|
+
color: #6add71;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.container > .attrs {
|
|
102
|
+
color: #aabbd2;
|
|
103
|
+
text-shadow: 1px 1px 0 #333;
|
|
104
|
+
/* padding-bottom: 0; */
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.value {
|
|
108
|
+
color: #fff;
|
|
109
|
+
font-weight: bold;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.abilities {
|
|
113
|
+
font-size: 14px;
|
|
114
|
+
margin: 10px;
|
|
115
|
+
padding: 0;
|
|
116
|
+
display: flex;
|
|
117
|
+
flex-direction: column;
|
|
118
|
+
gap: 6px;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.ability.passive {
|
|
122
|
+
background-color: #2d3c49;
|
|
123
|
+
color: #7e8b9e;
|
|
124
|
+
}
|
|
125
|
+
.ability.passive h1 {
|
|
126
|
+
color: #cce2ff;
|
|
127
|
+
background-image: linear-gradient(to right, #3b505e, #2b3c47);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.ability.active {
|
|
131
|
+
background-color: #2a3550;
|
|
132
|
+
color: #9ba2d4;
|
|
133
|
+
}
|
|
134
|
+
.ability.active h1 {
|
|
135
|
+
color: #AAAAFF;
|
|
136
|
+
background-image: linear-gradient(to right, #5155b9, #2a3550);
|
|
137
|
+
display: flex;
|
|
138
|
+
justify-content: space-between;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.ability h1 {
|
|
142
|
+
font-size: 14px;
|
|
143
|
+
padding: 6px 8px;
|
|
144
|
+
text-shadow: 1px 1px 2px #111;
|
|
145
|
+
font-weight: normal;
|
|
146
|
+
display: flex;
|
|
147
|
+
justify-content: space-between;
|
|
148
|
+
align-items: center;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.ability > p {
|
|
152
|
+
padding: 8px;
|
|
153
|
+
text-shadow: 1px 1px 2px #000;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.ability .attrs {
|
|
157
|
+
display: flex;
|
|
158
|
+
gap: 10px;
|
|
159
|
+
flex-wrap: wrap;
|
|
160
|
+
justify-content: flex-end;
|
|
161
|
+
max-width: 50%;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.ability .attr {
|
|
165
|
+
display: flex;
|
|
166
|
+
gap: 6px;
|
|
167
|
+
align-items: center;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.ability .attr > .icon {
|
|
171
|
+
width: 16px;
|
|
172
|
+
height: 16px;
|
|
173
|
+
border-radius: 4px;
|
|
174
|
+
border: 1px solid #000;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.notes {
|
|
178
|
+
font-size: 14px;
|
|
179
|
+
margin: 10px;
|
|
180
|
+
color: #beddf0;
|
|
181
|
+
background-color: #3b5566;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.lore {
|
|
185
|
+
margin: 10px;
|
|
186
|
+
/* margin-top: 20px; */
|
|
187
|
+
font-size: 12px;
|
|
188
|
+
color: #566d7e;
|
|
189
|
+
background-color: #172025;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.recipes {
|
|
193
|
+
overflow: hidden;
|
|
194
|
+
font-size: 12px;
|
|
195
|
+
color: #fff;
|
|
196
|
+
padding: 20px 50px;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.recipes > * {
|
|
200
|
+
display: flex;
|
|
201
|
+
width: 100%;
|
|
202
|
+
justify-content: center;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.recipes > *.multiple {
|
|
206
|
+
justify-content: space-between;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.recipes .item {
|
|
210
|
+
width: 60px;
|
|
211
|
+
text-align: center;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.recipes .item img {
|
|
215
|
+
width: 100%;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.hline.multiple {
|
|
219
|
+
width: calc(100% - 59px);
|
|
220
|
+
background-color: #fff;
|
|
221
|
+
height: 1px;
|
|
222
|
+
margin-left: 30px;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.recipes .line {
|
|
226
|
+
height: 5px;
|
|
227
|
+
background: linear-gradient(0deg, #fff, #fff) no-repeat center/1px 100%;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.recipes *.multiple .line,.recipes *.direct .line {
|
|
231
|
+
height: 10px;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.middle .item::after {
|
|
235
|
+
content: "";
|
|
236
|
+
display: block;
|
|
237
|
+
width: 1px;
|
|
238
|
+
height: 100%;
|
|
239
|
+
background-color: #fff;
|
|
240
|
+
position: absolute;
|
|
241
|
+
top: 0;
|
|
242
|
+
right: 0;
|
|
243
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
<% const item = data; %>
|
|
2
|
+
<%
|
|
3
|
+
// 构建占位符字典(兼容数值类型和百分比类型)
|
|
4
|
+
const valueMap = item.special_values.reduce((map, val) => {
|
|
5
|
+
map[val.name] = val.is_percentage ?
|
|
6
|
+
`${val.values_float.join("/")}%` : // 百分比类型加%后缀
|
|
7
|
+
val.values_float.join("/") // 普通数值直接取用
|
|
8
|
+
return map
|
|
9
|
+
}, {})
|
|
10
|
+
%>
|
|
11
|
+
<% function parseAbilityDesc(desc) {
|
|
12
|
+
const abilityRegExp = /<h1>(.*?)<\/h1>((?:(?!<h1>).|\n)*)/g;
|
|
13
|
+
return Array.from(desc.matchAll(abilityRegExp)).map(match => ({
|
|
14
|
+
name: match[1].trim(),
|
|
15
|
+
desc: match[2]
|
|
16
|
+
// 保留原有替换逻辑
|
|
17
|
+
// .replace(/<br>\s*<br>/g, '\n')
|
|
18
|
+
.replace(/%(\w+)%/g, (_, key) =>
|
|
19
|
+
`<span class="value">${valueMap[key] ?? `[${key}]`}</span>`
|
|
20
|
+
)
|
|
21
|
+
.replace(/%%/g, '<span class="value">%</span>')
|
|
22
|
+
.trim()
|
|
23
|
+
}));
|
|
24
|
+
} %>
|
|
25
|
+
<% function capitalize(str) {
|
|
26
|
+
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
27
|
+
} %>
|
|
28
|
+
<% function toArray(obj) {
|
|
29
|
+
return Array.isArray(obj) ? obj : [obj];
|
|
30
|
+
} %>
|
|
31
|
+
<!DOCTYPE html>
|
|
32
|
+
<html lang="<%= languageTag %>">
|
|
33
|
+
<head>
|
|
34
|
+
<meta charset="UTF-8">
|
|
35
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
36
|
+
<%- `<style>` %>
|
|
37
|
+
<%- include('./item/style.css') %>
|
|
38
|
+
<%- `</style>` %>
|
|
39
|
+
</head>
|
|
40
|
+
<body>
|
|
41
|
+
<div class="container">
|
|
42
|
+
<div class="header">
|
|
43
|
+
<img src="<%= utils.getImageUrl(item.name, ImageType.Items) %>">
|
|
44
|
+
<div>
|
|
45
|
+
<p class="name"><%= item.name_loc %> <span class="item_id"><%= item.name %></span></p>
|
|
46
|
+
<% if (item.item_cost) { %>
|
|
47
|
+
<p class="cost"><img style="height: 20px; width: auto; margin-right: 4px;" src="<%= utils.getImageUrl("gold", ImageType.Icons) %>"> <%= item.item_cost %></p>
|
|
48
|
+
<% } %>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
<% const citem = dotaconstants.items[item.name]; %>
|
|
52
|
+
<% if (citem?.abilities?.length) { %>
|
|
53
|
+
<div class="stats">
|
|
54
|
+
<p class="behavior">
|
|
55
|
+
<%= $t("dota2tracker.template.ability") %><!--
|
|
56
|
+
--><% if (citem.abilities.some(ability => capitalize(ability.type) === 'Active')) { %><!--
|
|
57
|
+
--><%= toArray(citem.behavior).map((beh)=>$t("dota2tracker.template.behavior."+beh)).join("/") %><!--
|
|
58
|
+
--><% } else { %><!--
|
|
59
|
+
--><%= $t("dota2tracker.template.behavior.Passive") %><!--
|
|
60
|
+
--><% } %>
|
|
61
|
+
</p>
|
|
62
|
+
<% if (citem.target_team && citem.target_team.length) { %>
|
|
63
|
+
<p class="target_team"><%= $t("dota2tracker.template.affects") %><%= toArray(citem.target_team).map((tt) => $t("dota2tracker.template.target_team."+tt)).join("/") %></p>
|
|
64
|
+
<% } %>
|
|
65
|
+
<% if (citem.dmg_type) { %>
|
|
66
|
+
<p class="dmg_type"><%= $t("dota2tracker.template.damage_type") %><span class="<%= citem.dmg_type %>"><%= $t("dota2tracker.template.damage_type_"+citem.dmg_type) %></span></p>
|
|
67
|
+
<% } %>
|
|
68
|
+
<% if (citem.dispellable) { %>
|
|
69
|
+
<p class="dispellable"><%= $t("dota2tracker.template.dispellable") %><span class="<%= citem.dispellable %>"><%= $t("dota2tracker.template."+(citem.dispellable == "Strong Dispels Only" ? "dispellable_Strong" : citem.dispellable)) %></span></p>
|
|
70
|
+
<% } %>
|
|
71
|
+
<% if (citem.bkbpierce) { %>
|
|
72
|
+
<p class="bkbpierce"><%= $t("dota2tracker.template.bkbpierce") %><span class="<%= citem.bkbpierce %>"><%= $t("dota2tracker.template."+citem.bkbpierce) %></span></p>
|
|
73
|
+
<% } %>
|
|
74
|
+
</div>
|
|
75
|
+
<% } %>
|
|
76
|
+
<div class="attrs">
|
|
77
|
+
<% item.special_values.filter(value=>value.heading_loc).forEach(value=>{ %>
|
|
78
|
+
<%
|
|
79
|
+
const [_, sign = '+', rawText] = value.heading_loc.match(/^([+-]?)(.*)/) || [];
|
|
80
|
+
const processedText = rawText.replace(/\$(\w+)/, (_, p1) => $t(`dota2tracker.template.item_token.${p1}`));
|
|
81
|
+
%>
|
|
82
|
+
<p class="attr_item <%= value.values_float[0] > 0 ? "positive" : "negative" %>">
|
|
83
|
+
<%= sign %>
|
|
84
|
+
<span class="value"><%= value.values_float.map(v=>v+(value.is_percentage?"%":"")).join("/") %></span>
|
|
85
|
+
<span class="desc"><%= processedText %></span>
|
|
86
|
+
</p>
|
|
87
|
+
<% }) %>
|
|
88
|
+
</div>
|
|
89
|
+
<% const abilities = parseAbilityDesc(item.desc_loc, valueMap); %>
|
|
90
|
+
<% if (abilities.length) { %>
|
|
91
|
+
<div class="abilities">
|
|
92
|
+
<% abilities.forEach(ability => { %>
|
|
93
|
+
<% const type = ability.name.startsWith($t("dota2tracker.template.behavior.Passive")) ? "passive" : "active"; %>
|
|
94
|
+
<div class="ability <%= type %>">
|
|
95
|
+
<h1>
|
|
96
|
+
<p class="name"><%= ability.name %></p>
|
|
97
|
+
<% if (type === "active") { %>
|
|
98
|
+
<div class="attrs">
|
|
99
|
+
<% if (item.mana_costs && item.mana_costs[0]) { %>
|
|
100
|
+
<div class="attr">
|
|
101
|
+
<div class="icon" style="background: linear-gradient(#00A4DB, #007196);"></div>
|
|
102
|
+
<span class="value"><%= item.mana_costs.join("/") %></span>
|
|
103
|
+
</div>
|
|
104
|
+
<% } %>
|
|
105
|
+
<% if (item.cooldowns && item.cooldowns[0]) { %>
|
|
106
|
+
<div class="attr">
|
|
107
|
+
<img class="icon" src="<%= utils.getImageUrl("cooldown", ImageType.Icons) %>">
|
|
108
|
+
<span class="value"><%= item.cooldowns.join("/") %></span>
|
|
109
|
+
</div>
|
|
110
|
+
<% } %>
|
|
111
|
+
</div>
|
|
112
|
+
<% } %>
|
|
113
|
+
</h1>
|
|
114
|
+
<p><%- ability.desc %></p>
|
|
115
|
+
</div>
|
|
116
|
+
<% }); %>
|
|
117
|
+
</div>
|
|
118
|
+
<% } %>
|
|
119
|
+
<% const notes = item.notes_loc.map(note => note.replace(/%(\w+)%/g, (_, key) => `<span class="value">${valueMap[key] ?? `[${key}]`}</span>`).replace(/%%/g, '<span class="value">%</span>').trim()); %>
|
|
120
|
+
<% if (notes && notes.length) { %>
|
|
121
|
+
<div class="notes">
|
|
122
|
+
<% notes.forEach(note => { %>
|
|
123
|
+
<p class="note"><%- note %></p>
|
|
124
|
+
<% }) %>
|
|
125
|
+
</div>
|
|
126
|
+
<% } %>
|
|
127
|
+
<% if (item.lore_loc) { %>
|
|
128
|
+
<div class="lore">
|
|
129
|
+
<p><%= item.lore_loc %></p>
|
|
130
|
+
</div>
|
|
131
|
+
<% } %>
|
|
132
|
+
</div>
|
|
133
|
+
<% if (item.recipes.length || item.builds_into.length) { %>
|
|
134
|
+
<%- include("./item/recipe") %>
|
|
135
|
+
<% } %>
|
|
136
|
+
</body>
|
|
137
|
+
</html>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<%
|
|
2
|
+
function calculateFontSize(text) {
|
|
3
|
+
// 中文字符正则(包含常见中文符号)
|
|
4
|
+
const chineseRegex = /[\u4e00-\u9fa5\u3000-\u303f\uff00-\uffef]/g
|
|
5
|
+
// 计算等效字符数(中文按2单位,其他按1单位)
|
|
6
|
+
const totalUnits = text.split('').reduce((acc, char) => {
|
|
7
|
+
return acc + (chineseRegex.test(char) ? 2 : 1)
|
|
8
|
+
}, 0)
|
|
9
|
+
|
|
10
|
+
// 容器可用宽度(根据.item的48px减去2px边距)
|
|
11
|
+
const maxWidth = 44
|
|
12
|
+
// 根据经验公式计算字号(系数需实际调试)
|
|
13
|
+
let fontSize = Math.floor((maxWidth / totalUnits) * 1.8)
|
|
14
|
+
|
|
15
|
+
// 边界限制
|
|
16
|
+
return Math.min(12, Math.max(6, fontSize))
|
|
17
|
+
}
|
|
18
|
+
%>
|
|
19
|
+
<!DOCTYPE html>
|
|
20
|
+
<html lang="en">
|
|
21
|
+
<head>
|
|
22
|
+
<meta charset="UTF-8" />
|
|
23
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
24
|
+
<style>
|
|
25
|
+
* {
|
|
26
|
+
margin: 0;
|
|
27
|
+
padding: 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
html,
|
|
31
|
+
body {
|
|
32
|
+
height: auto;
|
|
33
|
+
background-color: #000;
|
|
34
|
+
color: #fff;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
html {
|
|
38
|
+
width: 232px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
body {
|
|
42
|
+
width: 220px;
|
|
43
|
+
margin: 6px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.container {
|
|
47
|
+
width: 220px;
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-wrap: wrap;
|
|
50
|
+
justify-content: space-between;
|
|
51
|
+
align-items: center;
|
|
52
|
+
row-gap: 8px;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.container img {
|
|
56
|
+
width: 44px;
|
|
57
|
+
height: 32px;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.container .item {
|
|
61
|
+
width: 48px;
|
|
62
|
+
height: 54px;
|
|
63
|
+
display: flex;
|
|
64
|
+
flex-direction: column;
|
|
65
|
+
font-size: 12px;
|
|
66
|
+
align-items: center;
|
|
67
|
+
justify-content: space-around;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.name {
|
|
71
|
+
/* white-space: nowrap; */
|
|
72
|
+
overflow: hidden;
|
|
73
|
+
text-overflow: ellipsis;
|
|
74
|
+
text-align: center;
|
|
75
|
+
line-height: 1.2;
|
|
76
|
+
min-height: 12px;
|
|
77
|
+
}
|
|
78
|
+
</style>
|
|
79
|
+
</head>
|
|
80
|
+
<body>
|
|
81
|
+
<% const items = data; %>
|
|
82
|
+
<div class="container">
|
|
83
|
+
<% items.forEach(function(item) { %>
|
|
84
|
+
<div class="item">
|
|
85
|
+
<img src="<%= utils.getImageUrl(item.name, ImageType.Items) %>" />
|
|
86
|
+
<div class="name" <%- `style="font-size: ${calculateFontSize(item.name_loc)}px"` %>>
|
|
87
|
+
<%= item.name_loc %>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
<% }); %>
|
|
91
|
+
</div>
|
|
92
|
+
</body>
|
|
93
|
+
</html>
|
|
@@ -483,7 +483,7 @@
|
|
|
483
483
|
}
|
|
484
484
|
|
|
485
485
|
.item.recipe {
|
|
486
|
-
background-image: url("
|
|
486
|
+
background-image: url("<%= utils.getImageUrl('recipe', ImageType.Items) %>");
|
|
487
487
|
background-size: 100%;
|
|
488
488
|
}
|
|
489
489
|
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
<img src="${item ? utils.getImageUrl(item.name, ImageType.Items) : ""}" alt="" />
|
|
124
124
|
</div>`).join("")}
|
|
125
125
|
</div>`:`
|
|
126
|
-
<img class="bear_icon" src="
|
|
126
|
+
<img class="bear_icon" src="${utils.getImageUrl("lone_druid_spirit_bear", ImageType.Abilities)}" alt="">
|
|
127
127
|
<div class="bear">
|
|
128
128
|
${player.unitItems.map((item) =>`
|
|
129
129
|
<div class="item${item?.isRecipe ? " recipe" : ""}" data-id="${item?.id??0}">
|
|
@@ -180,7 +180,7 @@
|
|
|
180
180
|
%>
|
|
181
181
|
<!-- 新增的经济图表 -->
|
|
182
182
|
<svg width="<%= svgWidth %>" height="<%= svgHeight %>" xmlns="http://www.w3.org/2000/svg">
|
|
183
|
-
<text x="50%" y="30" text-anchor="middle" font-size="16" font-weight="bold"
|
|
183
|
+
<text x="50%" y="30" text-anchor="middle" font-size="16" font-weight="bold"><%= $t("dota2tracker.template.networth") %></text>
|
|
184
184
|
<!-- 横轴线与标签 -->
|
|
185
185
|
<% for (let i = 0; i < 5; i++) { %>
|
|
186
186
|
<% const y = padding + i * ((svgHeight - padding * 2) / 4) %>
|
|
@@ -114,7 +114,7 @@ ${generateLevelCircle(rivals[1].stats.experiencePerMinute.slice(0, Math.min(11,
|
|
|
114
114
|
}
|
|
115
115
|
%>
|
|
116
116
|
<div class="lane_outcome">
|
|
117
|
-
<h4 class="title"
|
|
117
|
+
<h4 class="title"><%= $t("dota2tracker.template.lane") %></h4>
|
|
118
118
|
<div class="panel">
|
|
119
119
|
<div class="lane">
|
|
120
120
|
<div class="title">
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<%- include('./match_2+/charts') %>
|
|
18
18
|
<%- include('./match_2+/lane_outcome') %>
|
|
19
19
|
<% } else { %>
|
|
20
|
-
<div class="tip"
|
|
20
|
+
<div class="tip"><%= $t("dota2tracker.template.empty_extra_info") %></div>
|
|
21
21
|
<% } %>
|
|
22
22
|
</section>
|
|
23
23
|
</body>
|