diff --git a/data/tools/unit_tree/html_output.py b/data/tools/unit_tree/html_output.py index 0bbf4bca290..fc5cc8c21a1 100644 --- a/data/tools/unit_tree/html_output.py +++ b/data/tools/unit_tree/html_output.py @@ -14,14 +14,49 @@ import wesnoth.wmlparser3 as wmlparser3 PICS_LOCATION = "../../pics" -HTML_ENTITY_HORIZONTAL_BAR = '―' -HTML_ENTITY_MULTIPLICATION_SIGN = '×' -HTML_ENTITY_FIGURE_DASH = '‒' +# Icons for mainline terrains used on the unit details page +TERRAIN_ICONS = { + "fungus": "forest/mushrooms-tile", + "cave": "cave/floor6", + "sand": "sand/beach", + "reef": "water/reef-tropical-tile", + "hills": "hills/regular", + "swamp_water": "swamp/water-tile", + "shallow_water": "water/coast-tile", + "castle": "castle/castle-tile", + "mountains": "mountains/snow-tile", + "deep_water": "water/ocean-tile", + "flat": "grass/green-symbol", + "forest": "forest/pine-tile", + "frozen": "frozen/ice", + "village": "village/human-tile", + "impassable": "void/void", + "unwalkable": "unwalkable/lava", + "rails": "misc/rails-ne-sw", +} -HTML_HEADER = ''' +# Omit these terrains from the terrain info report on the unit details page +HIDDEN_TERRAINS = [ + "off_map", "off_map2", "fog", "shroud", "impassable", "void", "rails" +] + +# Damage tpye ids and associated icons used on the details page +RESISTANCES = [ + ("blade", "attacks/sword-human.png"), + ("pierce", "attacks/spear.png"), + ("impact", "attacks/club.png"), + ("fire", "attacks/fireball.png"), + ("cold", "attacks/iceball.png"), + ("arcane", "attacks/faerie-fire.png") +] + +WESMERE_CSS_VERSION = "1.1.0" +WESMERE_CSS_PREFIX = "https://www.wesnoth.org" + +WESMERE_HEADER = '''\ - + @@ -29,8 +64,8 @@ HTML_HEADER = ''' - - + + %(title)s - Wesnoth Units Database @@ -38,9 +73,8 @@ HTML_HEADER = ''' -
'''.strip() +
-TOP_BAR = ''' -
'''.strip() +
''' -HTML_FOOTER = ''' +WESMERE_FOOTER = '''\
%(generation_note)s
@@ -92,13 +126,37 @@ HTML_FOOTER = '''
-'''.strip() +''' HTML_CLEAR_FLOATS = '
' +HTML_ENTITY_HORIZONTAL_BAR = '―' +HTML_ENTITY_MULTIPLICATION_SIGN = '×' +HTML_ENTITY_FIGURE_DASH = '‒' + +PRE_PLACEHOLDER_CAMPAIGNS = "PLACE CAMPAIGNS HERE\n" +PRE_PLACEHOLDER_ERAS = "PLACE ERAS HERE\n" + +def website_header(title='', path='../../', classes=[]): + """Returns the website header with the specified parameters.""" + return WESMERE_HEADER % { + "title": title, + "path": path, + "cssprefix": WESMERE_CSS_PREFIX, + "cssver": WESMERE_CSS_VERSION, + "classes": ' '.join(['wmlunits'] + classes)} + +def website_footer(timestamp=''): + """Returns the website footer, including the current timestamp.""" + if not timestamp: + timestamp = "Last updated on " + time.ctime() + "." + return WESMERE_FOOTER % { "generation_note": timestamp } + + all_written_html_files = [] error_only_once = {} + def error_message(message): if message in error_only_once: return @@ -131,6 +189,42 @@ def cleantext(text, quote=True): return text return html.escape(text, quote) +def resistance_rating_color_class(resistance): + """Return a color class adequate for the provided unit resistance value.""" + if resistance < 0: + return 'red' + elif resistance <= 20: + return 'yellow' + elif resistance <= 40: + return 'olive' + else: + return 'green' + +def defense_rating_color_class(defense): + """Return a color class adequate for the provided terrain defense value.""" + if defense <= 10: + return 'red' + elif defense <= 30: + return 'yellow' + elif defense <= 50: + return 'olive' + else: + return 'green' + +def mvtcost_rating_color_class(str_mvtcost, str_moves): + """Return a color class adequate for the provided movement cost value.""" + cost = int_fallback(str_mvtcost, 99) + moves = int_fallback(str_moves) + if cost >= moves: + return 'gray' + elif cost > moves/2: + return 'red' + elif cost > 1: + return 'yellow' + else: + return 'green' + + class MyFile: """ Python 2 is a bit weird with encodings, really should switch this to @@ -373,8 +467,6 @@ class HTMLOutput: langlist = list(languages.keys()) langlist.sort() - write(TOP_BAR % {"path" : "../../"}) - write('') @@ -1136,68 +1222,22 @@ class HTMLOutput: already = {} for tstring, t in list(terrains.items()): tid = t.get_text_val("id") - if tid in ["off_map", "off_map2", "fog", "shroud", "impassable", - "void", "rails"]: - continue - if t.get_all(att="aliasof"): - continue - if tid in already: + if tid in HIDDEN_TERRAINS or t.get_all(att="aliasof") or tid in already: continue already[tid] = 1 name = T(t, "name") ticon = t.get_text_val("symbol_image") if not ticon: ticon = t.get_text_val("icon_image") - # Use nice images for known mainline terrain types - if tid == "fungus": ticon = "forest/mushrooms-tile" - elif tid == "cave": ticon = "cave/floor6" - elif tid == "sand": ticon = "sand/beach" - elif tid == "reef": ticon = "water/reef-tropical-tile" - elif tid == "hills": ticon = "hills/regular" - elif tid == "swamp_water": ticon = "swamp/water-tile" - elif tid == "shallow_water": ticon = "water/coast-tile" - elif tid == "castle": ticon = "castle/castle-tile" - elif tid == "mountains": ticon = "mountains/snow-tile" - elif tid == "deep_water": ticon = "water/ocean-tile" - elif tid == "flat": ticon = "grass/green-symbol" - elif tid == "forest": ticon = "forest/pine-tile" - elif tid == "frozen": ticon = "frozen/ice" - elif tid == "village": ticon = "village/human-tile" - elif tid == "impassable": ticon = "void/void" - elif tid == "unwalkable": ticon = "unwalkable/lava" - elif tid == "rails": ticon = "misc/rails-ne-sw" - + if tid in TERRAIN_ICONS: + ticon = TERRAIN_ICONS[tid] if ticon: terrainlist.append((name, tid, ticon)) else: error_message("Terrain " + tid + " has no symbol_image\n") terrainlist.sort() - def defense_rating_color_class(defense): - # Logic from src/help/help_topic_generators.cpp @ 1.13.8+dev - if defense <= 10: - return 'red' - elif defense <= 30: - return 'yellow' - elif defense <= 50: - return 'olive' - else: - return 'green' - - def mvtcost_rating_color_class(str_mvtcost, str_moves): - cost = int_fallback(str_mvtcost, 99) - moves = int_fallback(str_moves) - # Logic from src/help/help_topic_generators.cpp @ 1.13.8+dev - if cost >= moves: - return 'gray' - elif cost > moves/2: - return 'red' - elif cost > 1: - return 'yellow' - else: - return 'green' - for tname, tid, ticon in terrainlist: not_from_race, move_cost = find_attr("movement_costs", tid) classes_cost = ['mvtcost'] @@ -1243,8 +1283,8 @@ class HTMLOutput: (cleantext(tname, quote=False), ' '.join(classes_cost), move_cost, ' '.join(classes_defense), defense)) - write("\n") - write("\n") + write('\n') + write('\n') write('') # right column @@ -1253,8 +1293,7 @@ class HTMLOutput: self.output.write(HTML_CLEAR_FLOATS) write('') # main - self.output.write(HTML_FOOTER % { - "generation_note": "Last updated on " + time.ctime() + "."}) + self.output.write(website_footer()) def generate_campaign_report(addon, isocode, campaign, wesnoth): @@ -1402,8 +1441,8 @@ def html_postprocess_file(filename, isocode, batchlist): f = open(filename, "r+b") html = f.read().decode("utf8") - html = html.replace("PLACE CAMPAIGNS HERE\n", chtml) - html = html.replace("PLACE ERAS HERE\n", ehtml) + html = html.replace(PRE_PLACEHOLDER_CAMPAIGNS, chtml) + html = html.replace(PRE_PLACEHOLDER_ERAS, ehtml) f.seek(0) f.write(html.encode("utf8")) f.close() diff --git a/data/tools/unit_tree/overview.py b/data/tools/unit_tree/overview.py index cb0a6cceea3..4657388c5f4 100755 --- a/data/tools/unit_tree/overview.py +++ b/data/tools/unit_tree/overview.py @@ -10,13 +10,12 @@ def write_addon_overview(folder, addon): name = addon["name"] - path = "../" title = html_output.cleantext("Build Report for " + name) generation_note = "Last updated on " + time.ctime() + "." - w(html_output.HTML_HEADER % locals()) - - w(html_output.TOP_BAR % locals()) + w(html_output.website_header(path="../", + title=title, + classes=["wmlunits-report"])) w('
') @@ -25,11 +24,11 @@ def write_addon_overview(folder, addon): w('

' + html_output.cleantext(name) + '

') if eras: - w("

Eras

') campaigns = addon.get("campaigns", []) if campaigns: @@ -37,17 +36,17 @@ def write_addon_overview(folder, addon): for campaign in campaigns: cpath = os.path.join("en_US", campaign["id"] + ".html") w('
  • ' + html_output.cleantext(campaign["name"], quote=False) + '
  • ') - w("") + w('') - w("
    ") + w('
    ') if os.path.exists(os.path.join(folder, "error.log")): w('

    Warnings or errors were found: log

    ') w('

    Back to the full report

    ') - w("
    ") + w('
    ') w('
    ') - w(html_output.HTML_FOOTER % locals()) + w(html_output.website_footer()) def main(folder): @@ -55,14 +54,9 @@ def main(folder): def w(x): out.write(x + "\n") - path = "" - title = "Database Build Report" - generation_note = "generated on " + time.ctime() - classes = "wmlunits-report" - - w(html_output.HTML_HEADER % locals()) - - w(html_output.TOP_BAR % locals()) + w(html_output.website_header(path="", + title="Database Build Report", + classes=["wmlunits-report"])) w('

    Database Build Report

    ') @@ -126,7 +120,8 @@ def main(folder): return "" mo = re.match(".*--preprocess-defines(.*)", line) - if mo: return "Defines: " + mo.group(1) + "
    " + if mo: + return "Defines: " + mo.group(1) + '
    ' for s in source: line = line.replace(s, "WML") @@ -136,34 +131,34 @@ def main(folder): out = "" for row in rows: row = row.strip() - out += row + "
    " + out += row + '
    ' return out htmlerr = open(error_html, "w") - htmlerr.write("") + htmlerr.write('') lines_count = 0 for line in text.splitlines(): line = line.strip() if line in ["", "", "", ""]: - htmlerr.write("

    ") + htmlerr.write('

    ') elif line in ["", "", "", ""]: - htmlerr.write("

    ") + htmlerr.write('

    ') else: err_html = postprocess(line) - lines_count += err_html.count("") + htmlerr.write('') total_lines += lines_count total_error_logs += 1 w('%s (%d lines)' % (html_output.cleanurl(error_name), error_kind, lines_count)) - w("") + w('') count += 1 - w("") + w('') - w("") + w('') w('Total (for %d addons):' % count) w('' + str(total_n) + '') w('' + str(total_error_logs) + ' (' + str(total_lines) + ' lines)') @@ -173,7 +168,7 @@ def main(folder): w(' ') - w(html_output.HTML_FOOTER % locals()) + w(html_output.website_footer()) if __name__ == "__main__": main(sys.argv[1])