MAJOR DIRECTORY OVERHAUL

This commit is contained in:
jrmiller82 committed 2020-04-25 01:37:42 -05:00
1 parent 71ed03b165
commit 34ef5a6025
138 files changed
+48 -6

No files matched your search

@@ -0,0 +1,147 @@
ancestries:
- boosts:
- CON
- WIS
- Free1
flavor_text: TODO
flaws:
- CHA
hp: 10
name: Dwarf
senses: Darkvision
size: Medium
source:
- abbr: CRB
page_start: 35
page_stop: 35
speed: 20
traits:
- Dwarf
- Humanoid
- boosts:
- DEX
- INT
- Free1
flavor_text: TODO
flaws:
- CON
hp: 6
name: Elf
senses: Low-Light Vision
size: Medium
source:
- abbr: CRB
page_start: 39
page_stop: 39
speed: 30
traits:
- Elf
- Humanoid
- boosts:
- CON
- CHA
- Free1
flavor_text: TODO
flaws:
- STR
hp: 8
name: Gnome
senses: Low-Light Vision
size: Small
source:
- abbr: CRB
page_start: 43
page_stop: 43
speed: 25
traits:
- Gnome
- Humanoid
- boosts:
- DEX
- CHA
- Free1
flavor_text: TODO
flaws:
- WIS
hp: 6
name: Goblin
senses: Darkvision
size: Small
source:
- abbr: CRB
page_start: 47
page_stop: 47
speed: 25
traits:
- Goblin
- Humanoid
- boosts:
- DEX
- WIS
- Free1
flavor_text: TODO
flaws:
- STR
hp: 6
name: Halfling
senses: Keen Eyes
size: Small
source:
- abbr: CRB
page_start: 51
page_stop: 51
speed: 25
traits:
- Halfling
- Humanoid
- boosts:
- Free1
- Free2
flavor_text: TODO
flaws: null
hp: 8
name: Human
senses: None
size: Medium
source:
- abbr: CRB
page_start: 55
page_stop: 55
speed: 25
traits:
- Human
- Humanoid
- boosts: null
flavor_text: TODO
flaws: null
hp: 8
name: Half-Elf
senses: None
size: Medium
source:
- abbr: CRB
page_start: 55
page_stop: 55
speed: 25
traits:
- Elf
- Human
- Humanoid
- Half-Elf
- boosts: null
flavor_text: TODO
flaws: null
hp: 8
name: Half-Orc
senses: None
size: Medium
source:
- abbr: CRB
page_start: 55
page_stop: 55
speed: 25
traits:
- Humanoid
- Human
- Orc
- Half-Orc
@@ -0,0 +1,489 @@
import yaml
import re
def main():
cleanuphtmlstuff()
with open("tmp-monsters-html-cleanup.yaml", 'r') as content_file:
data = yaml.full_load(content_file)
counter = 0
for i in data:
counter += 1
#print("{}\t{}".format(counter, i['name']))
# Set some data points before iteration
i['saves_special'] = {}
# clean up ability mods
for k, v in i['ability_mods'].items():
i['ability_mods'][k] = int(v)
# print(k, i['ability_mods'][k])
# clean up skills
for k, v in i['skills'].items():
i['skills'][k] = int(v)
# print(k, i['ability_mods'][k])
# clean up saves
for k, v in i['saves'].items():
# print(k, v)
i['saves_special'][k] = None
if ',' in v:
# print("WE GOT A COMMA")
i['saves'][k] = v.replace(',', '')
if ';' in v:
# print("WE GOT A SPECIAL")
a = v.split('; ')
# print(a)
i['saves_special'][k] = a[1]
i['saves'][k] = a[0]
elif '(' in v:
#print("we got a parentheses")
#print(v)
a = v.split(' (')
# print(a)
i['saves_special'][k] = a[1]
i['saves'][k] = a[0]
i['saves'][k] = int(i['saves'][k])
# print(k, i['saves'][k])
# clean up immunities
if i['immunities'] == "None":
i['immunities'] = None
else:
tmp = i['immunities']
splits = tmp.split(',')
res = []
for z in splits:
res.append(z.strip())
i['immunities'] = res
# clean up traits with trailing or leading whitespace
traitslist = []
#print(i['traits'])
for x in i['traits']:
traitslist.append(x.strip())
#print(x.strip())
#print(traitslist)
i['traits'] = traitslist
# clean up traits underneath proactive actions with trailing or leading whitespace
#print(i['proactive_abilities'])
for x in i['proactive_abilities']:
traitslist = []
if x['traits'] != None:
if len(x['traits']) == 0:
x['traits'] = None
else:
for y in x['traits']:
traitslist.append(y.strip())
#print(y.strip())
x['traits'] = traitslist
# clean up traits underneath automatic_abilities with trailing or leading whitespace
for x in i['automatic_abilities']:
# this one line fixes leading and trailing whitespace
x['description'] = x['description'].strip()
traitslist = []
if x['traits'] != None:
if len(x['traits']) == 0:
x['traits'] = None
else:
for y in x['traits']:
traitslist.append(y.strip())
#print(y.strip())
x['traits'] = traitslist
# clean up traits underneath melee with trailing or leading whitespace
for x in i['melee']:
traitslist = []
if x['traits'] != None:
if len(x['traits']) == 0:
x['traits'] = None
else:
for y in x['traits']:
traitslist.append(y.strip())
#print(y.strip())
x['traits'] = traitslist
# clean up traits underneath ranged with trailing or leading whitespace
for x in i['ranged']:
traitslist = []
if x['traits'] != None:
if len(x['traits']) == 0:
x['traits'] = None
else:
for y in x['traits']:
traitslist.append(y.strip())
#print(y.strip())
x['traits'] = traitslist
# clean up senses
senseslist = []
if i['senses'] != None:
if len(i['senses']) == 0:
i['senses'] = None
else:
for x in i['senses']:
senseslist.append(x.strip())
i['senses'] = senseslist
# clean up spell DC
if i['spell_dc'] == "None":
i['spell_dc'] = None
else:
i['spell_dc'] = int(i['spell_dc'])
# clean up innate_spell levels
if 'innate_spells' not in i:
i['innate_spells'] = None
elif i['innate_spells'] == "None":
i['innate_spells'] = None
else:
for x in i['innate_spells']:
x['level'] = int(x['level'])
# clean up level
i['level'] = int(i['level'])
# clean up AC and HP and Perception
###print("AC:\t{}".format(i['ac']))
###print("HP:\t{}".format(i['hp']))
res = re.match('(\d+)', i['ac'].strip())
i['ac'] = int(res.group(1))
res = re.match('(\d+)', i['hp'].strip())
i['hp'] = int(res.group(1))
# clean up melee to hit
if 'melee' not in i:
i['melee'] = None
elif i['melee'] == "None":
i['melee'] = None
else:
for x in i['melee']:
if 'to_hit' not in x:
x['to_hit'] = None
else:
res = re.search('(\d+)', x['to_hit'])
#print("{}\t{}".format(counter, i['name']))
if res:
x['to_hit'] = int(res.group(1))
# clean up ranged to hit
if 'ranged' not in i:
i['ranged'] = None
elif i['ranged'] == "None":
i['ranged'] = None
else:
for x in i['ranged']:
if 'to_hit' not in x:
x['to_hit'] = None
else:
res = re.search('(\d+)', x['to_hit'])
#print("{}\t{}".format(counter, i['name']))
if res:
x['to_hit'] = int(res.group(1))
# clean up spell attack to hit
if 'spell_attack_to_hit' not in i:
i['spell_attack_to_hit'] = None
elif i['spell_attack_to_hit'] == "None":
i['spell_attack_to_hit'] = None
else:
res = re.search('(\d+)', i['spell_attack_to_hit'])
#print("{}\t{}".format(counter, i['name']))
if res:
i['spell_attack_to_hit'] = int(res.group(1))
###if i['perception'] == None or i['perception'] == "":
### print("{}\t{}".format(counter, i['name']))
### print("\t\t\t\t{}".format(i['perception']))
if type(i['perception']) is str:
#print("{}\t{}".format(counter, i['name']))
res = re.match('(\d+)', i['perception'])
#print(res.group(1))
i['perception'] = int(res.group(1))
# clean up nulls for empty lists
if i['automatic_abilities'] == []:
i['automatic_abilities'] = None
if i['ranged'] == []:
i['ranged'] = None
if i['melee'] == []:
i['melee'] = None
# clean up resistances
# set Nones to null
if i['resistances'] == "None":
i['resistances'] = None
# remove trailing ;
elif i['resistances'].endswith(";"):
i['resistances'] = i['resistances'][:-1]
#print("\t{}".format(i['resistances']))
if i['resistances'] != None:
#print("{}\t{}".format(counter, i['name']))
#print("\t{}".format(i['resistances']))
# print("{}\t{}".format(counter, i['name']))
res = processResistances(i['resistances'])
i['resistances'] = res
#print(res)
#if type(i['resistances']) == str:
# print("{}\t{}".format(counter, i['name']))
# print("\t\t\t\t{}".format(i['resistances']))
# clean up speeds
newspeed = []
if 'land' in i['speed']:
# get number
res = re.match('(\d+)', i['speed']['land'])
amt = int(res.group(1))
newspeed.append({"type": "Land", "amount": amt })
if 'fly' in i['speed']:
if 'from fly' in i['speed']['fly']:
# do the from fly version
res = re.match('(\d+)', i['speed']['fly'])
amt = int(res.group(1))
newspeed.append({"type": "Fly (from Fly)", "amount": amt })
else:
# get number
res = re.match('(\d+)', i['speed']['fly'])
amt = int(res.group(1))
newspeed.append({"type": "Fly", "amount": amt })
if 'swim' in i['speed']:
# get number
res = re.match('(\d+)', i['speed']['swim'])
amt = int(res.group(1))
newspeed.append({"type": "Swim", "amount": amt })
if 'burrow' in i['speed']:
# get number
res = re.match('(\d+)', i['speed']['burrow'])
amt = int(res.group(1))
newspeed.append({"type": "Burrow", "amount": amt })
if 'climb' in i['speed']:
# get number
res = re.match('(\d+)', i['speed']['climb'])
amt = int(res.group(1))
newspeed.append({"type": "Climb", "amount": amt })
if 'iceclimb' in i['speed']:
# get number
res = re.match('(\d+)', i['speed']['iceclimb'])
amt = int(res.group(1))
newspeed.append({"type": "Ice Climb", "amount": amt })
if 'climbstone' in i['speed']:
# get number
res = re.match('(\d+)', i['speed']['climbstone'])
amt = int(res.group(1))
newspeed.append({"type": "Climb Stone", "amount": amt })
if 'burrowsnowonly' in i['speed']:
# get number
res = re.match('(\d+)', i['speed']['burrowsnowonly'])
amt = int(res.group(1))
newspeed.append({"type": "Burrow (snow only)", "amount": amt })
if 'burrowsandonly' in i['speed']:
# get number
res = re.match('(\d+)', i['speed']['burrowsandonly'])
amt = int(res.group(1))
newspeed.append({"type": "Burrow (sand only)", "amount": amt })
if 'special' in i['speed']:
for x in i['speed']['special']:
if x == "ice stride":
newspeed.append({"type": "Ice Stride", "amount": None })
if x == "trickster's step":
newspeed.append({"type": "Trickster's Step", "amount": None })
if x == "earth glide":
newspeed.append({"type": "Earth Glide", "amount": None })
if x == "sand glide":
newspeed.append({"type": "Sand Glide", "amount": None })
if x == "glide":
newspeed.append({"type": "Glide", "amount": None })
if x == "compression":
newspeed.append({"type": "Compression", "amount": None })
if x == "suction":
newspeed.append({"type": "Suction", "amount": None })
if x == "swamp stride":
newspeed.append({"type": "Swamp Stride", "amount": None })
if x == "powerful jumper":
newspeed.append({"type": "Powerful Jumper", "amount": None })
if x == "woodland stride":
newspeed.append({"type": "Woodland Stride", "amount": None })
if x == "trackless step":
newspeed.append({"type": "Trackless Step", "amount": None })
if x == "cloud walk":
newspeed.append({"type": "Cloud Walk", "amount": None })
if x == "swiftness":
newspeed.append({"type": "Swiftness", "amount": None })
if x == "freedom of movement (constant)":
newspeed.append({"type": "Freedom of Movement (constant)", "amount": None })
if x == "spider climb (constant)":
newspeed.append({"type": "Spider Climb (constant)", "amount": None })
if x == "unstoppable burrow":
newspeed.append({"type": "Unstoppable Burrow", "amount": None })
if x == "walk in shadow":
newspeed.append({"type": "Walk in Shadow", "amount": None })
if x == "magma swim":
newspeed.append({"type": "Magma Swim", "amount": None })
if x == "Can't Move":
newspeed.append({"type": "Can't Move", "amount": None })
if x == "Air Walk (constant)":
newspeed.append({"type": "Air Walk (constant)", "amount": None })
i['speed'] = newspeed
final = yaml.safe_dump(data, allow_unicode=True)
with open("tmp-monsters.yaml", 'w') as f:
f.write(final)
def cleanuphtmlstuff():
with open("monsters.yaml", 'r') as f:
lines = f.readlines()
for num, _ in enumerate(lines):
lines[num] = cleanupalinks(lines[num])
lines[num] = cleanupilinks(lines[num])
lines[num] = cleanupblinks(lines[num])
lines[num] = cleanupbrlinks(lines[num])
lines[num] = cleanupulinks(lines[num])
lines[num] = cleanupspellslinks(lines[num])
lines[num] = cleanupimglinks(lines[num])
lines[num] = cleanuptlinks(lines[num])
with open("tmp-monsters-html-cleanup.yaml", 'w') as f:
f.writelines(lines)
def cleanupalinks(x):
tmp = re.sub('<a.+?>', '', x)
tmp2 = re.sub('</a>', '', tmp)
return tmp2
def cleanuptlinks(x):
tmp = re.sub('<t>', '', x)
return tmp
def cleanupimglinks(x):
res = re.search('(<img.+?>)', x)
if res != None:
print(res)
if res:
if 'Single Action' in res.group(0):
print("SingleAction")
tmp = re.sub('<img.+?>', '|1|', x)
tmp = re.sub('\|1\|\|1\|', '|1|', tmp)
elif 'Two Actions' in res.group(0):
print("TwoActions")
tmp = re.sub('<img.+?>', '|2|', x)
tmp = re.sub('\|2\|\|2\|', '|2|', tmp)
elif 'Three Actions' in res.group(0):
print("ThreeActions")
tmp = re.sub('<img.+?>', '|3|', x)
tmp = re.sub('\|3\|\|3\|', '|3|', tmp)
elif 'Free Action' in res.group(0):
print("FreeAction")
tmp = re.sub('<img.+?>', '|F|', x)
tmp = re.sub('\|F\|\|F\|', '|F|', tmp)
print(tmp)
return tmp
else:
return x
def cleanupspellslinks(x):
tmp = re.sub('<spells.+?>', '', x)
tmp2 = re.sub('</spells.+?>', '', tmp)
return tmp2
def cleanupilinks(x):
tmp = re.sub('<i>', '*', x)
tmp2 = re.sub('</i>', '*', tmp)
return tmp2
def cleanupulinks(x):
tmp = re.sub('<u>', '', x)
tmp2 = re.sub('</u>', '', tmp)
return tmp2
def cleanupblinks(x):
tmp = re.sub('<b>', '**', x)
tmp2 = re.sub('</b>', '**', tmp)
return tmp2
def cleanupbrlinks(x):
return re.sub('<br>', '\n', x)
def processResistances(r):
if '(' in r:
# TODO This is what needs to be done
#print("\t\tTODO: Need to process with parentheses")
# this tree does the simple ones without multiple items
if ',' not in r:
rr = re.split('(\d+)', r)
return [{"type": rr[0].strip() + ' ' + rr[2].strip(), "amount": int(rr[1])},]
elif ',' in r:
# FIGURE OUT BRANCH FOR THE COMMA IS NOT INSIDE THE PARENTHETICAL
test = re.search('(\(.+\))', r)
tstr = test.group(0)
if ',' in tstr:
# TODO here's the case for comma IS inside the parenthetical
print("\n")
print(r)
if 'haunted form' not in r:
# DO the majority of them
rr = re.split('(\d+)', r)
print(rr)
return [{"type": rr[0].strip() + ' ' + rr[2].strip(), "amount": int(rr[1])},]
elif 'haunted form' in r:
# DO the single haunted form one
##### NOTE I'm hard coding this in as it will be faster than writing regex
result = [{"type": "all (except force, ghost touch, or positive; double resistance against non-magical)", "amount": 8},
{"type": "haunted form", "amount": 12}]
print(result)
return result
else:
# TODO Here's the case for comma is NOT inside the parenthetical
splits = re.split(',', r)
mysplitlist = []
for x in splits:
rr = re.split('(\d+)', x)
mysplitlist.append({"type": rr[0].strip() + ' ' + rr[2].strip(), "amount": int(rr[1])})
return mysplitlist
else:
print("else has been run")
return None
else:
#print("\t\tNo parentheses")
# split on commas
res = r.split(',')
#print(r.split(','))
#print(res)
results_list = []
for i in res:
#print(i)
#tmp = re.search('(\d+)', i)
#print(tmp.groups())
tmp = re.split('(\d+)', i)
#print(tmp)
tmpres = {"type": tmp[0].strip(), "amount": int(tmp[1])}
results_list.append(tmpres)
return results_list
return "Something went wrong"
if __name__ == "__main__":
main()
@@ -0,0 +1,59 @@
#!/usr/bin/env python3
#
#
import csv
import yaml
def main():
# Load the CSV file and print out the false ones that need to be updated
csvlist = []
with open('../../scripts/feat_level.csv') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
if row['match'] == "False":
csvlist.append(dict(row))
res = yaml.safe_dump(csvlist, allow_unicode=True, width=100000)
with open('feats-levels-false-matches.yaml', 'w') as f:
f.write(res)
# Load the CSV file and make YAML file for the matched ones
truelist = []
with open('../../scripts/feat_level.csv') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
if row['match'] == "True":
r = dict(row)
tmp = {'name': r['name'], 'level': r['level']}
truelist.append(tmp)
trueres = yaml.safe_dump(truelist, allow_unicode=True, width=100000)
with open('feats-levels-true-matches.yaml', 'w') as f:
f.write(trueres)
# open up feats.yaml
with open('feats.yaml') as yamlfile:
y = yaml.safe_load(yamlfile)
z = yaml.safe_load(trueres)
# y is original yaml to be modified
# z is new true list
for i in z:
#print("Looking for a match for: {}".format(i['name']))
match = False
for j in y['feat']:
if i['name'] == j['name']:
match = True
j['level'] = int(i['level'])
#print('We got a match for: {}'.format(i['name']))
if match == False:
print("We never got a match for: {}'.format(i['name'])")
final = yaml.safe_dump(y, allow_unicode=True, width=100000)
with open('feats.yaml', 'w') as f:
f.write(final)
if __name__ == "__main__":
main()
@@ -0,0 +1,420 @@
- level: '4'
match: 'False'
name: Refocus
name_aon: Arcane School Spell
url_aon: https://2e.aonprd.com/Feats.aspx?ID=743
url_search: https://2e.aonprd.com/Search.aspx?query=Refocus
- level: '2'
match: 'False'
name: Call on Ancient Blood
name_aon: Call of the Wild
url_aon: https://2e.aonprd.com/Feats.aspx?ID=317
url_search: https://2e.aonprd.com/Search.aspx?query=Call on Ancient Blood
- level: '-1'
match: 'False'
name: Burn It!
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Burn+It!
url_search: https://2e.aonprd.com/Search.aspx?query=Burn It!
- level: '-1'
match: 'False'
name: Very, Very Sneaky
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Very%2c+Very+Sneaky
url_search: https://2e.aonprd.com/Search.aspx?query=Very, Very Sneaky
- level: '9'
match: 'False'
name: Cooperataive Soul
name_aon: ''
url_aon: https://2e.aonprd.com/Spells.aspx?ID=21
url_search: https://2e.aonprd.com/Search.aspx?query=Cooperataive Soul
- level: '-1'
match: 'False'
name: Craft Philosopher's Stone
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Craft+Philosopher%u2019s+Stone
url_search: https://2e.aonprd.com/Search.aspx?query=Craft Philosopher’s Stone
- level: '-1'
match: 'False'
name: Dragon’s Rage Breath
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Dragon%u2019s+Rage+Breath
url_search: https://2e.aonprd.com/Search.aspx?query=Dragon’s Rage Breath
- level: '-1'
match: 'False'
name: Giant’s Stature
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Giant%u2019s+Stature
url_search: https://2e.aonprd.com/Search.aspx?query=Giant’s Stature
- level: '-1'
match: 'False'
name: Spirits’ Interference
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Spirits%u2019+Interference
url_search: https://2e.aonprd.com/Search.aspx?query=Spirits’ Interference
- level: '-1'
match: 'False'
name: Come and Get Me
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Come+and+Get+Me
url_search: https://2e.aonprd.com/Search.aspx?query=Come and Get Me
- level: '-1'
match: 'False'
name: Dragon’s Rage Wings
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Dragon%u2019s+Rage+Wings
url_search: https://2e.aonprd.com/Search.aspx?query=Dragon’s Rage Wings
- level: '-1'
match: 'False'
name: Predator’s Pounce
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Predator%u2019s+Pounce
url_search: https://2e.aonprd.com/Search.aspx?query=Predator’s Pounce
- level: '-1'
match: 'False'
name: Spirit’s Wrath
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Spirit%u2019s+Wrath
url_search: https://2e.aonprd.com/Search.aspx?query=Spirit’s Wrath
- level: '-1'
match: 'False'
name: Titan’s Stature
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Titan%u2019s+Stature
url_search: https://2e.aonprd.com/Search.aspx?query=Titan’s Stature
- level: '-1'
match: 'False'
name: Giant’s Lunge
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Giant%u2019s+Lunge
url_search: https://2e.aonprd.com/Search.aspx?query=Giant’s Lunge
- level: '1'
match: 'False'
name: Lingering Composition
name_aon: ''
url_aon: https://2e.aonprd.com/Spells.aspx?ID=389
url_search: https://2e.aonprd.com/Search.aspx?query=Lingering Composition
- level: '-1'
match: 'False'
name: Loremaster’s Etude
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Loremaster%u2019s+Etude
url_search: https://2e.aonprd.com/Search.aspx?query=Loremaster’s Etude
- level: '2'
match: 'False'
name: Inspire Defense
name_aon: ''
url_aon: https://2e.aonprd.com/Spells.aspx?ID=387
url_search: https://2e.aonprd.com/Search.aspx?query=Inspire Defense
- level: '4'
match: 'False'
name: Inspire Heroics
name_aon: ''
url_aon: https://2e.aonprd.com/Spells.aspx?ID=388
url_search: https://2e.aonprd.com/Search.aspx?query=Inspire Heroics
- level: '20'
match: 'False'
name: Symphony of the Muse
name_aon: Symphony of the Muses
url_aon: https://2e.aonprd.com/Feats.aspx?ID=213
url_search: https://2e.aonprd.com/Search.aspx?query=Symphony of the Muse
- level: '-1'
match: 'False'
name: Deity’s Domain
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Deity%u2019s+Domain
url_search: https://2e.aonprd.com/Search.aspx?query=Deity’s Domain
- level: '3'
match: 'False'
name: Litany Against Wrath
name_aon: ''
url_aon: https://2e.aonprd.com/Spells.aspx?ID=397
url_search: https://2e.aonprd.com/Search.aspx?query=Litany Against Wrath
- level: '6'
match: 'False'
name: Loyal Warhouse
name_aon: Loyal Warhorse
url_aon: https://2e.aonprd.com/Feats.aspx?ID=228
url_search: https://2e.aonprd.com/Search.aspx?query=Loyal Warhouse
- level: '-1'
match: 'False'
name: Advanced Deity’s Domain
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Advanced+Deity%u2019s+Domain
url_search: https://2e.aonprd.com/Search.aspx?query=Advanced Deity’s Domain
- level: '-1'
match: 'False'
name: Champion’s Sacrifice
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Champion%u2019s+Sacrifice
url_search: https://2e.aonprd.com/Search.aspx?query=Champion’s Sacrifice
- level: '-1'
match: 'False'
name: Deity’s Protection
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Deity%u2019s+Protection
url_search: https://2e.aonprd.com/Search.aspx?query=Deity’s Protection
- level: '-1'
match: 'False'
name: Avatar’s Audience
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Avatar%u2019s+Audience
url_search: https://2e.aonprd.com/Search.aspx?query=Avatar’s Audience
- level: '4'
match: 'False'
name: Mature Animal Companion (Druid)
name_aon: Mature Animal Companion (Druid)
url_aon: https://2e.aonprd.com/Feats.aspx?ID=322
url_search: https://2e.aonprd.com/Search.aspx?query=Mature Animal Companion
- level: '8'
match: 'False'
name: Incredible Companion (Druid)
name_aon: Incredible Companion (Druid)
url_aon: https://2e.aonprd.com/Feats.aspx?ID=332
url_search: https://2e.aonprd.com/Search.aspx?query=Incredible Companion
- level: '10'
match: 'False'
name: Side by Side (Druid)
name_aon: Side by Side (Druid)
url_aon: https://2e.aonprd.com/Feats.aspx?ID=339
url_search: https://2e.aonprd.com/Search.aspx?query=Side by Side
- level: '14'
match: 'False'
name: Specialized Companion (Druid)
name_aon: Specialized Companion (Druid)
url_aon: https://2e.aonprd.com/Feats.aspx?ID=344
url_search: https://2e.aonprd.com/Search.aspx?query=Specialized Companion
- level: '8'
match: 'False'
name: Impaling Briars
name_aon: ''
url_aon: https://2e.aonprd.com/Spells.aspx?ID=475
url_search: https://2e.aonprd.com/Search.aspx?query=Impaling Briars
- level: '-1'
match: 'False'
name: Hierophant’s Power
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Hierophant%u2019s+Power
url_search: https://2e.aonprd.com/Search.aspx?query=Hierophant’s Power
- level: '-1'
match: 'False'
name: Guardian’s Deflection
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Guardian%u2019s+Deflection
url_search: https://2e.aonprd.com/Search.aspx?query=Guardian’s Deflection
- level: '-1'
match: 'False'
name: Paragon’s Guard
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Paragon%u2019s+Guard
url_search: https://2e.aonprd.com/Search.aspx?query=Paragon’s Guard
- level: '14'
match: 'False'
name: Improved Twin Riposte (Fighter)
name_aon: Improved Twin Riposte (Fighter)
url_aon: https://2e.aonprd.com/Feats.aspx?ID=418
url_search: https://2e.aonprd.com/Search.aspx?query=Improved Twin Riposte
- level: '14'
match: 'False'
name: Stance Savant (Fighter)
name_aon: Stance Savant (Fighter)
url_aon: https://2e.aonprd.com/Feats.aspx?ID=419
url_search: https://2e.aonprd.com/Search.aspx?query=Stance Savant
- level: '20'
match: 'False'
name: Boudless Reprisals
name_aon: Boundless Reprisals
url_aon: https://2e.aonprd.com/Feats.aspx?ID=428
url_search: https://2e.aonprd.com/Search.aspx?query=Boudless Reprisals
- level: '1'
match: 'False'
name: Ki Strike
name_aon: ''
url_aon: https://2e.aonprd.com/Spells.aspx?ID=486
url_search: https://2e.aonprd.com/Search.aspx?query=Ki Strike
- level: '3'
match: 'False'
name: Ki Blast
name_aon: ''
url_aon: https://2e.aonprd.com/Spells.aspx?ID=484
url_search: https://2e.aonprd.com/Search.aspx?query=Ki Blast
- level: '14'
match: 'False'
name: Stance Savant (Monk)
name_aon: Stance Savant (Fighter)
url_aon: https://2e.aonprd.com/Feats.aspx?ID=419
url_search: https://2e.aonprd.com/Search.aspx?query=Stance Savant
- level: '8'
match: 'False'
name: Quivering Palm
name_aon: ''
url_aon: https://2e.aonprd.com/Spells.aspx?ID=487
url_search: https://2e.aonprd.com/Search.aspx?query=Quivering Palm
- level: '-1'
match: 'False'
name: Hunter’s Aim
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Hunter%u2019s+Aim
url_search: https://2e.aonprd.com/Search.aspx?query=Hunter’s Aim
- level: '-1'
match: 'False'
name: Companion’s Cry
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Companion%u2019s+Cry
url_search: https://2e.aonprd.com/Search.aspx?query=Companion’s Cry
- level: '-1'
match: 'False'
name: Scout’s Warning
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Scout%u2019s+Warning
url_search: https://2e.aonprd.com/Search.aspx?query=Scout’s Warning
- level: '4'
match: 'False'
name: Mature Animal Companion (Ranger)
name_aon: Mature Animal Companion (Druid)
url_aon: https://2e.aonprd.com/Feats.aspx?ID=322
url_search: https://2e.aonprd.com/Search.aspx?query=Mature Animal Companion
- level: '-1'
match: 'False'
name: Warden’s Boon
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Warden%u2019s+Boon
url_search: https://2e.aonprd.com/Search.aspx?query=Warden’s Boon
- level: '8'
match: 'False'
name: Incredible Companion (Ranger)
name_aon: Incredible Companion (Druid)
url_aon: https://2e.aonprd.com/Feats.aspx?ID=332
url_search: https://2e.aonprd.com/Search.aspx?query=Incredible Companion
- level: '-1'
match: 'False'
name: Warden’s Step
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Warden%u2019s+Step
url_search: https://2e.aonprd.com/Search.aspx?query=Warden’s Step
- level: '10'
match: 'False'
name: Side by Side (Ranger)
name_aon: Side by Side (Druid)
url_aon: https://2e.aonprd.com/Feats.aspx?ID=339
url_search: https://2e.aonprd.com/Search.aspx?query=Side by Side
- level: '-1'
match: 'False'
name: Warden’s Guidance
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Warden%u2019s+Guidance
url_search: https://2e.aonprd.com/Search.aspx?query=Warden’s Guidance
- level: '14'
match: 'False'
name: Improved Twin Riposte (Ranger)
name_aon: Improved Twin Riposte (Fighter)
url_aon: https://2e.aonprd.com/Feats.aspx?ID=418
url_search: https://2e.aonprd.com/Search.aspx?query=Improved Twin Riposte
- level: '14'
match: 'False'
name: Specialized Companion (Ranger)
name_aon: Specialized Companion (Druid)
url_aon: https://2e.aonprd.com/Feats.aspx?ID=344
url_search: https://2e.aonprd.com/Search.aspx?query=Specialized Companion
- level: '-1'
match: 'False'
name: You’re Next
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=You%u2019re+Next
url_search: https://2e.aonprd.com/Search.aspx?query=You’re Next
- level: '-1'
match: 'False'
name: Gang Up
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Gang+Up
url_search: https://2e.aonprd.com/Search.aspx?query=Gang Up
- level: '20'
match: 'False'
name: Sly Striker
name_aon: Impossible Striker
url_aon: https://2e.aonprd.com/Feats.aspx?ID=600
url_search: https://2e.aonprd.com/Search.aspx?query=Sly Striker
- level: '-1'
match: 'False'
name: Trickster’s Ace
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Trickster%u2019s+Ace
url_search: https://2e.aonprd.com/Search.aspx?query=Trickster’s Ace
- level: '12'
match: 'False'
name: Counterspell (Spontaneous)
name_aon: Clever Counterspell
url_aon: https://2e.aonprd.com/Feats.aspx?ID=653
url_search: https://2e.aonprd.com/Search.aspx?query=Counterspell
- level: '12'
match: 'False'
name: Counterspell (Prepared)
name_aon: Clever Counterspell
url_aon: https://2e.aonprd.com/Feats.aspx?ID=653
url_search: https://2e.aonprd.com/Search.aspx?query=Counterspell
- level: '-1'
match: 'False'
name: Archwizard’s Might
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Archwizard%u2019s+Might
url_search: https://2e.aonprd.com/Search.aspx?query=Archwizard’s Might
- level: '6'
match: 'False'
name: Advanced Conoction
name_aon: Advanced Weapon Training
url_aon: https://2e.aonprd.com/Feats.aspx?ID=378
url_search: https://2e.aonprd.com/Search.aspx?query=Advanced Conoction
- level: '-1'
match: 'False'
name: Juggernaut’s Fortitude
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Juggernaut%u2019s+Fortitude
url_search: https://2e.aonprd.com/Search.aspx?query=Juggernaut’s Fortitude
- level: '-1'
match: 'False'
name: Basic Muse’s Whispers
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Basic+Muse%u2019s+Whispers
url_search: https://2e.aonprd.com/Search.aspx?query=Basic Muse’s Whispers
- level: '-1'
match: 'False'
name: Advanced Muse’s Whispers
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Advanced+Muse%u2019s+Whispers
url_search: https://2e.aonprd.com/Search.aspx?query=Advanced Muse’s Whispers
- level: '-1'
match: 'False'
name: Champion’s Reaction
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Champion%u2019s+Reaction
url_search: https://2e.aonprd.com/Search.aspx?query=Champion’s Reaction
- level: '-1'
match: 'False'
name: Monk’s Flurry
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Monk%u2019s+Flurry
url_search: https://2e.aonprd.com/Search.aspx?query=Monk’s Flurry
- level: '-1'
match: 'False'
name: Perfection’s Path
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Perfection%u2019s+Path
url_search: https://2e.aonprd.com/Search.aspx?query=Perfection’s Path
- level: '-1'
match: 'False'
name: Basic Hunter’s Trick
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Basic+Hunter%u2019s+Trick
url_search: https://2e.aonprd.com/Search.aspx?query=Basic Hunter’s Trick
- level: '-1'
match: 'False'
name: Advanced Hunter’s Trick
name_aon: ''
url_aon: https://2e.aonprd.com/Search.aspx?query=Advanced+Hunter%u2019s+Trick
url_search: https://2e.aonprd.com/Search.aspx?query=Advanced Hunter’s Trick
- level: '1'
match: 'False'
name: Lie To Me
name_aon: Lie to Me
url_aon: https://2e.aonprd.com/Feats.aspx?ID=811
url_search: https://2e.aonprd.com/Search.aspx?query=Lie To Me
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,31 @@
import yaml
import pprint
def main():
with open('ancestries.yaml') as anc:
anc_data = yaml.full_load(anc)
with open('heritages.yaml') as her:
her_data = yaml.full_load(her)
print(anc_data)
print(her_data)
for i in anc_data['ancestries']:
i['heritages'] = []
for j in her_data:
print(j)
if i['name'] in j['name']:
i['heritages'].append(j)
pp = pprint.PrettyPrinter(indent=1)
pp.pprint(anc_data)
final = yaml.safe_dump(anc_data, allow_unicode=True)
with open('tmp-ancestriesheritages.yaml', 'w') as f:
f.write(final)
if __name__ == "__main__":
main()
@@ -0,0 +1,187 @@
- descr: Dwarven heroes of old could shrug off their enemies' magic, and some of that
resistance manifests in you. You gain the Call on Ancient Blood reaction.
feat: Call on Ancient Blood
name: Ancient-Blooded Dwarf
- descr: Your ancestors have been tomb guardians for generations, and the power they
cultivated to ward off necromancy has passed on to you. If you roll a success
on a saving throw against a necromancy effect, you get a critical success instead.
feat: null
name: Death Warden Dwarf
- descr: You have a remarkable adaptation to hot environments from ancestors who inhabited
blazing deserts or volcanic chambers beneath the earth. This grants you fire resistance
equal to half your level (minimum 1), and you treat environmental heat effects
as if they were one step less extreme (incredible heat becomes extreme, extreme
heat becomes severe, and so on).
feat: null
name: Forge Dwarf
- descr: Your ancestors lived and worked among the great ancient stones of the mountains
or the depths of the earth. This makes you solid as a rock when you plant your
feet. You gain a +2 circumstance bonus to your Fortitude or Reflex DC against
attempts to Shove or Trip you. This bonus also applies to saving throws against
spells or effects that attempt to knock you prone.
feat: null
name: Rock Dwarf
- descr: Your blood runs hearty and strong, and you can shake off toxins. You gain
poison resistance equal to half your level (minimum 1), and each of your successful
saving throws against a poison affliction reduces its stage by 2, or by 1 for
a virulent poison. Each critical success against an ongoing poison reduces its
stage by 3, or by 2 for a virulent poison.
feat: null
name: Strong-Blooded Dwarf
- descr: You dwell deep in the frozen north and have gained incredible resilience
against cold environments, granting you cold resistance equal to half your level
(minimum 1). You treat environmental cold effects as if they were one step less
extreme (incredible cold becomes extreme, extreme cold becomes severe, and so
on).
feat: null
name: Arctic Elf
- descr: You were born or spent many years in underground tunnels or caverns where
light is scarce. You gain darkvision.
feat: null
name: Cavern Elf
- descr: You have an inborn ability to detect and understand magical phenomena. You
can cast the detect magic cantrip as an arcane innate spell at will. A cantrip
is heightened to a spell level equal to half your level rounded up. In addition,
you gain a +1 circumstance bonus to checks to Identify Magic and to Decipher Writing
of a magical nature. These skill actions typically use the Arcana, Nature, Occultism,
or Religion skill.
feat: null
name: Seer Elf
- descr: Your ears are finely tuned, able to detect even the slightest whispers of
sound. As long as you can hear normally, you can use the Seek action to sense
undetected creatures in a 60-foot cone instead of a 30-foot cone. You also gain
a +2 circumstance bonus to locate undetected creatures that you could hear within
30 feet with a Seek action.
feat: null
name: Whisper Elf
- descr: You’re adapted to life in the forest or the deep jungle, and you know how
to climb trees and use foliage to your advantage. When Climbing trees, vines,
and other foliage, you move at half your Speed on a success and at full Speed
on a critical success (and you move at full Speed on a success if you have Quick
Climb). This doesn’t affect you if you’re using a climb Speed.
feat: null
name: Woodland Elf
- descr: The color of your hair and skin is mutable, possibly due to latent magic.
You can slowly change the vibrancy and the exact color, and the coloration can
be different across your body, allowing you to create patterns or other colorful
designs. It takes a single action for minor localized shifts and up to an hour
for dramatic shifts throughout your body. While you’re asleep, the colors shift
on their own in tune with your dreams, giving you an unusual coloration each morning.
When you’re in an area where your coloration is roughly similar to the environment
(for instance, forest green in a forest), you can use the single action to make
minor localized shifts designed to help you blend into your surroundings. This
grants you a +2 circumstance bonus to Stealth checks until your surroundings shift
in coloration or pattern.
feat: null
name: Chameleon Gnome
- descr: The blood of the fey is so strong within you that you’re truly one of them.
You gain the fey trait, in addition to the gnome and humanoid traits. Choose one
cantrip from the <%SPELL.LIST%Primal%%>primal spell list. You can cast this spell
as a primal innate spell at will. A cantrip is heightened to a spell level equal
to half your level rounded up. You can change this cantrip to a different one
from the same list once per day by meditating to realign yourself with the First
World; this is a 10-minute activity that has the concentrate trait.
feat: null
name: Fey-Touched Gnome
- descr: 'You see all colors as brighter, hear all sounds as richer, and especially
smell all scents with incredible detail. You gain a special sense: imprecise scent
with a range of 30 feet. This means you can use your sense of smell to determine
the exact location of a creature (as explained on page 465). The GM will usually
double the range if you’re downwind from the creature or halve the range if you’re
upwind.'
feat: null
name: Sensate Gnome
- descr: Whether from a connection to dark or shadowy fey, from the underground deep
gnomes also known as svirfneblin, or another source, you can see in complete darkness.
You gain darkvision.
feat: null
name: Umbral Gnome
- descr: Some other source of magic has a greater hold on you than the primal magic
of your fey lineage does. This connection might come from an occult plane or an
ancient occult song; a deity, celestial, or fiend; magical effluent left behind
by a mage war; or ancient rune magic.
feat: null
name: Wellspring Gnome
- descr: Your ancestors have always had a connection to fire and a thicker skin, which
allows you to resist burning. You gain fire resistance equal to half your level
(minimum 1). You can also recover from being on fire more easily. Your flat check
to remove persistent fire damage is DC 10 instead of DC 15, which is reduced to
DC 5 if another creature uses a particularly appropriate action to help.
feat: null
name: Charhide Goblin
- descr: You can subsist on food that most folks would consider spoiled. You can keep
yourself fed with poor meals in a settlement as long as garbage is readily available,
without using the Subsist downtime activity. You can eat and drink things when
you are sickened.
feat: null
name: Irongut Goblin
- descr: Your family’s teeth are formidable weapons. You gain a jaws unarmed attack
that deals 1d6 piercing damage. Your jaws are in the brawling group and have the
finesse and unarmed traits.
feat: null
name: Razortooth Goblin
- descr: You are acclimated to living in frigid lands and have skin ranging from sky
blue to navy in color, as well as blue fur. You gain cold resistance equal to
half your level (minimum 1). You treat environmental cold effects as if they were
one step less extreme (incredible cold becomes extreme, extreme cold becomes severe,
and so on).
feat: null
name: Snow Goblin
- descr: You’re able to bounce back from injuries easily due to an exceptionally thick
skull, cartilaginous bones, or some other mixed blessing. You gain 10 Hit Points
from your ancestry instead of 6. When you fall, reduce the falling damage you
take as though you had fallen half the distance.
feat: null
name: Unbreakable Goblin
- descr: Your family line is known for keeping a level head and staving off fear when
the chips were down, making them wise leaders and sometimes even heroes. When
you roll a success on a saving throw against an emotion effect, you get a critical
success instead.
feat: null
name: Gutsy Halfling
- descr: Accustomed to a calm life in the hills, your people find rest and relaxation
especially replenishing, particularly when indulging in creature comforts. When
you regain Hit Points overnight, add your level to the Hit Points regained. When
anyone uses the Medicine skill to Treat your Wounds, you can eat a snack to add
your level to the Hit Points you regain from their treatment.
feat: null
name: Hillock Halfling
- descr: 'Your ancestors have traveled from place to place for generations, never
content to settle down. You gain two additional languages of your choice, chosen
from among the common and uncommon languages available to you, and every time
you take the '
feat: null
name: Nomadic Halfling
- descr: Your ancestors performed many secret acts under the concealing cover of dusk,
whether for good or ill, and over time they developed the ability to see in twilight
beyond even the usual keen sight of halflings. You gain low-light vision.
feat: null
name: Twilight Halfling
- descr: You hail from deep in a jungle or forest, and you’ve learned how to use your
small size to wriggle through undergrowth, vines, and other obstacles. You ignore
difficult terrain from trees, foliage, and undergrowth.
feat: null
name: Wildwood Halfling
- descr: Either one of your parents was an elf, or one or both were half-elves. You
have pointed ears and other telltale signs of elf heritage. You gain the elf trait
and low-light vision. In addition, you can select elf, half-elf, and human feats
whenever you gain an ancestry feat.
feat: null
name: Half-Elf
- descr: One of your parents was an orc, or one or both were half-orcs. You have a
green tinge to your skin and other indicators of orc heritage. You gain the orc
trait and low-light vision. In addition, you can select orc, half-orc, and human
feats whenever you gain an ancestry feat.
feat: null
name: Half-Orc
- descr: Your ingenuity allows you to train in a wide variety of skills. You become
trained in one skill of your choice. At 5th level, you become an expert in the
chosen skill.
feat: null
name: Skilled Heritage
- descr: Humanity’s versatility and ambition have fueled its ascendance to be the
most common ancestry in most nations throughout the world. Select a general feat
of your choice for which you meet the prerequisites (as with your ancestry feat,
you can select this general feat at any point during character creation).
feat: null
name: Versatile Heritage
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,53 @@
import yaml
import sqlite3
def main():
q = "SELECT short_name, description, sources_pages FROM senses"
conn = sqlite3.connect('../../pf2.db')
c = conn.cursor()
c.execute(q)
data = c.fetchall()
datalist = []
for i in data:
# print(i)
print(i[2])
if i[2] != "TODO":
print("We got an int")
d = {
'name': i[0],
'descr': i[1],
'source': {
'abbr': 'CRB',
'page_start': int(i[2]),
'page_stop': int(i[2])
}
}
datalist.append(d)
else:
d = {
'name': i[0],
'descr': i[1],
'source': {
'abbr': 'CRB',
'page_start': 9999999,
'page_stop': 9999999,
'comment': "TODO fix the source page start and stop"
}
}
datalist.append(d)
tmpd = {'senses': datalist}
final = yaml.safe_dump(tmpd, allow_unicode=True)
with open('tmp-senses.yaml', 'w') as f:
f.write(final)
if __name__ == "__main__":
main()
@@ -0,0 +1,37 @@
import sqlite3
import yaml
def main():
q = """
select traits.short_name, traits.description, traittypes.name FROM traits INNER JOIN traittypes ON traits.traittype=traittypes.traittype_id;
"""
q = """
select short_name, description FROM heritages;
"""
conn = sqlite3.connect('../../../pf2.db')
c = conn.cursor()
c.execute(q)
data = c.fetchall()
# transform tuples into list of dicts
datalist = []
for i in data:
print(i)
d = { 'name': i[0], 'descr': i[1], 'feat': None}
datalist.append(d)
# now dump to yaml
final = yaml.safe_dump(datalist, allow_unicode=True)
with open('tmp-heritages.yaml', 'w') as f:
f.write(final)
if __name__ == "__main__":
main()
@@ -0,0 +1,34 @@
import sqlite3
import yaml
def main():
q = """
select traits.short_name, traits.description, traittypes.name FROM traits INNER JOIN traittypes ON traits.traittype=traittypes.traittype_id;
"""
conn = sqlite3.connect('../../pf2.db')
c = conn.cursor()
c.execute(q)
data = c.fetchall()
# transform tuples into list of dicts
datalist = []
for i in data:
print(i)
d = { 'type': i[2], 'name': i[0], 'descr': i[1]}
datalist.append(d)
tmpd = { 'trait': datalist }
# now dump to yaml
final = yaml.safe_dump(tmpd, allow_unicode=True)
with open('tmp-traits.yaml', 'w') as f:
f.write(final)
if __name__ == "__main__":
main()
@@ -0,0 +1,27 @@
import sqlite3
import yaml
def main():
q = """
SELECT is_comty_use, is_specific_to_adv, name, descr, sources_id, sources_pages
FROM backgrounds;
"""
conn = sqlite3.connect('../../pf2.db')
# so we get a dict out of our query
conn.row_factory = sqlite3.Row
c = conn.cursor()
c.execute(q)
# data = c.fetchall()
data = [dict(row) for row in c.fetchall()]
print(data)
final = yaml.safe_dump(data, allow_unicode=True)
with open('tmp-backgrounds.yaml', 'w') as f:
f.write(final)
if __name__ == "__main__":
main()
@@ -0,0 +1,25 @@
import yaml
def main():
with open('monsters.yaml') as m:
data = yaml.full_load(m)
monsterlist = []
for i in data:
if 'ac_special' in i:
monsterlist.append(i)
else:
i['ac_special'] = None
monsterlist.append(i)
finaldata = {'monsters': monsterlist}
final = yaml.safe_dump(finaldata, allow_unicode=True)
with open('tmp-monsters.yaml', 'w') as f:
f.write(final)
if __name__ == "__main__":
main()
@@ -0,0 +1,57 @@
import sqlite3
import yaml
def main():
q = """
SELECT * FROM actions;
"""
conn = sqlite3.connect('../../pf2.db')
# so we get a dict out of our query
conn.row_factory = sqlite3.Row
c = conn.cursor()
c.execute(q)
# data = c.fetchall()
data = [dict(row) for row in c.fetchall()]
# print(data)
for i in data:
del i['actions_id']
page = int(i['sources_pages'])
del i['sources_pages']
i['source'] = [{'abbr': 'CRB', 'page_start': page, 'page_stop': page }]
x = i['actioncategories_id']
if x == 1:
i['actioncategory'] = "Basic"
elif x ==2:
i['actioncategory'] = "Specialty Basic"
del i['actioncategories_id']
y = i['actioncosts_id']
if y == 0:
i['actioncost_name'] = "Varies"
elif y == 1:
i['actioncost_name'] = "Single Action"
elif y == 2:
i['actioncost_name'] = "Two Actions"
elif y == 3:
i['actioncost_name'] = "Three Actions"
elif y == 5:
i['actioncost_name'] = "Free Action"
elif y == 5:
i['actioncost_name'] = "Reaction"
del i['actioncosts_id']
data = {"action": data}
final = yaml.safe_dump(data, allow_unicode=True)
with open('tmp-actions.yaml', 'w') as f:
f.write(final)
if __name__ == "__main__":
main()
@@ -0,0 +1,50 @@
import sqlite3
import yaml
def main():
conn = sqlite3.connect('../../pf2.db')
conn.row_factory = sqlite3.Row
c = conn.cursor()
c.execute("select * from ammunition;")
res = [dict(row) for row in c.fetchall()]
# for i in res:
# print(i)
reslist = []
for i in res:
tmp = {
"name":
i['name'],
"price_gp":
i['price_gp'],
"amount":
i['amount'],
"bulk":
i['bulk'],
"descr":
i['descr'],
"source": [
{
'abbr': 'CRB',
'page_start': int(i['sources_pages']),
'page_stop': int(i['sources_pages'])
},
]
}
reslist.append(tmp)
# print(reslist)
tmpd = {'ammunition': reslist}
# now dump to yaml
final = yaml.safe_dump(tmpd, allow_unicode=True)
with open('tmp-ammo.yaml', 'w') as f:
f.write(final)
if __name__ == '__main__':
main()
@@ -0,0 +1,138 @@
import sqlite3
import yaml
def main():
conn = sqlite3.connect('../../pf2.db')
conn.row_factory = sqlite3.Row
c = conn.cursor()
stmt = """
SELECT ancestries.short_name as name,
flavor_text,
hp,
sizes.short_name AS size,
speed,
senses.short_name AS senses,
ancestries.sources_pages
FROM ancestries
INNER JOIN
sizes ON sizes.size_id = ancestries.size_id
INNER JOIN
senses ON senses.senses_id = ancestries.vision_id;
"""
c.execute(stmt)
res = [dict(row) for row in c.fetchall()]
print(res)
# for i in res:
# if i['hands'] == None or i['hands'] == '':
# i['hands'] = 0
reslist = []
for i in res:
tmp = {
"name": i['name'],
"flavor_text": i['flavor_text'],
"hp": i['hp'],
"size": i['size'],
'speed': i['speed'],
'senses': i['senses'],
"source": [
{
'abbr': 'CRB',
'page_start': int(i['sources_pages']),
'page_stop': int(i['sources_pages'])
},
],
'boosts': None,
'flaws': None,
'traits': None
}
# add in boosts
stmt = """
SELECT abilityscores.short_name
FROM abilityscores
INNER JOIN
ancestries_boosts ON abilityscores.abilityscores_id = ancestries_boosts.abilityscores_id
INNER JOIN
ancestries ON ancestries.ancestry_id = ancestries_boosts.ancestry_id
WHERE ancestries.ancestry_id = (
SELECT ancestries.ancestry_id
WHERE ancestries.short_name = ?
);
"""
c.execute(stmt, (i['name'],))
resboosts = [dict(row) for row in c.fetchall()]
print(resboosts)
if len(resboosts) == 0:
tmp['boosts'] = None
else:
boostslist = []
for j in resboosts:
boostslist.append(j['short_name'])
tmp['boosts'] = boostslist
# add in flaws
stmt = """
SELECT abilityscores.short_name
FROM abilityscores
INNER JOIN
ancestries_flaws ON abilityscores.abilityscores_id = ancestries_flaws.abilityscores_id
INNER JOIN
ancestries ON ancestries.ancestry_id = ancestries_flaws.ancestry_id
WHERE ancestries.ancestry_id = (
SELECT ancestries.ancestry_id
WHERE ancestries.short_name = ?
);
"""
c.execute(stmt, (i['name'],))
resflaws = [dict(row) for row in c.fetchall()]
print(resflaws)
if len(resflaws) == 0:
tmp['flaws'] = None
else:
flawslist = []
for j in resflaws:
flawslist.append(j['short_name'])
tmp['flaws'] = flawslist
# add in traits
stmt = """
SELECT traits.short_name
FROM traits
INNER JOIN
ancestries_traits ON traits.trait_id = ancestries_traits.trait_id
INNER JOIN
ancestries ON ancestries.ancestry_id = ancestries_traits.ancestry_id
WHERE ancestries.ancestry_id = (
SELECT ancestries.ancestry_id
WHERE ancestries.short_name = ?
);
"""
c.execute(stmt, (i['name'],))
restraits = [dict(row) for row in c.fetchall()]
print(restraits)
if len(restraits) == 0:
tmp['traits'] = None
else:
traitslist = []
for j in restraits:
traitslist.append(j['short_name'])
tmp['traits'] = traitslist
reslist.append(tmp)
# # print(reslist)
tmpd = {'ancestries': reslist}
# now dump to yaml
final = yaml.safe_dump(tmpd, allow_unicode=True)
with open('tmp-ancestries.yaml', 'w') as f:
f.write(final)
if __name__ == "__main__":
main()
@@ -0,0 +1,126 @@
import yaml
import sqlite3
def main():
acats = ["Unarmored", "Light Armor", "Medium Armor", "Heavy Armor"]
# DO ARMORGROUP
q = "SELECT short_name, descr FROM armorgroup"
conn = sqlite3.connect('../../pf2.db')
c = conn.cursor()
c.execute(q)
data = c.fetchall()
datalist = []
for i in data:
d = {
'name': i[0],
'descr': i[1],
'source': [{
'abbr': 'CRB',
'page_start': 275,
'page_stop': 275
}]
}
datalist.append(d)
# DO MAIN ARMOR TABLE
qq = """
SELECT
armor.short_name,
item_level,
price_text,
price_gp,
ac_bonus,
dex_cap,
check_penalty,
speed_penalty,
strength,
bulks.short_name AS bulkname,
armorgroup.short_name AS grpname,
armorcategory.short_name AS catname
FROM armor
LEFT JOIN
bulks ON bulks.bulk_id = armor.bulk_id
LEFT JOIN
armorgroup ON armorgroup.grp_id = armor.grp_id
LEFT JOIN
armorcategory ON armorcategory.armor_category_id = armor.armor_category_id;
"""
c.execute(qq)
data2 = c.fetchall()
armorlist = []
for i in data2:
print('\n')
print(i)
t = {
'name': i[0],
'level': i[1],
'price_text': i[2],
'price_gp': i[3],
'ac_bonus': i[4],
'dex_cap': i[5],
'check_penalty': i[6],
'speed_penalty': i[7],
'strength': i[8],
'bulk': i[9],
'group': i[10],
'category': i[11],
'source': [
{
'abbr': 'CRB',
'page_start': 275,
'page_stop': 275
},
]
}
armorlist.append(t)
# datalist = []
# for i in data:
# # print(i)
# print(i[2])
# if i[2] != "TODO":
# print("We got an int")
# d = {
# 'name': i[0],
# 'descr': i[1],
# 'source': {
# 'abbr': 'CRB',
# 'page_start': int(i[2]),
# 'page_stop': int(i[2])
# }
# }
# datalist.append(d)
# else:
# d = {
# 'name': i[0],
# 'descr': i[1],
# 'source': {
# 'abbr': 'CRB',
# 'page_start': 9999999,
# 'page_stop': 9999999,
# 'comment': "TODO fix the source page start and stop"
# }
# }
# datalist.append(d)
print(armorlist)
tmpd = {'armorcategory': acats, 'armorgroup': datalist, 'armor': armorlist}
final = yaml.safe_dump(tmpd, allow_unicode=True)
with open('tmp-armor.yaml', 'w') as f:
f.write(final)
if __name__ == "__main__":
main()
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,52 @@
import sqlite3
import yaml
def main():
conn = sqlite3.connect('../../pf2.db')
conn.row_factory = sqlite3.Row
c = conn.cursor()
c.execute("select * from gear;")
res = [dict(row) for row in c.fetchall()]
for i in res:
if i['hands'] == None or i['hands'] == '':
i['hands'] = 0
reslist = []
for i in res:
if i['descr'] == '':
i['descr'] = None
tmp = {
"name": i['name'],
'level': int(i['level']),
"price_gp": i['price'],
"bulk": i['bulk'],
"descr": i['descr'],
'hands': int(i['hands']),
"source": [
{
'abbr': 'CRB',
'page_start': int(i['sources_pages']),
'page_stop': int(i['sources_pages'])
},
],
"traits": None
}
reslist.append(tmp)
# print(reslist)
tmpd = {'gear': reslist}
# now dump to yaml
final = yaml.safe_dump(tmpd, allow_unicode=True)
with open('tmp-gear.yaml', 'w') as f:
f.write(final)
# NOTE the 4 traits were added by hand manually to the final tmp-gear.yaml and not via this script
if __name__ == '__main__':
main()
@@ -0,0 +1,160 @@
import json
import yaml
def main():
with open(
'../third_party_json/spells20191115.json',
encoding='utf-8-sig') as f:
data = json.load(f)
# print(data)
for i in data:
if 'manual' in i:
del i['manual']
i['has_been_manually_proofread'] = False
if 'duration' not in i:
i['duration'] = None
# Fix components
if 'components' not in i:
i['components'] = None
else:
if i['components'] == ['1minute(material', 'somatic', 'verbal)']:
i['components'] = ['material', 'somatic', 'verbal']
if i['components'] == ['10minutes(material', 'somatic', 'verbal)']:
i['components'] = ['material', 'somatic', 'verbal']
if i['components'] == ['1hour(material', 'somatic', 'verbal)']:
i['components'] = ['material', 'somatic', 'verbal']
if i['components'] == ['1minute','material', 'somatic', 'verbal)']:
i['components'] = ['material', 'somatic', 'verbal']
if i['components'] == ['10minutes(somatic', 'verbal)']:
i['components'] = ['somatic', 'verbal']
if i['components'] == ['1minute(somatic', 'verbal)']:
i['components'] = ['somatic', 'verbal']
if i['components'] == ['1hour(somatic', 'verbal)']:
i['components'] = ['somatic', 'verbal']
for j, item in enumerate(i['components']):
if i['components'][j] == "somatic":
i['components'][j] = "Somatic"
if i['components'][j] == "material":
i['components'][j] = "Material"
if i['components'][j] == "verbal":
i['components'][j] = "Verbal"
if i['components'][j] == "focus":
i['components'][j] = "Focus"
if 'cast' not in i:
i['cast'] = None
if 'action' not in i:
i['action'] = None
i['action_abbr'] = i['action']
del i['action']
if i['action_abbr'] == "10 minutes":
i['action_abbr'] = "10m"
if i['action_abbr'] == "1 minute":
i['action_abbr'] = "1m"
if i['action_abbr'] == "1 hour":
i['action_abbr'] = "1h"
if 'traditions' not in i:
i['traditions'] = None
if i['traditions'] != None:
for j, item in enumerate(i['traditions']):
i['traditions'][j] = i['traditions'][j].capitalize()
if 'nethysUrl' in i:
del i['nethysUrl']
# print("spell:{}\n\tcast:{}\n\tcomponents:{}\n\taction:{}".format(i['name'], i['cast'], i['components'],i['action']))
# Fix source data
x = i['source']
if "Core Rulebook" in x:
tmp_abbr = "CRB"
elif "Lost Omens" in x:
tmp_abbr = "LOWG"
else:
raise Exception(
'something went wrong on sources in 3pp json data.')
res = [int(i) for i in x.split() if i.isdigit()]
# print("source line:{}\tres:{}".format(i['source'], res))
tmp_page_start = res[0]
tmp_page_stop = res[0]
i['source'] = [{
'abbr': tmp_abbr,
'page_start': tmp_page_start,
'page_stop': tmp_page_stop
}]
# description to descr
i['descr'] = i['description']
del i['description']
# Fix action cost
# fix requirements
if 'requirements' not in i:
i['req'] = None
else:
i['req'] = i['requirements']
del i['requirements']
if 'trigger' not in i:
i['trigger'] = None
if 'traits' not in i:
i['traits'] = None
else:
for idx, item in enumerate(i['traits']):
i['traits'][idx] = i['traits'][idx].capitalize()
# TODO Decide to keep targets or target
if 'targets' not in i:
i['targets'] = None
# for i in data:
# del i['actions_id']
# page = int(i['sources_pages'])
# del i['sources_pages']
# i['source'] = [{'abbr': 'CRB', 'page_start': page, 'page_stop': page }]
# x = i['actioncategories_id']
# if x == 1:
# i['actioncategory'] = "Basic"
# elif x ==2:
# i['actioncategory'] = "Specialty Basic"
# del i['actioncategories_id']
# y = i['actioncosts_id']
# if y == 0:
# i['actioncost_name'] = "Varies"
# elif y == 1:
# i['actioncost_name'] = "Single Action"
# elif y == 2:
# i['actioncost_name'] = "Two Actions"
# elif y == 3:
# i['actioncost_name'] = "Three Actions"
# elif y == 5:
# i['actioncost_name'] = "Free Action"
# elif y == 5:
# i['actioncost_name'] = "Reaction"
# del i['actioncosts_id']
data = {"spell": data}
final = yaml.safe_dump(data, allow_unicode=True, width=100000)
with open('tmp-spells.yaml', 'w') as f:
f.write(final)
if __name__ == "__main__":
main()
@@ -0,0 +1,131 @@
import sqlite3
import yaml
import pprint
def main():
pp = pprint.PrettyPrinter(indent=1, width=180)
conn = sqlite3.connect('../deprecated/pf2.db')
conn.row_factory = sqlite3.Row
q = """
SELECT * FROM staff;
"""
c = conn.cursor()
c.execute(q)
data = [dict(row) for row in c.fetchall()]
for i in data:
# ADD THE ITEM CATEGORY
i['itemcategory'] = "Staves"
# convert gp prices to cp prices to avoid float issues
if i['price'] == '':
i['price'] = '0'
i['price_cp'] = int(float(i['price']) * 100)
del i['price']
# make bulk a string
i['bulk'] = str(i['bulk'])
# handle source entries
i['source'] = [
{
'abbr': 'CRB',
'page_start': int(i['source_pages']),
'page_stop': int(i['source_pages'])
}
]
del i['source_id']
del i['source_pages']
# Get staffactivations and effects
qq = """
SELECT activation, effect FROM staffactivations
INNER JOIN
staff_staffactivations ON
staffactivations.staffactivations_id = staff_staffactivations.staffactivations_id
INNER JOIN
staff ON staff.staff_id = staff_staffactivations.staff_id
WHERE staff.staff_id = ?;
"""
# Get staffactivations
cc = conn.cursor()
cc.execute(qq, (i['staff_id'],))
res = cc.fetchall()
# print("\n\nStaff: {}".format(i['name']))
slist = []
for j in res:
x = tuple(j)[0]
y = tuple(j)[1]
xy = {'activation': x, 'effect': y}
slist.append(xy)
if len(slist) > 0:
i['staffactivations'] = slist
else:
i['staffactivations'] = None
# Get traits
qq = """
SELECT traits.short_name
FROM traits
INNER JOIN
staff_trait ON traits.trait_id = staff_trait.trait_id
INNER JOIN
staff ON staff.staff_id = staff_trait.staff_id
WHERE staff.staff_id = ?;
"""
cc = conn.cursor()
cc.execute(qq, (i['staff_id'],))
res = cc.fetchall()
# print("\n\nWeapon: {}".format(i['name']))
tlist = []
for j in res:
x = tuple(j)[0]
tlist.append(x)
if len(tlist) > 0:
i['traits'] = tlist
else:
i['traits'] = None
# Get staff spells
qq = """
SELECT spells.name, staff_spell.level
FROM spells
INNER JOIN
staff_spell ON staff_spell.spell_id = spells.spells_id
INNER JOIN
staff ON staff_spell.staff_id = staff.staff_id
WHERE staff.staff_id = ?;
"""
cc = conn.cursor()
cc.execute(qq, (i['staff_id'],))
res = cc.fetchall()
# print("\n\nStaff: {}".format(i['name']))
slist = []
for j in res:
x = tuple(j)[0]
y = tuple(j)[1]
xy = {'name': x, 'level': y}
slist.append(xy)
if len(slist) > 0:
i['staffspells'] = slist
else:
i['staffspells'] = None
# DO THIS LAST
del i['staff_id']
# pp.pprint(data)
fdata = {'staves': data}
final = yaml.safe_dump(fdata, allow_unicode=True)
with open('tmp--items-staves.yaml', 'w') as f:
f.write(final)
for i in data:
print("Staff Name: {}\tPrice (copper): {}".format(i['name'], i['price_cp']))
if __name__ == '__main__':
main()
@@ -0,0 +1,143 @@
import sqlite3
import yaml
import pprint
def main():
pp = pprint.PrettyPrinter(indent=4, width=160)
conn = sqlite3.connect('../../pf2.db')
conn.row_factory = sqlite3.Row
# DO WEAPONS
q = """
SELECT
price_gp,
dice_size,
bulk,
hands,
range,
reload,
weapons.name,
weapons.descr,
weapons.sources_id,
weapons.sources_pages,
weaponcategories.name AS weaponcategory,
weapongroups.name AS weapongroup,
damagetypes.name AS damagetype
FROM weapons
INNER JOIN
weaponcategories ON weapons.weaponcategories_id = weaponcategories.weaponcategories_id
INNER JOIN
weapongroups ON weapons.weapongroups_id = weapongroups.weapongroups_id
INNER JOIN
damagetypes ON weapons.damagetypes_id = damagetypes.damagetypes_id
;
"""
c = conn.cursor()
c.execute(q)
data = [dict(row) for row in c.fetchall()]
for i in data:
# handle empty bulk entries to match the abbr field in bulks.yaml
if i['bulk'] == '':
i['bulk'] = '-'
# convert gp prices to cp prices to avoid float issues
if i['price_gp'] == '':
i['price_gp'] = '0'
i['price_cp'] = int(float(i['price_gp']) * 100)
del i['price_gp']
i['source'] = [
{
'abbr': 'CRB',
'page_start': int(i['sources_pages']),
'page_stop': int(i['sources_pages'])
}
]
del i['sources_id']
del i['sources_pages']
# Get traits
qq = """
SELECT traits.short_name
FROM traits
INNER JOIN
weapons_traits ON traits.trait_id = weapons_traits.trait_id
INNER JOIN
weapons ON weapons.weapons_id = weapons_traits.weapons_id
WHERE weapons.weapons_id = (
SELECT weapons.weapons_id
WHERE weapons.name = ?
);
"""
cc = conn.cursor()
cc.execute(qq, (i['name'],))
res = cc.fetchall()
print("\n\nWeapon: {}".format(i['name']))
tlist = []
for j in res:
x = tuple(j)[0]
tlist.append(x)
if len(tlist) > 0:
i['traits'] = tlist
else:
i['traits'] = None
# pp.pprint(data)
fdata = {'weapons': data}
final = yaml.safe_dump(fdata, allow_unicode=True)
with open('tmp-weapons.yaml', 'w') as f:
f.write(final)
if __name__ == '__main__':
main()
# def done():
# DO WEAPON GROUPS
# q = """
# SELECT
# sources_pages,
# name,
# descr
# FROM weapongroups
# """
# c = conn.cursor()
# c.execute(q)
# data = [dict(row) for row in c.fetchall()]
# pp.pprint(data)
# # "source": [
# # {
# # 'abbr': 'CRB',
# # 'page_start': int(i['sources_pages']),
# # 'page_stop': int(i['sources_pages'])
# # },
# wgdata = []
# for i in data:
# res = {
# 'name': i['name'],
# 'descr': i['descr'],
# 'source': [
# {
# 'abbr': 'CRB',
# 'page_start': int(i['sources_pages']),
# 'page_stop': int(i['sources_pages'])
# }
# ]
# }
# wgdata.append(res)
# pp.pprint(wgdata)
# finalwgdata = {'weapongroups': wgdata}
# pp.pprint(finalwgdata)
# final = yaml.safe_dump(finalwgdata, allow_unicode=True)
# with open('tmp-weapongroups.yaml', 'w') as f:
# f.write(final)
@@ -0,0 +1,209 @@
import sqlite3
import yaml
import pprint
def main():
conn = sqlite3.connect('../../pf2.db')
conn.row_factory = sqlite3.Row
q = """
SELECT * FROM feats;
"""
# so we get a dict out of our query
c = conn.cursor()
c.execute(q)
# data = c.fetchall()
data = [dict(row) for row in c.fetchall()]
# pprint.pprint(data)
q = """
SELECT * FROM requirements;
"""
# so we get a dict out of our query
c = conn.cursor()
c.execute(q)
# data = c.fetchall()
req_data = [dict(row) for row in c.fetchall()]
# pprint.pprint(req_data)
q = """
SELECT * FROM actioncosts;
"""
# so we get a dict out of our query
c = conn.cursor()
c.execute(q)
# data = c.fetchall()
act_data = [dict(row) for row in c.fetchall()]
# pprint.pprint(act_data)
q = """
SELECT * FROM frequency;
"""
# so we get a dict out of our query
c = conn.cursor()
c.execute(q)
# data = c.fetchall()
freq_data = [dict(row) for row in c.fetchall()]
# pprint.pprint(freq_data)
q = """
SELECT * FROM triggers;
"""
# so we get a dict out of our query
c = conn.cursor()
c.execute(q)
# data = c.fetchall()
trig_data = [dict(row) for row in c.fetchall()]
# pprint.pprint(trig_data)
q = """
SELECT featprereqs_id, descr, feat_id FROM featprereqs;
"""
# so we get a dict out of our query
c = conn.cursor()
c.execute(q)
# data = c.fetchall()
prdata = [dict(row) for row in c.fetchall()]
# pprint.pprint(prdata)
for i in prdata:
if i['feat_id'] != None:
q = """
SELECT short_name from feats WHERE feat_id=?;
"""
# so we get a dict out of our query
c = conn.cursor()
c.execute(q, (i['feat_id'],))
# data = c.fetchall()
subprdata = [dict(row) for row in c.fetchall()]
# pprint.pprint(subprdata)
i['feat'] = subprdata[0]['short_name']
else:
i['feat'] = None
for i in data:
# all this mess is getting the sources
x = i['sources_pages'].split(',')
# if len(x) > 1:
# print("name:{}, x:{}".format(i['short_name'], x))
s = []
for j in x:
page = int(j)
s.append({'abbr': 'CRB', 'page_start': page, 'page_stop': page })
i['source'] = s
del i['sources_pages']
# now get the actions
if i['action_id'] == None:
i['action'] = None
else:
# get action name based on id
id = i['action_id']
for a in act_data:
if a['actioncosts_id'] == id:
i['action'] = a['name']
del i['action_id']
# now do the triggers
if i['triggers_id'] == None:
i['trigger'] = None
else:
# get trigger name based on id
id = i['triggers_id']
for t in trig_data:
if t['triggers_id'] == id:
i['trigger'] = t['triggers_descr']
del i['triggers_id']
# now do the requirements
if i['requirements_id'] == None:
i['requirement'] = None
else:
# get requirement name based on id
id = i['requirements_id']
for r in req_data:
if r['requirements_id'] == id:
i['requirement'] = r['requirements_descr']
del i['requirements_id']
# now do the frequency
if i['frequency_id'] == None:
i['frequency'] = None
else:
# get requirement name based on id
id = i['frequency_id']
# print(id)
# print(i['short_name'])
for f in freq_data:
if f['freq_id'] == id:
i['frequency'] = f['freq_descr']
del i['frequency_id']
# populate prereqs:
### get prereq IDs for a feat
stmt = "SELECT featprereqs_id FROM feats_featprereqs WHERE feat_id=?"
c = conn.cursor()
# print(i['feat_id'])
c.execute(stmt, (i['feat_id'],))
# data = c.fetchall()
fpr_data = [dict(row) for row in c.fetchall()]
# if len(fpr_data) > 1:
# # print("fuck")
# pprint.pprint(fpr_data)
# print(fpr_data)
for f in fpr_data:
stmtnext = "SELECT descr, feat_id FROM featprereqs WHERE featprereqs_id=?"
c = conn.cursor()
# print(i['feat_id'])
c.execute(stmtnext, (f['featprereqs_id'],))
# data = c.fetchall()
fpr_data_next = [dict(row) for row in c.fetchall()]
# print(fpr_data_next)
prlist = []
for ff in fpr_data_next:
# print(ff)
if ff['feat_id'] == None:
prlist.append({'descr': ff['descr'], 'feat': None})
else:
stmtfinal = "SELECT short_name from feats WHERE feat_id=?"
c = conn.cursor()
# print(i['feat_id'])
c.execute(stmtfinal, (ff['feat_id'],))
# data = c.fetchall()
fn_data_final = [dict(row) for row in c.fetchall()]
# print("STUFF")
# print(fn_data_final)
prlist.append({'descr': ff['descr'], 'feat': fn_data_final[0]['short_name']})
i['prereqs'] = prlist
# Add in traits
tt = "SELECT feats_traits.trait_id AS trait_id, traits.short_name AS name FROM feats_traits LEFT JOIN traits ON feats_traits.trait_id = traits.trait_id WHERE feats_traits.feat_id=?"
c = conn.cursor()
# print(i['feat_id'])
c.execute(tt, (i['feat_id'],))
# data = c.fetchall()
trait_data = [dict(row) for row in c.fetchall()]
# print("short_name: {}\ttraits: {}".format(i['short_name'], trait_data))
trait_list = []
for item in trait_data:
trait_list.append(item['name'])
# print(trait_list)
if len(trait_list) < 1:
i['traits'] = None
else:
i['traits'] = trait_list
# THIS NEEDS TO BE LAST AS PREREQS REFERENCES IT
del i['feat_id']
i['has_been_manually_proofread'] = False
data = {"feat": data}
final = yaml.safe_dump(data, allow_unicode=True, width=10000)
with open('tmp-feat.yaml', 'w') as f:
f.write(final)
if __name__ == "__main__":
main()