@sjtdev/koishi-plugin-dota2tracker 1.5.2 → 1.5.4

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sjtdev/koishi-plugin-dota2tracker",
3
3
  "description": "koishi插件-追踪群友的DOTA2对局",
4
- "version": "1.5.2",
4
+ "version": "1.5.4",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -27,12 +27,12 @@
27
27
  "dota2"
28
28
  ],
29
29
  "dependencies": {
30
- "dotaconstants": "^9.4.0",
30
+ "dotaconstants": "^9.5.0",
31
31
  "ejs": "^3.1.10",
32
32
  "moment": "^2.30.1"
33
33
  },
34
34
  "peerDependencies": {
35
- "koishi": "^4.18.7"
35
+ "koishi": "^4.18.8"
36
36
  },
37
37
  "koishi": {
38
38
  "description": {
@@ -11,7 +11,6 @@
11
11
  background-color: black;
12
12
  color: white;
13
13
  width: 800px;
14
- font-family: 'MiSans', sans-serif;
15
14
  }
16
15
  p {
17
16
  margin: 0;
@@ -125,6 +124,12 @@
125
124
  width: 32px;
126
125
  }
127
126
  </style>
127
+
128
+ <% if (fontFamily && fontFamily.length > 0) { %>
129
+ <%- "<style>" %>
130
+ <%- `body { font-family: ${fontFamily.map(f => `${f}`).join(", ")}; }` %>
131
+ <%- "</style>" %>
132
+ <% } %>
128
133
  </head>
129
134
  <body>
130
135
  <% const users = data;
@@ -11,7 +11,6 @@
11
11
  background-color: black;
12
12
  color: white;
13
13
  width: 800px;
14
- font-family: 'MiSans', sans-serif;
15
14
  }
16
15
 
17
16
  .wrapper > *:not(.skills) {
@@ -616,6 +615,12 @@
616
615
  color: #aaa;
617
616
  }
618
617
  </style>
618
+
619
+ <% if (fontFamily && fontFamily.length > 0) { %>
620
+ <%- "<style>" %>
621
+ <%- `body { font-family: ${fontFamily.map(f => `${f}`).join(", ")}; }` %>
622
+ <%- "</style>" %>
623
+ <% } %>
619
624
  </head>
620
625
  <body>
621
626
  <% let hero = data; %>
Binary file
@@ -1 +1 @@
1
- <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>
1
+ <svg viewBox="0 0 24 24"><path fill="green" 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>
@@ -1 +1 @@
1
- <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>
1
+ <svg viewBox="-1 0 19 19"><path fill="red" 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>
@@ -1 +1 @@
1
- <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>
1
+ <svg viewBox="0 0 512 512"><path fill="lightgreen" 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>
@@ -35,6 +35,9 @@ const valueMap = item.special_values.reduce((map, val) => {
35
35
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
36
36
  <%- `<style>` %>
37
37
  <%- include('./item/style.css') %>
38
+ <% if (fontFamily && fontFamily.length > 0) { %>
39
+ <%- `body { font-family: ${fontFamily.map(f => `${f}`).join(", ")}; }` %>
40
+ <% } %>
38
41
  <%- `</style>` %>
39
42
  </head>
40
43
  <body>
@@ -76,6 +76,12 @@ function calculateFontSize(text) {
76
76
  min-height: 12px;
77
77
  }
78
78
  </style>
79
+
80
+ <% if (fontFamily && fontFamily.length > 0) { %>
81
+ <%- "<style>" %>
82
+ <%- `body { font-family: ${fontFamily.map(f => `${f}`).join(", ")}; }` %>
83
+ <%- "</style>" %>
84
+ <% } %>
79
85
  </head>
80
86
  <body>
81
87
  <% const items = data; %>
@@ -0,0 +1,11 @@
1
+ <% const isRecipe = item?.isRecipe ? ` style="background-image: url('${utils.getImageUrl("recipe", ImageType.Items)}');"` : ''; %>
2
+ <div class="relative <%= style %>"<%- isRecipe %>>
3
+ <% if (item) { %>
4
+ <% if (!isNeutral) { %>
5
+ <img class="w-full h-full object-cover <%= item.isRecipe ? "opacity-75 scale-[0.6] origin-top-right" : '' %>" src="<%= utils.getImageUrl(item.name, ImageType.Items) %>">
6
+ <p class="absolute w-full text-[#ccc] text-center bottom-0 leading-[1] text-xs bg-stone-700/50"><%= utils.sec2time(item.time) %></p>
7
+ <% } else { %>
8
+ <img class="w-full h-full object-contain" src="<%= utils.getImageUrl(dotaconstants.item_ids[player.neutral0Id], ImageType.Items) %>">
9
+ <% } %>
10
+ <% } %>
11
+ </div>
@@ -0,0 +1,35 @@
1
+ <div class="w-[790px] h-[100px] flex justify-between box m-[5px]">
2
+ <div class="flag w-[100px] h-full flex justify-center items-end bg-cover <%= !match.didRadiantWin ? 'grayscale' : "" %>" style="background-image: url('<%= utils.getImageUrl("flag_radiant") %>')"><%= match.didRadiantWin ? $t("dota2tracker.template.won") : "" %></div>
3
+ <div class="details grow relative flex-col flex">
4
+ <p class="w-full flex justify-around">
5
+ <span><%= $t("dota2tracker.template.match_id_") %><%= match.id %></span>
6
+ <span><%= $t("dota2tracker.template.game_mode_") %><%= $t("dota2tracker.template.lobby_types." + match.lobbyType) || match.lobbyType %> / <%= $t("dota2tracker.template.game_modes." + match.gameMode) || match.gameMode %></span>
7
+ <span><%= $t("dota2tracker.template.region_") %><%= $t("dota2tracker.template.regions." + match.regionId) %></span>
8
+ </p>
9
+ <p class="w-full flex justify-around">
10
+ <span><%= $t("dota2tracker.template.start_time_") %><%= moment(new Date(match.startDateTime * 1000)).format("YYYY-MM-DD HH:mm:ss").slice(2) %></span>
11
+ <span><%= $t("dota2tracker.template.end_time_") %><%= moment(new Date(match.endDateTime * 1000)).format("YYYY-MM-DD HH:mm:ss").slice(2) %></span>
12
+ </p>
13
+ <p class="w-full grow score flex justify-evenly items-end">
14
+ <span class="score radiant text-3xl"><%= match.radiant.killsCount %></span>
15
+ <span class="time text-sm"><%= utils.sec2time(match.durationSeconds) %></span>
16
+ <span class="score dire text-3xl"><%= match.dire.killsCount %></span>
17
+ </p>
18
+ <img class="star absolute w-[64px] bottom-[10px] left-1/2 -translate-x-1/2" src="<%= utils.getImageUrl('star_' + (match.rank ? match.rank.toString().split('')[1] : '')) %>">
19
+ <img class="medal absolute w-[64px] bottom-[10px] left-1/2 -translate-x-1/2" src="<%= utils.getImageUrl('medal_' + (match.rank ? match.rank.toString().split('')[0] : '')) %>">
20
+ </div>
21
+ <div class="flag w-[100px] h-full flex justify-center items-end bg-cover <%= match.didRadiantWin ? 'grayscale' : "" %>" style="background-image: url('<%= utils.getImageUrl("flag_dire") %>')"><%= !match.didRadiantWin ? $t("dota2tracker.template.won") : "" %></div>
22
+ </div>
23
+ <div class="w-[790px] grid grid-cols-2 gap-[5px] mx-[5px]">
24
+ <% for( let index = 0; index < match.players.length; index++ ) { %>
25
+ <%- include(`./player.ejs`, { match, player: match.players[index], kcndcStyle, laneSVG, facetColor, partyColor }) %>
26
+ <% } %>
27
+ </div>
28
+ <div class="ban_list box m-[5px] flex flex-wrap">
29
+ <% for (const hero of (match.pickBans ?? []).filter(x => !x.isPick)) { %>
30
+ <div class="ban_hero relative w-[10%]">
31
+ <i class="absolute w-full h-full z-1" style="background-image: linear-gradient(to bottom left, transparent calc(50% - 1px), red calc(50% - 1px), black calc(50% + 1px), transparent calc(50% + 1px));"></i>
32
+ <img class="grayscale" src="<%= utils.getImageUrl(/^npc_dota_hero_(?<name>.+)$/.exec(dotaconstants.heroes[hero.bannedHeroId].name)[1], ImageType.Heroes) %>" alt="" />
33
+ </div>
34
+ <% } %>
35
+ </div>
@@ -0,0 +1,154 @@
1
+ <div class="box h-[320px] flex flex-col gap-[4px] rounded-[5px]" <%- `style="grid-column: ${!player.isRadiant+1};grid-row: ${player.position?.slice(-1)%5}" ` %>>
2
+ <section class="grid grid-cols-[112px_1fr_100px] grid-rows-[63px_24px]">
3
+ <div class="avatar relative h-full relative row-1 col-1 text-[10px] text-shadow-[-1px_1px_2px_#000,1px_-1px_2px_#000,-1px_1px_2px_#000,1px_1px_2px_#000]">
4
+ <% if (player.leaverStatus != "NONE" && player.leaverStatus != "DISCONNECTED") { %>
5
+ <img class="leaver absolute w-full h-full object-contain" src="<%= utils.getImageUrl("disconnected") %>" />
6
+ <% } %>
7
+ <div class="party contents">
8
+ <i class="party_line absolute w-full h-[2px]" <%- `style="background-color:${partyColor[player.partyId]};"` %>></i>
9
+ <b class="party_mark absolute leading-[1.5] w-[16px] top-[3px] left-[2px] bg-black/80 text-center" <%- `style="color:${partyColor[player.partyId]};"` %>><%= match.party[player.partyId] %></b>
10
+ </div>
11
+ <div class="hero_info absolute top-[3px] right-0 text-right leading-[1.25]">
12
+ <p class="order" <%- `style="color: ${['red', 'yellow', 'green'][Math.floor(player.order / 4)]};"` %>><%- player.isRandom ? $t("dota2tracker.template.random") : $t("dota2tracker.template.pick_order",[`${player.order == null ? "?" : player.order + 1}`]) %></p>
13
+ <p class="position"><%= $t("dota2tracker.template.position_" + player.position?.slice(-1))??'' %></p>
14
+ </div>
15
+ <p class="level absolute bottom-0 right-0 text-xs px-[2px]"><%= player.level %></p>
16
+ <img class="h-full" src="<%= utils.getImageUrl(player.hero.shortName, ImageType.Heroes) %>" />
17
+ </div>
18
+ <div class="player_profile mx-[10px] row-1 col-2 w-auto h-full overflow-hidden text-center flex flex-col justify-around leading-[1]">
19
+ <p class="player_name truncate max-w-full"><%= player.steamAccount.name %></p>
20
+ <p class="flex gap-[12px] justify-center">
21
+ <span class="kda"><%= player.kills %>/<%= player.deaths %>/<%= player.assists %></span>
22
+ <span class="kc" <%- `style="color:${kcndcStyle.kc(player.killContribution * 100)}"` %>><%= Math.floor(player.killContribution * 100) %>%</span>
23
+ <span class="dc" <%- `style="color:${kcndcStyle.dc(player.deathContribution * 100)}"` %>><%= Math.floor(player.deathContribution * 100) %>%</span>
24
+ </p>
25
+ <p class="flex gap-[16px] justify-center">
26
+ <span class="networth text-[rgb(203,176,42)]"><%= player.networth %></span>
27
+ <span class="score"><%= (player.heroDamage / player.networth)?.toFixed(2) %></span>
28
+ </p>
29
+ </div>
30
+ <div class="lane_rank row-1 col-3 flex w-full h-full justify-between">
31
+ <div class="lane w-[44px] h-full">
32
+ <p class="text-[10px] text-center"><%= $t("dota2tracker.template.lane_" + player.laneResult) %></p>
33
+ <div class="h-[44px] w-[44px]"><%- laneSVG[player.laneResult] %></div>
34
+ </div>
35
+ <div class="rank_plus w-[36px] h-full relative text-[10px] leading-[1.15] text-shadow-[-1px_1px_0_#000,1px_-1px_0_#000,-1px_1px_0_#000,1px_1px_0_#000]">
36
+ <div class="rank absolute top-0 size-[36px] z-2">
37
+ <img class="medal absolute inset-0" src="<%= utils.getImageUrl('medal_' + (player.rank.inTop100 ?? player.rank.medal)) %>"/>
38
+ <img class="stars absolute inset-0" src="<%= utils.getImageUrl('star_' + player.rank.star) %>" />
39
+ <p class="leader absolute bottom-0 text-center w-full"><%= player.steamAccount?.seasonLeaderboardRank ?? "" %></p>
40
+ </div>
41
+ <% if (player.dotaPlus) { %>
42
+ <div class="plus absolute bottom-0 size-[36px] z-1">
43
+ <img class="" src="<%= utils.getImageUrl("hero_badge_" + (player.dotaPlus ? Math.ceil((player.dotaPlus?.level + 1) / 6) : 1)) %>">
44
+ <p class="level absolute bottom-0 text-center w-full"><%= player.dotaPlus?.level %></p>
45
+ </div>
46
+ <% } %>
47
+ </div>
48
+ </div>
49
+ <div class="facet row-2 col-1 w-full h-full flex bg-linear-to-r
50
+ <%- facetColor[player.facet?.color ?? 'Black'] %>">
51
+ <% if (player.facet) { %>
52
+ <div class="w-[24px] h-[24px] flex items-center justify-center bg-[#4444]">
53
+ <img class="h-[18px]" src="<%= utils.getImageUrl(player.facet?.icon, ImageType.IconsFacets) %>" />
54
+ </div>
55
+ <% } %>
56
+ <div class="facet_name grow text-sm flex justify-center items-center"><%= player.facet?.name ?? "?" %></div>
57
+ </div>
58
+ <div class="titles row-2 col-start-2 col-end-3 w-full flex items-center pl-[12px] gap-[6px]">
59
+ <% for (let item of player.titles) { %>
60
+ <% const [title, color] = $t(item).split("-"); %>
61
+ <span <%- `style="color:${color};"` %>><%= title %></span>
62
+ <% } %>
63
+ </div>
64
+ </section>
65
+ <% if (player.hero.id != 80) { %>
66
+ <section class="items w-full grid grid-cols-[repeat(3,3fr)_2fr_3fr] grid-rows-2">
67
+ <div class="items_main contents">
68
+ <% for( let i = 0; i < 6; i++ ) { %>
69
+ <%- include("./item.ejs", {item: player.items[i], style: `col-${i%3+1}`, isNeutral: false}) %>
70
+ <% } %>
71
+ </div>
72
+ <div class="items_backpack grayscale col-4 row-start-1 row-span-2 flex flex-col">
73
+ <% for( let i = 0; i < 3; i++ ) { %>
74
+ <%- include("./item.ejs", {item: player.backpacks[i], style: "", isNeutral: false}) %>
75
+ <% } %>
76
+ </div>
77
+ <div class="items_neutral contents"><%- include("./item.ejs", {item: player.neutral0Id, style: "row-start-1 row-span-2 col-5 flex items-center h-full", isNeutral: true}) %></div>
78
+ </section>
79
+ <% } else { %>
80
+ <section class="items w-full grid grid-cols-[repeat(6,3fr)_10fr] grid-rows-4">
81
+ <div class="items_hero contents">
82
+ <div class="items_main contents">
83
+ <% for( let i = 0; i < 6; i++ ) { %>
84
+ <%- include("./item.ejs", {item: player.items[i], style: `row-1 col-${i+1}`, isNeutral: false}) %>
85
+ <% } %>
86
+ </div>
87
+ <div class="items_backpack grayscale contents">
88
+ <% for( let i = 0; i < 3; i++ ) { %>
89
+ <%- include("./item.ejs", {item: player.backpacks[i], style: `row-2 col-${i+1}`, isNeutral: false}) %>
90
+ <% } %>
91
+ </div>
92
+ <div class="items_neutral contents">
93
+ <%- include("./item.ejs", {item: player.neutral0Id, style: "row-2 col-6", isNeutral: true}) %>
94
+ </div>
95
+ </div>
96
+ <div class="items_unit contents">
97
+ <div class="items_main contents">
98
+ <% for( let i = 0; i < 6; i++ ) { %>
99
+ <%- include("./item.ejs", {item: player.unitItems[i], style: `row-3 col-${i+1}`, isNeutral: false}) %>
100
+ <% } %>
101
+ </div>
102
+ <div class="items_backpack grayscale contents">
103
+ <% for( let i = 0; i < 3; i++ ) { %>
104
+ <%- include("./item.ejs", {item: player.unitBackpacks[i], style: `row-4 col-${i+1}`, isNeutral: false}) %>
105
+ <% } %>
106
+ </div>
107
+ <div class="items_neutral contents">
108
+ <%- include("./item.ejs", {item: player.additionalUnit.neutral0Id, style: "row-4 col-6", isNeutral: true}) %>
109
+ </div>
110
+ </div>
111
+ </section>
112
+ <% } %>
113
+ <section class="buffs_supports w-full h-[24px] flex justify-between">
114
+ <div class="buffs flex h-[24px]">
115
+ <% for (const buff of player.buffs) { %>
116
+ <div class="relative">
117
+ <img class="w-[33px] h-[24px]" src="<%= utils.getImageUrl(dotaconstants[`${buff.type}_ids`][buff.id], ImageType[buff.type === "ability" ? "Abilities" : "Items"]) %>" />
118
+ <p class="count absolute w-full bottom-0 leading-[1] text-center bg-stone-700/50 text-[10px]"><%= buff.stackCount || "" %></p>
119
+ </div>
120
+ <% } %>
121
+ </div>
122
+ <div class="supports flex h-[24px]">
123
+ <% for (const supportItem of player.supportItemsCount){ %>
124
+ <div class="relative">
125
+ <img class="w-[33px] h-[24px]" src="<%= utils.getImageUrl(supportItem.name, ImageType.Items) %>" />
126
+ <p class="count absolute w-full bottom-0 leading-[1] text-center bg-stone-700/50 text-[10px]"><%= supportItem.count || "" %></p>
127
+ </div>
128
+ <% } %>
129
+ </div>
130
+ </section>
131
+ <section class="player-stat h-full flex flex-col justify-around text-[13px] leading-[24px] whitespace-nowrap">
132
+ <p class="w-full flex justify-around">
133
+ <span><%= $t("dota2tracker.template.hero_damage_") %><span class="hero_damage"><%= player.heroDamage %></span></span>
134
+ <span><%= $t("dota2tracker.template.building_damage_") %><span class="building_damage"><%= player.towerDamage %></span></span>
135
+ <span><%= $t("dota2tracker.template.damage_received_") %><span class="tak">
136
+ <%= (player.stats?.heroDamageReport?.receivedTotal.physicalDamage || 0) +
137
+ (player.stats?.heroDamageReport?.receivedTotal.magicalDamage || 0) +
138
+ (player.stats?.heroDamageReport?.receivedTotal.pureDamage || 0) %>
139
+ </span>
140
+ </span>
141
+ </p>
142
+ <p class="w-full flex justify-around">
143
+ <span><%= $t("dota2tracker.template.lasthit_") %><span class="lh"><%= player.numLastHits %></span>/<span class="dn"><%= player.numDenies %></span></span>
144
+ <span><%= $t("dota2tracker.template.GPM/XPM_") %><span class="gpm"><%= player.goldPerMinute %></span>/<span class="xpm"><%= player.experiencePerMinute %></span></span>
145
+ <span><%= $t("dota2tracker.template.heal_") %><span class="heal"><%= player.heroHealing %></span></span>
146
+ </p>
147
+ <p class="w-full flex justify-center">
148
+ <span><%= $t("dota2tracker.template.crowd_control_duration_") %></span>
149
+ <span><%= ((player.stats?.heroDamageReport?.dealtTotal.stunDuration || 0) / 100).toFixed(2) + "/" %></span>
150
+ <span><%= ((player.stats?.heroDamageReport?.dealtTotal.slowDuration || 0) / 100).toFixed(2) + "/" %></span>
151
+ <span><%= ((player.stats?.heroDamageReport?.dealtTotal.disableDuration || 0) / 100).toFixed(2) %></span>s
152
+ </p>
153
+ </section>
154
+ </div>