@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.
@@ -0,0 +1,543 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
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
+ }
23
+
24
+ img {
25
+ width: auto;
26
+ vertical-align: middle;
27
+ }
28
+
29
+ p {
30
+ margin: 0;
31
+ }
32
+
33
+ .player {
34
+ display: flex;
35
+ position: relative;
36
+ height: 128px;
37
+ }
38
+
39
+ .player .avatar {
40
+ width: 128px;
41
+ height: 128px;
42
+ position: absolute;
43
+ }
44
+
45
+ .player .avatar img {
46
+ width: 100%;
47
+ border-radius: 5px;
48
+ }
49
+
50
+ .player .name {
51
+ font-size: 24px;
52
+ }
53
+
54
+ .player .info {
55
+ width: 100%;
56
+ display: flex;
57
+ flex-direction: column;
58
+ align-items: center;
59
+ /* line-height: 2; */
60
+ justify-content: space-around;
61
+ }
62
+
63
+ .player .info .guild.Copper {
64
+ color: #b4775f;
65
+ }
66
+ .player .info .guild.Silver {
67
+ color: #9a9593;
68
+ }
69
+ .player .info .guild.Gold {
70
+ color: #bda97f;
71
+ }
72
+ .player .info .guild.Diamond {
73
+ color: #a5cbcf;
74
+ }
75
+
76
+ .player .info p > span:not(:last-child) {
77
+ margin-right: 20px;
78
+ }
79
+
80
+ .player .info .matches span.win {
81
+ color: #006400;
82
+ }
83
+ .player .info .matches span.lose {
84
+ color: #8b0000;
85
+ }
86
+
87
+ .player .info .matches span.victory {
88
+ color: lightgreen;
89
+ }
90
+ .player .info .matches span.stomp {
91
+ color: green;
92
+ /* font-size: 8px; */
93
+ }
94
+ .player .info .matches span.fail {
95
+ color: #ff6961;
96
+ }
97
+ .player .info .matches span.stomped {
98
+ color: red;
99
+ /* font-size: 8px; */
100
+ }
101
+
102
+ .player .rank {
103
+ width: 64px;
104
+ height: 64px;
105
+ flex-grow: 1;
106
+ position: absolute;
107
+ top: 0;
108
+ right: 0;
109
+ }
110
+
111
+ .player .rank .medal {
112
+ z-index: 1;
113
+ }
114
+
115
+ .player .rank .star {
116
+ z-index: 2;
117
+ }
118
+
119
+ .player .rank p {
120
+ z-index: 4;
121
+ }
122
+
123
+ .player .rank div {
124
+ height: 100%;
125
+ width: 100%;
126
+ top: 0;
127
+ right: 0;
128
+ position: absolute;
129
+ }
130
+
131
+ .player .rank img {
132
+ top: 0;
133
+ right: 0;
134
+ position: absolute;
135
+ height: 64px;
136
+ }
137
+
138
+ .player .rank p {
139
+ font-size: 12px;
140
+ line-height: 1;
141
+ position: absolute;
142
+ text-align: center;
143
+ width: 64px;
144
+ bottom: 4px;
145
+ right: 0;
146
+ /* background-color: #222; */
147
+ /* border: black 1px solid; */
148
+ box-sizing: border-box;
149
+ text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; /* 描边效果 */
150
+ }
151
+
152
+ .hero_winrate > *:not(:last-child) {
153
+ /* margin-bottom: 10px; */
154
+ }
155
+
156
+ .hero_winrate .heroes {
157
+ display: grid;
158
+ /* line-height: 2; */
159
+ grid-template-columns: 32px auto auto auto auto auto;
160
+ /* grid-template-rows: repeat(auto-fill, 1fr); */
161
+ justify-content: start;
162
+ align-items: center;
163
+ }
164
+
165
+ .hero_winrate .heroes .hero {
166
+ width: 100%;
167
+ display: flex;
168
+ align-items: center;
169
+ }
170
+
171
+ .hero_winrate .heroes img {
172
+ width: 100%;
173
+ /* height: 32px; */
174
+ border-radius: 6px;
175
+ overflow: hidden;
176
+ }
177
+
178
+ .hero_winrate .heroes span.imp {
179
+ margin: 0 4px;
180
+ }
181
+
182
+ .hero_winrate .heroes span {
183
+ text-align: center;
184
+ }
185
+
186
+ .hero_winrate .heroes .tip.row {
187
+ grid-column: 1/-1;
188
+ }
189
+
190
+ .hero_winrate .heroes .win {
191
+ /* color: #000; */
192
+ text-align: right;
193
+ padding-right: 8px;
194
+ background-color: #006400;
195
+ border-radius: 16px 0 0 16px;
196
+ height: 16px;
197
+ justify-self: end;
198
+ }
199
+ .hero_winrate .heroes .lose {
200
+ /* color: #000; */
201
+ text-align: left;
202
+ padding-left: 8px;
203
+ background-color: #8b0000;
204
+ border-radius: 0 16px 16px 0;
205
+ height: 16px;
206
+ justify-self: start;
207
+ }
208
+
209
+ .matches {
210
+ table-layout: fixed;
211
+ }
212
+
213
+ .matches .match.win {
214
+ background-color: #006400;
215
+ }
216
+ .matches .match.lose {
217
+ background-color: #8b0000;
218
+ }
219
+
220
+ .matches .match td {
221
+ text-align: center;
222
+ /* line-height: 40px; */
223
+ height: 40px;
224
+ overflow: hidden;
225
+ }
226
+
227
+ .matches .match .player_lane {
228
+ width: 100%;
229
+ height: 100%;
230
+ justify-content: center; /* 水平居中 */
231
+ align-items: center; /* 垂直居中 */
232
+ display: flex;
233
+ }
234
+
235
+ .matches .match .player_lane:not(.tie) {
236
+ /* background-color: #000; */
237
+ }
238
+
239
+ .matches .match .player_lane svg {
240
+ width: 36px;
241
+ height: 36px;
242
+ }
243
+ .player_lane.victory svg path {
244
+ fill: lightgreen;
245
+ }
246
+
247
+ .player_lane.stomp svg path {
248
+ fill: green;
249
+ }
250
+
251
+ .player_lane.stomped svg path {
252
+ fill: red;
253
+ }
254
+
255
+ .plus {
256
+ display: grid;
257
+ grid-template-columns: repeat(4, 1fr);
258
+ gap: 10px;
259
+ }
260
+
261
+ .plus .hero {
262
+ width: 190px;
263
+ height: 190px;
264
+ border-radius: 5px;
265
+ position: relative;
266
+ display: grid;
267
+ grid-template-columns: repeat(2, 1fr);
268
+ grid-template-rows: 118.75px auto;
269
+ justify-items: center;
270
+ align-items: center;
271
+ }
272
+ .plus .hero img {
273
+ width: 100%;
274
+ grid-column: 1/-1;
275
+ }
276
+
277
+ .plus .level {
278
+ position: absolute;
279
+ width: 50px;
280
+ height: 50px;
281
+ left: calc(50% - 25px);
282
+ top: calc(118.75px - 25px);
283
+ }
284
+
285
+ .plus .level span {
286
+ position: absolute;
287
+ width: 100%;
288
+ text-align: center;
289
+ left: 0;
290
+ bottom: 18px;
291
+ font-size: 14px;
292
+ text-shadow: -1px -1px 1px #000, 1px -1px 1px #000, -1px 1px 1px #000, 1px 1px 1px #000;
293
+ }
294
+ </style>
295
+ </head>
296
+ <body>
297
+ <% const player = data;
298
+ const guildLevel = (percent) => {
299
+ if (percent <= 25) {
300
+ return "Copper";
301
+ } else if (percent <= 50) {
302
+ return "Silver";
303
+ } else if (percent <= 75) {
304
+ return "Gold";
305
+ } else {
306
+ return "Diamond";
307
+ }
308
+ };
309
+ const laneSVG = {
310
+ 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>`,
311
+ 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>`,
312
+ 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>`,
313
+ 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>`,
314
+ 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>`,
315
+ };
316
+ const outcomeCounts = {
317
+ victory: 0,
318
+ stomp: 0,
319
+ fail: 0,
320
+ stomped: 0,
321
+ tie: 0,
322
+ };
323
+ const processLaneOutcome = (outcome) => {
324
+ switch (outcome) {
325
+ case "RADIANT_VICTORY":
326
+ return { radiant: "victory", dire: "fail" };
327
+ case "RADIANT_STOMP":
328
+ return { radiant: "stomp", dire: "stomped" };
329
+ case "DIRE_VICTORY":
330
+ return { radiant: "fail", dire: "victory" };
331
+ case "DIRE_STOMP":
332
+ return { radiant: "stomped", dire: "stomp" };
333
+ default:
334
+ return { radiant: "tie", dire: "tie" };
335
+ }
336
+ };
337
+ let nearMatchCount = 25,
338
+ nearWinCount = 0,
339
+ streak = 0;
340
+ player.matches.forEach((match) => {
341
+ const innerPlayer = match.players[0];
342
+ nearWinCount += match.didRadiantWin == innerPlayer.isRadiant ? 1 : 0;
343
+ const didWin = match.didRadiantWin === innerPlayer.isRadiant;
344
+ if (!player.streak) {
345
+ if (streak != 0) {
346
+ if (didWin && streak > 0) streak++;
347
+ else if (!didWin && streak < 0) streak--;
348
+ else player.streak = streak;
349
+ } else streak = didWin ? 1 : -1;
350
+ }
351
+
352
+ const laneResult = {
353
+ top: processLaneOutcome(match.topLaneOutcome),
354
+ mid: processLaneOutcome(match.midLaneOutcome),
355
+ bottom: processLaneOutcome(match.bottomLaneOutcome),
356
+ };
357
+
358
+ let laneKey = "mid"; // 默认中路
359
+ if (innerPlayer.lane === "SAFE_LANE") {
360
+ laneKey = innerPlayer.isRadiant ? "bottom" : "top";
361
+ } else if (innerPlayer.lane === "OFF_LANE") {
362
+ laneKey = innerPlayer.isRadiant ? "top" : "bottom";
363
+ }
364
+
365
+ match.laneResult = laneResult[laneKey][innerPlayer.isRadiant ? "radiant" : "dire"];
366
+ if (match.laneResult in outcomeCounts) {
367
+ outcomeCounts[match.laneResult]++;
368
+ }
369
+ });
370
+ // 无法动态获取tip元素个数
371
+ // const heroesCountPixels = 800 - ($(".tip:not(.row):not(.win_count):not(.lose_count)").length + 1) * 40;
372
+ const heroesCountPixels = 800 - (4+1) * 40;
373
+ const highestCountsTotal = {
374
+ winCount: Math.max(...player.heroesPerformanceTop10.map((hero) => hero.winCount)),
375
+ loseCount: Math.max(...player.heroesPerformanceTop10.map((hero) => hero.matchCount - hero.winCount)),
376
+ };
377
+ const pixelOfPerMatchInTotal = heroesCountPixels / (highestCountsTotal.winCount + highestCountsTotal.loseCount);
378
+ const highestCountsNear = {
379
+ winCount: Math.max(...player.heroesPerformance?.filter((hero) => hero.matchCount > 1)?.map((hero) => hero.winCount)),
380
+ loseCount: Math.max(...player.heroesPerformance?.filter((hero) => hero.matchCount > 1)?.map((hero) => hero.matchCount - hero.winCount)),
381
+ };
382
+ const nearAdjustmentFactor = Math.min(highestCountsTotal.winCount / (highestCountsTotal.winCount + highestCountsTotal.loseCount), highestCountsTotal.loseCount / (highestCountsTotal.winCount + highestCountsTotal.loseCount));
383
+
384
+ const pixelOfPerMatchInNear = (heroesCountPixels / (highestCountsNear?.winCount + highestCountsNear?.loseCount ?? 1)) * nearAdjustmentFactor;
385
+
386
+ player.positionPerformance=[];
387
+ // 瞎j8定义的各位置代表物品,以后看情况调整
388
+ const positionItems=["greater_crit","dagon_5","heart","hand_of_midas","ward_observer"];
389
+ for (let index = 0; index < 5; index++) {
390
+ let currentPositionMatches = player.matches.filter(match=>match.players[0].position == ("POSITION_"+(index+1)))
391
+ let winCount = currentPositionMatches.filter(match=>match.didRadiantWin == match.players[0].isRadiant).length;
392
+ player.positionPerformance.push({
393
+ position : (index + 1),
394
+ icon : positionItems[index],
395
+ matchCount : currentPositionMatches.length,
396
+ winCount : winCount,
397
+ loseCount : currentPositionMatches.length - winCount,
398
+ imp : Math.round(currentPositionMatches.reduce((acc,match)=>acc+match.players[0].imp,0)/currentPositionMatches.length)
399
+ })
400
+ }
401
+ const highestCountsPosition = {
402
+ winCount: Math.max(...player.positionPerformance.filter((position) => position.matchCount > 1)?.map((position) => position.winCount)),
403
+ loseCount: Math.max(...player.positionPerformance.filter((position) => position.matchCount > 1)?.map((position) => position.matchCount - position.winCount)),
404
+ };
405
+ const pixelOfPerMatchInPosition = (heroesCountPixels / (highestCountsPosition.winCount + highestCountsPosition.loseCount ?? 1)) * nearAdjustmentFactor;
406
+ %>
407
+
408
+ <div class="wrapper">
409
+ <div class="player">
410
+ <%- `
411
+ <div class="avatar"><img src="${player.steamAccount.avatar}" alt="" /></div>
412
+ <div class="info">
413
+ <p class="name">${player.steamAccount.name}${player.guildMember ? ` <span class="guild ${guildLevel(player.guildMember.guild.currentPercentile)}">[${player.guildMember.guild.tag}]</span></p>` : ""}
414
+ <p class="matches"><span>场次:${player.matchCount}(<span class="win">${player.winCount}</span>/<span class="lose">${player.matchCount - player.winCount}</span>)</span>胜率:<span style="color:${utils.winRateColor(
415
+ player.winCount / player.matchCount
416
+ )};">${((player.winCount / player.matchCount) * 100).toFixed(2)}%</span></p>
417
+ <p class="matches"><span>最近25场:<span class="win">${nearWinCount}</span>/<span class="lose">${nearMatchCount - nearWinCount}</span></span><span>胜率:<span style="color:${utils.winRateColor(nearWinCount / nearMatchCount)};">${(
418
+ (nearWinCount / nearMatchCount) * 100).toFixed(2)}%</span></span><span>评分:${player.performance.imp}</span></span></p>
419
+ <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">${
420
+ outcomeCounts.fail + outcomeCounts.stomped
421
+ }(<span class="stomped">${outcomeCounts.stomped}</span>)</span></span><span>线优:<span style="color:${utils.winRateColor(
422
+ (outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.tie / 2) / (outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.tie + outcomeCounts.fail + outcomeCounts.stomped)
423
+ )};">${(((outcomeCounts.victory + outcomeCounts.stomp) / (outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.fail + outcomeCounts.stomped)) * 100).toFixed(2)}%</span></span></p>
424
+ </div>
425
+ <div class="rank">
426
+ <img class="medal" src="${utils.getImageUrl(
427
+ "medal_" +
428
+ ((player.steamAccount.seasonLeaderboardRank
429
+ ? player.steamAccount.seasonLeaderboardRank <= 100
430
+ ? player.steamAccount.seasonLeaderboardRank <= 10
431
+ ? "8c"
432
+ : "8b"
433
+ : player.steamAccount.seasonRank?.toString().split("")[0]
434
+ : player.steamAccount.seasonRank?.toString().split("")[0]) ?? "0")
435
+ )}" alt="" />
436
+ <img class="star" src="${utils.getImageUrl("star_" + (player.steamAccount.seasonRank?.toString().split("")[1] ?? "0"))}" alt="" />
437
+ <p>${player.steamAccount.seasonLeaderboardRank ?? ""}</p>
438
+ </div>` %>
439
+ </div>
440
+ <div class="hero_winrate">
441
+ <div class="heroes">
442
+ <p class="tip row total">全期场次前十的英雄:</p>
443
+ <span class="tip">英雄</span>
444
+ <span class="tip" style="margin: 0 4px">场次</span>
445
+ <span class="tip" style="margin: 0 4px">胜率</span>
446
+ <span class="tip" style="margin: 0 4px">表现</span>
447
+ <span class="tip win_count" style="justify-self: end; margin-right: 2px">胜场</span>
448
+ <span class="tip lose_count" style="justify-self: start; margin-left: 2px">败场</span>
449
+ <%- player.heroesPerformanceTop10
450
+ .map((hero) => `
451
+ <span><img alt="" src="${utils.getImageUrl(hero.hero.shortName, ImageType.HeroIcons)}" /></span>
452
+ <span class="count">${hero.matchCount}</span>
453
+ <span class="win_rate">${((hero.winCount / hero.matchCount) * 100).toFixed(0)}%</span>
454
+ <span class="imp">${(hero.imp > 0 ? "+" : "") + hero.imp}</span>
455
+ <span class="win" style="${hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${hero.winCount * pixelOfPerMatchInTotal}px">${hero.winCount}</span>
456
+ <span class="lose" style="${hero.matchCount - hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${(hero.matchCount - hero.winCount) * pixelOfPerMatchInTotal}px">${hero.matchCount - hero.winCount}</span>`).join("") %>
457
+ <p class="tip row near">近期使用场次大于1的英雄:</p>
458
+ <%- player.heroesPerformance
459
+ .filter((hero) => hero.matchCount > 1)
460
+ .map((hero, index) => `
461
+ <span><img alt="" src="${utils.getImageUrl(hero.hero.shortName, ImageType.HeroIcons)}" /></span>
462
+ <span class="count">${hero.matchCount}</span>
463
+ <span class="win_rate">${((hero.winCount / hero.matchCount) * 100).toFixed(0)}%</span>
464
+ <span class="imp">${(hero.imp > 0 ? "+" : "") + hero.imp}</span>
465
+ <span class="win" style="${hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${hero.winCount * pixelOfPerMatchInNear}px">${hero.winCount}</span>
466
+ <span class="lose" style="${hero.matchCount - hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${(hero.matchCount - hero.winCount) * pixelOfPerMatchInNear}px">${hero.matchCount - hero.winCount}</span>`).join("") %>
467
+ <p class="tip row near">近25场各个位置的表现:</p>
468
+ <span class="tip">位置</span>
469
+ <span class="tip" style="margin: 0 4px">场次</span>
470
+ <span class="tip" style="margin: 0 4px">胜率</span>
471
+ <span class="tip" style="margin: 0 4px">表现</span>
472
+ <span class="tip win_count" style="justify-self: end; margin-right: 2px">胜场</span>
473
+ <span class="tip lose_count" style="justify-self: start; margin-left: 2px">败场</span>
474
+ <%- player.positionPerformance
475
+ .map((position) => `
476
+ <span><img src="${utils.getImageUrl(position.icon,ImageType.Items)}"></span>
477
+ <span class="count">${position.matchCount}</span>
478
+ <span class="win_rate">${((position.winCount / position.matchCount) * 100).toFixed(0)}%</span>
479
+ <span class="imp">${(position.imp > 0 ? "+" : "") + position.imp}</span>
480
+ <span class="win" style="${position.winCount == 0 ? "visibility:hidden;" : ""}width: ${position.winCount * pixelOfPerMatchInPosition}px">${position.winCount}</span>
481
+ <span class="lose" style="${position.matchCount - position.winCount == 0 ? "visibility:hidden;" : ""}width: ${(position.matchCount - position.winCount) * pixelOfPerMatchInPosition}px">${position.matchCount - position.winCount}</span>`).join("") %>
482
+ </div>
483
+ </div>
484
+ <%- player.streak>1?`<div class="streak" style="box-shadow:none;color:${utils.winRateColor((player.streak + 10) / 20)};">${Math.abs(player.streak) + (player.streak > 0 ? "连胜" : "连败")}</div>`:"" %>
485
+ <table class="matches">
486
+ <colgroup>
487
+ <col style="width: auto" />
488
+ <col style="width: auto" />
489
+ <col style="width: 40px" />
490
+ <col style="width: auto" />
491
+ <col style="width: 40px" />
492
+ <col style="width: auto" />
493
+ <col style="width: auto" />
494
+ <col style="width: auto" />
495
+ <col style="width: 40px" />
496
+ </colgroup>
497
+ <thead>
498
+ <tr>
499
+ <th>编号</th>
500
+ <th>模式</th>
501
+ <th>英雄</th>
502
+ <th>KDA(参战率)</th>
503
+ <th>对线</th>
504
+ <th>结束于</th>
505
+ <th>时长</th>
506
+ <th>表现</th>
507
+ <th>段位</th>
508
+ </tr>
509
+ </thead>
510
+ <tbody>
511
+ <%- player.matches.map((match) => `
512
+ <tr class="match ${match.didRadiantWin == match.players[0].isRadiant ? "win" : "lose"}">
513
+ <td>${match.id}</td>
514
+ <td>
515
+ <p>${d2a.lobbyTypes[match.lobbyType] || match.lobbyType}</p>
516
+ <p>${d2a.gameMode[match.gameMode] || match.gameMode}</p>
517
+ </td>
518
+ <td><img alt="" src="${utils.getImageUrl(match.players[0].hero.shortName, ImageType.HeroIcons)}" /></td>
519
+ <td style="line-height: 20px">
520
+ <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) /
521
+ (match.players[0].isRadiant ? match.radiantKills.reduce((acc, cva) => acc + cva, 0) : match.direKills.reduce((acc, cva) => acc + cva, 0))) * 100).toFixed(0)}%)</p>
522
+ <p>${match.players[0].kills}/${match.players[0].deaths}/${match.players[0].assists}</p>
523
+ </td>
524
+ <td><div class="player_lane ${match.laneResult}">${laneSVG[match.laneResult]}</div></td>
525
+ <td style="line-height: 20px">${moment(new Date(match.endDateTime * 1000)).format("YYYY-MM-DD HH:mm:ss").slice(2)}</td>
526
+ <td>${utils.sec2time(match.durationSeconds)}</td>
527
+ <td>${(match.players[0].imp > 0 ? "+" : "") + match.players[0].imp}</td>
528
+ <td><img class="medal" src="${utils.getImageUrl("medal_" + match.rank.toString().split("")[0])}" style="width: 100%" /></td>
529
+ </tr>`).join("")%>
530
+ </tbody>
531
+ </table>
532
+ <div class="plus">
533
+ <%- player.dotaPlus.map((hero) => `
534
+ <div class="hero">
535
+ <img src="${utils.getImageUrl(hero.shortName, ImageType.Heroes)}" alt="" />
536
+ <div class="level"><img src="${utils.getImageUrl("hero_badge_" + Math.ceil((hero.level + 1) / 6))}" alt="" /><span>${hero.level}</span></div>
537
+ <span>${((hero.winCount / hero.matchCount) * 100).toFixed(2)}%</span>
538
+ <span>${hero.matchCount}</span>
539
+ </div>`).join("") %>
540
+ </div>
541
+ </div>
542
+ </body>
543
+ </html>