diff --git a/data/tools/unit_tree/animations.py b/data/tools/unit_tree/animations.py index 6c87b55506c..cc625a7056b 100644 --- a/data/tools/unit_tree/animations.py +++ b/data/tools/unit_tree/animations.py @@ -8,15 +8,15 @@ def write_animation(out, aa, name): out.write("%d" % c[0]) def count_animations(out, name, a, c): - frames = a.get_subs("frame") + frames = a.get_all(tag = "frame") if frames: c[0] += len(frames) c[1] += 1 - for a2 in a.get_subs("animation"): + for a2 in a.get_all(tag = "animation"): count_animations(out, name, a2, c) - for a2 in a.get_subs("if"): + for a2 in a.get_all(tag = "if"): count_animations(out, name, a2, c) - for a2 in a.get_subs("else"): + for a2 in a.get_all(tag = "else"): count_animations(out, name, a2, c) def write_table_row(out, unit, color, name = None): @@ -54,12 +54,12 @@ def write_table_row(out, unit, color, name = None): needed["healing_anim"] = False needed["leading_anim"] = False needed["teleport"] = False - for abil in unit.get_subs("abilities"): - if abil.get_subs("heals"): + for abil in unit.get_all(tag = "abilities"): + if abil.get_all(tag = "heals"): needed["healing_anim"] = True - if abil.get_subs("leadership"): + if abil.get_all(tag = "leadership"): needed["leading_anim"] = True - if abil.get_subs("teleport"): + if abil.get_all(tag = "teleport"): needed["teleport"] = True if name == None: name = unit.id @@ -68,7 +68,7 @@ def write_table_row(out, unit, color, name = None): for t in anim_types: if needed[t]: - aa = unit.get_subs(t) + aa = unit.get_all(tag = t) if t == "extra_anim": out.write("") else: @@ -80,10 +80,10 @@ def write_table_row(out, unit, color, name = None): out.write("\n") - female = unit.get_first("female") - if female: write_table_row(out, female, color, name + "[f]") + female = unit.get_all(tag = "female") + if female: write_table_row(out, female[0], color, name + "[f]") - for variation in unit.get_all("variation"): + for variation in unit.get_all(tag = "variation"): write_table_row(out, variation, color, name + "[%s]" % variation.get_text_val("variation_name")) @@ -109,12 +109,12 @@ def put_units(f, us): level out extra animation -resistance_anim -recruiting_anim -pre_movement_anim -post_movement_anim -draw_weapon_anim -sheath_weapon_anim +resistance +recruiting +pre movement +post movement +draw weapon +sheath weapon """.lstrip()) f.write("\n") diff --git a/data/tools/unit_tree/helpers.py b/data/tools/unit_tree/helpers.py index 8396200e0fb..bb4ffcaa76e 100755 --- a/data/tools/unit_tree/helpers.py +++ b/data/tools/unit_tree/helpers.py @@ -1,98 +1,63 @@ """ Various helpers for use by the wmlunits tool. """ -import sys, os, re, glob, shutil, copy, urllib2 -from subprocess import Popen +import sys, os, re, glob, shutil, copy, urllib2, subprocess -import wesnoth.wmldata as wmldata -import wesnoth.wmlparser as wmlparser +import wesnoth.wmlparser2 as wmlparser2 import wesnoth.wmltools as wmltools -class ParserWithCoreMacros: - """ - A wrapper around the WML parser to do some things like we want. - """ - def __init__(self, isocode, datadir, userdir, transdir): - self.datadir = datadir - self.userdir = userdir - # Handle translations. - self.translations = wmltools.Translations(transdir) - def gettext(textdomain, x): - return self.translations.get(textdomain, isocode, x, x) - self.gettext = gettext +def get_datadir(wesnoth_exe): + p = subprocess.Popen([wesnoth_exe, "--path"], + stdout = subprocess.PIPE, stderr = subprocess.PIPE) + out, err = p.communicate() + return out.strip() - # Create a new parser for the macros. - parser = wmlparser.Parser(datadir) - parser.gettext = self.gettext - - # Parse core macros. - parser.parse_text("{core/macros/}\n") - parser.parse_top(None) - self.core_macros = parser.macros - - def parse(self, text_to_parse, ignore_macros = None, - ignore_fatal_errors = False, verbose = False): - - # Create the real parser. - parser = wmlparser.Parser(self.datadir, self.userdir) - parser.verbose = verbose - parser.gettext = self.gettext - parser.macros = copy.copy(self.core_macros) - - #parser.verbose = True - - # Suppress complaints about undefined terrain macros - parser.set_macro_not_found_callback(lambda wmlparser, name, params: - name.startswith("TERRAIN") or name == "DISABLE_TRANSITIONS") - - if ignore_macros: - parser.macro_callback = ignore_macros - - # Create a WML root element and parse the given text into it. - WML = wmldata.DataSub("WML") - - parser.parse_text(text_to_parse) - - parser.parse_top(WML) - - return WML +def get_userdir(wesnoth_exe): + p = subprocess.Popen([wesnoth_exe, "--config-path"], + stdout = subprocess.PIPE, stderr = subprocess.PIPE) + out, err = p.communicate() + return out.strip() class ImageCollector: """ A class to collect all the images which need to be copied to the HTML output folder. """ - def __init__(self, datadir, userdir): + def __init__(self, wesnoth_exe): self.images = {} - self.pathes_per_campaign = {} - self.ipathes = {} + self.paths_per_campaign = {} + self.ipaths = {} self.notfound = {} - self.datadir = datadir - self.userdir = userdir self.id = 0 self.verbose = 0 + + self.datadir = get_datadir(wesnoth_exe) + self.userdir = get_userdir(wesnoth_exe) - def add_binary_pathes_from_WML(self, campaign, WML): - self.pathes_per_campaign[campaign] = self.pathes_per_campaign.get( + def add_binary_paths_from_WML(self, campaign, WML): + self.paths_per_campaign[campaign] = self.paths_per_campaign.get( campaign, []) - for binpath in WML.get_all("binary_path"): + for binpath in WML.get_all(tag = "binary_path"): path = binpath.get_text_val("path") - self.pathes_per_campaign[campaign].append(path) + self.paths_per_campaign[campaign].append(path) def find_image(self, i, c): if c == "mainline": - bases = [os.path.join(self.datadir, "core/images")] + bases = [os.path.join(self.datadir, "data/core/images")] else: - bases = [os.path.join(self.datadir, "core/images")] - binpaths = self.pathes_per_campaign.get(c, []) + bases = [os.path.join(self.datadir, "data/core/images")] + binpaths = self.paths_per_campaign.get(c, []) binpaths.reverse() for x in binpaths: if x.startswith("data/"): for idir in ["images", "images/units"]: - bases.append(os.path.join(self.datadir, x[5:], idir)) + bases.append(os.path.join(self.datadir, x, idir)) if self.userdir: - bases.append(os.path.join(self.userdir, x[5:], idir)) + bases.append(os.path.join(self.userdir, x, idir)) for base in bases: + tilde = i.find("~") + if tilde >= 0: + i = i[:tilde] ipath = os.path.join("%s" % base, i) if os.path.exists(ipath): return ipath, None return None, bases @@ -101,8 +66,8 @@ class ImageCollector: if (campaign, path) in self.notfound: return self.notfound[(campaign, path)], True ipath, error = self.find_image(path, campaign) - if ipath in self.ipathes: - return self.ipathes[ipath], False + if ipath in self.ipaths: + return self.ipaths[ipath], False name = "%05d_" % self.id name += os.path.basename(path) @@ -110,7 +75,7 @@ class ImageCollector: self.images[name] = ipath, path, campaign, error if ipath: - self.ipathes[ipath] = name + self.ipaths[ipath] = name return name, False else: self.notfound[(campaign, path)] = name @@ -135,7 +100,7 @@ class ImageCollector: # helpers.py currently executing. command = os.path.join(os.path.dirname(__file__), "TeamColorizer") - p = Popen([command, ipath, opath]) + p = subprocess.Popen([command, ipath, opath]) p.wait() else: sys.stderr.write( @@ -150,23 +115,25 @@ class WesnothList: """ Lists various Wesnoth stuff like units, campaigns, terrains, factions... """ - def __init__(self, isocode, datadir, userdir, transdir): + def __init__(self, wesnoth_exe, transdir): self.unit_lookup = {} self.race_lookup = {} self.terrain_lookup = {} self.movetype_lookup = {} self.era_lookup = {} self.campaign_lookup = {} - self.parser = ParserWithCoreMacros(isocode, datadir, userdir, transdir) + self.parser = wmlparser2.Parser(wesnoth_exe) + + self.parser = wmlparser2.Parser(wesnoth_exe) def add_terrains(self): """ We need those for movement costs and defenses. """ - WML = self.parser.parse("{core/terrain.cfg}\n") + self.parser.parse_text("{core/terrain.cfg}\n") n = 0 - for terrain in WML.get_all("terrain_type"): + for terrain in self.parser.get_all(tag = "terrain_type"): tstring = terrain.get_text_val("string") self.terrain_lookup[tstring] = terrain n += 1 @@ -180,7 +147,7 @@ class WesnothList: if not eid: return self.era_lookup[eid] = era era.faction_lookup = {} - for multiplayer_side in era.get_all("multiplayer_side"): + for multiplayer_side in era.get_all(tag = "multiplayer_side"): fid = multiplayer_side.get_text_val("id") if fid == "Random": continue era.faction_lookup[fid] = multiplayer_side @@ -214,10 +181,10 @@ class WesnothList: """ Find all mainline eras. """ - WML = self.parser.parse("{multiplayer/eras.cfg}\n") + self.parser.parse_text("{multiplayer/eras.cfg}") n = 0 - for era in WML.get_all("era"): + for era in self.parser.get_all(tag = "era"): self.add_era(era) n += 1 return n @@ -226,9 +193,9 @@ class WesnothList: """ Find all mainline campaigns. """ - WML = self.parser.parse("{campaigns}\n") + self.parser.parse_text("{campaigns}") n = 0 - for campaign in WML.find_all("campaign"): + for campaign in self.parser.get_all(tag = "campaign"): self.add_campaign(campaign) n += 1 return n @@ -237,45 +204,65 @@ class WesnothList: """ Find all addon eras and campaigns. """ - n = 0 - try: - WML = self.parser.parse(""" - #define MULTIPLAYER\n#enddef - #define RANDOM_SIDE\n#enddef - {~add-ons} - """) - except wmlparser.Error, e: - try: - print(e) - except UnicodeEncodeError: - print(e.text.encode("utf8", "ignore")) - return n - for campaign in WML.find_all("campaign"): - cid = self.add_campaign(campaign) - - for era in WML.find_all("era"): - eid = self.add_era(era) - if not eid: continue - image_collector.add_binary_pathes_from_WML(eid, WML) - - n = self.add_units(WML, "addons") + self.parser.parse_text("{multiplayer}{~add-ons}", "MULTIPLAYER") - image_collector.add_binary_pathes_from_WML("addons", WML) - return n + cn = 0 + for campaign in self.parser.get_all(tag = "campaign"): + cid = self.add_campaign(campaign) + cn += 1 - def add_units(self, WML, campaign): + en = 0 + for era in self.parser.get_all(tag = "era"): + eid = self.add_era(era) + en += 1 + if not eid: continue + image_collector.add_binary_paths_from_WML(eid, + self.parser.root) + + un = self.add_units("addons") + + image_collector.add_binary_paths_from_WML("addons", + self.parser.root) + return cn, en, un + + def add_mainline_units(self): + self.parser.parse_text("{core/units.cfg}") + return self.add_units("mainline") + + def add_campaign_units(self, cname, image_collector): + campaign = self.campaign_lookup[cname] + define = campaign.get_text_val("define") + self.parser.parse_text("{campaigns}", define) + + image_collector.add_binary_paths_from_WML(cname, + self.parser.root) + + return self.add_units(cname) + + def add_addon_campaign_units(self, cname, image_collector): + campaign = self.campaign_lookup[cname] + define = campaign.get_text_val("define") + self.parser.parse_text("{~add-ons}", define) + + image_collector.add_binary_paths_from_WML(cname, + self.parser.root) + + return self.add_units(cname) + + def add_units(self, campaign): """ We assume each unit, in mainline and all addons, has one unique id. So we reference them everywhere by this id, and here can add them all to one big collection. """ - addunits = WML.get_all("units") + addunits = self.parser.get_all(tag = "units") + addunits += self.parser.get_all(tag = "+units") if not addunits: return 0 - + def getall(oftype): r = [] for units in addunits: - r += units.get_all(oftype) + r += units.get_all(tag = oftype) return r # Find all unit types. @@ -285,10 +272,10 @@ class WesnothList: unit.get_text_val("hide_help", "no") in ["no", "false"]: uid = unit.get_text_val("id") if uid in self.unit_lookup: - sys.stderr.write( - ("Fatal: Unit id \"%s\" already exists - either it has" + - " to be renamed, or there's a bug in this script.\n") % - uid) + pass + # TODO: We might want to compare the two units + # with the same id and if one is different try + # to do something clever like rename it... else: self.unit_lookup[uid] = unit unit.campaign = campaign @@ -366,8 +353,9 @@ class WesnothList: unit.factions.append((eid, fid)) def get_base_unit(self, unit): - b = unit.get_first("base_unit") + b = unit.get_all(tag = "base_unit") if b: + b = b[0] buid = b.get_text_val("id") try: baseunit = self.unit_lookup[buid] except KeyError: @@ -378,12 +366,12 @@ class WesnothList: return baseunit return None - def get_unit_value(self, unit, attribute, default = None): - value = unit.get_text_val(attribute, None) + def get_unit_value(self, unit, attribute, default = None, translation = None): + value = unit.get_text_val(attribute, None, translation) if value == None: baseunit = self.get_base_unit(unit) if baseunit: - return self.get_unit_value(baseunit, attribute, default) + return self.get_unit_value(baseunit, attribute, default, translation) return default return value @@ -416,7 +404,6 @@ class UnitForest: u.children.append(c) if not uid in c.parent_ids: c.parent_ids.append(uid) - # Put all roots into the forest for uid, u in self.lookup.items(): diff --git a/data/tools/wmlunits b/data/tools/wmlunits index 1dc1167fe0e..316ca328bc8 100755 --- a/data/tools/wmlunits +++ b/data/tools/wmlunits @@ -10,13 +10,9 @@ Run without arguments to see usage. try: import psyco; psyco.full() except ImportError: pass -import sys, os, re, glob, shutil, copy, urllib2, gc +import sys, os, re, glob, shutil, copy, urllib2, gc, optparse, gettext -import wesnoth.wmldata as wmldata -import wesnoth.wmlparser as wmlparser -import wesnoth.wmltools as wmltools - -sys.path.append(".") +import wesnoth.wmlparser2 as wmlparser2 import unit_tree.helpers as helpers import unit_tree.animations as animations @@ -37,6 +33,34 @@ html_footer = ''' '''.strip() +class Translation: + def __init__(self, localedir, langcode): + self.catalog = {} + self.localedir = localedir + self.langcode = langcode + class Dummy: + def ugettext(self, x): + caret = x.find("^") + if caret < 0: return x + return x[caret + 1:] + self.dummy = Dummy() + + def translate(self, string, textdomain): + if textdomain not in self.catalog: + try: + self.catalog[textdomain] = gettext.translation( + textdomain, self.localedir, [self.langcode]) + except IOError: + self.catalog[textdomain] = self.dummy + try: + r = self.catalog[textdomain].ugettext(string) + except UnicodeDecodeError as e: + print(textdomain) + print(repr(string)) + print(type(string)) + raise + return r + class GroupByRace: def __init__(self, wesnoth, campaign): self.wesnoth = wesnoth @@ -51,7 +75,7 @@ class GroupByRace: def group_name(self, group): if not group: return "None" - return group.get_text_val("plural_name") + return T(group, "plural_name") class GroupByFaction: def __init__(self, wesnoth, era): @@ -67,24 +91,31 @@ class GroupByFaction: def group_name(self, group): era = self.wesnoth.era_lookup[group[0]] faction = era.faction_lookup[group[1]] - name = faction.get_text_val("name") + name = T(faction, "name") name = name[name.rfind("=") + 1:] - name = era.get_text_val("name") + " / " + name + name = T(era, "name") + " / " + name return name +global_htmlout = None +def T(tag, att): + return tag.get_text_val(att, translation = + global_htmlout.translate) + class HTMLOutput: def __init__(self, isocode, output, campaign, wesnoth, verbose = False): - self.isocode = isocode + global global_htmlout self.output = output self.campaign = campaign self.verbose = verbose self.target = "index.html" self.wesnoth = wesnoth self.forest = None - - def get_translation(self, textdomain, key): - return self.wesnoth.parser.translations.get(textdomain, self.isocode, - key, key) + self.translation = Translation(options.transdir, isocode) + self.isocode = isocode + global_htmlout = self + + def translate(self, string, domain): + return self.translation.translate(string, domain) def analyze_units(self, grouper): """ @@ -148,8 +179,8 @@ class HTMLOutput: u1 = t1.unit u2 = t2.unit - u1name = u1.get_text_val("name") - u2name = u2.get_text_val("name") + u1name = T(u1, "name") + u2name = T(u2, "name") return cmp(u1name, u2name) def grid_place(nodes, x): @@ -179,7 +210,7 @@ class HTMLOutput: def write_navbar(self): def write(x): self.output.write(x) - def _(x): return self.get_translation("wesnoth", x) + languages = find_languages() langlist = languages.keys() langlist.sort() @@ -208,7 +239,7 @@ class HTMLOutput: return abbrev # Campaigns - x = _("TitleScreen button^Campaign") + x = self.translate("TitleScreen button^Campaign", "wesnoth") write("%s" % x) cids = [[], []] for cid in self.wesnoth.campaign_lookup.keys(): @@ -217,19 +248,20 @@ class HTMLOutput: else: cids[1].append(cid) + lang = self.isocode + for i in range(2): cnames = cids[i] cnames.sort() for cname in cnames: - lang = self.isocode if cname == "mainline": - campname = self.get_translation("wesnoth", "Multiplayer") + campname = self.translate("Multiplayer", "wesnoth") campabbrev = campname else: - campname = self.wesnoth.campaign_lookup[cname].get_text_val("name") + campname = T(self.wesnoth.campaign_lookup[cname], "name") if not campname: campname = cname - campabbrev = self.wesnoth.campaign_lookup[cname].get_text_val("abbrev") + campabbrev = T(self.wesnoth.campaign_lookup[cname], "abbrev") if not campabbrev: campabbrev = abbrev(campname) @@ -242,7 +274,7 @@ class HTMLOutput: # Eras write("\n") - x = _("Era") + x = self.translate("Era", "wesnoth") write("%s" % x) eids = [[], []] for eid in self.wesnoth.era_lookup.keys(): @@ -251,12 +283,12 @@ class HTMLOutput: else: eids[1].append(eid) for i in range(2): - eranames = [(self.wesnoth.era_lookup[eid].get_text_val("name"), + eranames = [(T(self.wesnoth.era_lookup[eid], "name"), eid) for eid in eids[i]] eranames.sort() for eraname, eid in eranames: write(" %s
" % ( - eraname, lang, eid, abbrev(eraname))) + eraname, lang, eid, abbrev(eraname))) if i == 0 and eids[1]: write("-
\n") write("\n") @@ -265,15 +297,15 @@ class HTMLOutput: # Races if self.campaign == "mainline": write("\n") - x = _("Race") + x = self.translate("Race", "wesnoth") write("%s" % x) write("%s
\n" % ( - self.get_translation("wesnoth-editor", "all"))) + self.translate("all", "wesnoth-editor"))) racenames = {} for u in self.wesnoth.unit_lookup.values(): if u.campaign != self.campaign: continue race = u.race - racename = race.get_text_val("plural_name") + racename = T(race, "plural_name") racenames[racename] = race.get_text_val("id") racenames = racenames.items() racenames.sort() @@ -286,7 +318,7 @@ class HTMLOutput: # Languages write("\n") - x = _("Language") + x = self.translate("Language", "wesnoth") write("%s" % x) for lang in langlist: labb = lang @@ -306,8 +338,8 @@ class HTMLOutput: if x.name == "female": baseunit = self.wesnoth.get_base_unit(u) if baseunit: - female = baseunit.get_first("female") - return self.pic(u, female) + female = baseunit.get_all(tag = "female") + return self.pic(u, female[0]) sys.stderr.write( "Warning: Missing image for unit %s(%s).\n" % ( u.get_text_val("id"), x.name)) @@ -319,14 +351,14 @@ class HTMLOutput: def get_abilities(self, u): anames = [] already = {} - for abilities in u.get_all("abilities"): - try: c = abilities.children() + for abilities in u.get_all(tag = "abilities"): + try: c = abilities.get_all() except AttributeError: c = [] for ability in c: id = ability.get_text_val("id") if id in already: continue already[id] = True - name = ability.get_text_val("name") + name = T(ability, "name") if not name: name = id if not name: name = ability.name anames.append(name) @@ -335,9 +367,9 @@ class HTMLOutput: def get_recursive_attacks(self, this_unit): def copy_attributes(copy_from, copy_to): - for c in copy_from.children(): - if isinstance(c, wmldata.DataText): - copy_to.set_text_val(c.name, c.data) + for c in copy_from.data: + if isinstance(c, wmlparser2.AttributeNode): + copy_to.data.append(c) # Use attacks of base_units as base, if we have one. base_unit = self.wesnoth.get_base_unit(this_unit) @@ -346,7 +378,7 @@ class HTMLOutput: attacks = copy.deepcopy(self.get_recursive_attacks(base_unit)) base_attacks_count = len(attacks) - for i, attack in enumerate(this_unit.get_all("attack")): + for i, attack in enumerate(this_unit.get_all(tag = "attack")): # Attack merging is order based. if i < base_attacks_count: copy_attributes(attack, attacks[i]) @@ -357,7 +389,7 @@ class HTMLOutput: def write_units(self): def write(x): self.output.write(x) - def _(x): return self.get_translation("wesnoth", x) + def _(x): return self.translate(x, "wesnoth") rows = self.unitgrid write("\n") write("") @@ -403,12 +435,15 @@ class HTMLOutput: write("" % attributes) uid = u.get_text_val("id") - name = self.wesnoth.get_unit_value(u, "name") - cost = self.wesnoth.get_unit_value(u, "cost") - hp = self.wesnoth.get_unit_value(u, "hitpoints") - mp = self.wesnoth.get_unit_value(u, "movement") - xp = self.wesnoth.get_unit_value(u, "experience") - level = self.wesnoth.get_unit_value(u, "level") + def uval(name): + return self.wesnoth.get_unit_value(u, name, + translation = self.translation.translate) + name = uval("name") + cost = uval("cost") + hp = uval("hitpoints") + mp = uval("movement") + xp = uval("experience") + level = uval("level") crown = "" if ms: @@ -438,14 +473,10 @@ class HTMLOutput: write('\n\n') write("
") - write("%s%s
" % ( - self.get_translation("wesnoth", "Cost: "), cost)) - write("%s%s
" % ( - self.get_translation("wesnoth", "HP: "), hp)) - write("%s%s
" % ( - self.get_translation("wesnoth", "MP: "), mp)) - write("%s%s
" % ( - self.get_translation("wesnoth", "XP: "), xp)) + write("%s%s
" % (_("Cost: "), cost)) + write("%s%s
" % (_("HP: "), hp)) + write("%s%s
" % (_("MP: "), mp)) + write("%s%s
" % (_("XP: "), xp)) # Write info about abilities. anames = self.get_abilities(u) @@ -459,20 +490,20 @@ class HTMLOutput: attacks = self.get_recursive_attacks(u) for attack in attacks: - n = attack.get_text_val("number") - x = attack.get_text_val("damage") + n = T(attack, "number") + x = T(attack, "damage") x = "%s - %s" % (x, n) write("%s " % x) - r = attack.get_text_val("range") - t = attack.get_text_val("type") + r = T(attack, "range") + t = T(attack, "type") write("%s (%s)" % (_(r), _(t))) s = [] - specials = attack.get_first("specials") + specials = attack.get_all(tag = "specials") if specials: - for special in specials.children(): - sname = special.get_text_val("name") + for special in specials[0].get_all(): + sname = T(special, "name") if sname: s.append(sname) s = ", ".join(s) @@ -501,16 +532,19 @@ class HTMLOutput: def write_unit_report(self, output, unit): def write(x): self.output.write(x) - def _(x): return self.get_translation("wesnoth", x) + def _(x): return self.translate(x, "wesnoth") def find_attr(what, key): if unit.movetype: - mtx = unit.movetype.get_first(what) + mtx = unit.movetype.get_all(tag = what) mty = None - if mtx: mty = mtx.get_text_val(key) - x = unit.get_first(what) + if mtx: + mty = mtx[0].get_text_val(key) + x = unit.get_all(att = what) y = None - if x: y = x.get_text_val(key) + if x: + y = x[0].get_text_val(key, + translation = self.translation.translate) if y: return True, y if unit.movetype and mty != None: @@ -521,14 +555,18 @@ class HTMLOutput: write(html_header % {"path" : "../"}) self.write_navbar() + def uval(name): + return self.wesnoth.get_unit_value(unit, name, + translation = self.translation.translate) + # Write unit name, picture and description. uid = unit.get_text_val("id") - uname = self.wesnoth.get_unit_value(unit, "name") + uname = uval("name") display_name = uname - female = unit.get_first("female") + female = unit.get_all(tag = "female") if female: - fname = female.get_text_val("name") + fname = T(female[0], "name") if fname and fname != uname: display_name += "
" + fname @@ -537,7 +575,7 @@ class HTMLOutput: write('
') if female: mimage = self.pic(unit, unit) - fimage = self.pic(unit, female) + fimage = self.pic(unit, female[0]) if not fimage: fimage = mimage write('(image)\n' % mimage) write('(image)\n' % fimage) @@ -546,19 +584,19 @@ class HTMLOutput: write('(image)\n' % image) write('
\n') - description = self.wesnoth.get_unit_value(unit, "description") - + description = uval("description") + # TODO: what is unit_description? - if not description: description = unit.get_text_val("unit_description") + if not description: description = uval("unit_description") if not description: description = "-" - write("

%s

\n" % __import__('re').sub("\n","\n
", description) ) + write("

%s

\n" % re.sub("\n","\n
", description) ) # Base info. - hp = self.wesnoth.get_unit_value(unit, "hitpoints") - mp = self.wesnoth.get_unit_value(unit, "movement") - xp = self.wesnoth.get_unit_value(unit, "experience") - level = self.wesnoth.get_unit_value(unit, "level") - alignment = self.wesnoth.get_unit_value(unit, "alignment") + hp = uval("hitpoints") + mp = uval("movement") + xp = uval("experience") + level = uval("level") + alignment = uval("alignment") write("
\n") write("\n") @@ -569,11 +607,12 @@ class HTMLOutput: if unit.campaign == "mainline" and punit.campaign != "mainline": continue link = "../%s/%s.html" % (self.isocode, pid) - name = self.wesnoth.get_unit_value(punit, "name") + name = self.wesnoth.get_unit_value(punit, "name", + translation = self.translation.translate) write("\n%s" % (link, name)) write("\n") write("\n") - write("\n") write("" % text) - x = self.wesnoth.get_unit_value(unit, val) - if val == "alignment": x = self.get_translation("wesnoth", x) + x = uval(val) + if val == "alignment": x = _(x) write("" % x) write("\n") @@ -623,7 +663,7 @@ class HTMLOutput: write("") aid = attack.get_text_val("name") - aname = attack.get_text_val("description") + aname = T(attack, "description") icon = attack.get_text_val("icon") if not icon: @@ -638,22 +678,22 @@ class HTMLOutput: write("" % self.get_translation("wesnoth", t)) + t = T(attack, "type") + write("
%s" % _(t)) n = attack.get_text_val("number") x = attack.get_text_val("damage") x = "%s - %s" % (x, n) write("" % self.get_translation("wesnoth", r)) + r = T(attack, "range") + write("
%s" % _(r)) s = [] - specials = attack.get_first("specials") + specials = attack.get_all(tag = "specials") if specials: - for special in specials.children(): - sname = special.get_text_val("name") + for special in specials[0].get_all(): + sname = T(special, "name") if sname: s.append(sname) else: @@ -678,8 +718,7 @@ class HTMLOutput: write("
%s" % self.get_translation("wesnoth", "Advances to: ")) + write("%s" % _("Advances to: ")) write("\n") for cid in self.forest.get_children(uid): link = "../%s/%s.html" % (self.isocode, cid) @@ -581,7 +620,8 @@ class HTMLOutput: cunit = self.wesnoth.unit_lookup[cid] if unit.campaign == "mainline" and cunit.campaign != "mainline": continue - name = self.wesnoth.get_unit_value(cunit, "name") + name = self.wesnoth.get_unit_value(cunit, "name", + translation = self.translation.translate) except KeyError: sys.stderr.write("Warning: Unit %s not found.\n" % cid) name = cid @@ -600,8 +640,8 @@ class HTMLOutput: ("id", "ID")]: write("
%s%s
%s" % aname) - t = attack.get_text_val("type") - write("
%s
%s" % x) - r = attack.get_text_val("range") - write("
%s
\n") write("\n") - write("\n" % - self.get_translation("wesnoth", "Resistances: ")) + write("\n" % _("Resistances: ")) write("\n") for rid in resistances: @@ -692,8 +731,7 @@ class HTMLOutput: rcell = "td" if special: rcell += ' class="special"' write("\n") - write("\n" % ( - self.get_translation("wesnoth", rid), r)) + write("\n" % (_(rid), r)) write("\n") write("
%s%s
%s%s%s%s
\n") @@ -709,8 +747,8 @@ class HTMLOutput: for tstring, t in terrains.items(): tid = t.get_text_val("id") if tid in ["off_map", "fog", "shroud"]: continue - if t.get_first("aliasof"): continue - name = t.get_text_val("name") + if t.get_all(att = "aliasof"): continue + name = T(t, "name") terrainlist.append((name, tid)) terrainlist.sort() @@ -743,12 +781,10 @@ def find_languages(): """ global languages if languages_found: return languages_found - parser = wmlparser.Parser(datadir) - WML = wmldata.DataSub("WML") - parser.parse_text("{languages}\n") - parser.parse_top(WML) + parser = wmlparser2.Parser(options.wesnoth) + parser.parse_text("{languages}") - for locale in WML.get_all("locale"): + for locale in parser.get_all(tag = "locale"): isocode = locale.get_text_val("locale") name = locale.get_text_val("name") languages_found[isocode] = name @@ -767,7 +803,6 @@ class MyFile: self.f.close() def generate_campaign_report(out_path, isocode, campaign, wesnoth): - print "Generating report for %s_%s." % (isocode, campaign) path = os.path.join(out_path, isocode ) if not os.path.isdir(path): os.mkdir(path) output = MyFile(os.path.join(path, "%s.html" % campaign), "w") @@ -776,28 +811,26 @@ def generate_campaign_report(out_path, isocode, campaign, wesnoth): grouper = GroupByRace(wesnoth, campaign) if campaign == "mainline": - title = html.get_translation("wesnoth", "Multiplayer") + title = html.translate("Multiplayer", "wesnoth") else: - title = wesnoth.campaign_lookup[campaign].get_text_val("name") + title = wesnoth.campaign_lookup[campaign].get_text_val("name", + translation = html.translate) if not title: title = campaign html.write_units_tree(grouper, title) def generate_era_report(out_path, isocode, eid, wesnoth): - print "Generating report for %s_%s." % (isocode, eid) path = os.path.join(out_path, isocode) if not os.path.isdir(path): os.mkdir(path) - - era = wesnoth.era_lookup[eid] - ename = era.get_text_val("name") + output = MyFile(os.path.join(path, "%s.html" % eid), "w") - html = HTMLOutput(isocode, output, eid, wesnoth) html.target = "%s.html" % eid grouper = GroupByFaction(wesnoth, eid) - title = ename - html.write_units_tree(grouper, title) + era = wesnoth.era_lookup[eid] + ename = era.get_text_val("name", translation = html.translate) + html.write_units_tree(grouper, ename) def generate_single_unit_reports(out_path, isocode, wesnoth): @@ -828,9 +861,10 @@ def write_index(out_path): def copy_images(): if not options.nocopy: - print "Copying files." + print("Recolorizing pictures.") image_collector.copy_and_color_images(options.output) - shutil.copy2(os.path.join(datadir, "tools/unit_tree/style.css"), options.output) + shutil.copy2(os.path.join(image_collector.datadir, + "data/tools/unit_tree/style.css"), options.output) for grab in [ "http://www.wesnoth.org/mw/skins/glamdrol/headerbg.jpg", "http://www.wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg", @@ -841,7 +875,66 @@ def copy_images(): url = urllib2.urlopen(grab) file(local, "w").write(url.read()) -def output(isocode): +def parse_game(): + stuff = helpers.WesnothList(options.wesnoth, options.transdir) + + def p(x): sys.stdout.write(x); sys.stdout.flush() + def pn(x): print(x) + + # Parse some stuff we may need. + p("Parsing terrains ... ") + n = stuff.add_terrains() + pn("%d terrains found." % n) + + p("Parsing mainline eras ... ") + n = stuff.add_mainline_eras() + pn("%d mainline eras found." % n) + stuff.is_mainline_era = {} + for c in stuff.era_lookup.keys(): + stuff.is_mainline_era[c] = True + + stuff.is_mainline_campaign = {} + if options.campaigns: + p("Parsing mainline campaigns ... ") + n = stuff.add_mainline_campaigns() + pn("%d mainline campaigns found." % n) + for c in stuff.campaign_lookup.keys(): + stuff.is_mainline_campaign[c] = True + + # Parse all unit data + # This reads in units.cfg, giving us all the mainline units (and races). + p("Parsing mainline units ... ") + n = stuff.add_mainline_units() + pn("%d mainline units found." % n) + + # Now we read each mainline campaign in turn to get its units. + cnames = stuff.campaign_lookup.keys() + for cname in cnames: + p(" Parsing %s units ... " % cname) + n = stuff.add_campaign_units(cname, image_collector) + pn("%d units found." % n) + + mainline_campaigns = set(stuff.campaign_lookup.keys()) + + if options.addons: + p("Parsing addons ... ") + n = stuff.add_addons(image_collector) + pn("%d campaigns, %d eras, %d multiplayer units found." % n) + + # Now we read each addon campaign in turn to get its units. + cnames = stuff.campaign_lookup.keys() + for cname in cnames: + if cname in mainline_campaigns: continue + campaign = stuff.campaign_lookup[cname] + p(" Parsing %s units ... " % cname) + n = stuff.add_addon_campaign_units(cname, image_collector) + pn("%d units found." % n) + + stuff.find_unit_factions() + + return stuff + +def generate_report(stuff, isocode): """ We output: * All mainline units sorted by race @@ -850,81 +943,10 @@ def output(isocode): * Each addon era's units sorted by faction * Each addon campaign's units sorted by race """ - print "WML parser language reset to %s." % isocode - - stuff = helpers.WesnothList(isocode, datadir, userdir, transdir) - - # Parse some stuff we may need. - print "Parsing terrains ...", - n = stuff.add_terrains() - print "%d terrains found." % n - - print "Parsing mainline eras ...", - n = stuff.add_mainline_eras() - print "%d mainline eras found." % n - stuff.is_mainline_era = {} - for c in stuff.era_lookup.keys(): - stuff.is_mainline_era[c] = True - - print "Parsing mainline campaigns ...", - n = stuff.add_mainline_campaigns() - print "%d mainline campaigns found." % n - stuff.is_mainline_campaign = {} - for c in stuff.campaign_lookup.keys(): - stuff.is_mainline_campaign[c] = True - - # Parse all unit data - # This reads in units.cfg, giving us all the mainline units (and races). - print "Parsing mainline units ...", - sys.stdout.flush() - WML = stuff.parser.parse("{core/units.cfg}") - n = stuff.add_units(WML, "mainline") - print n, "mainline units found." - - # Now we read each mainline campaign in turn to get its units. - cnames = stuff.campaign_lookup.keys() - for cname in cnames: - print "Parsing %s units ..." % cname, - sys.stdout.flush() - campaign = stuff.campaign_lookup[cname] - define = campaign.get_text_val("define") - WML = stuff.parser.parse(""" - #define %s\n#enddef - {campaigns}""" % define, - ignore_macros = lambda x: x.find("/scenarios") == -1) - n = stuff.add_units(WML, cname) - image_collector.add_binary_pathes_from_WML(cname, WML) - print n, "units found." - sys.stderr.flush() - - if userdir: - print "Parsing addons ...", - sys.stdout.flush() - n = stuff.add_addons(image_collector) - print "%d units found." % n - - # Now we read each addon campaign in turn to get its units. - cnames = stuff.campaign_lookup.keys() - for cname in cnames: - if cname in stuff.is_mainline_campaign: continue - campaign = stuff.campaign_lookup[cname] - print "Parsing %s units ..." % cname, - sys.stdout.flush() - - define = campaign.get_text_val("define") - WML = stuff.parser.parse(""" - #define %s\n#enddef - {~add-ons}""" % define, - ignore_macros = lambda x: x.find("/scenarios") == -1) - n = stuff.add_units(WML, cname) - image_collector.add_binary_pathes_from_WML(cname, WML) - print n, "units found." - - stuff.find_unit_factions() + + print "Generating report for %s." % (isocode) # Report generation - if not os.path.isdir(options.output): - os.mkdir(options.output) write_index(options.output) campaigns = stuff.campaign_lookup.keys() @@ -940,8 +962,6 @@ def output(isocode): # Single unit reports. generate_single_unit_reports(options.output, isocode, stuff) - return stuff - if __name__ == '__main__': # We change the process name to "wmlunits" @@ -954,25 +974,29 @@ if __name__ == '__main__': global options global image_collector - import optparse gc.disable() op = optparse.OptionParser() op.add_option("-l", "--language", default = "all", - help = "Specify a language.") + help = "Specify a language to use. Else outputs is produced for all languages.") op.add_option("-o", "--output", - help = "Specify output directory.") + help = "Specify the output directory.") op.add_option("-n", "--nocopy", action = "store_true", - help = "No copying of files.") - op.add_option("-d", "--datadir", - help = "Specify Wesnoth's data to use. Default is /data.") - op.add_option("-u", "--userdir", - help = "Specify user data dir to use, which is automatically scanned "+\ - "for addons. For example -u ~/.wesnoth/data") + help = "No copying of files. By default all images are copied to the output dir.") + op.add_option("-w", "--wesnoth", + help = "Specify the wesnoth executable to use. Whatever data " + + "and config paths that executable is configured for will be " + + "used to find game files and addons.") op.add_option("-t", "--transdir", - help = "Specify the directory which has a po subfolder for translations. "+\ - "(Defaults to the current directory.)") + help = "Specify the directory with gettext message catalogues. " + + "Defaults to ./translations.", default = "translations") + op.add_option("-c", "--campaigns", action = "store_true", + help = "Include units from mainline campaigns.") + op.add_option("-a", "--addons", action = "store_true", + help = "Include also addon units (from all installed eras and campaigns). " + + "Note that some add-ons may try to modify stock units but such changes are " + + "not reflected in this version of wmlunits.") options, args = op.parse_args() if not options.output: @@ -981,17 +1005,11 @@ if __name__ == '__main__': options.output = os.path.expanduser(options.output) - if not options.datadir: - #wmltools.pop_to_top("wmlunits") - datadir = os.getcwd() + "/data" - else: - datadir = options.datadir + if not options.wesnoth: + options.wesnoth = "wesnoth" - userdir = options.userdir - if options.transdir: - transdir = options.transdir - else: - transdir = os.getcwd() + if not options.transdir: + options.transdir = os.getcwd() if options.language == "all": languages = find_languages().keys() @@ -999,57 +1017,53 @@ if __name__ == '__main__': else: languages = [options.language] - image_collector = helpers.ImageCollector(datadir, userdir) + image_collector = helpers.ImageCollector(options.wesnoth) - once_without_translation = False + wesnoth = parse_game() + + # Generate output dir. + if not os.path.isdir(options.output): + os.mkdir(options.output) + + # Store rid and id for each unit so we have it easier. + for u in wesnoth.unit_lookup.values(): + r = u.race + if r: r = r.get_text_val("id", "none") + else: r = "none" + u.rid = r + u.id = u.get_text_val("id") + + # Write a list with all unit ids, just for fun. + uids = wesnoth.unit_lookup.keys() + def by_race(u1, u2): + r = cmp(wesnoth.unit_lookup[u1].rid, + wesnoth.unit_lookup[u2].rid) + if r == 0: r = cmp(u1, u2) + return r + uids.sort(by_race) + race = None + f = MyFile(os.path.join(options.output, "uids.html"), "w") + f.write("") + for uid in uids: + u = wesnoth.unit_lookup[uid] + if u.rid != race: + if race != None: f.write("") + f.write("

%s

\n" % u.rid) + f.write("") + f.write("") + f.close() + + # Write animation statistics + f = MyFile(os.path.join(options.output, "animations.html"), "w") + animations.write_table(f, wesnoth) + f.close() + + # Now finally lets do the unit reports in all languages. for isocode in languages: - wesnoth = output(isocode) - if not once_without_translation: - copy_images() - once_without_translation = True - for u in wesnoth.unit_lookup.values(): - r = u.race - if r: r = r.get_text_val("id", "none") - else: r = "none" - # Store rid and id for each units so we have it easier - u.rid = r - u.id = u.get_text_val("id") + generate_report(wesnoth, isocode) - # Write a list with all unit ids, just for fun. - uids = wesnoth.unit_lookup.keys() - def by_race(u1, u2): - r = cmp(wesnoth.unit_lookup[u1].rid, - wesnoth.unit_lookup[u2].rid) - if r == 0: r = cmp(u1, u2) - return r - uids.sort(by_race) - race = None - f = MyFile(os.path.join(options.output, "uids.html"), "w") - f.write("") - for uid in uids: - u = wesnoth.unit_lookup[uid] - if u.rid != race: - if race != None: f.write("") - f.write("

%s

\n" % u.rid) - f.write("") - f.write("") - f.close() - - # Write animation statistics - f = MyFile(os.path.join(options.output, "animations.html"), "w") - animations.write_table(f, wesnoth) - f.close() - - # Kill all references, this makes sure the reference counting - # kicks in and throws away all data for the previous - # translation - saving a bit of memory since otherwise two - # translations would be kept at a time. - wesnoth = None - - # We run a GC collection here, this ensures that also data - # which still are referenced but not reachable (yes, yes, - # this shouldn't happen) are freed. - gc.collect() + if not options.nocopy: + copy_images()