From 5ffd104c6ca2c350614bb3e228f723441013d6f6 Mon Sep 17 00:00:00 2001 From: James Miller Date: Tue, 21 Apr 2020 17:30:07 -0500 Subject: [PATCH 1/9] working on feats --- data/yaml/feats.yaml | 6 +- data/yaml/requirements.yaml | 1 + gendb/gendb.py | 115 +++++++++++++++++++++++++++++++++--- 3 files changed, 111 insertions(+), 11 deletions(-) diff --git a/data/yaml/feats.yaml b/data/yaml/feats.yaml index d861bab..8ed3011 100644 --- a/data/yaml/feats.yaml +++ b/data/yaml/feats.yaml @@ -1906,7 +1906,7 @@ feat: descr: Given time to collect yourself after a near-death scrape, you can rebuild your ferocity and withstand additional finishing blows. You can use Orc Ferocity with a frequency of once per hour, rather than once per day. - frequency: null + frequency: once per hour has_been_manually_proofread: false level: 13 name: Incredible Ferocity @@ -3138,7 +3138,7 @@ feat: prereqs: - descr: 'Feature: dragon instinct' feat: null - requirement: You haven’t used this ability since you last Raged. + requirement: You haven't used this ability since you last Raged. source: - abbr: CRB page_start: 90 @@ -3605,7 +3605,7 @@ feat: prereqs: - descr: 'Come And Get Me' feat: Come and Get Me - requirement: You’re under the effect of Come and Get Me. + requirement: You're under the effect of Come and Get Me. source: - abbr: CRB page_start: 93 diff --git a/data/yaml/requirements.yaml b/data/yaml/requirements.yaml index 6bcba3f..e23b043 100644 --- a/data/yaml/requirements.yaml +++ b/data/yaml/requirements.yaml @@ -75,3 +75,4 @@ requirement: - You have an unexpended spell slot you could use to cast the triggered spell. - Your most recent action was to cast a non-cantrip spell. - The last action you used was Drain Bonded Item. +- You have a focus pool, and you have spent at least 1 Focus Point since you last regained any Focus Points. diff --git a/gendb/gendb.py b/gendb/gendb.py index 6d50860..58e555e 100644 --- a/gendb/gendb.py +++ b/gendb/gendb.py @@ -124,6 +124,10 @@ def main(): data = yaml.full_load(yl) do_gear(data, conn) + with open('feats.yaml') as yl: + data = yaml.full_load(yl) + do_feats(data, conn) + with open('ancestriesheritages.yaml') as yl: data = yaml.full_load(yl) do_ancestries(data, conn) @@ -132,6 +136,101 @@ def main(): data = yaml.full_load(yl) do_heritages(data, conn) +def do_feats(data, conn): + + table = """ + CREATE TABLE feat ( + feat_id INTEGER PRIMARY KEY, + actioncost_id INTEGER, + descr TEXT NOT NULL, + freq_id INTEGER, + level INTEGER NOT NULL, + name TEXT NOT NULL UNIQUE, + requirement_id INTEGER, + trigger_id INTEGER, + FOREIGN KEY (actioncost_id) REFERENCES actioncost(actioncost_id), + FOREIGN KEY (freq_id) REFERENCES frequency(freq_id), + FOREIGN KEY (requirement_id) REFERENCES requirement(requirement_id), + FOREIGN KEY (trigger_id) REFERENCES trigger(trigger_id) + ); + """ + c = conn.cursor() + c.execute(table) + + + feat_result_list = [] + for i in data['feat']: + if i['actioncost'] == None: + ac_id = None + else: + ac_id = get_actioncost_id_by_name(i['actioncost'], conn) + # print("ac_id for {} is {}".format(i['actioncost'], ac_id)) + if i['frequency'] == None: + f_id = None + else: + f_id = get_freq_id_by_descr(i['frequency'], conn) + # print("f_id for {} is {}".format(i['frequency'], f_id)) + if i['requirement'] == None: + r_id = None + else: + r_id = get_requirement_id_by_descr(i['requirement'], conn) + # print("f_id for {} is {}".format(i['frequency'], f_id)) + + # res = (ac_id, i['descr'], f_id, i['level'], i['name'], r_id, t_id) + + + + insert_stmt = "INSERT INTO feat (actioncost_id, descr, freq_id, level, name, requirement_id, trigger_id) VALUES (?,?,?,?,?,?,?);" + +def get_requirement_id_by_descr(r, conn): + qstmt = "SELECT requirement_id FROM requirement WHERE descr=?;" + try: + c = conn.cursor() + c.execute(qstmt, (r,)) + except sqlite3.Error as e: + print("Error getting an requirement_id by name: {} Error: {}".format(r, e)) + except: + print("Error getting an requirement_id_by_name something other than sqlite3 error") + else: + x = c.fetchone() + if x == None: + raise AssertionError('there was no requirement_id for given requirement name: {}\nYou should check to see if this requirement is in requirements.yaml and sometimes it is a straight apostrophe versus uni-code curly apostrophe.'.format(r)) + else: + return x[0] + +def get_freq_id_by_descr(f, conn): + qstmt = "SELECT freq_id FROM frequency WHERE freq_descr=?;" + try: + c = conn.cursor() + c.execute(qstmt, (f,)) + except sqlite3.Error as e: + print("Error getting an freq_id_id by name: {} Error: {}".format(f, e)) + except: + print("Error getting an freq_id_id_by_name something other than sqlite3 error") + else: + x = c.fetchone() + if x == None: + raise AssertionError('there was no freq_id_id for given freq_id name: {}'.format(f)) + else: + return x[0] + +def get_actioncost_id_by_name(ac, conn): + qstmt = "SELECT actioncost_id FROM actioncost WHERE name=?;" + try: + c = conn.cursor() + c.execute(qstmt, (ac,)) + except sqlite3.Error as e: + print("Error getting an actioncost_id by name: {} Error: {}".format(ac, e)) + except: + print("Error getting an actioncost_id_by_name something other than sqlite3 error") + else: + x = c.fetchone() + if x == None: + raise AssertionError('there was no actioncost_id for given actioncost name: {}'.format(ac)) + else: + return x[0] + + def do_heritages(data, conn): table = """ CREATE TABLE heritages ( @@ -153,7 +252,7 @@ def do_heritages(data, conn): rowid = c.fetchone() #FOR EACH HERITAGE, INSERT INTO TABLE USING ANCESTRY ID for j in i['heritages']: - print("doing this heritage: {}".format(j['name'])) + # print("doing this heritage: {}".format(j['name'])) stmt = "INSERT INTO heritages (name, descr, ancestry_id) VALUES (?,?,?);" c.execute(stmt, (j['name'], j['descr'], rowid[0])) conn.commit() @@ -226,7 +325,7 @@ def do_ancestries(data, conn): sinp_data = (i['size'], ) sres = c.execute(sstmt, sinp_data).fetchall() sid = sres[0][0] - print(sid) + # print(sid) # Get the vision_id vstmt = """ @@ -234,12 +333,12 @@ def do_ancestries(data, conn): """ vinp_data = (i['senses'], ) vres = c.execute(vstmt, vinp_data).fetchall() - print(vres) + # print(vres) if len(vres) > 0: vid = vres[0][0] else: vid = None - print(vid) + # print(vid) #print(i) inp_data.append( @@ -261,7 +360,7 @@ def do_ancestries(data, conn): if i['boosts'] != None: for j in i['boosts']: boostlist.append((i['name'], j)) - print("boostlist is:\t{}".format(boostlist)) + # print("boostlist is:\t{}".format(boostlist)) stmt = """ INSERT INTO ancestries_boosts (ancestry_id, abilityscore_id) VALUES ( @@ -286,7 +385,7 @@ def do_ancestries(data, conn): if i['flaws'] != None: for j in i['flaws']: flawlist.append((i['name'], j)) - print("flawlist is:\t{}".format(flawlist)) + # print("flawlist is:\t{}".format(flawlist)) stmt = """ INSERT INTO ancestries_flaws (ancestry_id, abilityscore_id) VALUES ( @@ -311,7 +410,7 @@ def do_ancestries(data, conn): if i['traits'] != None: for j in i['traits']: traitlist.append((i['name'], j)) - print("traitlist is:\t{}".format(traitlist)) + # print("traitlist is:\t{}".format(traitlist)) stmt = """ INSERT INTO ancestries_traits (ancestry_id, trait_id) VALUES ( @@ -605,7 +704,7 @@ def do_armor(data, conn): # insert basics into armorcategory table inp_data = [] for i in data['armorcategory']: - print(i) + # print(i) inp_data.append((i, )) stmt = "INSERT INTO armorcategory(name) VALUES (?)" From 7343aed690b483de1506da79db7c2dff2582290c Mon Sep 17 00:00:00 2001 From: James Miller Date: Tue, 21 Apr 2020 17:45:16 -0500 Subject: [PATCH 2/9] updating cleanyaml and cleaning up feats and requirements --- data/yaml/cleanyaml.py | 6 + data/yaml/feats.yaml | 424 ++++++++++++++++++------------------ data/yaml/requirements.yaml | 3 +- 3 files changed, 220 insertions(+), 213 deletions(-) diff --git a/data/yaml/cleanyaml.py b/data/yaml/cleanyaml.py index 8500952..16073df 100644 --- a/data/yaml/cleanyaml.py +++ b/data/yaml/cleanyaml.py @@ -17,6 +17,12 @@ def main(): print("Doing: {}".format(x)) with open(x, 'r') as r: data = yaml.full_load(r) + if x == "feats.yaml": + for i in data['feat']: + if i['requirement'] != None: + print("Before: {}".format(i['requirement'])) + i['requirement'] = i['requirement'].replace('’', "'") + print("After: {}".format(i['requirement'])) final = yaml.safe_dump(data, allow_unicode=True) with open(x, 'w') as f: f.write(final) diff --git a/data/yaml/feats.yaml b/data/yaml/feats.yaml index 8ed3011..3effb0a 100644 --- a/data/yaml/feats.yaml +++ b/data/yaml/feats.yaml @@ -41,7 +41,7 @@ feat: page_stop: 35 traits: null trigger: - - "You attempt a saving throw against a magical effect, but you haven't rolled yet." + - You attempt a saving throw against a magical effect, but you haven't rolled yet. - actioncost: null descr: You eagerly absorbed the old stories and traditions of your ancestors, your gods, and your people, studying in subjects and techniques passed down for generation @@ -205,7 +205,7 @@ feat: level: 5 name: Boulder Roll prereqs: - - descr: 'Rock Runner' + - descr: Rock Runner feat: Rock Runner requirement: null source: @@ -224,7 +224,7 @@ feat: level: 5 name: Dwarven Weapon Cunning prereqs: - - descr: 'Dwarven Weapon Familiarity' + - descr: Dwarven Weapon Familiarity feat: Dwarven Weapon Familiarity requirement: null source: @@ -292,7 +292,7 @@ feat: level: 13 name: Dwarven Weapon Expertise prereqs: - - descr: 'Dwarven Weapon Familiarity' + - descr: Dwarven Weapon Familiarity feat: Dwarven Weapon Familiarity requirement: null source: @@ -480,7 +480,7 @@ feat: level: 5 name: Elven Weapon Elegance prereqs: - - descr: 'Elven Weapon Familiarity' + - descr: Elven Weapon Familiarity feat: Elven Weapon Familiarity requirement: null source: @@ -522,7 +522,7 @@ feat: level: 9 name: Expert Longevity prereqs: - - descr: 'Ancestral Longevity' + - descr: Ancestral Longevity feat: Ancestral Longevity requirement: null source: @@ -542,7 +542,7 @@ feat: level: 13 name: Universal Longevity prereqs: - - descr: 'Expert Longevity' + - descr: Expert Longevity feat: Expert Longevity requirement: null source: @@ -563,7 +563,7 @@ feat: level: 13 name: Elven Weapon Expertise prereqs: - - descr: 'Elven Weapon Familiarity' + - descr: Elven Weapon Familiarity feat: Elven Weapon Familiarity requirement: null source: @@ -726,7 +726,7 @@ feat: level: 5 name: Animal Elocutionist prereqs: - - descr: 'Burrow Elocutionist' + - descr: Burrow Elocutionist feat: Burrow Elocutionist requirement: null source: @@ -764,7 +764,7 @@ feat: level: 5 name: Gnome Weapon Innovator prereqs: - - descr: 'Gnome Weapon Familiarity' + - descr: Gnome Weapon Familiarity feat: Gnome Weapon Familiarity requirement: null source: @@ -823,7 +823,7 @@ feat: level: 13 name: Gnome Weapon Expertise prereqs: - - descr: 'Gnome Weapon Familiarity' + - descr: Gnome Weapon Familiarity feat: Gnome Weapon Familiarity requirement: null source: @@ -1031,7 +1031,7 @@ feat: level: 5 name: Goblin Weapon Frenzy prereqs: - - descr: 'Goblin Weapon Familiarity' + - descr: Goblin Weapon Familiarity feat: Goblin Weapon Familiarity requirement: null source: @@ -1068,7 +1068,7 @@ feat: level: 9 name: Skittering Scuttle prereqs: - - descr: 'Goblin Scuttle' + - descr: Goblin Scuttle feat: Goblin Scuttle requirement: null source: @@ -1088,7 +1088,7 @@ feat: level: 13 name: Goblin Weapon Expertise prereqs: - - descr: 'Goblin Weapon Familiarity' + - descr: Goblin Weapon Familiarity feat: Goblin Weapon Familiarity requirement: null source: @@ -1105,7 +1105,7 @@ feat: has_been_manually_proofread: false name: Very, Very Sneaky prereqs: - - descr: 'Very Sneaky' + - descr: Very Sneaky feat: Very Sneaky requirement: null source: @@ -1319,7 +1319,7 @@ feat: level: 5 name: Halfling Weapon Trickster prereqs: - - descr: 'Halfling Weapon Familiarity' + - descr: Halfling Weapon Familiarity feat: Halfling Weapon Familiarity requirement: null source: @@ -1339,7 +1339,7 @@ feat: level: 9 name: Guiding Luck prereqs: - - descr: 'Halfling Luck' + - descr: Halfling Luck feat: Halfling Luck requirement: null source: @@ -1380,7 +1380,7 @@ feat: level: 13 name: Ceaseless Shadows prereqs: - - descr: 'Distracting Shadows' + - descr: Distracting Shadows feat: Distracting Shadows requirement: null source: @@ -1401,7 +1401,7 @@ feat: level: 13 name: Halfling Weapon Expertise prereqs: - - descr: 'Halfling Weapon Familiarity' + - descr: Halfling Weapon Familiarity feat: Halfling Weapon Familiarity requirement: null source: @@ -1612,7 +1612,7 @@ feat: has_been_manually_proofread: false name: Cooperataive Soul prereqs: - - descr: 'Cooperative Nature' + - descr: Cooperative Nature feat: Cooperative Nature requirement: null source: @@ -1630,7 +1630,7 @@ feat: level: 9 name: Incredible Improvisation prereqs: - - descr: 'Clever Improviser' + - descr: Clever Improviser feat: Clever Improviser requirement: null source: @@ -1854,7 +1854,7 @@ feat: level: 5 name: Orc Weapon Carnage prereqs: - - descr: 'Orc Weapon Famailiarity' + - descr: Orc Weapon Famailiarity feat: Orc Weapon Famailiarity requirement: null source: @@ -1892,7 +1892,7 @@ feat: level: 9 name: Pervasive Superstition prereqs: - - descr: 'Orc Superstition' + - descr: Orc Superstition feat: Orc Superstition requirement: null source: @@ -1911,7 +1911,7 @@ feat: level: 13 name: Incredible Ferocity prereqs: - - descr: 'Orc Ferocity' + - descr: Orc Ferocity feat: Orc Ferocity requirement: null source: @@ -1931,7 +1931,7 @@ feat: level: 13 name: Orc Weapon Expertise prereqs: - - descr: 'Orc Weapon Famailiarity' + - descr: Orc Weapon Famailiarity feat: Orc Weapon Famailiarity requirement: null source: @@ -2323,7 +2323,7 @@ feat: level: 10 name: Expanded Splash prereqs: - - descr: 'Calculated Splash' + - descr: Calculated Splash feat: Calculated Splash requirement: null source: @@ -2343,7 +2343,7 @@ feat: level: 10 name: Greater Debilitating Bomb prereqs: - - descr: 'Debilitating Bomb' + - descr: Debilitating Bomb feat: Debilitating Bomb requirement: null source: @@ -2383,7 +2383,7 @@ feat: level: 10 name: Potent Poisoner prereqs: - - descr: 'Powerful Alchemy' + - descr: Powerful Alchemy feat: Powerful Alchemy requirement: null source: @@ -2443,7 +2443,7 @@ feat: level: 12 name: Uncanny Bombs prereqs: - - descr: 'Far Lobber' + - descr: Far Lobber feat: Far Lobber requirement: null source: @@ -2485,7 +2485,7 @@ feat: level: 14 name: Greater Merciful Elixir prereqs: - - descr: 'Merciful Elixir' + - descr: Merciful Elixir feat: Merciful Elixir requirement: null source: @@ -2507,7 +2507,7 @@ feat: level: 14 name: True Debilitating Bomb prereqs: - - descr: 'Greater Debilitating Bomb' + - descr: Greater Debilitating Bomb feat: Greater Debilitating Bomb requirement: null source: @@ -2529,7 +2529,7 @@ feat: level: 16 name: Eternal Elixir prereqs: - - descr: 'Extend Elixir' + - descr: Extend Elixir feat: Extend Elixir requirement: null source: @@ -2593,7 +2593,7 @@ feat: level: 16 name: Persistent Mutagen prereqs: - - descr: 'Extend Elixir' + - descr: Extend Elixir feat: Extend Elixir requirement: null source: @@ -2721,7 +2721,7 @@ feat: level: 20 name: Mega Bomb prereqs: - - descr: 'Expanded Splash' + - descr: Expanded Splash feat: Expanded Splash requirement: You are holding an infused alchemical bomb you crafted, with a level at least 3 lower than your advanced alchemy level. @@ -3380,7 +3380,7 @@ feat: level: 10 name: Great Cleave prereqs: - - descr: 'Cleave' + - descr: Cleave feat: Cleave requirement: null source: @@ -3420,7 +3420,7 @@ feat: level: 10 name: Terrifying Howl prereqs: - - descr: 'Intimidating Glare' + - descr: Intimidating Glare feat: Intimidating Glare requirement: null source: @@ -3538,7 +3538,7 @@ feat: has_been_manually_proofread: false name: Titan’s Stature prereqs: - - descr: 'Giants Stature' + - descr: Giants Stature feat: Giant’s Stature requirement: null source: @@ -3560,7 +3560,7 @@ feat: level: 14 name: Awesome Blow prereqs: - - descr: 'Knockdown' + - descr: Knockdown feat: Knockback requirement: null source: @@ -3603,7 +3603,7 @@ feat: level: 14 name: Vengeful Strike prereqs: - - descr: 'Come And Get Me' + - descr: Come And Get Me feat: Come and Get Me requirement: You're under the effect of Come and Get Me. source: @@ -3646,7 +3646,7 @@ feat: level: 16 name: Collateral Thrash prereqs: - - descr: 'Thrash' + - descr: Thrash feat: Thrash requirement: null source: @@ -3669,7 +3669,7 @@ feat: level: 16 name: Dragon Transformation prereqs: - - descr: 'Dragons Rage Wings' + - descr: Dragons Rage Wings feat: Furious Bully requirement: null source: @@ -3780,7 +3780,7 @@ feat: level: 20 name: Contagious Rage prereqs: - - descr: 'Share Rage' + - descr: Share Rage feat: Share Rage requirement: null source: @@ -4285,7 +4285,7 @@ feat: level: 12 name: Eclectic Polymath prereqs: - - descr: 'Esoteric Polymath' + - descr: Esoteric Polymath feat: Esoteric Polymath requirement: null source: @@ -4382,7 +4382,7 @@ feat: prereqs: - descr: Class Level 16 feat: null - requirement: You haven’t acted yet on your turn. + requirement: You haven't acted yet on your turn. source: - abbr: CRB page_start: 103 @@ -4477,7 +4477,7 @@ feat: level: 18 name: Impossible Polymath prereqs: - - descr: 'Esoteric Polymath' + - descr: Esoteric Polymath feat: Esoteric Polymath requirement: null source: @@ -4533,7 +4533,7 @@ feat: has_been_manually_proofread: false name: Symphony of the Muse prereqs: - - descr: 'Harmonize' + - descr: Harmonize feat: Harmonize requirement: null source: @@ -4917,7 +4917,7 @@ feat: has_been_manually_proofread: false name: Advanced Deity’s Domain prereqs: - - descr: 'Deitys Domain' + - descr: Deitys Domain feat: Deity’s Domain requirement: null source: @@ -4936,7 +4936,7 @@ feat: level: 8 name: Greater Mercy prereqs: - - descr: 'Mercy' + - descr: Mercy feat: Mercy requirement: null source: @@ -5055,7 +5055,7 @@ feat: level: 10 name: Imposing Destrier prereqs: - - descr: 'Loyal Warhouse' + - descr: Loyal Warhouse feat: Loyal Warhouse requirement: null source: @@ -5115,7 +5115,7 @@ feat: level: 10 name: Shield of Reckoning prereqs: - - descr: 'Shield Warden' + - descr: Shield Warden feat: Shield Warden (Champion) requirement: null source: @@ -5136,7 +5136,7 @@ feat: level: 12 name: Affliction Mercy prereqs: - - descr: 'Mercy' + - descr: Mercy feat: Mercy requirement: null source: @@ -5273,7 +5273,7 @@ feat: level: 14 name: Anchoring Aura prereqs: - - descr: 'Fiendsbane Oath' + - descr: Fiendsbane Oath feat: Fiendsbane Oath requirement: Fiendsbane Oath source: @@ -5292,7 +5292,7 @@ feat: level: 14 name: Aura of Life prereqs: - - descr: 'Shining Oath' + - descr: Shining Oath feat: Shining Oath requirement: Shining Oath source: @@ -5329,7 +5329,7 @@ feat: level: 14 name: Aura of Vengeance prereqs: - - descr: 'Vengeful Oath' + - descr: Vengeful Oath feat: Vengeful Oath requirement: exalt and Vengeful Oath source: @@ -5386,7 +5386,7 @@ feat: level: 14 name: Wyrmbane Aura prereqs: - - descr: 'Dragonslayer Oath' + - descr: Dragonslayer Oath feat: Dragonslayer Oath requirement: Dragonslayer Oath source: @@ -5411,7 +5411,7 @@ feat: level: 16 name: Auspicious Mount prereqs: - - descr: 'Imposing Destrier' + - descr: Imposing Destrier feat: Imposing Destrier requirement: null source: @@ -5449,7 +5449,7 @@ feat: level: 16 name: Shield of Grace prereqs: - - descr: 'Shield Warden' + - descr: Shield Warden feat: Shield Warden (Champion) requirement: null source: @@ -5491,7 +5491,7 @@ feat: level: 18 name: Ultimate Mercy prereqs: - - descr: 'Mercy' + - descr: Mercy feat: Mercy requirement: null source: @@ -5533,7 +5533,7 @@ feat: level: 20 name: Radiant Blade Master prereqs: - - descr: 'Radiant Blade Spirit' + - descr: Radiant Blade Spirit feat: Radiant Blade Spirit requirement: null source: @@ -5865,7 +5865,7 @@ feat: level: 4 name: Improved Communal Healing prereqs: - - descr: 'Communal Healing' + - descr: Communal Healing feat: Communal Healing requirement: null source: @@ -6001,7 +6001,7 @@ feat: level: 8 name: Advanced Domain prereqs: - - descr: 'Domain Initiate' + - descr: Domain Initiate feat: Domain Initiate requirement: null source: @@ -6082,7 +6082,7 @@ feat: level: 8 name: Emblazon Energy prereqs: - - descr: 'Emblazon Armament' + - descr: Emblazon Armament feat: Emblazon Armament requirement: null source: @@ -6103,7 +6103,7 @@ feat: level: 10 name: Castigating Weapon prereqs: - - descr: 'Holy Castigation' + - descr: Holy Castigation feat: Holy Castigation requirement: null source: @@ -6227,7 +6227,7 @@ feat: level: 12 name: Emblazon Antimagic prereqs: - - descr: 'Emblazon Armament' + - descr: Emblazon Armament feat: Emblazon Armament requirement: null source: @@ -6248,7 +6248,7 @@ feat: level: 12 name: Shared Replenishment prereqs: - - descr: 'Replenishment Of War' + - descr: Replenishment Of War feat: Replenishment of War requirement: null source: @@ -6267,7 +6267,7 @@ feat: has_been_manually_proofread: false name: Deity’s Protection prereqs: - - descr: 'Advanced Domain' + - descr: Advanced Domain feat: Advanced Domain requirement: null source: @@ -6285,7 +6285,7 @@ feat: level: 14 name: Extend Armament Alignment prereqs: - - descr: 'Align Armament' + - descr: Align Armament feat: Align Armament requirement: null source: @@ -6406,7 +6406,7 @@ feat: level: 18 name: Domain Wellspring prereqs: - - descr: 'Domain Focus' + - descr: Domain Focus feat: Domain Focus requirement: null source: @@ -6453,7 +6453,7 @@ feat: level: 18 name: Improved Swift Banishment prereqs: - - descr: 'Swift Banishment' + - descr: Swift Banishment feat: Swift Banishment requirement: null source: @@ -6729,7 +6729,7 @@ feat: level: 4 name: Form Control prereqs: - - descr: 'Wild Shape' + - descr: Wild Shape feat: Wild Shape requirement: null source: @@ -6751,7 +6751,7 @@ feat: has_been_manually_proofread: false name: Mature Animal Companion (Druid) prereqs: - - descr: 'Animal Companion' + - descr: Animal Companion feat: Animal Companion (Druid) requirement: null source: @@ -6770,7 +6770,7 @@ feat: level: 4 name: Order Magic prereqs: - - descr: 'Order Explorer' + - descr: Order Explorer feat: Order Explorer requirement: null source: @@ -6788,7 +6788,7 @@ feat: level: 4 name: Thousand Faces prereqs: - - descr: 'Wild Shape' + - descr: Wild Shape feat: Wild Shape requirement: null source: @@ -6849,7 +6849,7 @@ feat: level: 6 name: Insect Shape prereqs: - - descr: 'Wild Shape' + - descr: Wild Shape feat: Wild Shape requirement: null source: @@ -6890,7 +6890,7 @@ feat: level: 8 name: Ferocious Shape prereqs: - - descr: 'Wild Shape' + - descr: Wild Shape feat: Wild Shape requirement: null source: @@ -6927,7 +6927,7 @@ feat: has_been_manually_proofread: false name: Incredible Companion (Druid) prereqs: - - descr: 'Mature Animal Companion' + - descr: Mature Animal Companion feat: Mature Animal Companion (Druid) requirement: null source: @@ -6949,7 +6949,7 @@ feat: level: 8 name: Soaring Shape prereqs: - - descr: 'Wild Shape' + - descr: Wild Shape feat: Wild Shape requirement: null source: @@ -6988,7 +6988,7 @@ feat: level: 10 name: Elemental Shape prereqs: - - descr: 'Wild Shape' + - descr: Wild Shape feat: Wild Shape requirement: null source: @@ -7073,7 +7073,7 @@ feat: has_been_manually_proofread: false name: Side by Side (Druid) prereqs: - - descr: 'Animal Companion' + - descr: Animal Companion feat: Animal Companion (Druid) requirement: null source: @@ -7093,7 +7093,7 @@ feat: level: 12 name: Dragon Shape prereqs: - - descr: 'Soaring Shape' + - descr: Soaring Shape feat: Soaring Shape requirement: null source: @@ -7113,7 +7113,7 @@ feat: level: 12 name: Green Tongue prereqs: - - descr: 'Green Empathy' + - descr: Green Empathy feat: Green Empathy requirement: null source: @@ -7151,7 +7151,7 @@ feat: level: 12 name: Primal Summons prereqs: - - descr: 'Call Of The Wild' + - descr: Call Of The Wild feat: Call of the Wild requirement: null source: @@ -7169,7 +7169,7 @@ feat: has_been_manually_proofread: false name: Specialized Companion (Druid) prereqs: - - descr: 'Incredible Companion' + - descr: Incredible Companion feat: Incredible Companion (Druid) requirement: null source: @@ -7251,7 +7251,7 @@ feat: level: 16 name: Monstrosity Shape prereqs: - - descr: 'Wild Shape' + - descr: Wild Shape feat: Wild Shape requirement: null source: @@ -7269,7 +7269,7 @@ feat: level: 18 name: Invoke Disaster prereqs: - - descr: 'Wind Caller' + - descr: Wind Caller feat: Wind Caller requirement: null source: @@ -7307,7 +7307,7 @@ feat: level: 18 name: Primal Wellspring prereqs: - - descr: 'Primal Focus' + - descr: Primal Focus feat: Primal Focus requirement: null source: @@ -7367,7 +7367,7 @@ feat: level: 20 name: True Shapeshifter prereqs: - - descr: 'Wild Shape' + - descr: Wild Shape feat: Wild Shape requirement: null source: @@ -7888,7 +7888,7 @@ feat: level: 6 name: Furious Focus prereqs: - - descr: 'Power Attack' + - descr: Power Attack feat: Power Attack requirement: null source: @@ -8000,7 +8000,7 @@ feat: level: 6 name: Shield Warden (Fighter) prereqs: - - descr: 'Shield Block' + - descr: Shield Block feat: Shield Block requirement: null source: @@ -8021,7 +8021,7 @@ feat: level: 6 name: Triple Shot prereqs: - - descr: 'Double Shot' + - descr: Double Shot feat: Double Shot requirement: null source: @@ -8063,7 +8063,7 @@ feat: level: 8 name: Dueling Riposte prereqs: - - descr: 'Dueling Parry' + - descr: Dueling Parry feat: Dueling Parry requirement: You are benefiting from Dueling Parry. source: @@ -8166,7 +8166,7 @@ feat: level: 8 name: Quick Shield Block prereqs: - - descr: 'Reactive Shield' + - descr: Reactive Shield feat: Reactive Shield requirement: null source: @@ -8357,7 +8357,7 @@ feat: level: 10 name: Improved Knockdown prereqs: - - descr: 'Knockdown' + - descr: Knockdown feat: Knockback requirement: null source: @@ -8420,7 +8420,7 @@ feat: level: 12 name: Dueling Dance prereqs: - - descr: 'Dueling Parry' + - descr: Dueling Parry feat: Dueling Parry requirement: You are wielding only a single one-handed melee weapon and have your other hand or hands free. @@ -8462,7 +8462,7 @@ feat: level: 12 name: Improved Dueling Riposte prereqs: - - descr: 'Dueling Riposte' + - descr: Dueling Riposte feat: Dueling Riposte requirement: null source: @@ -8481,7 +8481,7 @@ feat: level: 12 name: Incredible Ricochet prereqs: - - descr: 'Incredible Aim' + - descr: Incredible Aim feat: Incredible Aim requirement: null source: @@ -8503,7 +8503,7 @@ feat: level: 12 name: Lunging Stance prereqs: - - descr: 'Lunge' + - descr: Lunge feat: Lunge requirement: You are wielding a melee weapon. source: @@ -8637,7 +8637,7 @@ feat: level: 14 name: Guiding Riposte prereqs: - - descr: 'Dueling Riposte' + - descr: Dueling Riposte feat: Dueling Riposte requirement: null source: @@ -8656,7 +8656,7 @@ feat: has_been_manually_proofread: false name: Improved Twin Riposte (Fighter) prereqs: - - descr: 'Twin Riposte' + - descr: Twin Riposte feat: Twin Riposte requirement: null source: @@ -8713,7 +8713,7 @@ feat: level: 16 name: Graceful Poise prereqs: - - descr: 'Double Slice' + - descr: Double Slice feat: Double Slice requirement: null source: @@ -8733,7 +8733,7 @@ feat: level: 16 name: Improved Reflexive Shield prereqs: - - descr: 'Reflexive Shield' + - descr: Reflexive Shield feat: Reflexive Shield requirement: null source: @@ -8753,7 +8753,7 @@ feat: level: 16 name: Multishot Stance prereqs: - - descr: 'Triple Shot' + - descr: Triple Shot feat: Triple Shot requirement: You are wielding a ranged weapon with reload 0. source: @@ -8773,7 +8773,7 @@ feat: level: 16 name: Twinned Defense prereqs: - - descr: 'Twin Parry' + - descr: Twin Parry feat: Twin Parry requirement: You are wielding two melee weapons, one in each hand. source: @@ -9117,7 +9117,7 @@ feat: level: 2 name: Elemental Fist prereqs: - - descr: 'Ki Strike' + - descr: Ki Strike feat: Ki Strike requirement: null source: @@ -9159,7 +9159,7 @@ feat: prereqs: - descr: Class Level 4 feat: null - requirement: You’re aware of the attack, are not flat-footed against it, and have + requirement: You're aware of the attack, are not flat-footed against it, and have a hand free. source: - abbr: CRB @@ -9291,7 +9291,7 @@ feat: level: 6 name: Crane Flutter prereqs: - - descr: 'Crane Stance' + - descr: Crane Stance feat: Crane Stance requirement: You are in Crrane Stance. source: @@ -9316,7 +9316,7 @@ feat: level: 6 name: Dragon Roar prereqs: - - descr: 'Dragon Stance' + - descr: Dragon Stance feat: Dragon Stance requirement: You are in Dragon Stance. source: @@ -9357,7 +9357,7 @@ feat: level: 6 name: Mountain Stronghold prereqs: - - descr: 'Mountain Stance' + - descr: Mountain Stance feat: Mountain Stance requirement: You are in Mountain Stance. source: @@ -9378,7 +9378,7 @@ feat: level: 6 name: Tiger Slash prereqs: - - descr: 'Tiger Stance' + - descr: Tiger Stance feat: Tiger Stance requirement: You are in Tiger Stance. source: @@ -9436,7 +9436,7 @@ feat: level: 6 name: Wolf Drag prereqs: - - descr: 'Wolf Stance' + - descr: Wolf Stance feat: Wolf Stance requirement: You are in Wolf Stance. source: @@ -9457,7 +9457,7 @@ feat: level: 8 name: 'Arrow Snatching ' prereqs: - - descr: 'Deflect Arrow' + - descr: Deflect Arrow feat: Deflect Arrows requirement: null source: @@ -9768,7 +9768,7 @@ feat: level: 14 name: Ironblood Surge prereqs: - - descr: 'Ironblood Stance' + - descr: Ironblood Stance feat: Ironblood Stance requirement: You are in Ironblood Stance. source: @@ -9788,7 +9788,7 @@ feat: level: 14 name: Moutain Quake prereqs: - - descr: 'Mountain Stronghold' + - descr: Mountain Stronghold feat: Mountain Stronghold requirement: You are in Mountain Stance. source: @@ -9807,7 +9807,7 @@ feat: level: 14 name: Tangled Forest Rake prereqs: - - descr: 'Tangled Forest Stance' + - descr: Tangled Forest Stance feat: Tangled Forest Stance requirement: You are in Tangled Forest Stance. source: @@ -9864,7 +9864,7 @@ feat: level: 16 name: Wild Winds Gust prereqs: - - descr: 'Wild Winds Initiate' + - descr: Wild Winds Initiate feat: Wild Winds Initiate requirement: You are in Wild Winds Stance. source: @@ -9906,7 +9906,7 @@ feat: level: 16 name: Master of Many Styles prereqs: - - descr: 'Stance Savant' + - descr: Stance Savant feat: Stance Savant (Monk) requirement: This is the first action of your turn. source: @@ -9998,7 +9998,7 @@ feat: level: 18 name: Meditative Wellspring prereqs: - - descr: 'Meditative Focus' + - descr: Meditative Focus feat: Meditative Focus requirement: null source: @@ -10248,7 +10248,7 @@ feat: level: 2 name: Monster Warden prereqs: - - descr: 'Monster Hunter' + - descr: Monster Hunter feat: Monster Hunter requirement: null source: @@ -10428,7 +10428,7 @@ feat: level: 4 name: Snare Specialist prereqs: - - descr: 'Snare Crafting' + - descr: Snare Crafting feat: Snare Crafting requirement: null source: @@ -10468,7 +10468,7 @@ feat: has_been_manually_proofread: false name: Mature Animal Companion (Ranger) prereqs: - - descr: 'Animal Companion' + - descr: Animal Companion feat: Animal Companion (Druid) requirement: null source: @@ -10486,7 +10486,7 @@ feat: level: 6 name: Quick Snares prereqs: - - descr: 'Snare Specialist' + - descr: Snare Specialist feat: Snare Specialist requirement: null source: @@ -10552,7 +10552,7 @@ feat: level: 6 name: Swift Tracker prereqs: - - descr: 'Experienced Tracker' + - descr: Experienced Tracker feat: Experienced Tracker requirement: null source: @@ -10612,7 +10612,7 @@ feat: level: 8 name: Powerful Snares prereqs: - - descr: 'Snare Specialist' + - descr: Snare Specialist feat: Snare Specialist requirement: null source: @@ -10633,7 +10633,7 @@ feat: level: 8 name: Terrain Master prereqs: - - descr: 'Favored Terrain' + - descr: Favored Terrain feat: Favored Terrain requirement: null source: @@ -10688,7 +10688,7 @@ feat: has_been_manually_proofread: false name: Incredible Companion (Ranger) prereqs: - - descr: 'Mature Animal Compainion (Ranger)' + - descr: Mature Animal Compainion (Ranger) feat: Mature Animal Companion (Ranger) requirement: null source: @@ -10708,7 +10708,7 @@ feat: level: 10 name: Master Monster Hunter prereqs: - - descr: 'Monster Hunter' + - descr: Monster Hunter feat: Monster Hunter requirement: null source: @@ -10826,7 +10826,7 @@ feat: level: 12 name: Lightning Snares prereqs: - - descr: 'Snare Specialist' + - descr: Snare Specialist feat: Snare Specialist requirement: null source: @@ -10908,7 +10908,7 @@ feat: level: 14 name: Shared Prey prereqs: - - descr: 'Wardens Boon' + - descr: Wardens Boon feat: Warden’s Boon requirement: null source: @@ -10928,7 +10928,7 @@ feat: level: 14 name: Stealthy Companion prereqs: - - descr: 'Camouflage' + - descr: Camouflage feat: Camouflage requirement: null source: @@ -10947,7 +10947,7 @@ feat: level: 14 name: Targeting Shot prereqs: - - descr: 'Hunters Aim' + - descr: Hunters Aim feat: Hunter’s Aim requirement: null source: @@ -10990,7 +10990,7 @@ feat: level: 16 name: Greater Distracting Shot prereqs: - - descr: 'Distracting Shot' + - descr: Distracting Shot feat: Distracting Shot requirement: null source: @@ -11027,7 +11027,7 @@ feat: level: 16 name: Legendary Monster Hunter prereqs: - - descr: 'Master Monster Hunter' + - descr: Master Monster Hunter feat: Master Monster Hunter requirement: null source: @@ -11045,7 +11045,7 @@ feat: has_been_manually_proofread: false name: Specialized Companion (Ranger) prereqs: - - descr: 'Incredible Companion(Ranger)' + - descr: Incredible Companion(Ranger) feat: Incredible Companion (Ranger) requirement: null source: @@ -11064,7 +11064,7 @@ feat: level: 16 name: Ubiquitous Snares prereqs: - - descr: 'Snare Specialist' + - descr: Snare Specialist feat: Snare Specialist requirement: null source: @@ -11125,7 +11125,7 @@ feat: level: 18 name: Masterful Companion prereqs: - - descr: 'Animal Companion' + - descr: Animal Companion feat: Animal Companion (Druid) requirement: null source: @@ -11166,7 +11166,7 @@ feat: level: 18 name: Shadow Hunter prereqs: - - descr: 'Camouflage' + - descr: Camouflage feat: Camouflage requirement: null source: @@ -11186,7 +11186,7 @@ feat: level: 20 name: Legendary Shot prereqs: - - descr: 'Far Shot' + - descr: Far Shot feat: Far Shot requirement: null source: @@ -11229,7 +11229,7 @@ feat: level: 20 name: Triple Threat prereqs: - - descr: 'Shared Prey' + - descr: Shared Prey feat: Shared Prey requirement: null source: @@ -11667,7 +11667,7 @@ feat: level: 8 name: Improved Poison Weapon prereqs: - - descr: 'Poison Weapon' + - descr: Poison Weapon feat: Poison Weapon requirement: null source: @@ -11687,7 +11687,7 @@ feat: level: 8 name: Nimble Roll prereqs: - - descr: 'Nimble Dodge' + - descr: Nimble Dodge feat: Nimble Dodge requirement: null source: @@ -12156,7 +12156,7 @@ feat: level: 18 name: Implausible Infiltration prereqs: - - descr: 'Quick Squeeze' + - descr: Quick Squeeze feat: Quick Squeeze requirement: You are adjacent to a floor or vertical wall. source: @@ -12205,7 +12205,7 @@ feat: requirement: When you make your daily preparations, you must specify a trigger for this reaction using the same restrictions as the triggers for the Ready action. You also choose a single spell from the arcane, divine, occult, or primal list - of 4th level or lower. The spell can’t have a cost, nor can its casting time be + of 4th level or lower. The spell can't have a cost, nor can its casting time be more than 10 minutes. The spell must be able to target a single creature, and you must be a valid target for it. source: @@ -12248,7 +12248,7 @@ feat: level: 20 name: Impossible Striker prereqs: - - descr: 'Sly Striker' + - descr: Sly Striker feat: Sly Striker requirement: null source: @@ -12270,7 +12270,7 @@ feat: level: 20 name: Reactive Distraction prereqs: - - descr: 'Perfect Distraction' + - descr: Perfect Distraction feat: Perfect Distraction requirement: You have Perfect Distraction ready to use. source: @@ -12719,7 +12719,7 @@ feat: level: 14 name: Reflect Spell prereqs: - - descr: 'CounterSpell' + - descr: CounterSpell feat: Counterspell (Spontaneous) requirement: null source: @@ -12739,7 +12739,7 @@ feat: level: 16 name: Greater Mental Evolution prereqs: - - descr: 'Arcane Evolution or Occult Evolution' + - descr: Arcane Evolution or Occult Evolution feat: null requirement: null source: @@ -12759,7 +12759,7 @@ feat: level: 16 name: Greater Vital Evolution prereqs: - - descr: 'Divine Evolution or Primal Evolution' + - descr: Divine Evolution or Primal Evolution feat: null requirement: null source: @@ -12779,7 +12779,7 @@ feat: level: 18 name: Bloodline Wellspring prereqs: - - descr: 'Bloodline Focus' + - descr: Bloodline Focus feat: Bloodline Focus requirement: null source: @@ -12799,7 +12799,7 @@ feat: level: 18 name: Greater Crossblooded Evolution prereqs: - - descr: 'Crossblooded Evolution' + - descr: Crossblooded Evolution feat: Crossblooded Evolution requirement: null source: @@ -13050,7 +13050,7 @@ feat: level: 4 name: Silent Spell prereqs: - - descr: 'Conceal Spell' + - descr: Conceal Spell feat: Conceal Spell requirement: null source: @@ -13142,7 +13142,7 @@ feat: level: 8 name: Universal Versatility prereqs: - - descr: 'Hand of the Apprentice' + - descr: Hand of the Apprentice feat: Hand of the Apprentice requirement: null source: @@ -13240,7 +13240,7 @@ feat: level: 12 name: Clever Counterspell prereqs: - - descr: 'Quick Recognition' + - descr: Quick Recognition feat: Quick Recognition requirement: null source: @@ -13445,7 +13445,7 @@ feat: level: 4 name: Basic Concoction prereqs: - - descr: 'Alchemist Dedication' + - descr: Alchemist Dedication feat: Alchemist Dedication requirement: null source: @@ -13462,7 +13462,7 @@ feat: level: 4 name: Quick Alchemy prereqs: - - descr: 'Alchemist Dedication' + - descr: Alchemist Dedication feat: Alchemist Dedication requirement: null source: @@ -13479,7 +13479,7 @@ feat: has_been_manually_proofread: false name: Advanced Conoction prereqs: - - descr: 'Basic Concoction' + - descr: Basic Concoction feat: Basic Concoction requirement: null source: @@ -13573,7 +13573,7 @@ feat: level: 4 name: Basic Fury prereqs: - - descr: 'Barbarian Dedication' + - descr: Barbarian Dedication feat: Barbarian Resiliency requirement: null source: @@ -13591,7 +13591,7 @@ feat: level: 6 name: Advanced Fury prereqs: - - descr: 'Basic Fury' + - descr: Basic Fury feat: Basic Fury requirement: null source: @@ -13608,7 +13608,7 @@ feat: level: 6 name: Instinct Ability prereqs: - - descr: 'Barbarian Dedication' + - descr: Barbarian Dedication feat: Barbarian Resiliency requirement: null source: @@ -13669,7 +13669,7 @@ feat: level: 4 name: Basic Bard Spellcasting prereqs: - - descr: 'Bard Dedication' + - descr: Bard Dedication feat: Bard Dedication requirement: null source: @@ -13685,7 +13685,7 @@ feat: has_been_manually_proofread: false name: Basic Muse’s Whispers prereqs: - - descr: 'Bard Dedication' + - descr: Bard Dedication feat: Bard Dedication requirement: null source: @@ -13702,7 +13702,7 @@ feat: has_been_manually_proofread: false name: Advanced Muse’s Whispers prereqs: - - descr: 'Basic Muse''s Whispers' + - descr: Basic Muse's Whispers feat: Basic Muse’s Whispers requirement: null source: @@ -13721,7 +13721,7 @@ feat: level: 6 name: Counter Perform prereqs: - - descr: 'Bard Dedication' + - descr: Bard Dedication feat: Bard Dedication requirement: null source: @@ -13738,7 +13738,7 @@ feat: level: 8 name: Inspirational Performance prereqs: - - descr: 'Bard Dedication' + - descr: Bard Dedication feat: Bard Dedication requirement: null source: @@ -13758,7 +13758,7 @@ feat: level: 8 name: Occult Breadth prereqs: - - descr: 'Basic Bard Spellcasting' + - descr: Basic Bard Spellcasting feat: Basic Bard Spellcasting requirement: null source: @@ -13838,7 +13838,7 @@ feat: level: 4 name: Basic Devotion prereqs: - - descr: 'Champion Dedication' + - descr: Champion Dedication feat: Champion Dedication requirement: null source: @@ -13878,7 +13878,7 @@ feat: level: 4 name: Healing Touch prereqs: - - descr: 'Champion Dedication' + - descr: Champion Dedication feat: Champion Dedication requirement: null source: @@ -13896,7 +13896,7 @@ feat: level: 6 name: Advanced Devotion prereqs: - - descr: 'Basic Devotion' + - descr: Basic Devotion feat: Basic Devotion requirement: null source: @@ -13912,7 +13912,7 @@ feat: has_been_manually_proofread: false name: Champion’s Reaction prereqs: - - descr: 'Champion Dedication' + - descr: Champion Dedication feat: Champion Dedication requirement: null source: @@ -13929,7 +13929,7 @@ feat: level: 6 name: Divine Ally prereqs: - - descr: 'Champion Dedication' + - descr: Champion Dedication feat: Champion Dedication requirement: null source: @@ -13993,7 +13993,7 @@ feat: level: 4 name: Basic Cleric Spellcasting prereqs: - - descr: 'Cleric Dedication' + - descr: Cleric Dedication feat: Cleric Dedication requirement: null source: @@ -14010,7 +14010,7 @@ feat: level: 4 name: Basic Dogma prereqs: - - descr: 'Cleric Dedication' + - descr: Cleric Dedication feat: Cleric Dedication requirement: null source: @@ -14028,7 +14028,7 @@ feat: level: 6 name: Advanced Dogma prereqs: - - descr: 'Basic Dogma' + - descr: Basic Dogma feat: Basic Dogma requirement: null source: @@ -14047,7 +14047,7 @@ feat: level: 8 name: Divine Breadth prereqs: - - descr: 'Basic Cleric Spellcasting' + - descr: Basic Cleric Spellcasting feat: Basic Cleric Spellcasting requirement: null source: @@ -14122,7 +14122,7 @@ feat: level: 4 name: Basic Druid Spellcasting prereqs: - - descr: 'Druid Dedication' + - descr: Druid Dedication feat: null requirement: null source: @@ -14139,7 +14139,7 @@ feat: level: 4 name: Basic Wilding prereqs: - - descr: 'Druid Dedication' + - descr: Druid Dedication feat: null requirement: null source: @@ -14158,7 +14158,7 @@ feat: level: 4 name: Order Spell prereqs: - - descr: 'Druid Dedication' + - descr: Druid Dedication feat: null requirement: null source: @@ -14176,7 +14176,7 @@ feat: level: 6 name: Advanced Wilding prereqs: - - descr: 'Basic Wilding' + - descr: Basic Wilding feat: Basic Wilding requirement: null source: @@ -14194,7 +14194,7 @@ feat: level: 8 name: Primal Breadth prereqs: - - descr: 'Basic Druid Spellcasting' + - descr: Basic Druid Spellcasting feat: Basic Druid Spellcasting requirement: null source: @@ -14268,7 +14268,7 @@ feat: level: 4 name: Basic Maneuver prereqs: - - descr: 'Fighter Dedication' + - descr: Fighter Dedication feat: Fighter Dedication requirement: null source: @@ -14305,7 +14305,7 @@ feat: level: 4 name: Opportunist prereqs: - - descr: 'Fighter Dedication' + - descr: Fighter Dedication feat: Fighter Dedication requirement: null source: @@ -14323,7 +14323,7 @@ feat: level: 6 name: Advanced Maneuver prereqs: - - descr: 'Basic Maneuver' + - descr: Basic Maneuver feat: Basic Maneuver requirement: null source: @@ -14380,7 +14380,7 @@ feat: level: 4 name: Basic Kata prereqs: - - descr: 'Monk Dedication' + - descr: Monk Dedication feat: Monk Dedication requirement: null source: @@ -14418,7 +14418,7 @@ feat: level: 6 name: Advanced Kata prereqs: - - descr: 'Basic Kata' + - descr: Basic Kata feat: Basic Kata requirement: null source: @@ -14435,7 +14435,7 @@ feat: level: 8 name: Monk Moves prereqs: - - descr: 'Monk Dedication' + - descr: Monk Dedication feat: Monk Dedication requirement: null source: @@ -14451,7 +14451,7 @@ feat: has_been_manually_proofread: false name: Monk’s Flurry prereqs: - - descr: 'Monk Dedication' + - descr: Monk Dedication feat: Monk Dedication requirement: null source: @@ -14509,7 +14509,7 @@ feat: has_been_manually_proofread: false name: Basic Hunter’s Trick prereqs: - - descr: 'Ranger Dedication' + - descr: Ranger Dedication feat: Ranger Dedication requirement: null source: @@ -14546,7 +14546,7 @@ feat: has_been_manually_proofread: false name: Advanced Hunter’s Trick prereqs: - - descr: 'Basic Hunters Trick' + - descr: Basic Hunters Trick feat: Basic Hunter’s Trick requirement: null source: @@ -14603,7 +14603,7 @@ feat: level: 4 name: Basic Trickery prereqs: - - descr: 'Rogue Dedication' + - descr: Rogue Dedication feat: Rogue Dedication requirement: null source: @@ -14622,7 +14622,7 @@ feat: level: 4 name: Sneak Attacker prereqs: - - descr: 'Rogue Dedication' + - descr: Rogue Dedication feat: Rogue Dedication requirement: null source: @@ -14640,7 +14640,7 @@ feat: level: 6 name: Advanced Trickery prereqs: - - descr: 'Basic Trickery' + - descr: Basic Trickery feat: Basic Trickery requirement: null source: @@ -14676,7 +14676,7 @@ feat: level: 10 name: Uncanny Dodge prereqs: - - descr: 'Rogue Dedication' + - descr: Rogue Dedication feat: Rogue Dedication requirement: null source: @@ -14740,7 +14740,7 @@ feat: level: 4 name: Basic Sorcerer Spellcasting prereqs: - - descr: 'Sorcerer Dedication' + - descr: Sorcerer Dedication feat: Sorcerer Dedication requirement: null source: @@ -14757,7 +14757,7 @@ feat: level: 4 name: Basic Blood Potency prereqs: - - descr: 'Sorcerer Dedication' + - descr: Sorcerer Dedication feat: Sorcerer Dedication requirement: null source: @@ -14776,7 +14776,7 @@ feat: level: 4 name: Basic Bloodline Spell prereqs: - - descr: 'Sorcerer Dedication' + - descr: Sorcerer Dedication feat: Sorcerer Dedication requirement: null source: @@ -14794,7 +14794,7 @@ feat: level: 6 name: Advanced Blood Potency prereqs: - - descr: 'Basic Blood Potency' + - descr: Basic Blood Potency feat: Basic Blood Potency requirement: null source: @@ -14814,7 +14814,7 @@ feat: level: 8 name: Bloodline Breadth prereqs: - - descr: 'Basic Sorcerer Spellcasting' + - descr: Basic Sorcerer Spellcasting feat: Basic Sorcerer Spellcasting requirement: null source: @@ -14891,7 +14891,7 @@ feat: level: 4 name: Arcane School Spell prereqs: - - descr: 'Wizard Dedication' + - descr: Wizard Dedication feat: Wizard Dedication requirement: null source: @@ -14908,7 +14908,7 @@ feat: level: 4 name: Basic Arcana prereqs: - - descr: 'Wizard Dedication' + - descr: Wizard Dedication feat: Wizard Dedication requirement: null source: @@ -14927,7 +14927,7 @@ feat: level: 4 name: Basic Wizard Spellcasting prereqs: - - descr: 'Wizard Dedication' + - descr: Wizard Dedication feat: Wizard Dedication requirement: null source: @@ -14945,7 +14945,7 @@ feat: level: 6 name: Advanced Arcana prereqs: - - descr: 'Basic Arcana' + - descr: Basic Arcana feat: Basic Arcana requirement: null source: @@ -14964,7 +14964,7 @@ feat: level: 8 name: Arcane Breadth prereqs: - - descr: 'Basic Wizard Spellcasting' + - descr: Basic Wizard Spellcasting feat: Basic Wizard Spellcasting requirement: null source: @@ -14998,7 +14998,7 @@ feat: level: 18 name: Master Wizard Spellcasting prereqs: - - descr: 'legendary in Arcana' + - descr: legendary in Arcana feat: null requirement: null source: @@ -15450,7 +15450,7 @@ feat: level: 2 name: Connections prereqs: - - descr: 'Courtly Graces' + - descr: Courtly Graces feat: Courtly Graces requirement: null source: @@ -15702,7 +15702,7 @@ feat: level: 1 name: Fascinating Performance prereqs: - - descr: 'trained in Performance' + - descr: trained in Performance feat: null requirement: null source: @@ -15937,7 +15937,7 @@ feat: level: 7 name: Impeccable Crafter prereqs: - - descr: 'Specialty Crafting' + - descr: Specialty Crafting feat: Specialty Crafting requirement: null source: @@ -15956,7 +15956,7 @@ feat: level: 1 name: Impressive Performance prereqs: - - descr: 'trained in Performance' + - descr: trained in Performance feat: null requirement: null source: @@ -16142,7 +16142,7 @@ feat: level: 15 name: Legendary Linguist prereqs: - - descr: 'Multilingual' + - descr: Multilingual feat: Multilingual requirement: null source: @@ -16213,7 +16213,7 @@ feat: level: 15 name: Legendary Performer prereqs: - - descr: 'Virtuosic Performer' + - descr: Virtuosic Performer feat: Virtuosic Performer requirement: null source: @@ -16255,7 +16255,7 @@ feat: level: 15 name: Legendary Sneak prereqs: - - descr: 'Swift Sneak' + - descr: Swift Sneak feat: Swift Sneak requirement: null source: @@ -16300,7 +16300,7 @@ feat: level: 15 name: Legendary Thief prereqs: - - descr: 'Pickpocket' + - descr: Pickpocket feat: Pickpocket requirement: null source: @@ -16653,7 +16653,7 @@ feat: level: 7 name: Quick Recognition prereqs: - - descr: 'Recognize Spell' + - descr: Recognize Spell feat: Recognize Spell requirement: null source: @@ -17445,7 +17445,7 @@ feat: level: 1 name: Virtuosic Performer prereqs: - - descr: 'trained in Performance' + - descr: trained in Performance feat: null requirement: null source: diff --git a/data/yaml/requirements.yaml b/data/yaml/requirements.yaml index e23b043..97c2041 100644 --- a/data/yaml/requirements.yaml +++ b/data/yaml/requirements.yaml @@ -75,4 +75,5 @@ requirement: - You have an unexpended spell slot you could use to cast the triggered spell. - Your most recent action was to cast a non-cantrip spell. - The last action you used was Drain Bonded Item. -- You have a focus pool, and you have spent at least 1 Focus Point since you last regained any Focus Points. +- You have a focus pool, and you have spent at least 1 Focus Point since you last + regained any Focus Points. From a9765b85b74bf372af51767f2b23239e7cac922f Mon Sep 17 00:00:00 2001 From: James Miller Date: Tue, 21 Apr 2020 17:46:44 -0500 Subject: [PATCH 3/9] movingd deprecated yaml files --- data/yaml/{ => deprecated}/ancestries.yaml | 0 data/yaml/{ => deprecated}/heritages.yaml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename data/yaml/{ => deprecated}/ancestries.yaml (100%) rename data/yaml/{ => deprecated}/heritages.yaml (100%) diff --git a/data/yaml/ancestries.yaml b/data/yaml/deprecated/ancestries.yaml similarity index 100% rename from data/yaml/ancestries.yaml rename to data/yaml/deprecated/ancestries.yaml diff --git a/data/yaml/heritages.yaml b/data/yaml/deprecated/heritages.yaml similarity index 100% rename from data/yaml/heritages.yaml rename to data/yaml/deprecated/heritages.yaml From de1765445e6b308d3f08d08e46e1b14c3447ec42 Mon Sep 17 00:00:00 2001 From: James Miller Date: Tue, 21 Apr 2020 17:54:30 -0500 Subject: [PATCH 4/9] make cleanyaml.py get all yaml files in the directory and then run it --- data/yaml/ancestriesheritages.yaml | 27 +++++++++++++++------------ data/yaml/cleanyaml.py | 24 +++++++++++++++--------- data/yaml/gear.yaml | 10 +++++----- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/data/yaml/ancestriesheritages.yaml b/data/yaml/ancestriesheritages.yaml index b5ac249..f05bae9 100644 --- a/data/yaml/ancestriesheritages.yaml +++ b/data/yaml/ancestriesheritages.yaml @@ -236,7 +236,10 @@ ancestries: 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 Multilingual feat, you gain another new language. + - 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 Multilingual feat, you gain another new language. feat: null name: Nomadic Halfling - descr: Your ancestors performed many secret acts under the concealing cover of @@ -268,16 +271,16 @@ ancestries: flavor_text: TODO flaws: null heritages: - - 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. + - 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. + - 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 @@ -286,9 +289,9 @@ ancestries: 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). + 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 hp: 8 diff --git a/data/yaml/cleanyaml.py b/data/yaml/cleanyaml.py index 16073df..cb396d6 100644 --- a/data/yaml/cleanyaml.py +++ b/data/yaml/cleanyaml.py @@ -2,27 +2,33 @@ # TO CLEAN UP AND ORDER ALL THE YAML import yaml +import glob +import os -yfiles = [ - "actions.yaml", "ancestries.yaml", "armor.yaml", "backgrounds.yaml", - "basics.yaml", "bulks.yaml", "conditions.yaml", "damage.yaml", - "feats-levels-false-matches.yaml", "feats.yaml", "langs.yaml", - "monsters.yaml", "requirements.yaml", "senses.yaml", "skills.yaml", - "sources.yaml", "spells.yaml", "traits.yaml", "triggers.yaml" -] def main(): + + # gets all files with a yaml extension in the directory + yfiles = [] + for file in glob.glob("*.yaml"): + yfiles.append(file) + + yfiles.sort() + print(yfiles) + for x in yfiles: print("Doing: {}".format(x)) with open(x, 'r') as r: data = yaml.full_load(r) if x == "feats.yaml": for i in data['feat']: + # This is to clean out smart quotes that made it into the + # yaml file so it matches the requirements.yaml if i['requirement'] != None: - print("Before: {}".format(i['requirement'])) + # print("Before: {}".format(i['requirement'])) i['requirement'] = i['requirement'].replace('’', "'") - print("After: {}".format(i['requirement'])) + # print("After: {}".format(i['requirement'])) final = yaml.safe_dump(data, allow_unicode=True) with open(x, 'w') as f: f.write(final) diff --git a/data/yaml/gear.yaml b/data/yaml/gear.yaml index e11631a..63174ec 100644 --- a/data/yaml/gear.yaml +++ b/data/yaml/gear.yaml @@ -1073,7 +1073,7 @@ gear: page_start: 291 page_stop: 291 traits: - - Uncommon + - Uncommon - bulk: 0.1 descr: Maps are uncommon. Most maps you can find are simple and functional. A survey map details a single location in excellent detail. One of these maps gives you @@ -1088,7 +1088,7 @@ gear: page_start: 291 page_stop: 291 traits: - - Uncommon + - Uncommon - bulk: 0.0 descr: Picking an average lock requires four successes at DC 25. hands: 2 @@ -1192,8 +1192,8 @@ gear: - abbr: CRB page_start: 291 page_stop: 291 - traits: - - Uncommon + traits: + - Uncommon - bulk: 0.1 descr: This small wooden box contains cosmetics, false facial hair, spirit gum, and a few simple wigs. You usually need a disguise kit to set up a disguise in @@ -1271,7 +1271,7 @@ gear: page_start: 291 page_stop: 291 traits: - - Uncommon + - Uncommon - bulk: 0.1 descr: You need thieves' tools to Pick Locks or Disable Devices (of some types) using the Thievery skill. Infiltrator thieves' tools add a +1 item bonus to checks From 2788fbe1d426b0275f45bb9bf39f97957e6bbcd5 Mon Sep 17 00:00:00 2001 From: James Miller Date: Tue, 21 Apr 2020 17:55:07 -0500 Subject: [PATCH 5/9] move feats levels false matches to deprecated --- data/yaml/{ => deprecated}/feats-levels-false-matches.yaml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename data/yaml/{ => deprecated}/feats-levels-false-matches.yaml (100%) diff --git a/data/yaml/feats-levels-false-matches.yaml b/data/yaml/deprecated/feats-levels-false-matches.yaml similarity index 100% rename from data/yaml/feats-levels-false-matches.yaml rename to data/yaml/deprecated/feats-levels-false-matches.yaml From 2342bf19d5a3a10b214c7aa5d6f341cfff3ca528 Mon Sep 17 00:00:00 2001 From: James Miller Date: Tue, 21 Apr 2020 18:00:43 -0500 Subject: [PATCH 6/9] minor update to formatting of print statement on cleanyaml.py --- data/yaml/cleanyaml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/yaml/cleanyaml.py b/data/yaml/cleanyaml.py index cb396d6..ed971f7 100644 --- a/data/yaml/cleanyaml.py +++ b/data/yaml/cleanyaml.py @@ -15,7 +15,7 @@ def main(): yfiles.append(file) yfiles.sort() - print(yfiles) + print("Going to clean up the following files: {}".format(yfiles)) for x in yfiles: print("Doing: {}".format(x)) From 83e45e6c68344d15500f9dbee3f53d7fd9524435 Mon Sep 17 00:00:00 2001 From: James Miller Date: Tue, 21 Apr 2020 18:25:06 -0500 Subject: [PATCH 7/9] looks like fixed requirements so far, some requirements need to be switched to prereqs --- data/yaml/feats.yaml | 2 +- data/yaml/requirements.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/yaml/feats.yaml b/data/yaml/feats.yaml index 3effb0a..9f7d9c5 100644 --- a/data/yaml/feats.yaml +++ b/data/yaml/feats.yaml @@ -5275,7 +5275,7 @@ feat: prereqs: - descr: Fiendsbane Oath feat: Fiendsbane Oath - requirement: Fiendsbane Oath + requirement: null source: - abbr: CRB page_start: 114 diff --git a/data/yaml/requirements.yaml b/data/yaml/requirements.yaml index 97c2041..a8bc9c1 100644 --- a/data/yaml/requirements.yaml +++ b/data/yaml/requirements.yaml @@ -68,7 +68,7 @@ requirement: - When you make your daily preparations, you must specify a trigger for this reaction using the same restrictions as the triggers for the Ready action. You also choose a single spell from the arcane, divine, occult, or primal list of 4th level or lower. - The spell can’t have a cost, nor can its casting time be more than 10 minutes. The + The spell can't have a cost, nor can its casting time be more than 10 minutes. The spell must be able to target a single creature, and you must be a valid target for it. - You have Perfect Distraction ready to use. From a691f5c99422ff0db754605653215fb56eb9af86 Mon Sep 17 00:00:00 2001 From: James Miller Date: Tue, 21 Apr 2020 18:35:08 -0500 Subject: [PATCH 8/9] working on triggers in feats, cleanyaml updates to triggers --- data/yaml/cleanyaml.py | 4 ++++ data/yaml/feats.yaml | 24 ++++++++++++------------ gendb/gendb.py | 23 ++++++++++++++++++++--- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/data/yaml/cleanyaml.py b/data/yaml/cleanyaml.py index ed971f7..b7dee3f 100644 --- a/data/yaml/cleanyaml.py +++ b/data/yaml/cleanyaml.py @@ -29,6 +29,10 @@ def main(): # print("Before: {}".format(i['requirement'])) i['requirement'] = i['requirement'].replace('’', "'") # print("After: {}".format(i['requirement'])) + if i['trigger'] != None: + # print("Before: {}".format(i['trigger'])) + i['trigger'] = i['trigger'].replace('’', "'") + # print("After: {}".format(i['trigger'])) final = yaml.safe_dump(data, allow_unicode=True) with open(x, 'w') as f: f.write(final) diff --git a/data/yaml/feats.yaml b/data/yaml/feats.yaml index 9f7d9c5..45e8248 100644 --- a/data/yaml/feats.yaml +++ b/data/yaml/feats.yaml @@ -40,8 +40,8 @@ feat: page_start: 35 page_stop: 35 traits: null - trigger: - - You attempt a saving throw against a magical effect, but you haven't rolled yet. + trigger: You attempt a saving throw against a magical effect, but you haven't rolled + yet. - actioncost: null descr: You eagerly absorbed the old stories and traditions of your ancestors, your gods, and your people, studying in subjects and techniques passed down for generation @@ -1639,7 +1639,7 @@ feat: page_stop: 57 traits: - Human - trigger: You attempt a check using a skill you’re untrained in. + trigger: You attempt a check using a skill you're untrained in. - actioncost: null descr: You’ve learned to split your focus between multiple classes with ease. You gain a 2nd-level multiclass dedication feat (for more about multiclass archetypes, @@ -2558,7 +2558,7 @@ feat: traits: - Additive - Alchemist - trigger: You craft an alchemical bomb using Quick Alchemy that’s at least 2 levels + trigger: You craft an alchemical bomb using Quick Alchemy that's at least 2 levels lower than your advanced alchemy level. - actioncost: null descr: Specialized tweaks to your formula that supplements your genius considerably @@ -3086,7 +3086,7 @@ feat: traits: - Barbarian trigger: A creature within your reach uses a manipulate action or a move action, - makes a ranged attack, or leaves a square during a move action it’s using. + makes a ranged attack, or leaves a square during a move action it's using. - actioncost: null descr: You push your foes around and leave bruises. While raging, when you successfully Disarm, Grapple, Shove, or Trip a foe, you deal that foe bludgeoning damage equal @@ -5125,8 +5125,8 @@ feat: traits: - Champion - Flourish - trigger: A foe’s attack against an ally matches the trigger for both your Shield - Block reaction and your champion’s reaction. + trigger: A foe's attack against an ally matches the trigger for both your Shield + Block reaction and your champion's reaction. - actioncost: null descr: The divine grace that flows through you grants reprieve from an affliction. When you use Mercy, you can instead attempt to counteract a curse, disease, or @@ -9244,7 +9244,7 @@ feat: traits: - Monk trigger: A creature within your reach uses a move action or leaves a square during - a move action it’s using. + a move action it's using. - actioncost: null descr: You can restore your health by tapping into your ki. You gain the wholeness of body ki spell. Increase the number of Focus Points in your focus pool by 1. @@ -10089,7 +10089,7 @@ feat: traits: - Fortune - Monk - trigger: An enemy’s attack hits you or you fail a saving throw against an enemy’s + trigger: An enemy's attack hits you or you fail a saving throw against an enemy's ability. - actioncost: null descr: You gain the service of a young animal companion that travels with you and @@ -10333,7 +10333,7 @@ feat: traits: - Ranger trigger: Your hunted prey is within your reach, and it uses a manipulate action, - uses a move action, or leaves a square during a move action it’s using. + uses a move action, or leaves a square during a move action it's using. - actioncost: null descr: Your experience in the field has taught you how to focus your aim at a distance, increasing your accuracy. Double your weapons’ range increments. @@ -12282,7 +12282,7 @@ feat: - Manipulate - Rogue trigger: You would be hit by an attack or targeted by an effect, or you are within - an effect’s area. + an effect's area. - actioncost: Reaction descr: When a foe Casts a Spell you know and you can see its manifestations, you can use your own magic to disrupt it. You expend one of your spell slots to counter @@ -16836,7 +16836,7 @@ feat: - General - Secret - Skill - trigger: A creature within line of sight casts a spell that you don’t have prepared + trigger: A creature within line of sight casts a spell that you don't have prepared or in your spell repertoire, or a trap or similar object casts such a spell. You must be aware of the casting. - actioncost: null diff --git a/gendb/gendb.py b/gendb/gendb.py index 58e555e..fdfd856 100644 --- a/gendb/gendb.py +++ b/gendb/gendb.py @@ -174,14 +174,31 @@ def do_feats(data, conn): r_id = None else: r_id = get_requirement_id_by_descr(i['requirement'], conn) - # print("f_id for {} is {}".format(i['frequency'], f_id)) + if i['trigger'] == None: + t_id = None + else: + t_id = get_trigger_id_by_descr(i['trigger'], conn) # res = (ac_id, i['descr'], f_id, i['level'], i['name'], r_id, t_id) - - insert_stmt = "INSERT INTO feat (actioncost_id, descr, freq_id, level, name, requirement_id, trigger_id) VALUES (?,?,?,?,?,?,?);" +def get_trigger_id_by_descr(t, conn): + qstmt = "SELECT trigger_id FROM trigger WHERE descr=?;" + try: + c = conn.cursor() + c.execute(qstmt, (t,)) + except sqlite3.Error as e: + print("Error getting an trigger_id by name: {} Error: {}".format(t, e)) + except: + print("Error getting an trigger_id_by_name something other than sqlite3 error") + else: + x = c.fetchone() + if x == None: + raise AssertionError('there was no trigger_id for given trigger name: {}\nYou should check to see if this trigger is in triggers.yaml and sometimes it is a straight apostrophe versus uni-code curly apostrophe.'.format(t)) + else: + return x[0] + def get_requirement_id_by_descr(r, conn): qstmt = "SELECT requirement_id FROM requirement WHERE descr=?;" try: From eab2ce558ceeb49f60b6e4e7dc5e33e8e7074a16 Mon Sep 17 00:00:00 2001 From: James Miller Date: Tue, 21 Apr 2020 21:44:14 -0500 Subject: [PATCH 9/9] I think feats are done! --- data/yaml/cleanyaml.py | 7 ++ data/yaml/feats.yaml | 8 +- data/yaml/triggers.yaml | 12 ++- gendb/gendb.py | 205 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 219 insertions(+), 13 deletions(-) diff --git a/data/yaml/cleanyaml.py b/data/yaml/cleanyaml.py index b7dee3f..6169932 100644 --- a/data/yaml/cleanyaml.py +++ b/data/yaml/cleanyaml.py @@ -33,6 +33,13 @@ def main(): # print("Before: {}".format(i['trigger'])) i['trigger'] = i['trigger'].replace('’', "'") # print("After: {}".format(i['trigger'])) + if x == "triggers.yaml": + for i in data['trigger']: + print(i) + i = i.replace('’', "'") + + + final = yaml.safe_dump(data, allow_unicode=True) with open(x, 'w') as f: f.write(final) diff --git a/data/yaml/feats.yaml b/data/yaml/feats.yaml index 45e8248..a67324c 100644 --- a/data/yaml/feats.yaml +++ b/data/yaml/feats.yaml @@ -840,6 +840,7 @@ feat: damage you deal. frequency: null has_been_manually_proofread: false + level: 1 name: Burn It! prereqs: - descr: Ancestry Level 1 @@ -1103,6 +1104,7 @@ feat: need to have cover or greater cover or be concealed to Hide or Sneak. frequency: null has_been_manually_proofread: false + level: 1 name: Very, Very Sneaky prereqs: - descr: Very Sneaky @@ -1610,7 +1612,8 @@ feat: a critical success. frequency: null has_been_manually_proofread: false - name: Cooperataive Soul + level: 9 + name: Cooperative Soul prereqs: - descr: Cooperative Nature feat: Cooperative Nature @@ -17576,7 +17579,8 @@ feat: level: 2 name: Wilderness Spotter prereqs: - - expert in Survival + - descr: expert in Survival + feat: null requirement: null source: - abbr: CRB diff --git a/data/yaml/triggers.yaml b/data/yaml/triggers.yaml index 0d1baaf..13e2839 100644 --- a/data/yaml/triggers.yaml +++ b/data/yaml/triggers.yaml @@ -1,7 +1,7 @@ trigger: - An ally ends a move action adjacent to you. - You fail a skill check or saving throw. -- You attempt a check using a skill you’re untrained in. +- You attempt a check using a skill you're untrained in. - You would be reduced to 0 Hit Points but not immediately killed. - You attempt a saving throw against a spell or magical effect, before rolling. - You bring a foe to 0 Hit Points. @@ -13,12 +13,12 @@ trigger: than your advanced alchemy level. - You craft an elixer of life using Quick Alchemy, and that elixir is at least 2 levels lower than your advanced alchemy level. -- You craft an alchemical bomb using Quick Alchemy that’s at least 2 levels lower +- You craft an alchemical bomb using Quick Alchemy that's at least 2 levels lower than your advanced alchemy level. - A foe within reach attempts to move away from you. - You take damage and are capable of entering a rage. - A creature within your reach uses a manipulate action or a move action, makes a - ranged attack, or leaves a square during a move action it’s using. + ranged attack, or leaves a square during a move action it's using. - Your melee Strike kills a creature or knocks it unconscious, and another foe is adjacent to that creature. - A creature within your reach succeeds or critically succeeds at an attack against @@ -49,7 +49,7 @@ trigger: - You are targeted with a melee attack by an attacker you can see. - Your turn ends and you have a status penalty to your Speed or are immobilized or slowed. -- An enemy's attack hits you or you fail a saving throw against an enemy’s ability. +- An enemy's attack hits you or you fail a saving throw against an enemy's ability. - Your hunted prey is within your reach, and it uses a manipulate action, uses a move action, or leaves a square during a move action it's using. - You are about to roll a Perception or Survival check for initiative. @@ -71,10 +71,12 @@ trigger: area. - A creature casts a spell that you have in your repertoire. - A creature Casts a Spell that you have prepared. -- A creature within line of sight casts a spell that you don’t have prepared or in +- A creature within line of sight casts a spell that you don't have prepared or in your spell repertoire, or a trap or similar object casts such a spell. You must be aware of the casting. - While you have your shield raised, you would take damage from a physical attack. - An adjacent creature you are hunting attempts to move away from you using an action that has the move trait. - You attempt a saving throw against a magical effect, but you haven't rolled yet. +- You are unarmored and touching the ground. +- You are unarmored. diff --git a/gendb/gendb.py b/gendb/gendb.py index fdfd856..d2a1d3a 100644 --- a/gendb/gendb.py +++ b/gendb/gendb.py @@ -144,7 +144,7 @@ def do_feats(data, conn): actioncost_id INTEGER, descr TEXT NOT NULL, freq_id INTEGER, - level INTEGER NOT NULL, + level INTEGER, -- TODO Make not null once issue 88 is resolved name TEXT NOT NULL UNIQUE, requirement_id INTEGER, trigger_id INTEGER, @@ -157,8 +157,46 @@ def do_feats(data, conn): c = conn.cursor() c.execute(table) + table = """ +CREATE TABLE sourceentry_feat ( + id INTEGER PRIMARY KEY, + sourceentry_id INTEGER NOT NULL, + feat_id INTEGER NOT NULL, + UNIQUE (sourceentry_id, feat_id), -- prevent duplicates + FOREIGN KEY (sourceentry_id) REFERENCES sourceentry(sourceentry_id), + FOREIGN KEY (feat_id) REFERENCES feat(feat_id) +); + """ + c = conn.cursor() + c.execute(table) + + table = """ + CREATE TABLE trait_feat ( + id INTEGER PRIMARY KEY, + trait_id INTEGER NOT NULL, + feat_id INTEGER NOT NULL, + UNIQUE(trait_id, feat_id), + FOREIGN KEY (feat_id) REFERENCES feat(feat_id), + FOREIGN KEY (trait_id) REFERENCES trait(trait_id) + ); + """ + c.execute(table) + + table = """ + CREATE TABLE featprereq ( + featprereq_id INTEGER PRIMARY KEY, + descr TEXT NOT NULL, + parent_feat_id INTEGER NOT NULL, -- THE FEAT THAT REQUIRES THE PREREQ + is_prereq_feat_bool BOOL NOT NULL, -- THIS TELLS YOU THAT THE PREREQ ITSELF IS A FEAT + prereq_feat_id INTEGER, -- THIS IS THE PREREQ FEAT, NOT THE FEAT THAT REQUIRES THE PREREQ, if is_prereq_feat_bool == FALSE then this will also be null + FOREIGN KEY (prereq_feat_id) REFERENCES feat(feat_id), + FOREIGN KEY (parent_feat_id) REFERENCES feat(feat_id) + ); + """ + c.execute(table) feat_result_list = [] + feats_no_levels = [] for i in data['feat']: if i['actioncost'] == None: ac_id = None @@ -178,10 +216,163 @@ def do_feats(data, conn): t_id = None else: t_id = get_trigger_id_by_descr(i['trigger'], conn) + if 'level' not in i: + resl = {'name': i['name'], 'source': i['source']} + feats_no_levels.append(resl) + i['level'] = None - # res = (ac_id, i['descr'], f_id, i['level'], i['name'], r_id, t_id) + + + res = (ac_id, i['descr'], f_id, i['level'], i['name'], r_id, t_id) + feat_result_list.append(res) insert_stmt = "INSERT INTO feat (actioncost_id, descr, freq_id, level, name, requirement_id, trigger_id) VALUES (?,?,?,?,?,?,?);" + try: + conn.executemany(insert_stmt, feat_result_list) + except sqlite3.Error as e: + print("Error creating feats: {}".format(e)) + except: + print("Error creating feats something other than sqlite3 error") + else: + conn.commit() + + print("\n\nWARNING!\n\nThe following feats do not have level information and need to be manually checked!:\n") + for i in feats_no_levels: + print(i) + + # go through and do source entry linking + + for i in data['feat']: + # print("\n\nDoing the skill: {}".format(i['name'])) + srcs = [] + # TODO refactor this inner loop for sources out + for j in i['source']: + abbr = j['abbr'] + page_start = j['page_start'] + if 'page_stop' in j: + page_stop = j['page_stop'] + else: + page_stop = page_start + srcs.append([i['name'], abbr, page_start, page_stop]) + # print("srcs: {}".format(srcs)) + do_sourceentry_to_feats(srcs, conn) + + # do traits + for i in data['feat']: + traitlist = [] + if i['traits'] != None: + for j in i['traits']: + traitlist.append((i['name'], j)) + # print("traitlist is:\t{}".format(traitlist)) + + stmt = """ + INSERT INTO trait_feat (feat_id, trait_id) VALUES ( + (SELECT feat_id FROM feat WHERE name=?), + (SELECT trait_id FROM trait WHERE short_name=?) + ); + """ + try: + conn.executemany(stmt, traitlist) + except sqlite3.Error as e: + print("Error creating feat_trait: {}".format(e)) + except: + print( + "Error creating feat_trait something other than sqlite3 error" + ) + else: + conn.commit() + + # do prereqs + for i in data['feat']: + # print("\nDoing prereq:\t{}".format(i['name'])) + if i['prereqs'] == None: + # do nothing and start on next 'i' + # print("Continuing prereqs, skipping:\t{}".format(i['name'])) + continue + preqlist = [] + for j in i['prereqs']: + descr = j['descr'] + pfeat = j['feat'] + if pfeat == None: + is_feat_bool = False + else: + is_feat_bool = True + res = (descr, i['name'], is_feat_bool, pfeat) + preqlist.append(res) + # print(preqlist) + + # now to do the insert + istmt = """ + INSERT INTO featprereq (descr, parent_feat_id, is_prereq_feat_bool, prereq_feat_id) + VALUES ( + ?, + (SELECT feat_id FROM feat WHERE name=?), + ?, + (SELECT feat_id FROM feat WHERE name=?) + ) + """ + try: + conn.executemany(istmt, preqlist) + except sqlite3.Error as e: + print("Error creating featprereq {}".format(e)) + except: + print( + "Error creating featprereq something other than sqlite3 error" + ) + else: + conn.commit() + +# TODO ugggh;;; this is soooo ugly and needs refactoring but it's working +def do_sourceentry_to_feats(srcs, conn): + c = conn.cursor() + + stmt = "SELECT source.source_id, feat.feat_id FROM source, feat WHERE source.abbr=? AND feat.name=?" + istmt = "INSERT INTO sourceentry (source_id, page_start, page_stop) VALUES (?,?,?)" + for i in srcs: + # print("i in srcs: {}".format(i)) + inp_data = (i[1], i[0]) + # print("inp data: {}".format(inp_data)) + for row in c.execute(stmt, inp_data): + # print("source_id:{} skill_id:{}".format(row[0], row[1])) + iinp_data = (row[0], i[2], i[3]) + # print("iinp data: {}".format(iinp_data)) + + try: + c.execute(istmt, iinp_data) + except sqlite3.IntegrityError as e: + if "UNIQUE" in str(e): + # we fully expect UNIQUE constraint to fail on some of these so it's fine + conn.commit() + # print("committed istmt") + else: + # but we still want to know what's going on if there's some other error + print("Something went wrong with istmt: {}".format(e)) + except sqlite3.Error as e: + print("Error inserting a sourceentry for skill: {}".format(e)) + else: + conn.commit() + # print("committed istmt") + + linkstmt = "INSERT INTO sourceentry_feat (sourceentry_id, feat_id) VALUES ((SELECT sourceentry_id from sourceentry WHERE source_id=? AND page_start=? AND page_stop=?), ?)" + linkinp_data = (row[0], i[2], i[3], row[1]) + # print(linkinp_data) + try: + c.execute(linkstmt, linkinp_data) + except sqlite3.IntegrityError as e: + if "UNIQUE" in str(e): + # we fully expect UNIQUE constraint to fail on some of these so it's fine + conn.commit() + # print("committed linkstmt") + pass + else: + # but we still want to know what's going on if there's some other error + print(e) + except sqlite3.Error as e: + print("Error inserting a sourceentry for feat: {}".format(e)) + else: + # print("committed linkstmt") + conn.commit() + def get_trigger_id_by_descr(t, conn): qstmt = "SELECT trigger_id FROM trigger WHERE descr=?;" @@ -321,7 +512,7 @@ def do_ancestries(data, conn): c.execute(table) table = """ - CREATE TABLE ancestries_traits ( + CREATE TABLE trait_ancestries ( id INTEGER PRIMARY KEY, ancestry_id INTEGER NOT NULL, trait_id INTEGER NOT NULL, @@ -332,6 +523,7 @@ def do_ancestries(data, conn): """ c.execute(table) + # insert basics into ancestries table inp_data = [] for i in data['ancestries']: @@ -430,7 +622,7 @@ def do_ancestries(data, conn): # print("traitlist is:\t{}".format(traitlist)) stmt = """ - INSERT INTO ancestries_traits (ancestry_id, trait_id) VALUES ( + INSERT INTO trait_ancestries (ancestry_id, trait_id) VALUES ( (SELECT ancestry_id FROM ancestries WHERE name=?), (SELECT trait_id FROM trait WHERE short_name=?) ); @@ -438,15 +630,16 @@ def do_ancestries(data, conn): try: conn.executemany(stmt, traitlist) except sqlite3.Error as e: - print("Error creating ancestries_traits: {}".format(e)) + print("Error creating trait_ancestries {}".format(e)) except: print( - "Error creating ancestries_traits something other than sqlite3 error" + "Error creating trait_ancestries something other than sqlite3 error" ) else: conn.commit() + def do_gear(data, conn): table = """ CREATE TABLE gear(