@sjtdev/koishi-plugin-dota2tracker 2.3.2 → 2.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +24 -0
- package/lib/index.js +219 -112
- package/lib/templates/hero/hero_1/base.css +1 -0
- package/lib/templates/hero/hero_1.ejs +1 -1
- package/lib/templates/match/match_2+/extra.css +1 -1
- package/lib/templates/match/match_2+/map.ejs +5 -3
- package/lib/templates/report/daily.ejs +0 -8
- package/package.json +2 -5
- package/dist/index.js +0 -1
package/changelog.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# 更新日志
|
|
2
2
|
|
|
3
|
+
### [2.3.3](https://github.com/sjtdev/koishi-plugin-dota2tracker/compare/v2.3.2...v2.3.3) (2026-01-16)
|
|
4
|
+
|
|
5
|
+
### ✨ 新增功能
|
|
6
|
+
|
|
7
|
+
* **command:** 新增`TaskMessenger`实现调用指令时在回复正文或错误信息后将**撤回/删除**如“正在查询****,请稍候……”之类的提示语句。 ([bc987d2](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/bc987d2b3ee2774d9f9cc1894892333a398629cf))
|
|
8
|
+
* **config/autoRecallTips:** 为新增的**提示消息撤回**功能添加配置项`autoRecallTips`,默认启用。 ([31e173a](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/31e173a2e47a5b5b92535e8a93f54514f2ef9890))
|
|
9
|
+
|
|
10
|
+
### 🚀 功能优化
|
|
11
|
+
|
|
12
|
+
* **command/hero-of-the-day:** 适配提示消息撤回;增加了提示等待信息与错误提示信息。 ([43b9aa5](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/43b9aa5fd4364637148b34ff407f75faad0320ac))
|
|
13
|
+
* **command/query-hero:** 适配提示消息撤回;增加了查询失败的错误提示信息。 ([d7e577c](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/d7e577c749a19768f8852cbe9eacee24ffa9f150))
|
|
14
|
+
* **command/query-item:** 适配提示消息撤回;优化判断逻辑。 ([f3ae006](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/f3ae006eb93b49661cc10c58c201ffa279fb3462))
|
|
15
|
+
* **command/query-match:** 适配提示消息撤回;增加了查询失败时的错误提示信息。 ([b7a9d77](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/b7a9d774bd95ea0836bfe8d133a2c1a4a11c2050))
|
|
16
|
+
* **command/query-player:** 适配提示消息撤回;增加了查询失败时的错误提示信息。 ([476a7bc](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/476a7bc98fe275e3049e1f0f7a2efbee154e0699))
|
|
17
|
+
* **command/query-recent-match:** 适配提示消息撤回;优化了错误处理逻辑。 ([4ad88a3](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/4ad88a32f2bb9a053f757cda986c8fa6e4ceb27e))
|
|
18
|
+
* **configs:** 移除此前声明**已弃用**的配置项`suppressStratzNetworkErrors`。 ([f602ec3](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/f602ec34d8b5c37d9d936d82c9420e80ab1965a7))
|
|
19
|
+
* **console:** 移除**控制台**相关减小📦体积。想不到这玩意能做什么。 ([3002a03](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/3002a035adcdd87eb882c21ef32473bd167a521b))
|
|
20
|
+
|
|
21
|
+
### 🐛 Bug 修复
|
|
22
|
+
|
|
23
|
+
* **templates/match_2+:** 尝试修复部分场景下t4时间标签错误显示的问题。 ([92f2521](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/92f2521f47a8483889ca632f4abed3f10ee64092))
|
|
24
|
+
* **templates/match_2+:** 使`opendota-adapter`支持使用**opendota数据源**时正确渲染小地图图标与时间 ([2bedf8d](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/2bedf8d10071b4043eece1e4431ce2bdf86460c8))
|
|
25
|
+
* **templates/match_2+:** 修复`v2.3.0`添加小地图后,未解析提示、opendota数据提示样式不正确的问题。 ([4559509](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/455950977cce0f51648f2378f4cb46a21f4361d1))
|
|
26
|
+
|
|
3
27
|
### [2.3.2](https://github.com/sjtdev/koishi-plugin-dota2tracker/compare/v2.3.1...v2.3.2) (2025-12-18)
|
|
4
28
|
|
|
5
29
|
### 🚀 功能优化
|
package/lib/index.js
CHANGED
|
@@ -768,14 +768,14 @@ var require_zh_CN_constants = __commonJS({
|
|
|
768
768
|
// src/locales/en-US.command.yml
|
|
769
769
|
var require_en_US_command = __commonJS({
|
|
770
770
|
"src/locales/en-US.command.yml"(exports2, module2) {
|
|
771
|
-
module2.exports = { commands: { dota2tracker: { description: 'A series of commands for Dota 2 Tracker. Use "dota2tracker -h" to see all available commands.', subscribe: { description: "Subscribes the current channel to Dota 2 match tracking.", usage: "After subscribing, players need to bind their Steam ID in this channel. The bot will then track new matches of bound players and post image-based reports upon completion of parsing by Stratz.", examples: "subscribe", messages: { subscribe_success: "Subscription successful.", subscribed: "This Channel has been subscribed, no need to subscribe again." } }, unsubscribe: { description: "Unsubscribes the current channel from match tracking.", usage: "Unsubscribes the current channel from match tracking.", examples: "unsubscribe", messages: { unsubscribe_success: "Unsubscription successful.", not_subscribed: "This Channel has not been subscribed yet, so there is no need to unsubscribe." } }, bind: { description: "Binds your SteamID to your account in the current channel.", usage: 'Bind your SteamID to your account. If the channel is subscribed, your new match data will be posted automatically. Nicknames containing spaces must be enclosed in double quotes ("").', 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: "Unbinds your personal information in the current channel.", usage: "Unbind your personal information in the current channel.", examples: "unbind", messages: { unbind_success: "Unbinding successful.", not_binded: "Not bound, no need to unbind." } }, rename: { description: "Changes the nickname set during binding.", usage: 'Change the nickname set during binding. Nicknames containing spaces must be enclosed in double quotes ("").', 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.", nick_name_same: "The input content is the same as the original nickname and does not need to be renamed." } }, "query-members": { description: "Queries the players bound in this channel and generates an info image.", usage: "Queries the players bound in this channel and generates an informational image.", examples: "query-members", messages: { title: "Guild DOTA 2 Roster (Total: {count})", table_headers: { nickname: "Nickname", winrate: "Win Rate (L10)", last_match: "Last Match" }, 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.", usage: "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: { querying_match: "Searching for match details, please wait...", query_failed: "Failed to get the player's recent match.", 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: { querying_player: "Retrieving player data, please wait...", query_failed: "Failed to get player information." } }, "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.\nYou can set the maximum number of items to send per query on the configuration page, as well as whether to send the item list when the limit is exceeded or parameters are not entered.", 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}" } }, "hero-of-the-day": { description: "Get hero recommendations for the day.", usage: "Fetches recent and lifetime match history to recommend heroes based on parameters like wins, performance score, and hot streaks.\nThe parameter can be a player's SteamID or the nickname of a player bound in this group. If no parameter is provided, it will try to look up the command caller's SteamID.", options: { days: "-d <number> The range of recent days to consider, default is 30." }, examples: 'hero-of-the-day\nhero-of-the-day -d 60\nhero-of-the-day 1234567890\nhero-of-the-day "John Doe"', messages: { title_recommendation: "Today's Recommendation:", recommendation_intro: "The recommended heroes for you today are:", recommendation_heroes: "{#each heroes as hero}{hero}{#if hero !== heroes[heroes.length - 1]}, {/if}{/each}", recommendation_type_lifetime_only: "Your recent match history is empty. This recommendation is based on your lifetime statistics.", recommendation_type_no_record: "Recommendations cannot be generated due to a lack of recent and lifetime match data.", recommendation_type_anonymous: "Recommendations cannot be generated because your profile data is private.", details: { pool_description: "The recommendation is generated by scoring your recent and lifetime hero performance, sorting by total score, and then randomly selecting from the top 10 heroes weighted by their scores.", table_intro: "Below is the detailed score breakdown for the top 10 heroes.", table_headers: { hero: "Hero", recent_wins: "Recent Wins Score", lifetime_wins: "Lifetime Wins<br>(Logarithmic)", imp_bonus: "IMP Bonus", is_hot_streak: "Hot Streak", total_score: "Total Score" }, scoring_formula: "Current Scoring Formula: [Recent Wins x 1] + [log(Lifetime Wins + 1) x 5] + [Recent IMP x 0.1]", hot_streak_desc: "If a hero was played in the last 3 days, it's considered a 'Hot Streak' hero, receiving a 20% bonus to its total score." }, title_meta: "Meta Trends:", meta_intro: "Top 3 advantage heroes for each position with a <b>pick rate ≥2%</b> within ±1 of your rank bracket ({tiers}) over the last week, sorted by win rate:", meta_table_header: "Hero (Pick% Win%)", meta_position: "Pos {pos}:" } }, common: { messages: { user_not_binded_in_channel: "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.", user_not_in_group: "Command failed.\nCurrently not in a group chat, you must provide the specified player's SteamID.", invalid_input_include_steam_id: "Invalid SteamID and the player was not found in this group by the given input." } }, help: { description: "Get detailed information for all commands and the link to the online documentation.", usage: "Get detailed information for all commands and the link to the online documentation.", examples: "help", messages: { header: "Below is the full list of plugin commands.\n※Note: <arg> is a required argument, and [arg] is an optional argument. Please see the 'Examples' column for specific usage.", footer: "For more information on plugin configuration, template showcases, and other details, please visit the online documentation:\nhttps://sjtdev.github.io/koishi-plugin-dota2tracker/en-US/", table_headers: { command: "Command", alias: "Alias", arguments: "Arguments", description: "Description", options: "Options", examples: "Examples" } } } } } };
|
|
771
|
+
module2.exports = { commands: { dota2tracker: { description: 'A series of commands for Dota 2 Tracker. Use "dota2tracker -h" to see all available commands.', subscribe: { description: "Subscribes the current channel to Dota 2 match tracking.", usage: "After subscribing, players need to bind their Steam ID in this channel. The bot will then track new matches of bound players and post image-based reports upon completion of parsing by Stratz.", examples: "subscribe", messages: { subscribe_success: "Subscription successful.", subscribed: "This Channel has been subscribed, no need to subscribe again." } }, unsubscribe: { description: "Unsubscribes the current channel from match tracking.", usage: "Unsubscribes the current channel from match tracking.", examples: "unsubscribe", messages: { unsubscribe_success: "Unsubscription successful.", not_subscribed: "This Channel has not been subscribed yet, so there is no need to unsubscribe." } }, bind: { description: "Binds your SteamID to your account in the current channel.", usage: 'Bind your SteamID to your account. If the channel is subscribed, your new match data will be posted automatically. Nicknames containing spaces must be enclosed in double quotes ("").', 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: "Unbinds your personal information in the current channel.", usage: "Unbind your personal information in the current channel.", examples: "unbind", messages: { unbind_success: "Unbinding successful.", not_binded: "Not bound, no need to unbind." } }, rename: { description: "Changes the nickname set during binding.", usage: 'Change the nickname set during binding. Nicknames containing spaces must be enclosed in double quotes ("").', 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.", nick_name_same: "The input content is the same as the original nickname and does not need to be renamed." } }, "query-members": { description: "Queries the players bound in this channel and generates an info image.", usage: "Queries the players bound in this channel and generates an informational image.", examples: "query-members", messages: { title: "Guild DOTA 2 Roster (Total: {count})", table_headers: { nickname: "Nickname", winrate: "Win Rate (L10)", last_match: "Last Match" }, 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.", usage: "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: { querying_match: "Searching for match details, please wait...", query_failed: "Failed to get the player's recent match.", 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: { querying_player: "Retrieving player data, please wait...", query_failed: "Failed to get player information." } }, "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.\nYou can set the maximum number of items to send per query on the configuration page, as well as whether to send the item list when the limit is exceeded or parameters are not entered.", 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}" } }, "hero-of-the-day": { description: "Get hero recommendations for the day.", usage: "Fetches recent and lifetime match history to recommend heroes based on parameters like wins, performance score, and hot streaks.\nThe parameter can be a player's SteamID or the nickname of a player bound in this group. If no parameter is provided, it will try to look up the command caller's SteamID.", options: { days: "-d <number> The range of recent days to consider, default is 30." }, examples: 'hero-of-the-day\nhero-of-the-day -d 60\nhero-of-the-day 1234567890\nhero-of-the-day "John Doe"', messages: { title_recommendation: "Today's Recommendation:", recommendation_intro: "The recommended heroes for you today are:", recommendation_heroes: "{#each heroes as hero}{hero}{#if hero !== heroes[heroes.length - 1]}, {/if}{/each}", recommendation_type_lifetime_only: "Your recent match history is empty. This recommendation is based on your lifetime statistics.", recommendation_type_no_record: "Recommendations cannot be generated due to a lack of recent and lifetime match data.", recommendation_type_anonymous: "Recommendations cannot be generated because your profile data is private.", details: { pool_description: "The recommendation is generated by scoring your recent and lifetime hero performance, sorting by total score, and then randomly selecting from the top 10 heroes weighted by their scores.", table_intro: "Below is the detailed score breakdown for the top 10 heroes.", table_headers: { hero: "Hero", recent_wins: "Recent Wins Score", lifetime_wins: "Lifetime Wins<br>(Logarithmic)", imp_bonus: "IMP Bonus", is_hot_streak: "Hot Streak", total_score: "Total Score" }, scoring_formula: "Current Scoring Formula: [Recent Wins x 1] + [log(Lifetime Wins + 1) x 5] + [Recent IMP x 0.1]", hot_streak_desc: "If a hero was played in the last 3 days, it's considered a 'Hot Streak' hero, receiving a 20% bonus to its total score." }, title_meta: "Meta Trends:", meta_intro: "Top 3 advantage heroes for each position with a <b>pick rate ≥2%</b> within ±1 of your rank bracket ({tiers}) over the last week, sorted by win rate:", meta_table_header: "Hero (Pick% Win%)", meta_position: "Pos {pos}:", querying: "Retrieving player stats and hero win rates, please wait...", query_failed: "Command failed." } }, common: { messages: { user_not_binded_in_channel: "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.", user_not_in_group: "Command failed.\nCurrently not in a group chat, you must provide the specified player's SteamID.", invalid_input_include_steam_id: "Invalid SteamID and the player was not found in this group by the given input." } }, help: { description: "Get detailed information for all commands and the link to the online documentation.", usage: "Get detailed information for all commands and the link to the online documentation.", examples: "help", messages: { header: "Below is the full list of plugin commands.\n※Note: <arg> is a required argument, and [arg] is an optional argument. Please see the 'Examples' column for specific usage.", footer: "For more information on plugin configuration, template showcases, and other details, please visit the online documentation:\nhttps://sjtdev.github.io/koishi-plugin-dota2tracker/en-US/", table_headers: { command: "Command", alias: "Alias", arguments: "Arguments", description: "Description", options: "Options", examples: "Examples" } } } } } };
|
|
772
772
|
}
|
|
773
773
|
});
|
|
774
774
|
|
|
775
775
|
// src/locales/en-US.schema.yml
|
|
776
776
|
var require_en_US_schema = __commonJS({
|
|
777
777
|
"src/locales/en-US.schema.yml"(exports2, module2) {
|
|
778
|
-
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 if not using a proxy. \n※Cannot use the global proxy address configured by the `proxy-agent` plugin. This option must be set if you want to use a proxy.", suppressStratzNetworkErrors: "**Please use the `suppressApiNetworkErrors` option below, which applies to both Stratz and OpenDota. \nThis option is still effective. If either this or `suppressApiNetworkErrors` is enabled, Stratz/OpenDota logs will be downgraded to debug output. \nThis option will be removed in a future version.**", suppressApiNetworkErrors: "When enabled, Stratz/OpenDota network error logs will be output at the debug level. \n(e.g., timeouts, network connection issues, but excludes 403 Forbidden) \nKoishi does not display debug-level logs by default. To enable debug log display, please see [📖 Configs#suppressapinetworkerrors](http://sjtdev.github.io/koishi-plugin-dota2tracker/configs.html#suppressapinetworkerrors-boolean)", enableOpenDotaFallback: "Enable OpenDota as a fallback data source for match tracking and query-match features.", OPENDOTA_API_KEY: "Your paid subscription API key for OpenDota. \nSee https://www.opendota.com/api-keys for details. \nFree users should leave this blank.", OpenDotaIPStack: "If you experience frequent failures when accessing the OpenDota API, it might be caused by a faulty IPv6 environment. \nSetting this option will force the use of IPv4 when accessing the OpenDota API to try and resolve the issue." }, message: { $desc: "Message Settings", useHeroNicknames: "When disabled, only the official hero names will be used.", 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 [📖 Template Display](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", templateFonts: 'Font names used in the template. Requires font files installed on the koishi host machine. \nMultiple fonts can be added; the system will use the first available font from top to bottom. \nIf all fonts are unavailable, falls back to system defaults. \nImportant formatting rules: \n- Enclose font names in quotes (" ") if they contain spaces or special characters (recommended for all font names)\n- Do NOT enclose generic font family names (e.g. sans-serif, monospace) in quotes\nExamples:\n```\n"Microsoft YaHei"\nsans-serif\n```\nFor details on font-family syntax, see:\n[📖 MDN: font-family](https://developer.mozilla.org/en-US/docs/Web/CSS/font-family)' } } };
|
|
778
|
+
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 if not using a proxy. \n※Cannot use the global proxy address configured by the `proxy-agent` plugin. This option must be set if you want to use a proxy.", suppressStratzNetworkErrors: "**Please use the `suppressApiNetworkErrors` option below, which applies to both Stratz and OpenDota. \nThis option is still effective. If either this or `suppressApiNetworkErrors` is enabled, Stratz/OpenDota logs will be downgraded to debug output. \nThis option will be removed in a future version.**", suppressApiNetworkErrors: "When enabled, Stratz/OpenDota network error logs will be output at the debug level. \n(e.g., timeouts, network connection issues, but excludes 403 Forbidden) \nKoishi does not display debug-level logs by default. To enable debug log display, please see [📖 Configs#suppressapinetworkerrors](http://sjtdev.github.io/koishi-plugin-dota2tracker/configs.html#suppressapinetworkerrors-boolean)", enableOpenDotaFallback: "Enable OpenDota as a fallback data source for match tracking and query-match features.", OPENDOTA_API_KEY: "Your paid subscription API key for OpenDota. \nSee https://www.opendota.com/api-keys for details. \nFree users should leave this blank.", OpenDotaIPStack: "If you experience frequent failures when accessing the OpenDota API, it might be caused by a faulty IPv6 environment. \nSetting this option will force the use of IPv4 when accessing the OpenDota API to try and resolve the issue." }, message: { $desc: "Message Settings", useHeroNicknames: "When disabled, only the official hero names will be used.", 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" }, autoRecallTips: 'Automatically recall tip messages after the command finishes, e.g., "Searching for match details, please wait..."' }, 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 [📖 Template Display](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", templateFonts: 'Font names used in the template. Requires font files installed on the koishi host machine. \nMultiple fonts can be added; the system will use the first available font from top to bottom. \nIf all fonts are unavailable, falls back to system defaults. \nImportant formatting rules: \n- Enclose font names in quotes (" ") if they contain spaces or special characters (recommended for all font names)\n- Do NOT enclose generic font family names (e.g. sans-serif, monospace) in quotes\nExamples:\n```\n"Microsoft YaHei"\nsans-serif\n```\nFor details on font-family syntax, see:\n[📖 MDN: font-family](https://developer.mozilla.org/en-US/docs/Web/CSS/font-family)' } } };
|
|
779
779
|
}
|
|
780
780
|
});
|
|
781
781
|
|
|
@@ -796,14 +796,14 @@ var require_en_US = __commonJS({
|
|
|
796
796
|
// src/locales/zh-CN.command.yml
|
|
797
797
|
var require_zh_CN_command = __commonJS({
|
|
798
798
|
"src/locales/zh-CN.command.yml"(exports2, module2) {
|
|
799
|
-
module2.exports = { commands: { dota2tracker: { description: "dota2tracker的一系列指令,可以使用dota2tracker -h查看所有可用指令。", subscribe: { description: "[订阅本群]", usage: "订阅后还需玩家在本群绑定SteamID,BOT将订阅本群中已绑定玩家的新比赛数据,在STRATZ比赛解析完成后将比赛数据生成为图片战报发布至本群中。", examples: "订阅本群", messages: { subscribed: "本群已订阅,无需重复订阅。", subscribe_success: "订阅成功。" } }, unsubscribe: { description: "[取消订阅] 取消订阅本群。", usage: "取消订阅本群。", examples: "取消订阅", 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: "[取消绑定] 取消绑定你的个人信息。", usage: "取消绑定你的个人信息。", examples: "取消绑定", messages: { unbind_success: "取消绑定成功。", not_binded: "尚未绑定,无需取消绑定。" } }, rename: { description: "[改名] 修改绑定时设定的别名。", usage: '修改绑定时设定的别名。名称中含有空格时需要使用""引号包裹(英文半角引号)。', examples: '改名 李四\n改名 "李 四"', messages: { rename_success: "改名成功,现在你叫{nick_name}了。", empty_input: "请输入你的别名。", not_binded: "请先绑定,绑定时即可设定别名。", nick_name_too_long: "别名过长,请限制在20个字符以内。", nick_name_same: "目标别名与原始别名相同,无需改名。" } }, "query-members": { description: "[查询群友] 查询本群已绑定的玩家。", usage: "查询本群已绑定的玩家,生成简单信息图片发布。", examples: "查询群友", messages: { title: "本群 DOTA2 玩家名册 (共 {count} 人)", table_headers: { nickname: "昵称/别名", winrate: "胜率 (近10场)", last_match: "最近比赛" }, no_members: "本群尚无绑定玩家。", query_failed: "查询群友失败。" } }, "query-match": { description: "[查询比赛] 查询指定比赛ID的比赛数据,生成图片发布。", usage: "查询指定MatchID的比赛数据,生成图片发布。", 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: { 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: { querying_player: "正在获取玩家数据,请稍后……", query_failed: "获取玩家信息失败。", not_in_group: "指令调用失败。\n当前不属于群聊状态,必须提供指定玩家的SteamID。" } }, "query-hero": { description: "[查询英雄] 查询英雄技能/面板信息。", options: { random: "-r 随机选择英雄" }, usage: "查询英雄的技能说明与各项数据,生成图片发布。\n参数可输入英雄ID、英雄名、英雄常用别名。", examples: "查询英雄 15\n查询英雄 雷泽\n查询英雄 电魂\n查询英雄 -r", messages: { not_found: "未找到输入的英雄,请确认后重新输入。", querying_hero: "正在获取英雄数据,请稍后……", query_failed: "获取英雄数据失败。", empty_input: "请输入参数。" } }, "query-item": { description: "[查询物品] 查询物品信息。", usage: "查询物品的描述与各项数据,生成图片发布。\n参数可输入物品名(可模糊查找)、物品别名、物品ID。\n可在配置页中设置每次查询的最大发送数量、以及是否在超过限制或未输入参数时发送物品列表。", 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}" } }, "hero-of-the-day": { description: "[今日英雄] 获取今日英雄推荐。", usage: "获取近期比赛记录、生涯比赛记录,根据胜场、表现分、是否手热等参数计算推荐英雄。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID。", options: { days: "-d <number> 近期数据的获取范围,单位为天数,默认值为30" }, examples: "今日英雄\n今日英雄 -d 60\n今日英雄 1234567890\n今日英雄 张三", messages: { title_recommendation: "今日推荐:", recommendation_intro: "今日为您推荐的英雄是:", recommendation_heroes: "{#each heroes as hero}{hero}{#if hero !== heroes[heroes.length - 1]}、{/if}{/each}", recommendation_type_lifetime_only: "您的近期数据为空,本次推荐结果基于您的生涯数据。", recommendation_type_no_record: "您的近期与生涯数据为空,无法生成推荐信息。", recommendation_type_anonymous: "您的个人数据未公开,无法生成推荐信息。", details: { pool_description: "推荐结果根据对您的近期与生涯英雄使用记录计分后,按总分排序后对前10位英雄以分数为权重随机取得。", table_intro: "以下是前10位英雄具体得分表。", table_headers: { hero: "英雄名称", recent_wins: "近期胜场分", lifetime_wins: "生涯胜场分<br>(对数)", imp_bonus: "imp奖励分", is_hot_streak: "是否手热", total_score: "总分" }, scoring_formula: "当前计分规则:[近期胜场数 x 1] + [log(生涯胜场数+1) x 5] + [近期imp x 0.1]", hot_streak_desc: "若英雄在3天内使用过,则记为手热英雄,总分提升20%。" }, title_meta: "环境趋势:", meta_intro: "一周内,基于您段位±1 ({tiers}) 范围内各位置<b>选择率≥2%</b>按胜率从高到低前三名优势英雄:", meta_table_header: "英雄名称(选择率% 胜率%)", meta_position: "{pos}号位:" } }, common: { messages: { user_not_binded_in_channel: "无参数时默认从已绑定SteamID玩家中寻找你的信息,但你似乎并没有绑定。\n请在本群绑定SteamID。(可输入【绑定 -h】获取帮助)\n或在指令后跟上希望查询的SteamID或已绑定玩家的别名。", user_not_in_group: "指令调用失败。\n当前不属于群聊状态,必须提供指定玩家的SteamID。", invalid_input_include_steam_id: "SteamID无效并且未在本群根据输入信息找到玩家。" } }, help: { description: "[DOTA2指南] 获取插件的全部指令详细信息与在线文档链接。", usage: "获取插件的全部指令详细信息与在线文档链接。", examples: "DOTA2指南\nDOTA2帮助\nDOTA2说明", messages: { header: "以下是插件的全部指令。\n※注意 <arg> 是必须参数,[arg] 是可选参数,具体使用方法请看“用法示例”列。", footer: "插件配置、模板展示等更多信息请访问在线文档:\nhttps://sjtdev.github.io/koishi-plugin-dota2tracker/", table_headers: { command: "指令名", alias: "指令中文", arguments: "参数", description: "说明", options: "选项", examples: "用法示例" } } } } } };
|
|
799
|
+
module2.exports = { commands: { dota2tracker: { description: "dota2tracker的一系列指令,可以使用dota2tracker -h查看所有可用指令。", subscribe: { description: "[订阅本群]", usage: "订阅后还需玩家在本群绑定SteamID,BOT将订阅本群中已绑定玩家的新比赛数据,在STRATZ比赛解析完成后将比赛数据生成为图片战报发布至本群中。", examples: "订阅本群", messages: { subscribed: "本群已订阅,无需重复订阅。", subscribe_success: "订阅成功。" } }, unsubscribe: { description: "[取消订阅] 取消订阅本群。", usage: "取消订阅本群。", examples: "取消订阅", 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: "[取消绑定] 取消绑定你的个人信息。", usage: "取消绑定你的个人信息。", examples: "取消绑定", messages: { unbind_success: "取消绑定成功。", not_binded: "尚未绑定,无需取消绑定。" } }, rename: { description: "[改名] 修改绑定时设定的别名。", usage: '修改绑定时设定的别名。名称中含有空格时需要使用""引号包裹(英文半角引号)。', examples: '改名 李四\n改名 "李 四"', messages: { rename_success: "改名成功,现在你叫{nick_name}了。", empty_input: "请输入你的别名。", not_binded: "请先绑定,绑定时即可设定别名。", nick_name_too_long: "别名过长,请限制在20个字符以内。", nick_name_same: "目标别名与原始别名相同,无需改名。" } }, "query-members": { description: "[查询群友] 查询本群已绑定的玩家。", usage: "查询本群已绑定的玩家,生成简单信息图片发布。", examples: "查询群友", messages: { title: "本群 DOTA2 玩家名册 (共 {count} 人)", table_headers: { nickname: "昵称/别名", winrate: "胜率 (近10场)", last_match: "最近比赛" }, no_members: "本群尚无绑定玩家。", query_failed: "查询群友失败。" } }, "query-match": { description: "[查询比赛] 查询指定比赛ID的比赛数据,生成图片发布。", usage: "查询指定MatchID的比赛数据,生成图片发布。", 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: { 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: { querying_player: "正在获取玩家数据,请稍后……", query_failed: "获取玩家信息失败。", not_in_group: "指令调用失败。\n当前不属于群聊状态,必须提供指定玩家的SteamID。" } }, "query-hero": { description: "[查询英雄] 查询英雄技能/面板信息。", options: { random: "-r 随机选择英雄" }, usage: "查询英雄的技能说明与各项数据,生成图片发布。\n参数可输入英雄ID、英雄名、英雄常用别名。", examples: "查询英雄 15\n查询英雄 雷泽\n查询英雄 电魂\n查询英雄 -r", messages: { not_found: "未找到输入的英雄,请确认后重新输入。", querying_hero: "正在获取英雄数据,请稍后……", query_failed: "获取英雄数据失败。", empty_input: "请输入参数。" } }, "query-item": { description: "[查询物品] 查询物品信息。", usage: "查询物品的描述与各项数据,生成图片发布。\n参数可输入物品名(可模糊查找)、物品别名、物品ID。\n可在配置页中设置每次查询的最大发送数量、以及是否在超过限制或未输入参数时发送物品列表。", 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}" } }, "hero-of-the-day": { description: "[今日英雄] 获取今日英雄推荐。", usage: "获取近期比赛记录、生涯比赛记录,根据胜场、表现分、是否手热等参数计算推荐英雄。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID。", options: { days: "-d <number> 近期数据的获取范围,单位为天数,默认值为30" }, examples: "今日英雄\n今日英雄 -d 60\n今日英雄 1234567890\n今日英雄 张三", messages: { title_recommendation: "今日推荐:", recommendation_intro: "今日为您推荐的英雄是:", recommendation_heroes: "{#each heroes as hero}{hero}{#if hero !== heroes[heroes.length - 1]}、{/if}{/each}", recommendation_type_lifetime_only: "您的近期数据为空,本次推荐结果基于您的生涯数据。", recommendation_type_no_record: "您的近期与生涯数据为空,无法生成推荐信息。", recommendation_type_anonymous: "您的个人数据未公开,无法生成推荐信息。", details: { pool_description: "推荐结果根据对您的近期与生涯英雄使用记录计分后,按总分排序后对前10位英雄以分数为权重随机取得。", table_intro: "以下是前10位英雄具体得分表。", table_headers: { hero: "英雄名称", recent_wins: "近期胜场分", lifetime_wins: "生涯胜场分<br>(对数)", imp_bonus: "imp奖励分", is_hot_streak: "是否手热", total_score: "总分" }, scoring_formula: "当前计分规则:[近期胜场数 x 1] + [log(生涯胜场数+1) x 5] + [近期imp x 0.1]", hot_streak_desc: "若英雄在3天内使用过,则记为手热英雄,总分提升20%。" }, title_meta: "环境趋势:", meta_intro: "一周内,基于您段位±1 ({tiers}) 范围内各位置<b>选择率≥2%</b>按胜率从高到低前三名优势英雄:", meta_table_header: "英雄名称(选择率% 胜率%)", meta_position: "{pos}号位:", querying: "正在查询玩家数据、英雄胜率等数据,请稍候……", query_failed: "指令调用失败。" } }, common: { messages: { user_not_binded_in_channel: "无参数时默认从已绑定SteamID玩家中寻找你的信息,但你似乎并没有绑定。\n请在本群绑定SteamID。(可输入【绑定 -h】获取帮助)\n或在指令后跟上希望查询的SteamID或已绑定玩家的别名。", user_not_in_group: "指令调用失败。\n当前不属于群聊状态,必须提供指定玩家的SteamID。", invalid_input_include_steam_id: "SteamID无效并且未在本群根据输入信息找到玩家。" } }, help: { description: "[DOTA2指南] 获取插件的全部指令详细信息与在线文档链接。", usage: "获取插件的全部指令详细信息与在线文档链接。", examples: "DOTA2指南\nDOTA2帮助\nDOTA2说明", messages: { header: "以下是插件的全部指令。\n※注意 <arg> 是必须参数,[arg] 是可选参数,具体使用方法请看“用法示例”列。", footer: "插件配置、模板展示等更多信息请访问在线文档:\nhttps://sjtdev.github.io/koishi-plugin-dota2tracker/", table_headers: { command: "指令名", alias: "指令中文", arguments: "参数", description: "说明", options: "选项", examples: "用法示例" } } } } } };
|
|
800
800
|
}
|
|
801
801
|
});
|
|
802
802
|
|
|
803
803
|
// src/locales/zh-CN.schema.yml
|
|
804
804
|
var require_zh_CN_schema = __commonJS({
|
|
805
805
|
"src/locales/zh-CN.schema.yml"(exports2, module2) {
|
|
806
|
-
module2.exports = { _config: { base: { $desc: "基础设置", STRATZ_API_TOKEN: "※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取。", dataParsingTimeoutMinutes: "等待比赛数据解析的时间(单位:分钟)。如果数据解析时间超过等待时间,将直接生成战报而不再等待解析完成。", proxyAddress: "代理地址,不使用代理请留空。 \n※无法使用`proxy-agent`插件配置的全局代理地址,欲使用代理必须设置此项。", suppressStratzNetworkErrors: "**请使用下方通用于 stratz 与 opendota 的配置项`suppressApiNetworkErrors`。 \n此配置项仍然生效,当与`suppressApiNetworkErrors`任一启用时将会使 stratz/opendota 日志降级到debug输出。 \n此配置项将于下版本被移除。**", suppressApiNetworkErrors: "开启后将 stratz/opendota 网络错误日志使用debug级别输出。 \n(如超时、网络不通等,但403 Forbidden除外) \nkoishi默认不显示debug级日志,若需要开启debug日志显示,请见 [📖 配置项#suppressapinetworkerrors](http://sjtdev.github.io/koishi-plugin-dota2tracker/configs.html#suppressapinetworkerrors-boolean)", enableOpenDotaFallback: "启用 OpenDota 作为战报追踪与查询比赛功能的备用数据源。", OPENDOTA_API_KEY: "OpenDota 的订阅付费APIKEY, \n可在 https://www.opendota.com/api-keys 查看详情。 \nOpenDota 的免费用户此处请留空。", OpenDotaIPStack: "若访问 OpenDota API 时频繁失败,可能是由于错误的 IPv6 环境导致的。 \n设置此选项可在访问 OpenDota API 时强制使用 IPv4 尝试解决问题。" }, message: { $desc: "消息设置", useHeroNicknames: "是否使用英雄别名。关闭后仅使用英雄正式名称。", 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>估算的段位将以灰色图片显示", templateFonts: '模板所使用的字体名。需要 koishi 所在设备安装字体文件。 \n可添加多个字体名,将从上到下回退到第一个可用字体;若所有字体都不可用,则使用系统默认字体。 \n其中字体名若包含空格或特殊字符需要在名称首尾添加引号(此处建议尽量强制使用引号); \n若使用字体族名则必须**不使用引号**,如:\n```\n"Microsoft YaHei"\nsans-serif\n```\n有关font-family的更多信息,请查阅 [📖 MDN: font-family](https://developer.mozilla.org/zh-CN/docs/Web/CSS/font-family) ' } } };
|
|
806
|
+
module2.exports = { _config: { base: { $desc: "基础设置", STRATZ_API_TOKEN: "※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取。", dataParsingTimeoutMinutes: "等待比赛数据解析的时间(单位:分钟)。如果数据解析时间超过等待时间,将直接生成战报而不再等待解析完成。", proxyAddress: "代理地址,不使用代理请留空。 \n※无法使用`proxy-agent`插件配置的全局代理地址,欲使用代理必须设置此项。", suppressStratzNetworkErrors: "**请使用下方通用于 stratz 与 opendota 的配置项`suppressApiNetworkErrors`。 \n此配置项仍然生效,当与`suppressApiNetworkErrors`任一启用时将会使 stratz/opendota 日志降级到debug输出。 \n此配置项将于下版本被移除。**", suppressApiNetworkErrors: "开启后将 stratz/opendota 网络错误日志使用debug级别输出。 \n(如超时、网络不通等,但403 Forbidden除外) \nkoishi默认不显示debug级日志,若需要开启debug日志显示,请见 [📖 配置项#suppressapinetworkerrors](http://sjtdev.github.io/koishi-plugin-dota2tracker/configs.html#suppressapinetworkerrors-boolean)", enableOpenDotaFallback: "启用 OpenDota 作为战报追踪与查询比赛功能的备用数据源。", OPENDOTA_API_KEY: "OpenDota 的订阅付费APIKEY, \n可在 https://www.opendota.com/api-keys 查看详情。 \nOpenDota 的免费用户此处请留空。", OpenDotaIPStack: "若访问 OpenDota API 时频繁失败,可能是由于错误的 IPv6 环境导致的。 \n设置此选项可在访问 OpenDota API 时强制使用 IPv4 尝试解决问题。" }, message: { $desc: "消息设置", useHeroNicknames: "是否使用英雄别名。关闭后仅使用英雄正式名称。", 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: "别名" }, autoRecallTips: "在指令调用结束后自动撤回提示消息,如:“正在搜索对局详情,请稍后……”" }, 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>估算的段位将以灰色图片显示", templateFonts: '模板所使用的字体名。需要 koishi 所在设备安装字体文件。 \n可添加多个字体名,将从上到下回退到第一个可用字体;若所有字体都不可用,则使用系统默认字体。 \n其中字体名若包含空格或特殊字符需要在名称首尾添加引号(此处建议尽量强制使用引号); \n若使用字体族名则必须**不使用引号**,如:\n```\n"Microsoft YaHei"\nsans-serif\n```\n有关font-family的更多信息,请查阅 [📖 MDN: font-family](https://developer.mozilla.org/zh-CN/docs/Web/CSS/font-family) ' } } };
|
|
807
807
|
}
|
|
808
808
|
});
|
|
809
809
|
|
|
@@ -831,7 +831,7 @@ __export(src_exports, {
|
|
|
831
831
|
usage: () => usage
|
|
832
832
|
});
|
|
833
833
|
module.exports = __toCommonJS(src_exports);
|
|
834
|
-
var
|
|
834
|
+
var import_path4 = __toESM(require("path"));
|
|
835
835
|
|
|
836
836
|
// src/app/common/i18n.ts
|
|
837
837
|
var import_koishi = require("koishi");
|
|
@@ -1503,7 +1503,7 @@ function handleError(error, logger, i18n, config) {
|
|
|
1503
1503
|
`;
|
|
1504
1504
|
}
|
|
1505
1505
|
output += error.stack;
|
|
1506
|
-
const logLevel = config.suppressApiNetworkErrors
|
|
1506
|
+
const logLevel = config.suppressApiNetworkErrors ? "debug" : "error";
|
|
1507
1507
|
logger[logLevel](output);
|
|
1508
1508
|
} else {
|
|
1509
1509
|
let output = "An unexpected error was thrown:\n";
|
|
@@ -2232,7 +2232,6 @@ var CacheService = class extends import_koishi6.Service {
|
|
|
2232
2232
|
}
|
|
2233
2233
|
addOpendotaAPIRequestLog(request, count = 1) {
|
|
2234
2234
|
this.ctx.cache.set("dt_opendota_api_request_log", String(Date.now()), { count, request }, this.msUntilUTCEndOfDay);
|
|
2235
|
-
if (this.config.enableConsole) this.ctx.console.services["apiCount"].refresh();
|
|
2236
2235
|
}
|
|
2237
2236
|
async getTodayOpendotaAPIRequestCount() {
|
|
2238
2237
|
let count = 0;
|
|
@@ -2548,11 +2547,11 @@ var MiniQueue = class {
|
|
|
2548
2547
|
if (this.stopped) {
|
|
2549
2548
|
return Promise.reject(new Error("Queue has been disposed."));
|
|
2550
2549
|
}
|
|
2551
|
-
return new Promise((
|
|
2550
|
+
return new Promise((resolve, reject) => {
|
|
2552
2551
|
this.queue.push(async () => {
|
|
2553
2552
|
try {
|
|
2554
2553
|
const result = await task();
|
|
2555
|
-
|
|
2554
|
+
resolve(result);
|
|
2556
2555
|
} catch (error) {
|
|
2557
2556
|
reject(error);
|
|
2558
2557
|
}
|
|
@@ -2573,7 +2572,7 @@ var MiniQueue = class {
|
|
|
2573
2572
|
const task = this.queue.shift();
|
|
2574
2573
|
if (task) {
|
|
2575
2574
|
await task();
|
|
2576
|
-
await new Promise((
|
|
2575
|
+
await new Promise((resolve) => this.ctx.setTimeout(resolve, this.interval));
|
|
2577
2576
|
}
|
|
2578
2577
|
this.isProcessing = false;
|
|
2579
2578
|
this._process();
|
|
@@ -3454,13 +3453,58 @@ async function resolvePlayerAndHandleErrors(ctx, session, input) {
|
|
|
3454
3453
|
return Number(result.steamId);
|
|
3455
3454
|
}
|
|
3456
3455
|
__name(resolvePlayerAndHandleErrors, "resolvePlayerAndHandleErrors");
|
|
3456
|
+
var TaskMessenger = class {
|
|
3457
|
+
constructor(session, options = { autoRecall: true }) {
|
|
3458
|
+
this.session = session;
|
|
3459
|
+
this.options = options;
|
|
3460
|
+
}
|
|
3461
|
+
static {
|
|
3462
|
+
__name(this, "TaskMessenger");
|
|
3463
|
+
}
|
|
3464
|
+
tipIds = [];
|
|
3465
|
+
/**
|
|
3466
|
+
* 发送一条提示消息,并记录其 ID 以便后续撤回
|
|
3467
|
+
* @param content 提示内容
|
|
3468
|
+
* @returns 返回 this 实例,支持链式调用
|
|
3469
|
+
*/
|
|
3470
|
+
async send(content) {
|
|
3471
|
+
try {
|
|
3472
|
+
const result = await this.session.send(content);
|
|
3473
|
+
const newIds = Array.isArray(result) ? result : [result];
|
|
3474
|
+
this.tipIds.push(...newIds);
|
|
3475
|
+
} catch (e) {
|
|
3476
|
+
}
|
|
3477
|
+
return this;
|
|
3478
|
+
}
|
|
3479
|
+
/**
|
|
3480
|
+
* 任务结束,撤回所有提示消息
|
|
3481
|
+
*/
|
|
3482
|
+
async finish() {
|
|
3483
|
+
if (!this.options.autoRecall) {
|
|
3484
|
+
this.tipIds = [];
|
|
3485
|
+
return;
|
|
3486
|
+
}
|
|
3487
|
+
if (this.tipIds.length === 0) return;
|
|
3488
|
+
const idsToRecall = [...this.tipIds].reverse();
|
|
3489
|
+
this.tipIds = [];
|
|
3490
|
+
for (const id of idsToRecall) {
|
|
3491
|
+
try {
|
|
3492
|
+
await this.session.bot.deleteMessage(this.session.channelId, id);
|
|
3493
|
+
} catch (e) {
|
|
3494
|
+
}
|
|
3495
|
+
}
|
|
3496
|
+
}
|
|
3497
|
+
};
|
|
3457
3498
|
|
|
3458
3499
|
// src/app/commands/hero-of-the-day.command.ts
|
|
3459
3500
|
var import_luxon10 = require("luxon");
|
|
3460
3501
|
function registerHeroOfTheDayCommand(ctx) {
|
|
3461
3502
|
const name2 = "hero-of-the-day";
|
|
3503
|
+
const logger = ctx.logger("command/" + name2);
|
|
3462
3504
|
ctx.command(`dota2tracker.${name2} <input_data>`).alias("今日英雄").option("days", "-d <value:number>").action(async ({ session, options }, input_data) => {
|
|
3505
|
+
const task = new TaskMessenger(session, { autoRecall: ctx.config.autoRecallTips });
|
|
3463
3506
|
try {
|
|
3507
|
+
await task.send(session.text(".querying"));
|
|
3464
3508
|
const steamId = await resolvePlayerAndHandleErrors(ctx, session, input_data);
|
|
3465
3509
|
if (steamId === null) return;
|
|
3466
3510
|
const days = clamp(options.days, 1, 180, 30);
|
|
@@ -3472,10 +3516,13 @@ function registerHeroOfTheDayCommand(ctx) {
|
|
|
3472
3516
|
const metaPromise = ctx.dota2tracker.hero.getWeeklyHeroMeta(PlayerService.estimateWeightedRank(result.player));
|
|
3473
3517
|
const [recommendation, weeklyHeroMeta] = await Promise.all([recommendationPromise, metaPromise]);
|
|
3474
3518
|
const languageTag = await ctx.dota2tracker.i18n.getLanguageTag({ session });
|
|
3519
|
+
await task.finish();
|
|
3475
3520
|
const message = ctx.dota2tracker.messageBuilder.buildHeroOfTheDayMessage(languageTag, recommendation, weeklyHeroMeta);
|
|
3476
3521
|
return message;
|
|
3477
3522
|
} catch (error) {
|
|
3478
|
-
|
|
3523
|
+
await task.finish();
|
|
3524
|
+
handleError(error, logger, ctx.dota2tracker.i18n, ctx.config);
|
|
3525
|
+
return session.text(".query_failed");
|
|
3479
3526
|
}
|
|
3480
3527
|
});
|
|
3481
3528
|
}
|
|
@@ -3483,20 +3530,28 @@ __name(registerHeroOfTheDayCommand, "registerHeroOfTheDayCommand");
|
|
|
3483
3530
|
|
|
3484
3531
|
// src/app/commands/query-hero.command.ts
|
|
3485
3532
|
function registerQueryHeroCommand(ctx) {
|
|
3486
|
-
|
|
3487
|
-
|
|
3533
|
+
const name2 = "query-hero";
|
|
3534
|
+
const logger = ctx.logger("command/" + name2);
|
|
3535
|
+
ctx.command(`dota2tracker.${name2} <input_data>`).option("random", "-r").alias("查询英雄").action(async ({ session, options }, input_data) => {
|
|
3536
|
+
const task = new TaskMessenger(session, { autoRecall: ctx.config.autoRecallTips });
|
|
3488
3537
|
try {
|
|
3489
3538
|
if (input_data || options.random) {
|
|
3490
|
-
await
|
|
3539
|
+
await task.send(session.text(".querying_hero"));
|
|
3491
3540
|
const languageTag = await ctx.dota2tracker.i18n.getLanguageTag({ session });
|
|
3492
3541
|
const heroData = await ctx.dota2tracker.hero.getHeroDetails(input_data, languageTag, options.random);
|
|
3493
|
-
if (!heroData)
|
|
3542
|
+
if (!heroData) {
|
|
3543
|
+
await task.finish();
|
|
3544
|
+
return session.text(".not_found");
|
|
3545
|
+
}
|
|
3494
3546
|
const image = await ctx.dota2tracker.image.renderToImageByFile(heroData, ctx.config.template_hero, "hero" /* Hero */, languageTag);
|
|
3495
3547
|
const message = ctx.dota2tracker.messageBuilder.buildHeroMessage(heroData);
|
|
3548
|
+
await task.finish();
|
|
3496
3549
|
await session.send(message + image);
|
|
3497
3550
|
}
|
|
3498
3551
|
} catch (error) {
|
|
3499
|
-
|
|
3552
|
+
await task.finish();
|
|
3553
|
+
handleError(error, logger, ctx.dota2tracker.i18n, ctx.config);
|
|
3554
|
+
return session.text(".query_failed");
|
|
3500
3555
|
}
|
|
3501
3556
|
});
|
|
3502
3557
|
}
|
|
@@ -3504,46 +3559,56 @@ __name(registerQueryHeroCommand, "registerQueryHeroCommand");
|
|
|
3504
3559
|
|
|
3505
3560
|
// src/app/commands/query-item.command.ts
|
|
3506
3561
|
function registerQueryItemCommand(ctx) {
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
const image = await ctx.dota2tracker.image.renderToImageByFile(allItems, "itemlist", "item" /* Item */, languageTag2);
|
|
3514
|
-
await session.send(image);
|
|
3515
|
-
} else {
|
|
3516
|
-
await session.send(session.text(".empty_input"));
|
|
3517
|
-
}
|
|
3562
|
+
const name2 = "query-item";
|
|
3563
|
+
const logger = ctx.logger("command/" + name2);
|
|
3564
|
+
ctx.command(`dota2tracker.${name2} <input_data>`).alias("查询物品").action(async ({ session }, input_data) => {
|
|
3565
|
+
const task = new TaskMessenger(session, { autoRecall: ctx.config.autoRecallTips });
|
|
3566
|
+
if (!input_data && !ctx.config.showItemListAtTooMuchItems) {
|
|
3567
|
+
await session.send(session.text(".empty_input"));
|
|
3518
3568
|
return;
|
|
3519
3569
|
}
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
}
|
|
3528
|
-
if (matchedItemList.length > ctx.config.maxSendItemCount) {
|
|
3529
|
-
await session.send(session.text(".too_many_items", { count: matchedItemList.length, max: ctx.config.maxSendItemCount }));
|
|
3530
|
-
if (ctx.config.showItemListAtTooMuchItems) {
|
|
3531
|
-
const image = await ctx.dota2tracker.image.renderToImageByFile(matchedItemList, "itemlist", "item" /* Item */, languageTag);
|
|
3570
|
+
try {
|
|
3571
|
+
await task.send(session.text(".querying_item"));
|
|
3572
|
+
const languageTag = await ctx.dota2tracker.i18n.getLanguageTag({ session });
|
|
3573
|
+
const itemList = await ctx.dota2tracker.item.getItemList({ languageTag, onCacheMissTip: /* @__PURE__ */ __name(() => task.send(session.text(".cache_building")), "onCacheMissTip") });
|
|
3574
|
+
if (!input_data) {
|
|
3575
|
+
const image = await ctx.dota2tracker.image.renderToImageByFile(itemList, "itemlist", "item" /* Item */, languageTag);
|
|
3576
|
+
await task.finish();
|
|
3532
3577
|
await session.send(image);
|
|
3578
|
+
return;
|
|
3533
3579
|
}
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
const itemDetails = await ctx.dota2tracker.item.getItemDetails(basicItemInfo.id, languageTag);
|
|
3540
|
-
const finalItemData = { ...itemDetails, ...basicItemInfo };
|
|
3541
|
-
const image = await ctx.dota2tracker.image.renderToImageByFile(finalItemData, "item", "item" /* Item */, languageTag);
|
|
3542
|
-
await session.send(image);
|
|
3543
|
-
} catch (error) {
|
|
3544
|
-
ctx.logger.error(`查询物品[${basicItemInfo.name_loc}]详情失败:`, error);
|
|
3545
|
-
await session.send(session.text(".query_item_failed", { name: basicItemInfo.name_loc }));
|
|
3580
|
+
const matchedItemList = ctx.dota2tracker.item.searchItems(itemList, input_data, languageTag, ctx.config);
|
|
3581
|
+
if (matchedItemList.length === 0) {
|
|
3582
|
+
await task.finish();
|
|
3583
|
+
await session.send(session.text(".not_found"));
|
|
3584
|
+
return;
|
|
3546
3585
|
}
|
|
3586
|
+
if (matchedItemList.length > ctx.config.maxSendItemCount) {
|
|
3587
|
+
await task.finish();
|
|
3588
|
+
await session.send(session.text(".too_many_items", { count: matchedItemList.length, max: ctx.config.maxSendItemCount }));
|
|
3589
|
+
if (ctx.config.showItemListAtTooMuchItems) {
|
|
3590
|
+
const image = await ctx.dota2tracker.image.renderToImageByFile(matchedItemList, "itemlist", "item" /* Item */, languageTag);
|
|
3591
|
+
await session.send(image);
|
|
3592
|
+
}
|
|
3593
|
+
return;
|
|
3594
|
+
}
|
|
3595
|
+
await task.finish();
|
|
3596
|
+
await session.send(session.text(".finded_items", { items: matchedItemList }));
|
|
3597
|
+
for (const basicItemInfo of matchedItemList) {
|
|
3598
|
+
try {
|
|
3599
|
+
const itemDetails = await ctx.dota2tracker.item.getItemDetails(basicItemInfo.id, languageTag);
|
|
3600
|
+
const finalItemData = { ...itemDetails, ...basicItemInfo };
|
|
3601
|
+
const image = await ctx.dota2tracker.image.renderToImageByFile(finalItemData, "item", "item" /* Item */, languageTag);
|
|
3602
|
+
await session.send(image);
|
|
3603
|
+
} catch (error) {
|
|
3604
|
+
ctx.logger.error(`查询物品[${basicItemInfo.name_loc}]详情失败:`, error);
|
|
3605
|
+
await session.send(session.text(".query_item_failed", { name: basicItemInfo.name_loc }));
|
|
3606
|
+
}
|
|
3607
|
+
}
|
|
3608
|
+
} catch (error) {
|
|
3609
|
+
await task.finish();
|
|
3610
|
+
handleError(error, logger, ctx.dota2tracker.i18n, ctx.config);
|
|
3611
|
+
return session.text(".query_list_failed");
|
|
3547
3612
|
}
|
|
3548
3613
|
});
|
|
3549
3614
|
}
|
|
@@ -3553,32 +3618,45 @@ __name(registerQueryItemCommand, "registerQueryItemCommand");
|
|
|
3553
3618
|
function registerQueryMatchCommand(ctx) {
|
|
3554
3619
|
ctx.command("dota2tracker.query-match <match_id>").alias("查询比赛").option("parse", "-p").option("template", "-t <value:string>").action(async ({ session, options }, match_id) => {
|
|
3555
3620
|
const name2 = "query-match";
|
|
3621
|
+
const logger = ctx.logger("command/" + name2);
|
|
3622
|
+
const task = new TaskMessenger(session, { autoRecall: ctx.config.autoRecallTips });
|
|
3556
3623
|
try {
|
|
3557
3624
|
if (!match_id) return session.text(".empty_input");
|
|
3558
3625
|
if (!/^\d{1,11}$/.test(match_id)) return session.text(".match_id_invalid");
|
|
3559
|
-
await
|
|
3560
|
-
|
|
3626
|
+
await task.send(session.text(".querying_match"));
|
|
3627
|
+
const message = await handleQueryMatchCommand(ctx, ctx.config, session, options, match_id);
|
|
3628
|
+
await task.finish();
|
|
3629
|
+
return message;
|
|
3561
3630
|
} catch (error) {
|
|
3562
|
-
|
|
3631
|
+
await task.finish();
|
|
3632
|
+
handleError(error, logger, ctx.dota2tracker.i18n, ctx.config);
|
|
3633
|
+
return session.text(".query_failed");
|
|
3563
3634
|
}
|
|
3564
3635
|
});
|
|
3565
3636
|
ctx.command("dota2tracker.query-recent-match [input_data]").alias("查询最近比赛").option("parse", "-p").option("template", "-t <value:string>").action(async ({ session, options }, input_data) => {
|
|
3566
3637
|
const name2 = "query-recent-match";
|
|
3638
|
+
const logger = ctx.logger("command/" + name2);
|
|
3639
|
+
const task = new TaskMessenger(session, { autoRecall: ctx.config.autoRecallTips });
|
|
3567
3640
|
try {
|
|
3568
3641
|
const steamId = await resolvePlayerAndHandleErrors(ctx, session, input_data);
|
|
3569
3642
|
if (steamId === null) return;
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
handleError(error, ctx.logger(name2), ctx.dota2tracker.i18n, ctx.config);
|
|
3643
|
+
await task.send(session.text(".querying_match"));
|
|
3644
|
+
const lastMatch = await ctx.dota2tracker.player.getLastMatchId(Number(steamId));
|
|
3645
|
+
if (!lastMatch?.id) {
|
|
3646
|
+
await task.finish();
|
|
3647
|
+
return session.text(".query_failed");
|
|
3576
3648
|
}
|
|
3577
|
-
if (
|
|
3578
|
-
|
|
3579
|
-
|
|
3649
|
+
if (lastMatch.isAnonymous) {
|
|
3650
|
+
await task.finish();
|
|
3651
|
+
return session.text(".is_anonymous");
|
|
3652
|
+
}
|
|
3653
|
+
const message = await handleQueryMatchCommand(ctx, ctx.config, session, options, lastMatch.id);
|
|
3654
|
+
await task.finish();
|
|
3655
|
+
return message;
|
|
3580
3656
|
} catch (error) {
|
|
3581
|
-
|
|
3657
|
+
await task.finish();
|
|
3658
|
+
handleError(error, logger, ctx.dota2tracker.i18n, ctx.config);
|
|
3659
|
+
return session.text(".query_failed");
|
|
3582
3660
|
}
|
|
3583
3661
|
});
|
|
3584
3662
|
}
|
|
@@ -3615,24 +3693,29 @@ __name(registerQueryMembersCommand, "registerQueryMembersCommand");
|
|
|
3615
3693
|
|
|
3616
3694
|
// src/app/commands/query-player.command.ts
|
|
3617
3695
|
function registerQueryPlayerCommand(ctx) {
|
|
3696
|
+
const name2 = "query-player";
|
|
3697
|
+
const logger = ctx.logger("command/" + name2);
|
|
3618
3698
|
ctx.command("dota2tracker.query-player <input_data>").option("hero", "-o <value:string>").alias("查询玩家").action(async ({ session, options }, input_data) => {
|
|
3619
|
-
const
|
|
3699
|
+
const task = new TaskMessenger(session, { autoRecall: ctx.config.autoRecallTips });
|
|
3620
3700
|
try {
|
|
3621
3701
|
if (session.guild || !session.guild && input_data) {
|
|
3622
3702
|
const steamId = await resolvePlayerAndHandleErrors(ctx, session, input_data);
|
|
3623
3703
|
if (steamId === null) return;
|
|
3624
|
-
|
|
3704
|
+
await task.send(session.text(".querying_player"));
|
|
3625
3705
|
const heroId = ctx.dota2tracker.i18n.findHeroIdInLocale(options.hero);
|
|
3626
3706
|
const languageTag = await ctx.dota2tracker.i18n.getLanguageTag({ session });
|
|
3627
3707
|
const formattedPlayerData = await ctx.dota2tracker.player.getFormattedPlayerData(steamId, heroId, languageTag);
|
|
3628
3708
|
const image = await ctx.dota2tracker.image.renderToImageByFile(formattedPlayerData, ctx.config.template_player, "player" /* Player */, languageTag);
|
|
3629
3709
|
const message = ctx.dota2tracker.messageBuilder.buildPlayerMessage(steamId);
|
|
3710
|
+
await task.finish();
|
|
3630
3711
|
return message + image;
|
|
3631
3712
|
} else {
|
|
3632
3713
|
return session.text("commands.dota2tracker.common.messages.user_not_in_group");
|
|
3633
3714
|
}
|
|
3634
3715
|
} catch (error) {
|
|
3635
|
-
|
|
3716
|
+
await task.finish();
|
|
3717
|
+
handleError(error, logger, ctx.dota2tracker.i18n, ctx.config);
|
|
3718
|
+
return session.text(".query_failed");
|
|
3636
3719
|
}
|
|
3637
3720
|
});
|
|
3638
3721
|
}
|
|
@@ -3907,6 +3990,13 @@ var OpenDotaAdapter = class extends import_koishi16.Service {
|
|
|
3907
3990
|
radiantExperienceLeads: [0, ..._match.radiant_xp_adv],
|
|
3908
3991
|
// opendota两组数据都需要补充-1分钟时的数据对齐stratz格式。
|
|
3909
3992
|
winRates: null,
|
|
3993
|
+
towerStatusRadiant: _match.tower_status_radiant,
|
|
3994
|
+
towerStatusDire: _match.tower_status_dire,
|
|
3995
|
+
barracksStatusRadiant: _match.barracks_status_radiant,
|
|
3996
|
+
barracksStatusDire: _match.barracks_status_dire,
|
|
3997
|
+
playbackData: {
|
|
3998
|
+
buildingEvents: convertBuildingEvents(_match.objectives)
|
|
3999
|
+
},
|
|
3910
4000
|
players,
|
|
3911
4001
|
pickBans: _match.picks_bans?.map((pb) => ({ isPick: pb.is_pick, ...pb.is_pick ? { heroId: pb.hero_id, bannedHeroId: null } : { bannedHeroId: pb.hero_id, heroId: null }, order: pb.order })),
|
|
3912
4002
|
odParsed: true
|
|
@@ -4160,46 +4250,65 @@ function determineIMP(player) {
|
|
|
4160
4250
|
return Math.round(totalScore / values.length * 100 - 50);
|
|
4161
4251
|
}
|
|
4162
4252
|
__name(determineIMP, "determineIMP");
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4253
|
+
function convertBuildingEvents(objectives) {
|
|
4254
|
+
if (!objectives) return [];
|
|
4255
|
+
const KEY_TO_ID = {
|
|
4256
|
+
// ================= 天辉 Radiant =================
|
|
4257
|
+
npc_dota_goodguys_tower1_top: 16,
|
|
4258
|
+
npc_dota_goodguys_tower2_top: 19,
|
|
4259
|
+
npc_dota_goodguys_tower3_top: 22,
|
|
4260
|
+
npc_dota_goodguys_tower1_mid: 17,
|
|
4261
|
+
npc_dota_goodguys_tower2_mid: 20,
|
|
4262
|
+
npc_dota_goodguys_tower3_mid: 23,
|
|
4263
|
+
npc_dota_goodguys_tower1_bot: 18,
|
|
4264
|
+
npc_dota_goodguys_tower2_bot: 21,
|
|
4265
|
+
npc_dota_goodguys_tower3_bot: 24,
|
|
4266
|
+
npc_dota_goodguys_tower4: 25,
|
|
4267
|
+
// 统一映射 T4
|
|
4268
|
+
npc_dota_goodguys_melee_rax_top: 38,
|
|
4269
|
+
npc_dota_goodguys_range_rax_top: 41,
|
|
4270
|
+
npc_dota_goodguys_melee_rax_mid: 39,
|
|
4271
|
+
npc_dota_goodguys_range_rax_mid: 42,
|
|
4272
|
+
npc_dota_goodguys_melee_rax_bot: 40,
|
|
4273
|
+
npc_dota_goodguys_range_rax_bot: 43,
|
|
4274
|
+
npc_dota_goodguys_fort: 50,
|
|
4275
|
+
// ================= 夜魇 Dire =================
|
|
4276
|
+
npc_dota_badguys_tower1_top: 26,
|
|
4277
|
+
npc_dota_badguys_tower2_top: 29,
|
|
4278
|
+
npc_dota_badguys_tower3_top: 32,
|
|
4279
|
+
npc_dota_badguys_tower1_mid: 27,
|
|
4280
|
+
npc_dota_badguys_tower2_mid: 30,
|
|
4281
|
+
npc_dota_badguys_tower3_mid: 33,
|
|
4282
|
+
npc_dota_badguys_tower1_bot: 28,
|
|
4283
|
+
npc_dota_badguys_tower2_bot: 31,
|
|
4284
|
+
npc_dota_badguys_tower3_bot: 34,
|
|
4285
|
+
npc_dota_badguys_tower4: 35,
|
|
4286
|
+
// 统一映射 T4
|
|
4287
|
+
npc_dota_badguys_melee_rax_top: 44,
|
|
4288
|
+
npc_dota_badguys_range_rax_top: 47,
|
|
4289
|
+
npc_dota_badguys_melee_rax_mid: 45,
|
|
4290
|
+
npc_dota_badguys_range_rax_mid: 48,
|
|
4291
|
+
npc_dota_badguys_melee_rax_bot: 46,
|
|
4292
|
+
npc_dota_badguys_range_rax_bot: 49,
|
|
4293
|
+
npc_dota_badguys_fort: 51
|
|
4294
|
+
};
|
|
4295
|
+
const events = [];
|
|
4296
|
+
for (const obj of objectives) {
|
|
4297
|
+
if (obj.type === "building_kill" && obj.key && KEY_TO_ID[obj.key]) {
|
|
4298
|
+
events.push({
|
|
4299
|
+
time: obj.time,
|
|
4300
|
+
npcId: KEY_TO_ID[obj.key]
|
|
4301
|
+
});
|
|
4302
|
+
}
|
|
4181
4303
|
}
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
// src/console.ts
|
|
4185
|
-
function registerConsolePage(ctx) {
|
|
4186
|
-
const tracker = ctx.dota2tracker;
|
|
4187
|
-
if (!tracker) {
|
|
4188
|
-
ctx.logger("dota2tracker").warn("dota2tracker service is missing during console registration!");
|
|
4189
|
-
return;
|
|
4190
|
-
}
|
|
4191
|
-
new CustomProvider(ctx, tracker);
|
|
4192
|
-
ctx.console.addEntry({
|
|
4193
|
-
dev: (0, import_path3.resolve)(__dirname, "../client/index.ts"),
|
|
4194
|
-
prod: (0, import_path3.resolve)(__dirname, "../dist")
|
|
4195
|
-
});
|
|
4304
|
+
return events;
|
|
4196
4305
|
}
|
|
4197
|
-
__name(
|
|
4306
|
+
__name(convertBuildingEvents, "convertBuildingEvents");
|
|
4198
4307
|
|
|
4199
4308
|
// src/config.ts
|
|
4200
4309
|
var import_koishi17 = require("koishi");
|
|
4201
4310
|
var import_fs3 = __toESM(require("fs"));
|
|
4202
|
-
var
|
|
4311
|
+
var import_path3 = __toESM(require("path"));
|
|
4203
4312
|
|
|
4204
4313
|
// require("./locales/**/*.schema.yml") in src/config.ts
|
|
4205
4314
|
var globRequire_locales_schema_yml = __glob({
|
|
@@ -4208,7 +4317,7 @@ var globRequire_locales_schema_yml = __glob({
|
|
|
4208
4317
|
});
|
|
4209
4318
|
|
|
4210
4319
|
// src/config.ts
|
|
4211
|
-
var templateDir =
|
|
4320
|
+
var templateDir = import_path3.default.join(__dirname, "templates");
|
|
4212
4321
|
var allI18nConfigs = Object.fromEntries(Object.keys(LanguageTags).map((lang) => [lang, globRequire_locales_schema_yml(`./locales/${lang}.schema.yml`)._config]));
|
|
4213
4322
|
var Config = import_koishi17.Schema.intersect([
|
|
4214
4323
|
import_koishi17.Schema.intersect([
|
|
@@ -4216,10 +4325,8 @@ var Config = import_koishi17.Schema.intersect([
|
|
|
4216
4325
|
STRATZ_API_TOKEN: import_koishi17.Schema.string().required().role("secret"),
|
|
4217
4326
|
dataParsingTimeoutMinutes: import_koishi17.Schema.number().default(60).min(0).max(1440),
|
|
4218
4327
|
proxyAddress: import_koishi17.Schema.string(),
|
|
4219
|
-
suppressStratzNetworkErrors: import_koishi17.Schema.boolean().default(false).deprecated(),
|
|
4220
4328
|
suppressApiNetworkErrors: import_koishi17.Schema.boolean().default(false),
|
|
4221
|
-
enableOpenDotaFallback: import_koishi17.Schema.boolean().default(false)
|
|
4222
|
-
enableConsole: import_koishi17.Schema.boolean().default(false).experimental()
|
|
4329
|
+
enableOpenDotaFallback: import_koishi17.Schema.boolean().default(false)
|
|
4223
4330
|
}).i18n(getI18n("base")),
|
|
4224
4331
|
import_koishi17.Schema.union([
|
|
4225
4332
|
import_koishi17.Schema.object({
|
|
@@ -4242,6 +4349,7 @@ var Config = import_koishi17.Schema.intersect([
|
|
|
4242
4349
|
alias: import_koishi17.Schema.string().required()
|
|
4243
4350
|
})
|
|
4244
4351
|
).default([]).role("table"),
|
|
4352
|
+
autoRecallTips: import_koishi17.Schema.boolean().default(true),
|
|
4245
4353
|
rankBroadSwitch: import_koishi17.Schema.boolean().default(false)
|
|
4246
4354
|
}).i18n(getI18n("message")),
|
|
4247
4355
|
import_koishi17.Schema.union([
|
|
@@ -4279,9 +4387,9 @@ var Config = import_koishi17.Schema.intersect([
|
|
|
4279
4387
|
]).i18n(getI18n("report"))
|
|
4280
4388
|
]),
|
|
4281
4389
|
import_koishi17.Schema.object({
|
|
4282
|
-
template_match: import_koishi17.Schema.union([...readDirectoryFilesSync(
|
|
4283
|
-
template_player: import_koishi17.Schema.union([...readDirectoryFilesSync(
|
|
4284
|
-
template_hero: import_koishi17.Schema.union([...readDirectoryFilesSync(
|
|
4390
|
+
template_match: import_koishi17.Schema.union([...readDirectoryFilesSync(import_path3.default.join(templateDir, "match"))]).default("match_1"),
|
|
4391
|
+
template_player: import_koishi17.Schema.union([...readDirectoryFilesSync(import_path3.default.join(templateDir, "player"))]).default("player_1"),
|
|
4392
|
+
template_hero: import_koishi17.Schema.union([...readDirectoryFilesSync(import_path3.default.join(templateDir, "hero"))]).default("hero_1"),
|
|
4285
4393
|
playerRankEstimate: import_koishi17.Schema.boolean().default(true),
|
|
4286
4394
|
templateFonts: import_koishi17.Schema.array(String).default([]).role("table")
|
|
4287
4395
|
}).i18n(getI18n("template"))
|
|
@@ -4299,7 +4407,7 @@ __name(getI18n, "getI18n");
|
|
|
4299
4407
|
function readDirectoryFilesSync(directoryPath) {
|
|
4300
4408
|
try {
|
|
4301
4409
|
const files = import_fs3.default.readdirSync(directoryPath);
|
|
4302
|
-
const fileNames = files.filter((file) =>
|
|
4410
|
+
const fileNames = files.filter((file) => import_path3.default.extname(file).toLowerCase() === ".ejs").map((file) => import_path3.default.basename(file, ".ejs"));
|
|
4303
4411
|
return fileNames;
|
|
4304
4412
|
} catch (error) {
|
|
4305
4413
|
console.error("Error reading directory:", error);
|
|
@@ -4319,8 +4427,8 @@ async function apply(ctx, config) {
|
|
|
4319
4427
|
const lib = await import("dotaconstants");
|
|
4320
4428
|
const dotaconstants = lib.default || lib;
|
|
4321
4429
|
const logger = ctx.logger("dota2tracker");
|
|
4322
|
-
const currentDir =
|
|
4323
|
-
const pluginVersion = require(
|
|
4430
|
+
const currentDir = import_path4.default.resolve(__dirname);
|
|
4431
|
+
const pluginVersion = require(import_path4.default.join(currentDir, "..", "package.json")).version;
|
|
4324
4432
|
ctx.dota2tracker = {};
|
|
4325
4433
|
ctx.dota2tracker.dotaconstants = dotaconstants;
|
|
4326
4434
|
ctx.dota2tracker.i18n = new I18NService(ctx);
|
|
@@ -4360,7 +4468,6 @@ async function apply(ctx, config) {
|
|
|
4360
4468
|
registerQueryHeroCommand(ctx);
|
|
4361
4469
|
registerQueryItemCommand(ctx);
|
|
4362
4470
|
registerHeroOfTheDayCommand(ctx);
|
|
4363
|
-
if (ctx.console && config.enableConsole) registerConsolePage(ctx);
|
|
4364
4471
|
}
|
|
4365
4472
|
__name(apply, "apply");
|
|
4366
4473
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
html,body{background-color:#000;color:#fff;width:800px}.wrapper>*:not(.skills){margin:5px;box-shadow:0 0 5px #fff;display:flex}img{width:100%;vertical-align:middle}p{margin:0}.hero{position:relative}.hero img{width:25%}.hero .pri_attr{position:absolute;width:48px;left:25%}.hero .info{display:flex;width:75%;flex-direction:column;justify-content:space-around;align-items:center;padding:4px}.hero .info .name{font-size:24px}.hero .info .roles .role{font-size:14px}.hero .info .roles .role:not(:last-child){margin-right:12px}.hero .info .roles .role:after{margin-left:3px;font-size:22px}.hero .info .roles .role.level1:after{content:"\25a0\25a1\25a1"}.hero .info .roles .role.level2:after{content:"\25a0\25a0\25a1"}.hero .info .roles .role.level3:after{content:"\25a0\25a0\25a0"}.hero .info .attrs{height:16px;font-size:16px;line-height:1}.hero .info .attrs>span{margin:0 8px;vertical-align:middle}.hero .info .attrs>span:before{display:inline-block;content:"";background-size:100%;width:16px;height:16px;vertical-align:top}.hero .info .attrs>span.str:before{background-image:url("<%= getImageUrl('hero_strength', ImageType.Icons) %>")}.hero .info .attrs>span.agi:before{background-image:url("<%= getImageUrl('hero_agility', ImageType.Icons) %>")}.hero .info .attrs>span.int:before{background-image:url("<%= getImageUrl('hero_intelligence', ImageType.Icons) %>")}.details{flex-direction:row}.details>*{width:50%}.wrapper .hype{display:block;padding:8px;line-height:1.25}.wrapper .hype .npe{color:#a5e0f3;font-weight:700;line-height:1.25;margin-bottom:8px}.talents{display:grid;grid-template-rows:repeat(4,35px);gap:10px;border:#444 10px solid;box-sizing:border-box;position:relative}.talents:before{content:"";position:absolute;inset:0;background:#444;pointer-events:none;box-sizing:border-box;width:395px;transform:translate(-10px,-10px)}.talents .talent{width:375px;text-align:center;display:flex;align-items:center;background:#000;position:relative}.talents .talent .left,.talents .talent .right{width:170px;font-size:12px}.talents .talent .level{flex:0 0 auto;width:35px;height:35px;font-size:18px;line-height:35px;text-align:center;box-sizing:border-box;border-radius:100%;color:#e7d292;text-shadow:0px 0px 8px #ff531c;background-color:#444}.details .list table td{width:50%;text-align:center}.details .list table tr:nth-child(2n){background-color:#333}.details .list{display:flex;flex-direction:column;padding:6px}.details .list>*{flex-grow:1}.details .bars{height:64px;flex-grow:0}.details .bars>div{height:28px;margin-bottom:4px;border-radius:5px;box-shadow:inset 0 0 2px #00000080,0 0 2px #0000004d;position:relative;display:flex;align-items:center}.details .bars .health{background:linear-gradient(to top,#279027,#27a329 56%,#96e891 83%,#366a35)}.details .bars .mana{background:linear-gradient(to top,#4676c4,#2b76d5 56%,#95cdff)}.details .bars .mana.zero{background:none}.details .bars span{text-shadow:#000 1px 1px 4px}.details .bars .number{font-size:18px;position:absolute;left:50%;transform:translate(-50%)}.details .bars .suffix{margin-left:auto;font-size:14px;padding-right:10px}.details .stats{display:flex;justify-content:space-around;line-height:1.3}.details .stats>.column>p{padding:4px;color:#b2b2b2}.details .stats .stat img{width:20px}.facets{display:flex;flex-wrap:wrap;gap:10px}.facets>.facet,.skill>.facet{flex:1 1 calc(50% - 10px);box-sizing:border-box;background-color:#181f24;position:relative;border:1px solid #2b2f33}.facets>.facet:nth-child(odd):last-child{flex-basis:100%}.facets>.facet>.name_back,.skill>.facet>.name_back{position:absolute;height:50px;width:100%}.facet>.name_back.type_0{background:linear-gradient(to right,#9f3c3c,#4a2026)}.facet>.name_line.type_0{filter:invert(22%) sepia(100%) saturate(100%) hue-rotate(316deg) brightness(98%) contrast(100%)}.facet>.name_back.type_1{background:linear-gradient(to right,#c8a45c,#6f3d21)}.facet>.name_line.type_1{filter:invert(54%) sepia(99%) saturate(100%) hue-rotate(0deg) brightness(97%) contrast(100%)}.facet>.name_back.type_2{background:linear-gradient(to right,#a2b23e,#2d5a18)}.facet>.name_line.type_2{filter:invert(57%) sepia(100%) saturate(100%) hue-rotate(32deg) brightness(93%) contrast(100%)}.facet>.name_back.type_3{background:linear-gradient(to right,#547ea6,#2a385e)}.facet>.name_line.type_3{filter:invert(39%) sepia(100%) saturate(99%) hue-rotate(167deg) brightness(99%) contrast(100%)}.facet>.name_back.type_4{background:linear-gradient(to right,#675cae,#261c44)}.facet>.name_line.type_4{filter:invert(33%) sepia(100%) saturate(100%) hue-rotate(207deg) brightness(99%) contrast(100%)}.facet>.name_back.type_5{background:linear-gradient(to right,#adb6be,#4e5557)}.facet>.name_line.type_5{filter:invert(73%) sepia(23%) saturate(99%) hue-rotate(166deg) brightness(93%) contrast(94%)}.facet>.name_line{position:absolute;background-size:cover;height:50px;width:100%;background-image:url(https://cdn.akamai.steamstatic.com/apps/dota2/images/dota_react/icons/facets/ripple_texture.png)}.facet>.name{height:50px;line-height:50px;z-index:1;position:relative;display:flex}.facet>.name>img{width:24px;padding:13px;background-color:#0003}.facet>.name>span{margin-left:16px;letter-spacing:2px;text-shadow:2px 2px 3px rgba(0,0,0,.3),4px 4px 6px rgba(0,0,0,.2),6px 6px 9px rgba(0,0,0,.1)}.facet>.content{padding:12px;display:flex;flex-direction:column;gap:12px}.facet>.content>.ability{display:flex;flex-direction:column;gap:12px}.facet>.content>.ability>.name{background:linear-gradient(to right,#9bcdff17,#9bcdff09 30%,#d0e8ff00);line-height:1}.facet>.content>.ability>.name>img{width:30px}.facet>.content>.ability>.name>span{margin-left:10px;font-size:14px}.facet>.content .description{color:#9ab0cd}.facet>.content>.ability>.attributes{font-size:12px;display:flex;flex-direction:column;gap:5px}.facet>.content>.ability>.attributes .item{color:#737373}.facet>.content .value{color:#fff}.skills{width:800px;display:flex;flex-wrap:wrap}.skill{background-color:#141b1f;margin:5px;box-shadow:0 0 5px #fff;width:390px}.skill>*:not(:nth-child(2)){padding-left:8px}.skill>.title{position:relative;background-color:#1f272b;padding:8px;font-weight:100;height:auto;width:auto}.skill>.title>.name{font-family:KaiTi,\6977\4f53,\6977\4f53_GB2312,STKaiti,serif}.skill>.title>.is_innate{font-size:14px;line-height:18px;width:auto;display:inline;padding:2px 8px;box-sizing:content-box;background-color:#5b93d1}.skill>.title.name_back>img{width:16px}.skill img.scepter,.skill img.shard{position:absolute;width:24px;right:8px;top:50%;transform:translateY(-50%)}.skill .img_stats{display:flex;color:#546780;margin-bottom:16px;border-top:#2a363c 1px solid;border-bottom:#2a363c 1px solid}.skill .img_stats img{width:128px}.skill .img_stats .stats{padding:8px}.skill .stats .dmg_type.Physical span{color:#ae2f28}.skill .stats .dmg_type.Magical span{color:#5b93d1}.skill .stats .dmg_type.Pure span{color:#c29c4a}.skill .stats .dispellable.No span{color:red}.skill .stats .dispellable.Strong span{color:#9828ae}.skill .stats .bkbpierce.Yes span{color:#6add71}.skill>.description{color:#9bb1ce;margin-bottom:32px}.skill>.facet{padding-left:0;margin-bottom:16px}.skill .value{color:#fff}.skill .aghanim_description{padding-left:0;color:#9bb1ce;margin-bottom:16px;border:#263945 solid 3px;box-sizing:border-box}.skill .aghanim_description .title{display:block;font-size:20px;background-color:#263945;padding:12px}.skill .aghanim_description .desc{margin:12px;display:block}.skill .aghanim_description img{position:unset;transform:none;margin-right:8px}.skill .notes{padding:12px;margin-bottom:12px;color:#9fb7c6;background-color:#263945}.skill .attributes{line-height:1.2em;margin-bottom:12px}.skill .attributes .heading{color:#546780}.skill .attributes .values{color:#4b525d}.skill .attributes .values img{width:16px}.skill .attributes .facet{display:inline-flex;font-size:1em;align-items:center;line-height:1.2em;position:unset;color:#fff}.skill .attributes .facet span{height:auto;width:auto;position:unset;padding:0 2px}.skill .attributes .facet img{width:auto;height:1em;padding-right:.2em}.skill .attributes .alternative .plus{display:none}.skill .attributes .primary~.alternative .plus{display:inline}.skill .attributes .primary~.alternative:before{content:"("}.skill .attributes .primary~.alternative:after{content:")"}.skill .cooldown{padding-right:12px}.skill .cooldown:before,.skill .mana_cost:before{content:"";background-size:100%;width:21px;height:21px;display:inline-block;vertical-align:middle}.skill .cooldown:before{background-image:url(data:image/webp;base64,UklGRnABAABXRUJQVlA4TGMBAAAvE8AEEE2QTdqmkI5pRP/DS2wBEIT/bw8R/U8Ddq1NipSvGnd3eXJ3d3kmEM+GTDwBciCBTQCd7qpCeokBQdu2cc6f8tcQEBT5P9oEIGiwYuMBECqAbCUVIIAa19Py1I/AQMrJVGEABACe+DRqcl2GUxeOwIAzQkAAMCBxyi3BRcbSkzAKyIDTciQOAAgwyx43JA4CWRkeQXAAQKkGEs5+/siARwFHAHCUiAGwPwAEAGQSDgCAoCQUQc7OkwMbhgAAJBIKEAtkE9enBgcABEUxAIwyZ6cOx/lTkPiHsX+mqCQTMQRwcmAszPLUoTiCkVAAbDKEAWWUjWlGMYyEAR4n4wMeiBk8W9M1lphIQmAsmWxBJ1vfAJZIBMAoJwNQ0JTN04/yRaCCftofwWBkAMAjQ6BILaWMsEkFFVTTk/qEETyQlYFXnh9jmABKbkgzNQgemYwnTOKFEgAAOGJAeUbyhQIAAA==)}.skill .mana_cost:before{background-image:url(data:image/webp;base64,UklGRsYAAABXRUJQVlA4TLkAAAAvE8AEEIfBOIDbtEmdpEDhS8G2kSTF0eteuLOebJz/0KDREgwBAGEu/89yqe5LCyEaDT03NBcLpEXnJgkZKS2dmlqAlNSCgJXURBoNCHAY2bbSvEP0fxzi7sGh//rslRDR/xQxS0bXRkRMmr5Ho8iISY5523Ztr2vabBuaZZLVE99wRqWAUgGFAv4K+Cngo4CXAp4KeCjgroCbAi4KVv7pOnFwF8aP9+fRXeAaMZ63GbXWiIhxGJ0bEQA=)}.skill .lore{font-size:13px;color:#3e4f5b;padding:8px;line-height:1.25}body .wrapper>.lore{display:block;line-height:1.25;padding:8px;font-family:KaiTi,\6977\4f53,\6977\4f53_GB2312,STKaiti,serif;color:#aaa}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!DOCTYPE html><html lang="<%= languageTag %>"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Document</title><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css"/><style>body,html{background-color:#000;color:#fff;width:800px}.wrapper>:not(.skills){margin:5px;box-shadow:0 0 5px #fff;display:flex}img{width:100%;vertical-align:middle}p{margin:0}.hero{position:relative}.hero img{width:25%}.hero .pri_attr{position:absolute;width:48px;left:25%}.hero .info{display:flex;width:75%;flex-direction:column;justify-content:space-around;align-items:center;padding:4px}.hero .info .name{font-size:24px}.hero .info .roles .role{font-size:14px}.hero .info .roles .role:not(:last-child){margin-right:12px}.hero .info .roles .role::after{margin-left:3px;font-size:22px}.hero .info .roles .role.level1::after{content:"■□□"}.hero .info .roles .role.level2::after{content:"■■□"}.hero .info .roles .role.level3::after{content:"■■■"}.hero .info .attrs{height:16px;font-size:16px;line-height:1}.hero .info .attrs>span{margin:0 8px;vertical-align:middle}.hero .info .attrs>span::before{display:inline-block;content:"";background-size:100%;width:16px;height:16px;vertical-align:top}.hero .info .attrs>span.str::before{background-image:url("<%= getImageUrl('hero_strength', ImageType.Icons) %>")}.hero .info .attrs>span.agi::before{background-image:url("<%= getImageUrl('hero_agility', ImageType.Icons) %>")}.hero .info .attrs>span.int::before{background-image:url("<%= getImageUrl('hero_intelligence', ImageType.Icons) %>")}.details{flex-direction:row}.details>*{width:50%}.wrapper .hype{display:block;padding:8px;line-height:1.25}.wrapper .hype .npe{color:#a5e0f3;font-weight:700;line-height:1.25;margin-bottom:8px}.talents{display:grid;grid-template-rows:repeat(4,35px);gap:10px;border:#444 10px solid;box-sizing:border-box;position:relative}.talents::before{content:"";position:absolute;top:0;left:0;right:0;bottom:0;background:#444;pointer-events:none;box-sizing:border-box;width:395px;transform:translate(-10px,-10px)}.talents .talent{width:375px;text-align:center;display:flex;align-items:center;background:#000;position:relative}.talents .talent .left,.talents .talent .right{width:170px;font-size:12px}.talents .talent .level{flex:0 0 auto;width:35px;height:35px;font-size:18px;line-height:35px;text-align:center;box-sizing:border-box;border-radius:100%;color:#e7d292;text-shadow:0 0 8px #ff531c;background-color:#444}.details .list table td{width:50%;text-align:center}.details .list table tr:nth-child(2n){background-color:#333}.details .list{display:flex;flex-direction:column;padding:6px}.details .list>*{flex-grow:1}.details .bars{height:64px;flex-grow:0}.details .bars>div{height:28px;margin-bottom:4px;border-radius:5px;box-shadow:inset 0 0 2px rgba(0,0,0,.5),0 0 2px rgba(0,0,0,.3);position:relative;display:flex;align-items:center}.details .bars .health{background:linear-gradient(to top,#279027 0,#27a329 56%,#96e891 83%,#366a35 100%)}.details .bars .mana{background:linear-gradient(to top,#4676c4 0,#2b76d5 56%,#95cdff 100%)}.details .bars .mana.zero{background:0 0}.details .bars span{text-shadow:#000 1px 1px 4px}.details .bars .number{font-size:18px;position:absolute;left:50%;transform:translateX(-50%)}.details .bars .suffix{margin-left:auto;font-size:14px;padding-right:10px}.details .stats{display:flex;justify-content:space-around;line-height:1.3}.details .stats>.column>p{padding:4px;color:#b2b2b2}.details .stats .stat img{width:20px}.facets{display:flex;flex-wrap:wrap;gap:10px}.facets>.facet,.skill>.facet{flex:1 1 calc(50% - 10px);box-sizing:border-box;background-color:#181f24;position:relative;border:1px solid #2b2f33}.facets>.facet:nth-child(odd):last-child{flex-basis:100%}.facets>.facet>.name_back,.skill>.facet>.name_back{position:absolute;height:50px;width:100%}.facet>.name_back.type_0{background:linear-gradient(to right,#9f3c3c,#4a2026)}.facet>.name_line.type_0{filter:invert(22%) sepia(100%) saturate(100%) hue-rotate(316deg) brightness(98%) contrast(100%)}.facet>.name_back.type_1{background:linear-gradient(to right,#c8a45c,#6f3d21)}.facet>.name_line.type_1{filter:invert(54%) sepia(99%) saturate(100%) hue-rotate(0deg) brightness(97%) contrast(100%)}.facet>.name_back.type_2{background:linear-gradient(to right,#a2b23e,#2d5a18)}.facet>.name_line.type_2{filter:invert(57%) sepia(100%) saturate(100%) hue-rotate(32deg) brightness(93%) contrast(100%)}.facet>.name_back.type_3{background:linear-gradient(to right,#547ea6,#2a385e)}.facet>.name_line.type_3{filter:invert(39%) sepia(100%) saturate(99%) hue-rotate(167deg) brightness(99%) contrast(100%)}.facet>.name_back.type_4{background:linear-gradient(to right,#675cae,#261c44)}.facet>.name_line.type_4{filter:invert(33%) sepia(100%) saturate(100%) hue-rotate(207deg) brightness(99%) contrast(100%)}.facet>.name_back.type_5{background:linear-gradient(to right,#adb6be,#4e5557)}.facet>.name_line.type_5{filter:invert(73%) sepia(23%) saturate(99%) hue-rotate(166deg) brightness(93%) contrast(94%)}.facet>.name_line{position:absolute;background-size:cover;height:50px;width:100%;background-image:url("https://cdn.akamai.steamstatic.com/apps/dota2/images/dota_react/icons/facets/ripple_texture.png")}.facet>.name{height:50px;line-height:50px;z-index:1;position:relative;display:flex}.facet>.name>img{width:24px;padding:13px;background-color:#0003}.facet>.name>span{margin-left:16px;letter-spacing:2px;text-shadow:2px 2px 3px rgba(0,0,0,.3),4px 4px 6px rgba(0,0,0,.2),6px 6px 9px rgba(0,0,0,.1)}.facet>.content{padding:12px;display:flex;flex-direction:column;gap:12px}.facet>.content>.ability{display:flex;flex-direction:column;gap:12px}.facet>.content>.ability>.name{background:linear-gradient(to right,#9bcdff17 0,#9bcdff09 30%,#d0e8ff00 100%);line-height:1}.facet>.content>.ability>.name>img{width:30px}.facet>.content>.ability>.name>span{margin-left:10px;font-size:14px}.facet>.content .description{color:#9ab0cd}.facet>.content>.ability>.attributes{font-size:12px;display:flex;flex-direction:column;gap:5px}.facet>.content>.ability>.attributes .item{color:#737373}.facet>.content .value{color:#fff}.skills{width:800px;display:flex;flex-wrap:wrap}.skill{background-color:#141b1f;margin:5px;box-shadow:0 0 5px #fff;width:390px}.skill>:not(:nth-child(2)){padding-left:8px}.skill>.title{position:relative;background-color:#1f272b;padding:8px;font-weight:100;height:auto;width:auto}.skill>.title>.name{font-family:KaiTi,"楷体","楷体_GB2312",STKaiti,serif}.skill>.title>.is_innate{font-size:14px;line-height:18px;width:auto;display:inline;padding:2px 8px;box-sizing:content-box;background-color:#5b93d1}.skill>.title.name_back>img{width:16px}.skill img.scepter,.skill img.shard{position:absolute;width:24px;right:8px;top:50%;transform:translateY(-50%)}.skill .img_stats{display:flex;color:#546780;margin-bottom:16px;border-top:#2a363c 1px solid;border-bottom:#2a363c 1px solid}.skill .img_stats img{width:128px}.skill .img_stats .stats{padding:8px}.skill .stats .dmg_type.Physical span{color:#ae2f28}.skill .stats .dmg_type.Magical span{color:#5b93d1}.skill .stats .dmg_type.Pure span{color:#c29c4a}.skill .stats .dispellable.No span{color:red}.skill .stats .dispellable.Strong span{color:#9828ae}.skill .stats .bkbpierce.Yes span{color:#6add71}.skill>.description{color:#9bb1ce;margin-bottom:32px}.skill>.facet{padding-left:0;margin-bottom:16px}.skill .value{color:#fff}.skill .aghanim_description{padding-left:0;color:#9bb1ce;margin-bottom:16px;border:#263945 solid 3px;box-sizing:border-box}.skill .aghanim_description .title{display:block;font-size:20px;background-color:#263945;padding:12px}.skill .aghanim_description .desc{margin:12px;display:block}.skill .aghanim_description img{position:unset;transform:none;margin-right:8px}.skill .notes{padding:12px;margin-bottom:12px;color:#9fb7c6;background-color:#263945}.skill .attributes{line-height:1.2em;margin-bottom:12px}.skill .attributes .heading{color:#546780}.skill .attributes .values{color:#4b525d}.skill .attributes .values img{width:16px}.skill .attributes .facet{display:inline-flex;font-size:1em;align-items:center;line-height:1.2em;position:unset;color:#fff}.skill .attributes .facet span{height:auto;width:auto;position:unset;padding:0 2px}.skill .attributes .facet img{width:auto;height:1em;padding-right:.2em}.skill .attributes .alternative .plus{display:none}.skill .attributes .primary~.alternative .plus{display:inline}.skill .attributes .primary~.alternative::before{content:"("}.skill .attributes .primary~.alternative::after{content:")"}.skill .cooldown{padding-right:12px}.skill .cooldown::before,.skill .mana_cost::before{content:"";background-size:100%;width:21px;height:21px;display:inline-block;vertical-align:middle}.skill .cooldown::before{background-image:url("data:image/webp;base64,UklGRnABAABXRUJQVlA4TGMBAAAvE8AEEE2QTdqmkI5pRP/DS2wBEIT/bw8R/U8Ddq1NipSvGnd3eXJ3d3kmEM+GTDwBciCBTQCd7qpCeokBQdu2cc6f8tcQEBT5P9oEIGiwYuMBECqAbCUVIIAa19Py1I/AQMrJVGEABACe+DRqcl2GUxeOwIAzQkAAMCBxyi3BRcbSkzAKyIDTciQOAAgwyx43JA4CWRkeQXAAQKkGEs5+/siARwFHAHCUiAGwPwAEAGQSDgCAoCQUQc7OkwMbhgAAJBIKEAtkE9enBgcABEUxAIwyZ6cOx/lTkPiHsX+mqCQTMQRwcmAszPLUoTiCkVAAbDKEAWWUjWlGMYyEAR4n4wMeiBk8W9M1lphIQmAsmWxBJ1vfAJZIBMAoJwNQ0JTN04/yRaCCftofwWBkAMAjQ6BILaWMsEkFFVTTk/qEETyQlYFXnh9jmABKbkgzNQgemYwnTOKFEgAAOGJAeUbyhQIAAA==")}.skill .mana_cost::before{background-image:url("data:image/webp;base64,UklGRsYAAABXRUJQVlA4TLkAAAAvE8AEEIfBOIDbtEmdpEDhS8G2kSTF0eteuLOebJz/0KDREgwBAGEu/89yqe5LCyEaDT03NBcLpEXnJgkZKS2dmlqAlNSCgJXURBoNCHAY2bbSvEP0fxzi7sGh//rslRDR/xQxS0bXRkRMmr5Ho8iISY5523Ztr2vabBuaZZLVE99wRqWAUgGFAv4K+Cngo4CXAp4KeCjgroCbAi4KVv7pOnFwF8aP9+fRXeAaMZ63GbXWiIhxGJ0bEQA=")}.skill .lore{font-size:13px;color:#3e4f5b;padding:8px;line-height:1.25}body .wrapper>.lore{display:block;line-height:1.25;padding:8px;font-family:KaiTi,"楷体","楷体_GB2312",STKaiti,serif;color:#aaa}</style> <% if (fontFamily) { %> <%- "<style>" %> <%- `body { font-family: ${fontFamily}; }` %> <%- "</style>" %> <% } %> </head><body> <% let hero = data; %> <% if (hero.primary_attr==3) {
|
|
1
|
+
<!DOCTYPE html><html lang="<%= languageTag %>"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Document</title> <%- `<style>` %> <%- include("../common/styles/normalize.min.css") %> <%- include(`./hero_1/base.css`) %> <% if (fontFamily) { %><%- `body { font-family: ${fontFamily}; }` %><% } %> <%- `</style>` %> </head><body> <% let hero = data; %> <% if (hero.primary_attr==3) {
|
|
2
2
|
const base_damage = Math.floor((hero.str_base+hero.agi_base+hero.int_base)*0.45);
|
|
3
3
|
hero.damage_max+=base_damage;
|
|
4
4
|
hero.damage_min+=base_damage;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
html{overflow:visible}body{display:flex;flex-direction:column;overflow:visible}#regular{width:800px}#extra{font-size:10px;width:100%;>.tip{width:100%;line-height:4;text-align:center;color:#ccc}#charts{display:flex;>*{width:50%}}.container{height:300px;display:flex;.lane_outcome{position:relative;display:flex;flex-direction:column;width:500px;margin-right:20px;>.title{width:100%;text-align:center;padding:0;margin:0;line-height:50px}.panel{display:flex;flex-direction:column;height:100%;justify-content:space-evenly;.lane{display:flex;flex-direction:column;border-radius:10px;border:#ccc solid 1px;padding:2px;>.title{width:100%;text-align:center;height:32px;>p:nth-child(1){font-size:12px}>p:nth-child(2){font-size:14px}}img.hero{width:24px;height:24px}.kda{height:100%;line-height:32px;text-align:center;font-size:10px}.graph{height:32px;display:flex;align-items:center;justify-content:center;svg{shape-rendering:crispEdges}text{dominant-baseline:middle;white-space:nowrap}}}.details{display:grid;grid-template-columns:24px 32px 44px auto 44px 32px 24px;grid-template-rows:1fr;gap:1px;font-size:12px;height:32px;line-height:32px;align-items:center}}.subtitle{position:absolute;inset:
|
|
1
|
+
html{overflow:visible}body{display:flex;flex-direction:column;overflow:visible}#regular{width:800px}#extra{font-size:10px;width:100%;>.tip{font-size:16px;width:100%;line-height:4;text-align:center;color:#ccc}#charts{display:flex;>*{width:50%}}.container{height:300px;display:flex;.lane_outcome{position:relative;display:flex;flex-direction:column;width:500px;margin-right:20px;>.title{width:100%;text-align:center;padding:0;margin:0;line-height:50px}.panel{display:flex;flex-direction:column;height:100%;justify-content:space-evenly;.lane{display:flex;flex-direction:column;border-radius:10px;border:#ccc solid 1px;padding:2px;>.title{width:100%;text-align:center;height:32px;>p:nth-child(1){font-size:12px}>p:nth-child(2){font-size:14px}}img.hero{width:24px;height:24px}.kda{height:100%;line-height:32px;text-align:center;font-size:10px}.graph{height:32px;display:flex;align-items:center;justify-content:center;svg{shape-rendering:crispEdges}text{dominant-baseline:middle;white-space:nowrap}}}.details{display:grid;grid-template-columns:24px 32px 44px auto 44px 32px 24px;grid-template-rows:1fr;gap:1px;font-size:12px;height:32px;line-height:32px;align-items:center}}.subtitle{position:absolute;inset:10px 0 0;text-align:center;color:#ccc;font-size:12px;margin:0;z-index:1}}.map{box-sizing:border-box;width:300px;padding:25px;font-size:8px;pointer-events:none;text-shadow:0px 1px 1px rgba(0,0,0,.8);image{clip-path:inset(2% round 12px);opacity:.88;object-fit:contain}use{&.radiant{color:#95cc4b}&.dire{color:#ca4633}&.dead{color:#555}}}}}
|
|
@@ -60,7 +60,7 @@ const BUILDINGS = [
|
|
|
60
60
|
// 门牙 & 基地
|
|
61
61
|
{ id: 35, name: 'Dire T4 Left', type: 'tower', lane: "mid", bit: 9, team: 'dire', x: 189.7, y: 56.4 },
|
|
62
62
|
{ id: 35, name: 'Dire T4 Right', type: 'tower', lane: "mid", bit: 10, team: 'dire', x: 194.4, y: 60.2 },
|
|
63
|
-
{ id: 35, name: 'Dire T4 Time', type: 't4_time', lane: "mid", bit: 10, team: 'dire', x: 198, y: 63 },
|
|
63
|
+
{ id: 35, name: 'Dire T4 Time', type: 't4_time', lane: "mid", bit: [9, 10], team: 'dire', x: 198, y: 63 },
|
|
64
64
|
{ id: 51, name: 'Dire Ancient', type: 'fort', lane: "", bit: -1, team: 'dire', x: 195.7, y: 49 },
|
|
65
65
|
{ id: 51, name: 'Dire Ancient Time', type: 'fort_time', lane: "", bit: -1, team: 'dire', x: 210, y: 52 },
|
|
66
66
|
];
|
|
@@ -78,10 +78,12 @@ const BUILDINGS = [
|
|
|
78
78
|
// 2. 存活判定 (逻辑保持不变,确保正确引用 mask)
|
|
79
79
|
const checkAlive = (b) => {
|
|
80
80
|
let mask = 0;
|
|
81
|
+
const isTowerType = b.type.includes('tower') || b.type === 't4_time';
|
|
82
|
+
|
|
81
83
|
if (b.team === 'radiant') {
|
|
82
|
-
mask =
|
|
84
|
+
mask = isTowerType ? match.towerStatusRadiant : match.barracksStatusRadiant;
|
|
83
85
|
} else {
|
|
84
|
-
mask =
|
|
86
|
+
mask = isTowerType ? match.towerStatusDire : match.barracksStatusDire;
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
// T4 时间锚点 (只要有一个活着,整体就算活)
|
|
@@ -3,14 +3,6 @@
|
|
|
3
3
|
const isPos = impVal > 0;
|
|
4
4
|
const isOver = abs > 25;
|
|
5
5
|
|
|
6
|
-
// 宽度计算:如果溢出(>25),则填满单侧(25px);否则按比例
|
|
7
|
-
// 原逻辑中 .score_bar 宽 51px (中心各 25px?)。
|
|
8
|
-
// 原逻辑:
|
|
9
|
-
// if (abs > 25) { right = abs (if pos), left = abs (if neg) }
|
|
10
|
-
// 这里的逻辑有点奇怪,如果 abs=30,width=30px,父容器只有25px空间?
|
|
11
|
-
// 让我们严格遵循原逻辑:
|
|
12
|
-
// width 赋值直接是 absValue。CSS里父容器 overflow 没写 hidden,可能靠 flex 布局撑开?
|
|
13
|
-
// 无论如何,保持原值逻辑:
|
|
14
6
|
let left = 0, right = 0;
|
|
15
7
|
if (isOver) {
|
|
16
8
|
if (isPos) right = abs;
|
package/package.json
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjtdev/koishi-plugin-dota2tracker",
|
|
3
3
|
"description": "koishi插件-追踪群友的DOTA2对局",
|
|
4
|
-
"version": "2.3.
|
|
4
|
+
"version": "2.3.3",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
8
|
"lib",
|
|
9
|
-
"dist"
|
|
10
|
-
"images",
|
|
11
|
-
"template",
|
|
12
|
-
"queries"
|
|
9
|
+
"dist"
|
|
13
10
|
],
|
|
14
11
|
"contributors": [
|
|
15
12
|
"sjtdev <sh1j1n9ta0@foxmail.com>"
|
package/dist/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{store as u,icons as _}from"@koishijs/client";import{resolveComponent as a,createBlock as m,openBlock as p,withCtx as n,createVNode as l,createTextVNode as s,toDisplayString as k,unref as f,createElementVNode as i,createElementBlock as h,createStaticVNode as g}from"vue";const w={__name:"page",setup(t){return(e,o)=>{const r=a("k-card"),c=a("k-comment"),d=a("k-layout");return p(),m(d,null,{default:n(()=>[l(r,null,{default:n(()=>[s("OpenDotaAPI 今日已访问 "+k(f(u).apiCount.opendota)+" 次。",1)]),_:1}),l(r,null,{default:n(()=>[l(c,{type:"warning"},{default:n(()=>[...o[0]||(o[0]=[i("p",null,[s("该页面正在开发中,关于这个页面有任何想法或建议欢迎投稿至 "),i("a",{target:"_blank",href:"https://github.com/sjtdev/koishi-plugin-dota2tracker/issues"},"项目issues"),s("。")],-1)])]),_:1})]),_:1})]),_:1})}}},x=(t,e)=>{const o=t.__vccOpts||t;for(const[r,c]of e)o[r]=c;return o},C={},v={xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 600 600",fill:"currentColor"};function y(t,e){return p(),h("svg",v,[...e[0]||(e[0]=[g('<g><rect height="544" width="540" y="28.5" x="32" stroke="currentColor" fill="none" stroke-width="35" rx="50" ry="58"></rect><g transform="translate(300,300) scale(0.75) translate(-300,-300)" stroke-linejoin="round" stroke-linecap="round"><path d="m95,145.5l54,-30.5l361,306l-36,86l-113,-26l-266,-335.5z" stroke="currentColor" fill="none" stroke-width="35"></path><path transform="rotate(3.87406 449.593 151.279)" d="m458.26078,90.18786c0,0 61.75777,47.47474 61.75777,46.77658c0,0.69816 -8.66776,76.09922 -8.66776,75.40106c0,0.69816 -132.18329,-101.23291 -132.18329,-101.93106c0,0.69816 79.09328,-20.24658 79.09328,-20.24658z" stroke="currentColor" fill="none" stroke-width="35"></path><path d="m84,466.55926c0,0 16.71429,-92.78604 16.71429,-93.55926c0,0.77322 127.28571,110.57003 127.28571,109.79682c0,0.77322 -96.42857,23.96973 -96.42857,23.19651c0,0.77322 -47.57143,-39.43407 -47.57143,-39.43407z" stroke="currentColor" fill="none" stroke-width="35"></path></g></g>',1)])])}const B=x(C,[["render",y]]),V=t=>{_.register("dota2",B),t.page({name:"DOTA2Tracker(实验性)",path:"/dota2tracker",component:w,fields:["apiCount"],icon:"dota2"})};export{V as default};
|