@sjtdev/koishi-plugin-dota2tracker 2.2.2 → 2.3.0

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.
Files changed (106) hide show
  1. package/changelog.md +32 -0
  2. package/dist/index.js +1 -1
  3. package/lib/index.js +128 -94
  4. package/{queries → lib/queries}/MatchInfo.graphql +13 -0
  5. package/lib/templates/common/components/building_icons.ejs +20 -0
  6. package/lib/templates/common/styles/normalize.min.css +1 -0
  7. package/lib/templates/hero/hero_1.ejs +69 -0
  8. package/lib/templates/images/7.38_simple_minimap.png +0 -0
  9. package/lib/templates/item/item/recipe.ejs +9 -0
  10. package/lib/templates/item/item/style.css +1 -0
  11. package/lib/templates/item/item.ejs +52 -0
  12. package/lib/templates/item/itemlist.ejs +11 -0
  13. package/lib/templates/match/match_1/base.css +1 -0
  14. package/lib/templates/match/match_1/item.ejs +1 -0
  15. package/lib/templates/match/match_1/main.ejs +8 -0
  16. package/lib/templates/match/match_1/player.ejs +1 -0
  17. package/lib/templates/match/match_1/style.css +1 -0
  18. package/lib/templates/match/match_1.ejs +18 -0
  19. package/lib/templates/match/match_2/original.css +1 -0
  20. package/lib/templates/match/match_2/original.ejs +10 -0
  21. package/lib/templates/match/match_2+/charts.ejs +1 -0
  22. package/lib/templates/match/match_2+/extra.css +1 -0
  23. package/lib/templates/match/match_2+/lane_outcome.ejs +56 -0
  24. package/lib/templates/match/match_2+/map.ejs +160 -0
  25. package/lib/templates/match/match_2+.ejs +1 -0
  26. package/lib/templates/match/match_2.ejs +1 -0
  27. package/lib/templates/player/player_1/base.css +1 -0
  28. package/lib/templates/player/player_1/private.ejs +1 -0
  29. package/lib/templates/player/player_1.ejs +78 -0
  30. package/lib/templates/rank/rank_fun.ejs +1 -0
  31. package/lib/templates/report/daily/base.css +1 -0
  32. package/lib/templates/report/daily.ejs +29 -0
  33. package/package.json +2 -2
  34. package/template/hero/hero_1.ejs +0 -900
  35. package/template/item/item/recipe.ejs +0 -51
  36. package/template/item/item/style.css +0 -244
  37. package/template/item/item.ejs +0 -140
  38. package/template/item/itemlist.ejs +0 -99
  39. package/template/match/match_1/item.ejs +0 -11
  40. package/template/match/match_1/main.ejs +0 -37
  41. package/template/match/match_1/player.ejs +0 -154
  42. package/template/match/match_1/style.css +0 -764
  43. package/template/match/match_1.ejs +0 -56
  44. package/template/match/match_2/original.css +0 -463
  45. package/template/match/match_2/original.ejs +0 -192
  46. package/template/match/match_2+/charts.ejs +0 -261
  47. package/template/match/match_2+/extra.css +0 -143
  48. package/template/match/match_2+/lane_outcome.ejs +0 -157
  49. package/template/match/match_2+.ejs +0 -27
  50. package/template/match/match_2.ejs +0 -18
  51. package/template/player/player_1/private.ejs +0 -5
  52. package/template/player/player_1.ejs +0 -654
  53. package/template/rank/rank_fun.ejs +0 -131
  54. package/template/report/daily.ejs +0 -191
  55. /package/{queries → lib/queries}/Constants.graphql +0 -0
  56. /package/{queries → lib/queries}/GetWeeklyMetaByPosition.graphql +0 -0
  57. /package/{queries → lib/queries}/PlayerExtraInfo.graphql +0 -0
  58. /package/{queries → lib/queries}/PlayerInfoWith25Matches.graphql +0 -0
  59. /package/{queries → lib/queries}/PlayerPerformanceForHeroRecommendation.graphql +0 -0
  60. /package/{queries → lib/queries}/PlayersInfoWith10MatchesForGuild.graphql +0 -0
  61. /package/{queries → lib/queries}/PlayersLastmatchRankinfo.graphql +0 -0
  62. /package/{queries → lib/queries}/PlayersMatchesForDaily.graphql +0 -0
  63. /package/{queries → lib/queries}/RequestMatchDataAnalysis.graphql +0 -0
  64. /package/{queries → lib/queries}/VerifyingPlayer.graphql +0 -0
  65. /package/{template → lib/templates}/images/bei.jpg +0 -0
  66. /package/{template → lib/templates}/images/disconnected.png +0 -0
  67. /package/{template → lib/templates}/images/flag_dire.png +0 -0
  68. /package/{template → lib/templates}/images/flag_radiant.png +0 -0
  69. /package/{template → lib/templates}/images/hero_badge_1.png +0 -0
  70. /package/{template → lib/templates}/images/hero_badge_2.png +0 -0
  71. /package/{template → lib/templates}/images/hero_badge_3.png +0 -0
  72. /package/{template → lib/templates}/images/hero_badge_4.png +0 -0
  73. /package/{template → lib/templates}/images/hero_badge_5.png +0 -0
  74. /package/{template → lib/templates}/images/hero_badge_6.png +0 -0
  75. /package/{template → lib/templates}/images/lane_fail.svg +0 -0
  76. /package/{template → lib/templates}/images/lane_jungle.svg +0 -0
  77. /package/{template → lib/templates}/images/lane_stomp.svg +0 -0
  78. /package/{template → lib/templates}/images/lane_stomped.svg +0 -0
  79. /package/{template → lib/templates}/images/lane_tie.svg +0 -0
  80. /package/{template → lib/templates}/images/lane_victory.svg +0 -0
  81. /package/{template → lib/templates}/images/logo_dire.png +0 -0
  82. /package/{template → lib/templates}/images/logo_radiant.png +0 -0
  83. /package/{template → lib/templates}/images/medal_0.png +0 -0
  84. /package/{template → lib/templates}/images/medal_1.png +0 -0
  85. /package/{template → lib/templates}/images/medal_2.png +0 -0
  86. /package/{template → lib/templates}/images/medal_3.png +0 -0
  87. /package/{template → lib/templates}/images/medal_4.png +0 -0
  88. /package/{template → lib/templates}/images/medal_5.png +0 -0
  89. /package/{template → lib/templates}/images/medal_6.png +0 -0
  90. /package/{template → lib/templates}/images/medal_7.png +0 -0
  91. /package/{template → lib/templates}/images/medal_8.png +0 -0
  92. /package/{template → lib/templates}/images/medal_8b.png +0 -0
  93. /package/{template → lib/templates}/images/medal_8c.png +0 -0
  94. /package/{template → lib/templates}/images/scepter.png +0 -0
  95. /package/{template → lib/templates}/images/scepter_0.png +0 -0
  96. /package/{template → lib/templates}/images/scepter_1.png +0 -0
  97. /package/{template → lib/templates}/images/shard.png +0 -0
  98. /package/{template → lib/templates}/images/shard_0.png +0 -0
  99. /package/{template → lib/templates}/images/shard_1.png +0 -0
  100. /package/{template → lib/templates}/images/star_0.png +0 -0
  101. /package/{template → lib/templates}/images/star_1.png +0 -0
  102. /package/{template → lib/templates}/images/star_2.png +0 -0
  103. /package/{template → lib/templates}/images/star_3.png +0 -0
  104. /package/{template → lib/templates}/images/star_4.png +0 -0
  105. /package/{template → lib/templates}/images/star_5.png +0 -0
  106. /package/{template → lib/templates}/images/xi.jpg +0 -0
@@ -1,654 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="<%= languageTag %>">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Document</title>
7
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css" />
8
- <style>
9
- html,
10
- body {
11
- background-color: black;
12
- color: white;
13
- width: 800px;
14
- }
15
-
16
- .wrapper > * {
17
- margin: 5px;
18
- box-shadow: 0 0 5px #fff;
19
- width: 790px;
20
- border-radius: 5px;
21
- overflow: hidden;
22
- position: relative;
23
- }
24
-
25
- img {
26
- width: auto;
27
- vertical-align: middle;
28
- }
29
-
30
- p {
31
- margin: 0;
32
- }
33
-
34
- .player {
35
- display: flex;
36
- position: relative;
37
- height: 128px;
38
- }
39
-
40
- .player .avatar {
41
- width: 128px;
42
- height: 128px;
43
- position: absolute;
44
- }
45
-
46
- .player .avatar img {
47
- width: 100%;
48
- border-radius: 5px;
49
- }
50
-
51
- .player .name {
52
- font-size: 24px;
53
- }
54
- .player .name .guild::before {
55
- content: "[";
56
- color: #fff;
57
- }
58
- .player .name .guild::after {
59
- content: "]";
60
- color: #fff;
61
- }
62
- .player .name .hero_name::before {
63
- content: ">";
64
- color: #fff;
65
- }
66
- .player .name .hero_name::after {
67
- content: "<";
68
- color: #fff;
69
- }
70
-
71
- .player .info {
72
- width: 100%;
73
- display: flex;
74
- flex-direction: column;
75
- align-items: center;
76
- /* line-height: 2; */
77
- justify-content: space-around;
78
- }
79
-
80
- .player .info .guild.Copper {
81
- color: #b4775f;
82
- }
83
- .player .info .guild.Silver {
84
- color: #9a9593;
85
- }
86
- .player .info .guild.Gold {
87
- color: #bda97f;
88
- }
89
- .player .info .guild.Diamond {
90
- color: #a5cbcf;
91
- }
92
-
93
- .player .info .matches span.win {
94
- color: #007a00;
95
- }
96
- .player .info .matches span.lose {
97
- color: #b30000;
98
- }
99
-
100
- .player .info .matches span.victory {
101
- color: lightgreen;
102
- }
103
- .player .info .matches span.stomp {
104
- color: green;
105
- /* font-size: 8px; */
106
- }
107
- .player .info .matches span.fail {
108
- color: #ff6961;
109
- }
110
- .player .info .matches span.stomped {
111
- color: red;
112
- /* font-size: 8px; */
113
- }
114
- .player .info .matches.blur {
115
- filter: blur(10px);
116
- }
117
-
118
- .player .rank {
119
- width: 64px;
120
- height: 64px;
121
- flex-grow: 1;
122
- position: absolute;
123
- top: 0;
124
- right: 0;
125
- }
126
-
127
- .player .rank.estimated {
128
- filter: grayscale(100%);
129
- }
130
-
131
- .player .rank .medal {
132
- z-index: 1;
133
- }
134
-
135
- .player .rank .star {
136
- z-index: 2;
137
- }
138
-
139
- .player .rank p {
140
- z-index: 4;
141
- }
142
-
143
- .player .rank div {
144
- height: 100%;
145
- width: 100%;
146
- top: 0;
147
- right: 0;
148
- position: absolute;
149
- }
150
-
151
- .player .rank img {
152
- top: 0;
153
- right: 0;
154
- position: absolute;
155
- height: 64px;
156
- }
157
-
158
- .player .rank p {
159
- font-size: 12px;
160
- line-height: 1;
161
- position: absolute;
162
- text-align: center;
163
- width: 64px;
164
- bottom: 4px;
165
- right: 0;
166
- /* background-color: #222; */
167
- /* border: black 1px solid; */
168
- box-sizing: border-box;
169
- text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; /* 描边效果 */
170
- }
171
-
172
- .hero_winrate > *:not(:last-child) {
173
- /* margin-bottom: 10px; */
174
- }
175
-
176
- .hero_winrate {
177
- }
178
-
179
- .hero_winrate .heroes {
180
- display: grid;
181
- /* line-height: 2; */
182
- grid-template-columns: 32px auto auto auto auto auto;
183
- /* grid-template-rows: repeat(auto-fill, 1fr); */
184
- justify-content: start;
185
- align-items: center;
186
- }
187
-
188
- .hero_winrate .heroes .hero {
189
- width: 100%;
190
- display: flex;
191
- align-items: center;
192
- }
193
-
194
- .hero_winrate .heroes img {
195
- width: 100%;
196
- /* height: 32px; */
197
- border-radius: 6px;
198
- overflow: hidden;
199
- }
200
-
201
- .hero_winrate .heroes span.imp {
202
- margin: 0 4px;
203
- }
204
-
205
- .hero_winrate .heroes span {
206
- text-align: center;
207
- }
208
-
209
- .hero_winrate .heroes .tip.row {
210
- grid-column: 1/-1;
211
- }
212
-
213
- .hero_winrate .heroes .win {
214
- /* color: #000; */
215
- text-align: right;
216
- padding-right: 8px;
217
- background-color: #006400;
218
- border-radius: 16px 0 0 16px;
219
- height: 16px;
220
- justify-self: end;
221
- }
222
- .hero_winrate .heroes .lose {
223
- /* color: #000; */
224
- text-align: left;
225
- padding-left: 8px;
226
- background-color: #8b0000;
227
- border-radius: 0 16px 16px 0;
228
- height: 16px;
229
- justify-self: start;
230
- }
231
-
232
- table.matches {
233
- table-layout: fixed;
234
- width: 100%;
235
- }
236
-
237
- .matches .match.win {
238
- background-color: #006400;
239
- }
240
- .matches .match.lose {
241
- background-color: #8b0000;
242
- }
243
-
244
- .matches .match td {
245
- text-align: center;
246
- /* line-height: 40px; */
247
- height: 40px;
248
- overflow: hidden;
249
- }
250
-
251
- .matches .match .player_lane {
252
- width: 100%;
253
- height: 100%;
254
- justify-content: center; /* 水平居中 */
255
- align-items: center; /* 垂直居中 */
256
- display: flex;
257
- }
258
-
259
- .matches .match .player_lane:not(.tie) {
260
- /* background-color: #000; */
261
- }
262
-
263
- .matches .match .player_lane svg {
264
- width: 36px;
265
- height: 36px;
266
- }
267
- .player_lane.victory svg path {
268
- fill: lightgreen;
269
- }
270
-
271
- .player_lane.stomp svg path {
272
- fill: green;
273
- }
274
-
275
- .player_lane.stomped svg path {
276
- fill: red;
277
- }
278
-
279
- .plus {
280
- display: grid;
281
- grid-template-columns: repeat(4, 1fr);
282
- gap: 10px;
283
- }
284
-
285
- .plus .hero {
286
- width: 190px;
287
- height: 190px;
288
- border-radius: 5px;
289
- position: relative;
290
- display: grid;
291
- grid-template-columns: repeat(2, 1fr);
292
- grid-template-rows: 118.75px auto;
293
- justify-items: center;
294
- align-items: center;
295
- }
296
- .plus .hero img {
297
- width: 100%;
298
- grid-column: 1/-1;
299
- }
300
-
301
- .plus .level {
302
- position: absolute;
303
- width: 50px;
304
- height: 50px;
305
- left: calc(50% - 25px);
306
- top: calc(118.75px - 25px);
307
- }
308
-
309
- .plus .level span {
310
- position: absolute;
311
- width: 100%;
312
- text-align: center;
313
- left: 0;
314
- bottom: 18px;
315
- font-size: 14px;
316
- text-shadow: -1px -1px 1px #000, 1px -1px 1px #000, -1px 1px 1px #000, 1px 1px 1px #000;
317
- }
318
-
319
- .blur-overlay {
320
- position: absolute;
321
- top: 0;
322
- left: 0;
323
- width: 100%;
324
- height: 100%;
325
- background: #00000050;
326
- backdrop-filter: blur(10px);
327
- display: flex;
328
- flex-direction: column;
329
- justify-content: center;
330
- align-items: center;
331
- }
332
-
333
- .lock-icon {
334
- font-size: 24px;
335
- margin-bottom: 10px;
336
- }
337
-
338
- .lock-text {
339
- font-size: 18px;
340
- font-weight: bold;
341
- }
342
- .lock-sub {
343
- line-height: 3;
344
- font-size: 14px;
345
- color: #aaa;
346
- }
347
- </style>
348
-
349
- <% if (fontFamily) { %>
350
- <%- "<style>" %>
351
- <%- `body { font-family: ${fontFamily}; }` %>
352
- <%- "</style>" %>
353
- <% } %>
354
- </head>
355
- <body>
356
- <% const player = data;
357
- const guildLevel = (percent) => {
358
- if (percent <= 25) {
359
- return "Copper";
360
- } else if (percent <= 50) {
361
- return "Silver";
362
- } else if (percent <= 75) {
363
- return "Gold";
364
- } else {
365
- return "Diamond";
366
- }
367
- };
368
- const laneSVG = {
369
- stomp: getImageUrl("lane_stomp", undefined, ImageFormat.svg),
370
- victory: getImageUrl("lane_victory", undefined, ImageFormat.svg),
371
- fail: getImageUrl("lane_fail", undefined, ImageFormat.svg),
372
- stomped: getImageUrl("lane_stomped", undefined, ImageFormat.svg),
373
- tie: getImageUrl("lane_tie", undefined, ImageFormat.svg),
374
- jungle: getImageUrl("lane_jungle", undefined, ImageFormat.svg),
375
- };
376
- const outcomeCounts = {
377
- victory: 0,
378
- stomp: 0,
379
- fail: 0,
380
- stomped: 0,
381
- tie: 0,
382
- };
383
- const processLaneOutcome = (outcome) => {
384
- switch (outcome) {
385
- case "RADIANT_VICTORY":
386
- return { radiant: "victory", dire: "fail" };
387
- case "RADIANT_STOMP":
388
- return { radiant: "stomp", dire: "stomped" };
389
- case "DIRE_VICTORY":
390
- return { radiant: "fail", dire: "victory" };
391
- case "DIRE_STOMP":
392
- return { radiant: "stomped", dire: "stomp" };
393
- default:
394
- return { radiant: "tie", dire: "tie" };
395
- }
396
- };
397
- let nearMatchCount = 25,
398
- nearWinCount = 0,
399
- streak = 0;
400
- player.matches.forEach((match) => {
401
- const innerPlayer = match.players.find(innerPlayer=>player.steamAccount.id==innerPlayer.steamAccount.id);
402
- nearWinCount += match.didRadiantWin == innerPlayer.isRadiant ? 1 : 0;
403
- const didWin = match.didRadiantWin === innerPlayer.isRadiant;
404
- if (!player.streak) {
405
- if (streak != 0) {
406
- if (didWin && streak > 0) streak++;
407
- else if (!didWin && streak < 0) streak--;
408
- else player.streak = streak;
409
- } else streak = didWin ? 1 : -1;
410
- }
411
-
412
- const laneResult = {
413
- top: processLaneOutcome(match.topLaneOutcome),
414
- mid: processLaneOutcome(match.midLaneOutcome),
415
- bottom: processLaneOutcome(match.bottomLaneOutcome),
416
- };
417
-
418
- let laneKey = "mid"; // 默认中路
419
- if (innerPlayer.lane === "SAFE_LANE") laneKey = innerPlayer.isRadiant ? "bottom" : "top";
420
- else if (innerPlayer.lane === "OFF_LANE") laneKey = innerPlayer.isRadiant ? "top" : "bottom";
421
- if (innerPlayer.lane === "JUNGLE") match.laneResult = "jungle";
422
- else match.laneResult = laneResult[laneKey][innerPlayer.isRadiant ? "radiant" : "dire"];
423
-
424
- if (match.laneResult in outcomeCounts) {
425
- outcomeCounts[match.laneResult]++;
426
- }
427
- });
428
- // 无法动态获取tip元素个数
429
- // const heroesCountPixels = 800 - ($(".tip:not(.row):not(.win_count):not(.lose_count)").length + 1) * 40;
430
- const heroesCountPixels = 800 - (4+1) * 40;
431
- const highestCountsTotal = {
432
- winCount: Math.max(...player.heroesPerformanceTop10.map((hero) => hero.winCount)),
433
- loseCount: Math.max(...player.heroesPerformanceTop10.map((hero) => hero.matchCount - hero.winCount)),
434
- };
435
- const pixelOfPerMatchInTotal = heroesCountPixels / (highestCountsTotal.winCount + highestCountsTotal.loseCount);
436
- const highestCountsNear = {
437
- winCount: Math.max(...player.heroesPerformance?.filter((hero) => hero.matchCount > 1)?.map((hero) => hero.winCount)),
438
- loseCount: Math.max(...player.heroesPerformance?.filter((hero) => hero.matchCount > 1)?.map((hero) => hero.matchCount - hero.winCount)),
439
- };
440
- const nearAdjustmentFactor = Math.min(highestCountsTotal.winCount / (highestCountsTotal.winCount + highestCountsTotal.loseCount), highestCountsTotal.loseCount / (highestCountsTotal.winCount + highestCountsTotal.loseCount));
441
-
442
- const pixelOfPerMatchInNear = (heroesCountPixels / (highestCountsNear?.winCount + highestCountsNear?.loseCount ?? 1)) * nearAdjustmentFactor;
443
-
444
- player.positionPerformance=[];
445
- const positionIcons = ["damage","nuke","armor","speed","healing"];
446
- for (let index = 0; index < 5; index++) {
447
- let currentPositionMatches = player.matches.filter(match=>match.players.find(innerPlayer=>player.steamAccount.id==innerPlayer.steamAccount.id).position == ("POSITION_"+(index+1)))
448
- let winCount = currentPositionMatches.filter(match=>match.didRadiantWin == match.players.find(innerPlayer=>player.steamAccount.id==innerPlayer.steamAccount.id).isRadiant).length;
449
- player.positionPerformance.push({
450
- position : (index + 1),
451
- icon : positionIcons[index],
452
- matchCount : currentPositionMatches.length,
453
- winCount : winCount,
454
- loseCount : currentPositionMatches.length - winCount,
455
- imp : currentPositionMatches.length>0? Math.round(currentPositionMatches.reduce((acc,match)=>acc+match.players.find(innerPlayer=>player.steamAccount.id==innerPlayer.steamAccount.id).imp,0)/currentPositionMatches.length):"-"
456
- })
457
- }
458
- const highestCountsPosition = {
459
- winCount: Math.max(...player.positionPerformance.filter((position) => position.matchCount > 1)?.map((position) => position.winCount)),
460
- loseCount: Math.max(...player.positionPerformance.filter((position) => position.matchCount > 1)?.map((position) => position.matchCount - position.winCount)),
461
- };
462
- const pixelOfPerMatchInPosition = (heroesCountPixels / (highestCountsPosition.winCount + highestCountsPosition.loseCount ?? 1)) * nearAdjustmentFactor;
463
- %>
464
- <% function winRateColor(value) {
465
- value = value * 100;
466
- value = Math.max(0, Math.min(100, value));
467
-
468
- let red, green, blue;
469
-
470
- if (value <= 50) {
471
- // 从纯红到纯白
472
- let scale = Math.round(255 * (value / 50)); // Scale of 0 to 255
473
- red = 255;
474
- green = scale;
475
- blue = scale;
476
- } else {
477
- // 从纯白到纯绿
478
- let scale = Math.round(255 * ((value - 50) / 50)); // Scale of 0 to 255
479
- red = 255 - scale;
480
- green = 255;
481
- blue = 255 - scale;
482
- }
483
-
484
- // 将RGB值转换为两位十六进制代码
485
- const toHex = (color) => color.toString(16).padStart(2, "0").toUpperCase();
486
-
487
- return `#${toHex(red)}${toHex(green)}${toHex(blue)}`;
488
- }
489
- %>
490
-
491
- <div class="wrapper">
492
- <div class="player">
493
- <div class="avatar"><img src="<%= player.steamAccount?.avatar %>" alt="" /></div>
494
- <div class="info">
495
- <p class="name">
496
- <%= player.steamAccount.name %>
497
- <%- player.guildMember ? ` <span class="guild ${guildLevel(player.guildMember.guild.currentPercentile)}">${player.guildMember.guild.tag}</span>` : "" %>
498
- <%- player.genHero ? `<span class="hero_name">${player.genHero.name}</span>` : "" %>
499
- </p>
500
- <p class="matches">
501
- <%=$t("dota2tracker.template.match_count_")%><%=player.matchCount%> (<span class="win"><%=player.winCount%></span>/<span class="lose"><%=player.matchCount - player.winCount%></span>) &nbsp;&nbsp;
502
- <%=$t("dota2tracker.template.winrate_")%><span <%-`style="color:${winRateColor(player.winCount / player.matchCount)};"`%>><%=((player.winCount / player.matchCount) * 100).toFixed(2)%>%</span>
503
- </p>
504
- <p class="matches<%- player.steamAccount.isAnonymous ? " blur" : "" %>">
505
- <span><%-$t("dota2tracker.template.last25matches_")%>
506
- <span class="win"><%-nearWinCount%></span>/
507
- <span class="lose"><%-nearMatchCount - nearWinCount%></span>
508
- </span>&nbsp;
509
- <span><%-$t("dota2tracker.template.winrate_")%>
510
- <span <%-`style="color:${winRateColor(nearWinCount / nearMatchCount)};"`%>><%-((nearWinCount / nearMatchCount) * 100).toFixed(2)%>%</span>
511
- </span>&nbsp;
512
- <span><%-$t("dota2tracker.template.imp_")%><%-player.steamAccount.isAnonymous?"?":((player.performance?.imp > 0 ? "+" : "") + player.performance?.imp)%></span>
513
- </p>
514
- <p class="matches<%- player.steamAccount.isAnonymous ? " blur" : "" %>">
515
- <span><%-$t("dota2tracker.template.lane")%>
516
- <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>
517
- </span>&nbsp;&nbsp;
518
- <span><%-$t("dota2tracker.template.lane_advantage_rate_")%>
519
- <span <%-`style="color:${winRateColor((outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.tie / 2) / (outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.tie + outcomeCounts.fail + outcomeCounts.stomped))};"`%>><%-player.steamAccount.isAnonymous?"?":(((outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.tie / 2) / (outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.tie + outcomeCounts.fail + outcomeCounts.stomped)) * 100).toFixed(2)%>%</span>
520
- </span>
521
- </p>
522
- </div>
523
- <div class="rank<%= player.isEstimatedRank ? " estimated" : "" %>">
524
- <img class="medal" src="<%-getImageUrl('medal_' +(player.rank.inTop100??player.rank.medal))%>" alt="" />
525
- <img class="star" src="<%-getImageUrl('star_' + player.rank.star)%>" alt="" />
526
- <p><%-player.steamAccount.seasonLeaderboardRank ?? ""%></p>
527
- </div>
528
- </div>
529
- <div class="hero_winrate">
530
- <div class="heroes">
531
- <p class="tip row total"><%- player.genHero ? $t("dota2tracker.template.all_matches_") : $t("dota2tracker.template.top10_") %></p>
532
- <span class="tip"><%= $t("dota2tracker.template.hero") %></span>
533
- <span class="tip" style="margin: 0 4px"><%= $t("dota2tracker.template.match_count") %></span>
534
- <span class="tip" style="margin: 0 4px"><%= $t("dota2tracker.template.winrate") %></span>
535
- <span class="tip" style="margin: 0 4px"><%= $t("dota2tracker.template.imp") %></span>
536
- <span class="tip win_count" style="justify-self: end; margin-right: 2px"><%= $t("dota2tracker.template.win_count") %></span>
537
- <span class="tip lose_count" style="justify-self: start; margin-left: 2px"><%= $t("dota2tracker.template.lose_count") %></span>
538
- <%- player.heroesPerformanceTop10
539
- .map((hero) => `
540
- <span><img alt="" src="${getImageUrl(hero.hero.shortName, ImageType.HeroIcons)}" /></span>
541
- <span class="count">${hero.matchCount}</span>
542
- <span class="win_rate">${((hero.winCount / hero.matchCount) * 100).toFixed(0)}%</span>
543
- <span class="imp">${(hero.imp > 0 ? "+" : "") + hero.imp}</span>
544
- <span class="win" style="${hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${hero.winCount * pixelOfPerMatchInTotal}px">${hero.winCount}</span>
545
- <span class="lose" style="${hero.matchCount - hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${(hero.matchCount - hero.winCount) * pixelOfPerMatchInTotal}px">${hero.matchCount - hero.winCount}</span>`).join("") %>
546
- <%- !player.genHero ?
547
- `<p class="tip row near">${$t("dota2tracker.template.recently_heroes")}</p>`:
548
- `<p class="tip row total">${$t("dota2tracker.template.last25matches_")}</p>`
549
- %>
550
- <%- player.heroesPerformance
551
- .filter((hero) => hero.matchCount > 1)
552
- .map((hero, index) => `
553
- <span><img alt="" src="${getImageUrl(hero.hero.shortName, ImageType.HeroIcons)}" /></span>
554
- <span class="count">${hero.matchCount}</span>
555
- <span class="win_rate">${((hero.winCount / hero.matchCount) * 100).toFixed(0)}%</span>
556
- <span class="imp">${(hero.imp > 0 ? "+" : "") + hero.imp}</span>
557
- <span class="win" style="${hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${hero.winCount * pixelOfPerMatchInNear}px">${hero.winCount}</span>
558
- <span class="lose" style="${hero.matchCount - hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${(hero.matchCount - hero.winCount) * pixelOfPerMatchInNear}px">${hero.matchCount - hero.winCount}</span>`).join("") %>
559
- <p class="tip row near"><%= $t("dota2tracker.template.recently_positions") %></p>
560
- <span class="tip"><%= $t("dota2tracker.template.position") %></span>
561
- <span class="tip" style="margin: 0 4px"><%= $t("dota2tracker.template.match_count") %></span>
562
- <span class="tip" style="margin: 0 4px"><%= $t("dota2tracker.template.winrate") %></span>
563
- <span class="tip" style="margin: 0 4px"><%= $t("dota2tracker.template.imp") %></span>
564
- <span class="tip win_count" style="justify-self: end; margin-right: 2px"><%= $t("dota2tracker.template.win_count") %></span>
565
- <span class="tip lose_count" style="justify-self: start; margin-left: 2px"><%= $t("dota2tracker.template.lose_count") %></span>
566
- <%- player.positionPerformance
567
- .map((position) => `
568
- <span><img src="${getImageUrl(position.icon,ImageType.IconsFacets)}"></span>
569
- <span class="count">${position.matchCount}</span>
570
- <span class="win_rate">${position.matchCount>0?(((position.winCount / position.matchCount) * 100).toFixed(0)):"-"}%</span>
571
- <span class="imp">${(position.imp > 0 ? "+" : "") + position.imp}</span>
572
- <span class="win" style="${position.winCount == 0 ? "visibility:hidden;" : ""}width: ${position.winCount * pixelOfPerMatchInPosition}px">${position.winCount}</span>
573
- <span class="lose" style="${position.matchCount - position.winCount == 0 ? "visibility:hidden;" : ""}width: ${(position.matchCount - position.winCount) * pixelOfPerMatchInPosition}px">${position.matchCount - position.winCount}</span>`).join("") %>
574
- </div>
575
- <% if (player.steamAccount.isAnonymous) { %>
576
- <%- include("player_1/private", {$t, player}) %>
577
- <% } %>
578
- </div>
579
- <%- Math.abs(player.streak) > 1 && !player.steamAccount.isAnonymous ?
580
- `<div class="streak" style="box-shadow:none;color:${winRateColor((player.streak + 10) / 20)};">${Math.abs(player.streak) + (player.streak > 0 ? $t("dota2tracker.template.winning_streak") : $t("dota2tracker.template.losing_streak"))}</div>`:"" %>
581
- <div>
582
- <table class="matches">
583
- <colgroup>
584
- <col style="width: auto" />
585
- <col style="width: auto" />
586
- <col style="width: 40px" />
587
- <col style="width: auto" />
588
- <col style="width: 40px" />
589
- <col style="width: auto" />
590
- <col style="width: auto" />
591
- <col style="width: auto" />
592
- <col style="width: 40px" />
593
- </colgroup>
594
- <thead>
595
- <tr>
596
- <th><%= $t("dota2tracker.template.id") %></th>
597
- <th><%= $t("dota2tracker.template.mode") %></th>
598
- <th><%= $t("dota2tracker.template.hero") %></th>
599
- <th><%= $t("dota2tracker.template.kda_kc") %></th>
600
- <th><%= $t("dota2tracker.template.lane") %></th>
601
- <th><%= $t("dota2tracker.template.time") %></th>
602
- <th><%= $t("dota2tracker.template.duration") %></th>
603
- <th><%= $t("dota2tracker.template.imp") %></th>
604
- <th><%= $t("dota2tracker.template.rank") %></th>
605
- </tr>
606
- </thead>
607
- <tbody>
608
- <%- player.matches.map((match) => {
609
- const innerPlayer = match.players.find(innerPlayer => player.steamAccount.id == innerPlayer.steamAccount.id);
610
- innerPlayer.teamKillsCount = match.parsedDateTime ?
611
- (match[(innerPlayer.isRadiant ? "radiant" : "dire") + "Kills"]?.reduce((acc, cva) => acc + cva, 0) ?? 0) :
612
- match.players
613
- .filter(p => p.isRadiant === innerPlayer.isRadiant)
614
- .reduce((k, p) => k + p.kills, 0);
615
- return `
616
- <tr class="match ${match.didRadiantWin == innerPlayer.isRadiant ? "win" : "lose"}">
617
- <td>${match.parsedDateTime ? match.id : `<p>${match.id}</p><p>${$t("dota2tracker.template.un_parsed")}</p>`}</td>
618
- <td>
619
- <p>${$t("dota2tracker.template.lobby_types."+match.lobbyType) || match.lobbyType}</p>
620
- <p>${$t("dota2tracker.template.game_modes."+match.gameMode) || match.gameMode}</p>
621
- </td>
622
- <td><img alt="" src="${getImageUrl(innerPlayer.hero.shortName, ImageType.HeroIcons)}" /></td>
623
- <td style="line-height: 20px">
624
- <p>${((innerPlayer.kills + innerPlayer.assists) / Math.max(1, innerPlayer.deaths)).toFixed(2)} (${(match.parsedDateTime?"":"≈")+((((innerPlayer.kills + innerPlayer.assists) /
625
- innerPlayer.teamKillsCount) * 100)?.toFixed(0))}%)</p>
626
- <p>${innerPlayer.kills}/${innerPlayer.deaths}/${innerPlayer.assists}</p>
627
- </td>
628
- <td><div class="player_lane ${match.laneResult}">${laneSVG[match.laneResult]}</div></td>
629
- <td style="line-height: 20px">${DateTime.fromSeconds(match.startDateTime ?? 0).toFormat("yyyy-MM-dd HH:mm:ss").slice(2)}</td>
630
- <td>${match.durationTime}</td>
631
- <td>${innerPlayer.imp != null ? ((innerPlayer.imp >= 0 ? "+" : "") + innerPlayer.imp) : "?"}</td>
632
- <td><img class="medal" src="${getImageUrl("medal_" + match.rank?.toString().split("")[0])}" style="width: 100%" /></td>
633
- </tr>`}).join("")%>
634
- </tbody>
635
- </table>
636
- <% if (player.steamAccount.isAnonymous) { %>
637
- <%- include("player_1/private", {$t, player}) %>
638
- <% } %>
639
- </div>
640
- <div class="plus">
641
- <%- player.dotaPlus.map((hero) => `
642
- <div class="hero">
643
- <img src="${getImageUrl(hero.shortName, ImageType.Heroes)}" alt="" />
644
- <div class="level"><img src="${getImageUrl("hero_badge_" + Math.ceil((hero.level + 1) / 6))}" alt="" /><span>${hero.level}</span></div>
645
- <span>${((hero.winCount / hero.matchCount) * 100).toFixed(2)}%</span>
646
- <span>${hero.matchCount}</span>
647
- </div>`).join("") %>
648
- <% if (player.steamAccount.isAnonymous) { %>
649
- <%- include("player_1/private", {$t, player}) %>
650
- <% } %>
651
- </div>
652
- </div>
653
- </body>
654
- </html>