Difference between revisions of "Ability/Script"
From Wildermyth Wiki
< Ability
m |
|||
(6 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
This is a [https://www.python.org/downloads/ Python] script to generate the [[Ability]] tables. Copy the code in the box below into a text file named '''<nowiki> | This is a [https://www.python.org/downloads/ Python] script to generate the [[Ability]] tables. Copy the code in the box below into a text file named '''<nowiki>wikiAbilityTable.py</nowiki>''' (or whatever you want) inside the '''<nowiki>Wildermyth</nowiki>''' directory. Then run it by calling '''<nowiki>python wikiAbilityTable.py</nowiki>''' from the command line.<ref>More precisely, you can put the script anywhere, but you need to call it from the '''<nowiki>Wildermyth</nowiki>''' directory.</ref> It will create a text file named '''<nowiki>wikiAbilityTable.txt</nowiki>''' with the appropriate wiki-formatted content. | ||
{| role="presentation" class="wikitable mw-collapsible mw-collapsed" | {| role="presentation" class="wikitable mw-collapsible mw-collapsed" | ||
| '''<nowiki> | | '''<nowiki>wikiAbilityTable.py</nowiki>''' | ||
|- | |- | ||
| | | | ||
Line 9: | Line 9: | ||
import re | import re | ||
aspect_directory = 'assets/data/aspects' | |||
text_file = 'assets/text/aspects/aspects.properties' | text_file = 'assets/text/aspects/aspects.properties' | ||
# make dictionary of localized names | |||
aspectNames = {} | aspectNames = {} | ||
Line 31: | Line 33: | ||
elif len(key_split) == 2 and key_split[-1] == 'blurb': | elif len(key_split) == 2 and key_split[-1] == 'blurb': | ||
aspectBlurbs[key_split[0]] = val[:-1] | aspectBlurbs[key_split[0]] = val[:-1] | ||
# read game version | |||
with open('version.txt','r',encoding='utf8') as f: | with open('version.txt','r',encoding='utf8') as f: | ||
lines = f.readlines() | lines = f.readlines() | ||
version = lines[0] | version = lines[0] | ||
# make list of abilities, by deck | |||
decks = {'common':[],'warrior':[],'hunter':[],'mystic':[],'upgrade':[]} | decks = {'common':[],'warrior':[],'hunter':[],'mystic':[],'upgrade':[]} | ||
aspectfiles = glob( | aspectfiles = glob(aspect_directory + '/*') | ||
for file in aspectfiles: | for file in aspectfiles: | ||
with open(file) as f: | with open(file) as f: | ||
Line 46: | Line 52: | ||
if entry.get('info', {}).get('abilityDeckUsage') == deck: | if entry.get('info', {}).get('abilityDeckUsage') == deck: | ||
decks[deck] += [entry] | decks[deck] += [entry] | ||
# move upgrades to other deck, if they upgrade that deck's ability | |||
upgrades = [] | upgrades = [] | ||
Line 65: | Line 73: | ||
decks['upgrade'] = upgrades | decks['upgrade'] = upgrades | ||
# sort ability decks by localized name | |||
for deck in decks: | for deck in decks: | ||
decks[deck] = sorted(decks[deck], key=lambda d: aspectNames[d['id']]) | decks[deck] = sorted(decks[deck], key=lambda d: aspectNames[d['id']]) | ||
# wiki blurb for each deck | |||
deck_blurbs = { | deck_blurbs = { | ||
Line 77: | Line 89: | ||
} | } | ||
# function to replace [tag]...[] or [tag]...[tag] | |||
# with new...new, while respecting nested brackets | |||
def replace_tag(tag,new,string): | def replace_tag(tag,new,string): | ||
Line 97: | Line 110: | ||
return string | return string | ||
linkwords = | # function to replace <a/b/.../y:aa/bz/.../yy/zz> with zz | ||
'Bonus Damage', | |||
'Potency', | def fail_condition(string): | ||
'Stunt Chance', | for opentag in ['<self.','<test:','<mf']: | ||
'Temp Health', | while True: | ||
'Temporary Health', | start = string.find(opentag) | ||
'Armor', | if start < 0: | ||
'Warding', | break | ||
'Dodge', | num = 1 | ||
'Block', | slashes = [] | ||
'Speed', | passed_colon = False | ||
'Recovery Rate', | for i,c in enumerate(string[start+len(opentag):]): | ||
'Retirement Age', | if c == '<': | ||
'Grayplane', | num += 1 | ||
'bonus damage', | elif c == '>': | ||
'spell damage', | num -= 1 | ||
'armor', | if num == 0: | ||
'warding', | end = i+start+len(opentag)+1 | ||
'dodge', | break | ||
'block', | elif c == '/' and num == 1 and passed_colon: | ||
'augment', | slashes += [i+start+len(opentag)] | ||
'grayplane', | elif c == ':': | ||
passed_colon = True | |||
if len(slashes) == 0: | |||
slashes += [end-1] | |||
string = string[:start] + string[slashes[-1]+1:end-1] + string[end:] | |||
return string | |||
# list of words to replace with links in the wiki | |||
linkwords = { | |||
'Bonus Damage':None, | |||
'Spell Damage':None, | |||
'Potency':None, | |||
'Stunt Chance':None, | |||
'Temp Health':None, | |||
'Temporary Health':None, | |||
'Armor':'Armor (Stat)', | |||
'Warding':None, | |||
'Dodge':None, | |||
'Block':None, | |||
'Speed':None, | |||
'Recovery Rate':None, | |||
'Retirement Age':None, | |||
'Grayplane':None, | |||
'bonus damage':None, | |||
'spell damage':None, | |||
'armor':'Armor (Stat)', | |||
'warding':None, | |||
'dodge':None, | |||
'block':None, | |||
'augment':None, | |||
'grayplane':None, | |||
'hidden':None, | |||
} | |||
# function to turn game-formatted ability blurb into wiki-formatted ability blurb | |||
def parse(blurb): | def parse(blurb): | ||
out = blurb | out = blurb | ||
out = replace_tag('b',"'''",out) | out = replace_tag('b',"'''",out) # bold -> bold | ||
out = replace_tag('blue',"",out) | out = replace_tag('blue',"",out) # blue -> plain | ||
out = replace_tag('gray',"",out) | out = replace_tag('gray',"",out) # gray -> plain | ||
out = out.replace('<self>','Hero') | out = out.replace('<self>','Hero') | ||
out = out.replace('<name>','Hero') | out = out.replace('<name>','Hero') | ||
out = re.sub(r'\<int:(.*?)\>', 'x', out) | # assume any requirements are not met | ||
out = re.sub(r'\<float:(.*?)\>', 'x', out) | out = fail_condition(out) | ||
### TODO: rewrite these to appropriately respect nested brackets and braces | |||
out = re.sub(r'\<int:(.*?)\>', 'x', out) # formula -> x | |||
out = re.sub(r'\<float:(.*?)\>', 'x', out) # formula -> x | |||
# status effect -> link | |||
out = re.sub(r'\[:statusEffect\.(.*?)\](.*?)\[\]', '[[\g<1>|\g<2>]]', out) | out = re.sub(r'\[:statusEffect\.(.*?)\](.*?)\[\]', '[[\g<1>|\g<2>]]', out) | ||
out = re.sub(r'\[statusEffect:(.*?)\](.*?)\[\]', '[[\g<1>|\g<2>]]', out) | out = re.sub(r'\[statusEffect:(.*?)\](.*?)\[\]', '[[\g<1>|\g<2>]]', out) | ||
out | # leave out "(Currently ...)" note which is based on hero's current stats | ||
out = re.sub(r'\(Current.*?\)', '', out) | out = re.sub(r'\(Current.*?\)', '', out) | ||
out = out.replace('\\n','<br />') | ### --- | ||
out = out.replace('\\n','<br />') # newline -> newline | |||
for word in linkwords: | for word in linkwords: # replace words with links | ||
out = out. | if linkwords[word] is not None: | ||
out = re.sub(r'(^|[^\[])' + word + r'($|[^\]])','\g<1>[[%s|%s]]\g<2>'%(linkwords[word],word),out) | |||
else: | |||
out = re.sub(r'(^|[^\[])' + word + r'($|[^\]])','\g<1>[[%s]]\g<2>'%(word),out) | |||
return out | return out | ||
# build output string | |||
string = '' | |||
for deck in decks: | for deck in decks: | ||
# add deck blurb | |||
string += deck_blurbs[deck] | string += deck_blurbs[deck] | ||
# add table headings | |||
if deck != 'upgrade': | if deck != 'upgrade': | ||
string += '\n{| class="wikitable"\n! Name\n! Description\n|-\n' | string += '\n{| class="wikitable"\n! Name\n! Description\n|-\n' | ||
else: | else: | ||
string += '\n{| class="wikitable sortable"\n! Name\n! | string += '\n{| class="wikitable sortable"\n! Name\n! Requirement\n! Description\n|-\n' | ||
# add ability lines | |||
for entry in decks[deck]: | for entry in decks[deck]: | ||
# add name | |||
name = aspectNames[entry['id']] | name = aspectNames[entry['id']] | ||
if name[-1] == '+': | if name[-1] == '+': | ||
nameStr = '[[' + name[:-1] + ']]+' | nameStr = '[[' + name[:-1] + ']]+' | ||
Line 164: | Line 229: | ||
nameStr = '[[' + name + ']]' | nameStr = '[[' + name + ']]' | ||
nameStr = nameStr.replace('/',']]/[[') | nameStr = nameStr.replace('/',']]/[[') | ||
string += '| %s\n'%(nameStr) | |||
# add requirements | |||
if deck == 'upgrade': | if deck == 'upgrade': | ||
requirements = [] | requirements = [] | ||
themes = [] | |||
legs = {} | |||
arms = {} | |||
for req in entry.get('abilityRequiresOneAspectOf'): | for req in entry.get('abilityRequiresOneAspectOf'): | ||
requirements += [req] | |||
reqname = | # get associated info | ||
requirements += ['[[%s|%s]]'%( | theme = None | ||
string += '| %s\n'%(' | if req.startswith('themePiece_'): | ||
theme = 'theme_' + req.split('_')[1] | |||
if req.endswith('leftArm') or req.endswith('rightArm'): | |||
if arms.get(theme): arms[theme] += 1 | |||
else: arms[theme] = 1 | |||
if req.endswith('leftLeg') or req.endswith('rightLeg'): | |||
if legs.get(theme): legs[theme] += 1 | |||
else: legs[theme] = 1 | |||
elif req.startswith('theme_'): | |||
theme = req | |||
themes += [theme] | |||
# start requirement string | |||
reqStr = '' | |||
# only precede with theme if there is only one | |||
onlyTheme = None | |||
if len(set(themes)) == 1 and themes[0] is not None: | |||
reqStr += '[[%s]]'%aspectNames[themes[0]] | |||
onlyTheme = themes[0] | |||
# compress requirements | |||
reqs = [] | |||
for i,req in enumerate(requirements): | |||
# if requirement = theme, don't repeat it | |||
if onlyTheme is not None and req == onlyTheme: | |||
continue | |||
# combine 2 arms | |||
if (req.endswith('leftArm') or req.endswith('rightArm')) and arms[themes[i]] != 1: | |||
if arms.get(themes[i]) >= 2: | |||
reqname = re.sub(r' \([LR]\)', '', aspectNames[req]) | |||
arms[themes[i]] = -1 | |||
elif arms.get(themes[i]) < 0: | |||
continue | |||
# combine 2 legs | |||
elif (req.endswith('leftLeg') or req.endswith('rightLeg')) and legs[themes[i]] != 1: | |||
if legs.get(themes[i]) >= 2: | |||
reqname = re.sub(r' \([LR]\)', '', aspectNames[req]) | |||
legs[themes[i]] = -1 | |||
elif legs.get(themes[i]) < 0: | |||
continue | |||
else: | |||
reqname = aspectNames[req] | |||
# requirements don't need to link if the theme already will | |||
if onlyTheme is None: | |||
reqs += ['[[%s|%s]]'%(aspectNames[themes[i]],reqname)] | |||
else: | |||
reqs += ['%s'%(reqname)] | |||
# join requirements into our string | |||
if len(reqs) > 0: | |||
reqStr += ': ' | |||
reqStr += ' or '.join(reqs) | |||
string += '| %s\n'%(reqStr) | |||
# add blurb | |||
blurb = aspectBlurbs[entry['id']] | |||
string += '| %s\n|-\n'%parse(blurb) | string += '| %s\n|-\n'%parse(blurb) | ||
string += '|} | |||
# close table | |||
string += '|}\n' | |||
string += '<small>Last updated [[%s]] using [[/Script|this script]].</small>\n'%version[:-1] | string += '<small>Last updated [[%s]] using [[/Script|this script]].</small>\n'%version[:-1] | ||
with open(' | # write the final string | ||
with open('wikiAbilityTable.txt', 'w') as f: | |||
f.write(string)</nowiki> | f.write(string)</nowiki> | ||
|} | |} |
Latest revision as of 07:31, 27 May 2022
This is a Python script to generate the Ability tables. Copy the code in the box below into a text file named wikiAbilityTable.py (or whatever you want) inside the Wildermyth directory. Then run it by calling python wikiAbilityTable.py from the command line.[1] It will create a text file named wikiAbilityTable.txt with the appropriate wiki-formatted content.
wikiAbilityTable.py |
import json from glob import glob import re aspect_directory = 'assets/data/aspects' text_file = 'assets/text/aspects/aspects.properties' # make dictionary of localized names aspectNames = {} aspectBlurbs = {} with open(text_file,'r',encoding='utf8') as f: lines = f.readlines() for line in lines: if line[0] == '#': continue try: key,val = line.split('=') except: continue try: key_split = key.split('.') except: continue if len(key_split) == 2 and key_split[-1] == 'name': aspectNames[key_split[0]] = val[:-1] elif len(key_split) == 2 and key_split[-1] == 'blurb': aspectBlurbs[key_split[0]] = val[:-1] # read game version with open('version.txt','r',encoding='utf8') as f: lines = f.readlines() version = lines[0] # make list of abilities, by deck decks = {'common':[],'warrior':[],'hunter':[],'mystic':[],'upgrade':[]} aspectfiles = glob(aspect_directory + '/*') for file in aspectfiles: with open(file) as f: data = json.load(f) for entry in data: for deck in decks: if entry.get('info', {}).get('abilityDeckUsage') == deck: decks[deck] += [entry] # move upgrades to other deck, if they upgrade that deck's ability upgrades = [] for entry in decks['upgrade']: upgradeFor = entry.get('info', {}).get('upgradeForAbility') if upgradeFor is not None: for deck in decks: for base in decks[deck]: if base['id'] == upgradeFor: decks[deck] += [entry] break else: continue break else: upgrades += [entry] else: upgrades += [entry] decks['upgrade'] = upgrades # sort ability decks by localized name for deck in decks: decks[deck] = sorted(decks[deck], key=lambda d: aspectNames[d['id']]) # wiki blurb for each deck deck_blurbs = { 'common':'=== General Abilities ===\nThese abilities are available to all heroes.\n', 'warrior':'=== Warrior Abilities ===\nThese abilities are only available to [[Warrior]]s.\n', 'hunter':'=== Hunter Abilities ===\nThese abilities are only available to [[Hunter]]s.\n', 'mystic':'=== Mystic Abilities ===\nThese abilities are only available to [[Mystic]]s.\n', 'upgrade':'=== Theme Upgrades ===\nThese upgrades require specific [[theme]]s.', } # function to replace [tag]...[] or [tag]...[tag] # with new...new, while respecting nested brackets def replace_tag(tag,new,string): while True: start = string.find('[%s]'%tag) if start < 0: break num = 1 for j in re.finditer(r'\[.*?\]',string[start+len(tag)+2:]): tag_ = string[start+len(tag)+2+j.start():start+len(tag)+2+j.end()][1:-1] if tag_ not in ['',tag]: num += 1 else: num -= 1 if num == 0: end = start+len(tag)+2+j.end() string = string[:start] + new + string[start+len(tag)+2:end-2-len(tag_)] + new + string[end:] break return string # function to replace <a/b/.../y:aa/bz/.../yy/zz> with zz def fail_condition(string): for opentag in ['<self.','<test:','<mf']: while True: start = string.find(opentag) if start < 0: break num = 1 slashes = [] passed_colon = False for i,c in enumerate(string[start+len(opentag):]): if c == '<': num += 1 elif c == '>': num -= 1 if num == 0: end = i+start+len(opentag)+1 break elif c == '/' and num == 1 and passed_colon: slashes += [i+start+len(opentag)] elif c == ':': passed_colon = True if len(slashes) == 0: slashes += [end-1] string = string[:start] + string[slashes[-1]+1:end-1] + string[end:] return string # list of words to replace with links in the wiki linkwords = { 'Bonus Damage':None, 'Spell Damage':None, 'Potency':None, 'Stunt Chance':None, 'Temp Health':None, 'Temporary Health':None, 'Armor':'Armor (Stat)', 'Warding':None, 'Dodge':None, 'Block':None, 'Speed':None, 'Recovery Rate':None, 'Retirement Age':None, 'Grayplane':None, 'bonus damage':None, 'spell damage':None, 'armor':'Armor (Stat)', 'warding':None, 'dodge':None, 'block':None, 'augment':None, 'grayplane':None, 'hidden':None, } # function to turn game-formatted ability blurb into wiki-formatted ability blurb def parse(blurb): out = blurb out = replace_tag('b',"'''",out) # bold -> bold out = replace_tag('blue',"",out) # blue -> plain out = replace_tag('gray',"",out) # gray -> plain out = out.replace('<self>','Hero') out = out.replace('<name>','Hero') # assume any requirements are not met out = fail_condition(out) ### TODO: rewrite these to appropriately respect nested brackets and braces out = re.sub(r'\<int:(.*?)\>', 'x', out) # formula -> x out = re.sub(r'\<float:(.*?)\>', 'x', out) # formula -> x # status effect -> link out = re.sub(r'\[:statusEffect\.(.*?)\](.*?)\[\]', '[[\g<1>|\g<2>]]', out) out = re.sub(r'\[statusEffect:(.*?)\](.*?)\[\]', '[[\g<1>|\g<2>]]', out) # leave out "(Currently ...)" note which is based on hero's current stats out = re.sub(r'\(Current.*?\)', '', out) ### --- out = out.replace('\\n','<br />') # newline -> newline for word in linkwords: # replace words with links if linkwords[word] is not None: out = re.sub(r'(^|[^\[])' + word + r'($|[^\]])','\g<1>[[%s|%s]]\g<2>'%(linkwords[word],word),out) else: out = re.sub(r'(^|[^\[])' + word + r'($|[^\]])','\g<1>[[%s]]\g<2>'%(word),out) return out # build output string string = '' for deck in decks: # add deck blurb string += deck_blurbs[deck] # add table headings if deck != 'upgrade': string += '\n{| class="wikitable"\n! Name\n! Description\n|-\n' else: string += '\n{| class="wikitable sortable"\n! Name\n! Requirement\n! Description\n|-\n' # add ability lines for entry in decks[deck]: # add name name = aspectNames[entry['id']] if name[-1] == '+': nameStr = '[[' + name[:-1] + ']]+' else: nameStr = '[[' + name + ']]' nameStr = nameStr.replace('/',']]/[[') string += '| %s\n'%(nameStr) # add requirements if deck == 'upgrade': requirements = [] themes = [] legs = {} arms = {} for req in entry.get('abilityRequiresOneAspectOf'): requirements += [req] # get associated info theme = None if req.startswith('themePiece_'): theme = 'theme_' + req.split('_')[1] if req.endswith('leftArm') or req.endswith('rightArm'): if arms.get(theme): arms[theme] += 1 else: arms[theme] = 1 if req.endswith('leftLeg') or req.endswith('rightLeg'): if legs.get(theme): legs[theme] += 1 else: legs[theme] = 1 elif req.startswith('theme_'): theme = req themes += [theme] # start requirement string reqStr = '' # only precede with theme if there is only one onlyTheme = None if len(set(themes)) == 1 and themes[0] is not None: reqStr += '[[%s]]'%aspectNames[themes[0]] onlyTheme = themes[0] # compress requirements reqs = [] for i,req in enumerate(requirements): # if requirement = theme, don't repeat it if onlyTheme is not None and req == onlyTheme: continue # combine 2 arms if (req.endswith('leftArm') or req.endswith('rightArm')) and arms[themes[i]] != 1: if arms.get(themes[i]) >= 2: reqname = re.sub(r' \([LR]\)', '', aspectNames[req]) arms[themes[i]] = -1 elif arms.get(themes[i]) < 0: continue # combine 2 legs elif (req.endswith('leftLeg') or req.endswith('rightLeg')) and legs[themes[i]] != 1: if legs.get(themes[i]) >= 2: reqname = re.sub(r' \([LR]\)', '', aspectNames[req]) legs[themes[i]] = -1 elif legs.get(themes[i]) < 0: continue else: reqname = aspectNames[req] # requirements don't need to link if the theme already will if onlyTheme is None: reqs += ['[[%s|%s]]'%(aspectNames[themes[i]],reqname)] else: reqs += ['%s'%(reqname)] # join requirements into our string if len(reqs) > 0: reqStr += ': ' reqStr += ' or '.join(reqs) string += '| %s\n'%(reqStr) # add blurb blurb = aspectBlurbs[entry['id']] string += '| %s\n|-\n'%parse(blurb) # close table string += '|}\n' string += '<small>Last updated [[%s]] using [[/Script|this script]].</small>\n'%version[:-1] # write the final string with open('wikiAbilityTable.txt', 'w') as f: f.write(string) |
- ↑ More precisely, you can put the script anywhere, but you need to call it from the Wildermyth directory.