@sjtdev/koishi-plugin-dota2tracker 2.5.6 → 2.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/changelog.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # 更新日志
2
2
 
3
+ ### [2.5.7](https://github.com/sjtdev/koishi-plugin-dota2tracker/compare/v2.5.6...v2.5.7) (2026-03-25)
4
+
5
+ ### 🚀 功能优化
6
+
7
+ * 跟进`DOTA2 7.41`移除命石系统更新,全面清理`facet`相关代码以优化性能与减小存储占用 ([5842fd0](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/5842fd0d9925c361b0bccf8c0db9ab861cc4c47d))
8
+
9
+ ### 🐛 Bug 修复
10
+
11
+ * **template:** 修复因`2.4.0`重写ejs读取图片逻辑导致`match_1` `player_1`模板中对线结果图片显示错误的问题 ([d619b10](https://github.com/sjtdev/koishi-plugin-dota2tracker/commit/d619b10abd15a22eae052c725070b0db976ca097))
12
+
3
13
  ### [2.5.6](https://github.com/sjtdev/koishi-plugin-dota2tracker/compare/v2.5.5...v2.5.6) (2026-03-12)
4
14
 
5
15
  ### 🐛 Bug 修复
package/lib/index.js CHANGED
@@ -1144,55 +1144,8 @@ var HeroService = class _HeroService extends import_koishi2.Service {
1144
1144
  }
1145
1145
  static formatHeroDetails(rawHero) {
1146
1146
  let hero = Object.assign({}, rawHero);
1147
- hero.facet_abilities.forEach((fa, i) => {
1148
- if (fa.abilities.length) {
1149
- fa.abilities.forEach((ab) => {
1150
- if (!hero.facets[i].abilities) hero.facets[i].abilities = [];
1151
- if (hero.facets[i].description_loc !== ab.desc_loc)
1152
- hero.facets[i].abilities.push({
1153
- id: ab.id,
1154
- name: ab.name,
1155
- name_loc: ab.name_loc,
1156
- description_ability_loc: this.formatHeroDesc(ab.desc_loc, ab.special_values, "facet" /* Facet */)
1157
- });
1158
- else hero.facets[i].description_loc = this.formatHeroDesc(hero.facets[i].description_loc, ab.special_values, "facet" /* Facet */);
1159
- ab.ability_is_facet = true;
1160
- ab.facet = hero.facets[i];
1161
- hero.abilities.push(ab);
1162
- });
1163
- }
1164
- });
1165
- const all_special_values = [...hero.abilities.flatMap((ab) => ab.special_values), ...hero.facet_abilities.flatMap((fas) => fas.abilities.flatMap((fa) => fa.special_values))];
1166
1147
  hero.abilities.forEach((ab) => {
1167
- ab.facets_loc.forEach((facet, i) => {
1168
- i = i + (hero.facets.length - ab.facets_loc.length);
1169
- if (i < 0) return;
1170
- if (facet) {
1171
- if (!hero.facets[i].abilities) hero.facets[i].abilities = [];
1172
- hero.facets[i].abilities.push({
1173
- id: ab.id,
1174
- name: ab.name,
1175
- name_loc: ab.name_loc,
1176
- description_ability_loc: this.formatHeroDesc(facet, ab.special_values, "facet" /* Facet */),
1177
- attributes: []
1178
- });
1179
- }
1180
- });
1181
- hero.facets.forEach((facet) => {
1182
- const svs = ab.special_values.filter((sv) => sv.facet_bonus.name === facet.name);
1183
- svs.forEach((sv) => {
1184
- if (sv.heading_loc) {
1185
- if (!facet.abilities) facet.abilities = [];
1186
- facet.abilities.find((ability) => ab.id == ability.id)?.attributes.push({
1187
- heading_loc: sv.heading_loc,
1188
- values: [...sv.facet_bonus.values],
1189
- is_percentage: sv.is_percentage
1190
- });
1191
- }
1192
- });
1193
- facet.description_loc = this.formatHeroDesc(facet.description_loc, svs, "facet" /* Facet */);
1194
- });
1195
- ab.desc_loc = this.formatHeroDesc(ab.desc_loc, ab.special_values, ab.ability_is_facet ? "facet" /* Facet */ : void 0);
1148
+ ab.desc_loc = this.formatHeroDesc(ab.desc_loc, ab.special_values);
1196
1149
  ab.notes_loc = ab.notes_loc.map((note) => this.formatHeroDesc(note, ab.special_values));
1197
1150
  if (ab.ability_has_scepter) ab.scepter_loc = this.formatHeroDesc(ab.scepter_loc, ab.special_values, "scepter" /* Scepter */);
1198
1151
  if (ab.ability_has_shard) ab.shard_loc = this.formatHeroDesc(ab.shard_loc, ab.special_values, "shard" /* Shard */);
@@ -1245,9 +1198,6 @@ var HeroService = class _HeroService extends import_koishi2.Service {
1245
1198
  if (specialValue) {
1246
1199
  let valuesToUse = "";
1247
1200
  switch (type) {
1248
- case "facet" /* Facet */:
1249
- valuesToUse = specialValue.facet_bonus.name ? specialValue.facet_bonus.values.join(" / ") : specialValue.values_float.join(" / ");
1250
- break;
1251
1201
  case "scepter" /* Scepter */:
1252
1202
  valuesToUse = specialValue.values_scepter.length ? specialValue.values_scepter.join(" / ") : specialValue.values_float.join(" / ");
1253
1203
  break;
@@ -1610,49 +1560,12 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1610
1560
  }
1611
1561
  }
1612
1562
  async formatMatchData(matchQuery, languageTag) {
1613
- try {
1614
- let constantsQuery = await this.ctx.dota2tracker.cache.getFacetConstantsCache(languageTag);
1615
- const isFromOpenDota = matchQuery.match?.odParsed === true;
1616
- let needsRefetch = false;
1617
- if (!constantsQuery) {
1618
- needsRefetch = true;
1619
- } else if (!isFromOpenDota) {
1620
- if (!matchQuery.constants?.gameVersions?.[0]?.id || !constantsQuery.constants?.gameVersions?.[0]?.id || matchQuery.constants.gameVersions[0].id !== constantsQuery.constants.gameVersions[0].id) {
1621
- needsRefetch = true;
1622
- }
1623
- }
1624
- if (needsRefetch) {
1625
- constantsQuery = await this.ctx.dota2tracker.stratzAPI.queryConstants(languageTag);
1626
- }
1627
- const facetData = await _MatchService.constantsInjectFacetData(constantsQuery, matchQuery, languageTag, this.ctx.dota2tracker.hero);
1628
- this.ctx.dota2tracker.cache.setFacetConstantsCache(languageTag, constantsQuery);
1629
- const match = _MatchService.extendMatchData(matchQuery, facetData, this.ctx.dota2tracker.dotaconstants);
1630
- this.recordMatchExtension(match);
1631
- return match;
1632
- } catch (error) {
1633
- this.ctx.dota2tracker.cache.deleteFacetConstantsCache(languageTag);
1634
- throw error;
1635
- }
1636
- }
1637
- static async constantsInjectFacetData(constantsQuery, matchQuery, languageTag, heroService) {
1638
- const facetData = {};
1639
- for (let player of matchQuery.match?.players) {
1640
- if (player.variant != null) {
1641
- const constantsFacet = constantsQuery.constants.facets.find((facet) => facet.id === player.hero.facets[player.variant - 1]?.facetId || facet.name === player.hero.facets[player.variant - 1]?.name);
1642
- let displayName = constantsFacet?.language?.displayName;
1643
- if (!displayName && heroService) {
1644
- const valveFacet = (await heroService.getHeroDetails(player.hero.id, languageTag)).facets.find((facet) => facet.index === player.variant - 1);
1645
- constantsFacet.language.displayName = valveFacet.title_loc;
1646
- constantsFacet.name = valveFacet.name;
1647
- constantsFacet.icon = valveFacet.icon;
1648
- }
1649
- facetData[player.steamAccountId] = { id: constantsFacet.id, name: constantsFacet.name, icon: constantsFacet.icon, color: constantsFacet.color, displayName: constantsFacet.language?.displayName };
1650
- }
1651
- }
1652
- return facetData;
1563
+ const match = _MatchService.extendMatchData(matchQuery, this.ctx.dota2tracker.dotaconstants);
1564
+ this.recordMatchExtension(match);
1565
+ return match;
1653
1566
  }
1654
1567
  // 对比赛数据进行补充以供生成模板函数使用
1655
- static extendMatchData(matchQuery, facetData, dotaconstants) {
1568
+ static extendMatchData(matchQuery, dotaconstants) {
1656
1569
  const match = matchQuery.match;
1657
1570
  const matchParsed = _MatchService.isMatchParsed(matchQuery);
1658
1571
  ["radiant", "dire"].forEach((team) => {
@@ -1819,7 +1732,6 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1819
1732
  }
1820
1733
  }
1821
1734
  player.formattedNetworth = formatNumber(player.networth);
1822
- player.facet = facetData[player.steamAccountId];
1823
1735
  player.titles = [];
1824
1736
  player.mvpScore = // 计算MVP分数
1825
1737
  player.kills * 5 + player.assists * 3 + (player.stats.heroDamageReport?.dealtTotal.stunDuration ?? 0) / 100 * 0.1 + (player.stats.heroDamageReport?.dealtTotal.disableDuration ?? 0) / 100 * 0.05 + (player.stats.heroDamageReport?.dealtTotal.slowDuration ?? 0) / 100 * 0.025 + player.heroDamage * 1e-3 + player.towerDamage * 0.01 + player.heroHealing * 2e-3 + player.imp * 0.25 + player.utilityScore * 5e-3;
@@ -2294,15 +2206,6 @@ var CacheService = class extends import_koishi6.Service {
2294
2206
  }
2295
2207
  return sendedIds;
2296
2208
  }
2297
- async getFacetConstantsCache(languageTag) {
2298
- return this.ctx.cache.get("dt_facets_constants", languageTag);
2299
- }
2300
- setFacetConstantsCache(languageTag, constants) {
2301
- this.ctx.cache.set("dt_facets_constants", languageTag, constants, DAYS_30);
2302
- }
2303
- deleteFacetConstantsCache(languageTag) {
2304
- this.ctx.cache.delete("dt_facets_constants", languageTag);
2305
- }
2306
2209
  };
2307
2210
 
2308
2211
  // src/app/data/database.ts
@@ -2564,9 +2467,6 @@ var StratzAPI = class extends import_koishi8.Service {
2564
2467
  async queryPlayersLastMatchRankInfo({ steamAccountIds }) {
2565
2468
  return this.query("PlayersLastmatchRankinfo", { steamAccountIds }, (data) => !!data?.players);
2566
2469
  }
2567
- async queryConstants(languageTag) {
2568
- return this.query("Constants", { language: this.ctx.dota2tracker.i18n.getGraphqlLanguageTag(languageTag) }, (data) => !!data?.constants);
2569
- }
2570
2470
  async queryMatchInfo(matchId) {
2571
2471
  return this.query("MatchInfo", { matchId }, (data) => !!data?.match);
2572
2472
  }
@@ -2751,7 +2651,6 @@ var import_node_path2 = __toESM(require("node:path"));
2751
2651
  // src/app/common/types.ts
2752
2652
  var ImageType = /* @__PURE__ */ ((ImageType2) => {
2753
2653
  ImageType2["Icons"] = "icons";
2754
- ImageType2["IconsFacets"] = "icons/facets";
2755
2654
  ImageType2["Heroes"] = "heroes";
2756
2655
  ImageType2["HeroIcons"] = "heroes/icons";
2757
2656
  ImageType2["HeroStats"] = "heroes/stats";
@@ -4239,8 +4138,7 @@ var OpenDotaAdapter = class extends import_koishi17.Service {
4239
4138
  hero: {
4240
4139
  id: _player.hero_id,
4241
4140
  name: this.ctx.dota2tracker.dotaconstants.heroes[_player.hero_id].name,
4242
- shortName: this.ctx.dota2tracker.dotaconstants.heroes[_player.hero_id].name.match(/^npc_dota_hero_(.+)$/)[1],
4243
- facets: [...this.ctx.dota2tracker.dotaconstants.hero_abilities[this.ctx.dota2tracker.dotaconstants.heroes[_player.hero_id].name].facets.map((f) => ({ id: -1, name: f.name }))]
4141
+ shortName: this.ctx.dota2tracker.dotaconstants.heroes[_player.hero_id].name.match(/^npc_dota_hero_(.+)$/)[1]
4244
4142
  },
4245
4143
  dotaPlus: null,
4246
4144
  stats: {
@@ -43,9 +43,6 @@ query MatchInfo($matchId: Long!) {
43
43
  id
44
44
  name
45
45
  shortName
46
- facets {
47
- facetId
48
- }
49
46
  }
50
47
  variant
51
48
  dotaPlus {
@@ -2,7 +2,7 @@
2
2
  const base_damage = Math.floor((hero.str_base+hero.agi_base+hero.int_base)*0.45);
3
3
  hero.damage_max+=base_damage;
4
4
  hero.damage_min+=base_damage;
5
- } %> <% const primary_attrs = { "3": "hero_universal", "0": "hero_strength", "1": "hero_agility", "2": "hero_intelligence" }; %> <% const hero_dc = dotaconstants.heroes[hero.id]; %> <div class="wrapper"><div class="hero" id="<%= hero.id %>"><img src="<%= getImageUrl(hero["name"].match(/^npc_dota_hero_(.+)$/)[1], ImageType.Heroes) %>"/> <img class="pri_attr" src="<%= getImageUrl(primary_attrs[hero.primary_attr], ImageType.Icons) %>"/><div class="info"><p class="name"><%= hero.name_loc %></p><p class="roles"> <% hero.role_levels.forEach((item, index) => { %> <% if (item > 0) { %> <span class="role level<%= item %>"><%= $t("dota2tracker.template.roles."+index) %></span> <% } %> <% }); %> </p><p class="attrs"><span class="str"><%= hero.str_base %> <span class="gain">+<%= hero.str_gain.toFixed(1) %></span></span><span class="agi"><%= hero.agi_base %> <span class="gain">+<%= hero.agi_gain.toFixed(1) %></span></span><span class="int"><%= hero.int_base %> <span class="gain">+<%= hero.int_gain.toFixed(1) %></span></span></p></div></div><div class="hype"><p class="npe"><%= hero.npe_desc_loc %></p> <%- hero.hype_loc %> </div><div class="details"><div class="talents"><div class="talent"><div class="left"><%= hero.talents[7].name_loc %></div><div class="level">25</div><div class="right"><%= hero.talents[6].name_loc %></div></div><div class="talent"><div class="left"><%= hero.talents[5].name_loc %></div><div class="level">20</div><div class="right"><%= hero.talents[4].name_loc %></div></div><div class="talent"><div class="left"><%= hero.talents[3].name_loc %></div><div class="level">15</div><div class="right"><%= hero.talents[2].name_loc %></div></div><div class="talent"><div class="left"><%= hero.talents[1].name_loc %></div><div class="level">10</div><div class="right"><%= hero.talents[0].name_loc %></div></div></div><div class="list"><div class="bars"><div class="health"><span class="number"><%= hero.max_health %></span><span class="suffix">+<%= hero.health_regen.toFixed(1) %></span></div><div class="mana<%= !hero.max_mana ? ' zero' : '' %>"><span class="number"><%= hero.max_mana %></span><span class="suffix">+<%= hero.mana_regen.toFixed(1) %></span></div></div><div class="stats"><div class="column"><p><%= $t("dota2tracker.template.attack") %></p><div class="stat"><img src="<%= getImageUrl("icon_damage", ImageType.HeroStats) %>"/> <span><%= hero.damage_min %>~<%= hero.damage_max %></span></div><div class="stat"><img src="<%= getImageUrl("icon_attack_time", ImageType.HeroStats) %>"/> <span><%= hero.attack_rate.toFixed(1) %></span></div><div class="stat"><img src="<%= getImageUrl("icon_attack_range", ImageType.HeroStats) %>"/> <span><%= hero.attack_range %></span></div> <% if (hero_dc.attack_type !== "Melee") { %> <div class="stat"><img src="<%= getImageUrl("icon_projectile_speed", ImageType.HeroStats) %>"/> <span><%= hero.projectile_speed %></span></div> <% } %> </div><div class="column"><p><%= $t("dota2tracker.template.defense") %></p><div class="stat"><img src="<%= getImageUrl("icon_armor", ImageType.HeroStats) %>"/> <span><%= hero.armor.toFixed(1) %></span></div><div class="stat"><img src="<%= getImageUrl("icon_magic_resist", ImageType.HeroStats) %>"/> <span><%= hero.magic_resistance %>%</span></div></div><div class="column"><p><%= $t("dota2tracker.template.mobility") %></p><div class="stat"><img src="<%= getImageUrl("icon_movement_speed", ImageType.HeroStats) %>"/> <span><%= hero.movement_speed %></span></div><div class="stat"><img src="<%= getImageUrl("icon_turn_rate", ImageType.HeroStats) %>"/> <span><%= hero.turn_rate.toFixed(1) %></span></div><div class="stat"><img src="<%= getImageUrl("icon_vision", ImageType.HeroStats) %>"/> <span><%= hero.sight_range_day %> / <%= hero.sight_range_night %></span></div></div></div></div></div><div class="facets"> <% hero.facets.forEach(facet => { %> <div class="facet"><div class="name_back type_<%= facet.color %>"></div><div class="name_line type_<%= facet.color %>"></div><p class="name"><img src="<%= getImageUrl(facet.icon, ImageType.IconsFacets) %>"/> <span><%- facet.title_loc %></span></p><div class="content"> <% if (facet.description_loc && !facet.abilities?.some(ability => ability.description_ability_loc === facet.description_loc)) { %> <p class="description"><%- facet.description_loc %></p> <% } %> <% if (facet.abilities) { %> <% facet.abilities.forEach(ability => { %> <div class="ability"><div class="name"><img src="<%= getImageUrl(ability.name, ImageType.Abilities) %>" onerror="this.onerror=null; this.src='<%= getImageUrl(`innate_icon`, ImageType.Icons) %>';"/> <span><%- ability.name_loc %></span></div> <% if (ability.description_ability_loc) { %> <div class="description"><%- ability.description_ability_loc %></div> <% } %> <% if (ability.attributes && ability.attributes.length) { %> <% ability.attributes.forEach(attr => { %> <div class="attributes"><p><span class="item"><%- attr.heading_loc %></span><span class="values"><%- attr.values.map(value => value + (attr.is_percentage ? "%" : "")).join(" / ") %></span></p></div> <% }); %> <% } %> </div> <% }); %> <% } %> </div></div> <% }); %> </div><div class="skills"> <% hero.abilities.forEach((item) => {
5
+ } %> <% const primary_attrs = { "3": "hero_universal", "0": "hero_strength", "1": "hero_agility", "2": "hero_intelligence" }; %> <% const hero_dc = dotaconstants.heroes[hero.id]; %> <div class="wrapper"><div class="hero" id="<%= hero.id %>"><img src="<%= getImageUrl(hero["name"].match(/^npc_dota_hero_(.+)$/)[1], ImageType.Heroes) %>"/> <img class="pri_attr" src="<%= getImageUrl(primary_attrs[hero.primary_attr], ImageType.Icons) %>"/><div class="info"><p class="name"><%= hero.name_loc %></p><p class="roles"> <% hero.role_levels.forEach((item, index) => { %> <% if (item > 0) { %> <span class="role level<%= item %>"><%= $t("dota2tracker.template.roles."+index) %></span> <% } %> <% }); %> </p><p class="attrs"><span class="str"><%= hero.str_base %> <span class="gain">+<%= hero.str_gain.toFixed(1) %></span></span><span class="agi"><%= hero.agi_base %> <span class="gain">+<%= hero.agi_gain.toFixed(1) %></span></span><span class="int"><%= hero.int_base %> <span class="gain">+<%= hero.int_gain.toFixed(1) %></span></span></p></div></div><div class="hype"><p class="npe"><%= hero.npe_desc_loc %></p> <%- hero.hype_loc %> </div><div class="details"><div class="talents"><div class="talent"><div class="left"><%= hero.talents[7].name_loc %></div><div class="level">25</div><div class="right"><%= hero.talents[6].name_loc %></div></div><div class="talent"><div class="left"><%= hero.talents[5].name_loc %></div><div class="level">20</div><div class="right"><%= hero.talents[4].name_loc %></div></div><div class="talent"><div class="left"><%= hero.talents[3].name_loc %></div><div class="level">15</div><div class="right"><%= hero.talents[2].name_loc %></div></div><div class="talent"><div class="left"><%= hero.talents[1].name_loc %></div><div class="level">10</div><div class="right"><%= hero.talents[0].name_loc %></div></div></div><div class="list"><div class="bars"><div class="health"><span class="number"><%= hero.max_health %></span><span class="suffix">+<%= hero.health_regen.toFixed(1) %></span></div><div class="mana<%= !hero.max_mana ? ' zero' : '' %>"><span class="number"><%= hero.max_mana %></span><span class="suffix">+<%= hero.mana_regen.toFixed(1) %></span></div></div><div class="stats"><div class="column"><p><%= $t("dota2tracker.template.attack") %></p><div class="stat"><img src="<%= getImageUrl("icon_damage", ImageType.HeroStats) %>"/> <span><%= hero.damage_min %>~<%= hero.damage_max %></span></div><div class="stat"><img src="<%= getImageUrl("icon_attack_time", ImageType.HeroStats) %>"/> <span><%= hero.attack_rate.toFixed(1) %></span></div><div class="stat"><img src="<%= getImageUrl("icon_attack_range", ImageType.HeroStats) %>"/> <span><%= hero.attack_range %></span></div> <% if (hero_dc.attack_type !== "Melee") { %> <div class="stat"><img src="<%= getImageUrl("icon_projectile_speed", ImageType.HeroStats) %>"/> <span><%= hero.projectile_speed %></span></div> <% } %> </div><div class="column"><p><%= $t("dota2tracker.template.defense") %></p><div class="stat"><img src="<%= getImageUrl("icon_armor", ImageType.HeroStats) %>"/> <span><%= hero.armor.toFixed(1) %></span></div><div class="stat"><img src="<%= getImageUrl("icon_magic_resist", ImageType.HeroStats) %>"/> <span><%= hero.magic_resistance %>%</span></div></div><div class="column"><p><%= $t("dota2tracker.template.mobility") %></p><div class="stat"><img src="<%= getImageUrl("icon_movement_speed", ImageType.HeroStats) %>"/> <span><%= hero.movement_speed %></span></div><div class="stat"><img src="<%= getImageUrl("icon_turn_rate", ImageType.HeroStats) %>"/> <span><%= hero.turn_rate.toFixed(1) %></span></div><div class="stat"><img src="<%= getImageUrl("icon_vision", ImageType.HeroStats) %>"/> <span><%= hero.sight_range_day %> / <%= hero.sight_range_night %></span></div></div></div></div></div><div class="skills"> <% hero.abilities.forEach((item) => {
6
6
  const ability_dc = dotaconstants.abilities[item.name];
7
7
 
8
8
  // 预先查找冷却和耗蓝数据,避免在HTML中反复find
@@ -12,24 +12,14 @@
12
12
  // 预先计算是否需要显示冷却/耗蓝 (非空 且 不全为0)
13
13
  const hasCd = cdStats?.values_float.length && !(cdStats.values_float.length === 1 && cdStats.values_float[0] === 0);
14
14
  const hasMana = manaStats?.values_float.length && !(manaStats.values_float.length === 1 && manaStats.values_float[0] === 0);
15
- %> <div class="skill<%= item.facet ? ' facet' : '' %>" data-innate="<%= item.ability_is_innate && !item.ability_is_facet %>"><p class="title<%= item.facet ? (' name_back type_' + item.facet?.color) : '' %>"> <% if (item.facet) { %> <img src="<%= getImageUrl(item.facet?.icon, ImageType.IconsFacets) %>"> <% } %> <span class="name font-serif"><%= item.name_loc %></span> <% if (item.ability_is_innate && !item.ability_is_facet) { %> <span class="is_innate"><%= $t("dota2tracker.template.innate") %></span> <% } %> <% if (item.ability_is_granted_by_scepter) { %> <img src="<%= getImageUrl("scepter") %>" class="scepter"> <% } %> <% if (item.ability_is_granted_by_shard) { %> <img src="<%= getImageUrl("shard") %>" class="shard"> <% } %> </p><div class="img_stats"><img src="<%= getImageUrl(item.name, ImageType.Abilities) %>" onerror="this.onerror=null; this.src='<%= getImageUrl(`innate_icon`, ImageType.Icons) %>';"/><div class="stats"><p class="behavior"> <%= $t("dota2tracker.template.ability") %> <%= [].concat(ability_dc?.behavior)
15
+ %> <div class="skill" data-innate="<%= item.ability_is_innate %>"><p class="title"><span class="name font-serif"><%= item.name_loc %></span> <% if (item.ability_is_innate) { %> <span class="is_innate"><%= $t("dota2tracker.template.innate") %></span> <% } %> <% if (item.ability_is_granted_by_scepter) { %> <img src="<%= getImageUrl("scepter") %>" class="scepter"> <% } %> <% if (item.ability_is_granted_by_shard) { %> <img src="<%= getImageUrl("shard") %>" class="shard"> <% } %> </p><div class="img_stats"><img src="<%= getImageUrl(item.name, ImageType.Abilities) %>" onerror="this.onerror=null; this.src='<%= getImageUrl(`innate_icon`, ImageType.Icons) %>';"/><div class="stats"><p class="behavior"> <%= $t("dota2tracker.template.ability") %> <%= [].concat(ability_dc?.behavior)
16
16
  .filter((beh) => beh !== "Hidden" || !(item.ability_is_granted_by_shard || item.ability_is_granted_by_scepter))
17
- .map((beh) => $t("dota2tracker.template.behavior." + beh)).join("/") %> </p> <% if (ability_dc?.target_team) { %> <p class="target_team"> <%= $t("dota2tracker.template.affects") %> <%= [].concat(ability_dc?.target_team).map((tt) => $t("dota2tracker.template.target_team." + tt)).join("/") %> </p> <% } %> <% if (!Array.isArray(ability_dc?.dmg_type) && ability_dc?.dmg_type) { %> <p class="dmg_type <%= ability_dc?.dmg_type %>"> <%= $t("dota2tracker.template.damage_type") %> <span><%= $t("dota2tracker.template.damage_type_" + ability_dc?.dmg_type) %></span></p> <% } %> <% if (ability_dc?.dispellable) { %> <p class="dispellable <%= ability_dc?.dispellable == 'Strong Dispels Only' ? 'Strong' : ability_dc?.dispellable %>"> <%= $t("dota2tracker.template.dispellable") %> <span><%= $t("dota2tracker.template." + (ability_dc?.dispellable == "Strong Dispels Only" ? "dispellable_Strong" : ability_dc?.dispellable)) %></span></p> <% } %> <% if (!Array.isArray(ability_dc?.bkbpierce) && ability_dc?.bkbpierce) { %> <p class="bkbpierce <%= ability_dc?.bkbpierce %>"> <%= $t("dota2tracker.template.bkbpierce") %> <span><%= $t("dota2tracker.template." + ability_dc?.bkbpierce) %></span></p> <% } %> </div></div><p class="description"><%- item.desc_loc %></p> <%
18
- const facetStartIndex = hero.facets.length - item.facets_loc.length;
19
- item.facets_loc.forEach((facet_loc, i) => {
20
- const realIndex = i + facetStartIndex;
21
- if (realIndex >= 0 && facet_loc !== "") {
22
- const currentFacet = hero.facets[realIndex];
23
- %> <div class="facet"><div class="name_back type_<%= currentFacet.color %>"></div><div class="name_line type_<%= currentFacet.color %>"></div><p class="name"><img src="<%= getImageUrl(currentFacet.icon, ImageType.IconsFacets) %>"/> <span><%- currentFacet.title_loc %></span></p><div class="content"><div class="ability"><div class="description"><%- currentFacet.abilities.find(ab => ab.id == item.id)?.description_ability_loc %></div></div></div></div> <%
24
- }
25
- });
26
- %> <% if (item.ability_has_scepter && !item.ability_is_granted_by_scepter && item.scepter_loc) { %> <p class="aghanim_description"><span class="title"><img src="<%= getImageUrl("scepter") %>" class="scepter"><%= $t("dota2tracker.template.scepter") %></span><span class="desc"><%- item.scepter_loc %></span></p> <% } %> <% if (item.ability_has_shard && !item.ability_is_granted_by_shard && item.shard_loc) { %> <p class="aghanim_description"><span class="title"><img src="<%= getImageUrl("shard") %>" class="shard"><%= $t("dota2tracker.template.shard") %></span><span class="desc"><%- item.shard_loc %></span></p> <% } %> <% if (item.notes_loc && item.notes_loc.length > 0) { %> <div class="notes"> <% item.notes_loc.forEach((note) => { %> <p><%- note %></p> <% }); %> </div> <% } %> <div class="attributes"> <%
17
+ .map((beh) => $t("dota2tracker.template.behavior." + beh)).join("/") %> </p> <% if (ability_dc?.target_team) { %> <p class="target_team"> <%= $t("dota2tracker.template.affects") %> <%= [].concat(ability_dc?.target_team).map((tt) => $t("dota2tracker.template.target_team." + tt)).join("/") %> </p> <% } %> <% if (!Array.isArray(ability_dc?.dmg_type) && ability_dc?.dmg_type) { %> <p class="dmg_type <%= ability_dc?.dmg_type %>"> <%= $t("dota2tracker.template.damage_type") %> <span><%= $t("dota2tracker.template.damage_type_" + ability_dc?.dmg_type) %></span></p> <% } %> <% if (ability_dc?.dispellable) { %> <p class="dispellable <%= ability_dc?.dispellable == 'Strong Dispels Only' ? 'Strong' : ability_dc?.dispellable %>"> <%= $t("dota2tracker.template.dispellable") %> <span><%= $t("dota2tracker.template." + (ability_dc?.dispellable == "Strong Dispels Only" ? "dispellable_Strong" : ability_dc?.dispellable)) %></span></p> <% } %> <% if (!Array.isArray(ability_dc?.bkbpierce) && ability_dc?.bkbpierce) { %> <p class="bkbpierce <%= ability_dc?.bkbpierce %>"> <%= $t("dota2tracker.template.bkbpierce") %> <span><%= $t("dota2tracker.template." + ability_dc?.bkbpierce) %></span></p> <% } %> </div></div><p class="description"><%- item.desc_loc %></p> <% if (item.ability_has_scepter && !item.ability_is_granted_by_scepter && item.scepter_loc) { %> <p class="aghanim_description"><span class="title"><img src="<%= getImageUrl("scepter") %>" class="scepter"><%= $t("dota2tracker.template.scepter") %></span><span class="desc"><%- item.scepter_loc %></span></p> <% } %> <% if (item.ability_has_shard && !item.ability_is_granted_by_shard && item.shard_loc) { %> <p class="aghanim_description"><span class="title"><img src="<%= getImageUrl("shard") %>" class="shard"><%= $t("dota2tracker.template.shard") %></span><span class="desc"><%- item.shard_loc %></span></p> <% } %> <% if (item.notes_loc && item.notes_loc.length > 0) { %> <div class="notes"> <% item.notes_loc.forEach((note) => { %> <p><%- note %></p> <% }); %> </div> <% } %> <div class="attributes"> <%
27
18
  item.special_values.filter(sv => sv.heading_loc).forEach((sv) => {
28
19
  // 预计算条件,简化模板逻辑
29
20
  const isAllZero = sv.values_float?.every(value => value === 0) || sv.values_float.length == 0;
30
21
  const hasScepterVal = sv.values_scepter && sv.values_scepter.length;
31
22
  const hasShardVal = sv.values_shard && sv.values_shard.length;
32
- const hasFacetVal = sv.facet_bonus.name && hero.facets.some(facet => facet.name == sv.facet_bonus.name);
33
23
  const hasTalentVal = sv.bonuses.length > 0;
34
24
 
35
25
  // 如果基础值全为0,且没有任何额外加成(A杖/魔晶/命石),则该条目其实没意义,但在原逻辑里似乎是作为空 primary 渲染?
@@ -39,9 +29,7 @@
39
29
  // 让我们遵循原逻辑:
40
30
  // Primary 部分:除非 (全0 且 有额外加成),否则渲染数值。
41
31
  // 如果 (全0 且 有额外加成) -> 渲染内容为空字符串。
42
- %> <p><span class="heading"><%= sv.heading_loc %></span><span class="values"> <% if (!isAllZero || (isAllZero && (hasScepterVal || hasShardVal || hasFacetVal))) { %> <span class="primary<%= isAllZero ? ' empty' : '' %>"> <% if (!isAllZero) { %> <%= sv.values_float.map(value => value + (sv.is_percentage ? "%" : "")).join(" / ") %> <% } %> </span> <% } %> <% if (hasScepterVal) { %> <span class="alternative scepter"><img src="<%= getImageUrl("scepter") %>"/> <%- sv.values_scepter.map(value => (value > 0 ? '<span class="plus">+</span>' : "") + value + (sv.is_percentage ? "%" : "")).join(" / ") %> </span> <% } %> <% if (hasShardVal) { %> <span class="alternative shard"><img src="<%= getImageUrl("shard") %>"/> <%- sv.values_shard.map(value => (value > 0 ? '<span class="plus">+</span>' : "") + value + (sv.is_percentage ? "%" : "")).join(" / ") %> </span> <% } %> <% if (hasFacetVal) {
43
- const facet = hero.facets.find(f => f.name == sv.facet_bonus.name);
44
- %> <span class="alternative facet"><span class="facet"><span class="name_back type_<%= facet.color %>"><img src="<%= getImageUrl(facet.icon, ImageType.IconsFacets) %>"/> <%= sv.facet_bonus.values.map(value => value + (sv.is_percentage ? "%" : "")).join(" / ") %> </span></span></span> <% } %> <% if (hasTalentVal) { %> <span class="alternative talent"> <% sv.bonuses.forEach(bonus => { %> <img src="<%= getImageUrl("talents", "icons", "svg") %>"/> <%- (bonus.value > 0 ? '<span class="plus">+</span>' : "") + bonus.value + (sv.is_percentage ? "%" : "") %> <% }); %> </span> <% } %> </span></p> <% }); %> </div><p> <% if (hasCd) { %> <span class="cooldown"> <%= cdStats.values_float.join(" / ") %> </span> <% } %> <% if (hasMana) { %> <span class="mana_cost"> <%= manaStats.values_float.join(" / ") %> </span> <% } %> </p> <% if (item.lore_loc) { %> <p class="lore"><%= item.lore_loc %></p> <% } %> </div> <% }); %> </div><div class="lore"> <%- hero.bio_loc %> </div></div></body><script>document.addEventListener('DOMContentLoaded', function() {
32
+ %> <p><span class="heading"><%= sv.heading_loc %></span><span class="values"> <% if (!isAllZero || (isAllZero && (hasScepterVal || hasShardVal))) { %> <span class="primary<%= isAllZero ? ' empty' : '' %>"> <% if (!isAllZero) { %> <%= sv.values_float.map(value => value + (sv.is_percentage ? "%" : "")).join(" / ") %> <% } %> </span> <% } %> <% if (hasScepterVal) { %> <span class="alternative scepter"><img src="<%= getImageUrl("scepter") %>"/> <%- sv.values_scepter.map(value => (value > 0 ? '<span class="plus">+</span>' : "") + value + (sv.is_percentage ? "%" : "")).join(" / ") %> </span> <% } %> <% if (hasShardVal) { %> <span class="alternative shard"><img src="<%= getImageUrl("shard") %>"/> <%- sv.values_shard.map(value => (value > 0 ? '<span class="plus">+</span>' : "") + value + (sv.is_percentage ? "%" : "")).join(" / ") %> </span> <% } %> <% if (hasTalentVal) { %> <span class="alternative talent"> <% sv.bonuses.forEach(bonus => { %> <img src="<%= getImageUrl("talents", "icons", "svg") %>"/> <%- (bonus.value > 0 ? '<span class="plus">+</span>' : "") + bonus.value + (sv.is_percentage ? "%" : "") %> <% }); %> </span> <% } %> </span></p> <% }); %> </div><p> <% if (hasCd) { %> <span class="cooldown"> <%= cdStats.values_float.join(" / ") %> </span> <% } %> <% if (hasMana) { %> <span class="mana_cost"> <%= manaStats.values_float.join(" / ") %> </span> <% } %> </p> <% if (item.lore_loc) { %> <p class="lore"><%= item.lore_loc %></p> <% } %> </div> <% }); %> </div><div class="lore"> <%- hero.bio_loc %> </div></div></body><script>document.addEventListener('DOMContentLoaded', function() {
45
33
  const items = document.querySelectorAll('.skills > .skill');
46
34
  items.forEach(item => {
47
35
  // const name = item.getAttribute('data-name');
@@ -1 +1,2 @@
1
- <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>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/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>
@@ -1 +1,2 @@
1
- <svg fill="#fff" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 395 395" xml:space="preserve"><g><path d="M313.002,0H82C36.785,0,0,36.784,0,81.998v230.993C0,358.211,36.785,395,82,395h231.002 C358.216,395,395,358.211,395,312.991V81.998C395,36.784,358.216,0,313.002,0z M380,312.991C380,349.94,349.944,380,313.002,380H82 c-36.944,0-67-30.06-67-67.009V81.998C15,45.055,45.056,15,82,15h231.002C349.944,15,380,45.055,380,81.998V312.991z"/><path d="M305.336,107.5c-21.492,0-38.915,17.422-38.915,38.912c0,21.495,17.423,38.915,38.915,38.915 c21.49,0,38.911-17.42,38.911-38.915C344.247,124.922,326.826,107.5,305.336,107.5z"/><path d="M309.227,186.313c-10.602,0-21.818,7.267-21.818,7.267l-20.557-20.553c-2.876-2.876-3.857-3.915-6.746-3.915H145.701 H65.539v-0.193c0-2.149-1.742-3.891-3.892-3.891c-2.149,0-3.892,1.742-3.892,3.891v0.193h-7.003c-4.298,0-7.782,3.484-7.782,7.783 c0,4.298,3.484,7.783,7.782,7.783h87.166v9.081c0,4.298,3.484,7.783,7.782,7.783h36.863c-0.523,5.762,2.184,11.588,7.477,14.765 l53.325,31.996c2.468,1.48,5.238,2.218,8.009,2.218c2.905,0,5.809-0.813,8.355-2.433l14.475-9.209V287.5h70.042v-66.164 C344.247,201.992,328.567,186.313,309.227,186.313z M251.135,216.658L225.94,201.54h26.137l8.872,8.873L251.135,216.658z"/><path d="M167.491,165.612h45.528c4.298,0,7.782-3.484,7.782-7.783s-3.484-7.783-7.782-7.783h-45.528 c-4.298,0-7.782,3.484-7.782,7.783S163.193,165.612,167.491,165.612z"/></g></svg>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" fill="#fff" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 395 395" xml:space="preserve"><g><path d="M313.002,0H82C36.785,0,0,36.784,0,81.998v230.993C0,358.211,36.785,395,82,395h231.002 C358.216,395,395,358.211,395,312.991V81.998C395,36.784,358.216,0,313.002,0z M380,312.991C380,349.94,349.944,380,313.002,380H82 c-36.944,0-67-30.06-67-67.009V81.998C15,45.055,45.056,15,82,15h231.002C349.944,15,380,45.055,380,81.998V312.991z"/><path d="M305.336,107.5c-21.492,0-38.915,17.422-38.915,38.912c0,21.495,17.423,38.915,38.915,38.915 c21.49,0,38.911-17.42,38.911-38.915C344.247,124.922,326.826,107.5,305.336,107.5z"/><path d="M309.227,186.313c-10.602,0-21.818,7.267-21.818,7.267l-20.557-20.553c-2.876-2.876-3.857-3.915-6.746-3.915H145.701 H65.539v-0.193c0-2.149-1.742-3.891-3.892-3.891c-2.149,0-3.892,1.742-3.892,3.891v0.193h-7.003c-4.298,0-7.782,3.484-7.782,7.783 c0,4.298,3.484,7.783,7.782,7.783h87.166v9.081c0,4.298,3.484,7.783,7.782,7.783h36.863c-0.523,5.762,2.184,11.588,7.477,14.765 l53.325,31.996c2.468,1.48,5.238,2.218,8.009,2.218c2.905,0,5.809-0.813,8.355-2.433l14.475-9.209V287.5h70.042v-66.164 C344.247,201.992,328.567,186.313,309.227,186.313z M251.135,216.658L225.94,201.54h26.137l8.872,8.873L251.135,216.658z"/><path d="M167.491,165.612h45.528c4.298,0,7.782-3.484,7.782-7.783s-3.484-7.783-7.782-7.783h-45.528 c-4.298,0-7.782,3.484-7.782,7.783S163.193,165.612,167.491,165.612z"/></g></svg>
@@ -1 +1,2 @@
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
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/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,2 @@
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
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/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,2 @@
1
- <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>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/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>
@@ -1 +1,2 @@
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>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/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>
@@ -5,4 +5,4 @@
5
5
  const matchName = /^npc_dota_hero_(?<name>.+)$/.exec(heroData.name);
6
6
  return matchName ? matchName[1] : "";
7
7
  });
8
- %> <% const banGradientStyle = "background-image: linear-gradient(to bottom left, transparent calc(50% - 1px), red calc(50% - 1px), black calc(50% + 1px), transparent calc(50% + 1px));"; %> <div class="w-[790px] h-[100px] flex justify-between box m-[5px]"><div class="flag w-[100px] h-full flex justify-center items-end bg-cover <%= !match.didRadiantWin ? 'grayscale' : "" %>" style="background-image:url('<%= getImageUrl("flag_radiant") %>')"> <%= match.didRadiantWin ? $t("dota2tracker.template.won") : "" %> </div><div class="details grow relative flex-col flex"><p class="w-full flex justify-around"><span><%= $t("dota2tracker.template.match_id_") %><%= match.id %></span><span><%= $t("dota2tracker.template.game_mode_") %><%= gameModeStr %></span><span><%= $t("dota2tracker.template.region_") %><%= regionStr %></span></p><p class="w-full flex justify-around"><span><%= $t("dota2tracker.template.start_time_") %><%= startTime %></span><span><%= $t("dota2tracker.template.end_time_") %><%= endTime %></span></p><p class="w-full grow score flex justify-evenly items-end"><span class="score radiant text-3xl"><%= match.radiant.killsCount %></span><span class="time text-sm"><%= match.durationTime %></span><span class="score dire text-3xl"><%= match.dire.killsCount %></span></p><div class="rank absolute w-[64px] h-[64px] bottom-[10px] left-1/2 -translate-x-1/2<%- match.odParsed && match.lobbyType !== "RANKED" ? ` grayscale` : "" %>"><img class="star absolute w-full" src="<%= getImageUrl('star_' + (match.rank ? match.rank.toString().split('')[1] : '')) %>"> <img class="medal absolute w-full" src="<%= getImageUrl('medal_' + (match.rank ? match.rank.toString().split('')[0] : '')) %>"></div></div><div class="flag w-[100px] h-full flex justify-center items-end bg-cover <%= match.didRadiantWin ? 'grayscale' : "" %>" style="background-image:url('<%= getImageUrl("flag_dire") %>')"> <%= !match.didRadiantWin ? $t("dota2tracker.template.won") : "" %> </div></div><div class="w-[790px] grid grid-cols-2 gap-[5px] mx-[5px]"> <% match.players.forEach(player => { %> <%- include(`./player.ejs`, { match, player, utils: {kc, dc, laneSVG}, facetColor, partyColor }) %> <% }); %> </div><div class="ban_list box m-[5px] flex flex-wrap"> <% bannedHeroes.forEach(heroName => { %> <div class="ban_hero relative w-[10%]"><i class="absolute w-full h-full z-1" <%- `style="${banGradientStyle}"` %>></i> <img class="grayscale" src="<%= getImageUrl(heroName, ImageType.Heroes) %>" alt=""/></div> <% }); %> </div>
8
+ %> <% const banGradientStyle = "background-image: linear-gradient(to bottom left, transparent calc(50% - 1px), red calc(50% - 1px), black calc(50% + 1px), transparent calc(50% + 1px));"; %> <div class="w-[790px] h-[100px] flex justify-between box m-[5px]"><div class="flag w-[100px] h-full flex justify-center items-end bg-cover <%= !match.didRadiantWin ? 'grayscale' : "" %>" style="background-image:url('<%= getImageUrl("flag_radiant") %>')"> <%= match.didRadiantWin ? $t("dota2tracker.template.won") : "" %> </div><div class="details grow relative flex-col flex"><p class="w-full flex justify-around"><span><%= $t("dota2tracker.template.match_id_") %><%= match.id %></span><span><%= $t("dota2tracker.template.game_mode_") %><%= gameModeStr %></span><span><%= $t("dota2tracker.template.region_") %><%= regionStr %></span></p><p class="w-full flex justify-around"><span><%= $t("dota2tracker.template.start_time_") %><%= startTime %></span><span><%= $t("dota2tracker.template.end_time_") %><%= endTime %></span></p><p class="w-full grow score flex justify-evenly items-end"><span class="score radiant text-3xl"><%= match.radiant.killsCount %></span><span class="time text-sm"><%= match.durationTime %></span><span class="score dire text-3xl"><%= match.dire.killsCount %></span></p><div class="rank absolute w-[64px] h-[64px] bottom-[10px] left-1/2 -translate-x-1/2<%- match.odParsed && match.lobbyType !== "RANKED" ? ` grayscale` : "" %>"><img class="star absolute w-full" src="<%= getImageUrl('star_' + (match.rank ? match.rank.toString().split('')[1] : '')) %>"> <img class="medal absolute w-full" src="<%= getImageUrl('medal_' + (match.rank ? match.rank.toString().split('')[0] : '')) %>"></div></div><div class="flag w-[100px] h-full flex justify-center items-end bg-cover <%= match.didRadiantWin ? 'grayscale' : "" %>" style="background-image:url('<%= getImageUrl("flag_dire") %>')"> <%= !match.didRadiantWin ? $t("dota2tracker.template.won") : "" %> </div></div><div class="w-[790px] grid grid-cols-2 gap-[5px] mx-[5px]"> <% match.players.forEach(player => { %> <%- include(`./player.ejs`, { match, player, utils: {kc, dc, laneSVG}, partyColor }) %> <% }); %> </div><div class="ban_list box m-[5px] flex flex-wrap"> <% bannedHeroes.forEach(heroName => { %> <div class="ban_hero relative w-[10%]"><i class="absolute w-full h-full z-1" <%- `style="${banGradientStyle}"` %>></i> <img class="grayscale" src="<%= getImageUrl(heroName, ImageType.Heroes) %>" alt=""/></div> <% }); %> </div>
@@ -1 +1 @@
1
- <% const p = player; %> <% const isLD = p.hero.id == 80; %> <% const gridCol = !p.isRadiant + 1; %> <% const gridRow = (p.position ? parseInt(p.position.slice(-1)) : 0) % 5; %> <% const gridStyle = `grid-column: ${gridCol}; grid-row: ${gridRow}`; %> <% const pColor = partyColor[p.partyId]; %> <% const partyLineStyle = `background-color: ${pColor};`; %> <% const partyMarkStyle = `color: ${pColor};`; %> <% const orderColors = ['red', 'yellow', 'green']; %> <% const orderColor = orderColors[Math.floor(p.order / 4)] || 'white'; %> <% const kcVal = Math.floor(p.killContribution * 100); %> <% const dcVal = Math.floor(p.deathContribution * 100); %> <% const kcStyle = `color: ${utils.kc(kcVal)}`; %> <% const dcStyle = `color: ${utils.dc(dcVal)}`; %> <% const facetGradient = facetColor[p.facet?.color ?? 'Black']; %> <% const facetIcon = p.facet?.icon; %> <% const facetName = p.facet?.displayName ?? "?"; %> <% const damageReport = p.stats?.heroDamageReport?.receivedTotal || {}; %> <% const dealtReport = p.stats?.heroDamageReport?.dealtTotal || {}; %> <% const damageReceived = (damageReport.physicalDamage || 0) + (damageReport.magicalDamage || 0) + (damageReport.pureDamage || 0); %> <% const ccStun = ((dealtReport.stunDuration || 0) / 100).toFixed(2); %> <% const ccSlow = ((dealtReport.slowDuration || 0) / 100).toFixed(2); %> <% const ccDisable = ((dealtReport.disableDuration || 0) / 100).toFixed(2); %> <div class="box h-[320px] flex flex-col gap-[4px] rounded-[5px]" <%- `style="${gridStyle}"` %>><section class="grid grid-cols-[112px_1fr_100px] grid-rows-[63px_24px]"><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]"> <% if (p.leaverStatus != "NONE" && p.leaverStatus != "DISCONNECTED") { %> <img class="leaver absolute w-full h-full object-contain" src="<%= getImageUrl("disconnected") %>"/> <% } %> <div class="party contents"><i class="party_line absolute w-full h-[2px]" <%- `style="${partyLineStyle}"` %>></i> <b class="party_mark absolute leading-[1.5] w-[16px] top-[3px] left-[2px] bg-black/80 text-center" <%- `style="${partyMarkStyle}"` %>> <%= match.party[p.partyId] %> </b></div><div class="hero_info absolute top-[3px] right-0 text-right leading-[1.25]"><p class="order" <%- `style="color: ${orderColor};"` %>> <%= p.isRandom ? $t("dota2tracker.template.random") : $t("dota2tracker.template.pick_order", [`${p.order == null ? "?" : p.order + 1}`]) %> </p><p class="position"><%= $t("dota2tracker.template.position_" + p.position?.slice(-1)) ?? '' %></p></div><p class="level absolute bottom-0 right-0 text-xs px-[2px]"><%= p.level %></p><img class="h-full" src="<%= getImageUrl(p.hero.shortName, ImageType.Heroes) %>"/></div><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]"><p class="player_name truncate max-w-full"><%= p.steamAccount.name %></p><p class="flex gap-[12px] justify-center"><span class="kda"><%= p.kills %>/<%= p.deaths %>/<%= p.assists %></span><span class="kc" <%- `style="${kcStyle}"` %>><%= kcVal %>%</span> <span class="dc" <%- `style="${dcStyle}"` %>><%= dcVal %>%</span></p><p class="flex gap-[16px] justify-center"><span class="networth text-[rgb(203,176,42)]"><%= p.networth %></span><span class="score"><%= (p.heroDamage / p.networth)?.toFixed(2) %></span></p></div><div class="lane_rank row-1 col-3 flex w-full h-full justify-between"><div class="lane w-[44px] h-full"><p class="text-[10px] text-center"><%= $t("dota2tracker.template.lane_" + p.laneResult) %></p><div class="h-[44px] w-[44px]"><%- utils.laneSVG[p.laneResult] %></div></div><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]"><div class="rank absolute top-0 size-[36px] z-2"><img class="medal absolute inset-0" src="<%= getImageUrl('medal_' + (p.rank.inTop100 ?? p.rank.medal)) %>"/> <img class="stars absolute inset-0" src="<%= getImageUrl('star_' + p.rank.star) %>"/><p class="leader absolute bottom-0 text-center w-full"><%= p.steamAccount?.seasonLeaderboardRank ?? "" %></p></div> <% if (p.dotaPlus) { %> <div class="plus absolute bottom-0 size-[36px] z-1"><img class="" src="<%= getImageUrl("hero_badge_" + (p.dotaPlus ? Math.ceil((p.dotaPlus?.level + 1) / 6) : 1)) %>"><p class="level absolute bottom-0 text-center w-full"><%= p.dotaPlus?.level %></p></div> <% } %> </div></div><div class="facet row-2 col-1 w-full h-full grid grid-cols-[24px_1fr] grid-rows-1 bg-linear-to-r <%- facetGradient %>"> <% if (p.facet) { %> <div class="w-[24px] h-[24px] flex items-center justify-center bg-[#4444]"><img class="h-[18px]" src="<%= getImageUrl(facetIcon, ImageType.IconsFacets) %>"/></div> <% } %> <div class="facet_name w-full truncate grow px-[4px] text-sm flex justify-center items-center"><span class="w-full truncate text-center"><%= facetName %></span></div></div><div class="titles row-2 col-start-2 col-end-3 w-full flex items-center pl-[12px] gap-[6px]"> <% p.titles.forEach(item => { %> <% const title = parseBadge(item, $t); %> <span <%- `style="color: ${title.color};"` %>><%= title.shortText %></span> <% }); %> </div></section> <% if (!isLD) { %> <section class="items w-full grid grid-cols-[repeat(3,3fr)_2fr_3fr] grid-rows-2"><div class="items_main contents"> <% for(let i = 0; i < 6; i++) { %> <%- include("./item.ejs", {item: p.items[i], style: `col-${i%3+1}`, isNeutral: false}) %> <% } %> </div><div class="items_backpack grayscale col-4 row-start-1 row-span-2 flex flex-col"> <% for(let i = 0; i < 3; i++) { %> <%- include("./item.ejs", {item: p.backpacks[i], style: "", isNeutral: false}) %> <% } %> </div><div class="items_neutral contents"> <%- include("./item.ejs", {item: p.neutral0Id, style: "row-start-1 row-span-2 col-5 flex items-center h-full", isNeutral: true}) %> </div></section> <% } else { %> <section class="items w-full grid grid-cols-[repeat(6,3fr)_10fr] grid-rows-4"><div class="items_hero contents"><div class="items_main contents"> <% for(let i = 0; i < 6; i++) { %> <%- include("./item.ejs", {item: p.items[i], style: `row-1 col-${i+1}`, isNeutral: false}) %> <% } %> </div><div class="items_backpack grayscale contents"> <% for(let i = 0; i < 3; i++) { %> <%- include("./item.ejs", {item: p.backpacks[i], style: `row-2 col-${i+1}`, isNeutral: false}) %> <% } %> </div><div class="items_neutral contents"> <%- include("./item.ejs", {item: p.neutral0Id, style: "row-2 col-6", isNeutral: true}) %> </div></div><div class="items_unit contents"><div class="items_main contents"> <% for(let i = 0; i < 6; i++) { %> <%- include("./item.ejs", {item: p.unitItems[i], style: `row-3 col-${i+1}`, isNeutral: false}) %> <% } %> </div><div class="items_backpack grayscale contents"> <% for(let i = 0; i < 3; i++) { %> <%- include("./item.ejs", {item: p.unitBackpacks[i], style: `row-4 col-${i+1}`, isNeutral: false}) %> <% } %> </div><div class="items_neutral contents"> <%- include("./item.ejs", {item: p.additionalUnit.neutral0Id, style: "row-4 col-6", isNeutral: true}) %> </div></div></section> <% } %> <section class="buffs_supports w-full h-[24px] flex justify-between"><div class="buffs flex h-[24px]"> <% p.buffs.forEach(buff => { %> <div class="relative"><img class="w-[33px] h-[24px]" src="<%= getImageUrl(dotaconstants[`${buff.type}_ids`][buff.id], ImageType[buff.type === "ability" ? "Abilities" : "Items"]) %>"/><p class="count absolute w-full bottom-0 leading-[1] text-center bg-stone-700/50 text-[10px]"><%= buff.stackCount || "" %></p></div> <% }); %> </div><div class="supports flex h-[24px]"> <% p.supportItemsCount.forEach(supportItem => { %> <div class="relative"><img class="w-[33px] h-[24px]" src="<%= getImageUrl(supportItem.name, ImageType.Items) %>"/><p class="count absolute w-full bottom-0 leading-[1] text-center bg-stone-700/50 text-[10px]"><%= supportItem.count || "" %></p></div> <% }); %> </div></section><section class="player-stat h-full flex flex-col justify-around text-[13px] leading-[24px] whitespace-nowrap"><p class="w-full flex justify-around"><span><%= $t("dota2tracker.template.hero_damage_") %><span class="hero_damage"><%= p.heroDamage %></span></span><span><%= $t("dota2tracker.template.building_damage_") %><span class="building_damage"><%= p.towerDamage %></span></span><span><%= $t("dota2tracker.template.damage_received_") %><span class="tak"><%= damageReceived %></span></span></p><p class="w-full flex justify-around"><span><%= $t("dota2tracker.template.lasthit_") %><span class="lh"><%= p.numLastHits %></span>/<span class="dn"><%= p.numDenies %></span></span><span><%= $t("dota2tracker.template.GPM/XPM_") %><span class="gpm"><%= p.goldPerMinute %></span>/<span class="xpm"><%= p.experiencePerMinute %></span></span><span><%= $t("dota2tracker.template.heal_") %><span class="heal"><%= p.heroHealing %></span></span></p><p class="w-full flex justify-center"><span><%= $t("dota2tracker.template.crowd_control_duration_") %></span><span><%= ccStun + "/" %></span><span><%= ccSlow + "/" %></span><span><%= ccDisable %></span>s</p></section></div>
1
+ <% const p = player; %> <% const isLD = p.hero.id == 80; %> <% const gridCol = !p.isRadiant + 1; %> <% const gridRow = (p.position ? parseInt(p.position.slice(-1)) : 0) % 5; %> <% const gridStyle = `grid-column: ${gridCol}; grid-row: ${gridRow}`; %> <% const pColor = partyColor[p.partyId]; %> <% const partyLineStyle = `background-color: ${pColor};`; %> <% const partyMarkStyle = `color: ${pColor};`; %> <% const orderColors = ['red', 'yellow', 'green']; %> <% const orderColor = orderColors[Math.floor(p.order / 4)] || 'white'; %> <% const kcVal = Math.floor(p.killContribution * 100); %> <% const dcVal = Math.floor(p.deathContribution * 100); %> <% const kcStyle = `color: ${utils.kc(kcVal)}`; %> <% const dcStyle = `color: ${utils.dc(dcVal)}`; %> <% const damageReport = p.stats?.heroDamageReport?.receivedTotal || {}; %> <% const dealtReport = p.stats?.heroDamageReport?.dealtTotal || {}; %> <% const damageReceived = (damageReport.physicalDamage || 0) + (damageReport.magicalDamage || 0) + (damageReport.pureDamage || 0); %> <% const ccStun = ((dealtReport.stunDuration || 0) / 100).toFixed(2); %> <% const ccSlow = ((dealtReport.slowDuration || 0) / 100).toFixed(2); %> <% const ccDisable = ((dealtReport.disableDuration || 0) / 100).toFixed(2); %> <div class="box h-[320px] flex flex-col gap-[4px] rounded-[5px]" <%- `style="${gridStyle}"` %>><section class="grid grid-cols-[112px_1fr_100px] grid-rows-[63px_24px]"><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]"> <% if (p.leaverStatus != "NONE" && p.leaverStatus != "DISCONNECTED") { %> <img class="leaver absolute w-full h-full object-contain" src="<%= getImageUrl("disconnected") %>"/> <% } %> <div class="party contents"><i class="party_line absolute w-full h-[2px]" <%- `style="${partyLineStyle}"` %>></i> <b class="party_mark absolute leading-[1.5] w-[16px] top-[3px] left-[2px] bg-black/80 text-center" <%- `style="${partyMarkStyle}"` %>> <%= match.party[p.partyId] %> </b></div><div class="hero_info absolute top-[3px] right-0 text-right leading-[1.25]"><p class="order" <%- `style="color: ${orderColor};"` %>> <%= p.isRandom ? $t("dota2tracker.template.random") : $t("dota2tracker.template.pick_order", [`${p.order == null ? "?" : p.order + 1}`]) %> </p><p class="position"><%= $t("dota2tracker.template.position_" + p.position?.slice(-1)) ?? '' %></p></div><p class="level absolute bottom-0 right-0 text-xs px-[2px]"><%= p.level %></p><img class="h-full" src="<%= getImageUrl(p.hero.shortName, ImageType.Heroes) %>"/></div><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]"><p class="player_name truncate max-w-full"><%= p.steamAccount.name %></p><p class="flex gap-[12px] justify-center"><span class="kda"><%= p.kills %>/<%= p.deaths %>/<%= p.assists %></span><span class="kc" <%- `style="${kcStyle}"` %>><%= kcVal %>%</span> <span class="dc" <%- `style="${dcStyle}"` %>><%= dcVal %>%</span></p><p class="flex gap-[16px] justify-center"><span class="networth text-[rgb(203,176,42)]"><%= p.networth %></span><span class="score"><%= (p.heroDamage / p.networth)?.toFixed(2) %></span></p></div><div class="lane_rank row-1 col-3 flex w-full h-full justify-between"><div class="lane w-[44px] h-full"><p class="text-[10px] text-center"><%= $t("dota2tracker.template.lane_" + p.laneResult) %></p><div class="h-[44px] w-[44px]"><img src="<%- utils.laneSVG[p.laneResult] %>"/></div></div><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]"><div class="rank absolute top-0 size-[36px] z-2"><img class="medal absolute inset-0" src="<%= getImageUrl('medal_' + (p.rank.inTop100 ?? p.rank.medal)) %>"/> <img class="stars absolute inset-0" src="<%= getImageUrl('star_' + p.rank.star) %>"/><p class="leader absolute bottom-0 text-center w-full"><%= p.steamAccount?.seasonLeaderboardRank ?? "" %></p></div> <% if (p.dotaPlus) { %> <div class="plus absolute bottom-0 size-[36px] z-1"><img class="" src="<%= getImageUrl("hero_badge_" + (p.dotaPlus ? Math.ceil((p.dotaPlus?.level + 1) / 6) : 1)) %>"><p class="level absolute bottom-0 text-center w-full"><%= p.dotaPlus?.level %></p></div> <% } %> </div></div><div class="titles row-2 col-start-1 col-end-3 w-full flex items-center pl-[10px] gap-[10px]"> <% p.titles.forEach(item => { %> <% const title = parseBadge(item, $t); %> <span <%- `style="color: ${title.color};"` %>><%= title.shortText %></span> <% }); %> </div></section> <% if (!isLD) { %> <section class="items w-full grid grid-cols-[repeat(3,3fr)_2fr_3fr] grid-rows-2"><div class="items_main contents"> <% for(let i = 0; i < 6; i++) { %> <%- include("./item.ejs", {item: p.items[i], style: `col-${i%3+1}`, isNeutral: false}) %> <% } %> </div><div class="items_backpack grayscale col-4 row-start-1 row-span-2 flex flex-col"> <% for(let i = 0; i < 3; i++) { %> <%- include("./item.ejs", {item: p.backpacks[i], style: "", isNeutral: false}) %> <% } %> </div><div class="items_neutral contents"> <%- include("./item.ejs", {item: p.neutral0Id, style: "row-start-1 row-span-2 col-5 flex items-center h-full", isNeutral: true}) %> </div></section> <% } else { %> <section class="items w-full grid grid-cols-[repeat(6,3fr)_10fr] grid-rows-4"><div class="items_hero contents"><div class="items_main contents"> <% for(let i = 0; i < 6; i++) { %> <%- include("./item.ejs", {item: p.items[i], style: `row-1 col-${i+1}`, isNeutral: false}) %> <% } %> </div><div class="items_backpack grayscale contents"> <% for(let i = 0; i < 3; i++) { %> <%- include("./item.ejs", {item: p.backpacks[i], style: `row-2 col-${i+1}`, isNeutral: false}) %> <% } %> </div><div class="items_neutral contents"> <%- include("./item.ejs", {item: p.neutral0Id, style: "row-2 col-6", isNeutral: true}) %> </div></div><div class="items_unit contents"><div class="items_main contents"> <% for(let i = 0; i < 6; i++) { %> <%- include("./item.ejs", {item: p.unitItems[i], style: `row-3 col-${i+1}`, isNeutral: false}) %> <% } %> </div><div class="items_backpack grayscale contents"> <% for(let i = 0; i < 3; i++) { %> <%- include("./item.ejs", {item: p.unitBackpacks[i], style: `row-4 col-${i+1}`, isNeutral: false}) %> <% } %> </div><div class="items_neutral contents"> <%- include("./item.ejs", {item: p.additionalUnit.neutral0Id, style: "row-4 col-6", isNeutral: true}) %> </div></div></section> <% } %> <section class="buffs_supports w-full h-[24px] flex justify-between"><div class="buffs flex h-[24px]"> <% p.buffs.forEach(buff => { %> <div class="relative"><img class="w-[33px] h-[24px]" src="<%= getImageUrl(dotaconstants[`${buff.type}_ids`][buff.id], ImageType[buff.type === "ability" ? "Abilities" : "Items"]) %>"/><p class="count absolute w-full bottom-0 leading-[1] text-center bg-stone-700/50 text-[10px]"><%= buff.stackCount || "" %></p></div> <% }); %> </div><div class="supports flex h-[24px]"> <% p.supportItemsCount.forEach(supportItem => { %> <div class="relative"><img class="w-[33px] h-[24px]" src="<%= getImageUrl(supportItem.name, ImageType.Items) %>"/><p class="count absolute w-full bottom-0 leading-[1] text-center bg-stone-700/50 text-[10px]"><%= supportItem.count || "" %></p></div> <% }); %> </div></section><section class="player-stat h-full flex flex-col justify-around text-[13px] leading-[24px] whitespace-nowrap"><p class="w-full flex justify-around"><span><%= $t("dota2tracker.template.hero_damage_") %><span class="hero_damage"><%= p.heroDamage %></span></span><span><%= $t("dota2tracker.template.building_damage_") %><span class="building_damage"><%= p.towerDamage %></span></span><span><%= $t("dota2tracker.template.damage_received_") %><span class="tak"><%= damageReceived %></span></span></p><p class="w-full flex justify-around"><span><%= $t("dota2tracker.template.lasthit_") %><span class="lh"><%= p.numLastHits %></span>/<span class="dn"><%= p.numDenies %></span></span><span><%= $t("dota2tracker.template.GPM/XPM_") %><span class="gpm"><%= p.goldPerMinute %></span>/<span class="xpm"><%= p.experiencePerMinute %></span></span><span><%= $t("dota2tracker.template.heal_") %><span class="heal"><%= p.heroHealing %></span></span></p><p class="w-full flex justify-center"><span><%= $t("dota2tracker.template.crowd_control_duration_") %></span><span><%= ccStun + "/" %></span><span><%= ccSlow + "/" %></span><span><%= ccDisable %></span>s</p></section></div>
@@ -1 +1 @@
1
- /*! tailwindcss v4.1.13 | MIT License | https://tailwindcss.com */@layer properties;@layer theme,base,components,utilities;@layer theme{:root,:host{--font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-stone-700: oklch(37.4% .01 67.558);--color-black: #000;--color-white: #fff;--spacing: .25rem;--text-xs: .75rem;--text-xs--line-height: calc(1 / .75);--text-sm: .875rem;--text-sm--line-height: calc(1.25 / .875);--text-3xl: 1.875rem;--text-3xl--line-height: 1.2 ;--default-font-family: var(--font-sans);--default-mono-font-family: var(--font-mono)}}@layer base{*,:after,:before,::backdrop,::file-selector-button{box-sizing:border-box;margin:0;padding:0;border:0 solid}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;tab-size:4;font-family:var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings, normal);font-variation-settings:var(--default-font-variation-settings, normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings, normal);font-variation-settings:var(--default-mono-font-variation-settings, normal);font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea,::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;border-radius:0;background-color:transparent;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px){::placeholder{color:currentcolor;@supports (color: color-mix(in lab,red,red)){color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]),::file-selector-button{appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer utilities{.absolute{position:absolute}.relative{position:relative}.inset-0{inset:calc(var(--spacing) * 0)}.top-0{top:calc(var(--spacing) * 0)}.top-\[3px\]{top:3px}.right-0{right:calc(var(--spacing) * 0)}.bottom-0{bottom:calc(var(--spacing) * 0)}.bottom-\[10px\]{bottom:10px}.left-1\/2{left:50%}.left-\[2px\]{left:2px}.z-1{z-index:1}.z-2{z-index:2}.col-1{grid-column:1}.col-2{grid-column:2}.col-3{grid-column:3}.col-4{grid-column:4}.col-5{grid-column:5}.col-6{grid-column:6}.col-start-2{grid-column-start:2}.col-end-3{grid-column-end:3}.row-1{grid-row:1}.row-2{grid-row:2}.row-3{grid-row:3}.row-4{grid-row:4}.row-span-2{grid-row:span 2 / span 2}.row-start-1{grid-row-start:1}.m-\[5px\]{margin:5px}.mx-\[5px\]{margin-inline:5px}.mx-\[10px\]{margin-inline:10px}.contents{display:contents}.flex{display:flex}.grid{display:grid}.aspect-\[11\/8\]{aspect-ratio:11/8}.size-\[36px\]{width:36px;height:36px}.h-\[2px\]{height:2px}.h-\[18px\]{height:18px}.h-\[24px\]{height:24px}.h-\[44px\]{height:44px}.h-\[64px\]{height:64px}.h-\[100px\]{height:100px}.h-\[320px\]{height:320px}.h-full{height:100%}.w-\[10\%\]{width:10%}.w-\[16px\]{width:16px}.w-\[24px\]{width:24px}.w-\[33px\]{width:33px}.w-\[36px\]{width:36px}.w-\[44px\]{width:44px}.w-\[64px\]{width:64px}.w-\[100px\]{width:100px}.w-\[790px\]{width:790px}.w-\[800px\]{width:800px}.w-auto{width:auto}.w-full{width:100%}.max-w-full{max-width:100%}.grow{flex-grow:1}.origin-top-right{transform-origin:top right}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-\[0\.6\]{scale:.6}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[24px_1fr\]{grid-template-columns:24px 1fr}.grid-cols-\[112px_1fr_100px\]{grid-template-columns:112px 1fr 100px}.grid-cols-\[repeat\(3\,3fr\)_2fr_3fr\]{grid-template-columns:repeat(3,3fr) 2fr 3fr}.grid-cols-\[repeat\(6\,3fr\)_10fr\]{grid-template-columns:repeat(6,3fr) 10fr}.grid-rows-1{grid-template-rows:repeat(1,minmax(0,1fr))}.grid-rows-2{grid-template-rows:repeat(2,minmax(0,1fr))}.grid-rows-4{grid-template-rows:repeat(4,minmax(0,1fr))}.grid-rows-\[63px_24px\]{grid-template-rows:63px 24px}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-around{justify-content:space-around}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-evenly{justify-content:space-evenly}.gap-\[4px\]{gap:4px}.gap-\[5px\]{gap:5px}.gap-\[6px\]{gap:6px}.gap-\[12px\]{gap:12px}.gap-\[16px\]{gap:16px}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.overflow-hidden{overflow:hidden}.rounded-\[5px\]{border-radius:5px}.border{border-style:var(--tw-border-style);border-width:1px}.bg-\[\#4444\]{background-color:#4444}.bg-black{background-color:var(--color-black)}.bg-black\/80{background-color:color-mix(in srgb,#000 80%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-black) 80%,transparent)}}.bg-stone-700\/50{background-color:color-mix(in srgb,oklch(37.4% .01 67.558) 50%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-stone-700) 50%,transparent)}}.bg-linear-to-r{--tw-gradient-position: to right;@supports (background-image: linear-gradient(in lab,red,red)){--tw-gradient-position: to right in oklab}background-image:linear-gradient(var(--tw-gradient-stops))}.from-\[\#2d2d2d\]{--tw-gradient-from: #2d2d2d;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#9f3c3c\]{--tw-gradient-from: #9f3c3c;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#547ea6\]{--tw-gradient-from: #547ea6;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#675cae\]{--tw-gradient-from: #675cae;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#a2b23e\]{--tw-gradient-from: #a2b23e;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#adb6be\]{--tw-gradient-from: #adb6be;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#c8a45c\]{--tw-gradient-from: #c8a45c;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#000000\]{--tw-gradient-to: #000000;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#2a385e\]{--tw-gradient-to: #2a385e;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#2d5a18\]{--tw-gradient-to: #2d5a18;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#4a2026\]{--tw-gradient-to: #4a2026;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#4e5557\]{--tw-gradient-to: #4e5557;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#6f3d21\]{--tw-gradient-to: #6f3d21;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#261c44\]{--tw-gradient-to: #261c44;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.bg-cover{background-size:cover}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.px-\[2px\]{padding-inline:2px}.px-\[4px\]{padding-inline:4px}.pl-\[12px\]{padding-left:12px}.text-center{text-align:center}.text-right{text-align:right}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading, var(--text-3xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading, var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading, var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[13px\]{font-size:13px}.leading-\[1\.5\]{--tw-leading: 1.5;line-height:1.5}.leading-\[1\.15\]{--tw-leading: 1.15;line-height:1.15}.leading-\[1\.25\]{--tw-leading: 1.25;line-height:1.25}.leading-\[1\]{--tw-leading: 1;line-height:1}.leading-\[24px\]{--tw-leading: 24px;line-height:24px}.whitespace-nowrap{white-space:nowrap}.text-\[\#ccc\]{color:#ccc}.text-\[rgb\(203\,176\,42\)\]{color:#cbb02a}.text-white{color:var(--color-white)}.opacity-75{opacity:75%}.grayscale{--tw-grayscale: grayscale(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.text-shadow-\[-1px_1px_0_\#000\,1px_-1px_0_\#000\,-1px_1px_0_\#000\,1px_1px_0_\#000\]{text-shadow:-1px 1px 0 var(--tw-text-shadow-color, #000),1px -1px 0 var(--tw-text-shadow-color, #000),-1px 1px 0 var(--tw-text-shadow-color, #000),1px 1px 0 var(--tw-text-shadow-color, #000)}.text-shadow-\[-1px_1px_2px_\#000\,1px_-1px_2px_\#000\,-1px_1px_2px_\#000\,1px_1px_2px_\#000\]{text-shadow:-1px 1px 2px var(--tw-text-shadow-color, #000),1px -1px 2px var(--tw-text-shadow-color, #000),-1px 1px 2px var(--tw-text-shadow-color, #000),1px 1px 2px var(--tw-text-shadow-color, #000)}}@property --tw-translate-x{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-border-style{syntax: "*"; inherits: false; initial-value: solid;}@property --tw-gradient-position{syntax: "*"; inherits: false;}@property --tw-gradient-from{syntax: "<color>"; inherits: false; initial-value: #0000;}@property --tw-gradient-via{syntax: "<color>"; inherits: false; initial-value: #0000;}@property --tw-gradient-to{syntax: "<color>"; inherits: false; initial-value: #0000;}@property --tw-gradient-stops{syntax: "*"; inherits: false;}@property --tw-gradient-via-stops{syntax: "*"; inherits: false;}@property --tw-gradient-from-position{syntax: "<length-percentage>"; inherits: false; initial-value: 0%;}@property --tw-gradient-via-position{syntax: "<length-percentage>"; inherits: false; initial-value: 50%;}@property --tw-gradient-to-position{syntax: "<length-percentage>"; inherits: false; initial-value: 100%;}@property --tw-leading{syntax: "*"; inherits: false;}@property --tw-blur{syntax: "*"; inherits: false;}@property --tw-brightness{syntax: "*"; inherits: false;}@property --tw-contrast{syntax: "*"; inherits: false;}@property --tw-grayscale{syntax: "*"; inherits: false;}@property --tw-hue-rotate{syntax: "*"; inherits: false;}@property --tw-invert{syntax: "*"; inherits: false;}@property --tw-opacity{syntax: "*"; inherits: false;}@property --tw-saturate{syntax: "*"; inherits: false;}@property --tw-sepia{syntax: "*"; inherits: false;}@property --tw-drop-shadow{syntax: "*"; inherits: false;}@property --tw-drop-shadow-color{syntax: "*"; inherits: false;}@property --tw-drop-shadow-alpha{syntax: "<percentage>"; inherits: false; initial-value: 100%;}@property --tw-drop-shadow-size{syntax: "*"; inherits: false;}@property --tw-text-shadow-color{syntax: "*"; inherits: false;}@property --tw-text-shadow-alpha{syntax: "<percentage>"; inherits: false; initial-value: 100%;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0;--tw-border-style: solid;--tw-gradient-position: initial;--tw-gradient-from: #0000;--tw-gradient-via: #0000;--tw-gradient-to: #0000;--tw-gradient-stops: initial;--tw-gradient-via-stops: initial;--tw-gradient-from-position: 0%;--tw-gradient-via-position: 50%;--tw-gradient-to-position: 100%;--tw-leading: initial;--tw-blur: initial;--tw-brightness: initial;--tw-contrast: initial;--tw-grayscale: initial;--tw-hue-rotate: initial;--tw-invert: initial;--tw-opacity: initial;--tw-saturate: initial;--tw-sepia: initial;--tw-drop-shadow: initial;--tw-drop-shadow-color: initial;--tw-drop-shadow-alpha: 100%;--tw-drop-shadow-size: initial;--tw-text-shadow-color: initial;--tw-text-shadow-alpha: 100%}}}
1
+ /*! tailwindcss v4.1.13 | MIT License | https://tailwindcss.com */@layer properties;@layer theme,base,components,utilities;@layer theme{:root,:host{--font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-stone-700: oklch(37.4% .01 67.558);--color-black: #000;--color-white: #fff;--spacing: .25rem;--text-xs: .75rem;--text-xs--line-height: calc(1 / .75);--text-sm: .875rem;--text-sm--line-height: calc(1.25 / .875);--text-3xl: 1.875rem;--text-3xl--line-height: 1.2 ;--default-font-family: var(--font-sans);--default-mono-font-family: var(--font-mono)}}@layer base{*,:after,:before,::backdrop,::file-selector-button{box-sizing:border-box;margin:0;padding:0;border:0 solid}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;tab-size:4;font-family:var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings, normal);font-variation-settings:var(--default-font-variation-settings, normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings, normal);font-variation-settings:var(--default-mono-font-variation-settings, normal);font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea,::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;border-radius:0;background-color:transparent;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px){::placeholder{color:currentcolor;@supports (color: color-mix(in lab,red,red)){color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]),::file-selector-button{appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer utilities{.absolute{position:absolute}.relative{position:relative}.inset-0{inset:calc(var(--spacing) * 0)}.top-0{top:calc(var(--spacing) * 0)}.top-\[3px\]{top:3px}.right-0{right:calc(var(--spacing) * 0)}.bottom-0{bottom:calc(var(--spacing) * 0)}.bottom-\[10px\]{bottom:10px}.left-1\/2{left:50%}.left-\[2px\]{left:2px}.z-1{z-index:1}.z-2{z-index:2}.col-1{grid-column:1}.col-2{grid-column:2}.col-3{grid-column:3}.col-4{grid-column:4}.col-5{grid-column:5}.col-6{grid-column:6}.col-start-1{grid-column-start:1}.col-end-3{grid-column-end:3}.row-1{grid-row:1}.row-2{grid-row:2}.row-3{grid-row:3}.row-4{grid-row:4}.row-span-2{grid-row:span 2 / span 2}.row-start-1{grid-row-start:1}.m-\[5px\]{margin:5px}.mx-\[5px\]{margin-inline:5px}.mx-\[10px\]{margin-inline:10px}.contents{display:contents}.flex{display:flex}.grid{display:grid}.aspect-\[11\/8\]{aspect-ratio:11/8}.size-\[36px\]{width:36px;height:36px}.h-\[2px\]{height:2px}.h-\[24px\]{height:24px}.h-\[44px\]{height:44px}.h-\[64px\]{height:64px}.h-\[100px\]{height:100px}.h-\[320px\]{height:320px}.h-full{height:100%}.w-\[10\%\]{width:10%}.w-\[16px\]{width:16px}.w-\[33px\]{width:33px}.w-\[36px\]{width:36px}.w-\[44px\]{width:44px}.w-\[64px\]{width:64px}.w-\[100px\]{width:100px}.w-\[790px\]{width:790px}.w-\[800px\]{width:800px}.w-auto{width:auto}.w-full{width:100%}.max-w-full{max-width:100%}.grow{flex-grow:1}.origin-top-right{transform-origin:100% 0}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-\[0\.6\]{scale:.6}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[112px_1fr_100px\]{grid-template-columns:112px 1fr 100px}.grid-cols-\[repeat\(3\,3fr\)_2fr_3fr\]{grid-template-columns:repeat(3,3fr) 2fr 3fr}.grid-cols-\[repeat\(6\,3fr\)_10fr\]{grid-template-columns:repeat(6,3fr) 10fr}.grid-rows-2{grid-template-rows:repeat(2,minmax(0,1fr))}.grid-rows-4{grid-template-rows:repeat(4,minmax(0,1fr))}.grid-rows-\[63px_24px\]{grid-template-rows:63px 24px}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-around{justify-content:space-around}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-evenly{justify-content:space-evenly}.gap-\[4px\]{gap:4px}.gap-\[5px\]{gap:5px}.gap-\[10px\]{gap:10px}.gap-\[12px\]{gap:12px}.gap-\[16px\]{gap:16px}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.overflow-hidden{overflow:hidden}.rounded-\[5px\]{border-radius:5px}.bg-black{background-color:var(--color-black)}.bg-black\/80{background-color:color-mix(in srgb,#000 80%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-black) 80%,transparent)}}.bg-stone-700\/50{background-color:color-mix(in srgb,oklch(37.4% .01 67.558) 50%,transparent);@supports (color: color-mix(in lab,red,red)){background-color:color-mix(in oklab,var(--color-stone-700) 50%,transparent)}}.bg-cover{background-size:cover}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.px-\[2px\]{padding-inline:2px}.pl-\[10px\]{padding-left:10px}.text-center{text-align:center}.text-right{text-align:right}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading, var(--text-3xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading, var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading, var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[13px\]{font-size:13px}.leading-\[1\.5\]{--tw-leading: 1.5;line-height:1.5}.leading-\[1\.15\]{--tw-leading: 1.15;line-height:1.15}.leading-\[1\.25\]{--tw-leading: 1.25;line-height:1.25}.leading-\[1\]{--tw-leading: 1;line-height:1}.leading-\[24px\]{--tw-leading: 24px;line-height:24px}.whitespace-nowrap{white-space:nowrap}.text-\[\#ccc\]{color:#ccc}.text-\[rgb\(203\,176\,42\)\]{color:#cbb02a}.text-white{color:var(--color-white)}.opacity-75{opacity:75%}.grayscale{--tw-grayscale: grayscale(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.text-shadow-\[-1px_1px_0_\#000\,1px_-1px_0_\#000\,-1px_1px_0_\#000\,1px_1px_0_\#000\]{text-shadow:-1px 1px 0 var(--tw-text-shadow-color, #000),1px -1px 0 var(--tw-text-shadow-color, #000),-1px 1px 0 var(--tw-text-shadow-color, #000),1px 1px 0 var(--tw-text-shadow-color, #000)}.text-shadow-\[-1px_1px_2px_\#000\,1px_-1px_2px_\#000\,-1px_1px_2px_\#000\,1px_1px_2px_\#000\]{text-shadow:-1px 1px 2px var(--tw-text-shadow-color, #000),1px -1px 2px var(--tw-text-shadow-color, #000),-1px 1px 2px var(--tw-text-shadow-color, #000),1px 1px 2px var(--tw-text-shadow-color, #000)}}@property --tw-translate-x{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-leading{syntax: "*"; inherits: false;}@property --tw-blur{syntax: "*"; inherits: false;}@property --tw-brightness{syntax: "*"; inherits: false;}@property --tw-contrast{syntax: "*"; inherits: false;}@property --tw-grayscale{syntax: "*"; inherits: false;}@property --tw-hue-rotate{syntax: "*"; inherits: false;}@property --tw-invert{syntax: "*"; inherits: false;}@property --tw-opacity{syntax: "*"; inherits: false;}@property --tw-saturate{syntax: "*"; inherits: false;}@property --tw-sepia{syntax: "*"; inherits: false;}@property --tw-drop-shadow{syntax: "*"; inherits: false;}@property --tw-drop-shadow-color{syntax: "*"; inherits: false;}@property --tw-drop-shadow-alpha{syntax: "<percentage>"; inherits: false; initial-value: 100%;}@property --tw-drop-shadow-size{syntax: "*"; inherits: false;}@property --tw-text-shadow-color{syntax: "*"; inherits: false;}@property --tw-text-shadow-alpha{syntax: "<percentage>"; inherits: false; initial-value: 100%;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0;--tw-leading: initial;--tw-blur: initial;--tw-brightness: initial;--tw-contrast: initial;--tw-grayscale: initial;--tw-hue-rotate: initial;--tw-invert: initial;--tw-opacity: initial;--tw-saturate: initial;--tw-sepia: initial;--tw-drop-shadow: initial;--tw-drop-shadow-color: initial;--tw-drop-shadow-alpha: 100%;--tw-drop-shadow-size: initial;--tw-text-shadow-color: initial;--tw-text-shadow-alpha: 100%}}}
@@ -1,13 +1,4 @@
1
- <% const match = data; %> <% const partyColor = ["#caffe5","#ffe484","#e19be2","#ccdaf4"]; %> <% const facetColor = {
2
- Red: "from-[#9f3c3c] to-[#4a2026]",
3
- Yellow: "from-[#c8a45c] to-[#6f3d21]",
4
- Green: "from-[#a2b23e] to-[#2d5a18]",
5
- Blue: "from-[#547ea6] to-[#2a385e]",
6
- Purple: "from-[#675cae] to-[#261c44]",
7
- Gray: "from-[#adb6be] to-[#4e5557]",
8
- Black: "from-[#2d2d2d] to-[#000000]"
9
- };
10
- %> <% const kc = (num) => { let red = (255 - (num * 255) / 100).toFixed(2); return `rgb(255,${red},${red})`; }; %> <% const dc = (num) => { let gray = ((50 - Math.min(num, 50)) * (255 / 50)).toFixed(2); return `rgb(${gray},${gray},${gray})`; }; %> <% const laneSVG = {
1
+ <% const match = data; %> <% const partyColor = ["#caffe5","#ffe484","#e19be2","#ccdaf4"]; %> <% const kc = (num) => { let red = (255 - (num * 255) / 100).toFixed(2); return `rgb(255,${red},${red})`; }; %> <% const dc = (num) => { let gray = ((50 - Math.min(num, 50)) * (255 / 50)).toFixed(2); return `rgb(${gray},${gray},${gray})`; }; %> <% const laneSVG = {
11
2
  stomp: getImageUrl("lane_stomp", undefined, ImageFormat.svg),
12
3
  advantage: getImageUrl("lane_victory", undefined, ImageFormat.svg),
13
4
  disadvantage: getImageUrl("lane_fail", undefined, ImageFormat.svg),
@@ -15,4 +6,4 @@
15
6
  tie: getImageUrl("lane_tie", undefined, ImageFormat.svg),
16
7
  jungle: getImageUrl("lane_jungle", undefined, ImageFormat.svg),
17
8
  };
18
- %> <%- include("../common/utils/match") %> <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Match</title> <%- `<style>` %> <%- include(`./match_1/base.css`) %> <%- include(`./match_1/style.css`) %> <%- `</style>` %> </head><body class="bg-black w-[800px] text-white"> <%- include(`./match_1/main.ejs`, { match, partyColor, facetColor, kc, dc, laneSVG }) %> </body></html>
9
+ %> <%- include("../common/utils/match") %> <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Match</title> <%- `<style>` %> <%- include(`./match_1/base.css`) %> <%- include(`./match_1/style.css`) %> <%- `</style>` %> </head><body class="bg-black w-[800px] text-white"> <%- include(`./match_1/main.ejs`, { match, partyColor, kc, dc, laneSVG }) %> </body></html>
@@ -1 +1 @@
1
- p{margin:0}img{width:100%;vertical-align:middle}html,body{overflow:hidden;width:800px}nav{font-size:14px;line-height:1.8;height:72px;color:#fff;background-color:#000;display:flex;flex-direction:row;justify-content:space-around;align-items:center}nav>div>p:first-of-type{font-weight:700}nav .match_id p:first-of-type{font-size:16px}nav>div.match_id>p.success:after{content:"\203b<%= $t('dota2tracker.template.analysis_successful') %>";color:#7ba334}nav>div.match_id>p.fail:after{content:"\203b<%= $t('dota2tracker.template.analysis_incomplete') %>";color:#ffb400}nav>div.match_id>p.opendota:after{content:"\203b<%= $t('dota2tracker.template.analysis_by_opendota') %>";color:#34a39a}nav>.rank{width:48px;height:48px;position:relative}nav>.rank>img{width:48px;height:48px;position:absolute}.radiant{color:#3c9028}.dire{color:#9c3628}.match_result{font-weight:700;height:49px;display:flex;justify-content:center;align-items:center}.match_result .win{margin:0 25px}.match_result .win.radiant:after{content:"<%=$t('dota2tracker.template.radiant_won')%>"}.match_result .win.dire:after{content:"<%=$t('dota2tracker.template.dire_won')%>"}.players{display:flex;flex-direction:column}.players .panel{padding:0 10px}.players .panel{padding-top:4px;height:40px;border-top:3px solid #fff;font-size:13.3px;display:grid;grid-template-columns:32px 56px 378px repeat(4,1fr)}.players .panel.radiant{border-color:#3c9028}.players .panel.dire{border-color:#9c3628}.players .panel p{line-height:16px;margin-left:8px}.players .panel .win{font-size:20px;line-height:32px}.players .panel .data{color:#aaa}.player:not(:last-child){border-bottom:1px solid #e1e1e1}.player{color:#000;width:100%;display:grid;grid-template-columns:64px 48px 88px 160px 112px 252px 36px 20px;grid-template-rows:19px 14px 14px 14px;padding-bottom:3px;font-size:12px;line-height:14px;overflow:hidden;justify-content:center}.player>.row-1{margin-top:6px}.player>.hero_avatar{margin-bottom:5px;width:64px;grid-row:1 / span 3;grid-column:1;position:relative}.player>.hero_avatar>.level{width:20px;height:15px;background-color:#323232;position:absolute;bottom:0;right:0;font-size:12px;line-height:15px;color:#fff;text-align:center}.player>.hero_avatar>.party_line{position:absolute;height:2px;top:0;width:100%}.player>.hero_avatar>.party_mark{position:absolute;line-height:1.5;text-align:center;width:16px;font-size:10px;top:3px;left:1px;background-color:#000c}.player>.hero_avatar.party_I>.party_line{background-color:#caffe5}.player>.hero_avatar.party_I>.party_mark{color:#caffe5}.player>.hero_avatar.party_I>.party_mark:after{content:"I"}.player>.hero_avatar.party_II>.party_line{background-color:#ffe484}.player>.hero_avatar.party_II>.party_mark{color:#ffe484}.player>.hero_avatar.party_II>.party_mark:after{content:"II"}.player>.hero_avatar.party_III>.party_line{background-color:#e19be2}.player>.hero_avatar.party_III>.party_mark{color:#e19be2}.player>.hero_avatar.party_III>.party_mark:after{content:"III"}.player>.hero_avatar.party_IV>.party_line{background-color:#ccdaf4}.player>.hero_avatar.party_IV>.party_mark{color:#ccdaf4}.player>.hero_avatar.party_IV>.party_mark:after{content:"IV"}.player>.facet{color:#fff;width:100%;height:16px;grid-row:4;grid-column:1;display:grid;grid-template-columns:16px auto;z-index:1;position:relative;top:-5px}.player>.facet>img{padding:2px;width:12px;height:12px;background-color:#4444}.player>.facet>span{padding:0 2px;line-height:1;display:grid;place-items:center;align-items:center;justify-content:center;height:100%}.player>.facet>span>*{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.player>.facet.Red{background:linear-gradient(to right,#9f3c3c,#4a2026)}.player>.facet.Yellow{background:linear-gradient(to right,#c8a45c,#6f3d21)}.player>.facet.Green{background:linear-gradient(to right,#a2b23e,#2d5a18)}.player>.facet.Blue{background:linear-gradient(to right,#547ea6,#2a385e)}.player>.facet.Purple{background:linear-gradient(to right,#675cae,#261c44)}.player>.facet.Gray{background:linear-gradient(to right,#adb6be,#4e5557)}.player>.facet.Black{background:linear-gradient(to right,#2d2d2d,#000);display:flex;justify-content:center}.player>.rank{position:relative;grid-row:1 / span 3;grid-column:2;width:48px;height:48px}.player>.rank>img{position:absolute}.player>.rank>p{position:absolute;width:100%;bottom:1.5px;text-align:center;font-size:8px;color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000}.player>.titles{grid-row:4;grid-column:2/4;margin-left:6px}.player>.player_name{grid-row:1;grid-column:3 / span 2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.player>.player_name>.rank{color:#aaa}.player.radiant>.player_name>.name{color:#3c9028}.player.dire>.player_name>.name{color:#9c3628}.player .pick,.player .networth{grid-column:3}.player .networth .gold{color:#cbb02a;text-shadow:1px 1px 0 #000}.player .hero_damage{grid-row:2;grid-column:4}.player .damage_received{grid-row:3;grid-column:4}.player .tower_damage{grid-row:4;grid-column:4}.player .kda{grid-row:1;grid-column:5}.player .kill_contribution{grid-row:2;grid-column:5}.player .stun_duration{grid-row:3;grid-column:5}.player .heal{grid-row:4;grid-column:5}.player .items{grid-row:1 / span 4;grid-column:6;display:grid;grid-template-columns:24px 192px auto;grid-template-rows:32px 24px}.player .items>div{display:flex;background-color:silver}.player .items .normal{height:32px;grid-column:1/-1;grid-row:1}.player .items .backpack{height:24px;width:96px;grid-row:2}.player .items .normal .item{width:40px;height:30px;margin:1px;position:relative}.player .items .time{position:absolute;width:100%;text-align:center;bottom:0;height:11px;line-height:11px;color:#ccc;background-color:#323232}.player .items .backpack{filter:grayscale(100%)}.player .items .backpack .item,.player .items .bear .item{width:30px;height:22px;margin:1px;position:relative}.player .neutral_item{grid-row:1 / span 3;grid-column:7;overflow:hidden;height:32px;width:32px;border-radius:50%;background-size:auto 100%;background-position:center;margin-left:2px}.player .items .item.recipe{background-image:url(https://cdn.cloudflare.steamstatic.com/apps/dota2/images/dota_react/items/recipe.png);background-size:100%}.player .ahgs{grid-row:1 / span 3;grid-column:8}.player .items .bear{height:24px;width:192px;grid-row:2;grid-column:2}.player.bear .items .bear .time{font-size:10px}.player.bear .items .bear_icon{grid-row:2;grid-column:1}.player.bear .items .neutral_item{height:24px;width:24px;grid-row:2;grid-column:3}
1
+ p{margin:0}img{width:100%;vertical-align:middle}html,body{overflow:hidden;width:800px}nav{font-size:14px;line-height:1.8;height:72px;color:#fff;background-color:#000;display:flex;flex-direction:row;justify-content:space-around;align-items:center}nav>div>p:first-of-type{font-weight:700}nav .match_id p:first-of-type{font-size:16px}nav>div.match_id>p.success:after{content:"\203b<%= $t('dota2tracker.template.analysis_successful') %>";color:#7ba334}nav>div.match_id>p.fail:after{content:"\203b<%= $t('dota2tracker.template.analysis_incomplete') %>";color:#ffb400}nav>div.match_id>p.opendota:after{content:"\203b<%= $t('dota2tracker.template.analysis_by_opendota') %>";color:#34a39a}nav>.rank{width:48px;height:48px;position:relative}nav>.rank>img{width:48px;height:48px;position:absolute}.radiant{color:#3c9028}.dire{color:#9c3628}.match_result{font-weight:700;height:49px;display:flex;justify-content:center;align-items:center}.match_result .win{margin:0 25px}.match_result .win.radiant:after{content:"<%=$t('dota2tracker.template.radiant_won')%>"}.match_result .win.dire:after{content:"<%=$t('dota2tracker.template.dire_won')%>"}.players{display:flex;flex-direction:column}.players .panel{padding:0 10px}.players .panel{padding-top:4px;height:40px;border-top:3px solid #fff;font-size:13.3px;display:grid;grid-template-columns:32px 56px 378px repeat(4,1fr)}.players .panel.radiant{border-color:#3c9028}.players .panel.dire{border-color:#9c3628}.players .panel p{line-height:16px;margin-left:8px}.players .panel .win{font-size:20px;line-height:32px}.players .panel .data{color:#aaa}.player:not(:last-child){border-bottom:1px solid #e1e1e1}.player{color:#000;width:100%;display:grid;grid-template-columns:64px 48px 88px 160px 112px 252px 36px 20px;grid-template-rows:19px 14px 14px 14px;padding-bottom:3px;font-size:12px;line-height:14px;overflow:hidden;justify-content:center}.player>.row-1{margin-top:6px}.player>.hero_avatar{margin-bottom:5px;width:64px;grid-row:1 / span 3;grid-column:1;position:relative}.player>.hero_avatar>.level{width:20px;height:15px;background-color:#323232;position:absolute;bottom:0;right:0;font-size:12px;line-height:15px;color:#fff;text-align:center}.player>.hero_avatar>.party_line{position:absolute;height:2px;top:0;width:100%}.player>.hero_avatar>.party_mark{position:absolute;line-height:1.5;text-align:center;width:16px;font-size:10px;top:3px;left:1px;background-color:#000c}.player>.hero_avatar.party_I>.party_line{background-color:#caffe5}.player>.hero_avatar.party_I>.party_mark{color:#caffe5}.player>.hero_avatar.party_I>.party_mark:after{content:"I"}.player>.hero_avatar.party_II>.party_line{background-color:#ffe484}.player>.hero_avatar.party_II>.party_mark{color:#ffe484}.player>.hero_avatar.party_II>.party_mark:after{content:"II"}.player>.hero_avatar.party_III>.party_line{background-color:#e19be2}.player>.hero_avatar.party_III>.party_mark{color:#e19be2}.player>.hero_avatar.party_III>.party_mark:after{content:"III"}.player>.hero_avatar.party_IV>.party_line{background-color:#ccdaf4}.player>.hero_avatar.party_IV>.party_mark{color:#ccdaf4}.player>.hero_avatar.party_IV>.party_mark:after{content:"IV"}.player>.facet{color:#fff;width:100%;height:16px;grid-row:4;grid-column:1;display:grid;grid-template-columns:16px auto;z-index:1;position:relative;top:-5px}.player>.facet>img{padding:2px;width:12px;height:12px;background-color:#4444}.player>.facet>span{padding:0 2px;line-height:1;display:grid;place-items:center;align-items:center;justify-content:center;height:100%}.player>.facet>span>*{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.player>.facet.Red{background:linear-gradient(to right,#9f3c3c,#4a2026)}.player>.facet.Yellow{background:linear-gradient(to right,#c8a45c,#6f3d21)}.player>.facet.Green{background:linear-gradient(to right,#a2b23e,#2d5a18)}.player>.facet.Blue{background:linear-gradient(to right,#547ea6,#2a385e)}.player>.facet.Purple{background:linear-gradient(to right,#675cae,#261c44)}.player>.facet.Gray{background:linear-gradient(to right,#adb6be,#4e5557)}.player>.facet.Black{background:linear-gradient(to right,#2d2d2d,#000);display:flex;justify-content:center}.player>.rank{position:relative;grid-row:1 / span 3;grid-column:2;width:48px;height:48px}.player>.rank>img{position:absolute}.player>.rank>p{position:absolute;width:100%;bottom:1.5px;text-align:center;font-size:8px;color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000}.player>.titles{grid-row:4;grid-column:1/4;margin-left:2px}.player>.player_name{grid-row:1;grid-column:3 / span 2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.player>.player_name>.rank{color:#aaa}.player.radiant>.player_name>.name{color:#3c9028}.player.dire>.player_name>.name{color:#9c3628}.player .pick,.player .networth{grid-column:3}.player .networth .gold{color:#cbb02a;text-shadow:1px 1px 0 #000}.player .hero_damage{grid-row:2;grid-column:4}.player .damage_received{grid-row:3;grid-column:4}.player .tower_damage{grid-row:4;grid-column:4}.player .kda{grid-row:1;grid-column:5}.player .kill_contribution{grid-row:2;grid-column:5}.player .stun_duration{grid-row:3;grid-column:5}.player .heal{grid-row:4;grid-column:5}.player .items{grid-row:1 / span 4;grid-column:6;display:grid;grid-template-columns:24px 192px auto;grid-template-rows:32px 24px}.player .items>div{display:flex;background-color:silver}.player .items .normal{height:32px;grid-column:1/-1;grid-row:1}.player .items .backpack{height:24px;width:96px;grid-row:2}.player .items .normal .item{width:40px;height:30px;margin:1px;position:relative}.player .items .time{position:absolute;width:100%;text-align:center;bottom:0;height:11px;line-height:11px;color:#ccc;background-color:#323232}.player .items .backpack{filter:grayscale(100%)}.player .items .backpack .item,.player .items .bear .item{width:30px;height:22px;margin:1px;position:relative}.player .neutral_item{grid-row:1 / span 3;grid-column:7;overflow:hidden;height:32px;width:32px;border-radius:50%;background-size:auto 100%;background-position:center;margin-left:2px}.player .items .item.recipe{background-image:url(https://cdn.cloudflare.steamstatic.com/apps/dota2/images/dota_react/items/recipe.png);background-size:100%}.player .ahgs{grid-row:1 / span 3;grid-column:8}.player .items .bear{height:24px;width:192px;grid-row:2;grid-column:2}.player.bear .items .bear .time{font-size:10px}.player.bear .items .bear_icon{grid-row:2;grid-column:1}.player.bear .items .neutral_item{height:24px;width:24px;grid-row:2;grid-column:3}
@@ -7,4 +7,4 @@
7
7
  const b = Math.max(0, (num & 0x0000FF) - Math.round(2.55 * amt));
8
8
  return `#${(0x1000000 + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
9
9
  };
10
- %> <% const getFacetSize = n => { const l=n?.length||0; return l<=4?"11px":l===5?"8px":l>=6?"7px":"10px"; }; %> <% const startTime = DateTime.fromSeconds(match.startDateTime).toFormat("yyyy-MM-dd HH:mm:ss").slice(2); %> <% const regionName = $t("dota2tracker.template.regions." + match.regionId); %> <% const modeName = ($t("dota2tracker.template.lobby_types." + match.lobbyType) || match.lobbyType) + "/" + ($t("dota2tracker.template.game_modes." + match.gameMode) || match.gameMode); %> <% const statusClass = match.odParsed ? "opendota" : (match.parsedDateTime ? "success" : "fail"); %> <% const rankStyle = (match.odParsed && match.lobbyType !== "RANKED") ? "filter:grayscale(1)" : ""; %> <%- include("../../common/utils/match") %> <nav><div class="match_id"><p><%= $t("dota2tracker.template.match_id_").slice(0, -1) %> <%- match.id %></p><p class="<%= statusClass %>"></p></div><div class="start_time"><p><%= $t("dota2tracker.template.start_time_").slice(0, -1) %></p><p><%- startTime %></p></div><div class="duration"><p><%= $t("dota2tracker.template.duration_").slice(0, -1) %></p><p><%- match.durationTime %></p></div><div class="region"><p><%= $t("dota2tracker.template.region_").slice(0, -1) %></p><p><%- regionName %></p></div><div class="mode"><p><%= $t("dota2tracker.template.game_mode_").slice(0, -1) %></p><p><%- modeName %></p></div><div class="rank" <%- `style="${rankStyle}"` %>><img src="<%- getImageUrl('medal_' + (match.rank?.toString().split('')[0] ?? '0')) %>" alt=""/> <img style="z-index:1" src="<%- getImageUrl('star_' + (match.rank?.toString().split('')[1] ?? '0')) %>" alt=""/></div></nav><section class="match_result"><span class="kills radiant"><%- match.radiant.killsCount %></span><span class="win <%- match.didRadiantWin ? 'radiant' : 'dire' %>"></span> <span class="kills dire"><%- match.dire.killsCount %></span></section><section class="players"> <% ['radiant', 'dire'].forEach(team => { %> <% const isRadiant = team === 'radiant'; %> <% const teamData = match[team]; %> <% const orderStyle = `order: ${isRadiant ? 0 : 50}`; %> <% const teamName = isRadiant ? ['Radiant', '天辉'] : ['Dire', '夜魇']; %> <% const showWin = (isRadiant === match.didRadiantWin); %> <section class="panel <%= team %>" <%- `style="${orderStyle}"` %>><img src="<%- getImageUrl('logo_' + team) %>"><p><%- teamName.join('<br>') %></p> <% if (showWin) { %> <p class="win"><%= $t('dota2tracker.template.won') %></p> <% } else { %> <p></p> <% } %> <p class="data"><%= $t('dota2tracker.template.kill') %><br><%= teamData.killsCount %></p><p class="data"><%= $t('dota2tracker.template.total_damage') %><br><%= teamData.heroDamage %></p><p class="data"><%= $t('dota2tracker.template.total_gold') %><br><%= teamData.networth %></p><p class="data"><%= $t('dota2tracker.template.total_experience') %><br><%= teamData.experience %></p></section> <% }); %> <% match.players.forEach(p => { %> <% const isBear = p.hero.id == 80; %> <% const orderStyle = `order: ${p.team === 'radiant' ? 1 : 100}`; %> <% const partyClass = p.partyId != null ? ' party_' + match.party[p.partyId] : ''; %> <% const facetColor = p.facet?.color ?? 'Black'; %> <% const facetStyle = `font-size: ${getFacetSize(p.facet?.displayName)}`; %> <% const facetName = p.facet?.displayName ?? '?'; %> <% const teamTotalDmg = match[p.team].heroDamage || 1; %> <% const teamTotalTaken = match[p.team].damageReceived || 1; %> <% const dmgPct = (p.heroDamage / teamTotalDmg * 100).toFixed(2); %> <% const takenPct = (p.damageReceived / teamTotalTaken * 100).toFixed(2); %> <% const kdaVal = ((p.kills + p.assists) / (p.deaths || 1)).toFixed(2); %> <% const kcVal = (p.killContribution * 100).toFixed(2); %> <% const stunVal = ((p.stats.heroDamageReport?.dealtTotal.stunDuration ?? 0) / 100).toFixed(2); %> <% const pBuffs = p.stats?.matchPlayerBuffEvent || []; %> <% const hasAghs = p.items.some(i => i?.id == 108) || p.backpacks.some(i => i?.id == 108) || pBuffs.some(b => b.itemId == 108); %> <% const hasShard = pBuffs.some(b => b.itemId == 609); %> <div class="player <%= p.team %><%= isBear ? ' bear' : '' %>" <%- `style="${orderStyle}"` %>><div class="hero_avatar row-1<%= partyClass %>"><img src="<%- getImageUrl(p.hero.shortName, ImageType.Heroes) %>"/><p class="level"><%= p.level %></p><p class="party_line"></p><p class="party_mark"></p></div><div class="facet <%= facetColor %>"> <% if (p.facet) { %> <img src="<%- getImageUrl(p.facet.icon, ImageType.IconsFacets) %>"> <% } %> <span <%- `style="${facetStyle}"` %>><p><%= facetName %></p></span></div><div class="rank"><img src="<%- getImageUrl('medal_' + (p.rank.inTop100 ?? p.rank.medal)) %>" class="medal"/> <img src="<%- getImageUrl('star_' + p.rank.star) %>" class="stars"/><p><%= p.steamAccount.seasonLeaderboardRank ?? '' %></p></div><div class="titles"> <% p.titles.forEach(item => { %> <% const title = parseBadge(item, $t); %> <span <%- `style="color: ${darken(title.color, 25)};"` %>><%= title.shortText %></span> <% }); %> </div><div class="player_name row-1"><span class="rank">[<%= $t('dota2tracker.template.ranks.' + p.rank.medal) %><%= p.rank.star || '' %>]</span> <span class="name"><%= p.steamAccount.name %></span></div><p class="pick"> <%- p.isRandom ? $t('dota2tracker.template.random') : $t('dota2tracker.template.pick_order', [p.order == null ? '?' : p.order + 1]) %> <%= $t('dota2tracker.template.position_' + p.position?.slice(-1)) ?? '' %> </p><p class="networth"><span class="gold"><%= p.formattedNetworth %></span>(<%= (p.heroDamage / p.networth)?.toFixed(2) %>)</p><p class="hero_damage"> <%= $t('dota2tracker.template.hero_damage_') %><%= p.heroDamage %> (<%= dmgPct %>%)</p><p class="damage_received"> <%= $t('dota2tracker.template.damage_received_') %><%= p.damageReceived %> (<%= takenPct %>%)</p><p class="tower_damage"> <%= $t('dota2tracker.template.building_damage_') %><%= p.towerDamage %> </p><p class="kda row-1"> <%= p.kills %>/<%= p.deaths %>/<%= p.assists %> (<%= kdaVal %>)</p><p class="kill_contribution"> <%= $t('dota2tracker.template.kill_contribution_') %><%= kcVal %>%</p><p class="stun_duration"> <%= $t('dota2tracker.template.crowd_control_duration_') %> <%= stunVal %>s</p><p class="heal"> <%= $t('dota2tracker.template.heal_') %><%= p.heroHealing %> </p><div class="items row-1"><div class="normal"> <% p.items.forEach(item => { %> <div class="item<%= item?.isRecipe ? ' recipe' : '' %>" data-id="<%= item?.id ?? 0 %>"><img src="<%- item ? getImageUrl(item.name, ImageType.Items) : '' %>" alt=""/> <% if (item) { %> <p class="time"><%= item.time %></p> <% } %> </div> <% }); %> </div> <% if (!isBear) { %> <div class="backpack"> <% p.backpacks.forEach(item => { %> <div class="item<%= item?.isRecipe ? ' recipe' : '' %>"><img src="<%- item ? getImageUrl(item.name, ImageType.Items) : '' %>" alt=""/></div> <% }); %> </div> <% } else { %> <img class="bear_icon" src="<%- getImageUrl('lone_druid_spirit_bear', ImageType.Abilities) %>" alt=""><div class="bear"> <% p.unitItems.forEach(item => { %> <div class="item<%= item?.isRecipe ? ' recipe' : '' %>" data-id="<%= item?.id ?? 0 %>"><img src="<%- item ? getImageUrl(item.name, ImageType.Items) : '' %>" alt=""/> <% if (item) { %> <p class="time"><%= item.time %></p> <% } %> </div> <% }); %> </div><div class="neutral_item" <%- `style="background-image: url(${getImageUrl(dotaconstants.item_ids[p.additionalUnit.neutral0Id], ImageType.Items)})"` %>></div> <% } %> </div><div class="neutral_item row-1" <%- `style="background-image: url(${getImageUrl(dotaconstants.item_ids[p.neutral0Id], ImageType.Items)})"` %>></div><div class="ahgs row-1"><img src="<%- getImageUrl('scepter_' + (hasAghs ? 1 : 0)) %>" alt=""/> <img src="<%- getImageUrl('shard_' + (hasShard ? 1 : 0)) %>" alt=""/></div></div> <% }); %> </section>
10
+ %> <% const startTime = DateTime.fromSeconds(match.startDateTime).toFormat("yyyy-MM-dd HH:mm:ss").slice(2); %> <% const regionName = $t("dota2tracker.template.regions." + match.regionId); %> <% const modeName = ($t("dota2tracker.template.lobby_types." + match.lobbyType) || match.lobbyType) + "/" + ($t("dota2tracker.template.game_modes." + match.gameMode) || match.gameMode); %> <% const statusClass = match.odParsed ? "opendota" : (match.parsedDateTime ? "success" : "fail"); %> <% const rankStyle = (match.odParsed && match.lobbyType !== "RANKED") ? "filter:grayscale(1)" : ""; %> <%- include("../../common/utils/match") %> <nav><div class="match_id"><p><%= $t("dota2tracker.template.match_id_").slice(0, -1) %> <%- match.id %></p><p class="<%= statusClass %>"></p></div><div class="start_time"><p><%= $t("dota2tracker.template.start_time_").slice(0, -1) %></p><p><%- startTime %></p></div><div class="duration"><p><%= $t("dota2tracker.template.duration_").slice(0, -1) %></p><p><%- match.durationTime %></p></div><div class="region"><p><%= $t("dota2tracker.template.region_").slice(0, -1) %></p><p><%- regionName %></p></div><div class="mode"><p><%= $t("dota2tracker.template.game_mode_").slice(0, -1) %></p><p><%- modeName %></p></div><div class="rank" <%- `style="${rankStyle}"` %>><img src="<%- getImageUrl('medal_' + (match.rank?.toString().split('')[0] ?? '0')) %>" alt=""/> <img style="z-index:1" src="<%- getImageUrl('star_' + (match.rank?.toString().split('')[1] ?? '0')) %>" alt=""/></div></nav><section class="match_result"><span class="kills radiant"><%- match.radiant.killsCount %></span><span class="win <%- match.didRadiantWin ? 'radiant' : 'dire' %>"></span> <span class="kills dire"><%- match.dire.killsCount %></span></section><section class="players"> <% ['radiant', 'dire'].forEach(team => { %> <% const isRadiant = team === 'radiant'; %> <% const teamData = match[team]; %> <% const orderStyle = `order: ${isRadiant ? 0 : 50}`; %> <% const teamName = isRadiant ? ['Radiant', '天辉'] : ['Dire', '夜魇']; %> <% const showWin = (isRadiant === match.didRadiantWin); %> <section class="panel <%= team %>" <%- `style="${orderStyle}"` %>><img src="<%- getImageUrl('logo_' + team) %>"><p><%- teamName.join('<br>') %></p> <% if (showWin) { %> <p class="win"><%= $t('dota2tracker.template.won') %></p> <% } else { %> <p></p> <% } %> <p class="data"><%= $t('dota2tracker.template.kill') %><br><%= teamData.killsCount %></p><p class="data"><%= $t('dota2tracker.template.total_damage') %><br><%= teamData.heroDamage %></p><p class="data"><%= $t('dota2tracker.template.total_gold') %><br><%= teamData.networth %></p><p class="data"><%= $t('dota2tracker.template.total_experience') %><br><%= teamData.experience %></p></section> <% }); %> <% match.players.forEach(p => { %> <% const isBear = p.hero.id == 80; %> <% const orderStyle = `order: ${p.team === 'radiant' ? 1 : 100}`; %> <% const partyClass = p.partyId != null ? ' party_' + match.party[p.partyId] : ''; %> <% const teamTotalDmg = match[p.team].heroDamage || 1; %> <% const teamTotalTaken = match[p.team].damageReceived || 1; %> <% const dmgPct = (p.heroDamage / teamTotalDmg * 100).toFixed(2); %> <% const takenPct = (p.damageReceived / teamTotalTaken * 100).toFixed(2); %> <% const kdaVal = ((p.kills + p.assists) / (p.deaths || 1)).toFixed(2); %> <% const kcVal = (p.killContribution * 100).toFixed(2); %> <% const stunVal = ((p.stats.heroDamageReport?.dealtTotal.stunDuration ?? 0) / 100).toFixed(2); %> <% const pBuffs = p.stats?.matchPlayerBuffEvent || []; %> <% const hasAghs = p.items.some(i => i?.id == 108) || p.backpacks.some(i => i?.id == 108) || pBuffs.some(b => b.itemId == 108); %> <% const hasShard = pBuffs.some(b => b.itemId == 609); %> <div class="player <%= p.team %><%= isBear ? ' bear' : '' %>" <%- `style="${orderStyle}"` %>><div class="hero_avatar row-1<%= partyClass %>"><img src="<%- getImageUrl(p.hero.shortName, ImageType.Heroes) %>"/><p class="level"><%= p.level %></p><p class="party_line"></p><p class="party_mark"></p></div><div class="rank"><img src="<%- getImageUrl('medal_' + (p.rank.inTop100 ?? p.rank.medal)) %>" class="medal"/> <img src="<%- getImageUrl('star_' + p.rank.star) %>" class="stars"/><p><%= p.steamAccount.seasonLeaderboardRank ?? '' %></p></div><div class="titles"> <% p.titles.forEach(item => { %> <% const title = parseBadge(item, $t); %> <span <%- `style="color: ${darken(title.color, 25)};"` %>><%= title.shortText %></span> <% }); %> </div><div class="player_name row-1"><span class="rank">[<%= $t('dota2tracker.template.ranks.' + p.rank.medal) %><%= p.rank.star || '' %>]</span> <span class="name"><%= p.steamAccount.name %></span></div><p class="pick"> <%- p.isRandom ? $t('dota2tracker.template.random') : $t('dota2tracker.template.pick_order', [p.order == null ? '?' : p.order + 1]) %> <%= $t('dota2tracker.template.position_' + p.position?.slice(-1)) ?? '' %> </p><p class="networth"><span class="gold"><%= p.formattedNetworth %></span>(<%= (p.heroDamage / p.networth)?.toFixed(2) %>)</p><p class="hero_damage"> <%= $t('dota2tracker.template.hero_damage_') %><%= p.heroDamage %> (<%= dmgPct %>%)</p><p class="damage_received"> <%= $t('dota2tracker.template.damage_received_') %><%= p.damageReceived %> (<%= takenPct %>%)</p><p class="tower_damage"> <%= $t('dota2tracker.template.building_damage_') %><%= p.towerDamage %> </p><p class="kda row-1"> <%= p.kills %>/<%= p.deaths %>/<%= p.assists %> (<%= kdaVal %>)</p><p class="kill_contribution"> <%= $t('dota2tracker.template.kill_contribution_') %><%= kcVal %>%</p><p class="stun_duration"> <%= $t('dota2tracker.template.crowd_control_duration_') %> <%= stunVal %>s</p><p class="heal"> <%= $t('dota2tracker.template.heal_') %><%= p.heroHealing %> </p><div class="items row-1"><div class="normal"> <% p.items.forEach(item => { %> <div class="item<%= item?.isRecipe ? ' recipe' : '' %>" data-id="<%= item?.id ?? 0 %>"><img src="<%- item ? getImageUrl(item.name, ImageType.Items) : '' %>" alt=""/> <% if (item) { %> <p class="time"><%= item.time %></p> <% } %> </div> <% }); %> </div> <% if (!isBear) { %> <div class="backpack"> <% p.backpacks.forEach(item => { %> <div class="item<%= item?.isRecipe ? ' recipe' : '' %>"><img src="<%- item ? getImageUrl(item.name, ImageType.Items) : '' %>" alt=""/></div> <% }); %> </div> <% } else { %> <img class="bear_icon" src="<%- getImageUrl('lone_druid_spirit_bear', ImageType.Abilities) %>" alt=""><div class="bear"> <% p.unitItems.forEach(item => { %> <div class="item<%= item?.isRecipe ? ' recipe' : '' %>" data-id="<%= item?.id ?? 0 %>"><img src="<%- item ? getImageUrl(item.name, ImageType.Items) : '' %>" alt=""/> <% if (item) { %> <p class="time"><%= item.time %></p> <% } %> </div> <% }); %> </div><div class="neutral_item" <%- `style="background-image: url(${getImageUrl(dotaconstants.item_ids[p.additionalUnit.neutral0Id], ImageType.Items)})"` %>></div> <% } %> </div><div class="neutral_item row-1" <%- `style="background-image: url(${getImageUrl(dotaconstants.item_ids[p.neutral0Id], ImageType.Items)})"` %>></div><div class="ahgs row-1"><img src="<%- getImageUrl('scepter_' + (hasAghs ? 1 : 0)) %>" alt=""/> <img src="<%- getImageUrl('shard_' + (hasShard ? 1 : 0)) %>" alt=""/></div></div> <% }); %> </section>
@@ -75,4 +75,4 @@
75
75
  const impAvg = posMatches.length > 0 ? Math.round(posMatches.reduce((acc, m) => acc + m.players.find(ip => ip.steamAccount.id == p.steamAccount.id).imp, 0) / posMatches.length) : "-";
76
76
  p.positionPerformance.push({ pos: i + 1, icon: posIcons[i], matchCount: posMatches.length, winCount: wins, imp: impAvg });
77
77
  }
78
- %> <% const posScale = getScale(p.positionPerformance.filter(pos => pos.matchCount > 1), true); %> <!DOCTYPE html><html lang="<%= languageTag %>"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Player</title> <%- `<style>` %> <%- include("../common/styles/normalize.min.css") %> <%- include(`./player_1/base.css`) %> <%- `</style>` %> </head><body><div class="wrapper"><div class="player"><div class="avatar"><img src="<%= p.steamAccount?.avatar %>" alt=""/></div><div class="info"><p class="name"> <%= p.steamAccount.name %> <% if (p.guildMember) { %> <span class="guild <%= getGuildClass(p.guildMember.guild.currentPercentile) %>"><%= p.guildMember.guild.tag %></span> <% } %> <% if (p.genHero) { %> <span class="hero_name"><%= p.genHero.name %></span> <% } %> </p><p class="matches"> <%= $t("dota2tracker.template.match_count_") %><%= p.matchCount %> (<span class="win"><%= p.winCount %></span>/<span class="lose"><%= p.matchCount - p.winCount %></span>) &nbsp;&nbsp; <%= $t("dota2tracker.template.winrate_") %> <span <%- `style="color:${getWinRateColor(p.winCount / p.matchCount)};"` %>><%= ((p.winCount / p.matchCount) * 100).toFixed(2) %>%</span></p><p class="matches<%= isAnon ? " blur" : "" %>"><span><%= $t("dota2tracker.template.last25matches_") %> <span class="win"><%= nearWin %></span>/<span class="lose"><%= nearCount - nearWin %></span></span>&nbsp; <span><%= $t("dota2tracker.template.winrate_") %> <span <%- `style="color:${getWinRateColor(nearWin / nearCount)};"` %>><%= ((nearWin / nearCount) * 100).toFixed(2) %>%</span> </span>&nbsp; <span><%= $t("dota2tracker.template.imp_") %><%= isAnon ? "?" : ((p.performance?.imp > 0 ? "+" : "") + p.performance?.imp) %></span></p><p class="matches<%= isAnon ? " blur" : "" %>"><span><%= $t("dota2tracker.template.lane") %> <span class="victory"><%= outcomes.victory + outcomes.stomp %>(<span class="stomp"><%= outcomes.stomp %></span>)</span>-<span class="tie"><%= outcomes.tie %></span>-<span class="fail"><%= outcomes.fail + outcomes.stomped %>(<span class="stomped"><%= outcomes.stomped %></span>)</span> </span>&nbsp;&nbsp; <% const laneTotal = outcomes.victory + outcomes.stomp + outcomes.tie + outcomes.fail + outcomes.stomped; %> <% const laneScore = (outcomes.victory + outcomes.stomp + outcomes.tie / 2) / laneTotal; %> <span><%= $t("dota2tracker.template.lane_advantage_rate_") %> <span <%- `style="color:${getWinRateColor(laneScore)};"` %>><%= isAnon ? "?" : (laneScore * 100).toFixed(2) %>%</span></span></p></div><div class="rank<%= p.isEstimatedRank ? " estimated" : "" %>"><img class="medal" src="<%= getImageUrl('medal_' + (p.rank.inTop100 ?? p.rank.medal)) %>" alt=""/> <img class="star" src="<%= getImageUrl('star_' + p.rank.star) %>" alt=""/><p><%= p.steamAccount.seasonLeaderboardRank ?? "" %></p></div></div><div class="hero_winrate"><div class="heroes"><p class="tip row total"><%= p.genHero ? $t("dota2tracker.template.all_matches_") : $t("dota2tracker.template.top10_") %></p><span class="tip"><%= $t("dota2tracker.template.hero") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.match_count") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.winrate") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.imp") %></span><span class="tip win_count" style="justify-self:end;margin-right:2px"><%= $t("dota2tracker.template.win_count") %></span><span class="tip lose_count" style="justify-self:start;margin-left:2px"><%= $t("dota2tracker.template.lose_count") %></span> <% heroList.forEach(hero => { %> <span><img alt="" src="<%= getImageUrl(hero.hero.shortName, ImageType.HeroIcons) %>"/></span><span class="count"><%= hero.matchCount %></span><span class="win_rate"><%= ((hero.winCount / hero.matchCount) * 100).toFixed(0) %>%</span> <span class="imp"><%= (hero.imp > 0 ? "+" : "") + hero.imp %></span><span class="win" <%- `style="${hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${hero.winCount * heroScale}px"` %>><%= hero.winCount %></span><span class="lose" <%- `style="${hero.matchCount - hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${(hero.matchCount - hero.winCount) * heroScale}px"` %>><%= hero.matchCount - hero.winCount %></span> <% }); %> <p class="tip row near"><%= $t("dota2tracker.template.recently_positions") %></p><span class="tip"><%= $t("dota2tracker.template.position") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.match_count") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.winrate") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.imp") %></span><span class="tip win_count" style="justify-self:end;margin-right:2px"><%= $t("dota2tracker.template.win_count") %></span><span class="tip lose_count" style="justify-self:start;margin-left:2px"><%= $t("dota2tracker.template.lose_count") %></span> <% p.positionPerformance.forEach(pos => { %> <span><img src="<%= getImageUrl(pos.icon, ImageType.IconsFacets) %>"></span><span class="count"><%= pos.matchCount %></span><span class="win_rate"><%= pos.matchCount > 0 ? ((pos.winCount / pos.matchCount) * 100).toFixed(0) : "-" %>%</span> <span class="imp"><%= (pos.imp > 0 ? "+" : "") + pos.imp %></span><span class="win" <%- `style="${pos.winCount == 0 ? "visibility:hidden;" : ""}width: ${pos.winCount * posScale}px"` %>><%= pos.winCount %></span><span class="lose" <%- `style="${pos.matchCount - pos.winCount == 0 ? "visibility:hidden;" : ""}width: ${(pos.matchCount - pos.winCount) * posScale}px"` %>><%= pos.matchCount - pos.winCount %></span> <% }); %> </div> <% if (isAnon) { %> <%- include("player_1/private", {$t, player: p}) %> <% } %> </div> <% if (Math.abs(p.streak) > 1 && !isAnon) { %> <div class="streak" <%- `style="box-shadow:none;color:${getWinRateColor((p.streak + 10) / 20)};"` %>> <%= Math.abs(p.streak) + (p.streak > 0 ? $t("dota2tracker.template.winning_streak") : $t("dota2tracker.template.losing_streak")) %> </div> <% } %> <div><table class="matches"><colgroup><col style="width:auto"/><col style="width:auto"/><col style="width:40px"/><col style="width:auto"/><col style="width:40px"/><col style="width:auto"/><col style="width:auto"/><col style="width:auto"/><col style="width:40px"/></colgroup><thead><tr><th><%= $t("dota2tracker.template.id") %></th><th><%= $t("dota2tracker.template.mode") %></th><th><%= $t("dota2tracker.template.hero") %></th><th><%= $t("dota2tracker.template.kda_kc") %></th><th><%= $t("dota2tracker.template.lane") %></th><th><%= $t("dota2tracker.template.time") %></th><th><%= $t("dota2tracker.template.duration") %></th><th><%= $t("dota2tracker.template.imp") %></th><th><%= $t("dota2tracker.template.rank") %></th></tr></thead><tbody> <% matchesData.forEach(m => { %> <tr class="match <%= m.didWin ? "win" : "lose" %>"><td><%- m.parsedDateTime ? m.id : `<p>${m.id}</p><p>${$t("dota2tracker.template.un_parsed")}</p>` %></td><td><p><%= $t("dota2tracker.template.lobby_types." + m.lobbyType) || m.lobbyType %></p><p><%= $t("dota2tracker.template.game_modes." + m.gameMode) || m.gameMode %></p></td><td><img alt="" src="<%= getImageUrl(m.inner.hero.shortName, ImageType.HeroIcons) %>"/></td><td style="line-height:20px"><p><%= m.kda %> (<%= (m.parsedDateTime ? "" : "≈") + m.kp %>%)</p><p><%= m.inner.kills %>/<%= m.inner.deaths %>/<%= m.inner.assists %></p></td><td><div class="player_lane <%= m.laneRes %>"><%- getImageUrl("lane_" + m.laneRes, undefined, ImageFormat.svg) %></div></td><td style="line-height:20px"><%= m.timeStr %></td><td><%= m.durationTime %></td><td><%= m.inner.imp != null ? ((m.inner.imp >= 0 ? "+" : "") + m.inner.imp) : "?" %></td><td><img class="medal" src="<%= getImageUrl("medal_" + m.rank?.toString().split("")[0]) %>" style="width:100%"/></td></tr> <% }); %> </tbody></table> <% if (isAnon) { %> <%- include("player_1/private", {$t, player: p}) %> <% } %> </div><div class="plus"> <% p.dotaPlus.forEach(hero => { %> <div class="hero"><img src="<%= getImageUrl(hero.shortName, ImageType.Heroes) %>" alt=""/><div class="level"><img src="<%= getImageUrl("hero_badge_" + Math.ceil((hero.level + 1) / 6)) %>" alt=""/><span><%= hero.level %></span></div><span><%= ((hero.winCount / hero.matchCount) * 100).toFixed(2) %>%</span> <span><%= hero.matchCount %></span></div> <% }); %> <% if (isAnon) { %> <%- include("player_1/private", {$t, player: p}) %> <% } %> </div></div></body></html>
78
+ %> <% const posScale = getScale(p.positionPerformance.filter(pos => pos.matchCount > 1), true); %> <!DOCTYPE html><html lang="<%= languageTag %>"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Player</title> <%- `<style>` %> <%- include("../common/styles/normalize.min.css") %> <%- include(`./player_1/base.css`) %> <%- `</style>` %> </head><body><div class="wrapper"><div class="player"><div class="avatar"><img src="<%= p.steamAccount?.avatar %>" alt=""/></div><div class="info"><p class="name"> <%= p.steamAccount.name %> <% if (p.guildMember) { %> <span class="guild <%= getGuildClass(p.guildMember.guild.currentPercentile) %>"><%= p.guildMember.guild.tag %></span> <% } %> <% if (p.genHero) { %> <span class="hero_name"><%= p.genHero.name %></span> <% } %> </p><p class="matches"> <%= $t("dota2tracker.template.match_count_") %><%= p.matchCount %> (<span class="win"><%= p.winCount %></span>/<span class="lose"><%= p.matchCount - p.winCount %></span>) &nbsp;&nbsp; <%= $t("dota2tracker.template.winrate_") %> <span <%- `style="color:${getWinRateColor(p.winCount / p.matchCount)};"` %>><%= ((p.winCount / p.matchCount) * 100).toFixed(2) %>%</span></p><p class="matches<%= isAnon ? " blur" : "" %>"><span><%= $t("dota2tracker.template.last25matches_") %> <span class="win"><%= nearWin %></span>/<span class="lose"><%= nearCount - nearWin %></span></span>&nbsp; <span><%= $t("dota2tracker.template.winrate_") %> <span <%- `style="color:${getWinRateColor(nearWin / nearCount)};"` %>><%= ((nearWin / nearCount) * 100).toFixed(2) %>%</span> </span>&nbsp; <span><%= $t("dota2tracker.template.imp_") %><%= isAnon ? "?" : ((p.performance?.imp > 0 ? "+" : "") + p.performance?.imp) %></span></p><p class="matches<%= isAnon ? " blur" : "" %>"><span><%= $t("dota2tracker.template.lane") %> <span class="victory"><%= outcomes.victory + outcomes.stomp %>(<span class="stomp"><%= outcomes.stomp %></span>)</span>-<span class="tie"><%= outcomes.tie %></span>-<span class="fail"><%= outcomes.fail + outcomes.stomped %>(<span class="stomped"><%= outcomes.stomped %></span>)</span> </span>&nbsp;&nbsp; <% const laneTotal = outcomes.victory + outcomes.stomp + outcomes.tie + outcomes.fail + outcomes.stomped; %> <% const laneScore = (outcomes.victory + outcomes.stomp + outcomes.tie / 2) / laneTotal; %> <span><%= $t("dota2tracker.template.lane_advantage_rate_") %> <span <%- `style="color:${getWinRateColor(laneScore)};"` %>><%= isAnon ? "?" : (laneScore * 100).toFixed(2) %>%</span></span></p></div><div class="rank<%= p.isEstimatedRank ? " estimated" : "" %>"><img class="medal" src="<%= getImageUrl('medal_' + (p.rank.inTop100 ?? p.rank.medal)) %>" alt=""/> <img class="star" src="<%= getImageUrl('star_' + p.rank.star) %>" alt=""/><p><%= p.steamAccount.seasonLeaderboardRank ?? "" %></p></div></div><div class="hero_winrate"><div class="heroes"><p class="tip row total"><%= p.genHero ? $t("dota2tracker.template.all_matches_") : $t("dota2tracker.template.top10_") %></p><span class="tip"><%= $t("dota2tracker.template.hero") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.match_count") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.winrate") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.imp") %></span><span class="tip win_count" style="justify-self:end;margin-right:2px"><%= $t("dota2tracker.template.win_count") %></span><span class="tip lose_count" style="justify-self:start;margin-left:2px"><%= $t("dota2tracker.template.lose_count") %></span> <% heroList.forEach(hero => { %> <span><img alt="" src="<%= getImageUrl(hero.hero.shortName, ImageType.HeroIcons) %>"/></span><span class="count"><%= hero.matchCount %></span><span class="win_rate"><%= ((hero.winCount / hero.matchCount) * 100).toFixed(0) %>%</span> <span class="imp"><%= (hero.imp > 0 ? "+" : "") + hero.imp %></span><span class="win" <%- `style="${hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${hero.winCount * heroScale}px"` %>><%= hero.winCount %></span><span class="lose" <%- `style="${hero.matchCount - hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${(hero.matchCount - hero.winCount) * heroScale}px"` %>><%= hero.matchCount - hero.winCount %></span> <% }); %> <p class="tip row near"><%= $t("dota2tracker.template.recently_positions") %></p><span class="tip"><%= $t("dota2tracker.template.position") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.match_count") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.winrate") %></span><span class="tip" style="margin:0 4px"><%= $t("dota2tracker.template.imp") %></span><span class="tip win_count" style="justify-self:end;margin-right:2px"><%= $t("dota2tracker.template.win_count") %></span><span class="tip lose_count" style="justify-self:start;margin-left:2px"><%= $t("dota2tracker.template.lose_count") %></span> <% p.positionPerformance.forEach(pos => { %> <span><img src="<%= getImageUrl(pos.icon, ImageType.IconsFacets) %>"></span><span class="count"><%= pos.matchCount %></span><span class="win_rate"><%= pos.matchCount > 0 ? ((pos.winCount / pos.matchCount) * 100).toFixed(0) : "-" %>%</span> <span class="imp"><%= (pos.imp > 0 ? "+" : "") + pos.imp %></span><span class="win" <%- `style="${pos.winCount == 0 ? "visibility:hidden;" : ""}width: ${pos.winCount * posScale}px"` %>><%= pos.winCount %></span><span class="lose" <%- `style="${pos.matchCount - pos.winCount == 0 ? "visibility:hidden;" : ""}width: ${(pos.matchCount - pos.winCount) * posScale}px"` %>><%= pos.matchCount - pos.winCount %></span> <% }); %> </div> <% if (isAnon) { %> <%- include("player_1/private", {$t, player: p}) %> <% } %> </div> <% if (Math.abs(p.streak) > 1 && !isAnon) { %> <div class="streak" <%- `style="box-shadow:none;color:${getWinRateColor((p.streak + 10) / 20)};"` %>> <%= Math.abs(p.streak) + (p.streak > 0 ? $t("dota2tracker.template.winning_streak") : $t("dota2tracker.template.losing_streak")) %> </div> <% } %> <div><table class="matches"><colgroup><col style="width:auto"/><col style="width:auto"/><col style="width:40px"/><col style="width:auto"/><col style="width:40px"/><col style="width:auto"/><col style="width:auto"/><col style="width:auto"/><col style="width:40px"/></colgroup><thead><tr><th><%= $t("dota2tracker.template.id") %></th><th><%= $t("dota2tracker.template.mode") %></th><th><%= $t("dota2tracker.template.hero") %></th><th><%= $t("dota2tracker.template.kda_kc") %></th><th><%= $t("dota2tracker.template.lane") %></th><th><%= $t("dota2tracker.template.time") %></th><th><%= $t("dota2tracker.template.duration") %></th><th><%= $t("dota2tracker.template.imp") %></th><th><%= $t("dota2tracker.template.rank") %></th></tr></thead><tbody> <% matchesData.forEach(m => { %> <tr class="match <%= m.didWin ? "win" : "lose" %>"><td><%- m.parsedDateTime ? m.id : `<p>${m.id}</p><p>${$t("dota2tracker.template.un_parsed")}</p>` %></td><td><p><%= $t("dota2tracker.template.lobby_types." + m.lobbyType) || m.lobbyType %></p><p><%= $t("dota2tracker.template.game_modes." + m.gameMode) || m.gameMode %></p></td><td><img alt="" src="<%= getImageUrl(m.inner.hero.shortName, ImageType.HeroIcons) %>"/></td><td style="line-height:20px"><p><%= m.kda %> (<%= (m.parsedDateTime ? "" : "≈") + m.kp %>%)</p><p><%= m.inner.kills %>/<%= m.inner.deaths %>/<%= m.inner.assists %></p></td><td><div class="player_lane <%= m.laneRes %>"><img src="<%- getImageUrl("lane_" + m.laneRes, undefined, ImageFormat.svg) %>"/></div></td><td style="line-height:20px"><%= m.timeStr %></td><td><%= m.durationTime %></td><td><%= m.inner.imp != null ? ((m.inner.imp >= 0 ? "+" : "") + m.inner.imp) : "?" %></td><td><img class="medal" src="<%= getImageUrl("medal_" + m.rank?.toString().split("")[0]) %>" style="width:100%"/></td></tr> <% }); %> </tbody></table> <% if (isAnon) { %> <%- include("player_1/private", {$t, player: p}) %> <% } %> </div><div class="plus"> <% p.dotaPlus.forEach(hero => { %> <div class="hero"><img src="<%= getImageUrl(hero.shortName, ImageType.Heroes) %>" alt=""/><div class="level"><img src="<%= getImageUrl("hero_badge_" + Math.ceil((hero.level + 1) / 6)) %>" alt=""/><span><%= hero.level %></span></div><span><%= ((hero.winCount / hero.matchCount) * 100).toFixed(2) %>%</span> <span><%= hero.matchCount %></span></div> <% }); %> <% if (isAnon) { %> <%- include("player_1/private", {$t, player: p}) %> <% } %> </div></div></body></html>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sjtdev/koishi-plugin-dota2tracker",
3
3
  "description": "koishi插件-追踪群友的DOTA2对局 | A Koishi plugin to track Dota 2 matches",
4
- "version": "2.5.6",
4
+ "version": "2.5.7",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -1,16 +0,0 @@
1
- query Constants($language: LanguageEnum = ENGLISH) {
2
- constants {
3
- gameVersions {
4
- id
5
- }
6
- facets(language: $language) {
7
- name
8
- id
9
- color
10
- icon
11
- language {
12
- displayName
13
- }
14
- }
15
- }
16
- }