|
|
@ -1,9 +1,7 @@ |
|
|
|
import random |
|
|
|
import random |
|
|
|
import json |
|
|
|
import json |
|
|
|
|
|
|
|
|
|
|
|
# TODO AC? Or Gold Start no AC? |
|
|
|
# Constants Lists |
|
|
|
# TODO Feats? |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOWELS = ["A", "E", "I", "O", "U"] |
|
|
|
VOWELS = ["A", "E", "I", "O", "U"] |
|
|
|
|
|
|
|
|
|
|
|
SKILL_LIST = ["acrobatics", "animal_handling", "arcana", "athletics", "deception", "history", "insight", "intimidation", |
|
|
|
SKILL_LIST = ["acrobatics", "animal_handling", "arcana", "athletics", "deception", "history", "insight", "intimidation", |
|
|
@ -12,24 +10,13 @@ SKILL_LIST = ["acrobatics", "animal_handling", "arcana", "athletics", "deception |
|
|
|
|
|
|
|
|
|
|
|
ATTRIBUTE_LIST = ["strength", "dexterity", "wisdom", "constitution", "intelligence", "charisma"] |
|
|
|
ATTRIBUTE_LIST = ["strength", "dexterity", "wisdom", "constitution", "intelligence", "charisma"] |
|
|
|
|
|
|
|
|
|
|
|
CLASS_LIST = ["Artificer", "Barbarian", "Bard", "Cleric", "Druid", "Fighter", "Monk", "Paladin", |
|
|
|
JOB_LIST = ["Artificer", "Barbarian", "Bard", "Cleric", "Druid", "Fighter", "Monk", "Paladin", |
|
|
|
"Ranger", "Rogue", "Sorcerer", "Warlock", "Wizard", "Blood Hunter"] |
|
|
|
"Ranger", "Rogue", "Sorcerer", "Warlock", "Wizard", "Blood Hunter"] |
|
|
|
|
|
|
|
|
|
|
|
BACKGROUND_LIST = ["Acolyte", "Charlatan", "Criminal / Spy", "Entertainer", "Folk Hero", "Gladiator", |
|
|
|
BACKGROUND_LIST = ["Acolyte", "Charlatan", "Criminal / Spy", "Entertainer", "Folk Hero", "Gladiator", |
|
|
|
"Guild Artisan / Guild Merchant", "Hermit", "Knight", "Noble", "Outlander", "Pirate", "Sage", |
|
|
|
"Guild Artisan / Guild Merchant", "Hermit", "Knight", "Noble", "Outlander", "Pirate", "Sage", |
|
|
|
"Sailor", "Soldier", "Urchin", ] |
|
|
|
"Sailor", "Soldier", "Urchin", ] |
|
|
|
|
|
|
|
|
|
|
|
instrument_list = ["Bagpipes", "Birdpipes", "Clarinet", "Drum", "Dulcimer", "Fiddle", "Flute", "Glaur", "Hand Drum", |
|
|
|
|
|
|
|
"Harp", "Horn", "Longhorn", "Lute", "Lyre", "Pan Flute", "Shawm", "Songhorn", "Tantan", "Thelarr", |
|
|
|
|
|
|
|
"Tocken", "Trumpet", "Viol", "Wargong", "Yarting", "Zulkoon"] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
languages = ["Aarakocra", "Abyssal", "Aquan", "Auran", "Celestial", "Deep Speech", "Draconic", "Dwarvish", "Elvish", |
|
|
|
|
|
|
|
"Giant", |
|
|
|
|
|
|
|
"Gith", "Gnomish", "Goblin", "Halfling", "Infernal", "Orc", "Primordial", "Sylvan", "Undercommon", |
|
|
|
|
|
|
|
"Vedalken"] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
known_language_list = ["Common"] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GAMING_SETS = ["Bowls", "Darts", "Dice Set", "Dragonchess Set", "Playing Card Set", "Quoits", "Three-Dragon Ante Set"] |
|
|
|
GAMING_SETS = ["Bowls", "Darts", "Dice Set", "Dragonchess Set", "Playing Card Set", "Quoits", "Three-Dragon Ante Set"] |
|
|
|
|
|
|
|
|
|
|
|
ARTISANS_TOOLS = ["Alchemist's Supplies", "Brewer's Supplies", "Calligrapher's Supplies", "Carpenter's Tools", |
|
|
|
ARTISANS_TOOLS = ["Alchemist's Supplies", "Brewer's Supplies", "Calligrapher's Supplies", "Carpenter's Tools", |
|
|
@ -48,21 +35,33 @@ WIZARD_SUBCLASSES = ["Bladesinging", "Chronurgy Magic", "Graviturgy Magic", "Ord |
|
|
|
"School of Conjuration", "School of Divination", "School of Enchantment", "School of Evocation", |
|
|
|
"School of Conjuration", "School of Divination", "School of Enchantment", "School of Evocation", |
|
|
|
"School of Illusion", "School of Necromancy", "School of Transmutation", "War Magic"] |
|
|
|
"School of Illusion", "School of Necromancy", "School of Transmutation", "War Magic"] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Variable/Functional Lists |
|
|
|
|
|
|
|
instrument_list = ["Bagpipes", "Birdpipes", "Clarinet", "Drum", "Dulcimer", "Fiddle", "Flute", "Glaur", "Hand Drum", |
|
|
|
|
|
|
|
"Harp", "Horn", "Longhorn", "Lute", "Lyre", "Pan Flute", "Shawm", "Songhorn", "Tantan", "Thelarr", |
|
|
|
|
|
|
|
"Tocken", "Trumpet", "Viol", "Wargong", "Yarting", "Zulkoon"] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
languages = ["Aarakocra", "Abyssal", "Aquan", "Auran", "Celestial", "Deep Speech", "Draconic", "Dwarvish", "Elvish", |
|
|
|
|
|
|
|
"Giant", "Gith", "Gnomish", "Goblin", "Halfling", "Infernal", "Orc", "Primordial", "Sylvan", "Undercommon", |
|
|
|
|
|
|
|
"Vedalken"] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
known_language_list = ["Common"] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Begin the class for creation |
|
|
|
class HeroCreation: |
|
|
|
class HeroCreation: |
|
|
|
def __init__(self): |
|
|
|
def __init__(self): |
|
|
|
self.name_generation() |
|
|
|
self.name_generation() |
|
|
|
self.race_selection() |
|
|
|
self.race_selection() |
|
|
|
self.race = self.race_string["Race"] |
|
|
|
self.race = self.race_dict["Race"] |
|
|
|
# 'job' is used in place of 'class' to avoid a function conflict |
|
|
|
# 'job' is used in place of 'class' to avoid a function conflict |
|
|
|
self.job = random.choice(CLASS_LIST) |
|
|
|
self.job = random.choice(JOB_LIST) |
|
|
|
self.job_characteristics() |
|
|
|
self.job_characteristics() |
|
|
|
self.background = random.choice(BACKGROUND_LIST) |
|
|
|
self.background = random.choice(BACKGROUND_LIST) |
|
|
|
self.stat_rolls() |
|
|
|
self.stat_rolls() |
|
|
|
self.racial_bonuses() |
|
|
|
self.racial_bonuses() |
|
|
|
self.speed = self.race_string["Speed"] |
|
|
|
self.speed = self.race_dict["Speed"] |
|
|
|
self.article = self.grammar() |
|
|
|
|
|
|
|
self.skill_generation() |
|
|
|
self.skill_generation() |
|
|
|
self.skill_proficiency() |
|
|
|
self.skill_proficiency() |
|
|
|
|
|
|
|
#Initial configuration of tool proficiencies. These are left alone if none are selected. |
|
|
|
self.instruments = "None" |
|
|
|
self.instruments = "None" |
|
|
|
self.artisan_tools = "None" |
|
|
|
self.artisan_tools = "None" |
|
|
|
self.additional_tools = "None" |
|
|
|
self.additional_tools = "None" |
|
|
@ -72,51 +71,29 @@ class HeroCreation: |
|
|
|
self.background_proficiencies() |
|
|
|
self.background_proficiencies() |
|
|
|
self.finalize_languages() |
|
|
|
self.finalize_languages() |
|
|
|
self.apply_skill_modifiers("dexterity", "initiative") |
|
|
|
self.apply_skill_modifiers("dexterity", "initiative") |
|
|
|
self.whoami() |
|
|
|
self.print_generator() |
|
|
|
self.stat_block = (f"Stat Block\n----------\nCharisma: {self.charisma}\nConstitution: {self.constitution}\n" |
|
|
|
self.output() |
|
|
|
f"Dexterity: {self.dexterity}\nIntelligence: {self.intelligence}\n" |
|
|
|
|
|
|
|
f"Strength: {self.strength}\nWisdom: {self.wisdom}\n") |
|
|
|
# Selects two random entries from a large text file containing fantasy names. |
|
|
|
self.saves = (f"Saving Throws\n----------\nCharisma Save: {self.charisma_save}\n" |
|
|
|
def name_generation(self): |
|
|
|
f"Constitution Save: {self.constitution_save}\n" |
|
|
|
with open("names.txt", "r") as f: |
|
|
|
f"Dexterity Save: {self.dexterity_save}\n" |
|
|
|
name_list = f.read().splitlines() |
|
|
|
f"Intelligence Save: {self.intelligence_save}\n" |
|
|
|
first_name = random.choice(name_list) |
|
|
|
f"Strength Save: {self.strength_save}\n" |
|
|
|
sur_name = random.choice(name_list) |
|
|
|
f"Wisdom Save: {self.wisdom_save}\n") |
|
|
|
combined_name = f"{first_name} {sur_name}" |
|
|
|
self.additional_stats = ( |
|
|
|
setattr(self, "name", combined_name) |
|
|
|
f"Additional Stats\n----------\nStarting HP: {self.starting_hp}\nHit Die: {self.hit_die}\n" |
|
|
|
|
|
|
|
f"Initiative Bonus: {self.initiative}\nSpeed: {self.speed}\n") |
|
|
|
|
|
|
|
self.skill_bonuses = ( |
|
|
|
|
|
|
|
f"Skill Bonuses\n----------\nAcrobatics: {self.acrobatics}\nAnimal Handling: {self.animal_handling}" |
|
|
|
|
|
|
|
f"\nArcana: {self.arcana}\nAthletics: {self.athletics}\nDeception: {self.deception}" |
|
|
|
|
|
|
|
f"\nHistory: {self.history}\nInsight: {self.insight}\nIntimidation: {self.intimidation}" |
|
|
|
|
|
|
|
f"\nInvestigation: {self.investigation}\nMedicine: {self.medicine}\nNature: {self.nature}" |
|
|
|
|
|
|
|
f"\nPerception: {self.perception}\nPerformance: {self.performance}\nPersuasion: {self.persuasion}" |
|
|
|
|
|
|
|
f"\nReligion: {self.religion}\nSleight of Hand: {self.sleight_of_hand}" |
|
|
|
|
|
|
|
f"\nStealth: {self.stealth}\nSurvival: {self.survival}\n") |
|
|
|
|
|
|
|
self.other_proficiencies = (f"Additional Proficiencies\n----------\n" |
|
|
|
|
|
|
|
f"Languages: {self.languages}\n" |
|
|
|
|
|
|
|
f"Instruments: {self.instruments}\n" |
|
|
|
|
|
|
|
f"Artisan's Tools: {self.artisan_tools}\nAdditional Tools: " |
|
|
|
|
|
|
|
f"{self.additional_tools}\n" |
|
|
|
|
|
|
|
f"Weapon Proficiencies: {self.weapon_proficiency}\n" |
|
|
|
|
|
|
|
f"Armor Proficiencies: {self.armor_proficiency}\n") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Assign the correct a/an article in the 'whoami' attr |
|
|
|
|
|
|
|
def grammar(self): |
|
|
|
|
|
|
|
if self.race[0] in VOWELS: |
|
|
|
|
|
|
|
return "an" |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
return "a" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Chooses race at random. Each race has a dictionary with other assigned values/proficiencies |
|
|
|
|
|
|
|
# Things like attribute bonuses or language proficiencies come from this dictionary |
|
|
|
def race_selection(self): |
|
|
|
def race_selection(self): |
|
|
|
with open('races.json') as json_file: |
|
|
|
with open('races.json') as json_file: |
|
|
|
race_data = json.load(json_file) |
|
|
|
race_data = json.load(json_file) |
|
|
|
chosen_race = random.choice(race_data) |
|
|
|
chosen_race = random.choice(race_data) |
|
|
|
setattr(self, "race_string", chosen_race) |
|
|
|
setattr(self, "race_dict", chosen_race) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Rolls the 6 main attributes in the style of roll for d6, drop the lowest. |
|
|
|
|
|
|
|
# Configured to "Re-roll" 1s. To include 1s, increase the randint range to 1,6 |
|
|
|
def stat_rolls(self): |
|
|
|
def stat_rolls(self): |
|
|
|
# Configured to "Re-roll" 1s |
|
|
|
|
|
|
|
# To include 1s, increase the randint range to 1,6 |
|
|
|
|
|
|
|
for attribute in ATTRIBUTE_LIST: |
|
|
|
for attribute in ATTRIBUTE_LIST: |
|
|
|
roll_list = [] |
|
|
|
roll_list = [] |
|
|
|
for each in range(4): |
|
|
|
for each in range(4): |
|
|
@ -125,22 +102,14 @@ class HeroCreation: |
|
|
|
stat_total = sum(roll_list) |
|
|
|
stat_total = sum(roll_list) |
|
|
|
setattr(self, f"{attribute}", stat_total) |
|
|
|
setattr(self, f"{attribute}", stat_total) |
|
|
|
|
|
|
|
|
|
|
|
# Assign racial stat bonuses |
|
|
|
# Assign racial stat bonuses from the race_dict pulled from races.json |
|
|
|
def racial_bonuses(self): |
|
|
|
def racial_bonuses(self): |
|
|
|
self.charisma += self.race_string["Charisma"] |
|
|
|
self.charisma += self.race_dict["Charisma"] |
|
|
|
self.constitution += self.race_string["Constitution"] |
|
|
|
self.constitution += self.race_dict["Constitution"] |
|
|
|
self.dexterity += self.race_string["Dexterity"] |
|
|
|
self.dexterity += self.race_dict["Dexterity"] |
|
|
|
self.intelligence += self.race_string["Intelligence"] |
|
|
|
self.intelligence += self.race_dict["Intelligence"] |
|
|
|
self.strength += self.race_string["Strength"] |
|
|
|
self.strength += self.race_dict["Strength"] |
|
|
|
self.wisdom += self.race_string["Wisdom"] |
|
|
|
self.wisdom += self.race_dict["Wisdom"] |
|
|
|
|
|
|
|
|
|
|
|
def name_generation(self): |
|
|
|
|
|
|
|
with open("names.txt", "r") as f: |
|
|
|
|
|
|
|
name_list = f.read().splitlines() |
|
|
|
|
|
|
|
first_name = random.choice(name_list) |
|
|
|
|
|
|
|
sur_name = random.choice(name_list) |
|
|
|
|
|
|
|
combined_name = f"{first_name} {sur_name}" |
|
|
|
|
|
|
|
setattr(self, "name", combined_name) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Created skill attributes and save attributes with a base value of +0 to the roll |
|
|
|
# Created skill attributes and save attributes with a base value of +0 to the roll |
|
|
|
def skill_generation(self): |
|
|
|
def skill_generation(self): |
|
|
@ -162,6 +131,8 @@ class HeroCreation: |
|
|
|
setattr(self, save_name, 0) |
|
|
|
setattr(self, save_name, 0) |
|
|
|
self.apply_skill_modifiers(attribute, save_name) |
|
|
|
self.apply_skill_modifiers(attribute, save_name) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Receives input for all skills and saves and applies a modifier to the roll based on the associated |
|
|
|
|
|
|
|
# attribute value |
|
|
|
def apply_skill_modifiers(self, attribute_name, skill_name): |
|
|
|
def apply_skill_modifiers(self, attribute_name, skill_name): |
|
|
|
attribute = getattr(self, attribute_name) |
|
|
|
attribute = getattr(self, attribute_name) |
|
|
|
if attribute == 1: |
|
|
|
if attribute == 1: |
|
|
@ -191,27 +162,32 @@ class HeroCreation: |
|
|
|
setattr(self, skill_name, modifier) |
|
|
|
setattr(self, skill_name, modifier) |
|
|
|
|
|
|
|
|
|
|
|
def skill_proficiency(self): |
|
|
|
def skill_proficiency(self): |
|
|
|
|
|
|
|
# Pulls the available skills that each background is proficient in and applies a +2 proficiency modifier |
|
|
|
with open('backgrounds.json') as json_file: |
|
|
|
with open('backgrounds.json') as json_file: |
|
|
|
background_data = json.load(json_file) |
|
|
|
background_data = json.load(json_file) |
|
|
|
# Is this actually a dict? |
|
|
|
background_list = background_data[self.background]["Skills"] |
|
|
|
background_dict = background_data[self.background]["Skills"] |
|
|
|
for skill in background_list: |
|
|
|
for skill in background_dict: |
|
|
|
|
|
|
|
current_score = getattr(self, skill) |
|
|
|
current_score = getattr(self, skill) |
|
|
|
new_score = str(current_score + 2) |
|
|
|
new_score = str(current_score + 2) |
|
|
|
setattr(self, skill, f"{new_score} (Prof)") |
|
|
|
setattr(self, skill, f"{new_score} (Prof)") |
|
|
|
|
|
|
|
# Pulls the available skills that each job can choose to be proficient in |
|
|
|
with open('jobs.json') as json_file: |
|
|
|
with open('jobs.json') as json_file: |
|
|
|
job_data = json.load(json_file) |
|
|
|
job_data = json.load(json_file) |
|
|
|
# Is this actually a dict? |
|
|
|
|
|
|
|
job_dict = job_data[self.job] |
|
|
|
job_dict = job_data[self.job] |
|
|
|
|
|
|
|
# Pulls the number of proficiencies able to be chosen |
|
|
|
proficiencies = job_dict["Proficiencies"] |
|
|
|
proficiencies = job_dict["Proficiencies"] |
|
|
|
|
|
|
|
# Pulls available skills to be proficient in |
|
|
|
job_skill_list = job_dict["Skills"] |
|
|
|
job_skill_list = job_dict["Skills"] |
|
|
|
for skill in background_dict: |
|
|
|
# Removes any skills chosen by background proficiencies, so they can not be chosen as double proficient. |
|
|
|
|
|
|
|
for skill in background_list: |
|
|
|
if skill in job_skill_list: |
|
|
|
if skill in job_skill_list: |
|
|
|
job_skill_list.remove(skill) |
|
|
|
job_skill_list.remove(skill) |
|
|
|
# rogue list for expertise calculation |
|
|
|
# Rogue list for expertise calculation (Rogues get one double proficiency at level 1) |
|
|
|
rogue_proficient_list = [] |
|
|
|
rogue_proficient_list = [] |
|
|
|
|
|
|
|
# Choose proficient skills and add a +2 modifier for the level 1 proficiency bonus. |
|
|
|
for each in range(proficiencies): |
|
|
|
for each in range(proficiencies): |
|
|
|
proficient_skill = random.choice(job_skill_list) |
|
|
|
proficient_skill = random.choice(job_skill_list) |
|
|
|
|
|
|
|
# Chooses rogue proficiencies and saves them to a list for expertise selection |
|
|
|
if self.job == "Rogue": |
|
|
|
if self.job == "Rogue": |
|
|
|
rogue_proficient_list.append(proficient_skill) |
|
|
|
rogue_proficient_list.append(proficient_skill) |
|
|
|
job_skill_list.remove(proficient_skill) |
|
|
|
job_skill_list.remove(proficient_skill) |
|
|
@ -219,12 +195,14 @@ class HeroCreation: |
|
|
|
setattr(self, f"{proficient_skill}_base_value", current_score) |
|
|
|
setattr(self, f"{proficient_skill}_base_value", current_score) |
|
|
|
new_score = str(current_score + 2) |
|
|
|
new_score = str(current_score + 2) |
|
|
|
setattr(self, proficient_skill, f"{new_score} (Prof)") |
|
|
|
setattr(self, proficient_skill, f"{new_score} (Prof)") |
|
|
|
|
|
|
|
# Selects one proficient skill to be chosen for expertise for rogues. |
|
|
|
if self.job == "Rogue": |
|
|
|
if self.job == "Rogue": |
|
|
|
expertise_skill = random.choice(rogue_proficient_list) |
|
|
|
expertise_skill = random.choice(rogue_proficient_list) |
|
|
|
score_value = getattr(self, f"{expertise_skill}_base_value") |
|
|
|
score_value = getattr(self, f"{expertise_skill}_base_value") |
|
|
|
new_score = score_value + 4 |
|
|
|
new_score = score_value + 4 |
|
|
|
setattr(self, expertise_skill, f"{new_score} (Expertise)") |
|
|
|
setattr(self, expertise_skill, f"{new_score} (Expertise)") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Assigns additional stats from the job dictionary |
|
|
|
def job_characteristics(self): |
|
|
|
def job_characteristics(self): |
|
|
|
with open('jobs.json') as json_file: |
|
|
|
with open('jobs.json') as json_file: |
|
|
|
job_data = json.load(json_file) |
|
|
|
job_data = json.load(json_file) |
|
|
@ -233,9 +211,11 @@ class HeroCreation: |
|
|
|
starting_hp_value = job_data[self.job]["Starting HP"] |
|
|
|
starting_hp_value = job_data[self.job]["Starting HP"] |
|
|
|
setattr(self, "starting_hp", starting_hp_value) |
|
|
|
setattr(self, "starting_hp", starting_hp_value) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#Assigns language and tool proficiencies based on job |
|
|
|
def job_proficiencies(self): |
|
|
|
def job_proficiencies(self): |
|
|
|
with open('jobs.json') as json_file: |
|
|
|
with open('jobs.json') as json_file: |
|
|
|
job_data = json.load(json_file) |
|
|
|
job_data = json.load(json_file) |
|
|
|
|
|
|
|
# Monk receives a choice of instrument tool or artisan tool. This selects one at random. |
|
|
|
if self.job == "Monk": |
|
|
|
if self.job == "Monk": |
|
|
|
tool_choice = random.randint(0, 1) |
|
|
|
tool_choice = random.randint(0, 1) |
|
|
|
if tool_choice == 0: |
|
|
|
if tool_choice == 0: |
|
|
@ -243,6 +223,7 @@ class HeroCreation: |
|
|
|
else: |
|
|
|
else: |
|
|
|
artisan_tool_value = 1 |
|
|
|
artisan_tool_value = 1 |
|
|
|
else: |
|
|
|
else: |
|
|
|
|
|
|
|
# Attempt to pull number of proficiencies for each job. Some have none in these values. |
|
|
|
try: |
|
|
|
try: |
|
|
|
instrument_value = job_data[self.job]["Instruments"] |
|
|
|
instrument_value = job_data[self.job]["Instruments"] |
|
|
|
except KeyError: |
|
|
|
except KeyError: |
|
|
@ -251,8 +232,10 @@ class HeroCreation: |
|
|
|
artisan_tool_value = job_data[self.job]["Artisan's Tools"] |
|
|
|
artisan_tool_value = job_data[self.job]["Artisan's Tools"] |
|
|
|
except KeyError: |
|
|
|
except KeyError: |
|
|
|
pass |
|
|
|
pass |
|
|
|
|
|
|
|
# Empty list creation for tools and instruments. May not be populated. |
|
|
|
instrument_prof_list = [] |
|
|
|
instrument_prof_list = [] |
|
|
|
artisan_prof_list = [] |
|
|
|
artisan_prof_list = [] |
|
|
|
|
|
|
|
# Attempts to assign random tool values, assuming the job has any proficiencies available |
|
|
|
try: |
|
|
|
try: |
|
|
|
for value in range(0, instrument_value): |
|
|
|
for value in range(0, instrument_value): |
|
|
|
new_instrument = random.choice(instrument_list) |
|
|
|
new_instrument = random.choice(instrument_list) |
|
|
@ -277,25 +260,30 @@ class HeroCreation: |
|
|
|
setattr(self, "additional_tools", str(additional_tool_string)) |
|
|
|
setattr(self, "additional_tools", str(additional_tool_string)) |
|
|
|
except KeyError: |
|
|
|
except KeyError: |
|
|
|
pass |
|
|
|
pass |
|
|
|
|
|
|
|
# Set Armor proficiencies and update the attribute |
|
|
|
armor_prof_list = job_data[self.job]["Armor Proficiency"] |
|
|
|
armor_prof_list = job_data[self.job]["Armor Proficiency"] |
|
|
|
if not armor_prof_list: |
|
|
|
if not armor_prof_list: |
|
|
|
setattr(self, "armor_proficiency", "None") |
|
|
|
setattr(self, "armor_proficiency", "None") |
|
|
|
else: |
|
|
|
else: |
|
|
|
armor_prof_string = ", ".join(armor_prof_list) |
|
|
|
armor_prof_string = ", ".join(armor_prof_list) |
|
|
|
setattr(self, "armor_proficiency", armor_prof_string) |
|
|
|
setattr(self, "armor_proficiency", armor_prof_string) |
|
|
|
|
|
|
|
# Set Weapon proficiencies and update the attribute |
|
|
|
weapon_prof_list = job_data[self.job]["Weapon Proficiency"] |
|
|
|
weapon_prof_list = job_data[self.job]["Weapon Proficiency"] |
|
|
|
weapon_prof_string = ", ".join(weapon_prof_list) |
|
|
|
weapon_prof_string = ", ".join(weapon_prof_list) |
|
|
|
setattr(self, "weapon_proficiency", weapon_prof_string) |
|
|
|
setattr(self, "weapon_proficiency", weapon_prof_string) |
|
|
|
|
|
|
|
#Add proficiency modifier of +2 to both saving throws that each job is proficient with. |
|
|
|
for attribute in job_data[self.job]["Saving Throws"]: |
|
|
|
for attribute in job_data[self.job]["Saving Throws"]: |
|
|
|
current_score = getattr(self, f"{attribute}_save") |
|
|
|
current_score = getattr(self, f"{attribute}_save") |
|
|
|
new_score = str(current_score + 2) |
|
|
|
new_score = str(current_score + 2) |
|
|
|
setattr(self, f"{attribute}_save", f"{new_score} (Prof)") |
|
|
|
setattr(self, f"{attribute}_save", f"{new_score} (Prof)") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Assigns tool and instrument proficiencies based on background |
|
|
|
def background_proficiencies(self): |
|
|
|
def background_proficiencies(self): |
|
|
|
|
|
|
|
# Importing list that starts with only "Common" and will be added to |
|
|
|
global known_language_list |
|
|
|
global known_language_list |
|
|
|
with open('backgrounds.json') as json_file: |
|
|
|
with open('backgrounds.json') as json_file: |
|
|
|
background_data = json.load(json_file) |
|
|
|
background_data = json.load(json_file) |
|
|
|
# background instrument proficiencies |
|
|
|
# Attempt instrument proficiencies (if any are available) |
|
|
|
try: |
|
|
|
try: |
|
|
|
instrument_value = background_data[self.background]["Additional Proficiencies"]["Instrument"] |
|
|
|
instrument_value = background_data[self.background]["Additional Proficiencies"]["Instrument"] |
|
|
|
except KeyError or UnboundLocalError: |
|
|
|
except KeyError or UnboundLocalError: |
|
|
@ -307,7 +295,7 @@ class HeroCreation: |
|
|
|
setattr(self, "instruments", f"{new_instrument}") |
|
|
|
setattr(self, "instruments", f"{new_instrument}") |
|
|
|
else: |
|
|
|
else: |
|
|
|
setattr(self, "instruments", current_instruments + f", {new_instrument}") |
|
|
|
setattr(self, "instruments", current_instruments + f", {new_instrument}") |
|
|
|
# background artisan's tools proficiencies |
|
|
|
# Attempt artisan's tool proficiencies (if any are available) |
|
|
|
try: |
|
|
|
try: |
|
|
|
tool_value = background_data[self.background]["Additional Proficiencies"]["Artisan's Tool"] |
|
|
|
tool_value = background_data[self.background]["Additional Proficiencies"]["Artisan's Tool"] |
|
|
|
except KeyError or UnboundLocalError: |
|
|
|
except KeyError or UnboundLocalError: |
|
|
@ -319,7 +307,7 @@ class HeroCreation: |
|
|
|
setattr(self, "artisan_tools", f"{new_tool}") |
|
|
|
setattr(self, "artisan_tools", f"{new_tool}") |
|
|
|
else: |
|
|
|
else: |
|
|
|
setattr(self, "artisan_tools", current_tools + f", {new_tool}") |
|
|
|
setattr(self, "artisan_tools", current_tools + f", {new_tool}") |
|
|
|
# language proficiencies |
|
|
|
# Attempt language proficiencies (if any are available) |
|
|
|
try: |
|
|
|
try: |
|
|
|
language_value = background_data[self.background]["Additional Proficiencies"]["Languages"] |
|
|
|
language_value = background_data[self.background]["Additional Proficiencies"]["Languages"] |
|
|
|
except UnboundLocalError: |
|
|
|
except UnboundLocalError: |
|
|
@ -331,7 +319,7 @@ class HeroCreation: |
|
|
|
languages.remove(new_language) |
|
|
|
languages.remove(new_language) |
|
|
|
except IndexError: |
|
|
|
except IndexError: |
|
|
|
pass |
|
|
|
pass |
|
|
|
# additional tool proficiencies |
|
|
|
# Attempt additional tool proficiencies (if any are available) |
|
|
|
additional_tool_list = background_data[self.background]["Additional Proficiencies"]["Additional Tools"] |
|
|
|
additional_tool_list = background_data[self.background]["Additional Proficiencies"]["Additional Tools"] |
|
|
|
if not additional_tool_list: |
|
|
|
if not additional_tool_list: |
|
|
|
pass |
|
|
|
pass |
|
|
@ -347,17 +335,20 @@ class HeroCreation: |
|
|
|
new_tool_list = getattr(self, "additional_tools") + f", {tool}" |
|
|
|
new_tool_list = getattr(self, "additional_tools") + f", {tool}" |
|
|
|
setattr(self, "additional_tools", new_tool_list) |
|
|
|
setattr(self, "additional_tools", new_tool_list) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Assigns tool and instrument proficiencies based on race |
|
|
|
def race_proficiencies(self): |
|
|
|
def race_proficiencies(self): |
|
|
|
|
|
|
|
# Importing list that starts with only "Common" and will be added to |
|
|
|
global known_language_list |
|
|
|
global known_language_list |
|
|
|
|
|
|
|
# Adds racial language proficiencies |
|
|
|
try: |
|
|
|
try: |
|
|
|
known_languages = self.race_string["Languages"] |
|
|
|
known_languages = self.race_dict["Languages"] |
|
|
|
for language in known_languages: |
|
|
|
for language in known_languages: |
|
|
|
known_language_list.append(language) |
|
|
|
known_language_list.append(language) |
|
|
|
print(language) |
|
|
|
|
|
|
|
languages.remove(language) |
|
|
|
languages.remove(language) |
|
|
|
except KeyError: |
|
|
|
except KeyError: |
|
|
|
pass |
|
|
|
pass |
|
|
|
for value in range(0, self.race_string["AdditionalLanguages"]): |
|
|
|
# Attempt additional language proficiencies (if the race is able to learn additional languages) |
|
|
|
|
|
|
|
for value in range(0, self.race_dict["AdditionalLanguages"]): |
|
|
|
try: |
|
|
|
try: |
|
|
|
new_language = random.choice(languages) |
|
|
|
new_language = random.choice(languages) |
|
|
|
known_language_list.append(new_language) |
|
|
|
known_language_list.append(new_language) |
|
|
@ -365,30 +356,89 @@ class HeroCreation: |
|
|
|
except IndexError: |
|
|
|
except IndexError: |
|
|
|
pass |
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Creates and joins a string of languages using the known_language_list updated by background and race |
|
|
|
def finalize_languages(self): |
|
|
|
def finalize_languages(self): |
|
|
|
global known_language_list |
|
|
|
global known_language_list |
|
|
|
language_string = ", ".join(known_language_list) |
|
|
|
language_string = ", ".join(known_language_list) |
|
|
|
setattr(self, "languages", language_string) |
|
|
|
setattr(self, "languages", language_string) |
|
|
|
|
|
|
|
|
|
|
|
def whoami(self): |
|
|
|
# Creates attributes for the different text blocks that will be printed as an output |
|
|
|
|
|
|
|
def print_generator(self): |
|
|
|
|
|
|
|
# Grammar check for using "a" or "an" when describing which race was chosen |
|
|
|
|
|
|
|
if self.race[0] in VOWELS: |
|
|
|
|
|
|
|
setattr(self,"article","an") |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
setattr(self,"article","a") |
|
|
|
|
|
|
|
# Chooses subclass for Cleric, as they get one at level 1. Creates the "whoami" attribute |
|
|
|
if self.job == "Cleric": |
|
|
|
if self.job == "Cleric": |
|
|
|
subclass = random.choice(CLERIC_SUBCLASSES) |
|
|
|
subclass = random.choice(CLERIC_SUBCLASSES) |
|
|
|
setattr(self,"subclass",subclass) |
|
|
|
setattr(self, "subclass", subclass) |
|
|
|
print(f"Your new character is {self.name}, {self.article} {self.race} {self.job}, with the " |
|
|
|
setattr(self, "whoami", |
|
|
|
f"{self.background} background and the {self.subclass} subclass.\n") |
|
|
|
f"Your new character is {self.name}, {self.article} {self.race} {self.job}, with the " |
|
|
|
|
|
|
|
f"{self.background} background and the {self.subclass} subclass.\n") |
|
|
|
|
|
|
|
# Chooses subclass for Sorcerer, as they get one at level 1. Creates the "whoami" attribute |
|
|
|
elif self.job == "Sorcerer": |
|
|
|
elif self.job == "Sorcerer": |
|
|
|
subclass = random.choice(SORCERER_SUBCLASSES) |
|
|
|
subclass = random.choice(SORCERER_SUBCLASSES) |
|
|
|
setattr(self, "subclass", subclass) |
|
|
|
setattr(self, "subclass", subclass) |
|
|
|
print(f"Your new character is {self.name}, {self.article} {self.race} {self.job}, with the " |
|
|
|
setattr(self, "whoami", |
|
|
|
f"{self.background} background and the {self.subclass} subclass.\n") |
|
|
|
f"Your new character is {self.name}, {self.article} {self.race} {self.job}, with the " |
|
|
|
|
|
|
|
f"{self.background} background and the {self.subclass} subclass.\n") |
|
|
|
|
|
|
|
# Chooses subclass for Wizard, as they get one at level 1. Creates the "whoami" attribute |
|
|
|
elif self.job == "Wizard": |
|
|
|
elif self.job == "Wizard": |
|
|
|
subclass = random.choice(WIZARD_SUBCLASSES) |
|
|
|
subclass = random.choice(WIZARD_SUBCLASSES) |
|
|
|
setattr(self, "subclass", subclass) |
|
|
|
setattr(self, "subclass", subclass) |
|
|
|
print(f"Your new character is {self.name}, {self.article} {self.race} {self.job}, with the " |
|
|
|
setattr(self, "whoami", |
|
|
|
f"{self.background} background and the {self.subclass} subclass.\n") |
|
|
|
f"Your new character is {self.name}, {self.article} {self.race} {self.job}, with the " |
|
|
|
|
|
|
|
f"{self.background} background and the {self.subclass} subclass.\n") |
|
|
|
|
|
|
|
# For all other classes, creates the "whoami" attribute |
|
|
|
else: |
|
|
|
else: |
|
|
|
print(f"Your new character is {self.name}, {self.article} {self.race} {self.job}, with the " |
|
|
|
setattr(self, "whoami", f"Your new character is {self.name}, {self.article} {self.race} {self.job}, with the " |
|
|
|
f"{self.background} background.\n") |
|
|
|
f"{self.background} background.\n") |
|
|
|
|
|
|
|
# Create the stat_block attribute |
|
|
|
|
|
|
|
setattr(self,"stat_block", f"Stat Block\n----------\nCharisma: {self.charisma}\nConstitution: {self.constitution}\n" |
|
|
|
|
|
|
|
f"Dexterity: {self.dexterity}\nIntelligence: {self.intelligence}\n" |
|
|
|
|
|
|
|
f"Strength: {self.strength}\nWisdom: {self.wisdom}\n") |
|
|
|
|
|
|
|
# Create the saving throw attribute |
|
|
|
|
|
|
|
setattr(self, "saves", "Saving Throws\n----------\nCharisma Save: {self.charisma_save}\n" |
|
|
|
|
|
|
|
f"Constitution Save: {self.constitution_save}\n" |
|
|
|
|
|
|
|
f"Dexterity Save: {self.dexterity_save}\n" |
|
|
|
|
|
|
|
f"Intelligence Save: {self.intelligence_save}\n" |
|
|
|
|
|
|
|
f"Strength Save: {self.strength_save}\n" |
|
|
|
|
|
|
|
f"Wisdom Save: {self.wisdom_save}\n") |
|
|
|
|
|
|
|
# Create the additional stats attribute |
|
|
|
|
|
|
|
setattr(self, "additional_stats", f"Additional Stats\n----------\nStarting HP: {self.starting_hp}\n" |
|
|
|
|
|
|
|
f"Hit Die: {self.hit_die}\n" |
|
|
|
|
|
|
|
f"Initiative Bonus: {self.initiative}\nSpeed: {self.speed}\n") |
|
|
|
|
|
|
|
# Create the skill bonuses attribute |
|
|
|
|
|
|
|
setattr(self, "skill_bonuses", f"Skill Bonuses\n----------\nAcrobatics: {self.acrobatics}\n" |
|
|
|
|
|
|
|
f"Animal Handling: {self.animal_handling}" |
|
|
|
|
|
|
|
f"\nArcana: {self.arcana}\nAthletics: {self.athletics}\nDeception: " |
|
|
|
|
|
|
|
f"{self.deception}" |
|
|
|
|
|
|
|
f"\nHistory: {self.history}\nInsight: {self.insight}\nIntimidation: " |
|
|
|
|
|
|
|
f"{self.intimidation}" |
|
|
|
|
|
|
|
f"\nInvestigation: {self.investigation}\nMedicine: {self.medicine}\nNature: " |
|
|
|
|
|
|
|
f"{self.nature}" |
|
|
|
|
|
|
|
f"\nPerception: {self.perception}\nPerformance: " |
|
|
|
|
|
|
|
f"{self.performance}\nPersuasion: {self.persuasion}" |
|
|
|
|
|
|
|
f"\nReligion: {self.religion}\nSleight of Hand: {self.sleight_of_hand}" |
|
|
|
|
|
|
|
f"\nStealth: {self.stealth}\nSurvival: {self.survival}\n") |
|
|
|
|
|
|
|
# Create the additional proficiencies attribute |
|
|
|
|
|
|
|
setattr(self, "additional_proficiencies", f"Additional Proficiencies\n----------\n" |
|
|
|
|
|
|
|
f"Languages: {self.languages}\n" |
|
|
|
|
|
|
|
f"Instruments: {self.instruments}\n" |
|
|
|
|
|
|
|
f"Artisan's Tools: {self.artisan_tools}\nAdditional Tools: " |
|
|
|
|
|
|
|
f"{self.additional_tools}\n" |
|
|
|
|
|
|
|
f"Weapon Proficiencies: {self.weapon_proficiency}\n" |
|
|
|
|
|
|
|
f"Armor Proficiencies: {self.armor_proficiency}\n") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Prints all stats, bonuses, and character info |
|
|
|
|
|
|
|
def output(self): |
|
|
|
|
|
|
|
print(self.whoami) |
|
|
|
|
|
|
|
print(self.stat_block) |
|
|
|
|
|
|
|
print(self.saves) |
|
|
|
|
|
|
|
print(self.additional_stats) |
|
|
|
|
|
|
|
print(self.skill_bonuses) |
|
|
|
|
|
|
|
print(self.additional_proficiencies) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|