@sjtdev/koishi-plugin-dota2tracker 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +665 -973
- package/package.json +3 -3
- package/readme.md +6 -7
- package/template/{hero.html → hero/hero_1.ejs} +543 -516
- package/template/images/scepter.png +0 -0
- package/template/images/shard.png +0 -0
- package/template/match/match_1.ejs +9 -8
- package/template/match/match_2.ejs +7 -5
- package/template/player/player_1.ejs +543 -0
- package/template/match_old.html +0 -1029
- package/template/player.html +0 -414
package/lib/index.js
CHANGED
|
@@ -44,285 +44,22 @@ var utils_exports = {};
|
|
|
44
44
|
__export(utils_exports, {
|
|
45
45
|
CONFIGS: () => CONFIGS,
|
|
46
46
|
ImageType: () => ImageType,
|
|
47
|
+
formatNumber: () => formatNumber,
|
|
47
48
|
getFormattedMatchData: () => getFormattedMatchData,
|
|
48
49
|
getImageUrl: () => getImageUrl,
|
|
49
|
-
|
|
50
|
+
playerisValid: () => playerisValid,
|
|
51
|
+
query: () => query,
|
|
52
|
+
readDirectoryFilesSync: () => readDirectoryFilesSync,
|
|
53
|
+
sec2time: () => sec2time,
|
|
54
|
+
winRateColor: () => winRateColor
|
|
50
55
|
});
|
|
51
56
|
var import_axios = __toESM(require("axios"));
|
|
52
57
|
var import_fs = __toESM(require("fs"));
|
|
53
|
-
var
|
|
54
|
-
var
|
|
55
|
-
async function query(query_str) {
|
|
56
|
-
return await import_axios.default.post(CONFIGS.STRATZ_API.URL, query_str, {
|
|
57
|
-
headers: {
|
|
58
|
-
"Content-Type": "application/graphql",
|
|
59
|
-
Authorization: `Bearer ${CONFIGS.STRATZ_API.TOKEN}`
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
__name(query, "query");
|
|
64
|
-
var ImageType = /* @__PURE__ */ ((ImageType2) => {
|
|
65
|
-
ImageType2["Icons"] = "icons";
|
|
66
|
-
ImageType2["Heroes"] = "heroes";
|
|
67
|
-
ImageType2["HeroIcons"] = "heroes/icons";
|
|
68
|
-
ImageType2["Items"] = "items";
|
|
69
|
-
ImageType2["Abilities"] = "abilities";
|
|
70
|
-
ImageType2["Local"] = "local";
|
|
71
|
-
return ImageType2;
|
|
72
|
-
})(ImageType || {});
|
|
73
|
-
function getImageUrl(image, type = "local" /* Local */) {
|
|
74
|
-
if (type === "local" /* Local */) {
|
|
75
|
-
try {
|
|
76
|
-
const imageData = import_fs.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-dota2tracker/template/images/${image}.png`);
|
|
77
|
-
const base64Data = imageData.toString("base64");
|
|
78
|
-
return `data:image/png;base64,${base64Data}`;
|
|
79
|
-
} catch (error) {
|
|
80
|
-
console.error(error);
|
|
81
|
-
return "";
|
|
82
|
-
}
|
|
83
|
-
} else
|
|
84
|
-
return `https://cdn.cloudflare.steamstatic.com/apps/dota2/images/dota_react/${type}/${image}.png`;
|
|
85
|
-
}
|
|
86
|
-
__name(getImageUrl, "getImageUrl");
|
|
87
|
-
function getFormattedMatchData(match) {
|
|
88
|
-
["radiant", "dire"].forEach((team) => {
|
|
89
|
-
match[team] = { killsCount: match[team + "Kills"]?.reduce((acc, cva) => acc + cva, 0) ?? 0, damageReceived: 0, heroDamage: 0, networth: 0, experience: 0 };
|
|
90
|
-
});
|
|
91
|
-
match.party = {};
|
|
92
|
-
let party_index = 0;
|
|
93
|
-
const party_mark = ["I", "II", "III", "IV"];
|
|
94
|
-
let heroOrderList = {};
|
|
95
|
-
for (let hero of match.pickBans) {
|
|
96
|
-
if (hero.isPick)
|
|
97
|
-
heroOrderList[hero.heroId] = hero.order;
|
|
98
|
-
}
|
|
99
|
-
let processLaneOutcome = /* @__PURE__ */ __name(function(outcome) {
|
|
100
|
-
switch (outcome) {
|
|
101
|
-
case "RADIANT_VICTORY":
|
|
102
|
-
return { radiant: "victory", dire: "fail" };
|
|
103
|
-
case "RADIANT_STOMP":
|
|
104
|
-
return { radiant: "stomp", dire: "stomped" };
|
|
105
|
-
case "DIRE_VICTORY":
|
|
106
|
-
return { radiant: "fail", dire: "victory" };
|
|
107
|
-
case "DIRE_STOMP":
|
|
108
|
-
return { radiant: "stomped", dire: "stomp" };
|
|
109
|
-
default:
|
|
110
|
-
return { radiant: "tie", dire: "tie" };
|
|
111
|
-
}
|
|
112
|
-
}, "processLaneOutcome");
|
|
113
|
-
let laneResult = { top: {}, mid: {}, bottom: {} };
|
|
114
|
-
laneResult.top = processLaneOutcome(match.topLaneOutcome);
|
|
115
|
-
laneResult.mid = processLaneOutcome(match.midLaneOutcome);
|
|
116
|
-
laneResult.bottom = processLaneOutcome(match.bottomLaneOutcome);
|
|
117
|
-
match.players.forEach((player) => {
|
|
118
|
-
player.team = player.isRadiant ? "radiant" : "dire";
|
|
119
|
-
player.rank = {
|
|
120
|
-
medal: parseInt(player.steamAccount.seasonRank?.toString().split("")[0] ?? 0),
|
|
121
|
-
star: parseInt(player.steamAccount.seasonRank?.toString().split("")[1] ?? 0),
|
|
122
|
-
leaderboard: player.steamAccount.seasonLeaderboardRank,
|
|
123
|
-
inTop100: player.steamAccount.seasonLeaderboardRank ? player.steamAccount.seasonLeaderboardRank <= 10 ? "8c" : player.steamAccount.seasonLeaderboardRank <= 100 ? "8b" : void 0 : void 0
|
|
124
|
-
};
|
|
125
|
-
player.killContribution = (player.kills + player.assists) / match[player.team].killsCount;
|
|
126
|
-
player.deathContribution = player.deaths / match[player.team === "radiant" ? "dire" : player.team].killsCount;
|
|
127
|
-
player.damageReceived = player.stats?.heroDamageReport?.receivedTotal.physicalDamage + player.stats?.heroDamageReport?.receivedTotal.magicalDamage + player.stats?.heroDamageReport?.receivedTotal.pureDamage;
|
|
128
|
-
match[player.team].heroDamage = (match[player.team].heroDamage ?? 0) + player.heroDamage;
|
|
129
|
-
match[player.team].damageReceived = (match[player.team].damageReceived ?? 0) + player.damageReceived;
|
|
130
|
-
match[player.team].networth += player.networth;
|
|
131
|
-
match[player.team].experience += Math.floor(player.experiencePerMinute / 60 * match.durationSeconds);
|
|
132
|
-
player.titles = [];
|
|
133
|
-
player.mvpScore = // 计算MVP分数
|
|
134
|
-
player.kills * 5 + player.assists * 3 + player.stats.heroDamageReport.dealtTotal.stunDuration / 100 * 0.1 + (player.stats.heroDamageReport.dealtTotal.slowDuration + player.stats.heroDamageReport.dealtTotal.disableDuration) / 100 * 0.05 + player.heroDamage * 1e-3 + player.towerDamage * 0.01 + player.heroHealing * 2e-3 + player.imp * 0.25;
|
|
135
|
-
player.order = heroOrderList[player.hero.id];
|
|
136
|
-
if (player.partyId != null) {
|
|
137
|
-
if (!match.party[player.partyId])
|
|
138
|
-
match.party[player.partyId] = party_mark[party_index++];
|
|
139
|
-
}
|
|
140
|
-
const maxStackCountsByAbilityOrItem = player.stats.matchPlayerBuffEvent.reduce((acc, event) => {
|
|
141
|
-
const key = event.abilityId !== null ? `ability-${event.abilityId}` : `item-${event.itemId}`;
|
|
142
|
-
if (!acc[key] || event.stackCount > acc[key].stackCount) {
|
|
143
|
-
acc[key] = event;
|
|
144
|
-
}
|
|
145
|
-
return acc;
|
|
146
|
-
}, {});
|
|
147
|
-
player.stats.matchPlayerBuffEvent.splice(0, player.stats.matchPlayerBuffEvent.length, ...Object.values(maxStackCountsByAbilityOrItem));
|
|
148
|
-
switch (player.lane) {
|
|
149
|
-
case "SAFE_LANE":
|
|
150
|
-
player.laneResult = laneResult[player.isRadiant ? "bottom" : "top"][player.team];
|
|
151
|
-
break;
|
|
152
|
-
case "OFF_LANE":
|
|
153
|
-
player.laneResult = laneResult[!player.isRadiant ? "bottom" : "top"][player.team];
|
|
154
|
-
break;
|
|
155
|
-
default:
|
|
156
|
-
player.laneResult = laneResult.mid[player.team];
|
|
157
|
-
break;
|
|
158
|
-
}
|
|
159
|
-
let items_timelist = {};
|
|
160
|
-
player.supportItemsCount = { 30: 0, 40: 0, 42: 0, 43: 0, 188: 0 };
|
|
161
|
-
if (player.playbackData) {
|
|
162
|
-
for (let item of player.playbackData.purchaseEvents) {
|
|
163
|
-
items_timelist[item.itemId] = item.time;
|
|
164
|
-
if (item.itemId == 42 || item.itemId == 43)
|
|
165
|
-
items_timelist[218] = item.time;
|
|
166
|
-
switch (item.itemId) {
|
|
167
|
-
case 30:
|
|
168
|
-
case 40:
|
|
169
|
-
case 42:
|
|
170
|
-
case 43:
|
|
171
|
-
case 188:
|
|
172
|
-
player.supportItemsCount[item.itemId]++;
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
player.items = [];
|
|
178
|
-
player.backpacks = [];
|
|
179
|
-
const prefix = "recipe_";
|
|
180
|
-
for (let i = 0; i <= 5; i++) {
|
|
181
|
-
const key = `item${i}Id`;
|
|
182
|
-
const itemId = player[key];
|
|
183
|
-
if (itemId === void 0 || itemId === null) {
|
|
184
|
-
player.items.push(null);
|
|
185
|
-
} else if (dotaconstants.item_ids[itemId]) {
|
|
186
|
-
const name2 = dotaconstants.item_ids[itemId];
|
|
187
|
-
const isRecipe = name2.startsWith(prefix);
|
|
188
|
-
const cleanName = isRecipe ? name2.substring(prefix.length) : name2;
|
|
189
|
-
player.items.push({
|
|
190
|
-
id: itemId,
|
|
191
|
-
name: cleanName,
|
|
192
|
-
time: items_timelist[itemId],
|
|
193
|
-
isRecipe
|
|
194
|
-
});
|
|
195
|
-
} else {
|
|
196
|
-
player.items.push(null);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
for (let i = 0; i <= 2; i++) {
|
|
200
|
-
const key = `backpack${i}Id`;
|
|
201
|
-
const itemId = player[key];
|
|
202
|
-
if (itemId === void 0 || itemId === null) {
|
|
203
|
-
player.backpacks.push(null);
|
|
204
|
-
} else if (dotaconstants.item_ids[itemId]) {
|
|
205
|
-
const name2 = dotaconstants.item_ids[itemId];
|
|
206
|
-
const isRecipe = name2.startsWith(prefix);
|
|
207
|
-
const cleanName = isRecipe ? name2.substring(prefix.length) : name2;
|
|
208
|
-
player.backpacks.push({
|
|
209
|
-
id: itemId,
|
|
210
|
-
name: cleanName,
|
|
211
|
-
time: items_timelist[itemId],
|
|
212
|
-
isRecipe
|
|
213
|
-
});
|
|
214
|
-
} else {
|
|
215
|
-
player.backpacks.push(null);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
if (player.additionalUnit) {
|
|
219
|
-
player.unitItems = [];
|
|
220
|
-
player.unitBackpacks = [];
|
|
221
|
-
const prefix2 = "recipe_";
|
|
222
|
-
for (let i = 0; i <= 5; i++) {
|
|
223
|
-
const key = `item${i}Id`;
|
|
224
|
-
const itemId = player.additionalUnit[key];
|
|
225
|
-
if (itemId === void 0 || itemId === null) {
|
|
226
|
-
player.unitItems.push(null);
|
|
227
|
-
} else if (dotaconstants.item_ids[itemId]) {
|
|
228
|
-
const name2 = dotaconstants.item_ids[itemId];
|
|
229
|
-
const isRecipe = name2.startsWith(prefix2);
|
|
230
|
-
const cleanName = isRecipe ? name2.substring(prefix2.length) : name2;
|
|
231
|
-
player.unitItems.push({
|
|
232
|
-
id: itemId,
|
|
233
|
-
name: cleanName,
|
|
234
|
-
time: items_timelist[itemId],
|
|
235
|
-
isRecipe
|
|
236
|
-
});
|
|
237
|
-
} else {
|
|
238
|
-
player.unitItems.push(null);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
for (let i = 0; i <= 2; i++) {
|
|
242
|
-
const key = `backpack${i}Id`;
|
|
243
|
-
const itemId = player.additionalUnit[key];
|
|
244
|
-
if (itemId === void 0 || itemId === null) {
|
|
245
|
-
player.unitBackpacks.push(null);
|
|
246
|
-
} else if (dotaconstants.item_ids[itemId]) {
|
|
247
|
-
const name2 = dotaconstants.item_ids[itemId];
|
|
248
|
-
const isRecipe = name2.startsWith(prefix2);
|
|
249
|
-
const cleanName = isRecipe ? name2.substring(prefix2.length) : name2;
|
|
250
|
-
player.unitBackpacks.push({
|
|
251
|
-
id: itemId,
|
|
252
|
-
name: cleanName,
|
|
253
|
-
time: items_timelist[itemId],
|
|
254
|
-
isRecipe
|
|
255
|
-
});
|
|
256
|
-
} else {
|
|
257
|
-
player.unitBackpacks.push(null);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
let ComparisonMode;
|
|
263
|
-
((ComparisonMode2) => {
|
|
264
|
-
ComparisonMode2["Max"] = "max";
|
|
265
|
-
ComparisonMode2["Min"] = "min";
|
|
266
|
-
})(ComparisonMode || (ComparisonMode = {}));
|
|
267
|
-
function findMaxByProperty(primaryProperty, secondaryProperty = null, players = match.players, primaryMode = "max" /* Max */, secondaryMode = "max" /* Max */) {
|
|
268
|
-
return players.reduce((result, player) => {
|
|
269
|
-
const primaryComparison = primaryMode === "max" /* Max */ ? player[primaryProperty] > result[primaryProperty] : player[primaryProperty] < result[primaryProperty];
|
|
270
|
-
const secondaryComparison = secondaryMode === "max" /* Max */ ? player[secondaryProperty] > result[secondaryProperty] : player[secondaryProperty] < result[secondaryProperty];
|
|
271
|
-
if (primaryComparison) {
|
|
272
|
-
return player;
|
|
273
|
-
} else if (player[primaryProperty] === result[primaryProperty] && secondaryProperty && secondaryComparison) {
|
|
274
|
-
return player;
|
|
275
|
-
}
|
|
276
|
-
return result;
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
__name(findMaxByProperty, "findMaxByProperty");
|
|
280
|
-
findMaxByProperty(
|
|
281
|
-
"mvpScore",
|
|
282
|
-
void 0,
|
|
283
|
-
match.players.filter((player) => match.didRadiantWin == player.isRadiant)
|
|
284
|
-
).titles.push({ name: "MVP", color: "#FFA500" });
|
|
285
|
-
findMaxByProperty(
|
|
286
|
-
"mvpScore",
|
|
287
|
-
void 0,
|
|
288
|
-
match.players.filter((player) => match.didRadiantWin != player.isRadiant)
|
|
289
|
-
).titles.push({ name: "魂", color: "#6cf" });
|
|
290
|
-
findMaxByProperty("networth").titles.push({ name: "富", color: "#FFD700" });
|
|
291
|
-
findMaxByProperty("experiencePerMinute").titles.push({ name: "睿", color: "#8888FF" });
|
|
292
|
-
match.players.reduce(
|
|
293
|
-
(max, player) => player.stats.heroDamageReport.dealtTotal.stunDuration + player.stats.heroDamageReport.dealtTotal.disableDuration + player.stats.heroDamageReport.dealtTotal.slowDuration / 2 > max.stats.heroDamageReport.dealtTotal.stunDuration + max.stats.heroDamageReport.dealtTotal.disableDuration + max.stats.heroDamageReport.dealtTotal.slowDuration / 2 ? player : max
|
|
294
|
-
).titles.push({ name: "控", color: "#FF00FF" });
|
|
295
|
-
findMaxByProperty("heroDamage").titles.push({ name: "爆", color: "#CC0088" });
|
|
296
|
-
findMaxByProperty("kills", "heroDamage").titles.push({ name: "破", color: "#DD0000" });
|
|
297
|
-
findMaxByProperty("deaths", "networth", void 0, void 0, "min" /* Min */).titles.push({ name: "鬼", color: "#CCCCCC" });
|
|
298
|
-
findMaxByProperty("assists", "heroDamage").titles.push({ name: "助", color: "#006400" });
|
|
299
|
-
findMaxByProperty("towerDamage", "heroDamage").titles.push({ name: "拆", color: "#FEDCBA" });
|
|
300
|
-
findMaxByProperty("heroHealing").titles.push({ name: "奶", color: "#00FF00" });
|
|
301
|
-
match.players.reduce(
|
|
302
|
-
(max, player) => player.stats.heroDamageReport.receivedTotal.physicalDamage + player.stats.heroDamageReport.receivedTotal.magicalDamage + player.stats.heroDamageReport.receivedTotal.pureDamage > max.stats.heroDamageReport.receivedTotal.physicalDamage + max.stats.heroDamageReport.receivedTotal.magicalDamage + max.stats.heroDamageReport.receivedTotal.pureDamage ? player : max
|
|
303
|
-
).titles.push({ name: "耐", color: "#84A1C7" });
|
|
304
|
-
match.players.reduce((lowest, player) => {
|
|
305
|
-
const currentContribution = (player.kills + player.assists) / match[player.team].KillsCount;
|
|
306
|
-
const lowestContribution = (lowest.kills + lowest.assists) / match[lowest.team].KillsCount;
|
|
307
|
-
if (currentContribution < lowestContribution) {
|
|
308
|
-
return player;
|
|
309
|
-
} else if (currentContribution === lowestContribution) {
|
|
310
|
-
const currentPlayerScore = player.kills + player.assists;
|
|
311
|
-
const lowestPlayerScore = lowest.kills + lowest.assists;
|
|
312
|
-
if (currentPlayerScore < lowestPlayerScore) {
|
|
313
|
-
return player;
|
|
314
|
-
} else if (currentPlayerScore === lowestPlayerScore) {
|
|
315
|
-
return player.heroDamage < lowest.heroDamage ? player : lowest;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
return lowest;
|
|
319
|
-
}).titles.push({ name: "摸", color: "#DDDDDD" });
|
|
320
|
-
return match;
|
|
321
|
-
}
|
|
322
|
-
__name(getFormattedMatchData, "getFormattedMatchData");
|
|
58
|
+
var dotaconstants2 = __toESM(require("dotaconstants"));
|
|
59
|
+
var import_path = __toESM(require("path"));
|
|
323
60
|
|
|
324
61
|
// src/queries.ts
|
|
325
|
-
var
|
|
62
|
+
var dotaconstants = __toESM(require("dotaconstants"));
|
|
326
63
|
function MATCH_INFO(matchId) {
|
|
327
64
|
return `
|
|
328
65
|
{
|
|
@@ -349,341 +86,665 @@ function MATCH_INFO(matchId) {
|
|
|
349
86
|
steamAccount {
|
|
350
87
|
name
|
|
351
88
|
}
|
|
352
|
-
level
|
|
353
|
-
hero {
|
|
89
|
+
level
|
|
90
|
+
hero {
|
|
91
|
+
id
|
|
92
|
+
name
|
|
93
|
+
shortName
|
|
94
|
+
}
|
|
95
|
+
dotaPlus{
|
|
96
|
+
level
|
|
97
|
+
}
|
|
98
|
+
leaverStatus
|
|
99
|
+
partyId
|
|
100
|
+
position
|
|
101
|
+
lane
|
|
102
|
+
imp
|
|
103
|
+
kills
|
|
104
|
+
deaths
|
|
105
|
+
assists
|
|
106
|
+
isRadiant
|
|
107
|
+
networth
|
|
108
|
+
steamAccount {
|
|
109
|
+
seasonRank
|
|
110
|
+
seasonLeaderboardRank
|
|
111
|
+
}
|
|
112
|
+
item0Id
|
|
113
|
+
item1Id
|
|
114
|
+
item2Id
|
|
115
|
+
item3Id
|
|
116
|
+
item4Id
|
|
117
|
+
item5Id
|
|
118
|
+
backpack0Id
|
|
119
|
+
backpack1Id
|
|
120
|
+
backpack2Id
|
|
121
|
+
neutral0Id
|
|
122
|
+
stats {
|
|
123
|
+
matchPlayerBuffEvent {
|
|
124
|
+
abilityId
|
|
125
|
+
itemId
|
|
126
|
+
stackCount
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
playbackData {
|
|
130
|
+
purchaseEvents {
|
|
131
|
+
itemId
|
|
132
|
+
time
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
heroDamage
|
|
136
|
+
towerDamage
|
|
137
|
+
stats {
|
|
138
|
+
heroDamageReport {
|
|
139
|
+
receivedTotal {
|
|
140
|
+
physicalDamage
|
|
141
|
+
magicalDamage
|
|
142
|
+
pureDamage
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
numLastHits
|
|
147
|
+
numDenies
|
|
148
|
+
goldPerMinute
|
|
149
|
+
experiencePerMinute
|
|
150
|
+
heroHealing
|
|
151
|
+
|
|
152
|
+
stats {
|
|
153
|
+
campStack
|
|
154
|
+
heroDamageReport {
|
|
155
|
+
dealtTotal {
|
|
156
|
+
stunDuration
|
|
157
|
+
stunCount
|
|
158
|
+
slowDuration
|
|
159
|
+
slowCount
|
|
160
|
+
disableDuration
|
|
161
|
+
disableCount
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
additionalUnit{
|
|
166
|
+
item0Id
|
|
167
|
+
item1Id
|
|
168
|
+
item2Id
|
|
169
|
+
item3Id
|
|
170
|
+
item4Id
|
|
171
|
+
item5Id
|
|
172
|
+
backpack0Id
|
|
173
|
+
backpack1Id
|
|
174
|
+
backpack2Id
|
|
175
|
+
neutral0Id
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
isRandom
|
|
179
|
+
}
|
|
180
|
+
pickBans {
|
|
181
|
+
isPick
|
|
182
|
+
bannedHeroId
|
|
183
|
+
heroId
|
|
184
|
+
order
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
`;
|
|
190
|
+
}
|
|
191
|
+
__name(MATCH_INFO, "MATCH_INFO");
|
|
192
|
+
function VERIFYING_PLAYER(steamAccountId) {
|
|
193
|
+
return `
|
|
194
|
+
{
|
|
195
|
+
player(steamAccountId: ${steamAccountId}) {
|
|
196
|
+
matchCount
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
`;
|
|
201
|
+
}
|
|
202
|
+
__name(VERIFYING_PLAYER, "VERIFYING_PLAYER");
|
|
203
|
+
function PLAYERS_LASTMATCH(steamAccountIds) {
|
|
204
|
+
return `
|
|
205
|
+
{
|
|
206
|
+
players(steamAccountIds:${JSON.stringify(steamAccountIds)}) {
|
|
207
|
+
steamAccount{id}
|
|
208
|
+
matches(request:{take:1}){
|
|
209
|
+
id
|
|
210
|
+
parsedDateTime
|
|
211
|
+
startDateTime
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
`;
|
|
217
|
+
}
|
|
218
|
+
__name(PLAYERS_LASTMATCH, "PLAYERS_LASTMATCH");
|
|
219
|
+
function PLAYER_INFO_WITH_25_MATCHES(steamAccountId) {
|
|
220
|
+
return `
|
|
221
|
+
{
|
|
222
|
+
player(steamAccountId: ${steamAccountId}) {
|
|
223
|
+
steamAccount {
|
|
224
|
+
avatar
|
|
225
|
+
name
|
|
226
|
+
seasonRank
|
|
227
|
+
seasonLeaderboardRank
|
|
228
|
+
id
|
|
229
|
+
}
|
|
230
|
+
guildMember {
|
|
231
|
+
guild {
|
|
232
|
+
tag
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
matchCount
|
|
236
|
+
winCount
|
|
237
|
+
performance {
|
|
238
|
+
imp
|
|
239
|
+
}
|
|
240
|
+
heroesPerformance(take: 25, request: {matchGroupOrderBy: WIN_COUNT, take: 25}) {
|
|
241
|
+
hero {
|
|
242
|
+
id
|
|
243
|
+
shortName
|
|
244
|
+
}
|
|
245
|
+
imp
|
|
246
|
+
winCount
|
|
247
|
+
matchCount
|
|
248
|
+
}
|
|
249
|
+
matches(request: {take: 25}) {
|
|
250
|
+
id
|
|
251
|
+
rank
|
|
252
|
+
lobbyType
|
|
253
|
+
gameMode
|
|
254
|
+
endDateTime
|
|
255
|
+
durationSeconds
|
|
256
|
+
didRadiantWin
|
|
257
|
+
topLaneOutcome
|
|
258
|
+
midLaneOutcome
|
|
259
|
+
bottomLaneOutcome
|
|
260
|
+
radiantKills
|
|
261
|
+
direKills
|
|
262
|
+
players(steamAccountId: ${steamAccountId}) {
|
|
263
|
+
isRadiant
|
|
264
|
+
lane
|
|
265
|
+
kills
|
|
266
|
+
deaths
|
|
267
|
+
assists
|
|
268
|
+
position
|
|
269
|
+
award
|
|
270
|
+
imp
|
|
271
|
+
hero {
|
|
272
|
+
id
|
|
273
|
+
shortName
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
`;
|
|
282
|
+
}
|
|
283
|
+
__name(PLAYER_INFO_WITH_25_MATCHES, "PLAYER_INFO_WITH_25_MATCHES");
|
|
284
|
+
function PLAYER_EXTRA_INFO(steamAccountId, matchCount, totalHeroCount) {
|
|
285
|
+
return `{
|
|
286
|
+
player(steamAccountId: ${steamAccountId}) {
|
|
287
|
+
heroesPerformance(take: ${totalHeroCount}, request: {matchGroupOrderBy: MATCH_COUNT, take: ${matchCount}}) {
|
|
288
|
+
hero {
|
|
289
|
+
id
|
|
290
|
+
shortName
|
|
291
|
+
}
|
|
292
|
+
winCount
|
|
293
|
+
matchCount
|
|
294
|
+
imp
|
|
295
|
+
}
|
|
296
|
+
dotaPlus {
|
|
297
|
+
heroId
|
|
298
|
+
level
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
`;
|
|
303
|
+
}
|
|
304
|
+
__name(PLAYER_EXTRA_INFO, "PLAYER_EXTRA_INFO");
|
|
305
|
+
function CURRENT_GAMEVERSION() {
|
|
306
|
+
return `
|
|
307
|
+
{
|
|
308
|
+
constants {
|
|
309
|
+
gameVersions{name id}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
`;
|
|
314
|
+
}
|
|
315
|
+
__name(CURRENT_GAMEVERSION, "CURRENT_GAMEVERSION");
|
|
316
|
+
function ALL_ABILITIES_CHINESE_NAME() {
|
|
317
|
+
return `
|
|
318
|
+
{
|
|
319
|
+
constants {
|
|
320
|
+
abilities(language:S_CHINESE){
|
|
321
|
+
id
|
|
322
|
+
language{displayName}
|
|
323
|
+
}
|
|
324
|
+
gameVersions{name id}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
`;
|
|
329
|
+
}
|
|
330
|
+
__name(ALL_ABILITIES_CHINESE_NAME, "ALL_ABILITIES_CHINESE_NAME");
|
|
331
|
+
function HERO_INFO(heroId) {
|
|
332
|
+
return `
|
|
333
|
+
{
|
|
334
|
+
constants {
|
|
335
|
+
hero(id: ${heroId}, language: S_CHINESE) {
|
|
354
336
|
id
|
|
355
337
|
name
|
|
356
338
|
shortName
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
leaverStatus
|
|
362
|
-
partyId
|
|
363
|
-
position
|
|
364
|
-
lane
|
|
365
|
-
imp
|
|
366
|
-
kills
|
|
367
|
-
deaths
|
|
368
|
-
assists
|
|
369
|
-
isRadiant
|
|
370
|
-
networth
|
|
371
|
-
steamAccount {
|
|
372
|
-
seasonRank
|
|
373
|
-
seasonLeaderboardRank
|
|
374
|
-
}
|
|
375
|
-
item0Id
|
|
376
|
-
item1Id
|
|
377
|
-
item2Id
|
|
378
|
-
item3Id
|
|
379
|
-
item4Id
|
|
380
|
-
item5Id
|
|
381
|
-
backpack0Id
|
|
382
|
-
backpack1Id
|
|
383
|
-
backpack2Id
|
|
384
|
-
neutral0Id
|
|
385
|
-
stats {
|
|
386
|
-
matchPlayerBuffEvent {
|
|
387
|
-
abilityId
|
|
388
|
-
itemId
|
|
389
|
-
stackCount
|
|
339
|
+
aliases
|
|
340
|
+
roles {
|
|
341
|
+
roleId
|
|
342
|
+
level
|
|
390
343
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
time
|
|
344
|
+
language {
|
|
345
|
+
displayName
|
|
346
|
+
lore
|
|
347
|
+
hype
|
|
396
348
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
349
|
+
abilities {
|
|
350
|
+
ability(language: S_CHINESE) {
|
|
351
|
+
name
|
|
352
|
+
language {
|
|
353
|
+
displayName
|
|
354
|
+
description
|
|
355
|
+
attributes
|
|
356
|
+
lore
|
|
357
|
+
aghanimDescription
|
|
358
|
+
shardDescription
|
|
359
|
+
notes
|
|
360
|
+
}
|
|
361
|
+
stat {
|
|
362
|
+
type
|
|
363
|
+
behavior
|
|
364
|
+
unitTargetType
|
|
365
|
+
unitTargetTeam
|
|
366
|
+
unitTargetFlags
|
|
367
|
+
unitDamageType
|
|
368
|
+
cooldown
|
|
369
|
+
manaCost
|
|
370
|
+
spellImmunity
|
|
371
|
+
isOnCastbar
|
|
372
|
+
isGrantedByShard
|
|
373
|
+
isGrantedByScepter
|
|
374
|
+
hasShardUpgrade
|
|
375
|
+
hasScepterUpgrade
|
|
376
|
+
}
|
|
406
377
|
}
|
|
407
378
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
goldPerMinute
|
|
412
|
-
experiencePerMinute
|
|
413
|
-
heroHealing
|
|
414
|
-
|
|
415
|
-
stats {
|
|
416
|
-
campStack
|
|
417
|
-
heroDamageReport {
|
|
418
|
-
dealtTotal {
|
|
419
|
-
stunDuration
|
|
420
|
-
stunCount
|
|
421
|
-
slowDuration
|
|
422
|
-
slowCount
|
|
423
|
-
disableDuration
|
|
424
|
-
disableCount
|
|
425
|
-
}
|
|
379
|
+
talents {
|
|
380
|
+
abilityId
|
|
381
|
+
slot
|
|
426
382
|
}
|
|
427
383
|
}
|
|
428
|
-
additionalUnit{
|
|
429
|
-
item0Id
|
|
430
|
-
item1Id
|
|
431
|
-
item2Id
|
|
432
|
-
item3Id
|
|
433
|
-
item4Id
|
|
434
|
-
item5Id
|
|
435
|
-
backpack0Id
|
|
436
|
-
backpack1Id
|
|
437
|
-
backpack2Id
|
|
438
|
-
neutral0Id
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
isRandom
|
|
442
384
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
`;
|
|
388
|
+
}
|
|
389
|
+
__name(HERO_INFO, "HERO_INFO");
|
|
390
|
+
function HERO_MATCHUP_WINRATE(heroId) {
|
|
391
|
+
return `
|
|
392
|
+
{
|
|
393
|
+
heroStats {
|
|
394
|
+
matchUp(heroId: ${heroId}, take: ${Object.keys(dotaconstants.heroes).length - 1},bracketBasicIds:LEGEND_ANCIENT) {
|
|
395
|
+
heroId
|
|
396
|
+
matchCountWith
|
|
397
|
+
matchCountVs
|
|
398
|
+
with {
|
|
399
|
+
heroId1
|
|
400
|
+
winRateHeroId1
|
|
401
|
+
heroId2
|
|
402
|
+
winRateHeroId2
|
|
403
|
+
winCount
|
|
404
|
+
matchCount
|
|
405
|
+
}
|
|
406
|
+
vs {
|
|
407
|
+
heroId1
|
|
408
|
+
winRateHeroId1
|
|
409
|
+
heroId2
|
|
410
|
+
winRateHeroId2
|
|
411
|
+
winCount
|
|
412
|
+
matchCount
|
|
413
|
+
}
|
|
414
|
+
}
|
|
448
415
|
}
|
|
449
416
|
}
|
|
417
|
+
|
|
418
|
+
`;
|
|
419
|
+
}
|
|
420
|
+
__name(HERO_MATCHUP_WINRATE, "HERO_MATCHUP_WINRATE");
|
|
421
|
+
|
|
422
|
+
// src/utils.ts
|
|
423
|
+
var CONFIGS = { STRATZ_API: { URL: "https://api.stratz.com/graphql", TOKEN: "" } };
|
|
424
|
+
async function query(query_str) {
|
|
425
|
+
return await import_axios.default.post(CONFIGS.STRATZ_API.URL, query_str, {
|
|
426
|
+
headers: {
|
|
427
|
+
"Content-Type": "application/graphql",
|
|
428
|
+
Authorization: `Bearer ${CONFIGS.STRATZ_API.TOKEN}`
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
__name(query, "query");
|
|
433
|
+
var ImageType = /* @__PURE__ */ ((ImageType2) => {
|
|
434
|
+
ImageType2["Icons"] = "icons";
|
|
435
|
+
ImageType2["Heroes"] = "heroes";
|
|
436
|
+
ImageType2["HeroIcons"] = "heroes/icons";
|
|
437
|
+
ImageType2["Items"] = "items";
|
|
438
|
+
ImageType2["Abilities"] = "abilities";
|
|
439
|
+
ImageType2["Local"] = "local";
|
|
440
|
+
return ImageType2;
|
|
441
|
+
})(ImageType || {});
|
|
442
|
+
function getImageUrl(image, type = "local" /* Local */) {
|
|
443
|
+
if (type === "local" /* Local */) {
|
|
444
|
+
try {
|
|
445
|
+
const imageData = import_fs.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-dota2tracker/template/images/${image}.png`);
|
|
446
|
+
const base64Data = imageData.toString("base64");
|
|
447
|
+
return `data:image/png;base64,${base64Data}`;
|
|
448
|
+
} catch (error) {
|
|
449
|
+
console.error(error);
|
|
450
|
+
return "";
|
|
451
|
+
}
|
|
452
|
+
} else
|
|
453
|
+
return `https://cdn.cloudflare.steamstatic.com/apps/dota2/images/dota_react/${type}/${image}.png`;
|
|
454
|
+
}
|
|
455
|
+
__name(getImageUrl, "getImageUrl");
|
|
456
|
+
function getFormattedMatchData(match) {
|
|
457
|
+
["radiant", "dire"].forEach((team) => {
|
|
458
|
+
match[team] = { killsCount: match[team + "Kills"]?.reduce((acc, cva) => acc + cva, 0) ?? 0, damageReceived: 0, heroDamage: 0, networth: 0, experience: 0 };
|
|
459
|
+
});
|
|
460
|
+
match.party = {};
|
|
461
|
+
let party_index = 0;
|
|
462
|
+
const party_mark = ["I", "II", "III", "IV"];
|
|
463
|
+
let heroOrderList = {};
|
|
464
|
+
for (let hero of match.pickBans) {
|
|
465
|
+
if (hero.isPick)
|
|
466
|
+
heroOrderList[hero.heroId] = hero.order;
|
|
467
|
+
}
|
|
468
|
+
let processLaneOutcome = /* @__PURE__ */ __name(function(outcome) {
|
|
469
|
+
switch (outcome) {
|
|
470
|
+
case "RADIANT_VICTORY":
|
|
471
|
+
return { radiant: "victory", dire: "fail" };
|
|
472
|
+
case "RADIANT_STOMP":
|
|
473
|
+
return { radiant: "stomp", dire: "stomped" };
|
|
474
|
+
case "DIRE_VICTORY":
|
|
475
|
+
return { radiant: "fail", dire: "victory" };
|
|
476
|
+
case "DIRE_STOMP":
|
|
477
|
+
return { radiant: "stomped", dire: "stomp" };
|
|
478
|
+
default:
|
|
479
|
+
return { radiant: "tie", dire: "tie" };
|
|
480
|
+
}
|
|
481
|
+
}, "processLaneOutcome");
|
|
482
|
+
let laneResult = { top: {}, mid: {}, bottom: {} };
|
|
483
|
+
laneResult.top = processLaneOutcome(match.topLaneOutcome);
|
|
484
|
+
laneResult.mid = processLaneOutcome(match.midLaneOutcome);
|
|
485
|
+
laneResult.bottom = processLaneOutcome(match.bottomLaneOutcome);
|
|
486
|
+
match.players.forEach((player) => {
|
|
487
|
+
player.team = player.isRadiant ? "radiant" : "dire";
|
|
488
|
+
player.rank = {
|
|
489
|
+
medal: parseInt(player.steamAccount.seasonRank?.toString().split("")[0] ?? 0),
|
|
490
|
+
star: parseInt(player.steamAccount.seasonRank?.toString().split("")[1] ?? 0),
|
|
491
|
+
leaderboard: player.steamAccount.seasonLeaderboardRank,
|
|
492
|
+
inTop100: player.steamAccount.seasonLeaderboardRank ? player.steamAccount.seasonLeaderboardRank <= 10 ? "8c" : player.steamAccount.seasonLeaderboardRank <= 100 ? "8b" : void 0 : void 0
|
|
493
|
+
};
|
|
494
|
+
player.killContribution = (player.kills + player.assists) / match[player.team].killsCount;
|
|
495
|
+
player.deathContribution = player.deaths / match[player.team === "radiant" ? "dire" : player.team].killsCount;
|
|
496
|
+
player.damageReceived = player.stats?.heroDamageReport?.receivedTotal.physicalDamage + player.stats?.heroDamageReport?.receivedTotal.magicalDamage + player.stats?.heroDamageReport?.receivedTotal.pureDamage;
|
|
497
|
+
match[player.team].heroDamage = (match[player.team].heroDamage ?? 0) + player.heroDamage;
|
|
498
|
+
match[player.team].damageReceived = (match[player.team].damageReceived ?? 0) + player.damageReceived;
|
|
499
|
+
match[player.team].networth += player.networth;
|
|
500
|
+
match[player.team].experience += Math.floor(player.experiencePerMinute / 60 * match.durationSeconds);
|
|
501
|
+
player.titles = [];
|
|
502
|
+
player.mvpScore = // 计算MVP分数
|
|
503
|
+
player.kills * 5 + player.assists * 3 + player.stats.heroDamageReport.dealtTotal.stunDuration / 100 * 0.1 + (player.stats.heroDamageReport.dealtTotal.slowDuration + player.stats.heroDamageReport.dealtTotal.disableDuration) / 100 * 0.05 + player.heroDamage * 1e-3 + player.towerDamage * 0.01 + player.heroHealing * 2e-3 + player.imp * 0.25;
|
|
504
|
+
player.order = heroOrderList[player.hero.id];
|
|
505
|
+
if (player.partyId != null) {
|
|
506
|
+
if (!match.party[player.partyId])
|
|
507
|
+
match.party[player.partyId] = party_mark[party_index++];
|
|
508
|
+
}
|
|
509
|
+
const maxStackCountsByAbilityOrItem = player.stats.matchPlayerBuffEvent.reduce((acc, event) => {
|
|
510
|
+
const key = event.abilityId !== null ? `ability-${event.abilityId}` : `item-${event.itemId}`;
|
|
511
|
+
if (!acc[key] || event.stackCount > acc[key].stackCount) {
|
|
512
|
+
acc[key] = event;
|
|
513
|
+
}
|
|
514
|
+
return acc;
|
|
515
|
+
}, {});
|
|
516
|
+
player.stats.matchPlayerBuffEvent.splice(0, player.stats.matchPlayerBuffEvent.length, ...Object.values(maxStackCountsByAbilityOrItem));
|
|
517
|
+
switch (player.lane) {
|
|
518
|
+
case "SAFE_LANE":
|
|
519
|
+
player.laneResult = laneResult[player.isRadiant ? "bottom" : "top"][player.team];
|
|
520
|
+
break;
|
|
521
|
+
case "OFF_LANE":
|
|
522
|
+
player.laneResult = laneResult[!player.isRadiant ? "bottom" : "top"][player.team];
|
|
523
|
+
break;
|
|
524
|
+
default:
|
|
525
|
+
player.laneResult = laneResult.mid[player.team];
|
|
526
|
+
break;
|
|
450
527
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
528
|
+
let items_timelist = {};
|
|
529
|
+
player.supportItemsCount = { 30: 0, 40: 0, 42: 0, 43: 0, 188: 0 };
|
|
530
|
+
if (player.playbackData) {
|
|
531
|
+
for (let item of player.playbackData.purchaseEvents) {
|
|
532
|
+
items_timelist[item.itemId] = item.time;
|
|
533
|
+
if (item.itemId == 42 || item.itemId == 43)
|
|
534
|
+
items_timelist[218] = item.time;
|
|
535
|
+
switch (item.itemId) {
|
|
536
|
+
case 30:
|
|
537
|
+
case 40:
|
|
538
|
+
case 42:
|
|
539
|
+
case 43:
|
|
540
|
+
case 188:
|
|
541
|
+
player.supportItemsCount[item.itemId]++;
|
|
542
|
+
break;
|
|
460
543
|
}
|
|
461
544
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
545
|
+
}
|
|
546
|
+
player.items = [];
|
|
547
|
+
player.backpacks = [];
|
|
548
|
+
const prefix = "recipe_";
|
|
549
|
+
for (let i = 0; i <= 5; i++) {
|
|
550
|
+
const key = `item${i}Id`;
|
|
551
|
+
const itemId = player[key];
|
|
552
|
+
if (itemId === void 0 || itemId === null) {
|
|
553
|
+
player.items.push(null);
|
|
554
|
+
} else if (dotaconstants2.item_ids[itemId]) {
|
|
555
|
+
const name2 = dotaconstants2.item_ids[itemId];
|
|
556
|
+
const isRecipe = name2.startsWith(prefix);
|
|
557
|
+
const cleanName = isRecipe ? name2.substring(prefix.length) : name2;
|
|
558
|
+
player.items.push({
|
|
559
|
+
id: itemId,
|
|
560
|
+
name: cleanName,
|
|
561
|
+
time: items_timelist[itemId],
|
|
562
|
+
isRecipe
|
|
563
|
+
});
|
|
564
|
+
} else {
|
|
565
|
+
player.items.push(null);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
for (let i = 0; i <= 2; i++) {
|
|
569
|
+
const key = `backpack${i}Id`;
|
|
570
|
+
const itemId = player[key];
|
|
571
|
+
if (itemId === void 0 || itemId === null) {
|
|
572
|
+
player.backpacks.push(null);
|
|
573
|
+
} else if (dotaconstants2.item_ids[itemId]) {
|
|
574
|
+
const name2 = dotaconstants2.item_ids[itemId];
|
|
575
|
+
const isRecipe = name2.startsWith(prefix);
|
|
576
|
+
const cleanName = isRecipe ? name2.substring(prefix.length) : name2;
|
|
577
|
+
player.backpacks.push({
|
|
578
|
+
id: itemId,
|
|
579
|
+
name: cleanName,
|
|
580
|
+
time: items_timelist[itemId],
|
|
581
|
+
isRecipe
|
|
582
|
+
});
|
|
583
|
+
} else {
|
|
584
|
+
player.backpacks.push(null);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
if (player.additionalUnit) {
|
|
588
|
+
player.unitItems = [];
|
|
589
|
+
player.unitBackpacks = [];
|
|
590
|
+
const prefix2 = "recipe_";
|
|
591
|
+
for (let i = 0; i <= 5; i++) {
|
|
592
|
+
const key = `item${i}Id`;
|
|
593
|
+
const itemId = player.additionalUnit[key];
|
|
594
|
+
if (itemId === void 0 || itemId === null) {
|
|
595
|
+
player.unitItems.push(null);
|
|
596
|
+
} else if (dotaconstants2.item_ids[itemId]) {
|
|
597
|
+
const name2 = dotaconstants2.item_ids[itemId];
|
|
598
|
+
const isRecipe = name2.startsWith(prefix2);
|
|
599
|
+
const cleanName = isRecipe ? name2.substring(prefix2.length) : name2;
|
|
600
|
+
player.unitItems.push({
|
|
601
|
+
id: itemId,
|
|
602
|
+
name: cleanName,
|
|
603
|
+
time: items_timelist[itemId],
|
|
604
|
+
isRecipe
|
|
605
|
+
});
|
|
606
|
+
} else {
|
|
607
|
+
player.unitItems.push(null);
|
|
476
608
|
}
|
|
477
609
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
tag
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
matchCount
|
|
499
|
-
winCount
|
|
500
|
-
performance {
|
|
501
|
-
imp
|
|
502
|
-
}
|
|
503
|
-
heroesPerformance(take: 25, request: {matchGroupOrderBy: WIN_COUNT, take: 25}) {
|
|
504
|
-
hero {
|
|
505
|
-
id
|
|
506
|
-
shortName
|
|
507
|
-
}
|
|
508
|
-
imp
|
|
509
|
-
winCount
|
|
510
|
-
matchCount
|
|
511
|
-
}
|
|
512
|
-
matches(request: {take: 25}) {
|
|
513
|
-
id
|
|
514
|
-
rank
|
|
515
|
-
lobbyType
|
|
516
|
-
gameMode
|
|
517
|
-
endDateTime
|
|
518
|
-
durationSeconds
|
|
519
|
-
didRadiantWin
|
|
520
|
-
topLaneOutcome
|
|
521
|
-
midLaneOutcome
|
|
522
|
-
bottomLaneOutcome
|
|
523
|
-
radiantKills
|
|
524
|
-
direKills
|
|
525
|
-
players(steamAccountId: ${steamAccountId}) {
|
|
526
|
-
isRadiant
|
|
527
|
-
lane
|
|
528
|
-
kills
|
|
529
|
-
deaths
|
|
530
|
-
assists
|
|
531
|
-
award
|
|
532
|
-
imp
|
|
533
|
-
hero {
|
|
534
|
-
id
|
|
535
|
-
shortName
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
`;
|
|
544
|
-
}
|
|
545
|
-
__name(PLAYER_INFO_WITH_25_MATCHES, "PLAYER_INFO_WITH_25_MATCHES");
|
|
546
|
-
function PLAYER_EXTRA_INFO(steamAccountId, matchCount, totalHeroCount) {
|
|
547
|
-
return `{
|
|
548
|
-
player(steamAccountId: ${steamAccountId}) {
|
|
549
|
-
heroesPerformance(take: ${totalHeroCount}, request: {matchGroupOrderBy: MATCH_COUNT, take: ${matchCount}}) {
|
|
550
|
-
hero {
|
|
551
|
-
id
|
|
552
|
-
shortName
|
|
553
|
-
}
|
|
554
|
-
winCount
|
|
555
|
-
matchCount
|
|
556
|
-
imp
|
|
557
|
-
}
|
|
558
|
-
dotaPlus {
|
|
559
|
-
heroId
|
|
560
|
-
level
|
|
561
|
-
}
|
|
610
|
+
for (let i = 0; i <= 2; i++) {
|
|
611
|
+
const key = `backpack${i}Id`;
|
|
612
|
+
const itemId = player.additionalUnit[key];
|
|
613
|
+
if (itemId === void 0 || itemId === null) {
|
|
614
|
+
player.unitBackpacks.push(null);
|
|
615
|
+
} else if (dotaconstants2.item_ids[itemId]) {
|
|
616
|
+
const name2 = dotaconstants2.item_ids[itemId];
|
|
617
|
+
const isRecipe = name2.startsWith(prefix2);
|
|
618
|
+
const cleanName = isRecipe ? name2.substring(prefix2.length) : name2;
|
|
619
|
+
player.unitBackpacks.push({
|
|
620
|
+
id: itemId,
|
|
621
|
+
name: cleanName,
|
|
622
|
+
time: items_timelist[itemId],
|
|
623
|
+
isRecipe
|
|
624
|
+
});
|
|
625
|
+
} else {
|
|
626
|
+
player.unitBackpacks.push(null);
|
|
562
627
|
}
|
|
563
628
|
}
|
|
564
|
-
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
let ComparisonMode;
|
|
632
|
+
((ComparisonMode2) => {
|
|
633
|
+
ComparisonMode2["Max"] = "max";
|
|
634
|
+
ComparisonMode2["Min"] = "min";
|
|
635
|
+
})(ComparisonMode || (ComparisonMode = {}));
|
|
636
|
+
function findMaxByProperty(primaryProperty, secondaryProperty = null, players = match.players, primaryMode = "max" /* Max */, secondaryMode = "max" /* Max */) {
|
|
637
|
+
return players.reduce((result, player) => {
|
|
638
|
+
const primaryComparison = primaryMode === "max" /* Max */ ? player[primaryProperty] > result[primaryProperty] : player[primaryProperty] < result[primaryProperty];
|
|
639
|
+
const secondaryComparison = secondaryMode === "max" /* Max */ ? player[secondaryProperty] > result[secondaryProperty] : player[secondaryProperty] < result[secondaryProperty];
|
|
640
|
+
if (primaryComparison) {
|
|
641
|
+
return player;
|
|
642
|
+
} else if (player[primaryProperty] === result[primaryProperty] && secondaryProperty && secondaryComparison) {
|
|
643
|
+
return player;
|
|
644
|
+
}
|
|
645
|
+
return result;
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
__name(findMaxByProperty, "findMaxByProperty");
|
|
649
|
+
findMaxByProperty(
|
|
650
|
+
"mvpScore",
|
|
651
|
+
void 0,
|
|
652
|
+
match.players.filter((player) => match.didRadiantWin == player.isRadiant)
|
|
653
|
+
).titles.push({ name: "MVP", color: "#FFA500" });
|
|
654
|
+
findMaxByProperty(
|
|
655
|
+
"mvpScore",
|
|
656
|
+
void 0,
|
|
657
|
+
match.players.filter((player) => match.didRadiantWin != player.isRadiant)
|
|
658
|
+
).titles.push({ name: "魂", color: "#6cf" });
|
|
659
|
+
findMaxByProperty("networth").titles.push({ name: "富", color: "#FFD700" });
|
|
660
|
+
findMaxByProperty("experiencePerMinute").titles.push({ name: "睿", color: "#8888FF" });
|
|
661
|
+
match.players.reduce(
|
|
662
|
+
(max, player) => player.stats.heroDamageReport.dealtTotal.stunDuration + player.stats.heroDamageReport.dealtTotal.disableDuration + player.stats.heroDamageReport.dealtTotal.slowDuration / 2 > max.stats.heroDamageReport.dealtTotal.stunDuration + max.stats.heroDamageReport.dealtTotal.disableDuration + max.stats.heroDamageReport.dealtTotal.slowDuration / 2 ? player : max
|
|
663
|
+
).titles.push({ name: "控", color: "#FF00FF" });
|
|
664
|
+
findMaxByProperty("heroDamage").titles.push({ name: "爆", color: "#CC0088" });
|
|
665
|
+
findMaxByProperty("kills", "heroDamage").titles.push({ name: "破", color: "#DD0000" });
|
|
666
|
+
findMaxByProperty("deaths", "networth", void 0, void 0, "min" /* Min */).titles.push({ name: "鬼", color: "#CCCCCC" });
|
|
667
|
+
findMaxByProperty("assists", "heroDamage").titles.push({ name: "助", color: "#006400" });
|
|
668
|
+
findMaxByProperty("towerDamage", "heroDamage").titles.push({ name: "拆", color: "#FEDCBA" });
|
|
669
|
+
findMaxByProperty("heroHealing").titles.push({ name: "奶", color: "#00FF00" });
|
|
670
|
+
match.players.reduce(
|
|
671
|
+
(max, player) => player.stats.heroDamageReport.receivedTotal.physicalDamage + player.stats.heroDamageReport.receivedTotal.magicalDamage + player.stats.heroDamageReport.receivedTotal.pureDamage > max.stats.heroDamageReport.receivedTotal.physicalDamage + max.stats.heroDamageReport.receivedTotal.magicalDamage + max.stats.heroDamageReport.receivedTotal.pureDamage ? player : max
|
|
672
|
+
).titles.push({ name: "耐", color: "#84A1C7" });
|
|
673
|
+
match.players.reduce((lowest, player) => {
|
|
674
|
+
const currentContribution = (player.kills + player.assists) / match[player.team].KillsCount;
|
|
675
|
+
const lowestContribution = (lowest.kills + lowest.assists) / match[lowest.team].KillsCount;
|
|
676
|
+
if (currentContribution < lowestContribution) {
|
|
677
|
+
return player;
|
|
678
|
+
} else if (currentContribution === lowestContribution) {
|
|
679
|
+
const currentPlayerScore = player.kills + player.assists;
|
|
680
|
+
const lowestPlayerScore = lowest.kills + lowest.assists;
|
|
681
|
+
if (currentPlayerScore < lowestPlayerScore) {
|
|
682
|
+
return player;
|
|
683
|
+
} else if (currentPlayerScore === lowestPlayerScore) {
|
|
684
|
+
return player.heroDamage < lowest.heroDamage ? player : lowest;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return lowest;
|
|
688
|
+
}).titles.push({ name: "摸", color: "#DDDDDD" });
|
|
689
|
+
return match;
|
|
565
690
|
}
|
|
566
|
-
__name(
|
|
567
|
-
function
|
|
568
|
-
return
|
|
569
|
-
{
|
|
570
|
-
constants {
|
|
571
|
-
gameVersions{name id}
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
`;
|
|
691
|
+
__name(getFormattedMatchData, "getFormattedMatchData");
|
|
692
|
+
function sec2time(sec) {
|
|
693
|
+
return sec ? (sec < 0 ? "-" : "") + Math.floor(Math.abs(sec) / 60) + ":" + ("00" + Math.abs(sec) % 60).slice(-2) : "--:--";
|
|
576
694
|
}
|
|
577
|
-
__name(
|
|
578
|
-
function
|
|
579
|
-
return
|
|
580
|
-
{
|
|
581
|
-
constants {
|
|
582
|
-
abilities(language:S_CHINESE){
|
|
583
|
-
id
|
|
584
|
-
language{displayName}
|
|
585
|
-
}
|
|
586
|
-
gameVersions{name id}
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
`;
|
|
695
|
+
__name(sec2time, "sec2time");
|
|
696
|
+
function formatNumber(num) {
|
|
697
|
+
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
591
698
|
}
|
|
592
|
-
__name(
|
|
593
|
-
function
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
roles {
|
|
603
|
-
roleId
|
|
604
|
-
level
|
|
605
|
-
}
|
|
606
|
-
language {
|
|
607
|
-
displayName
|
|
608
|
-
lore
|
|
609
|
-
hype
|
|
610
|
-
}
|
|
611
|
-
abilities {
|
|
612
|
-
ability(language: S_CHINESE) {
|
|
613
|
-
name
|
|
614
|
-
language {
|
|
615
|
-
displayName
|
|
616
|
-
description
|
|
617
|
-
attributes
|
|
618
|
-
lore
|
|
619
|
-
aghanimDescription
|
|
620
|
-
shardDescription
|
|
621
|
-
notes
|
|
622
|
-
}
|
|
623
|
-
stat {
|
|
624
|
-
type
|
|
625
|
-
behavior
|
|
626
|
-
unitTargetType
|
|
627
|
-
unitTargetTeam
|
|
628
|
-
unitTargetFlags
|
|
629
|
-
unitDamageType
|
|
630
|
-
cooldown
|
|
631
|
-
manaCost
|
|
632
|
-
spellImmunity
|
|
633
|
-
isOnCastbar
|
|
634
|
-
isGrantedByShard
|
|
635
|
-
isGrantedByScepter
|
|
636
|
-
hasShardUpgrade
|
|
637
|
-
hasScepterUpgrade
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
talents {
|
|
642
|
-
abilityId
|
|
643
|
-
slot
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
`;
|
|
699
|
+
__name(formatNumber, "formatNumber");
|
|
700
|
+
function readDirectoryFilesSync(directoryPath) {
|
|
701
|
+
try {
|
|
702
|
+
const files = import_fs.default.readdirSync(directoryPath);
|
|
703
|
+
const fileNames = files.map((file) => import_path.default.basename(file, import_path.default.extname(file)));
|
|
704
|
+
return fileNames;
|
|
705
|
+
} catch (error) {
|
|
706
|
+
console.error("Error reading directory:", error);
|
|
707
|
+
return [];
|
|
708
|
+
}
|
|
650
709
|
}
|
|
651
|
-
__name(
|
|
652
|
-
function
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
heroId1
|
|
670
|
-
winRateHeroId1
|
|
671
|
-
heroId2
|
|
672
|
-
winRateHeroId2
|
|
673
|
-
winCount
|
|
674
|
-
matchCount
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
`;
|
|
710
|
+
__name(readDirectoryFilesSync, "readDirectoryFilesSync");
|
|
711
|
+
function winRateColor(value) {
|
|
712
|
+
value = value * 100;
|
|
713
|
+
value = Math.max(0, Math.min(100, value));
|
|
714
|
+
let red, green, blue;
|
|
715
|
+
if (value <= 50) {
|
|
716
|
+
let scale = Math.round(255 * (value / 50));
|
|
717
|
+
red = 255;
|
|
718
|
+
green = scale;
|
|
719
|
+
blue = scale;
|
|
720
|
+
} else {
|
|
721
|
+
let scale = Math.round(255 * ((value - 50) / 50));
|
|
722
|
+
red = 255 - scale;
|
|
723
|
+
green = 255;
|
|
724
|
+
blue = 255 - scale;
|
|
725
|
+
}
|
|
726
|
+
const toHex = /* @__PURE__ */ __name((color) => color.toString(16).padStart(2, "0").toUpperCase(), "toHex");
|
|
727
|
+
return `#${toHex(red)}${toHex(green)}${toHex(blue)}`;
|
|
681
728
|
}
|
|
682
|
-
__name(
|
|
729
|
+
__name(winRateColor, "winRateColor");
|
|
730
|
+
async function playerisValid(steamAccountId) {
|
|
731
|
+
try {
|
|
732
|
+
let queryRes = await query(VERIFYING_PLAYER(steamAccountId));
|
|
733
|
+
if (queryRes.status == 200) {
|
|
734
|
+
if (queryRes.data.data.player.matchCount != null)
|
|
735
|
+
return { isValid: true };
|
|
736
|
+
else
|
|
737
|
+
return { isValid: false, reason: "SteamID无效或无任何场次。" };
|
|
738
|
+
}
|
|
739
|
+
} catch (error) {
|
|
740
|
+
console.error(error);
|
|
741
|
+
return { isValid: false, reason: "网络状况不佳SteamID验证失败,请稍后重试。" };
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
__name(playerisValid, "playerisValid");
|
|
683
745
|
|
|
684
746
|
// src/index.ts
|
|
685
747
|
var import_fs2 = __toESM(require("fs"));
|
|
686
|
-
var cheerio = __toESM(require("cheerio"));
|
|
687
748
|
var import_moment = __toESM(require("moment"));
|
|
688
749
|
var dotaconstants3 = __toESM(require("dotaconstants"));
|
|
689
750
|
|
|
@@ -956,14 +1017,20 @@ var dotaconstants_add_default = {
|
|
|
956
1017
|
// src/index.ts
|
|
957
1018
|
var import_koishi2 = require("koishi");
|
|
958
1019
|
var ejs = __toESM(require("ejs"));
|
|
959
|
-
var
|
|
1020
|
+
var import_path2 = __toESM(require("path"));
|
|
960
1021
|
var name = "dota2tracker";
|
|
961
1022
|
var usage = "DOTA2Bot插件-提供自动追踪群友的最新对局的功能(需群友绑定),以及一系列查询功能。";
|
|
962
1023
|
var inject = ["database", "puppeteer", "cron"];
|
|
963
|
-
var Config = import_koishi.Schema.
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
})
|
|
1024
|
+
var Config = import_koishi.Schema.intersect([
|
|
1025
|
+
import_koishi.Schema.object({
|
|
1026
|
+
STRATZ_API_TOKEN: import_koishi.Schema.string().required().description("※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取")
|
|
1027
|
+
}).description("基础设置"),
|
|
1028
|
+
import_koishi.Schema.object({
|
|
1029
|
+
template_match: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/match`)]).default("match_1").description("生成比赛信息图片使用的模板,见 https://github.com/sjtdev/koishi-plugin-dota2tracker/wiki 有模板展示。"),
|
|
1030
|
+
template_player: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/player`)]).default("player_1").description("生成玩家信息图片使用的模板。(目前仅有一张模板)"),
|
|
1031
|
+
template_hero: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/hero`)]).default("hero_1").description("生成英雄信息图片使用的模板。(目前仅有一张模板)")
|
|
1032
|
+
}).description("模板设置")
|
|
1033
|
+
]);
|
|
967
1034
|
var pendingMatches = [];
|
|
968
1035
|
var random = new import_koishi2.Random(() => Math.random());
|
|
969
1036
|
async function apply(ctx, config) {
|
|
@@ -1008,8 +1075,8 @@ async function apply(ctx, config) {
|
|
|
1008
1075
|
);
|
|
1009
1076
|
return;
|
|
1010
1077
|
}
|
|
1011
|
-
let verifyRes = await
|
|
1012
|
-
if (!verifyRes.
|
|
1078
|
+
let verifyRes = await playerisValid(steam_id);
|
|
1079
|
+
if (!verifyRes.isValid) {
|
|
1013
1080
|
session.send(`绑定失败,${verifyRes.reason}`);
|
|
1014
1081
|
return;
|
|
1015
1082
|
}
|
|
@@ -1069,7 +1136,7 @@ async function apply(ctx, config) {
|
|
|
1069
1136
|
}
|
|
1070
1137
|
}
|
|
1071
1138
|
if (match && match.parsedDateTime) {
|
|
1072
|
-
session.send(await ctx.puppeteer.render(
|
|
1139
|
+
session.send(await ctx.puppeteer.render(genImageHTML(match, config.template_match, "match" /* Match */)));
|
|
1073
1140
|
ctx.database.upsert("dt_previous_query_results", (row) => [{ matchId: match.id, data: match, queryTime: /* @__PURE__ */ new Date() }]);
|
|
1074
1141
|
} else {
|
|
1075
1142
|
pendingMatches.push({ matchId, platform: session.event.platform, guildId: session.event.guild.id });
|
|
@@ -1175,7 +1242,7 @@ async function apply(ctx, config) {
|
|
|
1175
1242
|
player.heroesPerformanceTop10 = playerExtra.heroesPerformance.slice(0, 10);
|
|
1176
1243
|
} else
|
|
1177
1244
|
throw 0;
|
|
1178
|
-
session.send(await ctx.puppeteer.render(
|
|
1245
|
+
session.send(await ctx.puppeteer.render(genImageHTML(player, config.template_player, "player" /* Player */)));
|
|
1179
1246
|
} catch (error) {
|
|
1180
1247
|
console.error(error);
|
|
1181
1248
|
session.send("获取玩家信息失败。");
|
|
@@ -1228,7 +1295,7 @@ async function apply(ctx, config) {
|
|
|
1228
1295
|
if (queryRes3.status == 200) {
|
|
1229
1296
|
let hero = queryRes3.data.data.constants.hero;
|
|
1230
1297
|
hero.talents.forEach((talent) => talent.name_cn = AbilitiesConstantsCN.data.abilities.find((item) => item.id == talent.abilityId).language.displayName);
|
|
1231
|
-
await session.send(await ctx.puppeteer.render(
|
|
1298
|
+
await session.send(await ctx.puppeteer.render(genImageHTML(hero, config.template_hero, "hero" /* Hero */)));
|
|
1232
1299
|
} else
|
|
1233
1300
|
throw 0;
|
|
1234
1301
|
} catch (error) {
|
|
@@ -1355,7 +1422,7 @@ async function apply(ctx, config) {
|
|
|
1355
1422
|
const commingMatches = scanningMatches.filter((item) => item.matchId == match.id);
|
|
1356
1423
|
const realCommingMatches = commingMatches.filter((commingMatch, index, self) => index === self.findIndex((t) => t.guildId === commingMatch.guildId && t.platform === commingMatch.platform));
|
|
1357
1424
|
let broadMatchMessage = "";
|
|
1358
|
-
const img = await ctx.puppeteer.render(
|
|
1425
|
+
const img = await ctx.puppeteer.render(genImageHTML(match, config.template_match, "match" /* Match */));
|
|
1359
1426
|
for (let comming of realCommingMatches) {
|
|
1360
1427
|
let commingSubscribedPlayers = subscribedPlayersInGuild.filter((item) => item.platform == comming.platform && item.guildId == comming.guildId);
|
|
1361
1428
|
let idsToFind = commingSubscribedPlayers.map((item) => item.steamId);
|
|
@@ -1394,20 +1461,18 @@ KDA:${((player.kills + player.assists) / (player.deaths || 1)).toFixed(2)} [${
|
|
|
1394
1461
|
});
|
|
1395
1462
|
}
|
|
1396
1463
|
__name(apply, "apply");
|
|
1397
|
-
function
|
|
1398
|
-
const templatePath =
|
|
1399
|
-
const
|
|
1400
|
-
|
|
1464
|
+
function genImageHTML(data, template, type) {
|
|
1465
|
+
const templatePath = import_path2.default.join(`./node_modules/@sjtdev/koishi-plugin-${name}/template/${type}`, template + ".ejs");
|
|
1466
|
+
const templateData = {
|
|
1467
|
+
data,
|
|
1401
1468
|
utils: utils_exports,
|
|
1402
1469
|
ImageType,
|
|
1403
1470
|
d2a: dotaconstants_add_exports,
|
|
1404
1471
|
dotaconstants: dotaconstants3,
|
|
1405
|
-
moment: import_moment.default
|
|
1406
|
-
sec2time,
|
|
1407
|
-
formatNumber
|
|
1472
|
+
moment: import_moment.default
|
|
1408
1473
|
};
|
|
1409
1474
|
let result = "";
|
|
1410
|
-
ejs.renderFile(templatePath,
|
|
1475
|
+
ejs.renderFile(templatePath, templateData, (err, html) => {
|
|
1411
1476
|
if (err)
|
|
1412
1477
|
throw err;
|
|
1413
1478
|
else
|
|
@@ -1417,380 +1482,7 @@ function newGenMatchImageHTML(match, template = "match_1") {
|
|
|
1417
1482
|
import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.html", result);
|
|
1418
1483
|
return result;
|
|
1419
1484
|
}
|
|
1420
|
-
__name(
|
|
1421
|
-
function genHeroHTML(hero) {
|
|
1422
|
-
let $ = cheerio.load(import_fs2.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/hero.html`, "utf-8"));
|
|
1423
|
-
let html = `
|
|
1424
|
-
<div class="hero" id="${hero.id}">
|
|
1425
|
-
<img src="${getImageUrl(hero.shortName, "heroes" /* Heroes */)}" alt="" />
|
|
1426
|
-
<img class="pri_attr" src="${getImageUrl(primary_attrs[dotaconstants3.heroes[hero.id].primary_attr], "icons" /* Icons */)}" alt="" />
|
|
1427
|
-
<div class="info">
|
|
1428
|
-
<p class="name">${hero.language.displayName}</p>
|
|
1429
|
-
<p class="roles">
|
|
1430
|
-
${hero.roles.map((item) => `<span class="role level${item.level}">${roles[item.roleId]}</span>`).join("")}
|
|
1431
|
-
</p>
|
|
1432
|
-
<p class="attrs">
|
|
1433
|
-
<span class="str">${dotaconstants3.heroes[hero.id].base_str} <span class="gain">+${dotaconstants3.heroes[hero.id].str_gain.toFixed(1)}</span></span>
|
|
1434
|
-
<span class="agi">${dotaconstants3.heroes[hero.id].base_agi} <span class="gain">+${dotaconstants3.heroes[hero.id].agi_gain.toFixed(1)}</span></span>
|
|
1435
|
-
<span class="int">${dotaconstants3.heroes[hero.id].base_int} <span class="gain">+${dotaconstants3.heroes[hero.id].int_gain.toFixed(1)}</span></span>
|
|
1436
|
-
</p>
|
|
1437
|
-
</div>
|
|
1438
|
-
</div>
|
|
1439
|
-
<div class="details">
|
|
1440
|
-
<div class="hype_talents">
|
|
1441
|
-
<div class="hype">
|
|
1442
|
-
${hero.language.hype}
|
|
1443
|
-
</div>
|
|
1444
|
-
<div class="talents">
|
|
1445
|
-
<div class="talent">
|
|
1446
|
-
<div class="left">${hero.talents[7].name_cn}</div>
|
|
1447
|
-
<div class="level">25</div>
|
|
1448
|
-
<div class="right">${hero.talents[6].name_cn}</div>
|
|
1449
|
-
</div>
|
|
1450
|
-
<div class="talent">
|
|
1451
|
-
<div class="left">${hero.talents[5].name_cn}</div>
|
|
1452
|
-
<div class="level">20</div>
|
|
1453
|
-
<div class="right">${hero.talents[4].name_cn}</div>
|
|
1454
|
-
</div>
|
|
1455
|
-
<div class="talent">
|
|
1456
|
-
<div class="left">${hero.talents[3].name_cn}</div>
|
|
1457
|
-
<div class="level">15</div>
|
|
1458
|
-
<div class="right">${hero.talents[2].name_cn}</div>
|
|
1459
|
-
</div>
|
|
1460
|
-
<div class="talent">
|
|
1461
|
-
<div class="left">${hero.talents[1].name_cn}</div>
|
|
1462
|
-
<div class="level">10</div>
|
|
1463
|
-
<div class="right">${hero.talents[0].name_cn}</div>
|
|
1464
|
-
</div>
|
|
1465
|
-
</div>
|
|
1466
|
-
</div>
|
|
1467
|
-
<table class="list">
|
|
1468
|
-
<tbody>
|
|
1469
|
-
<tr>
|
|
1470
|
-
<td>初始生命值</td>
|
|
1471
|
-
<td>${dotaconstants3.heroes[hero.id].base_health + dotaconstants3.heroes[hero.id].base_str * 22}</td>
|
|
1472
|
-
</tr>
|
|
1473
|
-
<tr>
|
|
1474
|
-
<td>初始生命回复</td>
|
|
1475
|
-
<td>${dotaconstants3.heroes[hero.id].base_health_regen}</td>
|
|
1476
|
-
</tr>
|
|
1477
|
-
<tr>
|
|
1478
|
-
<td>初始魔法值</td>
|
|
1479
|
-
<td>${dotaconstants3.heroes[hero.id].base_mana + dotaconstants3.heroes[hero.id].base_int * 12}</td>
|
|
1480
|
-
</tr>
|
|
1481
|
-
<tr>
|
|
1482
|
-
<td>初始魔法回复</td>
|
|
1483
|
-
<td>${dotaconstants3.heroes[hero.id].base_mana_regen}</td>
|
|
1484
|
-
</tr>
|
|
1485
|
-
<tr>
|
|
1486
|
-
<td>初始攻击力</td>
|
|
1487
|
-
<td>${dotaconstants3.heroes[hero.id].base_mr + Math.round(
|
|
1488
|
-
dotaconstants3.heroes[hero.id].primary_attr == "all" ? (dotaconstants3.heroes[hero.id].base_str + dotaconstants3.heroes[hero.id].base_agi + dotaconstants3.heroes[hero.id].base_int) * 0.7 : dotaconstants3.heroes[hero.id]["base_" + dotaconstants3.heroes[hero.id].primary_attr]
|
|
1489
|
-
)}(${dotaconstants3.heroes[hero.id].base_attack_min + Math.round(
|
|
1490
|
-
dotaconstants3.heroes[hero.id].primary_attr == "all" ? (dotaconstants3.heroes[hero.id].base_str + dotaconstants3.heroes[hero.id].base_agi + dotaconstants3.heroes[hero.id].base_int) * 0.7 : dotaconstants3.heroes[hero.id]["base_" + dotaconstants3.heroes[hero.id].primary_attr]
|
|
1491
|
-
)}~${dotaconstants3.heroes[hero.id].base_attack_max + Math.round(
|
|
1492
|
-
dotaconstants3.heroes[hero.id].primary_attr == "all" ? (dotaconstants3.heroes[hero.id].base_str + dotaconstants3.heroes[hero.id].base_agi + dotaconstants3.heroes[hero.id].base_int) * 0.7 : dotaconstants3.heroes[hero.id]["base_" + dotaconstants3.heroes[hero.id].primary_attr]
|
|
1493
|
-
)})</td>
|
|
1494
|
-
</tr>
|
|
1495
|
-
<tr>
|
|
1496
|
-
<td>基础攻击间隔</td>
|
|
1497
|
-
<td>${dotaconstants3.heroes[hero.id].attack_rate.toFixed(1)}</td>
|
|
1498
|
-
</tr>
|
|
1499
|
-
<tr>
|
|
1500
|
-
<td>基础攻击前摇</td>
|
|
1501
|
-
<td>${dotaconstants3.heroes[hero.id].attack_point.toFixed(1)}</td>
|
|
1502
|
-
</tr>
|
|
1503
|
-
<tr>
|
|
1504
|
-
<td>攻击范围</td>
|
|
1505
|
-
<td>${dotaconstants3.heroes[hero.id].attack_range}</td>
|
|
1506
|
-
</tr>
|
|
1507
|
-
<tr>
|
|
1508
|
-
<td>护甲</td>
|
|
1509
|
-
<td>${(Math.round((dotaconstants3.heroes[hero.id].base_armor + dotaconstants3.heroes[hero.id].base_agi * 0.167) * 10) / 10).toFixed(1)}</td>
|
|
1510
|
-
</tr>
|
|
1511
|
-
<tr>
|
|
1512
|
-
<td>移动速度</td>
|
|
1513
|
-
<td>${dotaconstants3.heroes[hero.id].move_speed}</td>
|
|
1514
|
-
</tr>
|
|
1515
|
-
<tr>
|
|
1516
|
-
<td>视野范围</td>
|
|
1517
|
-
<td>${dotaconstants3.heroes[hero.id].day_vision}(${dotaconstants3.heroes[hero.id].night_vision})</td>
|
|
1518
|
-
</tr>
|
|
1519
|
-
</tbody>
|
|
1520
|
-
</table>
|
|
1521
|
-
</div>
|
|
1522
|
-
<div class="skills">
|
|
1523
|
-
${hero.abilities.filter((item) => dotaconstants3.abilities[item.ability.name].behavior != "Hidden").map(
|
|
1524
|
-
(item) => `
|
|
1525
|
-
<div class="skill">
|
|
1526
|
-
<p class="title">${item.ability.language.displayName}</p>
|
|
1527
|
-
${item.ability.stat.isGrantedByScepter ? `<svg class="scepter" viewBox="0 0 19 20" fill="hsla(0,0%,100%,0.16)" width="24"><path d="M4.795 14.99a2.06 2.06 0 00-.96-.388c-1.668-.204-2.506.518-3.107 1.008.464.128.879.364.867.97 2.347-1.605 4.159.84 2.415 2.666-.14.147.65.929.767.718.203-.365.79-1.064 1.445-1.064.964 0 1.529.68 1.823.838.267.144.793-.372.642-.675-.03-.06-.229-.204-.569-.438-1.407-.197-1.935-1.093-2.37-2.026-.276-.593-.503-1.206-.953-1.61zm9.41 0a2.06 2.06 0 01.96-.388c1.668-.204 2.507.518 3.107 1.008-.464.128-.879.364-.867.97-2.347-1.605-4.158.84-2.415 2.666.14.147-.65.929-.768.718-.202-.365-.79-1.064-1.444-1.064-.965 0-1.529.68-1.823.838-.267.144-.793-.372-.642-.675.03-.06.229-.204.569-.438 1.407-.197 1.935-1.093 2.37-2.026.276-.593.503-1.206.953-1.61zm-3.919-2.211c0-.233-.175-.423-.392-.423h-.788c-.217 0-.392.19-.392.423v5.665c0 .232.175.421.392.421h.788c.216 0 .392-.189.392-.421v-5.665zm-1.989 2.543c-.553-.139-2.074-.563-2.702-1.17-.814-.784-1.107-3.135-2.655-3.52-1.29-.32-2.448.27-2.924 1.05-.06.101.055.241.252.178 2.786-.884 2.957 1.674 2.672 2.215a.275.275 0 00-.024.057c.87-.106 1.462.043 1.893.328.447.294.732.738.975 1.231.515 1.042.822 2.335 2.513 2.512v-2.88zm2.406 0c.553-.139 2.074-.563 2.703-1.17.812-.784 1.106-3.135 2.654-3.52 1.29-.32 2.448.27 2.924 1.05.06.101-.055.241-.252.178-2.786-.884-2.957 1.674-2.672 2.215a.27.27 0 01.024.057c-.87-.106-1.462.043-1.893.328-.447.294-.732.738-.975 1.231-.515 1.042-.822 2.335-2.513 2.512v-2.88z" fill="hsla(0,0%,100%,0.6)"></path><path d="M9.753.093a.39.39 0 00-.506 0C8.461.747 6.08 2.946 5.515 3.417a.434.434 0 00-.15.262c-.162.895-.949 4.817-1.12 5.764a.46.46 0 00.067.333c.37.564 1.665 2.752 2.071 3.37a.404.404 0 00.336.187h.768c.19 0 .356-.14.4-.337l.35-1.577a.416.416 0 01.399-.336h1.728c.19 0 .356.139.399.336l.35 1.577a.416.416 0 00.4.337h.768c.133 0 .259-.07.336-.187.406-.618 1.7-2.806 2.07-3.37a.457.457 0 00.067-.333c-.17-.947-.957-4.87-1.118-5.764a.435.435 0 00-.15-.262C12.92 2.946 10.537.747 9.752.093z" fill="url(#activeAghanimScepterGradient)"></path><defs><radialGradient id="activeAghanimScepterGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(9.03623 10.4684) rotate(-90) scale(9.38905 7.0456)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient></defs></svg>` : ""}
|
|
1528
|
-
${item.ability.stat.isGrantedByShard ? `<svg class="shard" viewBox="0 0 19 10" fill="hsla(0,0%,100%,0.16)" width="24"><path d="M0.259504 4.54746C0.272981 4.60325 0.326002 4.64198 0.386194 4.64198C0.831857 4.62418 2.60461 4.45628 3.91732 2.90727C4.49956 2.22054 4.37916 1.21884 3.64777 0.671532C2.91819 0.125197 1.85256 0.238284 1.27032 0.924899C-0.0423919 2.47305 0.17864 4.13525 0.259504 4.54746Z" fill="url(#activeAghanimLeftShardGradient)"></path><path d="M9.46713 9.98081C9.42698 10.0064 9.37572 10.0064 9.33559 9.98081C8.88968 9.67166 6.33212 7.75166 6.33212 4.38581C6.33212 2.96661 7.70742 1.81406 9.40136 1.81406C11.0953 1.81406 12.4706 2.96661 12.4706 4.38581C12.4706 7.75166 9.91303 9.67166 9.46713 9.98081Z" fill="url(#activeAghanimMidShardGradient)"></path><path d="M18.6888 4.54746C18.6753 4.60325 18.6232 4.64198 18.5631 4.64198C18.1173 4.62418 16.3445 4.45628 15.0317 2.90727C14.4494 2.22054 14.5697 1.21884 15.3003 0.671532C16.0308 0.125197 17.0966 0.238284 17.6788 0.924899C18.9917 2.47305 18.7707 4.13525 18.6888 4.54746Z" fill="url(#activeAghanimRightShardGradient)"></path><defs><radialGradient id="activeAghanimMidShardGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(9.01787 2.49983) rotate(90) scale(7.50029 5.21143)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient><radialGradient id="activeAghanimLeftShardGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(3.98746 0.625367) rotate(128.66) scale(6.00315 4.79432)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient><radialGradient id="activeAghanimRightShardGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(14.2996 0.625367) rotate(51.3402) scale(6.00316 4.7942)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient></defs></svg>` : ""}
|
|
1529
|
-
<div class="img_stats">
|
|
1530
|
-
<img src="${getImageUrl(item.ability.name, "abilities" /* Abilities */)}" alt="" />
|
|
1531
|
-
<div class="stats">
|
|
1532
|
-
<p class="behavior">技能:${(Array.isArray(dotaconstants3.abilities[item.ability.name].behavior) ? dotaconstants3.abilities[item.ability.name].behavior : [dotaconstants3.abilities[item.ability.name].behavior]).filter((beh) => beh !== "Hidden" || !(item.ability.stat.isGrantedByShard || item.ability.stat.isGrantedByScepter)).map((beh) => behavior[beh]).join("/")}</p>
|
|
1533
|
-
${dotaconstants3.abilities[item.ability.name].target_team ? `<p class="target_team">影响:${(Array.isArray(dotaconstants3.abilities[item.ability.name].target_team) ? dotaconstants3.abilities[item.ability.name].target_team : [dotaconstants3.abilities[item.ability.name].target_team]).map((tt) => target_team[tt]).join("/")}</p>` : ""}
|
|
1534
|
-
${!Array.isArray(dotaconstants3.abilities[item.ability.name].dmg_type) && dotaconstants3.abilities[item.ability.name].dmg_type ? `<p class="dmg_type ${dotaconstants3.abilities[item.ability.name].dmg_type}">伤害类型:</p>` : ""}
|
|
1535
|
-
${dotaconstants3.abilities[item.ability.name].dispellable ? `<p class="dispellable ${dotaconstants3.abilities[item.ability.name].dispellable == "Strong Dispels Only" ? "Strong" : dotaconstants3.abilities[item.ability.name].dispellable}">能否驱散:</p>` : ""}
|
|
1536
|
-
${!Array.isArray(dotaconstants3.abilities[item.ability.name].bkbpierce) && dotaconstants3.abilities[item.ability.name].bkbpierce ? `<p class="bkbpierce">无视减益免疫: ${dotaconstants3.abilities[item.ability.name].bkbpierce == "Yes" ? "是" : "否"}</p>` : ""}
|
|
1537
|
-
</div>
|
|
1538
|
-
</div>
|
|
1539
|
-
${item.ability.language.description.map((desc) => `<p class="description">${desc}</p>`).join("")}
|
|
1540
|
-
${item.ability.language.aghanimDescription ? `<p class="aghanim_description"><span class="title"><svg viewBox="0 0 19 20" fill="hsla(0,0%,100%,0.16)" width="24"><path d="M4.795 14.99a2.06 2.06 0 00-.96-.388c-1.668-.204-2.506.518-3.107 1.008.464.128.879.364.867.97 2.347-1.605 4.159.84 2.415 2.666-.14.147.65.929.767.718.203-.365.79-1.064 1.445-1.064.964 0 1.529.68 1.823.838.267.144.793-.372.642-.675-.03-.06-.229-.204-.569-.438-1.407-.197-1.935-1.093-2.37-2.026-.276-.593-.503-1.206-.953-1.61zm9.41 0a2.06 2.06 0 01.96-.388c1.668-.204 2.507.518 3.107 1.008-.464.128-.879.364-.867.97-2.347-1.605-4.158.84-2.415 2.666.14.147-.65.929-.768.718-.202-.365-.79-1.064-1.444-1.064-.965 0-1.529.68-1.823.838-.267.144-.793-.372-.642-.675.03-.06.229-.204.569-.438 1.407-.197 1.935-1.093 2.37-2.026.276-.593.503-1.206.953-1.61zm-3.919-2.211c0-.233-.175-.423-.392-.423h-.788c-.217 0-.392.19-.392.423v5.665c0 .232.175.421.392.421h.788c.216 0 .392-.189.392-.421v-5.665zm-1.989 2.543c-.553-.139-2.074-.563-2.702-1.17-.814-.784-1.107-3.135-2.655-3.52-1.29-.32-2.448.27-2.924 1.05-.06.101.055.241.252.178 2.786-.884 2.957 1.674 2.672 2.215a.275.275 0 00-.024.057c.87-.106 1.462.043 1.893.328.447.294.732.738.975 1.231.515 1.042.822 2.335 2.513 2.512v-2.88zm2.406 0c.553-.139 2.074-.563 2.703-1.17.812-.784 1.106-3.135 2.654-3.52 1.29-.32 2.448.27 2.924 1.05.06.101-.055.241-.252.178-2.786-.884-2.957 1.674-2.672 2.215a.27.27 0 01.024.057c-.87-.106-1.462.043-1.893.328-.447.294-.732.738-.975 1.231-.515 1.042-.822 2.335-2.513 2.512v-2.88z" fill="hsla(0,0%,100%,0.6)"></path><path d="M9.753.093a.39.39 0 00-.506 0C8.461.747 6.08 2.946 5.515 3.417a.434.434 0 00-.15.262c-.162.895-.949 4.817-1.12 5.764a.46.46 0 00.067.333c.37.564 1.665 2.752 2.071 3.37a.404.404 0 00.336.187h.768c.19 0 .356-.14.4-.337l.35-1.577a.416.416 0 01.399-.336h1.728c.19 0 .356.139.399.336l.35 1.577a.416.416 0 00.4.337h.768c.133 0 .259-.07.336-.187.406-.618 1.7-2.806 2.07-3.37a.457.457 0 00.067-.333c-.17-.947-.957-4.87-1.118-5.764a.435.435 0 00-.15-.262C12.92 2.946 10.537.747 9.752.093z" fill="url(#activeAghanimScepterGradient)"></path><defs><radialGradient id="activeAghanimScepterGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(9.03623 10.4684) rotate(-90) scale(9.38905 7.0456)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient></defs></svg>
|
|
1541
|
-
阿哈利姆神杖</span><span class="desc">${item.ability.language.aghanimDescription}</span></p>` : ""}
|
|
1542
|
-
${item.ability.language.shardDescription ? `<p class="aghanim_description"><span class="title"><svg viewBox="0 0 19 10" fill="hsla(0,0%,100%,0.16)" width="24"><path d="M0.259504 4.54746C0.272981 4.60325 0.326002 4.64198 0.386194 4.64198C0.831857 4.62418 2.60461 4.45628 3.91732 2.90727C4.49956 2.22054 4.37916 1.21884 3.64777 0.671532C2.91819 0.125197 1.85256 0.238284 1.27032 0.924899C-0.0423919 2.47305 0.17864 4.13525 0.259504 4.54746Z" fill="url(#activeAghanimLeftShardGradient)"></path><path d="M9.46713 9.98081C9.42698 10.0064 9.37572 10.0064 9.33559 9.98081C8.88968 9.67166 6.33212 7.75166 6.33212 4.38581C6.33212 2.96661 7.70742 1.81406 9.40136 1.81406C11.0953 1.81406 12.4706 2.96661 12.4706 4.38581C12.4706 7.75166 9.91303 9.67166 9.46713 9.98081Z" fill="url(#activeAghanimMidShardGradient)"></path><path d="M18.6888 4.54746C18.6753 4.60325 18.6232 4.64198 18.5631 4.64198C18.1173 4.62418 16.3445 4.45628 15.0317 2.90727C14.4494 2.22054 14.5697 1.21884 15.3003 0.671532C16.0308 0.125197 17.0966 0.238284 17.6788 0.924899C18.9917 2.47305 18.7707 4.13525 18.6888 4.54746Z" fill="url(#activeAghanimRightShardGradient)"></path><defs><radialGradient id="activeAghanimMidShardGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(9.01787 2.49983) rotate(90) scale(7.50029 5.21143)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient><radialGradient id="activeAghanimLeftShardGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(3.98746 0.625367) rotate(128.66) scale(6.00315 4.79432)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient><radialGradient id="activeAghanimRightShardGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(14.2996 0.625367) rotate(51.3402) scale(6.00316 4.7942)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient></defs></svg>
|
|
1543
|
-
阿哈利姆魔晶</span><span class="desc">${item.ability.language.shardDescription}</span></p>` : ""}
|
|
1544
|
-
<div class="notes"${!item.ability.language.notes.length ? ` style="display:none;"` : ""}>
|
|
1545
|
-
${item.ability.language.notes.map((note) => `<p>${note}</p>`).join("")}
|
|
1546
|
-
</div>
|
|
1547
|
-
<div class="attributes">
|
|
1548
|
-
${item.ability.language.attributes.map((attr) => {
|
|
1549
|
-
const parts = attr.split(":");
|
|
1550
|
-
return `<p><span class="item">${parts[0]}</span><span class="values">${parts[1]}</span></p>`;
|
|
1551
|
-
}).join("")}
|
|
1552
|
-
</div>
|
|
1553
|
-
<p>
|
|
1554
|
-
${dotaconstants3.abilities[item.ability.name].cd ? `<span class="cooldown"> ${(Array.isArray(dotaconstants3.abilities[item.ability.name].cd) ? dotaconstants3.abilities[item.ability.name].cd : [dotaconstants3.abilities[item.ability.name].cd]).join(
|
|
1555
|
-
" / "
|
|
1556
|
-
)} </span>` : ""}
|
|
1557
|
-
${dotaconstants3.abilities[item.ability.name].mc ? `<span class="mana_cost"> ${(Array.isArray(dotaconstants3.abilities[item.ability.name].mc) ? dotaconstants3.abilities[item.ability.name].mc : [dotaconstants3.abilities[item.ability.name].mc]).join(
|
|
1558
|
-
" / "
|
|
1559
|
-
)} </span>` : ""}
|
|
1560
|
-
</p>
|
|
1561
|
-
<p class="lore"${!item.ability.language.lore ? ` style="display:none;"` : ""}>${item.ability.language.lore}</p>
|
|
1562
|
-
</div>
|
|
1563
|
-
`
|
|
1564
|
-
).join("")}
|
|
1565
|
-
</div>
|
|
1566
|
-
<div class="lore">
|
|
1567
|
-
${hero.language.lore}
|
|
1568
|
-
</div>
|
|
1569
|
-
`;
|
|
1570
|
-
$(".wrapper").html(html);
|
|
1571
|
-
if (process.env.NODE_ENV === "development")
|
|
1572
|
-
import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.html", $.html());
|
|
1573
|
-
return $.html();
|
|
1574
|
-
}
|
|
1575
|
-
__name(genHeroHTML, "genHeroHTML");
|
|
1576
|
-
function genPlayerHTML(player) {
|
|
1577
|
-
let $ = cheerio.load(import_fs2.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/player.html`, "utf-8"));
|
|
1578
|
-
const guildLevel = /* @__PURE__ */ __name((percent) => {
|
|
1579
|
-
if (percent <= 25) {
|
|
1580
|
-
return "Copper";
|
|
1581
|
-
} else if (percent <= 50) {
|
|
1582
|
-
return "Silver";
|
|
1583
|
-
} else if (percent <= 75) {
|
|
1584
|
-
return "Gold";
|
|
1585
|
-
} else {
|
|
1586
|
-
return "Diamond";
|
|
1587
|
-
}
|
|
1588
|
-
}, "guildLevel");
|
|
1589
|
-
const laneSVG = {
|
|
1590
|
-
stomp: `<svg viewBox="0 0 24 24" class="hitagi__sc-1apuy4g-0 hmhZOG"><path d="M8.05731 22.3674L9.60454 22.8002L11.5974 21.6551L12.043 20.0773L13.5902 20.51L15.583 19.3649L16.0287 17.7871L17.5759 18.2199L19.5687 17.0748L20.0143 15.4969L21.5615 15.9297L23.5544 14.7846L24 13.2068L23.4492 12.2014L7.50651 21.3621L8.05731 22.3674ZM12.1328 3.50265L11.0312 1.49196C10.8798 1.21549 10.5316 1.11811 10.2576 1.27556L0.29345 7.00098C0.0194354 7.15843 -0.0808273 7.51346 0.0706444 7.78993L1.44766 10.3033L11.91 4.29159C12.184 4.13414 12.2843 3.77912 12.1328 3.50265ZM18.3935 8.4063L14.1658 9.60458L12.4221 10.6065C12.2851 10.6853 12.111 10.6366 12.0353 10.4983L11.7599 9.99565C11.6842 9.85742 11.7343 9.6799 11.8713 9.60118L13.615 8.59924L13.0642 7.59389L11.3205 8.59584C11.1835 8.67456 11.0094 8.62587 10.9337 8.48765L10.6583 7.98497C10.5826 7.84673 10.6327 7.66922 10.7697 7.5905L12.5134 6.58855L11.9626 5.58321L1.99846 11.3086L6.9557 20.3567L22.8984 11.196L22.2615 10.0336C21.5024 8.64813 19.9073 7.97847 18.3935 8.4063Z"></path></svg>`,
|
|
1591
|
-
victory: `<svg viewBox="0 0 512 512"><path d="M198.844 64.75c-.985 0-1.974.03-2.97.094-15.915 1.015-32.046 11.534-37.78 26.937-34.072 91.532-51.085 128.865-61.5 222.876 14.633 13.49 31.63 26.45 50.25 38.125l66.406-196.467 17.688 5.968L163.28 362.5c19.51 10.877 40.43 20.234 62 27.28l75.407-201.53 17.5 6.53-74.937 200.282c19.454 5.096 39.205 8.2 58.78 8.875L381.345 225.5l17.094 7.594-75.875 170.656c21.82-1.237 43.205-5.768 63.437-14.28 43.317-53.844 72.633-109.784 84.5-172.69 5.092-26.992-14.762-53.124-54.22-54.81l-6.155-.282-2.188-5.75c-8.45-22.388-19.75-30.093-31.5-32.47-11.75-2.376-25.267 1.535-35.468 7.376l-13.064 7.47-.906-15c-.99-16.396-10.343-29.597-24.313-35.626-13.97-6.03-33.064-5.232-54.812 9.906l-10.438 7.25-3.812-12.125c-6.517-20.766-20.007-27.985-34.78-27.97zM103.28 188.344C71.143 233.448 47.728 299.56 51.407 359.656c27.54 21.84 54.61 33.693 80.063 35.438 14.155.97 27.94-1.085 41.405-6.438-35.445-17.235-67.36-39.533-92.594-63.53l-3.343-3.157.5-4.595c5.794-54.638 13.946-91.5 25.844-129.03z"/></svg>`,
|
|
1592
|
-
fail: `<svg viewBox="0 0 36 36"><path fill="#ff6961" d="M36 32a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4h28a4 4 0 0 1 4 4v28z"></path><circle fill="#FFF" cx="27" cy="7" r="3"></circle><path fill="#FFF" d="M13.06 13.06l2.367-2.366l3.859 1.158l-2.635 2.847a10.018 10.018 0 0 1 4.392 3.379l5.017-5.017a1.5 1.5 0 0 0-.63-2.497l-9.999-3a1.495 1.495 0 0 0-1.492.376l-3 3a1.5 1.5 0 1 0 2.121 2.12zm16.065 4.949a1.496 1.496 0 0 0-1.262-.503l-6.786.617a9.966 9.966 0 0 1 1.464 2.879l3.548-.322l-1.554 6.995a1.499 1.499 0 1 0 2.928.65l2-9a1.5 1.5 0 0 0-.338-1.316zM13 16a8 8 0 1 0 0 16a8 8 0 0 0 0-16zm0 14a6 6 0 1 1 .002-12.002A6 6 0 0 1 13 30z"></path></svg>`,
|
|
1593
|
-
stomped: `<svg viewBox="-1 0 19 19"><path d="M16.417 9.579A7.917 7.917 0 1 1 8.5 1.662a7.917 7.917 0 0 1 7.917 7.917zm-2.458 2.96a.396.396 0 0 0-.396-.397h-.667a1.527 1.527 0 0 0-1.249-1.114.777.777 0 0 0 .014-.145V9.378a.794.794 0 0 0-.792-.792H8.201a2.984 2.984 0 0 0-1.682-.516l-.11.002V7.42h2.997a.396.396 0 1 0 0-.792H6.41v-1.3a.396.396 0 0 0-.396-.397H4.891a.396.396 0 0 0 0 .792h.727V8.21a2.997 2.997 0 1 0 3.836 3.466h.71a1.526 1.526 0 1 0 2.732 1.26h.667a.396.396 0 0 0 .396-.397zM8.078 9.507a2.205 2.205 0 1 1-1.559-.646 2.19 2.19 0 0 1 1.559.646zm4.078 3.03a.734.734 0 1 1-.733-.734.735.735 0 0 1 .733.733z"/></svg>`,
|
|
1594
|
-
tie: `<svg fill="#fff" viewBox="0 0 512.001 512.001"><g><g><path d="M120.988,239.868c-4.496,10.625-5.122,20.183-5.157,20.811c-0.267,4.607,3.243,8.547,7.849,8.829 c4.618,0.29,8.574-3.228,8.873-7.833c0.265-4.771,2.339-13.092,5.884-19.44C137.421,242.113,141.397,242.649,120.988,239.868z"/></g></g><g><g><path d="M391.178,255.418c-0.211,8.054-2.458,17.62-6.74,28.398c-1.708,4.299,0.393,9.168,4.692,10.875 c4.293,1.708,9.167-0.39,10.875-4.692c5.103-12.842,7.74-24.392,7.943-34.581H391.178z"/></g></g><g><g><path d="M164.769,210.51c1.046,3.339,1.397,6.953,0.893,10.65c-0.293,2.146-0.857,4.188-1.648,6.1c0,0,51.266,3.416,198.065,3.949 c-0.086-6.331,2.19-12.199,6.244-16.732C217.627,214.046,164.769,210.51,164.769,210.51z"/></g></g><g><g><circle cx="37.179" cy="128.669" r="29.491"/></g></g><g><g><path d="M510.146,391.511l-37.916-66.985c14.35-49.173,20.678-68.137,20.678-68.137l8.949-67.014 c1.502-10.977-6.248-21.075-17.235-22.468l-18.183-2.305c-10.984-1.393-20.996,6.445-22.293,17.431l-1.884,15.955l28.718-21.317 l-37.91,42.278h-46.432c-6.571,0-11.898,5.328-11.898,11.898c0,6.57,5.328,11.898,11.898,11.898h51.744 c3.381,0,6.601-1.438,8.859-3.956l41.456-46.234l-32.023,54.694c-5.28,9.018-14.374,8.169-18.293,8.167c-1.959,0-3.31,0-5.295,0 c-0.399,0.898,3.152-7.399-24.44,57.181c-0.548,1.284-0.907,2.642-1.06,4.031l-8.934,80.338 c-0.939,8.447,5.667,15.857,14.208,15.857c7.179,0,13.361-5.401,14.172-12.701l8.702-78.244l21.512-50.353l-14.121,50.463 c-1.158,3.756-0.718,7.823,1.218,11.243l40.949,72.345c3.885,6.864,12.596,9.276,19.459,5.392 C511.615,407.085,514.03,398.373,510.146,391.511z"/></g></g><g><g><circle cx="464.865" cy="128.702" r="29.491"/></g></g><g><g><path d="M142.923,206.051l-59.556-8.118l-39.135-18.451l13.626,2.292c-1.422-10.945-11.411-18.577-22.254-17.202l-18.182,2.305 C6.43,168.271-1.315,178.374,0.186,189.345l9.12,68.689l21.865,70.857l5.829,70.795c0.646,7.848,7.527,13.705,15.401,13.057 c7.859-0.647,13.705-7.542,13.058-15.401l-5.956-72.345c-0.084-1.031-0.281-2.05-0.585-3.039l-14.123-50.463l21.514,50.353 l8.702,78.244c0.873,7.86,7.96,13.486,15.768,12.612c7.838-0.871,13.483-7.931,12.612-15.768l-8.934-80.338 c-0.154-1.388-0.511-2.747-1.06-4.032l-27.336-61.43l-2.945-24.951l-29.029-25.179l40.79,19.231 c1.097,0.517,2.266,0.862,3.468,1.027l61.369,8.365c6.521,0.887,12.509-3.68,13.396-10.183 C153.994,212.936,149.435,206.939,142.923,206.051z"/></g></g></svg>`
|
|
1595
|
-
};
|
|
1596
|
-
const outcomeCounts = {
|
|
1597
|
-
victory: 0,
|
|
1598
|
-
stomp: 0,
|
|
1599
|
-
fail: 0,
|
|
1600
|
-
stomped: 0,
|
|
1601
|
-
tie: 0
|
|
1602
|
-
};
|
|
1603
|
-
const processLaneOutcome = /* @__PURE__ */ __name((outcome) => {
|
|
1604
|
-
switch (outcome) {
|
|
1605
|
-
case "RADIANT_VICTORY":
|
|
1606
|
-
return { radiant: "victory", dire: "fail" };
|
|
1607
|
-
case "RADIANT_STOMP":
|
|
1608
|
-
return { radiant: "stomp", dire: "stomped" };
|
|
1609
|
-
case "DIRE_VICTORY":
|
|
1610
|
-
return { radiant: "fail", dire: "victory" };
|
|
1611
|
-
case "DIRE_STOMP":
|
|
1612
|
-
return { radiant: "stomped", dire: "stomp" };
|
|
1613
|
-
default:
|
|
1614
|
-
return { radiant: "tie", dire: "tie" };
|
|
1615
|
-
}
|
|
1616
|
-
}, "processLaneOutcome");
|
|
1617
|
-
let nearMatchCount = 25, nearWinCount = 0, streak = 0;
|
|
1618
|
-
player.matches.forEach((match) => {
|
|
1619
|
-
const innerPlayer = match.players[0];
|
|
1620
|
-
nearWinCount += match.didRadiantWin == innerPlayer.isRadiant ? 1 : 0;
|
|
1621
|
-
const didWin = match.didRadiantWin === innerPlayer.isRadiant;
|
|
1622
|
-
if (!player.streak) {
|
|
1623
|
-
if (streak != 0) {
|
|
1624
|
-
if (didWin && streak > 0)
|
|
1625
|
-
streak++;
|
|
1626
|
-
else if (!didWin && streak < 0)
|
|
1627
|
-
streak--;
|
|
1628
|
-
else
|
|
1629
|
-
player.streak = streak;
|
|
1630
|
-
} else
|
|
1631
|
-
streak = didWin ? 1 : -1;
|
|
1632
|
-
}
|
|
1633
|
-
const laneResult = {
|
|
1634
|
-
top: processLaneOutcome(match.topLaneOutcome),
|
|
1635
|
-
mid: processLaneOutcome(match.midLaneOutcome),
|
|
1636
|
-
bottom: processLaneOutcome(match.bottomLaneOutcome)
|
|
1637
|
-
};
|
|
1638
|
-
let laneKey = "mid";
|
|
1639
|
-
if (innerPlayer.lane === "SAFE_LANE") {
|
|
1640
|
-
laneKey = innerPlayer.isRadiant ? "bottom" : "top";
|
|
1641
|
-
} else if (innerPlayer.lane === "OFF_LANE") {
|
|
1642
|
-
laneKey = innerPlayer.isRadiant ? "top" : "bottom";
|
|
1643
|
-
}
|
|
1644
|
-
match.laneResult = laneResult[laneKey][innerPlayer.isRadiant ? "radiant" : "dire"];
|
|
1645
|
-
if (match.laneResult in outcomeCounts) {
|
|
1646
|
-
outcomeCounts[match.laneResult]++;
|
|
1647
|
-
}
|
|
1648
|
-
});
|
|
1649
|
-
const playerHTML = `
|
|
1650
|
-
<div class="avatar"><img src="${player.steamAccount.avatar}" alt="" /></div>
|
|
1651
|
-
<div class="info">
|
|
1652
|
-
<p class="name">${player.steamAccount.name}${player.guildMember ? ` <span class="guild ${guildLevel(player.guildMember.guild.currentPercentile)}">[${player.guildMember.guild.tag}]</span></p>` : ""}
|
|
1653
|
-
<p class="matches"><span>场次:${player.matchCount}(<span class="win">${player.winCount}</span>/<span class="lose">${player.matchCount - player.winCount}</span>)</span>胜率:<span style="color:${winRateColor(
|
|
1654
|
-
player.winCount / player.matchCount
|
|
1655
|
-
)};">${(player.winCount / player.matchCount * 100).toFixed(2)}%</span></p>
|
|
1656
|
-
<p class="matches"><span>最近25场:<span class="win">${nearWinCount}</span>/<span class="lose">${nearMatchCount - nearWinCount}</span></span><span>胜率:<span style="color:${winRateColor(nearWinCount / nearMatchCount)};">${(nearWinCount / nearMatchCount * 100).toFixed(2)}%</span></span><span>评分:${player.performance.imp}</span></span></p>
|
|
1657
|
-
<p class="matches"><span>对线:<span class="victory">${outcomeCounts.victory + outcomeCounts.stomp}(<span class="stomp">${outcomeCounts.stomp}</span>)</span>-<span class="tie">${outcomeCounts.tie}</span>-<span class="fail">${outcomeCounts.fail + outcomeCounts.stomped}(<span class="stomped">${outcomeCounts.stomped}</span>)</span></span><span>线优:<span style="color:${winRateColor(
|
|
1658
|
-
(outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.tie / 2) / (outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.tie + outcomeCounts.fail + outcomeCounts.stomped)
|
|
1659
|
-
)};">${((outcomeCounts.victory + outcomeCounts.stomp) / (outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.fail + outcomeCounts.stomped) * 100).toFixed(2)}%</span></span></p>
|
|
1660
|
-
</div>
|
|
1661
|
-
<div class="rank">
|
|
1662
|
-
<img class="medal" src="${getImageUrl(
|
|
1663
|
-
"medal_" + ((player.steamAccount.seasonLeaderboardRank ? player.steamAccount.seasonLeaderboardRank <= 100 ? player.steamAccount.seasonLeaderboardRank <= 10 ? "8c" : "8b" : player.steamAccount.seasonRank?.toString().split("")[0] : player.steamAccount.seasonRank?.toString().split("")[0]) ?? "0")
|
|
1664
|
-
)}" alt="" />
|
|
1665
|
-
<img class="star" src="${getImageUrl("star_" + (player.steamAccount.seasonRank?.toString().split("")[1] ?? "0"))}" alt="" />
|
|
1666
|
-
<p>${player.steamAccount.seasonLeaderboardRank ?? ""}</p>
|
|
1667
|
-
</div>`;
|
|
1668
|
-
const heroesCountPixels = 800 - ($(".tip:not(.row):not(.win_count):not(.lose_count)").length + 1) * 40;
|
|
1669
|
-
const highestCountsTotal = {
|
|
1670
|
-
winCount: Math.max(...player.heroesPerformanceTop10.map((hero) => hero.winCount)),
|
|
1671
|
-
loseCount: Math.max(...player.heroesPerformanceTop10.map((hero) => hero.matchCount - hero.winCount))
|
|
1672
|
-
};
|
|
1673
|
-
const pixelOfPerMatchInTotal = heroesCountPixels / (highestCountsTotal.winCount + highestCountsTotal.loseCount);
|
|
1674
|
-
const highestCountsNear = {
|
|
1675
|
-
winCount: Math.max(...player.heroesPerformance?.filter((hero) => hero.matchCount > 1)?.map((hero) => hero.winCount)),
|
|
1676
|
-
loseCount: Math.max(...player.heroesPerformance?.filter((hero) => hero.matchCount > 1)?.map((hero) => hero.matchCount - hero.winCount))
|
|
1677
|
-
};
|
|
1678
|
-
const nearAdjustmentFactor = Math.min(highestCountsTotal.winCount / (highestCountsTotal.winCount + highestCountsTotal.loseCount), highestCountsTotal.loseCount / (highestCountsTotal.winCount + highestCountsTotal.loseCount));
|
|
1679
|
-
const pixelOfPerMatchInNear = heroesCountPixels / (highestCountsNear?.winCount + highestCountsNear?.loseCount) * nearAdjustmentFactor;
|
|
1680
|
-
const heroesTotalHTML = player.heroesPerformanceTop10.map(
|
|
1681
|
-
(hero) => `
|
|
1682
|
-
<span><img alt="" src="${getImageUrl(hero.hero.shortName, "heroes/icons" /* HeroIcons */)}" /></span>
|
|
1683
|
-
<span class="count">${hero.matchCount}</span>
|
|
1684
|
-
<span class="win_rate">${(hero.winCount / hero.matchCount * 100).toFixed(0)}%</span>
|
|
1685
|
-
<span class="imp">${(hero.imp > 0 ? "+" : "") + hero.imp}</span>
|
|
1686
|
-
<span class="win" style="${hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${hero.winCount * pixelOfPerMatchInTotal}px">${hero.winCount}</span>
|
|
1687
|
-
<span class="lose" style="${hero.matchCount - hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${(hero.matchCount - hero.winCount) * pixelOfPerMatchInTotal}px">${hero.matchCount - hero.winCount}</span>`
|
|
1688
|
-
).join("") + player.heroesPerformance.filter((hero) => hero.matchCount > 1).map(
|
|
1689
|
-
(hero, index) => `
|
|
1690
|
-
<span style="order:${index + 1};"><img alt="" src="${getImageUrl(hero.hero.shortName, "heroes/icons" /* HeroIcons */)}" /></span>
|
|
1691
|
-
<span style="order:${index + 1};" class="count">${hero.matchCount}</span>
|
|
1692
|
-
<span style="order:${index + 1};" class="win_rate">${(hero.winCount / hero.matchCount * 100).toFixed(0)}%</span>
|
|
1693
|
-
<span style="order:${index + 1};" class="imp">${(hero.imp > 0 ? "+" : "") + hero.imp}</span>
|
|
1694
|
-
<span class="win" style="order:${index + 1};${hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${hero.winCount * pixelOfPerMatchInNear}px">${hero.winCount}</span>
|
|
1695
|
-
<span class="lose" style="order:${index + 1};${hero.matchCount - hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${(hero.matchCount - hero.winCount) * pixelOfPerMatchInNear}px">${hero.matchCount - hero.winCount}</span>`
|
|
1696
|
-
).join("");
|
|
1697
|
-
const streakHTML = `<div class="streak" style="box-shadow:none;color:${winRateColor((player.streak + 10) / 20)};">${Math.abs(player.streak) + (player.streak > 0 ? "连胜" : "连败")}</div>`;
|
|
1698
|
-
const matchesHTML = player.matches.map(
|
|
1699
|
-
(match) => `
|
|
1700
|
-
<tr class="match ${match.didRadiantWin == match.players[0].isRadiant ? "win" : "lose"}">
|
|
1701
|
-
<td>${match.id}</td>
|
|
1702
|
-
<td>
|
|
1703
|
-
<p>${lobbyTypes[match.lobbyType] || match.lobbyType}</p>
|
|
1704
|
-
<p>${gameMode[match.gameMode] || match.gameMode}</p>
|
|
1705
|
-
</td>
|
|
1706
|
-
<td><img alt="" src="${getImageUrl(match.players[0].hero.shortName, "heroes/icons" /* HeroIcons */)}" /></td>
|
|
1707
|
-
<td style="line-height: 20px">
|
|
1708
|
-
<p>${((match.players[0].kills + match.players[0].assists) / Math.max(1, match.players[0].deaths)).toFixed(2)} (${((match.players[0].kills + match.players[0].assists) / (match.players[0].isRadiant ? match.radiantKills.reduce((acc, cva) => acc + cva, 0) : match.direKills.reduce((acc, cva) => acc + cva, 0)) * 100).toFixed(0)}%)</p>
|
|
1709
|
-
<p>${match.players[0].kills}/${match.players[0].deaths}/${match.players[0].assists}</p>
|
|
1710
|
-
</td>
|
|
1711
|
-
<td>
|
|
1712
|
-
<div class="player_lane ${match.laneResult}">${laneSVG[match.laneResult]}</div>
|
|
1713
|
-
</td>
|
|
1714
|
-
<td style="line-height: 20px">${(0, import_moment.default)(new Date(match.endDateTime * 1e3)).format("YYYY-MM-DD HH:mm:ss").slice(2)}</td>
|
|
1715
|
-
<td>${sec2time(match.durationSeconds)}</td>
|
|
1716
|
-
<td>${(match.players[0].imp > 0 ? "+" : "") + match.players[0].imp}</td>
|
|
1717
|
-
<td><img class="medal" src="${getImageUrl("medal_" + match.rank.toString().split("")[0])}" style="width: 100%" /></td>
|
|
1718
|
-
</tr>`
|
|
1719
|
-
).join("");
|
|
1720
|
-
const dotaPlusHTML = player.dotaPlus.map(
|
|
1721
|
-
(hero) => `
|
|
1722
|
-
<div class="hero">
|
|
1723
|
-
<img src="${getImageUrl(hero.shortName, "heroes" /* Heroes */)}" alt="" />
|
|
1724
|
-
<div class="level"><img src="${getImageUrl("hero_badge_" + Math.ceil((hero.level + 1) / 6))}" alt="" /><span>${hero.level}</span></div>
|
|
1725
|
-
<span>${(hero.winCount / hero.matchCount * 100).toFixed(2)}%</span>
|
|
1726
|
-
<span>${hero.matchCount}</span>
|
|
1727
|
-
</div>`
|
|
1728
|
-
).join("");
|
|
1729
|
-
$(".player").html(playerHTML);
|
|
1730
|
-
$(".heroes > span:not(.tip)").remove();
|
|
1731
|
-
$(".heroes .tip.near").before(heroesTotalHTML);
|
|
1732
|
-
if (player.streak > 1 || player.streak < -1)
|
|
1733
|
-
$(".streak").replaceWith(streakHTML);
|
|
1734
|
-
$(".matches tbody").html(matchesHTML);
|
|
1735
|
-
$(".plus").html(dotaPlusHTML);
|
|
1736
|
-
if (process.env.NODE_ENV === "development")
|
|
1737
|
-
import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.html", $.html());
|
|
1738
|
-
return $.html();
|
|
1739
|
-
}
|
|
1740
|
-
__name(genPlayerHTML, "genPlayerHTML");
|
|
1741
|
-
async function playerIsInvalid(steamAccountId) {
|
|
1742
|
-
try {
|
|
1743
|
-
let queryRes = await query(VERIFYING_PLAYER(steamAccountId));
|
|
1744
|
-
if (queryRes.status == 200) {
|
|
1745
|
-
if (queryRes.data.data.player.matchCount != null)
|
|
1746
|
-
return { isInvalid: true };
|
|
1747
|
-
else
|
|
1748
|
-
return { isInvalid: false, reason: "SteamID无效或无任何场次。" };
|
|
1749
|
-
}
|
|
1750
|
-
} catch (error) {
|
|
1751
|
-
console.error(error);
|
|
1752
|
-
return { isInvalid: false, reason: "网络状况不佳SteamID验证失败,请稍后重试。" };
|
|
1753
|
-
}
|
|
1754
|
-
}
|
|
1755
|
-
__name(playerIsInvalid, "playerIsInvalid");
|
|
1756
|
-
function sec2time(sec) {
|
|
1757
|
-
return sec ? (sec < 0 ? "-" : "") + Math.floor(Math.abs(sec) / 60) + ":" + ("00" + Math.abs(sec) % 60).slice(-2) : "--:--";
|
|
1758
|
-
}
|
|
1759
|
-
__name(sec2time, "sec2time");
|
|
1760
|
-
function winRateColor(value) {
|
|
1761
|
-
value = value * 100;
|
|
1762
|
-
value = Math.max(0, Math.min(100, value));
|
|
1763
|
-
let red, green, blue;
|
|
1764
|
-
if (value <= 50) {
|
|
1765
|
-
let scale = Math.round(255 * (value / 50));
|
|
1766
|
-
red = 255;
|
|
1767
|
-
green = scale;
|
|
1768
|
-
blue = scale;
|
|
1769
|
-
} else {
|
|
1770
|
-
let scale = Math.round(255 * ((value - 50) / 50));
|
|
1771
|
-
red = 255 - scale;
|
|
1772
|
-
green = 255;
|
|
1773
|
-
blue = 255 - scale;
|
|
1774
|
-
}
|
|
1775
|
-
const toHex = /* @__PURE__ */ __name((color) => color.toString(16).padStart(2, "0").toUpperCase(), "toHex");
|
|
1776
|
-
return `#${toHex(red)}${toHex(green)}${toHex(blue)}`;
|
|
1777
|
-
}
|
|
1778
|
-
__name(winRateColor, "winRateColor");
|
|
1779
|
-
function formatNumber(num) {
|
|
1780
|
-
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
1781
|
-
}
|
|
1782
|
-
__name(formatNumber, "formatNumber");
|
|
1783
|
-
function readDirectoryFilesSync(directoryPath) {
|
|
1784
|
-
try {
|
|
1785
|
-
const files = import_fs2.default.readdirSync(directoryPath);
|
|
1786
|
-
const fileNames = files.map((file) => import_path.default.basename(file, import_path.default.extname(file)));
|
|
1787
|
-
return fileNames;
|
|
1788
|
-
} catch (error) {
|
|
1789
|
-
console.error("Error reading directory:", error);
|
|
1790
|
-
return [];
|
|
1791
|
-
}
|
|
1792
|
-
}
|
|
1793
|
-
__name(readDirectoryFilesSync, "readDirectoryFilesSync");
|
|
1485
|
+
__name(genImageHTML, "genImageHTML");
|
|
1794
1486
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1795
1487
|
0 && (module.exports = {
|
|
1796
1488
|
Config,
|