wesnoth/data/tools/wmlunits
2010-12-23 19:27:21 +00:00

1105 lines
38 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
#encoding: utf8
"""
wmlunits -- tool to output information on all units in HTML
Run without arguments to see usage.
"""
# Makes things faster on 32-bit systems
try: import psyco; psyco.full()
except ImportError: pass
import sys, os, re, glob, shutil, copy, urllib2, gc, optparse, gettext
import wesnoth.wmlparser2 as wmlparser2
import unit_tree.helpers as helpers
import unit_tree.animations as animations
html_header = '''
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel=stylesheet href=\"%(path)sstyle.css\" type=\"text/css\">
</head>
<body>'''.strip()
html_footer = '''
<div id="footer">
<p><a href="http://www.wesnoth.org/wiki/Wesnoth:Copyrights">Copyright</a> &copy; 2003-2009 The Battle for Wesnoth</p>
<p>Supported by <a href="http://www.jexiste.fr/">Jexiste</a></p>
</div>
</body></html>
'''.strip()
error_only_once = {}
def error_message(message):
if message in error_only_once: return
error_only_once[message] = 1
sys.stderr.write(message)
helpers.error_message = error_message
def reset_errors():
error_only_once = {}
class Translation:
def __init__(self, localedir, langcode):
self.catalog = {}
self.localedir = localedir
self.langcode = langcode
class Dummy:
def ugettext(self, x):
if not x: return ""
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
except IndexError:
# not sure why, but this happens within the
# gettext.translation call sometimes
self.catalog[textdomain] = self.dummy
r = self.catalog[textdomain].ugettext(string)
return r
class GroupByRace:
def __init__(self, wesnoth, campaign):
self.wesnoth = wesnoth
self.campaign = campaign
def unitfilter(self, unit):
if not self.campaign: return True
return unit.campaign == self.campaign
def groups(self, unit):
return [unit.race]
def group_name(self, group):
if not group: return "None"
return T(group, "plural_name")
class GroupByFaction:
def __init__(self, wesnoth, era):
self.wesnoth = wesnoth
self.era = era
def unitfilter(self, unit):
return self.era in unit.eras
def groups(self, unit):
return [x for x in unit.factions if x[0] == self.era]
def group_name(self, group):
era = self.wesnoth.era_lookup[group[0]]
faction = era.faction_lookup[group[1]]
name = T(faction, "name")
name = name[name.rfind("=") + 1:]
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):
global global_htmlout
self.output = output
self.campaign = campaign
self.verbose = verbose
self.target = "index.html"
self.wesnoth = wesnoth
self.forest = None
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):
"""
This takes all units belonging to a campaign, then groups them either
by race or faction, and creates an advancements tree out of it.
"""
# Build an advancement tree forest of all units.
forest = self.forest = helpers.UnitForest()
units_added = {}
for uid, u in self.wesnoth.unit_lookup.items():
if grouper.unitfilter(u):
forest.add_node(helpers.UnitNode(u))
units_added[uid] = u
# Always add any child units, even if they have been filtered out..
while units_added:
new_units_added = {}
for uid, u in units_added.items():
for auid in u.advance:
if not auid in units_added:
try:
au = self.wesnoth.unit_lookup[auid]
except KeyError:
error_message(
"Warning: Unit %s not found as advancement of %s\n" %
(auid, repr(uid)))
continue
forest.add_node(helpers.UnitNode(au))
new_units_added[auid] = au
units_added = new_units_added
forest.update()
# Partition trees by race/faction of first unit.
groups = {}
breadth = 0
for tree in forest.trees.values():
u = tree.unit
ugroups = grouper.groups(u)
for group in ugroups:
groups[group] = groups.get(group, []) + [tree]
breadth += tree.breadth
thelist = groups.keys()
thelist.sort()
rows_count = breadth + len(thelist)
# Create empty grid.
rows = []
for j in range(rows_count):
column = []
for i in range(6):
column.append((1, 1, None))
rows.append(column)
# Sort advancement trees by name of first unit and place into the grid.
def by_name(t1, t2):
u1 = t1.unit
u2 = t2.unit
u1name = T(u1, "name")
u2name = T(u2, "name")
return cmp(u1name, u2name)
def grid_place(nodes, x):
nodes.sort(by_name)
for node in nodes:
level = node.unit.level
rows[x][level] = (1, node.breadth, node)
for i in range(1, node.breadth):
rows[x + i][level] = (0, 0, node)
grid_place(node.children, x)
x += node.breadth
return x
x = 0
for group in thelist:
node = helpers.GroupNode(group)
node.name = grouper.group_name(group)
rows[x][0] = (6, 1, node)
for i in range(1, 6):
rows[x][i] = (0, 0, None)
nodes = groups[group]
x += 1
x = grid_place(nodes, x)
self.unitgrid = rows
def write_navbar(self):
def write(x): self.output.write(x)
languages = find_languages()
langlist = languages.keys()
langlist.sort()
write("""
<div class="header">
<a href="http://www.wesnoth.org">
<img src="../wesnoth-logo.jpg" alt="Wesnoth logo"/>
</a>
</div>
<div class="topnav">
<a href="../index.html">Wesnoth Units database</a>
</div>
""")
write("<table class=\"navbar\">")
write("<tr>\n")
def abbrev(name):
abbrev = name[0]
word_seperators = [" ", "_", "+", "(", ")"]
for i in range(1, len(name)):
if name[i] in ["+", "(", ")"] or name[i - 1] in word_seperators and name[i] not in word_seperators:
abbrev += name[i]
return abbrev
# Campaigns
x = self.translate("addon_type^Campaign", "wesnoth")
write("<th>%s</th></tr><tr><td>" % x)
cids = [[], []]
for cid in self.wesnoth.campaign_lookup.keys():
if cid in self.wesnoth.is_mainline_campaign:
cids[0].append(cid)
else:
cids[1].append(cid)
for i in range(2):
cnames = cids[i]
cnames.sort()
for cname in cnames:
lang = self.isocode
if cname == "mainline":
campname = self.translate("Multiplayer", "wesnoth")
campabbrev = campname
else:
if not cname in self.wesnoth.is_mainline_campaign:
lang = "C" # only mainline campaigns have translations right now
campname = T(self.wesnoth.campaign_lookup[cname], "name")
if not campname:
campname = cname
campabbrev = T(self.wesnoth.campaign_lookup[cname], "abbrev")
if not campabbrev:
campabbrev = abbrev(campname)
write(" <a title=\"%s\" href=\"../%s/%s.html\">%s</a><br/>\n" % (
campname, lang, cname, campabbrev))
if i == 0 and cids[1]:
write("-<br/>\n")
write("</td>\n")
write("</tr>\n")
# Eras
write("<tr>\n")
x = self.translate("Era", "wesnoth")
write("<th>%s</th></tr><tr><td>" % x)
eids = [[], []]
for eid in self.wesnoth.era_lookup.keys():
if eid in self.wesnoth.is_mainline_era:
eids[0].append(eid)
else:
eids[1].append(eid)
for i in range(2):
lang = self.isocode
if i == 1: lang = "C" # only mainline translations
eranames = [(T(self.wesnoth.era_lookup[eid], "name"),
eid) for eid in eids[i]]
eranames.sort()
for eraname, eid in eranames:
write(" <a title=\"%s\" href=\"../%s/%s.html\">%s</a><br/>" % (
eraname, lang, eid, abbrev(eraname)))
if i == 0 and eids[1]:
write("-<br/>\n")
write("</td>\n")
write("</tr>\n")
# Races
if self.campaign == "mainline":
write("<tr>\n")
x = self.translate("Race", "wesnoth")
write("<th>%s</th></tr><tr><td>" % x)
write("<a href=\"mainline.html\">%s</a><br/>\n" % (
self.translate("all", "wesnoth-editor")))
racenames = {}
for u in self.wesnoth.unit_lookup.values():
if u.campaign != self.campaign: continue
race = u.race
racename = T(race, "plural_name")
racenames[racename] = race.get_text_val("id")
racenames = racenames.items()
racenames.sort()
for racename, rid in racenames:
write(" <a href=\"mainline.html#%s\">%s</a><br/>" % (
racename, racename))
write("</td>\n")
write("</tr>\n")
# Languages
write("<tr>\n")
x = self.translate("Language", "wesnoth")
write("<th>%s</th></tr><tr><td>" % x)
for lang in langlist:
labb = lang
underscore = labb.find("_")
if underscore > 0: labb = labb[:underscore]
write(" <a title=\"%s\" href=\"../%s/%s\">%s</a><br/>\n" % (
languages[lang], lang, self.target,
labb))
write("</td>\n")
write("</tr>\n")
write("</table>\n")
def pic(self, u, x):
image = self.wesnoth.get_unit_value(x, "image")
if not image:
if x.name == "female":
baseunit = self.wesnoth.get_base_unit(u)
if baseunit:
female = baseunit.get_all(tag = "female")
return self.pic(u, female[0])
else:
return self.pic(u, u)
error_message(
"Warning: Missing image for unit %s(%s).\n" % (
u.get_text_val("id"), x.name))
return None
picname = image_collector.add_image(u.campaign, image)
image = os.path.join("../pics", picname)
return image
def get_abilities(self, u):
anames = []
already = {}
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 = T(ability, "name")
if not name: name = id
if not name: name = ability.name
anames.append(name)
return anames
def get_recursive_attacks(self, this_unit):
def copy_attributes(copy_from, copy_to):
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)
attacks = []
if base_unit:
attacks = copy.deepcopy(self.get_recursive_attacks(base_unit))
base_attacks_count = len(attacks)
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])
else:
attacks.append(attack)
return attacks
def write_units(self):
def write(x): self.output.write(x)
def _(x): return self.translate(x, "wesnoth")
rows = self.unitgrid
write("<table class=\"units\">\n")
write("<colgroup>")
for i in range(6):
write("<col class=\"col%d\" />" % i)
write("</colgroup>")
pic = image_collector.add_image("mainline",
"../../../images/misc/leader-crown.png")
crownimage = os.path.join("../pics", pic)
ms = None
for row in range(len(rows)):
write("<tr>\n")
for column in range(6):
hspan, vspan, un = rows[row][column]
if vspan:
attributes = ""
if hspan == 1 and vspan == 1:
pass
elif hspan == 1:
attributes += " rowspan=%d" % vspan
elif vspan == 1:
attributes += " colspan=%d" % hspan
if un and isinstance(un, helpers.GroupNode):
# Find the current multiplayer side so we can show the
# little crowns..
ms = None
try:
eid, fid = un.data
era = self.wesnoth.era_lookup[eid]
ms = era.faction_lookup[fid]
except TypeError:
pass
racename = un.name
attributes += " class=\"raceheader\""
write("<td%s>" % attributes)
write("<a name=\"%s\">%s</a>" % (racename, racename))
write("</td>\n")
elif un:
u = un.unit
attributes += " class=\"unitcell\""
write("<td%s>" % attributes)
uid = u.get_text_val("id")
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:
if un.id in ms.units:
crown = u""
if un.id in ms.is_leader:
crown = u""
link = "../%s/%s.html" % (self.isocode, uid)
write("<div class=\"i\"><a href=\"%s\" title=\"id=%s\">%s</a>" % (
link, uid, u""))
write("</div>")
write("<div class=\"l\">L%s%s</div>" % (level, crown))
write("<a href=\"%s\">%s</a><br/>" % (link, name))
write('<div class="pic">')
image = self.pic(u, u)
write('<a href=\"%s\">' % link)
if crown == u"":
write('<div style="background: url(%s)">' % image)
write('<img src="%s" alt="(image)" />' % crownimage)
write("</div>")
else:
write('<img src="%s" alt="(image)" />' % image)
write('</a>\n</div>\n')
write("<div class=\"attributes\">")
write("%s%s<br />" % (_("Cost: "), cost))
write("%s%s<br />" % (_("HP: "), hp))
write("%s%s<br />" % (_("MP: "), mp))
write("%s%s<br />" % (_("XP: "), xp))
# Write info about abilities.
anames = self.get_abilities(u)
if anames:
write("\n<div style=\"clear:both\">")
write(", ".join(anames))
write("</div>")
# Write info about attacks.
write("\n<div style=\"clear:both\">")
attacks = self.get_recursive_attacks(u)
for attack in attacks:
n = T(attack, "number")
x = T(attack, "damage")
x = "%s - %s" % (x, n)
write("%s " % x)
r = T(attack, "range")
t = T(attack, "type")
write("%s (%s)" % (_(r), _(t)))
s = []
specials = attack.get_all(tag = "specials")
if specials:
for special in specials[0].get_all():
sname = T(special, "name")
if sname:
s.append(sname)
s = ", ".join(s)
if s: write(" (%s)" % s)
write("<br />")
write("</div>")
write("</div>")
write("</td>\n")
else:
write("<td class=\"empty\"></td>")
write("</tr>\n")
write("</table>\n")
def write_units_tree(self, grouper, title):
self.output.write(html_header % {"path" : "../"})
self.analyze_units(grouper)
self.write_navbar()
self.output.write("<h1>%s</h1>" % title)
self.write_units()
self.output.write(html_footer)
def write_unit_report(self, output, unit):
def write(x): self.output.write(x)
def _(x): return self.translate(x, "wesnoth")
def find_attr(what, key):
if unit.movetype:
mtx = unit.movetype.get_all(tag = what)
mty = None
if mtx:
mty = mtx[0].get_text_val(key)
x = unit.get_all(att = what)
y = None
if x:
y = x[0].get_text_val(key,
translation = self.translation.translate)
if y:
return True, y
if unit.movetype and mty != None:
return False, mty
return False, "-"
self.output = output
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 = uval("name")
display_name = uname
female = unit.get_all(tag = "female")
if female:
fname = T(female[0], "name")
if fname and fname != uname:
display_name += "<br/>" + fname
write("<h1>%s</h1>\n" % display_name)
write('<div class="pic">')
if female:
mimage = self.pic(unit, unit)
fimage = self.pic(unit, female[0])
if not fimage: fimage = mimage
write('<img src="%s" alt="(image)" />\n' % mimage)
write('<img src="%s" alt="(image)" />\n' % fimage)
else:
image = self.pic(unit, unit)
write('<img src="%s" alt="(image)" />\n' % image)
write('</div>\n')
description = uval("description")
# TODO: what is unit_description?
if not description: description = uval("unit_description")
if not description: description = "-"
write("<p>%s</p>\n" % re.sub("\n","\n<br />", description) )
# Base info.
hp = uval("hitpoints")
mp = uval("movement")
xp = uval("experience")
level = uval("level")
alignment = uval("alignment")
write("<table class=\"unitinfo\">\n")
write("<tr>\n")
write("<th>%s" % _("Advances from: "))
write("</th><td>\n")
for pid in self.forest.get_parents(uid):
punit = self.wesnoth.unit_lookup[pid]
if unit.campaign == "mainline" and punit.campaign != "mainline":
continue
link = "../%s/%s.html" % (self.isocode, pid)
name = self.wesnoth.get_unit_value(punit, "name",
translation = self.translation.translate)
write("\n<a href=\"%s\">%s</a>" % (link, name))
write("</td>\n")
write("</tr><tr>\n")
write("<th>%s" % _("Advances to: "))
write("</th><td>\n")
for cid in self.forest.get_children(uid):
link = "../%s/%s.html" % (self.isocode, cid)
try:
cunit = self.wesnoth.unit_lookup[cid]
if unit.campaign == "mainline" and cunit.campaign != "mainline":
continue
name = self.wesnoth.get_unit_value(cunit, "name",
translation = self.translation.translate)
except KeyError:
error_message("Warning: Unit %s not found.\n" % cid)
name = cid
if unit.campaign == "mainline": continue
write("\n<a href=\"%s\">%s</a>" % (link, name))
write("</td>\n")
write("</tr>\n")
for val, text in [
("cost", _("Cost: ")),
("hitpoints", _("HP: ")),
("movement", _("Movement") + ": "),
("experience", _("XP: ")),
("level", _("Level") + ": "),
("alignment", _("Alignment: ")),
("id", "ID")]:
write("<tr>\n")
write("<th>%s</th>" % text)
x = uval(val)
if val == "alignment": x = _(x)
write("<td>%s</td>" % x)
write("</tr>\n")
# Write info about abilities.
anames = self.get_abilities(unit)
write("<tr>\n")
write("<th>%s</th>" % _("Abilities: "))
write("<td>" + (", ".join(anames)) + "</td>")
write("</tr>\n")
write("</table>\n")
# Write info about attacks.
write("<table class=\"unitinfo\">\n")
attacks = self.get_recursive_attacks(unit)
for attack in attacks:
write("<tr>")
aid = attack.get_text_val("name")
aname = T(attack, "description")
icon = attack.get_text_val("icon")
if not icon:
icon = "attacks/%s.png" % aid
picname, error = image_collector.add_image_check(unit.campaign, icon)
if error:
error_message("Error: No attack icon '%s' found for '%s'.\n" % (
icon, uid))
icon = os.path.join("../pics", picname)
write("<td><img src=\"%s\" alt=\"(image)\"/></td>" % icon)
write("<td>%s" % aname)
t = T(attack, "type")
write("<br/>%s</td>" % _(t))
n = attack.get_text_val("number")
x = attack.get_text_val("damage")
x = "%s - %s" % (x, n)
write("<td>%s" % x)
r = T(attack, "range")
write("<br/>%s</td>" % _(r))
s = []
specials = attack.get_all(tag = "specials")
if specials:
for special in specials[0].get_all():
sname = T(special, "name")
if sname:
s.append(sname)
else:
error_message(
"Warning: Weapon special %s has no name for %s.\n" % (
special.name, uid))
s = "<br/>".join(s)
write("<td>%s</td>" % s)
write("</tr>")
write("</table>\n")
# Write info about resistances.
resistances = [
"blade",
"pierce",
"impact",
"fire",
"cold",
"arcane"]
write("<table class=\"unitinfo\">\n")
write("<tr>\n")
write("<th colspan=\"2\">%s</th>\n" % _("Resistances: "))
write("</tr>\n")
for rid in resistances:
special, r = find_attr("resistance", rid)
if r == "-": r = 100
try: r = "%d%%" % (100 - int(r))
except ValueError:
error_message("Warning: Invalid resistance %s for %s.\n" % (
r, uid))
rcell = "td"
if special: rcell += ' class="special"'
write("<tr>\n")
write("<th>%s</th><td>%s</td>\n" % (_(rid), r))
write("</tr>\n")
write("</table>\n")
# Write info about movement costs and terrain defense.
write("<table class=\"unitinfo\">\n")
write("<tr>\n")
write("<th>%s</th><th>%s</th><th>%s</th>\n" % (
_("Terrain"), _("Movement Cost"), _("Defense") ))
write("</tr>\n")
terrains = self.wesnoth.terrain_lookup
terrainlist = []
for tstring, t in terrains.items():
tid = t.get_text_val("id")
if tid in ["off_map", "fog", "shroud"]: continue
if t.get_all(att = "aliasof"): continue
name = T(t, "name")
terrainlist.append((name, tid))
terrainlist.sort()
for tname, tid in terrainlist:
not_from_race, c = find_attr("movement_costs", tid)
ccell = "td"
if c == "99": ccell += ' class="grayed"'
dcell = "td"
not_from_race, d = find_attr("defense", tid)
if d == "-": d = 100
try: d = "%d%%" % (100 - int(d))
except ValueError:
error_message("Warning: Invalid defense %s for %s.\n" % (
d, uid))
write("<tr>\n")
write("<td>%s</td><%s>%s</td><%s>%s</td>\n" % (
tname, ccell, c, dcell, d))
write("</tr>\n")
write("</table>\n")
write(html_footer)
languages_found = {}
def find_languages():
"""
Returns a dictionary mapping isocodes to languages.
"""
global languages
if languages_found: return languages_found
parser = wmlparser2.Parser(options.wesnoth, options.config_dir,
options.data_dir, no_preprocess = False)
parser.parse_text("{languages}")
for locale in parser.get_all(tag = "locale"):
isocode = locale.get_text_val("locale")
name = locale.get_text_val("name")
languages_found[isocode] = name
return languages_found
class MyFile:
"""
I don't understand why this is needed..
"""
def __init__(self, filename, mode):
self.f = open(filename, mode)
def write(self, x):
x = x.encode("utf8")
self.f.write(x)
def close(self):
self.f.close()
def generate_campaign_report(out_path, isocode, campaign, wesnoth):
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")
html = HTMLOutput(isocode, output, campaign, wesnoth)
html.target = "%s.html" % campaign
grouper = GroupByRace(wesnoth, campaign)
if campaign == "mainline":
title = html.translate("Multiplayer", "wesnoth")
else:
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):
path = os.path.join(out_path, isocode)
if not os.path.isdir(path): os.mkdir(path)
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)
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):
odir = os.path.join(out_path, isocode)
if not os.path.isdir(odir):
os.mkdir(odir)
html = HTMLOutput(isocode, None, "units", wesnoth)
grouper = GroupByRace(wesnoth, None)
html.analyze_units(grouper)
for uid, unit in wesnoth.unit_lookup.items():
if isocode != "C" and not uid in wesnoth.is_mainline_unit: continue
output = MyFile(os.path.join(odir, "%s.html" % uid), "w")
html.target = "%s.html" % uid
html.write_unit_report(output, unit)
def write_index(out_path):
output = MyFile(os.path.join(out_path, "index.html"), "w")
output.write("""
<html><head>
<meta http-equiv="refresh" content="0;url=C/mainline.html">
</head>
<body>
<a href="C/mainline.html">Redirecting to Wesnoth units database...</a>
</body>
</html>
""")
def copy_images():
if not options.nocopy:
print("Recolorizing pictures.")
image_collector.copy_and_color_images(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",
"http://www.wesnoth.org/mw/skins/glamdrol/navbg.png"]:
local = os.path.join(options.output, grab[grab.rfind("/") + 1:])
if not os.path.exists(local):
print "Fetching", grab
url = urllib2.urlopen(grab)
file(local, "w").write(url.read())
def parse_game():
stuff = helpers.WesnothList(
options.wesnoth,
options.config_dir,
options.data_dir,
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())
stuff.is_mainline_unit = {}
for uid in stuff.unit_lookup.keys():
stuff.is_mainline_unit[uid] = True
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
* Each mainline era's units sorted by faction
* Each mainline campaign's units sorted by race
* Each addon era's units sorted by faction
* Each addon campaign's units sorted by race
"""
print "Generating report for %s." % (isocode)
reset_errors()
# Report generation
write_index(options.output)
campaigns = stuff.campaign_lookup.keys()
generate_campaign_report(options.output, isocode, "mainline", stuff)
for campaign in campaigns:
if isocode != "C" and not campaign in stuff.is_mainline_campaign: continue
generate_campaign_report(options.output, isocode, campaign, stuff)
for eid in stuff.era_lookup.keys():
if isocode != "C" and not eid in stuff.is_mainline_era: continue
generate_era_report(options.output, isocode, eid, stuff)
# Single unit reports.
generate_single_unit_reports(options.output, isocode, stuff)
if __name__ == '__main__':
# We change the process name to "wmlunits"
try:
import ctypes
libc = ctypes.CDLL("libc.so.6")
libc.prctl(15, "wmlunits", 0, 0, 0)
except: # oh well...
pass
global options
global image_collector
gc.disable()
op = optparse.OptionParser()
op.add_option("-C", "--config-dir",
help = "Specify the user configuration dir (wesnoth --config-path).")
op.add_option("-D", "--data-dir",
help = "Specify the wesnoth data dir (wesnoth --path).")
op.add_option("-l", "--language", default = "all",
help = "Specify a language to use. Else outputs is produced for all languages.")
op.add_option("-o", "--output",
help = "Specify the output directory.")
op.add_option("-n", "--nocopy", action = "store_true",
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 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:
op.print_help()
sys.exit(-1)
options.output = os.path.expanduser(options.output)
if not options.wesnoth:
options.wesnoth = "wesnoth"
if not options.transdir:
options.transdir = os.getcwd()
if options.language == "all":
languages = find_languages().keys()
languages.sort()
else:
languages = [options.language]
image_collector = helpers.ImageCollector(options.wesnoth,
options.config_dir, options.data_dir)
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("<html><body>")
for uid in uids:
u = wesnoth.unit_lookup[uid]
if u.rid != race:
if race != None: f.write("</ul>")
f.write("<p>%s</p>\n" % u.rid)
f.write("<ul>")
race = u.rid
f.write("<li>%s</li>\n" % uid)
f.write("</ul>")
f.write("</body></html>")
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:
generate_report(wesnoth, isocode)
if not options.nocopy:
copy_images()