import random import json #TODO 1 Languages #TODO 2 Tool Proficiencies #TODO 3 Weapon Proficiencies #TODO 4 Rogue Expertise #TODO 5 AC? Or Gold Start no AC? #TODO 6 Sub Classes? VOWELS = ["A","E","I","O","U"] SKILL_LIST = ["acrobatics", "animal_handling", "arcana", "athletics", "deception", "history", "insight", "intimidation", "investigation", "medicine", "nature", "perception", "performance", "persuasion", "religion", "sleight_of_hand", "stealth", "survival"] ATTRIBUTE_LIST = ["strength", "dexterity", "wisdom", "constitution", "intelligence", "charisma"] CLASS_LIST = ["Artificer","Barbarian","Bard","Cleric","Druid","Fighter","Monk","Paladin", "Ranger","Rogue","Sorcerer","Warlock","Wizard","Blood Hunter"] BACKGROUND_LIST = ["Acolyte", "Charlatan", "Criminal / Spy", "Entertainer", "Folk Hero", "Gladiator", "Guild Artisan / Guild Merchant", "Hermit", "Knight", "Noble", "Outlander", "Pirate", "Sage", "Sailor", "Soldier", "Urchin",] class HeroCreation: def __init__(self): self.name_generation() self.race_selection() self.race = self.race_string["Race"] #'job' is used in place of 'class' to avoid a function conflict self.job = random.choice(CLASS_LIST) self.job_characteristics() self.background = random.choice(BACKGROUND_LIST) self.stat_rolls() self.racial_bonuses() self.article = self.grammar() self.skill_generation() self.skill_proficiency() self.apply_skill_modifiers("dexterity","initiative") self.whoami = (f"Your new character is {self.name}, {self.article} {self.race} {self.job}, with the " f"{self.background} background.\n") 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") self.additional_stats = (f"Additional Stats\n----------\nStarting HP: {self.starting_hp}\nHit Die: {self.hit_die}\n" f"Initiative Bonus: {self.initiative}\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}") #Assign the correct a/an article in the 'whoami' attr def grammar(self): if self.race[0] in VOWELS: return "an" else: return "a" def race_selection(self): with open('races.json') as json_file: race_data = json.load(json_file) chosen_race = random.choice(race_data) setattr(self,"race_string",chosen_race) def stat_rolls(self): # Configured to "Re-roll" 1s # To include 1s, increase the randint range to 1,6 for attribute in ATTRIBUTE_LIST: roll_list = [] for each in range(4): roll_list.append(random.randint(2, 6)) roll_list.remove(min(roll_list)) stat_total = sum(roll_list) setattr(self,f"{attribute}", stat_total) #Assign racial stat bonuses def racial_bonuses(self): self.charisma += self.race_string["Charisma"] self.constitution += self.race_string["Constitution"] self.dexterity += self.race_string["Dexterity"] self.intelligence += self.race_string["Intelligence"] self.strength += self.race_string["Strength"] self.wisdom += self.race_string["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 with a base value of +0 to the roll def skill_generation(self): for skill in SKILL_LIST: setattr(self, skill, 0) if skill == "athletics": self.apply_skill_modifiers("strength",skill) elif skill in ["acrobatics", "sleight_of_hand", "stealth"]: self.apply_skill_modifiers("dexterity",skill) elif skill in ["arcana", "history", "investigation", "nature", "religion"]: self.apply_skill_modifiers("intelligence",skill) elif skill in ["animal_handling", "insight", "medicine", "perception", "survival"]: self.apply_skill_modifiers("wisdom",skill) elif skill in ["deception", "intimidation", "performance", "persuasion"]: self.apply_skill_modifiers("charisma",skill) def apply_skill_modifiers(self,attribute_name,skill_name): attribute = getattr(self,attribute_name) if attribute == 1: modifier = -5 elif attribute in [2, 3]: modifier = -4 elif attribute in [4, 5]: modifier = -3 elif attribute in [6, 7]: modifier = -2 elif attribute in [8, 9]: modifier = -1 elif attribute in [10, 11]: modifier = 0 elif attribute in [12, 13]: modifier = 1 elif attribute in [14, 15]: modifier = 2 elif attribute in [16, 17]: modifier = 3 elif attribute in [18, 19]: modifier = 4 elif attribute in [20, 21]: modifier = 5 else: modifier = 0 setattr(self,skill_name,modifier) def skill_proficiency(self): with open('backgrounds.json') as json_file: background_data = json.load(json_file) # Is this actually a dict? background_dict = background_data[self.background]["Skills"] for skill in background_dict: current_score = getattr(self, skill) new_score = str(current_score + 2) setattr(self, skill, f"{new_score} (Prof)") with open('jobs.json') as json_file: job_data = json.load(json_file) # Is this actually a dict? job_dict = job_data[self.job] proficiencies = job_dict["Proficiencies"] job_skill_list = job_dict["Skills"] for skill in background_dict: if skill in job_skill_list: job_skill_list.remove(skill) for each in range(proficiencies): proficient_skill = random.choice(job_skill_list) job_skill_list.remove(proficient_skill) current_score = getattr(self,proficient_skill) new_score = str(current_score + 2) setattr(self,proficient_skill,f"{new_score} (Prof)") def job_characteristics(self): with open('jobs.json') as json_file: job_data = json.load(json_file) hit_die_value = job_data[self.job]["Hit Die"] setattr(self,"hit_die",hit_die_value) starting_hp_value = job_data[self.job]["Starting HP"] setattr(self,"starting_hp",starting_hp_value) #Used for interactively moving around stats in case of a bad allocation. #Disabling for now, as this project is intended to be one-command and self-contained # def stat_moves(self): # finished = False # while not finished: # move_request = input("Would you like to move any of these stats around? (y/n)").lower() # if move_request == "y": # stat_1 = input("What is the first stat you would like to move? Please enter the full stat name.").lower() # stat_2 = input("What is the second stat you would like to move? Please enter the full stat name.").lower() # if hasattr(self, stat_1) and hasattr(self, stat_2): # stat_1_value = getattr(self, stat_1) # stat_2_value = getattr(self, stat_2) # setattr(self, stat_1, stat_2_value) # setattr(self, stat_2, stat_1_value) # self.update_stat_block() # print(self.whoami) # print(self.stat_block) # elif move_request == "n": # finished = True #Currently only used for the stat_moves functionality. Disabling for now # def update_stat_block(self): # 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}")