wesnoth/data/tools/wmlunits

270 lines
8.6 KiB
Python
Executable File

#!/usr/bin/env python
"""
wmlunits -- List unit names by race and level in either wikimedia or HTML tables
usage: wmlunits [-h] [-l lang]
-h = list as html
-l lang = specify language (as ISO country code)
"""
# Makes things faster on 32-bit systems
try: import psyco; psyco.full()
except ImportError: pass
import sys, os, re, glob
import wesnoth.wmldata as wmldata
import wesnoth.wmlparser as wmlparser
import wesnoth.wmltools as wmltools
def parse_core_macros_and_WML(text_to_parse):
# Create a new parser.
parser = wmlparser.Parser(datadir)
parser.do_preprocessor_logic = True
#parser.verbose = True
# Create a new WML object.
WML = wmldata.DataSub("WML")
# Parse some macros.
# TODO: Obviously, this is not ideal, e.g. we parse the macros multiple
# times. Could easily be fixed by keeping a reference to parser.macros
# and re-using it instead of re-parsing.
parser.parse_text("{core/macros/}\n")
parser.parse_top(None)
# Parse the actual WML.
parser.parse_text(text_to_parse)
parser.parse_top(WML)
return WML
class UnitList:
def __init__(self):
self.units_by_campaign = {}
def add(self, text_to_parse, campaign):
"Collect all units in the specified namespace, None = mainline."
WML = parse_core_macros_and_WML(text_to_parse)
#WML.debug()
# Collect unit data. First, we look for a [+units] section.
units = WML.get_first("+units")
# If no [+units] section, assume it is inside a [campaign].
if not units:
campaign_wml = WML.get_first("campaign")
if not campaign_wml:
# FIXME: The tutorial has no [campaign], need to special case it
# somehow. Currently, we ignore it.
return
# Now we get the define - strange, but seems to be how Wesnoth
# works..
define = campaign_wml.get_text_val("define")
# Re-parse, this time with the define defined.
WML = parse_core_macros_and_WML(
"#define %s\n#enddef\n%s" % (define, text_to_parse))
# This time, it oughta work.
units = WML.get_first("+units")
if not units:
# This campaign has no units. Nothing to do.
return
newunits = units.get_all("unit_type")
self.units_by_campaign[campaign] = []
for unit in newunits:
if unit.get_text_val("do_not_list", "no") == "no":
self.units_by_campaign[campaign].append(unit)
unit.campaign = campaign
def find_unit(self, unit_id):
"Find unit by id. Relies on IDs being unique."
for c in campaigns:
for u in self.units_by_campaign[c]:
if u.get_text_val("id") == unit_id:
return u
return None
def lookup(self, unit_id, attr):
"Get named attribute from unit, resolving [base_unit] references."
u = self.find_unit(unit_id)
firsttry = u.get_text_val(attr)
if firsttry:
return (firsttry, u.textdomain)
baseunit = u.get_first("base_unit")
if baseunit is None:
return None
print "*** Found baseunit %s while looking up (%s,%s)" \
% (baseunit, unit_id, attr)
# FIXME: lookup through baseunit doesn't work yet.
return None
def report_unit_names(campaign, unitlist, isocode):
tx = None
doubles = {}
races = {}
for u in unitlist:
# Fetch name of unit
name = u.get_text_val("name")
if name == None or name == "":
sys.stderr.write("Empty name detected! (id = %s)\n" %
u.get_text_val("id"))
continue
# Swap in the appropriate translation dictionary for this unit
if not u.textdomain:
sys.stderr.write("Unit %s has no textdomain (?)\n" % name)
continue
if tx == None or u.textdomain != tx.textdomain:
tx = wmltools.Translation(u.textdomain, isocode)
# Sanity check
if not name in tx:
# Hm...
sys.stderr.write("Unit %s has no translation (?)\n" % name)
if name in doubles:
sys.stderr.write("Unit %s found multiple times!\n" % name)
continue
doubles[name] = 1
r = u.get_text_val("race") or "unknown"
r = r[0].upper() + r[1:]
l = u.get_text_val("level")
levels = races.get(r, {})
ulist = levels.get(l, [])
ulist.append(u)
levels[l] = ulist
races[r] = levels
def poname(name):
return name[name.find("^") + 1:]
def place_units(race):
if use_html:
print "<font size=5>%s - %s</font>" % (race, campaign)
print "<table border=solid>"
else:
print '| colspan="6" | <font size=5>%s - %s</font>' % (race, campaign)
print '|-'
print '| level 0 || level 1 || level 2 || level 3 || level 4 || level 5'
levels = []
for i in range(6):
levels.append(races[race].get(str(i), []))
row = 0
while 1:
if use_html: print "<tr>"
else: print "|-"
ok = False
units = []
for i in range(6):
if row < len(levels[i]):
ok = True
if not ok: break
for i in range(6):
if use_html: print "<td>"
else: print "|",
if row < len(levels[i]):
u = levels[i][row]
name = u.get_text_val("name")
translated = tx.get(name, "?")
if use_html:
print "<b>%s</b>" % translated
print "<br>"
print poname(name)
else:
print "'''%s''' <br>" % translated,
print poname(name),
f = u.get_first("female")
if f:
name = f.get_text_val("name")
translated = tx.get(name, "?")
if use_html:
print "<br>"
print "<b>%s</b>" % translated
print "<br>"
print poname(name)
else:
print "<br>",
print "'''%s''' <br>" % translated,
print poname(name),
if use_html: print "</td>"
else: print
if use_html: print "</tr>"
else: print "|-"
row += 1
if use_html: print "</table>"
rlist = races.keys()
rlist.sort()
for race in rlist:
place_units(race)
def force_encoding():
"""
Temporary hack to always have redirecting of the script output always
produce utf8. Can be removed once there is a way to output to a file.
"""
if sys.stdout.encoding == "UTF-8": return
out = sys.stdout
class stdout_wrapper:
def write(self, x):
out.write(x.encode("utf8"))
sys.stdout = stdout_wrapper()
if __name__ == '__main__':
import getopt
force_encoding()
try:
(options, arguments) = getopt.getopt(sys.argv[1:], "hl:?", [
"html",
"lang=",
"usage",
])
except getopt.GetoptError:
help()
sys.exit(1)
isocode = "de"
use_html = False
for (switch, val) in options:
if switch in ('-h', '--html'):
html = True
elif switch in ('-l', '--lang'):
isocode = val
elif switch in ('-?', '--usage'):
print __doc__
sys.exit(1)
wmltools.pop_to_top("wmlunits")
datadir = os.getcwd() + "/data"
unitlist = UnitList()
# Parse all unit data
# This reads in units.cfg, giving us all the mainline units.
unitlist.add("{core/units.cfg}", "mainline")
# Now we read each campaign in turn to get its units.
campaigns = glob.glob("data/campaigns/*")
for campaign in campaigns:
dirname = campaign[5:] # strip leading data/
description = dirname[10:].replace("_", " ")
unitlist.add("{%s}" % dirname, description)
# Report generation
if use_html:
print "<html><body>"
else:
print '{| border="solid"'
for (campaign, unitgroup) in unitlist.units_by_campaign.items():
report_unit_names(campaign, unitgroup, isocode)
if use_html:
print "</body></html>"
else:
print "|}"