Python version of wmlunits is done (minus some todos and bugs).
This commit is contained in:
parent
8d2a2a6d54
commit
1d2e6debf4
5 changed files with 489 additions and 201 deletions
|
@ -1,24 +1,47 @@
|
|||
body {
|
||||
background-color: #c0cbcf;
|
||||
margin: 0px;
|
||||
}
|
||||
table.units {
|
||||
background-color: #fffbf0;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
margin: 0px;
|
||||
border: none;
|
||||
padding: 0px;
|
||||
border-spacing: 0px;
|
||||
}
|
||||
table.frmale {
|
||||
div.pic {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
border: none;
|
||||
}
|
||||
td {
|
||||
border: none;
|
||||
display: inline;
|
||||
float: left;
|
||||
}
|
||||
td.unitcell {
|
||||
font-size: small;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
border-bottom: 2px solid #cfcbc0;
|
||||
border-top: 2px solid #fffbf0;
|
||||
border-right: 2px solid #fffbf0;
|
||||
}
|
||||
div#navbar a {
|
||||
td.unitcell a {
|
||||
color: black;
|
||||
font-size: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
table.navbar {
|
||||
margin: 0px;
|
||||
float: left;
|
||||
width: 0px;
|
||||
border-spacing: 0px;
|
||||
padding: 2px;
|
||||
border: 1px solid #b0bbff;
|
||||
}
|
||||
table.navbar th {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
table.navbar a {
|
||||
color: black;
|
||||
font-size: small;
|
||||
font-weight: bold;
|
||||
|
@ -29,10 +52,23 @@ td.raceheader {
|
|||
font-size: xx-large;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
border: 1px solid #b0bbff;
|
||||
}
|
||||
tr.levels th {
|
||||
border-bottom: 1px solid #cfcbc0;
|
||||
}
|
||||
table.unitinfo {
|
||||
background-color: #efebd0;
|
||||
margin: 2px;
|
||||
border: 1px solid black;
|
||||
float: left;
|
||||
}
|
||||
table.unitinfo th {
|
||||
text-align: left;
|
||||
}
|
||||
td.special {
|
||||
color: red;
|
||||
}
|
||||
td.empty {
|
||||
background-color: #fffbf0;
|
||||
}
|
||||
|
@ -60,9 +96,6 @@ col.col5 {
|
|||
background-color: #f7ebd8;
|
||||
width: 16%;
|
||||
}
|
||||
td.unitcell img {
|
||||
float: left;
|
||||
}
|
||||
div.l {
|
||||
color: gray;
|
||||
font-weight: normal;
|
||||
|
|
|
@ -3,6 +3,13 @@
|
|||
|
||||
"""
|
||||
This module represents the internal appearance of WML.
|
||||
|
||||
Note: We cannot store textdomain information, due to how the parser work.
|
||||
For example:
|
||||
name = _"x" + {foor} + {bar}
|
||||
That string may actually be composed from three different textdomains. The
|
||||
textdomain stuff in here is therefore only useful to CampGen, as that does
|
||||
not allow composed strings like above.
|
||||
"""
|
||||
|
||||
import re, sys, os
|
||||
|
@ -40,15 +47,13 @@ class Data:
|
|||
|
||||
class DataText(Data):
|
||||
"""Represents any text strings."""
|
||||
def __init__(self, name, text, translatable = False, textdomain = ""):
|
||||
def __init__(self, name, text, translatable = False):
|
||||
Data.__init__(self, name)
|
||||
self.data = text
|
||||
self.translatable = translatable
|
||||
self.textdomain = textdomain
|
||||
|
||||
def copy(self):
|
||||
return DataText(self.name, self.data, self.translatable,
|
||||
self.textdomain)
|
||||
return DataText(self.name, self.data, self.translatable)
|
||||
|
||||
def get_value(self):
|
||||
return self.data
|
||||
|
|
|
@ -28,8 +28,9 @@ class Parser:
|
|||
|
||||
class Macro:
|
||||
"""Class to hold one single macro."""
|
||||
def __init__(self, name, params, text):
|
||||
self.name, self.params, self.text = name, params, text
|
||||
def __init__(self, name, params, text, textdomain):
|
||||
self.name, self.params, self.text, self.textdomain =\
|
||||
name, params, text, textdomain
|
||||
|
||||
class TextState:
|
||||
def __init__(self, filename, text, textpos, line, current_path,
|
||||
|
@ -65,6 +66,11 @@ class Parser:
|
|||
|
||||
self.macro_not_found_callback = None
|
||||
self.no_macros = False
|
||||
|
||||
# If set to a function, the function is called with the current
|
||||
# textdomain and string as arguments for any translatable string, and
|
||||
# is expected to return a translation.
|
||||
self.gettext = None
|
||||
|
||||
# If set, we actually do preprocessor logic with #ifdef and so on.
|
||||
# Otherwise, they get included in the parse tree as nodes.
|
||||
|
@ -344,7 +350,8 @@ class Parser:
|
|||
if macro.startswith("~"):
|
||||
return None
|
||||
|
||||
# No file was found, try to do macro expansion.
|
||||
# No file was found, try to do macro expansion. First, push the
|
||||
# macro call again. E.g. {blah 1 2 3}.
|
||||
self.push_text("macro", preserve)
|
||||
|
||||
# Find all parameters.
|
||||
|
@ -418,7 +425,7 @@ class Parser:
|
|||
params[1 + i])
|
||||
|
||||
if text:
|
||||
self.push_text(name, text, initial_textdomain = self.textdomain)
|
||||
self.push_text(name, text, initial_textdomain = macro.textdomain)
|
||||
else:
|
||||
pass # empty macro, nothing to do
|
||||
else:
|
||||
|
@ -483,12 +490,18 @@ class Parser:
|
|||
variable += c
|
||||
else:
|
||||
if c == '"':
|
||||
# We want the textdomain at the beginning of the string,
|
||||
# the end of the string may be outside a macro and already
|
||||
# in another textdomain.
|
||||
textdomain = self.textdomain
|
||||
# remove possible _
|
||||
i = len(value)
|
||||
while i > 0:
|
||||
i -= 1
|
||||
if value[i] != " ": break
|
||||
got_underscore = False
|
||||
if value and value[i] == "_":
|
||||
got_underscore = True
|
||||
translatable = True
|
||||
# This is not the assignement =, but from e.g. MENU_IMG_TXT
|
||||
if i == 0 or value[i - 1] in [" ", "="]:
|
||||
|
@ -499,6 +512,9 @@ class Parser:
|
|||
value = value[:i]
|
||||
|
||||
string = self.parse_string()
|
||||
if got_underscore:
|
||||
if self.gettext:
|
||||
string = self.gettext(textdomain, string)
|
||||
value += string
|
||||
spaces = ""
|
||||
else:
|
||||
|
@ -523,8 +539,7 @@ class Parser:
|
|||
data = []
|
||||
j = 0
|
||||
for i in range(len(variables)):
|
||||
data += [wmldata.DataText(variables[i], values[j],
|
||||
translatable = translatable, textdomain = self.textdomain)]
|
||||
data += [wmldata.DataText(variables[i], values[j])]
|
||||
j += 1
|
||||
return data
|
||||
|
||||
|
@ -551,7 +566,7 @@ class Parser:
|
|||
return
|
||||
if not self.just_parse:
|
||||
self.macros[params[0]] = self.Macro(
|
||||
params[0], params[1:], text)
|
||||
params[0], params[1:], text, self.textdomain)
|
||||
if self.verbose:
|
||||
sys.stderr.write("New macro: %s.\n" % params[0])
|
||||
|
||||
|
@ -635,7 +650,7 @@ class Parser:
|
|||
if state == name[1:] or state == "+" + name[1:]:
|
||||
return
|
||||
raise Error(self, "Mismatched closing tag [%s], expected [/%s]" % (name, state))
|
||||
subdata = wmldata.DataSub(name, textdomain=self.textdomain)
|
||||
subdata = wmldata.DataSub(name)
|
||||
self.parse_top(subdata, name)
|
||||
data.insert(subdata)
|
||||
elif c == '{':
|
||||
|
|
|
@ -615,14 +615,16 @@ class Translation(dict):
|
|||
matches = re.compile("""(msgid|msgstr)((\s*".*?")+)""").findall(gettext)
|
||||
id = ""
|
||||
for match in matches:
|
||||
text = "".join(re.compile('"(.*?)"').findall(match[1].replace("\\n", "")))
|
||||
text = "".join(re.compile('"(.*?)"').findall(match[1]))
|
||||
if match[0] == "msgid":
|
||||
id = text
|
||||
id = text.replace("\\n", "\n")
|
||||
else:
|
||||
self.gettext[id] = text
|
||||
self.gettext[id] = text.replace("\\n", "\n")
|
||||
def get(self, key, dflt):
|
||||
if self.isocode == "C":
|
||||
return key
|
||||
if key:
|
||||
return key[key.find("^") + 1:]
|
||||
return "?"
|
||||
else:
|
||||
return self.gettext.get(key, dflt)
|
||||
def __getitem__(self, key):
|
||||
|
|
|
@ -15,47 +15,55 @@ import wesnoth.wmldata as wmldata
|
|||
import wesnoth.wmlparser as wmlparser
|
||||
import wesnoth.wmltools as wmltools
|
||||
|
||||
macros_parsed = None
|
||||
def parse_core_macros_and_WML(text_to_parse):
|
||||
global macros_parsed
|
||||
# Create a new parser.
|
||||
parser = wmlparser.Parser(datadir)
|
||||
parser.do_preprocessor_logic = True
|
||||
#parser.verbose = True
|
||||
class ParserWithCoreMacros:
|
||||
def __init__(self, isocode):
|
||||
# Handle translations.
|
||||
self.translations = wmltools.Translations()
|
||||
def gettext(textdomain, x):
|
||||
return self.translations.get(textdomain, isocode, x, x)
|
||||
self.gettext = gettext
|
||||
|
||||
# Suppress complaints about undefined terrain macros
|
||||
parser.set_macro_not_found_callback(lambda wmlparser, name, params:
|
||||
name.startswith("TERRAIN") or name == "DISABLE_TRANSITIONS")
|
||||
|
||||
# Create a new WML object.
|
||||
WML = wmldata.DataSub("WML")
|
||||
|
||||
# Parse some macros.
|
||||
if macros_parsed:
|
||||
parser.macros = copy.copy(macros_parsed)
|
||||
else:
|
||||
print "Parsing core macros."
|
||||
# Create a new parser for the macros.
|
||||
parser = wmlparser.Parser(datadir)
|
||||
parser.do_preprocessor_logic = True
|
||||
parser.gettext = self.gettext
|
||||
|
||||
# Parse core macros.
|
||||
parser.parse_text("{core/macros/}\n")
|
||||
parser.parse_top(None)
|
||||
macros_parsed = copy.copy(parser.macros)
|
||||
|
||||
# Parse the actual WML.
|
||||
parser.parse_text(text_to_parse)
|
||||
parser.parse_top(WML)
|
||||
|
||||
return WML
|
||||
self.core_macros = parser.macros
|
||||
|
||||
def parse(self, text_to_parse):
|
||||
# Create the real parser.
|
||||
parser = wmlparser.Parser(datadir)
|
||||
parser.do_preprocessor_logic = True
|
||||
parser.gettext = self.gettext
|
||||
parser.macros = copy.copy(self.core_macros)
|
||||
|
||||
# Suppress complaints about undefined terrain macros
|
||||
parser.set_macro_not_found_callback(lambda wmlparser, name, params:
|
||||
name.startswith("TERRAIN") or name == "DISABLE_TRANSITIONS")
|
||||
|
||||
# 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
|
||||
|
||||
class ImageCollector:
|
||||
def __init__(self):
|
||||
self.images = {}
|
||||
def add(self, campaign, path):
|
||||
self.images[path] = campaign
|
||||
self.images[(path, campaign)] = True
|
||||
def copy_and_color_images(self, target_path):
|
||||
for i, c in self.images.items():
|
||||
if c == "mainline":
|
||||
ipath = os.path.join("data/core/images", i)
|
||||
else:
|
||||
ipath = os.path.join("data/campaigns/%s/images" % c, i)
|
||||
for i, c in self.images.keys():
|
||||
|
||||
if c == "mainline": bases = ["core/images"]
|
||||
else: bases = ["campaigns/%s/images" % c, "campaigns/%s/images/units" % c, "core/images"]
|
||||
for base in bases:
|
||||
ipath = os.path.join("data/%s" % base, i)
|
||||
if os.path.exists(ipath): break
|
||||
opath = os.path.join(target_path, "pics", c, i)
|
||||
try:
|
||||
os.makedirs(os.path.dirname(opath))
|
||||
|
@ -68,22 +76,31 @@ class ImageCollector:
|
|||
os.system(command)
|
||||
else:
|
||||
sys.stderr.write(
|
||||
"Warning: Required image \"%s\" does not exist.\n" % ipath)
|
||||
"Warning: Required image %s: \"%s\" does not exist.\n" % (c, i))
|
||||
|
||||
image_collector = ImageCollector()
|
||||
|
||||
class UnitList:
|
||||
def __init__(self):
|
||||
def __init__(self, isocode):
|
||||
self.units_by_campaign = {}
|
||||
self.unit_lookup = {}
|
||||
self.race_lookup = {}
|
||||
self.terrain_lookup = {}
|
||||
self.movetype_lookup = {}
|
||||
self.parser = ParserWithCoreMacros(isocode)
|
||||
|
||||
def add_terrains(self):
|
||||
WML = self.parser.parse("{core/terrain.cfg}\n")
|
||||
|
||||
for terrain in WML.get_all("terrain"):
|
||||
tid = terrain.get_text_val("id")
|
||||
self.terrain_lookup[tid] = terrain
|
||||
|
||||
def add(self, text_to_parse, campaign):
|
||||
"Collect all units in the specified namespace."
|
||||
|
||||
WML = parse_core_macros_and_WML(text_to_parse)
|
||||
#WML.debug()
|
||||
|
||||
WML = self.parser.parse(text_to_parse)
|
||||
|
||||
# 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].
|
||||
|
@ -98,7 +115,7 @@ class UnitList:
|
|||
define = campaign_wml.get_text_val("define")
|
||||
|
||||
# Re-parse, this time with the define defined.
|
||||
WML = parse_core_macros_and_WML(
|
||||
WML = self.parser.parse(
|
||||
"#define %s\n#enddef\n%s" % (define, text_to_parse))
|
||||
# This time, it oughta work.
|
||||
units = WML.get_first("+units")
|
||||
|
@ -121,8 +138,14 @@ class UnitList:
|
|||
for race in newraces:
|
||||
rid = race.get_text_val("id")
|
||||
self.race_lookup[rid] = race
|
||||
|
||||
# Find all movetypes.
|
||||
newmovetypes = units.get_all("movetype")
|
||||
for movetype in newmovetypes:
|
||||
mtname = movetype.get_text_val("name")
|
||||
self.movetype_lookup[mtname] = movetype
|
||||
|
||||
# Store the race of each unit for easier access later.
|
||||
# Store the race and movetype of each unit for easier access later.
|
||||
for unit in newunits:
|
||||
race = self.get_unit_value(unit, "race")
|
||||
try: unit.race = self.race_lookup[race]
|
||||
|
@ -130,20 +153,30 @@ class UnitList:
|
|||
unit.race = None
|
||||
sys.stderr.write("Warning: No race \"%s\" found (%s).\n" % (
|
||||
race, unit.get_text_val("id")))
|
||||
movetype = self.get_unit_value(unit, "movement_type")
|
||||
try: unit.movetype = self.movetype_lookup[movetype]
|
||||
except KeyError: unit.movetype = None
|
||||
|
||||
return len(newunits)
|
||||
|
||||
def get_base_unit(self, unit):
|
||||
b = unit.get_first("base_unit")
|
||||
if b:
|
||||
buid = b.get_text_val("id")
|
||||
try: baseunit = self.unit_lookup[buid]
|
||||
except KeyError:
|
||||
sys.stderr.write(
|
||||
"Warning: No baseunit \"%s\" for \"%s\".\n" % (
|
||||
buid, unit.get_text_val("id")))
|
||||
return None
|
||||
return baseunit
|
||||
return None
|
||||
|
||||
def get_unit_value(self, unit, attribute, default = None):
|
||||
value = unit.get_text_val(attribute, None)
|
||||
if value == None:
|
||||
b = unit.get_first("base_unit")
|
||||
if b:
|
||||
buid = b.get_text_val("id")
|
||||
try: baseunit = self.unit_lookup[buid]
|
||||
except KeyError:
|
||||
sys.stderr.write(
|
||||
"Warning: No baseunit \"%s\" for \"%s\".\n" % (
|
||||
buid, unit.get_text_val("id")))
|
||||
return default
|
||||
baseunit = self.get_base_unit(unit)
|
||||
if baseunit:
|
||||
return self.get_unit_value(baseunit, attribute, default)
|
||||
return default
|
||||
return value
|
||||
|
@ -154,31 +187,44 @@ class UnitForest:
|
|||
"""
|
||||
def __init__(self):
|
||||
self.trees = {}
|
||||
self.lookup = {}
|
||||
|
||||
def add_node(self, un):
|
||||
"""
|
||||
Add a new unit to the forest.
|
||||
"""
|
||||
|
||||
self.lookup[un.id] = un
|
||||
|
||||
# First, we check if any of the new node's advancements already is in
|
||||
# the forest. If so, remove it and attach it to the new node.
|
||||
for cid in un.child_ids:
|
||||
if cid in self.trees:
|
||||
un.children.append(self.trees[cid])
|
||||
self.lookup[cid].parent_ids.append(un.id)
|
||||
del self.trees[cid]
|
||||
|
||||
# Next, we check if the ndoe is an advancement of an existing node. If
|
||||
# Next, we check if the node is an advancement of an existing node. If
|
||||
# so, add it there.
|
||||
for rootnode in self.trees.values():
|
||||
if rootnode.try_add(un):
|
||||
return
|
||||
|
||||
# Else, add a new tree with the new ndoe as root.
|
||||
# Else, add a new tree with the new node as root.
|
||||
self.trees[un.id] = un
|
||||
|
||||
def update_breadth(self):
|
||||
self.breadth = sum([x.update_breadth() for x in self.trees.values()])
|
||||
return self.breadth
|
||||
|
||||
def get_children(self, uid):
|
||||
un = self.lookup[uid]
|
||||
return un.child_ids
|
||||
|
||||
def get_parents(self, uid):
|
||||
un = self.lookup[uid]
|
||||
return un.parent_ids
|
||||
|
||||
class UnitNode:
|
||||
"""
|
||||
A node in the advancement trees forest.
|
||||
|
@ -188,6 +234,7 @@ class UnitNode:
|
|||
self.children = []
|
||||
self.id = unit.get_text_val("id")
|
||||
self.child_ids = []
|
||||
self.parent_ids = []
|
||||
advanceto = unit.get_text_val("advanceto")
|
||||
if advanceto and advanceto != "null":
|
||||
for advance in advanceto.split(","):
|
||||
|
@ -198,6 +245,7 @@ class UnitNode:
|
|||
# A child of yours truly?
|
||||
if un.id in self.child_ids:
|
||||
self.children.append(un)
|
||||
un.parent_ids.append(self.id)
|
||||
return True
|
||||
# A recursive child?
|
||||
for child in self.children:
|
||||
|
@ -227,33 +275,23 @@ html_header = '''
|
|||
html_footer = "</body></html>"
|
||||
|
||||
class HTMLOutput:
|
||||
def __init__(self, isocode, output, campaign, verbose = False):
|
||||
def __init__(self, isocode, output, campaign, unitlist, verbose = False):
|
||||
self.isocode = isocode
|
||||
self.output = output
|
||||
self.campaign = campaign
|
||||
self.verbose = verbose
|
||||
|
||||
# Handle translations.
|
||||
self.gettext = wmltools.Translations()
|
||||
self.target = "index.html"
|
||||
self.unitlist = unitlist
|
||||
self.forest = None
|
||||
|
||||
def get_translation(self, item, attribute):
|
||||
value = item.get_text_val(attribute)
|
||||
text = self.gettext.get(item.textdomain, self.isocode, value, None)
|
||||
if not text:
|
||||
text = value
|
||||
if self.verbose:
|
||||
sys.stderr.write("Warning: No translation for %s/%s/%s.\n" % (
|
||||
self.isocode, item.textdomain, value))
|
||||
return text[text.find("^") + 1:]
|
||||
|
||||
def analyze_units(self, unitlist):
|
||||
# Lookup tables.
|
||||
unit_lookup = {}
|
||||
race_lookup = {}
|
||||
def get_translation(self, textdomain, key):
|
||||
return self.unitlist.parser.translations.get(textdomain, self.isocode,
|
||||
key, key)
|
||||
|
||||
def analyze_units(self):
|
||||
# Build an advancement tree forest of all units.
|
||||
forest = UnitForest()
|
||||
for u in unitlist.units_by_campaign[self.campaign]:
|
||||
forest = self.forest = UnitForest()
|
||||
for u in self.unitlist.units_by_campaign[self.campaign]:
|
||||
forest.add_node(UnitNode(u))
|
||||
forest.update_breadth()
|
||||
|
||||
|
@ -281,7 +319,7 @@ class HTMLOutput:
|
|||
def by_name(t1, t2):
|
||||
u1 = t1.unit
|
||||
u2 = t2.unit
|
||||
# FIXME: Use translated name for sorting
|
||||
|
||||
u1name = u1.get_text_val("name")
|
||||
u2name = u2.get_text_val("name")
|
||||
return cmp(u1name, u2name)
|
||||
|
@ -299,7 +337,7 @@ class HTMLOutput:
|
|||
|
||||
x = 0
|
||||
for race in racelist:
|
||||
node = RaceNode(unitlist.race_lookup[race])
|
||||
node = RaceNode(self.unitlist.race_lookup[race])
|
||||
rows[x][0] = (6, 1, node)
|
||||
for i in range(1, 6):
|
||||
rows[x][i] = (0, 0, None)
|
||||
|
@ -315,38 +353,63 @@ class HTMLOutput:
|
|||
languages = find_languages()
|
||||
langlist = languages.keys()
|
||||
langlist.sort()
|
||||
write("<div id=\"navbar\">\n")
|
||||
write("<table class=\"navbar\">")
|
||||
|
||||
write("Language:\n")
|
||||
for lang in langlist:
|
||||
write(" <a href=\"../%s_%s/index.html\">%s</a>" % (
|
||||
lang, self.campaign, languages[lang]))
|
||||
write("<br/>\n")
|
||||
|
||||
write("By Campaign: ")
|
||||
write("<tr>\n")
|
||||
write("<th>By Campaign</th></tr><tr><td>")
|
||||
for campaign in all_campaigns:
|
||||
lang = self.isocode
|
||||
# FIXME: translate campaign names
|
||||
write(" <a href=\"../%s_%s/index.html\">%s</a>" % (
|
||||
write(" <a href=\"../%s_%s/index.html\">%s</a><br/>\n" % (
|
||||
lang, campaign, campaign.replace("_", " ")))
|
||||
write("<br/>\n")
|
||||
write("</td>\n")
|
||||
write("</tr>\n")
|
||||
|
||||
write("By Faction: TODO<br/>\n")
|
||||
write("<tr>\n")
|
||||
write("<th>By Faction</th></tr><tr><td>TODO</td>\n")
|
||||
write("</tr>\n")
|
||||
|
||||
write("By Race: ")
|
||||
write("<a href=\"index.html\">All</a>")
|
||||
write("<tr>\n")
|
||||
write("<th>By Race</th></tr><tr><td>")
|
||||
write("<a href=\"index.html\">All</a><br/>\n")
|
||||
for rid in self.racelist:
|
||||
race = unitlist.race_lookup[rid]
|
||||
racename = self.get_translation(race, "plural_name")
|
||||
write(" <a href=\"index.html\">%s</a>" % racename)
|
||||
write("<br/>\n")
|
||||
race = self.unitlist.race_lookup[rid]
|
||||
racename = race.get_text_val("plural_name")
|
||||
write(" <a href=\"index.html\">%s</a><br/>" % racename)
|
||||
write("</td>\n")
|
||||
write("</tr>\n")
|
||||
|
||||
write("<tr>\n")
|
||||
write("<th>Language</th></tr><tr><td>")
|
||||
for lang in langlist:
|
||||
write(" <a href=\"../%s_%s/%s\">%s</a><br/>\n" % (
|
||||
lang, self.campaign, self.target, languages[lang]))
|
||||
write("</td>\n")
|
||||
write("</tr>\n")
|
||||
|
||||
write("</div>\n")
|
||||
write("</table>\n")
|
||||
|
||||
def write_units(self, unitlist):
|
||||
def pic(self, u, x):
|
||||
image = self.unitlist.get_unit_value(x, "image")
|
||||
if not image:
|
||||
if x.name == "female":
|
||||
baseunit = self.unitlist.get_base_unit(u)
|
||||
if baseunit:
|
||||
female = baseunit.get_first("female")
|
||||
return self.pic(u, female)
|
||||
sys.stderr.write(
|
||||
"Warning: Missing image for unit %s(%s).\n" % (
|
||||
u.get_text_val("id"), x.name))
|
||||
return None
|
||||
image_collector.add(self.campaign, image)
|
||||
image = os.path.join("../pics/%s" % self.campaign,
|
||||
image)
|
||||
return image
|
||||
|
||||
def write_units(self):
|
||||
def write(x): self.output.write(x)
|
||||
rows = self.unitgrid
|
||||
write("<table>\n")
|
||||
write("<table class=\"units\">\n")
|
||||
write("<colgroup>")
|
||||
for i in range(6):
|
||||
write("<col class=\"col%d\" />" % i)
|
||||
|
@ -365,8 +428,7 @@ class HTMLOutput:
|
|||
attributes += " colspan=%d" % hspan
|
||||
|
||||
if un and isinstance(un, RaceNode):
|
||||
# FIXME: translation
|
||||
racename = self.get_translation(un.race, "plural_name")
|
||||
racename = un.race.get_text_val("plural_name")
|
||||
attributes += " class=\"raceheader\""
|
||||
write("<td%s>" % attributes)
|
||||
write("%s" % racename)
|
||||
|
@ -375,46 +437,26 @@ class HTMLOutput:
|
|||
u = un.unit
|
||||
attributes += " class=\"unitcell\""
|
||||
write("<td%s>" % attributes)
|
||||
# FIXME: translation
|
||||
name = self.get_translation(u, "name")
|
||||
female = u.get_first("female")
|
||||
if female:
|
||||
fname = self.get_translation(female, "name")
|
||||
if fname != name:
|
||||
name += "<br/>" + fname
|
||||
|
||||
name = u.get_text_val("name")
|
||||
|
||||
uid = u.get_text_val("id")
|
||||
cost = u.get_text_val("cost")
|
||||
hp = u.get_text_val("hitpoints")
|
||||
mp = u.get_text_val("movement")
|
||||
xp = u.get_text_val("experience")
|
||||
level = u.get_text_val("level")
|
||||
|
||||
def pic(x):
|
||||
image = x.get_text_val("image")
|
||||
if not image:
|
||||
sys.stderr.write(
|
||||
"Warning: Missing image for unit %s(%s).\n" % (
|
||||
u.get_text_val("id"), x.name))
|
||||
return None
|
||||
image_collector.add(campaign, image)
|
||||
image = os.path.join("../pics/%s" % self.campaign,
|
||||
image)
|
||||
return image
|
||||
|
||||
write("<div class=\"l\">L%s</div>" % level)
|
||||
write("%s<br/>" % name)
|
||||
link = "../%s_%s/%s.html" % (self.isocode,
|
||||
self.campaign, uid)
|
||||
write("<a href=\"%s\">%s</a><br/>" % (link, name))
|
||||
|
||||
if female:
|
||||
mimage = pic(u)
|
||||
fimage = pic(female)
|
||||
if not fimage: fimage = mimage
|
||||
write('<table class="female"><tr><td>')
|
||||
write('<img src="%s" alt="(image)" />\n' % mimage)
|
||||
write('</td></tr><tr><td>')
|
||||
write('<img src="%s" alt="(image)" />\n' % fimage)
|
||||
write('</td></tr></table>\n')
|
||||
else:
|
||||
image = pic(u)
|
||||
write('<img src="%s" alt="(image)" />\n' % image)
|
||||
write('<div class="pic">')
|
||||
image = self.pic(u, u)
|
||||
write('<a href=\"%s\"><img src="%s" alt="(image)" /></a>\n' % (
|
||||
link, image))
|
||||
write('</div>\n')
|
||||
write("<div class=\"attributes\">")
|
||||
write("cost: %s<br />" % cost)
|
||||
write("HP: %s<br />" % hp)
|
||||
|
@ -427,15 +469,191 @@ class HTMLOutput:
|
|||
write("</tr>\n")
|
||||
write("</table>\n")
|
||||
|
||||
def create_page(self, unitlist):
|
||||
def write_unit_tree(self):
|
||||
self.output.write(html_header % {"path" : "../"})
|
||||
|
||||
self.analyze_units(unitlist)
|
||||
self.analyze_units()
|
||||
self.write_navbar()
|
||||
self.write_units(unitlist)
|
||||
self.write_units()
|
||||
|
||||
self.output.write(html_footer)
|
||||
|
||||
def write_unit_report(self, output, unit):
|
||||
def write(x): self.output.write(x)
|
||||
|
||||
self.output = output
|
||||
write(html_header % {"path" : "../"})
|
||||
self.write_navbar()
|
||||
|
||||
# Write unit name, picture and description.
|
||||
uid = unit.get_text_val("id")
|
||||
uname = unit.get_text_val("name")
|
||||
display_name = uname
|
||||
|
||||
female = unit.get_first("female")
|
||||
if female:
|
||||
fname = female.get_text_val("name")
|
||||
if 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)
|
||||
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 = unit.get_text_val("description")
|
||||
if not description: description = "-"
|
||||
write("<p>%s</p>\n" % description)
|
||||
|
||||
# Base info.
|
||||
|
||||
hp = self.unitlist.get_unit_value(unit, "hitpoints")
|
||||
mp = self.unitlist.get_unit_value(unit, "movement")
|
||||
xp = self.unitlist.get_unit_value(unit, "experience")
|
||||
level = self.unitlist.get_unit_value(unit, "level")
|
||||
alignment = self.unitlist.get_unit_value(unit, "alignment")
|
||||
|
||||
write("<p>%s" % self.get_translation("wesnoth", "Advances from: "))
|
||||
for pid in self.forest.get_parents(uid):
|
||||
link = "../%s_%s/%s.html" % (self.isocode, self.campaign, pid)
|
||||
name = self.unitlist.unit_lookup[pid].get_text_val("name")
|
||||
write(" <a href=\"%s\">%s</a>" % (link, name))
|
||||
write("</p>\n")
|
||||
write("<p>%s" % self.get_translation("wesnoth", "Advances to: "))
|
||||
for cid in self.forest.get_children(uid):
|
||||
link = "../%s_%s/%s.html" % (self.isocode, self.campaign, cid)
|
||||
name = self.unitlist.unit_lookup[cid].get_text_val("name")
|
||||
write(" <a href=\"%s\">%s</a>" % (link, name))
|
||||
write("</p>\n")
|
||||
write("<table class=\"unitinfo\">\n")
|
||||
for val in ["cost", "hitpoints", "movement", "experience", "level",
|
||||
"alignment"]:
|
||||
write("<tr>\n")
|
||||
write("<th>%s</th>" % val)
|
||||
x = self.unitlist.get_unit_value(unit, val)
|
||||
write("<td>%s</td>" % x)
|
||||
write("</tr>\n")
|
||||
write("</table>\n")
|
||||
|
||||
# Write info about movement costs and terrain defense.
|
||||
write("<table class=\"unitinfo\">\n")
|
||||
write("<tr>\n")
|
||||
write("<th>Terrain</th><th>Movement</th><th>Defense</th>\n")
|
||||
write("</tr>\n")
|
||||
|
||||
def find_attr(what, key):
|
||||
if unit.movetype:
|
||||
mtx = unit.movetype.get_first(what)
|
||||
mty = None
|
||||
if mtx: mty = mtx.get_text_val(key)
|
||||
x = unit.get_first(what)
|
||||
y = None
|
||||
if x: y = x.get_text_val(key)
|
||||
if y:
|
||||
return True, y
|
||||
if unit.movetype and mty != None:
|
||||
return False, mty
|
||||
return False, "-"
|
||||
|
||||
terrains = self.unitlist.terrain_lookup
|
||||
terrainlist = []
|
||||
for tid, t in terrains.items():
|
||||
if tid in ["off_map", "fog", "shroud"]: continue
|
||||
if t.get_first("aliasof"): continue
|
||||
name = t.get_text_val("name")
|
||||
terrainlist.append((name, tid))
|
||||
terrainlist.sort()
|
||||
|
||||
for tname, tid in terrainlist:
|
||||
special, c = find_attr("movement_costs", tid)
|
||||
ccell = "td"
|
||||
if special: ccell += ' class="special"'
|
||||
dcell = "td"
|
||||
special, d = find_attr("defense", tid)
|
||||
if special: dcell += ' class="special"'
|
||||
|
||||
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 info about resistances.
|
||||
resistances = [
|
||||
"blade",
|
||||
"pierce",
|
||||
"impact",
|
||||
"fire",
|
||||
"cold",
|
||||
"arcane"]
|
||||
|
||||
write("<table class=\"unitinfo\">\n")
|
||||
for rid in resistances:
|
||||
special, r = find_attr("resistance", rid)
|
||||
rcell = "td"
|
||||
if special: rcell += ' class="special"'
|
||||
write("<tr>\n")
|
||||
write("<th>%s</th><td>%s</td>\n" % (
|
||||
self.get_translation("wesnoth", rid), r))
|
||||
write("</tr>\n")
|
||||
write("</table>\n")
|
||||
|
||||
# Write info about attacks.
|
||||
write("<table class=\"unitinfo\">\n")
|
||||
for attack in unit.get_all("attack"):
|
||||
write("<tr>")
|
||||
|
||||
aid = attack.get_text_val("name")
|
||||
aname = attack.get_text_val("description")
|
||||
|
||||
icon = attack.get_text_val("icon")
|
||||
if not icon:
|
||||
icon = "attacks/%s.png" % aid
|
||||
image_collector.add(self.campaign, icon)
|
||||
icon = os.path.join("../pics/%s" % self.campaign, icon)
|
||||
write("<td><img src=\"%s\" alt=\"(image)\"/></td>" % icon)
|
||||
|
||||
write("<td>%s" % aname)
|
||||
|
||||
t = attack.get_text_val("type")
|
||||
write("<br/>%s</td>" % self.get_translation("wesnoth", t))
|
||||
|
||||
n = attack.get_text_val("number")
|
||||
x = attack.get_text_val("damage")
|
||||
try:
|
||||
x = " ".join(int(n) * [x])
|
||||
except TypeError:
|
||||
sys.stderr.write("Warning: Invalid damage for %s in %s.\n" % (
|
||||
aname, uname.encode("utf8")))
|
||||
x = "?"
|
||||
write("<td>%s" % x)
|
||||
|
||||
r = attack.get_text_val("range")
|
||||
write("<br/>%s</td>" % self.get_translation("wesnoth", r))
|
||||
|
||||
s = []
|
||||
specials = attack.get_first("specials")
|
||||
if specials:
|
||||
for special in specials.children():
|
||||
s.append(special.name)
|
||||
s = "<br/>".join(s)
|
||||
write("<td>%s</td>" % s)
|
||||
|
||||
|
||||
write("</tr>")
|
||||
write("</table>\n")
|
||||
|
||||
write(html_footer)
|
||||
|
||||
languages_found = {}
|
||||
def find_languages():
|
||||
"""
|
||||
|
@ -486,8 +704,14 @@ def generate_report(out_path, isocode, campaign, unitlist):
|
|||
path = os.path.join(out_path, isocode + "_" + campaign)
|
||||
if not os.path.isdir(path): os.mkdir(path)
|
||||
output = MyFile(os.path.join(path, "index.html"), "w")
|
||||
html = HTMLOutput(isocode, output, campaign)
|
||||
html.create_page(unitlist)
|
||||
html = HTMLOutput(isocode, output, campaign, unitlist)
|
||||
html.write_unit_tree()
|
||||
|
||||
for unit in unitlist.units_by_campaign[campaign]:
|
||||
uid = unit.get_text_val("id")
|
||||
output = MyFile(os.path.join(path, "%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")
|
||||
|
@ -501,8 +725,54 @@ def write_index(out_path):
|
|||
output.write("</div>")
|
||||
output.write(html_footer)
|
||||
|
||||
if __name__ == '__main__':
|
||||
def output(isocode):
|
||||
global all_campaigns
|
||||
|
||||
unitlist = UnitList(isocode)
|
||||
|
||||
# Parse all unit data
|
||||
# This reads in units.cfg, giving us all the mainline units.
|
||||
all_campaigns = []
|
||||
all_updated_campaigns = []
|
||||
|
||||
print "Reading WML stuff."
|
||||
unitlist.add_terrains()
|
||||
|
||||
print "Reading mainline units."
|
||||
unitlist.add("{core/units.cfg}", "mainline")
|
||||
all_updated_campaigns.append("mainline")
|
||||
all_campaigns.append("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:]
|
||||
if options.campaign == "all" or options.campaign == description:
|
||||
print "Reading %s units." % description
|
||||
if unitlist.add("{%s}" % dirname, description):
|
||||
all_updated_campaigns.append(description)
|
||||
all_campaigns.append(description)
|
||||
|
||||
# Report generation
|
||||
if not os.path.isdir(options.output):
|
||||
os.mkdir(options.output)
|
||||
write_index(options.output)
|
||||
|
||||
if options.campaign == "all":
|
||||
campaigns = all_updated_campaigns
|
||||
else:
|
||||
campaigns = [options.campaign]
|
||||
|
||||
if not campaigns:
|
||||
sys.stderr.write("No such campaign: %s\n" % options.campaign)
|
||||
sys.exit(1)
|
||||
|
||||
for campaign in campaigns:
|
||||
generate_report(options.output, isocode, campaign, unitlist)
|
||||
|
||||
if __name__ == '__main__':
|
||||
global options
|
||||
import optparse
|
||||
|
||||
op = optparse.OptionParser()
|
||||
|
@ -522,55 +792,18 @@ if __name__ == '__main__':
|
|||
|
||||
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.
|
||||
all_campaigns = []
|
||||
all_updated_campaigns = []
|
||||
#if options.campaign == "all" or options.campaign == "mainline":
|
||||
if 1: # Always need them for standard races
|
||||
print "Reading mainline units."
|
||||
unitlist.add("{core/units.cfg}", "mainline")
|
||||
all_updated_campaigns.append("mainline")
|
||||
all_campaigns.append("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:]
|
||||
if options.campaign == "all" or options.campaign == description:
|
||||
print "Reading %s units." % description
|
||||
if unitlist.add("{%s}" % dirname, description):
|
||||
all_updated_campaigns.append(description)
|
||||
all_campaigns.append(description)
|
||||
|
||||
# Report generation
|
||||
if not os.path.isdir(options.output):
|
||||
os.mkdir(options.output)
|
||||
write_index(options.output)
|
||||
|
||||
|
||||
if options.language == "all":
|
||||
languages = find_languages().keys()
|
||||
else:
|
||||
languages = [options.language]
|
||||
if options.campaign == "all":
|
||||
campaigns = all_updated_campaigns
|
||||
else:
|
||||
campaigns = [options.campaign]
|
||||
|
||||
if not campaigns:
|
||||
sys.stderr.write("No such campaign: %s\n" % options.campaign)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if not languages:
|
||||
sys.stderr.write("No such language: %s\n" % options.language)
|
||||
sys.exit(1)
|
||||
|
||||
sys.exit(1)
|
||||
|
||||
for isocode in languages:
|
||||
for campaign in campaigns:
|
||||
generate_report(options.output, isocode, campaign, unitlist)
|
||||
output(isocode)
|
||||
|
||||
if not options.nocopy:
|
||||
print "Copying files."
|
||||
|
|
Loading…
Add table
Reference in a new issue