@sjtdev/koishi-plugin-dota2tracker 1.1.10-hotfix → 1.2.0-hotfix
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +144 -174
- package/package.json +2 -2
- package/template/hero/hero_1.ejs +337 -118
package/lib/index.js
CHANGED
|
@@ -43,12 +43,16 @@ var import_koishi = require("koishi");
|
|
|
43
43
|
var utils_exports = {};
|
|
44
44
|
__export(utils_exports, {
|
|
45
45
|
CONFIGS: () => CONFIGS,
|
|
46
|
+
HeroDescType: () => HeroDescType,
|
|
47
|
+
ImageFormat: () => ImageFormat,
|
|
46
48
|
ImageType: () => ImageType,
|
|
49
|
+
formatHeroDesc: () => formatHeroDesc,
|
|
47
50
|
formatNumber: () => formatNumber,
|
|
48
51
|
getFormattedMatchData: () => getFormattedMatchData,
|
|
49
52
|
getImageUrl: () => getImageUrl,
|
|
50
53
|
playerisValid: () => playerisValid,
|
|
51
54
|
query: () => query,
|
|
55
|
+
queryHeroFromValve: () => queryHeroFromValve,
|
|
52
56
|
readDirectoryFilesSync: () => readDirectoryFilesSync,
|
|
53
57
|
roundToDecimalPlaces: () => roundToDecimalPlaces,
|
|
54
58
|
sec2time: () => sec2time,
|
|
@@ -513,6 +517,17 @@ async function query(query_str) {
|
|
|
513
517
|
});
|
|
514
518
|
}
|
|
515
519
|
__name(query, "query");
|
|
520
|
+
async function queryHeroFromValve(heroId) {
|
|
521
|
+
return (await http.get(`https://www.dota2.com/datafeed/herodata?language=schinese&hero_id=${heroId}`)).result.data.heroes[0];
|
|
522
|
+
}
|
|
523
|
+
__name(queryHeroFromValve, "queryHeroFromValve");
|
|
524
|
+
var HeroDescType = /* @__PURE__ */ ((HeroDescType2) => {
|
|
525
|
+
HeroDescType2["Normal"] = "normal";
|
|
526
|
+
HeroDescType2["Facet"] = "facet";
|
|
527
|
+
HeroDescType2["Scepter"] = "scepter";
|
|
528
|
+
HeroDescType2["Shard"] = "shard";
|
|
529
|
+
return HeroDescType2;
|
|
530
|
+
})(HeroDescType || {});
|
|
516
531
|
var ImageType = /* @__PURE__ */ ((ImageType2) => {
|
|
517
532
|
ImageType2["Icons"] = "icons";
|
|
518
533
|
ImageType2["IconsFacets"] = "icons/facets";
|
|
@@ -523,7 +538,12 @@ var ImageType = /* @__PURE__ */ ((ImageType2) => {
|
|
|
523
538
|
ImageType2["Local"] = "local";
|
|
524
539
|
return ImageType2;
|
|
525
540
|
})(ImageType || {});
|
|
526
|
-
|
|
541
|
+
var ImageFormat = /* @__PURE__ */ ((ImageFormat2) => {
|
|
542
|
+
ImageFormat2["png"] = "png";
|
|
543
|
+
ImageFormat2["svg"] = "svg";
|
|
544
|
+
return ImageFormat2;
|
|
545
|
+
})(ImageFormat || {});
|
|
546
|
+
function getImageUrl(image, type = "local" /* Local */, format = "png" /* png */) {
|
|
527
547
|
if (type === "local" /* Local */) {
|
|
528
548
|
try {
|
|
529
549
|
const imageData = import_fs.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-dota2tracker/template/images/${image}.png`);
|
|
@@ -534,7 +554,7 @@ function getImageUrl(image, type = "local" /* Local */) {
|
|
|
534
554
|
return "";
|
|
535
555
|
}
|
|
536
556
|
} else
|
|
537
|
-
return `https://cdn.cloudflare.steamstatic.com/apps/dota2/images/dota_react/${type}/${image}
|
|
557
|
+
return `https://cdn.cloudflare.steamstatic.com/apps/dota2/images/dota_react/${type}/${image}.${format}`;
|
|
538
558
|
}
|
|
539
559
|
__name(getImageUrl, "getImageUrl");
|
|
540
560
|
function getFormattedMatchData(match) {
|
|
@@ -600,7 +620,7 @@ function getFormattedMatchData(match) {
|
|
|
600
620
|
if (!match.party[player.partyId])
|
|
601
621
|
match.party[player.partyId] = party_mark[party_index++];
|
|
602
622
|
}
|
|
603
|
-
if (
|
|
623
|
+
if (player.stats.matchPlayerBuffEvent) {
|
|
604
624
|
const maxStackCountsByAbilityOrItem = player.stats.matchPlayerBuffEvent.reduce((acc, event) => {
|
|
605
625
|
const key = event.abilityId !== null ? `ability-${event.abilityId}` : `item-${event.itemId}`;
|
|
606
626
|
if (!acc[key] || event.stackCount > acc[key].stackCount) {
|
|
@@ -843,6 +863,34 @@ function roundToDecimalPlaces(number, decimalPlaces) {
|
|
|
843
863
|
return Math.round(number * factor) / factor;
|
|
844
864
|
}
|
|
845
865
|
__name(roundToDecimalPlaces, "roundToDecimalPlaces");
|
|
866
|
+
function formatHeroDesc(template, special_values, type = "normal" /* Normal */) {
|
|
867
|
+
return template.replace(/%%|%([^%]+)%/g, (match, p1) => {
|
|
868
|
+
if (match === "%%") {
|
|
869
|
+
return "%";
|
|
870
|
+
} else {
|
|
871
|
+
const specialValue = special_values.find((sv) => {
|
|
872
|
+
const match2 = /bonus_(.*)/.exec(p1);
|
|
873
|
+
return sv.name === p1 || sv.name === match2?.[1];
|
|
874
|
+
});
|
|
875
|
+
if (specialValue) {
|
|
876
|
+
let valuesToUse = "";
|
|
877
|
+
if (type == "facet" /* Facet */) {
|
|
878
|
+
valuesToUse = specialValue.facet_bonus.name ? specialValue.facet_bonus.values.join(" / ") : specialValue.values_float.join(" / ");
|
|
879
|
+
} else if (type == "scepter" /* Scepter */) {
|
|
880
|
+
valuesToUse = specialValue.values_scepter.length ? specialValue.values_scepter.join(" / ") : specialValue.values_float.join(" / ");
|
|
881
|
+
} else if (type == "shard" /* Shard */) {
|
|
882
|
+
valuesToUse = specialValue.values_shard.length ? specialValue.values_shard.join(" / ") : specialValue.values_float.join(" / ");
|
|
883
|
+
} else {
|
|
884
|
+
valuesToUse = specialValue.values_float.join(" / ");
|
|
885
|
+
}
|
|
886
|
+
return `<span class="value">${valuesToUse}</span>`;
|
|
887
|
+
} else {
|
|
888
|
+
return match;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
__name(formatHeroDesc, "formatHeroDesc");
|
|
846
894
|
|
|
847
895
|
// src/index.ts
|
|
848
896
|
var import_fs2 = __toESM(require("fs"));
|
|
@@ -954,8 +1002,8 @@ var rank = {
|
|
|
954
1002
|
"7": "超凡入圣",
|
|
955
1003
|
"8": "冠绝一世"
|
|
956
1004
|
};
|
|
957
|
-
var roles =
|
|
958
|
-
var primary_attrs = {
|
|
1005
|
+
var roles = ["核心", "辅助", "爆发", "控制", "打野", "耐久", "逃生", "推进", "先手"];
|
|
1006
|
+
var primary_attrs = { "3": "hero_universal", "0": "hero_strength", "1": "hero_agility", "2": "hero_intelligence" };
|
|
959
1007
|
var behavior = {
|
|
960
1008
|
"Unit Target": "单位目标",
|
|
961
1009
|
Channeled: "持续施法",
|
|
@@ -1402,29 +1450,103 @@ async function apply(ctx, config) {
|
|
|
1402
1450
|
}
|
|
1403
1451
|
}
|
|
1404
1452
|
});
|
|
1405
|
-
ctx.command("查询英雄 <input_data>", "查询英雄技能/面板信息").usage("查询英雄的技能说明与各项数据,生成图片发布。\n参数可输入英雄ID、英雄名、英雄常用别名").example("-查询英雄 15").example("-查询英雄 雷泽").example("-查询英雄 电魂").action(async ({ session }, input_data) => {
|
|
1453
|
+
ctx.command("查询英雄 <input_data>", "查询英雄技能/面板信息").usage("查询英雄的技能说明与各项数据,生成图片发布。\n参数可输入英雄ID、英雄名、英雄常用别名").option("random", "-r 随机选择英雄").option("refresh", "-f 忽略缓存刷新数据").example("-查询英雄 15").example("-查询英雄 雷泽").example("-查询英雄 电魂").action(async ({ session, options }, input_data) => {
|
|
1454
|
+
if (options.random)
|
|
1455
|
+
input_data = random.pick(Object.keys(HEROES_CHINESE));
|
|
1406
1456
|
if (input_data) {
|
|
1407
|
-
let
|
|
1408
|
-
if (!
|
|
1457
|
+
let hero = findingHero(input_data);
|
|
1458
|
+
if (!hero) {
|
|
1409
1459
|
session.send("未找到输入的英雄,请确认后重新输入。");
|
|
1410
1460
|
return;
|
|
1411
1461
|
}
|
|
1412
1462
|
try {
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1463
|
+
const tempHero = await ctx.database.get("dt_hero_data_cache", hero.id);
|
|
1464
|
+
if (tempHero.length && !options.refresh) {
|
|
1465
|
+
const gameVersionId = (await query(CURRENT_GAMEVERSION())).data.constants.gameVersions[0].id;
|
|
1466
|
+
if (tempHero[0].gameVersionId >= gameVersionId) {
|
|
1467
|
+
hero = tempHero[0].hero;
|
|
1468
|
+
}
|
|
1469
|
+
} else {
|
|
1470
|
+
const queryHero = await queryHeroFromValve(hero.id);
|
|
1471
|
+
Object.assign(hero, queryHero);
|
|
1472
|
+
hero.facet_abilities.forEach((fa, i) => {
|
|
1473
|
+
if (fa.abilities.length) {
|
|
1474
|
+
fa.abilities.forEach((ab) => {
|
|
1475
|
+
if (!hero.facets[i].abilities)
|
|
1476
|
+
hero.facets[i].abilities = [];
|
|
1477
|
+
if (hero.facets[i].description_loc !== ab.desc_loc)
|
|
1478
|
+
hero.facets[i].abilities.push({ id: ab.id, name: ab.name, name_loc: ab.name_loc, description_ability_loc: formatHeroDesc(ab.desc_loc, ab.special_values, "facet" /* Facet */) });
|
|
1479
|
+
else
|
|
1480
|
+
hero.facets[i].description_loc = formatHeroDesc(hero.facets[i].description_loc, ab.special_values, "facet" /* Facet */);
|
|
1481
|
+
hero.abilities.push(ab);
|
|
1482
|
+
});
|
|
1483
|
+
}
|
|
1484
|
+
});
|
|
1485
|
+
const all_special_values = [...hero.abilities.flatMap((ab) => ab.special_values), ...hero.facet_abilities.flatMap((fas) => fas.abilities.flatMap((fa) => fa.special_values))];
|
|
1486
|
+
hero.abilities.forEach((ab) => {
|
|
1487
|
+
ab.facets_loc.forEach((facet, i) => {
|
|
1488
|
+
if (facet) {
|
|
1489
|
+
if (!hero.facets[i].abilities)
|
|
1490
|
+
hero.facets[i].abilities = [];
|
|
1491
|
+
hero.facets[i].abilities.push({ id: ab.id, name: ab.name, name_loc: ab.name_loc, description_ability_loc: formatHeroDesc(facet, all_special_values, "facet" /* Facet */), attributes: [] });
|
|
1492
|
+
}
|
|
1493
|
+
});
|
|
1494
|
+
hero.facets.forEach((facet) => {
|
|
1495
|
+
const svs = ab.special_values.filter((sv) => sv.facet_bonus.name === facet.name);
|
|
1496
|
+
svs.forEach((sv) => {
|
|
1497
|
+
if (sv.heading_loc) {
|
|
1498
|
+
facet.abilities.find((ability) => ab.id == ability.id)?.attributes.push({ heading_loc: sv.heading_loc, values: [...sv.facet_bonus.values] });
|
|
1499
|
+
}
|
|
1500
|
+
});
|
|
1501
|
+
});
|
|
1502
|
+
ab.desc_loc = formatHeroDesc(ab.desc_loc, all_special_values);
|
|
1503
|
+
ab.notes_loc = ab.notes_loc.map((note) => formatHeroDesc(note, all_special_values));
|
|
1504
|
+
if (ab.ability_has_scepter)
|
|
1505
|
+
ab.scepter_loc = formatHeroDesc(ab.scepter_loc, ab.special_values, "scepter" /* Scepter */);
|
|
1506
|
+
if (ab.ability_has_shard)
|
|
1507
|
+
ab.shard_loc = formatHeroDesc(ab.shard_loc, ab.special_values, "shard" /* Shard */);
|
|
1508
|
+
});
|
|
1509
|
+
hero.talents.forEach((talent) => {
|
|
1510
|
+
const regex = /\{s:(.*?)\}/g;
|
|
1511
|
+
let match;
|
|
1512
|
+
while ((match = regex.exec(talent.name_loc)) !== null) {
|
|
1513
|
+
const specialValueName = match[1];
|
|
1514
|
+
const target = talent.special_values?.find((sv) => sv.name === specialValueName);
|
|
1515
|
+
if (target) {
|
|
1516
|
+
talent.name_loc = talent.name_loc.replace(match[0], target.values_float.join("/"));
|
|
1517
|
+
} else {
|
|
1518
|
+
const ability = hero.abilities.find((ability2) => ability2.special_values.some((specialValue) => specialValue.bonuses.some((bonus) => bonus.name === talent.name)));
|
|
1519
|
+
if (ability) {
|
|
1520
|
+
const specialValues = ability.special_values.filter((specialValue) => specialValue.bonuses.some((bonus) => bonus.name === talent.name));
|
|
1521
|
+
const regex2 = /{s:bonus_(.*?)}/g;
|
|
1522
|
+
let match2;
|
|
1523
|
+
const replacements = [];
|
|
1524
|
+
while ((match2 = regex2.exec(talent.name_loc)) !== null) {
|
|
1525
|
+
const specialValue = specialValues.find((sv) => sv.name === String(match2[1]));
|
|
1526
|
+
const replacement = specialValue?.bonuses.find((bonus) => bonus.name === talent.name)?.value;
|
|
1527
|
+
if (replacement !== void 0) {
|
|
1528
|
+
replacements.push({ original: match2[0], replacement });
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
replacements.forEach(({ original, replacement }) => {
|
|
1532
|
+
talent.name_loc = talent.name_loc.replace(original, replacement);
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
});
|
|
1538
|
+
try {
|
|
1539
|
+
const gameVersionId = (await query(CURRENT_GAMEVERSION())).data.constants.gameVersions[0].id;
|
|
1540
|
+
await ctx.database.upsert("dt_hero_data_cache", (row) => [{ id: hero.id, hero, gameVersionId }]);
|
|
1541
|
+
} catch (error) {
|
|
1542
|
+
ctx.logger.error(error);
|
|
1543
|
+
await session.send("数据缓存失败。");
|
|
1544
|
+
}
|
|
1420
1545
|
}
|
|
1421
|
-
let hero = (await query(HERO_INFO(fhero.id))).data.constants.hero;
|
|
1422
|
-
hero.talents.forEach((talent) => talent.name_cn = AbilitiesConstantsCN.data.abilities?.find((item) => item.id == talent.abilityId)?.language?.displayName);
|
|
1423
1546
|
await session.send(await ctx.puppeteer.render(genImageHTML(hero, config.template_hero, "hero" /* Hero */)));
|
|
1424
1547
|
} catch (error) {
|
|
1425
1548
|
ctx.logger.error(error);
|
|
1426
|
-
session.send("获取数据失败");
|
|
1427
|
-
return;
|
|
1549
|
+
await session.send("获取数据失败");
|
|
1428
1550
|
}
|
|
1429
1551
|
} else {
|
|
1430
1552
|
session.send("请输入参数。");
|
|
@@ -1466,8 +1588,7 @@ async function apply(ctx, config) {
|
|
|
1466
1588
|
let dc_heroes = Object.values(dotaconstants3.heroes).map((hero) => ({
|
|
1467
1589
|
id: hero["id"],
|
|
1468
1590
|
name: hero["name"],
|
|
1469
|
-
shortName: hero["name"].match(/^npc_dota_hero_(.+)$/)[1]
|
|
1470
|
-
localized_name: hero["localized_name"].toLowerCase().replace(/\s+/g, "")
|
|
1591
|
+
shortName: hero["name"].match(/^npc_dota_hero_(.+)$/)[1]
|
|
1471
1592
|
}));
|
|
1472
1593
|
let cn_heroes = Object.keys(HEROES_CHINESE).map((key) => ({
|
|
1473
1594
|
id: parseInt(key),
|
|
@@ -1487,157 +1608,6 @@ async function apply(ctx, config) {
|
|
|
1487
1608
|
return heroes3.find((hero) => hero.names_cn.some((cn) => cn.toLowerCase() == input.toLowerCase()) || hero.shortName === input.toLowerCase() || hero.id == input);
|
|
1488
1609
|
}
|
|
1489
1610
|
__name(findingHero, "findingHero");
|
|
1490
|
-
ctx.command("7.36 <input_data>", "查询7.36改动").option("refresh", "-r 重新获取数据").usage("可查询英雄改动并生成图片返回").example("7.36 小松许").action(async ({ session, options }, input_data) => {
|
|
1491
|
-
if (!("dt_7_36" in ctx.database.tables))
|
|
1492
|
-
await ctx.model.extend("dt_7_36", { id: "integer", data: "string" });
|
|
1493
|
-
const tem = await ctx.database.get("dt_7_36", void 0, ["id"]);
|
|
1494
|
-
if (!tem.length || options.refresh) {
|
|
1495
|
-
try {
|
|
1496
|
-
session.send((!tem.length ? "初次使用," : "") + "正在获取数据……");
|
|
1497
|
-
await ctx.model.extend("dt_7_36", { id: "integer", data: "string" });
|
|
1498
|
-
const page = await ctx.puppeteer.page();
|
|
1499
|
-
await page.setExtraHTTPHeaders({
|
|
1500
|
-
"Accept-Language": "zh-CN,zh;q=0.9"
|
|
1501
|
-
});
|
|
1502
|
-
await page.goto("https://www.dota2.com/patches/7.36");
|
|
1503
|
-
await page.waitForSelector("body > div:nth-of-type(2) > div:first-of-type > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(5) > div:nth-of-type(2) > div:nth-of-type(1)");
|
|
1504
|
-
await page.evaluate(() => {
|
|
1505
|
-
const scripts = document.querySelectorAll("script");
|
|
1506
|
-
scripts.forEach((script) => script.remove());
|
|
1507
|
-
});
|
|
1508
|
-
const result = await page.evaluate(() => {
|
|
1509
|
-
try {
|
|
1510
|
-
const divs = document.querySelectorAll("body > div:nth-of-type(2) > div:first-of-type > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(5) > div:nth-of-type(2) > div");
|
|
1511
|
-
const divArray = [];
|
|
1512
|
-
divs.forEach((div) => {
|
|
1513
|
-
const subDiv = div.querySelector("a > div");
|
|
1514
|
-
console.log(subDiv);
|
|
1515
|
-
const match = subDiv?.style.backgroundImage.match(/\/apps\/dota2\/images\/dota_react\/heroes\/([^"]+)\.png"\)/);
|
|
1516
|
-
console.log(match);
|
|
1517
|
-
divArray.push({ heroName: match[1], div: div.outerHTML });
|
|
1518
|
-
});
|
|
1519
|
-
document.querySelectorAll("body > div:nth-of-type(2) > div:first-of-type > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(5) > div:nth-of-type(2) > div:not(:first-of-type)").forEach((node) => node.remove());
|
|
1520
|
-
document.querySelector("body > div:nth-of-type(2) > div:first-of-type > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(5) > div:nth-of-type(2) > div").classList.add("placeholder");
|
|
1521
|
-
const prepareToRemovesNodes = [
|
|
1522
|
-
document.querySelector("body > div:first-of-type"),
|
|
1523
|
-
document.querySelector("body > div:nth-of-type(2) > div:first-of-type > div:first-of-type"),
|
|
1524
|
-
document.querySelector("body > div:nth-of-type(2) > div:first-of-type > div:nth-of-type(2) > div:nth-of-type(1)"),
|
|
1525
|
-
document.querySelector("body > div:nth-of-type(2) > div:first-of-type > div:nth-of-type(2) > div:nth-of-type(2)"),
|
|
1526
|
-
document.querySelector("body > div:nth-of-type(2) > div:first-of-type > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(5) > div:nth-of-type(1)"),
|
|
1527
|
-
...document.querySelectorAll("body > div:nth-of-type(2) > div:first-of-type > div:nth-of-type(2) > div:nth-of-type(3) > div:not(:last-of-type)")
|
|
1528
|
-
];
|
|
1529
|
-
prepareToRemovesNodes.forEach((node) => node?.remove());
|
|
1530
|
-
const remainingContent = document.documentElement.outerHTML;
|
|
1531
|
-
return {
|
|
1532
|
-
divArray,
|
|
1533
|
-
remainingContent
|
|
1534
|
-
};
|
|
1535
|
-
} catch (error) {
|
|
1536
|
-
console.error(error);
|
|
1537
|
-
}
|
|
1538
|
-
});
|
|
1539
|
-
page.close();
|
|
1540
|
-
const heroes3 = [];
|
|
1541
|
-
result.divArray.forEach((hero) => {
|
|
1542
|
-
const res = Object.values(dotaconstants3.heroes).find((Chero) => Chero.name.match(/^npc_dota_hero_(.+)$/)[1] == hero.heroName);
|
|
1543
|
-
heroes3.push({ id: res.id, data: hero.div });
|
|
1544
|
-
});
|
|
1545
|
-
heroes3.push({ id: 0, data: result.remainingContent });
|
|
1546
|
-
await ctx.database.upsert("dt_7_36", (row) => heroes3);
|
|
1547
|
-
await session.send("数据获取完成。");
|
|
1548
|
-
} catch (error) {
|
|
1549
|
-
ctx.logger.error(error);
|
|
1550
|
-
session.send("数据获取失败。");
|
|
1551
|
-
return;
|
|
1552
|
-
}
|
|
1553
|
-
}
|
|
1554
|
-
if (input_data) {
|
|
1555
|
-
try {
|
|
1556
|
-
const hero = findingHero(input_data);
|
|
1557
|
-
if (!hero) {
|
|
1558
|
-
session.send("英雄参数输入有误,请检查后重试。");
|
|
1559
|
-
return;
|
|
1560
|
-
}
|
|
1561
|
-
session.send("正在查询,请耐心等待……");
|
|
1562
|
-
const page = await ctx.puppeteer.page();
|
|
1563
|
-
await page.setRequestInterception(false);
|
|
1564
|
-
const [wrapperHTML, newHeroHTML] = (await ctx.database.get("dt_7_36", [0, hero.id])).map((data) => data.data);
|
|
1565
|
-
await page.setContent(wrapperHTML);
|
|
1566
|
-
await page.waitForSelector("div.placeholder");
|
|
1567
|
-
const placeholder = await page.$("div.placeholder");
|
|
1568
|
-
await page.waitForSelector("div.placeholder");
|
|
1569
|
-
await page.evaluate(
|
|
1570
|
-
(element, html) => {
|
|
1571
|
-
element.outerHTML = html;
|
|
1572
|
-
},
|
|
1573
|
-
placeholder,
|
|
1574
|
-
newHeroHTML
|
|
1575
|
-
);
|
|
1576
|
-
await page.evaluate(async () => {
|
|
1577
|
-
const images = Array.from(document.querySelectorAll("img"));
|
|
1578
|
-
const backgroundImages = Array.from(document.querySelectorAll("*")).filter((element) => {
|
|
1579
|
-
const bg = window.getComputedStyle(element).backgroundImage;
|
|
1580
|
-
return bg && bg !== "none";
|
|
1581
|
-
});
|
|
1582
|
-
await Promise.all([
|
|
1583
|
-
...images.map((img) => {
|
|
1584
|
-
if (img.complete)
|
|
1585
|
-
return Promise.resolve();
|
|
1586
|
-
else {
|
|
1587
|
-
return new Promise((resolve) => {
|
|
1588
|
-
img.onload = resolve;
|
|
1589
|
-
img.onerror = () => {
|
|
1590
|
-
const placeholderSrc = "https://cdn.cloudflare.steamstatic.com/apps/dota2/images/dota_react/icons/innate_icon.png";
|
|
1591
|
-
img.src = placeholderSrc;
|
|
1592
|
-
img.onload = resolve;
|
|
1593
|
-
img.onerror = resolve;
|
|
1594
|
-
};
|
|
1595
|
-
});
|
|
1596
|
-
}
|
|
1597
|
-
}),
|
|
1598
|
-
...backgroundImages.map((element) => {
|
|
1599
|
-
const bg = window.getComputedStyle(element).backgroundImage;
|
|
1600
|
-
const urlMatch = bg.match(/url\(["']?([^"')]+)["']?\)/);
|
|
1601
|
-
if (urlMatch && urlMatch[1]) {
|
|
1602
|
-
const src = urlMatch[1];
|
|
1603
|
-
return new Promise((resolve) => {
|
|
1604
|
-
const img = new Image();
|
|
1605
|
-
img.onload = resolve;
|
|
1606
|
-
img.onerror = () => {
|
|
1607
|
-
const placeholderSrc = "https://cdn.cloudflare.steamstatic.com/apps/dota2/images/dota_react/icons/innate_icon.png";
|
|
1608
|
-
img.src = placeholderSrc;
|
|
1609
|
-
img.onload = resolve;
|
|
1610
|
-
img.onerror = resolve;
|
|
1611
|
-
};
|
|
1612
|
-
img.src = src;
|
|
1613
|
-
});
|
|
1614
|
-
} else
|
|
1615
|
-
return Promise.resolve();
|
|
1616
|
-
})
|
|
1617
|
-
]);
|
|
1618
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1619
|
-
});
|
|
1620
|
-
const testE = await page.$("body > div > div > div > div > div > div > div");
|
|
1621
|
-
const res = await testE.screenshot();
|
|
1622
|
-
const base64String = Buffer.from(res).toString("base64");
|
|
1623
|
-
const imgTag = `<img src="data:image/png;base64,${base64String}" alt="Image" />`;
|
|
1624
|
-
if (process.env.NODE_ENV === "development")
|
|
1625
|
-
import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.png", res);
|
|
1626
|
-
if (process.env.NODE_ENV === "development")
|
|
1627
|
-
import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.html", await page.content());
|
|
1628
|
-
session.send(imgTag);
|
|
1629
|
-
page.close();
|
|
1630
|
-
} catch (error) {
|
|
1631
|
-
ctx.logger.error(error);
|
|
1632
|
-
session.send("查询改动失败。");
|
|
1633
|
-
}
|
|
1634
|
-
} else
|
|
1635
|
-
session.send("https://www.dota2.com/patches/7.36");
|
|
1636
|
-
});
|
|
1637
|
-
ctx.command("test <input_data>").option("a", "a").action(async ({ session, options }, input_data) => {
|
|
1638
|
-
console.log(session);
|
|
1639
|
-
ctx.broadcast(["kook:9510442027074966"], "test");
|
|
1640
|
-
});
|
|
1641
1611
|
ctx.on("ready", async () => {
|
|
1642
1612
|
const tables = await ctx.database.tables;
|
|
1643
1613
|
if (!("dt_subscribed_guilds" in tables)) {
|
|
@@ -1652,8 +1622,8 @@ async function apply(ctx, config) {
|
|
|
1652
1622
|
if (!("dt_previous_query_results" in tables)) {
|
|
1653
1623
|
ctx.model.extend("dt_previous_query_results", { matchId: "unsigned", data: "json", queryTime: "timestamp" }, { primary: "matchId" });
|
|
1654
1624
|
}
|
|
1655
|
-
if (!("
|
|
1656
|
-
ctx.model.extend("
|
|
1625
|
+
if (!("dt_hero_data_cache" in tables)) {
|
|
1626
|
+
ctx.model.extend("dt_hero_data_cache", { id: "unsigned", gameVersionId: "unsigned", hero: "json" });
|
|
1657
1627
|
}
|
|
1658
1628
|
ctx.cron("0 */6 * * *", () => {
|
|
1659
1629
|
const oneMonthAgo = (0, import_moment.default)().subtract(1, "months").toDate();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjtdev/koishi-plugin-dota2tracker",
|
|
3
3
|
"description": "koishi插件-追踪群友的DOTA2对局",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.0-hotfix",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"dota2"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"dotaconstants": "^8.
|
|
29
|
+
"dotaconstants": "^8.8.0",
|
|
30
30
|
"ejs": "^3.1.10",
|
|
31
31
|
"moment": "^2.30.1"
|
|
32
32
|
},
|
package/template/hero/hero_1.ejs
CHANGED
|
@@ -131,21 +131,42 @@
|
|
|
131
131
|
line-height: 1.25;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
.details .hype .npe {
|
|
135
|
+
color: #a5e0f3;
|
|
136
|
+
font-weight: bold;
|
|
137
|
+
line-height: 2;
|
|
138
|
+
}
|
|
139
|
+
|
|
134
140
|
.talents {
|
|
135
|
-
display:
|
|
136
|
-
|
|
137
|
-
|
|
141
|
+
display: grid;
|
|
142
|
+
grid-template-rows: repeat(4, 35px);
|
|
143
|
+
gap: 10px;
|
|
138
144
|
border: #444 10px solid;
|
|
139
|
-
/* background-color: ; */
|
|
140
|
-
/* padding: 10px; */
|
|
141
145
|
box-sizing: border-box;
|
|
146
|
+
position: relative; /* 添加相对定位 */
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.talents::before {
|
|
150
|
+
content: "";
|
|
151
|
+
position: absolute;
|
|
152
|
+
top: 0;
|
|
153
|
+
left: 0;
|
|
154
|
+
right: 0;
|
|
155
|
+
bottom: 0;
|
|
156
|
+
background: #444;
|
|
157
|
+
pointer-events: none; /* 使伪元素不可点击 */
|
|
158
|
+
box-sizing: border-box;
|
|
159
|
+
width: 395px;
|
|
160
|
+
transform: translate(-10px, -10px); /* 调整伪元素的位置 */
|
|
142
161
|
}
|
|
143
162
|
|
|
144
163
|
.talents .talent {
|
|
145
164
|
width: 375px;
|
|
146
|
-
line-height: 35px;
|
|
147
165
|
text-align: center;
|
|
148
166
|
display: flex;
|
|
167
|
+
align-items: center;
|
|
168
|
+
background: #000; /* 设置背景颜色以覆盖伪元素的背景 */
|
|
169
|
+
position: relative; /* 添加相对定位 */
|
|
149
170
|
}
|
|
150
171
|
|
|
151
172
|
.talents .talent .left,
|
|
@@ -154,13 +175,9 @@
|
|
|
154
175
|
font-size: 12px;
|
|
155
176
|
}
|
|
156
177
|
|
|
157
|
-
.talents .talent:not(:last-child) {
|
|
158
|
-
border-bottom: 10px solid #444;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
178
|
.talents .talent .level {
|
|
162
|
-
flex: 0 0 auto;
|
|
163
|
-
width: 35px;
|
|
179
|
+
flex: 0 0 auto;
|
|
180
|
+
width: 35px;
|
|
164
181
|
height: 35px;
|
|
165
182
|
font-size: 18px;
|
|
166
183
|
line-height: 35px;
|
|
@@ -170,8 +187,6 @@
|
|
|
170
187
|
color: #e7d292;
|
|
171
188
|
text-shadow: 0px 0px 8px #ff531c;
|
|
172
189
|
background-color: #444;
|
|
173
|
-
/* font-family: Reaver, serif;
|
|
174
|
-
font-weight: bold; */
|
|
175
190
|
}
|
|
176
191
|
|
|
177
192
|
.details .list {
|
|
@@ -186,6 +201,128 @@
|
|
|
186
201
|
background-color: #333;
|
|
187
202
|
}
|
|
188
203
|
|
|
204
|
+
.facets {
|
|
205
|
+
display: flex;
|
|
206
|
+
flex-wrap: wrap;
|
|
207
|
+
gap: 10px; /* 可选:设置项目之间的间距 */
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.facet {
|
|
211
|
+
flex: 1 1 calc(50% - 10px); /* 每行两个项目 */
|
|
212
|
+
box-sizing: border-box; /* 包含padding和border在宽度和高度的计算中 */
|
|
213
|
+
background-color: #181f24;
|
|
214
|
+
position: relative;
|
|
215
|
+
border: 1px solid #2b2f33;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.facet:nth-child(odd):last-child {
|
|
219
|
+
flex-basis: 100%; /* 最后一个奇数项目占据整行 */
|
|
220
|
+
}
|
|
221
|
+
.facet > .name_back {
|
|
222
|
+
position: absolute;
|
|
223
|
+
height: 50px;
|
|
224
|
+
width: 100%;
|
|
225
|
+
}
|
|
226
|
+
.facet > .name_back.type_0 {
|
|
227
|
+
background: linear-gradient(to right, #9f3c3c, #4a2026);
|
|
228
|
+
}
|
|
229
|
+
.facet > .name_line.type_0 {
|
|
230
|
+
filter: invert(22%) sepia(100%) saturate(100%) hue-rotate(316deg) brightness(98%) contrast(100%);
|
|
231
|
+
}
|
|
232
|
+
.facet > .name_back.type_1 {
|
|
233
|
+
background: linear-gradient(to right, #c8a45c, #6f3d21);
|
|
234
|
+
}
|
|
235
|
+
.facet > .name_line.type_1 {
|
|
236
|
+
filter: invert(54%) sepia(99%) saturate(100%) hue-rotate(0deg) brightness(97%) contrast(100%);
|
|
237
|
+
}
|
|
238
|
+
.facet > .name_back.type_2 {
|
|
239
|
+
background: linear-gradient(to right, #a2b23e, #2d5a18);
|
|
240
|
+
}
|
|
241
|
+
.facet > .name_line.type_2 {
|
|
242
|
+
filter: invert(57%) sepia(100%) saturate(100%) hue-rotate(32deg) brightness(93%) contrast(100%);
|
|
243
|
+
}
|
|
244
|
+
.facet > .name_back.type_3 {
|
|
245
|
+
background: linear-gradient(to right, #547ea6, #2a385e);
|
|
246
|
+
}
|
|
247
|
+
.facet > .name_line.type_3 {
|
|
248
|
+
filter: invert(39%) sepia(100%) saturate(99%) hue-rotate(167deg) brightness(99%) contrast(100%);
|
|
249
|
+
}
|
|
250
|
+
.facet > .name_back.type_4 {
|
|
251
|
+
background: linear-gradient(to right, #675cae, #261c44);
|
|
252
|
+
}
|
|
253
|
+
.facet > .name_line.type_4 {
|
|
254
|
+
filter: invert(33%) sepia(100%) saturate(100%) hue-rotate(207deg) brightness(99%) contrast(100%);
|
|
255
|
+
}
|
|
256
|
+
.facet > .name_back.type_5 {
|
|
257
|
+
background: linear-gradient(to right, #adb6be, #4e5557);
|
|
258
|
+
}
|
|
259
|
+
.facet > .name_line.type_5 {
|
|
260
|
+
filter: invert(73%) sepia(23%) saturate(99%) hue-rotate(166deg) brightness(93%) contrast(94%);
|
|
261
|
+
}
|
|
262
|
+
.facet > .name_line {
|
|
263
|
+
position: absolute;
|
|
264
|
+
background-size: cover;
|
|
265
|
+
height: 50px;
|
|
266
|
+
width: 100%;
|
|
267
|
+
background-image: url("https://cdn.akamai.steamstatic.com/apps/dota2/images/dota_react/icons/facets/ripple_texture.png");
|
|
268
|
+
}
|
|
269
|
+
.facet > .name {
|
|
270
|
+
height: 50px;
|
|
271
|
+
line-height: 50px;
|
|
272
|
+
z-index: 1;
|
|
273
|
+
position: relative;
|
|
274
|
+
display: flex;
|
|
275
|
+
}
|
|
276
|
+
.facet > .name > img {
|
|
277
|
+
width: 24px;
|
|
278
|
+
padding: 13px;
|
|
279
|
+
background-color: #0003;
|
|
280
|
+
}
|
|
281
|
+
.facet > .name > span {
|
|
282
|
+
margin-left: 16px;
|
|
283
|
+
letter-spacing: 2px;
|
|
284
|
+
text-shadow: 2px 2px 3px rgba(0, 0, 0, 0.3), 4px 4px 6px rgba(0, 0, 0, 0.2), 6px 6px 9px rgba(0, 0, 0, 0.1);
|
|
285
|
+
}
|
|
286
|
+
.facet > .content {
|
|
287
|
+
padding: 12px;
|
|
288
|
+
|
|
289
|
+
display: flex;
|
|
290
|
+
flex-direction: column;
|
|
291
|
+
gap: 12px;
|
|
292
|
+
}
|
|
293
|
+
.facet > .content > .ability {
|
|
294
|
+
display: flex;
|
|
295
|
+
flex-direction: column;
|
|
296
|
+
gap: 12px;
|
|
297
|
+
}
|
|
298
|
+
.facet > .content > .ability > .name {
|
|
299
|
+
background: linear-gradient(to right, #9bcdff17 0%, #9bcdff09 30%, #d0e8ff00 100%);
|
|
300
|
+
line-height: 1;
|
|
301
|
+
}
|
|
302
|
+
.facet > .content > .ability > .name > img {
|
|
303
|
+
width: 30px;
|
|
304
|
+
}
|
|
305
|
+
.facet > .content > .ability > .name > span {
|
|
306
|
+
margin-left: 10px;
|
|
307
|
+
font-size: 14px;
|
|
308
|
+
/* font-weight: bold; */
|
|
309
|
+
}
|
|
310
|
+
.facet > .content .description {
|
|
311
|
+
color: #9ab0cd;
|
|
312
|
+
}
|
|
313
|
+
.facet > .content > .ability > .attributes {
|
|
314
|
+
font-size: 12px;
|
|
315
|
+
display: flex;
|
|
316
|
+
flex-direction: column;
|
|
317
|
+
gap: 5px;
|
|
318
|
+
}
|
|
319
|
+
.facet > .content > .ability > .attributes .item {
|
|
320
|
+
color: #737373;
|
|
321
|
+
}
|
|
322
|
+
.facet > .content .value {
|
|
323
|
+
color: #fff;
|
|
324
|
+
}
|
|
325
|
+
|
|
189
326
|
.skills {
|
|
190
327
|
width: 800px;
|
|
191
328
|
display: flex;
|
|
@@ -209,8 +346,19 @@
|
|
|
209
346
|
background-color: #1f272b;
|
|
210
347
|
padding: 8px;
|
|
211
348
|
font-weight: 100;
|
|
349
|
+
}
|
|
350
|
+
.skill > .title > .name {
|
|
212
351
|
font-family: "KaiTi", "楷体", "楷体_GB2312", "STKaiti", serif;
|
|
213
352
|
}
|
|
353
|
+
.skill > .title > .is_innate {
|
|
354
|
+
font-size: 14px;
|
|
355
|
+
line-height: 18px;
|
|
356
|
+
width: auto;
|
|
357
|
+
display: inline;
|
|
358
|
+
padding: 2px 8px;
|
|
359
|
+
box-sizing: content-box;
|
|
360
|
+
background-color: #5b93d1;
|
|
361
|
+
}
|
|
214
362
|
|
|
215
363
|
.skill img.scepter,
|
|
216
364
|
.skill img.shard {
|
|
@@ -272,6 +420,14 @@
|
|
|
272
420
|
margin-bottom: 32px;
|
|
273
421
|
}
|
|
274
422
|
|
|
423
|
+
.skill .facet {
|
|
424
|
+
padding-left: 0;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.skill .value{
|
|
428
|
+
color: #fff;
|
|
429
|
+
}
|
|
430
|
+
|
|
275
431
|
.skill .aghanim_description {
|
|
276
432
|
padding-left: 0;
|
|
277
433
|
color: #9bb1ce;
|
|
@@ -293,7 +449,7 @@
|
|
|
293
449
|
display: block;
|
|
294
450
|
}
|
|
295
451
|
|
|
296
|
-
.skill .aghanim_description img{
|
|
452
|
+
.skill .aghanim_description img {
|
|
297
453
|
position: unset;
|
|
298
454
|
transform: none;
|
|
299
455
|
}
|
|
@@ -317,6 +473,10 @@
|
|
|
317
473
|
color: #4b525d;
|
|
318
474
|
}
|
|
319
475
|
|
|
476
|
+
.skill .attributes .values > img {
|
|
477
|
+
width: 16px;
|
|
478
|
+
}
|
|
479
|
+
|
|
320
480
|
.skill .attributes {
|
|
321
481
|
margin-bottom: 12px;
|
|
322
482
|
}
|
|
@@ -365,45 +525,46 @@
|
|
|
365
525
|
<div class="wrapper">
|
|
366
526
|
<%- `
|
|
367
527
|
<div class="hero" id="${hero.id}">
|
|
368
|
-
<img src="${utils.getImageUrl(hero.shortName, ImageType.Heroes)}"
|
|
369
|
-
<img class="pri_attr" src="${utils.getImageUrl(d2a.primary_attrs[
|
|
528
|
+
<img src="${utils.getImageUrl(hero.shortName, ImageType.Heroes)}"/>
|
|
529
|
+
<img class="pri_attr" src="${utils.getImageUrl(d2a.primary_attrs[hero.primary_attr], ImageType.Icons)}"/>
|
|
370
530
|
<div class="info">
|
|
371
|
-
<p class="name">${hero.
|
|
531
|
+
<p class="name">${hero.name_loc}</p>
|
|
372
532
|
<p class="roles">
|
|
373
|
-
${hero.
|
|
533
|
+
${hero.role_levels.map((item, index) => item>0?`<span class="role level${item}">${d2a.roles[index]}</span>`:"").join("")}
|
|
374
534
|
</p>
|
|
375
535
|
<p class="attrs">
|
|
376
|
-
<span class="str">${
|
|
377
|
-
<span class="agi">${
|
|
378
|
-
<span class="int">${
|
|
536
|
+
<span class="str">${hero.str_base} <span class="gain">+${hero.str_gain.toFixed(1)}</span></span>
|
|
537
|
+
<span class="agi">${hero.agi_base} <span class="gain">+${hero.agi_gain.toFixed(1)}</span></span>
|
|
538
|
+
<span class="int">${hero.int_base} <span class="gain">+${hero.int_gain.toFixed(1)}</span></span>
|
|
379
539
|
</p>
|
|
380
540
|
</div>
|
|
381
541
|
</div>
|
|
382
542
|
<div class="details">
|
|
383
543
|
<div class="hype_talents">
|
|
384
544
|
<div class="hype">
|
|
385
|
-
|
|
545
|
+
<p class="npe">${hero.npe_desc_loc}</p>
|
|
546
|
+
${hero.hype_loc}
|
|
386
547
|
</div>
|
|
387
548
|
<div class="talents">
|
|
388
549
|
<div class="talent">
|
|
389
|
-
<div class="left">${hero.talents[7].
|
|
550
|
+
<div class="left">${hero.talents[7].name_loc}</div>
|
|
390
551
|
<div class="level">25</div>
|
|
391
|
-
<div class="right">${hero.talents[6].
|
|
552
|
+
<div class="right">${hero.talents[6].name_loc}</div>
|
|
392
553
|
</div>
|
|
393
554
|
<div class="talent">
|
|
394
|
-
<div class="left">${hero.talents[5].
|
|
555
|
+
<div class="left">${hero.talents[5].name_loc}</div>
|
|
395
556
|
<div class="level">20</div>
|
|
396
|
-
<div class="right">${hero.talents[4].
|
|
557
|
+
<div class="right">${hero.talents[4].name_loc}</div>
|
|
397
558
|
</div>
|
|
398
559
|
<div class="talent">
|
|
399
|
-
<div class="left">${hero.talents[3].
|
|
560
|
+
<div class="left">${hero.talents[3].name_loc}</div>
|
|
400
561
|
<div class="level">15</div>
|
|
401
|
-
<div class="right">${hero.talents[2].
|
|
562
|
+
<div class="right">${hero.talents[2].name_loc}</div>
|
|
402
563
|
</div>
|
|
403
564
|
<div class="talent">
|
|
404
|
-
<div class="left">${hero.talents[1].
|
|
565
|
+
<div class="left">${hero.talents[1].name_loc}</div>
|
|
405
566
|
<div class="level">10</div>
|
|
406
|
-
<div class="right">${hero.talents[0].
|
|
567
|
+
<div class="right">${hero.talents[0].name_loc}</div>
|
|
407
568
|
</div>
|
|
408
569
|
</div>
|
|
409
570
|
</div>
|
|
@@ -411,36 +572,27 @@
|
|
|
411
572
|
<tbody>
|
|
412
573
|
<tr>
|
|
413
574
|
<td>初始生命值</td>
|
|
414
|
-
<td>${
|
|
575
|
+
<td>${hero.max_health}</td>
|
|
415
576
|
</tr>
|
|
416
577
|
<tr>
|
|
417
578
|
<td>初始生命回复</td>
|
|
418
|
-
<td>${
|
|
579
|
+
<td>${hero.health_regen.toFixed(2)}</td>
|
|
419
580
|
</tr>
|
|
420
581
|
<tr>
|
|
421
582
|
<td>初始魔法值</td>
|
|
422
|
-
<td>${
|
|
583
|
+
<td>${hero.max_mana}</td>
|
|
423
584
|
</tr>
|
|
424
585
|
<tr>
|
|
425
586
|
<td>初始魔法回复</td>
|
|
426
|
-
<td>${
|
|
587
|
+
<td>${hero.mana_regen.toFixed(2)}</td>
|
|
427
588
|
</tr>
|
|
428
589
|
<tr>
|
|
429
590
|
<td>初始攻击力</td>
|
|
430
|
-
<td>${
|
|
431
|
-
(dotaconstants.heroes[hero.id].base_str + dotaconstants.heroes[hero.id].base_agi + dotaconstants.heroes[hero.id].base_int) * 0.7
|
|
432
|
-
: dotaconstants.heroes[hero.id]["base_" + dotaconstants.heroes[hero.id].primary_attr])}
|
|
433
|
-
(${dotaconstants.heroes[hero.id].base_attack_min + Math.round(dotaconstants.heroes[hero.id].primary_attr == "all" ?
|
|
434
|
-
(dotaconstants.heroes[hero.id].base_str + dotaconstants.heroes[hero.id].base_agi + dotaconstants.heroes[hero.id].base_int) * 0.7
|
|
435
|
-
: dotaconstants.heroes[hero.id]["base_" + dotaconstants.heroes[hero.id].primary_attr])}
|
|
436
|
-
~${dotaconstants.heroes[hero.id].base_attack_max + Math.round(dotaconstants.heroes[hero.id].primary_attr == "all" ?
|
|
437
|
-
(dotaconstants.heroes[hero.id].base_str + dotaconstants.heroes[hero.id].base_agi + dotaconstants.heroes[hero.id].base_int) * 0.7
|
|
438
|
-
: dotaconstants.heroes[hero.id]["base_" + dotaconstants.heroes[hero.id].primary_attr])})
|
|
439
|
-
</td>
|
|
591
|
+
<td>${hero.damage_min}~${hero.damage_max}</td>
|
|
440
592
|
</tr>
|
|
441
593
|
<tr>
|
|
442
594
|
<td>基础攻击间隔</td>
|
|
443
|
-
<td>${
|
|
595
|
+
<td>${hero.attack_capability.toFixed(1)}</td>
|
|
444
596
|
</tr>
|
|
445
597
|
<tr>
|
|
446
598
|
<td>基础攻击前摇</td>
|
|
@@ -448,96 +600,163 @@
|
|
|
448
600
|
</tr>
|
|
449
601
|
<tr>
|
|
450
602
|
<td>攻击范围</td>
|
|
451
|
-
<td>${
|
|
603
|
+
<td>${hero.attack_range}</td>
|
|
452
604
|
</tr>
|
|
453
605
|
<tr>
|
|
454
606
|
<td>护甲</td>
|
|
455
|
-
<td>${
|
|
607
|
+
<td>${hero.armor.toFixed(1)}</td>
|
|
456
608
|
</tr>
|
|
457
609
|
<tr>
|
|
458
610
|
<td>移动速度</td>
|
|
459
|
-
<td>${
|
|
611
|
+
<td>${hero.movement_speed}</td>
|
|
460
612
|
</tr>
|
|
461
613
|
<tr>
|
|
462
614
|
<td>视野范围</td>
|
|
463
|
-
<td>${
|
|
615
|
+
<td>${hero.sight_range_day}(${hero.sight_range_night})</td>
|
|
464
616
|
</tr>
|
|
465
617
|
</tbody>
|
|
466
618
|
</table>
|
|
467
619
|
</div>
|
|
620
|
+
<div class="facets">
|
|
621
|
+
${hero.facets.map(facet=>`
|
|
622
|
+
<div class="facet">
|
|
623
|
+
<div class="name_back type_${facet.color}"></div>
|
|
624
|
+
<div class="name_line type_${facet.color}"></div>
|
|
625
|
+
<p class="name">
|
|
626
|
+
<img src="${utils.getImageUrl(facet.icon, ImageType.IconsFacets)}"/>
|
|
627
|
+
<span>${facet.title_loc}</span>
|
|
628
|
+
</p>
|
|
629
|
+
<div class="content">
|
|
630
|
+
${facet.description_loc ?`<p class="description">${facet.description_loc}</p>`:""}
|
|
631
|
+
${facet.abilities?facet.abilities.map(ability=>
|
|
632
|
+
`<div class="ability">
|
|
633
|
+
<div class="name">
|
|
634
|
+
<img src="${utils.getImageUrl(ability.name, ImageType.Abilities)}" onerror="this.onerror=null; this.src='${utils.getImageUrl(`innate_icon`,ImageType.Icons)}';"/>
|
|
635
|
+
<span>${ability.name_loc}</span>
|
|
636
|
+
</div>
|
|
637
|
+
${ability.description_ability_loc?`<div class="description">${ability.description_ability_loc}</div>`:""}
|
|
638
|
+
${ability.attributes&&ability.attributes?.length ? ability.attributes.map(attr=>
|
|
639
|
+
`<div class="attributes">
|
|
640
|
+
<p><span class="item">${attr.heading_loc}</span><span class="values">${attr.values.join(" / ")}</span></p>
|
|
641
|
+
</div>`).join(""):""}
|
|
642
|
+
</div>`).join("")
|
|
643
|
+
:""}
|
|
644
|
+
</div>
|
|
645
|
+
</div>
|
|
646
|
+
`).join("")}
|
|
647
|
+
</div>
|
|
468
648
|
<div class="skills">
|
|
469
|
-
${hero.abilities
|
|
649
|
+
${hero.abilities//.filter((item) => dotaconstants.abilities[item.name].behavior != "Hidden")
|
|
470
650
|
.map((item) => `
|
|
471
|
-
<div class="skill">
|
|
651
|
+
<div class="skill" data-ability="${item.ability_is_innate}">
|
|
472
652
|
<p class="title">
|
|
473
|
-
<span>${item.
|
|
474
|
-
${item.
|
|
475
|
-
${item.
|
|
653
|
+
<span class="name">${item.name_loc}</span>
|
|
654
|
+
${item.ability_is_innate?`<span class="is_innate">先天技能</span>`:""}
|
|
655
|
+
${item.ability_is_granted_by_scepter ?`<img src="${utils.getImageUrl("scepter")}" class="scepter">`:""}
|
|
656
|
+
${item.ability_is_granted_by_shard ?`<img src="${utils.getImageUrl("shard")}" class="shard">`:""}
|
|
476
657
|
</p>
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
658
|
+
<div class="img_stats">
|
|
659
|
+
<img src="${utils.getImageUrl(item.name, ImageType.Abilities)}" onerror="this.onerror=null; this.src='${utils.getImageUrl(`innate_icon`,ImageType.Icons)}';"/>
|
|
660
|
+
<div class="stats">
|
|
661
|
+
<p class="behavior">技能:${(Array.isArray(dotaconstants.abilities[item.name].behavior) ? dotaconstants.abilities[item.name].behavior : [dotaconstants.abilities[item.name].behavior])
|
|
662
|
+
.filter((beh) => beh !== "Hidden" || !(item.ability_is_granted_by_shard || item.ability_is_granted_by_scepter))
|
|
663
|
+
.map((beh) => d2a.behavior[beh])
|
|
664
|
+
.join("/")}</p>
|
|
665
|
+
${dotaconstants.abilities[item.name].target_team
|
|
666
|
+
? `<p class="target_team">影响:${(Array.isArray(dotaconstants.abilities[item.name].target_team)
|
|
667
|
+
? dotaconstants.abilities[item.name].target_team
|
|
668
|
+
: [dotaconstants.abilities[item.name].target_team])
|
|
669
|
+
.map((tt) => d2a.target_team[tt])
|
|
670
|
+
.join("/")}</p>`
|
|
671
|
+
: ""}
|
|
672
|
+
${!Array.isArray(dotaconstants.abilities[item.name].dmg_type) && dotaconstants.abilities[item.name].dmg_type
|
|
673
|
+
? `<p class="dmg_type ${dotaconstants.abilities[item.name].dmg_type}">伤害类型:</p>`
|
|
674
|
+
: ""}
|
|
675
|
+
${dotaconstants.abilities[item.name].dispellable
|
|
676
|
+
? `<p class="dispellable ${dotaconstants.abilities[item.name].dispellable == "Strong Dispels Only" ? "Strong" : dotaconstants.abilities[item.name].dispellable}">能否驱散:</p>`
|
|
677
|
+
: ""}
|
|
678
|
+
${!Array.isArray(dotaconstants.abilities[item.name].bkbpierce) && dotaconstants.abilities[item.name].bkbpierce
|
|
679
|
+
? `<p class="bkbpierce">无视减益免疫: ${dotaconstants.abilities[item.name].bkbpierce == "Yes" ? "是" : "否"}</p>`
|
|
680
|
+
: ""}
|
|
681
|
+
</div>
|
|
500
682
|
</div>
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
}
|
|
522
|
-
.
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
</
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
683
|
+
<p class="description">${item.desc_loc}</p>
|
|
684
|
+
${item.facets_loc.map((facet_loc,index)=>(facet_loc!=""?`
|
|
685
|
+
<div class="facet">
|
|
686
|
+
<div class="name_back type_${hero.facets[index].color}"></div>
|
|
687
|
+
<div class="name_line type_${hero.facets[index].color}"></div>
|
|
688
|
+
<p class="name">
|
|
689
|
+
<img src="${utils.getImageUrl(hero.facets[index].icon, ImageType.IconsFacets)}" />
|
|
690
|
+
<span>${hero.facets[index].title_loc}</span>
|
|
691
|
+
</p>
|
|
692
|
+
<div class="content">
|
|
693
|
+
<div class="ability">
|
|
694
|
+
<div class="description">${hero.facets[index].abilities.find(ab=>ab.id==item.id)?.description_ability_loc}</div>
|
|
695
|
+
</div>
|
|
696
|
+
</div>
|
|
697
|
+
</div>
|
|
698
|
+
`:"")).join("")}
|
|
699
|
+
${item.ability_has_scepter&&!item.ability_is_granted_by_scepter
|
|
700
|
+
? `<p class="aghanim_description">
|
|
701
|
+
<span class="title"><img src="${utils.getImageUrl("scepter")}"class="scepter">阿哈利姆神杖</span>
|
|
702
|
+
<span class="desc">${item.scepter_loc}</span>
|
|
703
|
+
</p>` : ""}
|
|
704
|
+
${item.ability_has_shard&&!item.ability_is_granted_by_shard
|
|
705
|
+
? `<p class="aghanim_description">
|
|
706
|
+
<span class="title"><img src="${utils.getImageUrl("shard")}"class="shard">阿哈利姆魔晶</span>
|
|
707
|
+
<span class="desc">${item.shard_loc}</span>
|
|
708
|
+
</p>` : ""}
|
|
709
|
+
<div class="notes"${!item.notes_loc.length ? ` style="display:none;"` : ""}>
|
|
710
|
+
${item.notes_loc.map((note) => `<p>${note}</p>`).join("")}
|
|
711
|
+
</div>
|
|
712
|
+
<div class="attributes">
|
|
713
|
+
${item.special_values
|
|
714
|
+
.filter(sv => sv.heading_loc)
|
|
715
|
+
.map((sv) => `<p><span class="item">${sv.heading_loc}</span><span class="values">${sv.values_float.map(value=>value+(sv.is_percentage?"%":"")).join(" / ")}${sv.bonuses.map(bonus=>` (<img src="${utils.getImageUrl("talents","icons","svg")}"/>${(bonus.value>0?"+":"")+bonus.value+(sv.is_percentage?"%":"")})`).join(" ")}</span></p>`)
|
|
716
|
+
.join("")}
|
|
717
|
+
</div>
|
|
718
|
+
<p>
|
|
719
|
+
${item.special_values.find(sv=>sv.name=="AbilityCooldown").values_float.length && !(item.special_values.find(sv=>sv.name=="AbilityCooldown").values_float.length === 1 && item.special_values.find(sv=>sv.name=="AbilityCooldown").values_float[0] === 0) ?
|
|
720
|
+
`<span class="cooldown"> ${item.special_values.find(sv=>sv.name=="AbilityCooldown").values_float.join(" / ")}
|
|
721
|
+
</span>` : ""}
|
|
722
|
+
${item.special_values.find(sv=>sv.name=="AbilityManaCost").values_float.length && !(item.special_values.find(sv=>sv.name=="AbilityManaCost").values_float.length === 1 && item.special_values.find(sv=>sv.name=="AbilityManaCost").values_float[0] === 0) ?
|
|
723
|
+
`<span class="mana_cost"> ${item.special_values.find(sv=>sv.name=="AbilityManaCost").values_float.join(" / ")}
|
|
724
|
+
</span>` : ""}
|
|
725
|
+
</p>
|
|
726
|
+
<p class="lore"${!item.lore_loc ? ` style="display:none;"` : ""}>${item.lore_loc}</p>
|
|
727
|
+
</div>`).join("")}
|
|
728
|
+
</div>
|
|
729
|
+
<div class="lore">
|
|
730
|
+
${hero.bio_loc}
|
|
731
|
+
</div>` %>
|
|
538
732
|
</div>
|
|
539
|
-
<div class="lore">
|
|
540
|
-
${hero.language.lore}
|
|
541
|
-
</div>` %>
|
|
542
733
|
</body>
|
|
734
|
+
<script>
|
|
735
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
736
|
+
const items = document.querySelectorAll('.skills > .skill');
|
|
737
|
+
items.forEach(item => {
|
|
738
|
+
// const name = item.getAttribute('data-name');
|
|
739
|
+
const abilityIsInnate = item.getAttribute('data-ability') === 'true';
|
|
740
|
+
const img = item.querySelector('.img_stats > img');
|
|
741
|
+
const imageUrl = img.src;
|
|
742
|
+
|
|
743
|
+
// Check if image exists
|
|
744
|
+
const image = new Image();
|
|
745
|
+
image.src = imageUrl;
|
|
746
|
+
image.onload = function() {
|
|
747
|
+
// Image exists, do nothing
|
|
748
|
+
};
|
|
749
|
+
image.onerror = function() {
|
|
750
|
+
// Image doesn't exist
|
|
751
|
+
if (abilityIsInnate) {
|
|
752
|
+
item.style.order = -1;
|
|
753
|
+
item.style.flexBasis = "100%";
|
|
754
|
+
img.src = '<%- utils.getImageUrl("innate_icon",ImageType.Icons) %>'; // Set backup image URL
|
|
755
|
+
// item.querySelector(".cooldown").style.display = "none";
|
|
756
|
+
// item.querySelector(".mana_cost").style.display = "none";
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
});
|
|
760
|
+
});
|
|
761
|
+
</script>
|
|
543
762
|
</html>
|