v0.5.109: hero role toolbar, skill side-by-side layout, taller detail panel.
Move role filters between grid and detail, fix skill video/text layout and detail height jump, unify item dividers, drop OpenDota matchup cross, sync docs and assets. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
"""Download UI art used by https://www.dota2.com/heroes.
|
||||
"""Download UI art used by https://www.dota2.com/heroes / dota2.com.cn.
|
||||
|
||||
- Landscape hero cards: Steam CDN `heroes/{key}.png`
|
||||
- Attribute icons: Steam CDN `icons/hero_{strength,agility,...}.png`
|
||||
- Combat stat icons: dota2.com.cn `herostatic/stats/icon_*.png`
|
||||
|
||||
Separate from `templates/cdn/` face crops used for top-bar matching.
|
||||
|
||||
@@ -12,6 +13,7 @@ Usage:
|
||||
Writes:
|
||||
assets/hero_portraits/{key}.png
|
||||
assets/attr_icons/{str,agi,int,all}.png
|
||||
assets/ui_icons/icon_{damage,armor,...}.png
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -25,7 +27,7 @@ import argparse
|
||||
import json
|
||||
|
||||
from shared.http_utils import fetch_hero_keys, http_bytes
|
||||
from shared.paths import ATTR_ICONS, HERO_PORTRAITS, HEROES_JSON
|
||||
from shared.paths import ATTR_ICONS, HERO_PORTRAITS, HEROES_JSON, UI_ICONS
|
||||
|
||||
# wide = face headshots; crop = waist-up 3D renders (usually worse in dense grids).
|
||||
CARD_URL = (
|
||||
@@ -43,6 +45,19 @@ ATTR_FILES = {
|
||||
"int": "hero_intelligence",
|
||||
"all": "hero_universal",
|
||||
}
|
||||
# Same filenames as https://www.dota2.com.cn/hero/<key> DetailsStats panel.
|
||||
COMBAT_STAT_ICON_URL = "https://www.dota2.com.cn/herostatic/stats/{name}.png"
|
||||
COMBAT_STAT_ICONS = (
|
||||
"icon_damage",
|
||||
"icon_attack_time",
|
||||
"icon_attack_range",
|
||||
"icon_projectile_speed",
|
||||
"icon_armor",
|
||||
"icon_magic_resist",
|
||||
"icon_movement_speed",
|
||||
"icon_turn_rate",
|
||||
"icon_vision",
|
||||
)
|
||||
|
||||
|
||||
def hero_keys() -> list[str]:
|
||||
@@ -71,6 +86,25 @@ def fetch_attr_icons(*, force: bool) -> tuple[int, int, int]:
|
||||
return ok, skip, fail
|
||||
|
||||
|
||||
def fetch_combat_stat_icons(*, force: bool) -> tuple[int, int, int]:
|
||||
UI_ICONS.mkdir(parents=True, exist_ok=True)
|
||||
ok = skip = fail = 0
|
||||
for name in COMBAT_STAT_ICONS:
|
||||
out = UI_ICONS / f"{name}.png"
|
||||
if out.is_file() and not force:
|
||||
skip += 1
|
||||
continue
|
||||
try:
|
||||
data = http_bytes(COMBAT_STAT_ICON_URL.format(name=name), timeout=30)
|
||||
out.write_bytes(data)
|
||||
ok += 1
|
||||
print(f" combat {name} ({len(data)} bytes)")
|
||||
except Exception as e: # noqa: BLE001
|
||||
fail += 1
|
||||
print(f" FAIL combat {name}: {e}")
|
||||
return ok, skip, fail
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ap = argparse.ArgumentParser(description="Download dota2.com/heroes UI art")
|
||||
ap.add_argument("--force", action="store_true", help="re-download existing files")
|
||||
@@ -85,6 +119,9 @@ def main() -> None:
|
||||
print("attribute icons...")
|
||||
a_ok, a_skip, a_fail = fetch_attr_icons(force=args.force)
|
||||
|
||||
print("combat stat icons...")
|
||||
c_ok, c_skip, c_fail = fetch_combat_stat_icons(force=args.force)
|
||||
|
||||
HERO_PORTRAITS.mkdir(parents=True, exist_ok=True)
|
||||
keys = hero_keys()
|
||||
ok = skip = fail = 0
|
||||
@@ -104,6 +141,9 @@ def main() -> None:
|
||||
fail += 1
|
||||
print(f" FAIL {key}: {e}")
|
||||
print(f"attrs: downloaded={a_ok} skipped={a_skip} failed={a_fail} -> {ATTR_ICONS}")
|
||||
print(
|
||||
f"combat: downloaded={c_ok} skipped={c_skip} failed={c_fail} -> {UI_ICONS}"
|
||||
)
|
||||
print(f"heroes: downloaded={ok} skipped={skip} failed={fail} -> {HERO_PORTRAITS}")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user