Compare commits

...

No commits in common. 'master' and '248f66e4f0374d63c9d797fd0824c9d8fbefb7d5' have entirely different histories.

  1. 154
      .gitignore
  2. 9
      LICENSE
  3. 3
      README.md
  4. 226
      backgrounds.json
  5. 421
      creation_engine.py
  6. 407
      jobs.json
  7. 10
      main.py
  8. 4282
      master_class.json
  9. 3177
      names.txt
  10. 772
      races.json

154
.gitignore vendored

@ -1,154 +0,0 @@
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

9
LICENSE

@ -1,9 +0,0 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
README.md

@ -1,3 +0,0 @@
# 5e_one_click_character_creation
A one click character creator that generates a complete level one character for D&D 5th Edition.

226
backgrounds.json

@ -0,0 +1,226 @@
{
"Acolyte": {
"Skills": [
"insight",
"religion"
],
"Additional Proficiencies": {
"Languages": 2,
"Tools": 0,
"Additional Tools": [],
"Gaming Set": 0,
"Instrument": 0,
"Artisan's Tool": 0
}
},
"Charlatan": {
"Skills": [
"deception",
"sleight_of_hand"
],
"Additional Proficiencies": {
"Languages": 0,
"Tools": 0,
"Additional Tools": ["Disguise Kit", "Forgery Kit"],
"Gaming Set": 0,
"Instrument": 0,
"Artisan's Tool": 0
}
},
"Criminal / Spy": {
"Skills": [
"deception",
"stealth"
],
"Additional Proficiencies": {
"Languages": 0,
"Tools": 1,
"Additional Tools": ["Thieves Tools"],
"Gaming Set": 0,
"Instrument": 0,
"Artisan's Tool": 0
}
},
"Entertainer": {
"Skills": [
"acrobatics",
"performance"
],
"Additional Proficiencies": {
"Languages": 0,
"Tools": 0,
"Additional Tools": ["Disguise Kit"],
"Gaming Set": 0,
"Instrument": 1,
"Artisan's Tool": 0
}
},
"Folk Hero": {
"Skills": [
"animal_handling",
"survival"
],
"Additional Proficiencies": {
"Languages": 0,
"Tools": 1,
"Additional Tools": ["Vehicles (Land)"],
"Gaming Set": 0,
"Instrument": 0,
"Artisan's Tool": 0
}
},
"Gladiator": {
"Skills": [
"acrobatics",
"performance"
],
"Additional Proficiencies": {
"Languages": 0,
"Tools": 0,
"Additional Tools": ["Disguise Kit"],
"Gaming Set": 0,
"Instrument": 1,
"Artisan's Tool": 0
}
},
"Guild Artisan / Guild Merchant": {
"Skills": [
"insight",
"persuasion"
],
"Additional Proficiencies": {
"Languages": 1,
"Tools": 0,
"Additional Tools": [],
"Gaming Set": 0,
"Instrument": 0,
"Artisan's Tool": 1
}
},
"Hermit": {
"Skills": [
"medicine",
"religion"
],
"Additional Proficiencies": {
"Languages": 1,
"Tools": 0,
"Additional Tools": ["Herbalism Kit"],
"Gaming Set": 0,
"Instrument": 0,
"Artisan's Tool": 0
}
},
"Knight": {
"Skills": [
"history",
"persuasion"
],
"Additional Proficiencies": {
"Languages": 1,
"Tools": 0,
"Additional Tools": [],
"Gaming Set": 1,
"Instrument": 0,
"Artisan's Tool": 0
}
},
"Noble": {
"Skills": [
"persuasion",
"history"
],
"Additional Proficiencies": {
"Languages": 1,
"Tools": 0,
"Additional Tools": [],
"Gaming Set": 1,
"Instrument": 0,
"Artisan's Tool": 0
}
},
"Outlander": {
"Skills": [
"athletics",
"survival"
],
"Additional Proficiencies": {
"Languages": 1,
"Tools": 0,
"Additional Tools": [],
"Gaming Set": 0,
"Instrument": 1,
"Artisan's Tool": 0
}
},
"Pirate": {
"Skills": [
"athletics",
"perception"
],
"Additional Proficiencies": {
"Languages": 0,
"Tools": 0,
"Additional Tools": ["Navigator's Tools", "Vehicles (Water)"],
"Gaming Set": 0,
"Instrument": 0,
"Artisan's Tool": 0
}
},
"Sage": {
"Skills": [
"arcana",
"history"
],
"Additional Proficiencies": {
"Languages": 2,
"Tools": 0,
"Additional Tools": [],
"Gaming Set": 0,
"Instrument": 0,
"Artisan's Tool": 0
}
},
"Sailor": {
"Skills": [
"athletics",
"perception"
],
"Additional Proficiencies": {
"Languages": 0,
"Tools": 0,
"Additional Tools": ["Navigator's Tools", "Vehicles (Water)"],
"Gaming Set": 0,
"Instrument": 0,
"Artisan's Tool": 0
}
},
"Soldier": {
"Skills": [
"athletics",
"intimidation"
],
"Additional Proficiencies": {
"Languages": 0,
"Tools": 1,
"Additional Tools": ["Vehicles (Land)"],
"Gaming Set": 1,
"Instrument": 0,
"Artisan's Tool": 0
}
},
"Urchin": {
"Skills": [
"sleight_of_hand",
"stealth"
],
"Additional Proficiencies": {
"Languages": 0,
"Tools": 0,
"Additional Tools": ["Disguise Kit", "Thieves' Tools"],
"Gaming Set": 0,
"Instrument": 0,
"Artisan's Tool": 0
}
}
}

421
creation_engine.py

@ -0,0 +1,421 @@
import random
import json
# TODO AC? Or Gold Start no AC?
# TODO Feats?
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", ]
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"]
ARTISANS_TOOLS = ["Alchemist's Supplies", "Brewer's Supplies", "Calligrapher's Supplies", "Carpenter's Tools",
"Cartographer's Tools", "Cobbler's Tools", "Cook's Utensils", "Glassblower's Tools",
"Jeweler's Tools", "Leatherworker's Tools", "Mason's Tools", "Painter's Supplies", "Potter's Tools",
"Smith's Tools", "Tinker's Tools", "Weaver's Tools", "Woodcarver's Tools"]
CLERIC_SUBCLASSES = ["Life Domain", "Knowledge Domain", "Light Domain", "Nature Domain", "Tempest Domain",
"Trickery Domain", "War Domain", "Death Domain", "Arcana Domain", "Forge Domain", "Grave Domain",
"Twilight Domain", "Peace Domain", "Order Domain"]
SORCERER_SUBCLASSES = ["Aberrant Mind", "Clockwork Soul", "Divine Soul", "Draconic Bloodline", "Lunar Sorcery",
"Shadow Magic", "Storm Sorcery", "Wild Magic"]
WIZARD_SUBCLASSES = ["Bladesinging", "Chronurgy Magic", "Graviturgy Magic", "Order of Scribes", "School of Abjuration",
"School of Conjuration", "School of Divination", "School of Enchantment", "School of Evocation",
"School of Illusion", "School of Necromancy", "School of Transmutation", "War Magic"]
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.speed = self.race_string["Speed"]
self.article = self.grammar()
self.skill_generation()
self.skill_proficiency()
self.instruments = "None"
self.artisan_tools = "None"
self.additional_tools = "None"
self.armor_proficiency = "None"
self.race_proficiencies()
self.job_proficiencies()
self.background_proficiencies()
self.finalize_languages()
self.apply_skill_modifiers("dexterity", "initiative")
self.whoami()
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.saves = (f"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")
self.additional_stats = (
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"
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 and save 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)
# Initialization of saving throw modifiers
for attribute in ATTRIBUTE_LIST:
save_name = f"{attribute}_save"
setattr(self, save_name, 0)
self.apply_skill_modifiers(attribute, save_name)
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)
# rogue list for expertise calculation
rogue_proficient_list = []
for each in range(proficiencies):
proficient_skill = random.choice(job_skill_list)
if self.job == "Rogue":
rogue_proficient_list.append(proficient_skill)
job_skill_list.remove(proficient_skill)
current_score = getattr(self, proficient_skill)
setattr(self, f"{proficient_skill}_base_value", current_score)
new_score = str(current_score + 2)
setattr(self, proficient_skill, f"{new_score} (Prof)")
if self.job == "Rogue":
expertise_skill = random.choice(rogue_proficient_list)
score_value = getattr(self, f"{expertise_skill}_base_value")
new_score = score_value + 4
setattr(self, expertise_skill, f"{new_score} (Expertise)")
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)
def job_proficiencies(self):
with open('jobs.json') as json_file:
job_data = json.load(json_file)
if self.job == "Monk":
tool_choice = random.randint(0, 1)
if tool_choice == 0:
instrument_value = 1
else:
artisan_tool_value = 1
else:
try:
instrument_value = job_data[self.job]["Instruments"]
except KeyError:
pass
try:
artisan_tool_value = job_data[self.job]["Artisan's Tools"]
except KeyError:
pass
instrument_prof_list = []
artisan_prof_list = []
try:
for value in range(0, instrument_value):
new_instrument = random.choice(instrument_list)
instrument_list.remove(new_instrument)
instrument_prof_list.append(new_instrument)
instrument_string = ", ".join(instrument_prof_list)
setattr(self, "instruments", str(instrument_string))
except UnboundLocalError:
pass
try:
for value in range(0, artisan_tool_value):
new_tool = random.choice(ARTISANS_TOOLS)
ARTISANS_TOOLS.remove(new_tool)
artisan_prof_list.append(new_tool)
artisan_tool_string = ", ".join(artisan_prof_list)
setattr(self, "artisan_tools", str(artisan_tool_string))
except UnboundLocalError:
pass
try:
additional_tool_list = job_data[self.job]["Additional Tools"]
additional_tool_string = ", ".join(additional_tool_list)
setattr(self, "additional_tools", str(additional_tool_string))
except KeyError:
pass
armor_prof_list = job_data[self.job]["Armor Proficiency"]
if not armor_prof_list:
setattr(self, "armor_proficiency", "None")
else:
armor_prof_string = ", ".join(armor_prof_list)
setattr(self, "armor_proficiency", armor_prof_string)
weapon_prof_list = job_data[self.job]["Weapon Proficiency"]
weapon_prof_string = ", ".join(weapon_prof_list)
setattr(self, "weapon_proficiency", weapon_prof_string)
for attribute in job_data[self.job]["Saving Throws"]:
current_score = getattr(self, f"{attribute}_save")
new_score = str(current_score + 2)
setattr(self, f"{attribute}_save", f"{new_score} (Prof)")
def background_proficiencies(self):
global known_language_list
with open('backgrounds.json') as json_file:
background_data = json.load(json_file)
# background instrument proficiencies
try:
instrument_value = background_data[self.background]["Additional Proficiencies"]["Instrument"]
except KeyError or UnboundLocalError:
pass
for value in range(0, instrument_value):
new_instrument = random.choice(instrument_list)
current_instruments = getattr(self, "instruments")
if current_instruments == "None":
setattr(self, "instruments", f"{new_instrument}")
else:
setattr(self, "instruments", current_instruments + f", {new_instrument}")
# background artisan's tools proficiencies
try:
tool_value = background_data[self.background]["Additional Proficiencies"]["Artisan's Tool"]
except KeyError or UnboundLocalError:
pass
for value in range(0, tool_value):
new_tool = random.choice(ARTISANS_TOOLS)
current_tools = getattr(self, "artisan_tools")
if current_tools == "None":
setattr(self, "artisan_tools", f"{new_tool}")
else:
setattr(self, "artisan_tools", current_tools + f", {new_tool}")
# language proficiencies
try:
language_value = background_data[self.background]["Additional Proficiencies"]["Languages"]
except UnboundLocalError:
pass
for value in range(0, language_value):
try:
new_language = random.choice(languages)
known_language_list.append(new_language)
languages.remove(new_language)
except IndexError:
pass
# additional tool proficiencies
additional_tool_list = background_data[self.background]["Additional Proficiencies"]["Additional Tools"]
if not additional_tool_list:
pass
else:
current_tools = getattr(self, "additional_tools")
if current_tools == "None":
setattr(self, "additional_tools", ", ".join(additional_tool_list))
else:
for tool in additional_tool_list:
if tool in current_tools:
pass
else:
new_tool_list = getattr(self, "additional_tools") + f", {tool}"
setattr(self, "additional_tools", new_tool_list)
def race_proficiencies(self):
global known_language_list
try:
known_languages = self.race_string["Languages"]
for language in known_languages:
known_language_list.append(language)
print(language)
languages.remove(language)
except KeyError:
pass
for value in range(0, self.race_string["AdditionalLanguages"]):
try:
new_language = random.choice(languages)
known_language_list.append(new_language)
languages.remove(new_language)
except IndexError:
pass
def finalize_languages(self):
global known_language_list
language_string = ", ".join(known_language_list)
setattr(self, "languages", language_string)
def whoami(self):
if self.job == "Cleric":
subclass = random.choice(CLERIC_SUBCLASSES)
setattr(self,"subclass",subclass)
print(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")
elif self.job == "Sorcerer":
subclass = random.choice(SORCERER_SUBCLASSES)
setattr(self, "subclass", subclass)
print(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")
elif self.job == "Wizard":
subclass = random.choice(WIZARD_SUBCLASSES)
setattr(self, "subclass", subclass)
print(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")
else:
print(f"Your new character is {self.name}, {self.article} {self.race} {self.job}, with the "
f"{self.background} background.\n")
# 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}")

407
jobs.json

@ -0,0 +1,407 @@
{
"Artificer": {
"Proficiencies": 2,
"Skills": [
"arcana",
"history",
"investigation",
"medicine",
"nature",
"perception",
"sleight_of_hand"
],
"Hit Die": "1d8",
"Starting HP": 8,
"Artisan's Tools": 1,
"Additional Tools": [
"Thieves' Tools",
"Tinker's Tools"
],
"Armor Proficiency": [
"Light Armor",
"Medium Armor",
"Shields"
],
"Weapon Proficiency": [
"Simple Weapons"
],
"Saving Throws": [
"constitution",
"intelligence"
]
},
"Barbarian": {
"Proficiencies": 2,
"Skills": [
"animal_handling",
"athletics",
"intimidation",
"nature",
"perception",
"survival"
],
"Hit Die": "1d12",
"Starting HP": 12,
"Armor Proficiency": [
"Light Armor",
"Medium Armor",
"Shields"
],
"Weapon Proficiency": [
"Simple Weapons",
"Martial Weapons"
],
"Saving Throws": [
"strength",
"constitution"
]
},
"Bard": {
"Proficiencies": 3,
"Skills": [
"acrobatics",
"animal_handling",
"arcana",
"athletics",
"deception",
"history",
"insight",
"intimidation",
"investigation",
"medicine",
"nature",
"perception",
"performance",
"persuasion",
"religion",
"sleight_of_hand",
"stealth",
"survival"
],
"Hit Die": "1d8",
"Starting HP": 8,
"Instruments": 3,
"Armor Proficiency": [
"Light Armor"
],
"Weapon Proficiency": [
"Simple Weapons",
"Hand Crossbows",
"Longswords",
"Rapiers",
"Shortswords"
],
"Saving Throws": [
"dexterity",
"charisma"
]
},
"Cleric": {
"Proficiencies": 2,
"Skills": [
"history",
"insight",
"medicine",
"persuasion",
"religion"
],
"Hit Die": "1d8",
"Starting HP": 8,
"Armor Proficiency": [
"Light Armor",
"Medium Armor",
"Shields"
],
"Weapon Proficiency": [
"Simple Weapons"
],
"Saving Throws": [
"wisdom",
"charisma"
],
"Subclass": 1
},
"Druid": {
"Proficiencies": 2,
"Skills": [
"animal_handling",
"arcana",
"insight",
"medicine",
"nature",
"perception",
"religion",
"survival"
],
"Hit Die": "1d8",
"Starting HP": 8,
"Additional Tools": [
"Herbalism Kit"
],
"Armor Proficiency": [
"Light Armor",
"Medium Armor",
"Shields"
],
"Weapon Proficiency": [
"Clubs",
"Daggers",
"Darts",
"Javelins",
"Maces",
"Quarterstaffs",
"Scimitars",
"Sickles",
"Slings",
"Spears"
],
"Saving Throws": [
"intelligence",
"wisdom"
]
},
"Fighter": {
"Proficiencies": 2,
"Skills": [
"acrobatics",
"animal_handling",
"athletics",
"history",
"insight",
"intimidation",
"perception",
"survival"
],
"Hit Die": "1d10",
"Starting HP": 10,
"Armor Proficiency": [
"All Armor",
"Shields"
],
"Weapon Proficiency": [
"Simple Weapons",
"Martial Weapons"
],
"Saving Throws": [
"strength",
"constitution"
]
},
"Monk": {
"Proficiencies": 2,
"Skills": [
"acrobatics",
"athletics",
"history",
"insight",
"religion"
],
"Hit Die": "1d8",
"Starting HP": 8,
"Armor Proficiency": [],
"Weapon Proficiency": [
"Simple Weapons",
"Shortswords"
],
"Saving Throws": [
"strength",
"dexterity"
]
},
"Paladin": {
"Proficiencies": 2,
"Skills": [
"athletics",
"insight",
"intimidation",
"medicine",
"persuasion",
"religion"
],
"Hit Die": "1d10",
"Starting HP": 10,
"Armor Proficiency": [
"All Armor",
"Shields"
],
"Weapon Proficiency": [
"Simple Weapons",
"Martial Weapons"
],
"Saving Throws": [
"wisdom",
"charisma"
]
},
"Ranger": {
"Proficiencies": 3,
"Skills": [
"animal_handling",
"athletics",
"insight",
"investigation",
"nature",
"perception",
"stealth",
"survival"
],
"Hit Die": "1d10",
"Starting HP": 10,
"Armor Proficiency": [
"Light Armor",
"Medium Armor",
"Shields"
],
"Weapon Proficiency": [
"Simple Weapons",
"Martial Weapons"
],
"Saving Throws": [
"strength",
"dexterity"
]
},
"Rogue": {
"Proficiencies": 4,
"Skills": [
"acrobatics",
"athletics",
"deception",
"insight",
"intimidation",
"investigation",
"perception",
"performance",
"persuasion",
"sleight_of_hand",
"stealth"
],
"Hit Die": "1d8",
"Starting HP": 8,
"Additional Tools": [
"Thieves' Tools"
],
"Armor Proficiency": [
"Light Armor"
],
"Weapon Proficiency": [
"Simple Weapons",
"Hand Crossbows",
"Longswords",
"Rapiers",
"Shortswords"
],
"Saving Throws": [
"dexterity",
"intelligence"
],
"Expertise": 1
},
"Sorcerer": {
"Proficiencies": 2,
"Skills": [
"arcana",
"deception",
"insight",
"intimidation",
"persuasion",
"religion"
],
"Hit Die": "1d6",
"Starting HP": 6,
"Armor Proficiency": [],
"Weapon Proficiency": [
"Daggers",
"Darts",
"Slings",
"Quarterstaffs",
"Light Crossbows"
],
"Saving Throws": [
"constitution",
"charisma"
],
"Subclass": 1
},
"Warlock": {
"Proficiencies": 2,
"Skills": [
"arcana",
"deception",
"history",
"intimidation",
"investigation",
"nature",
"religion"
],
"Hit Die": "1d8",
"Starting HP": 8,
"Armor Proficiency": [
"Light Armor"
],
"Weapon Proficiency": [
"Simple Weapons"
],
"Saving Throws": [
"wisdom",
"charisma"
],
"Subclass": 1
},
"Wizard": {
"Proficiencies": 2,
"Skills": [
"arcana",
"history",
"insight",
"investigation",
"medicine",
"religion"
],
"Hit Die": "1d6",
"Starting HP": 6,
"Armor Proficiency": [],
"Weapon Proficiency": [
"Daggers",
"Darts",
"Slings",
"Quarterstaffs",
"Light Crossbows"
],
"Saving Throws": [
"intelligence",
"wisdom"
]
},
"Blood Hunter": {
"Proficiencies": 3,
"Skills": [
"acrobatics",
"arcana",
"athletics",
"history",
"insight",
"investigation",
"religion",
"survival"
],
"Hit Die": "1d8",
"Starting HP": 8,
"Additional Tools": [
"Alchemist's Supplies"
],
"Armor Proficiency": [
"Light Armor",
"Medium Armor",
"Shields"
],
"Weapon Proficiency": [
"Simple Weapons",
"Martial Weapons"
],
"Saving Throws": [
"dexterity",
"intelligence"
]
}
}

10
main.py

@ -0,0 +1,10 @@
import creation_engine
hero = creation_engine.HeroCreation()
print(hero.stat_block)
print(hero.saves)
print(hero.additional_stats)
print(hero.skill_bonuses)
print(hero.other_proficiencies)
print(hero.job)

4282
master_class.json

File diff suppressed because it is too large Load Diff

3177
names.txt

File diff suppressed because it is too large Load Diff

772
races.json

@ -0,0 +1,772 @@
[
{
"Race": "Aarakocra",
"Strength": 0,
"Dexterity": 2,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 1,
"Charisma": 0,
"Languages": [
"Aarakocra",
"Auran"
],
"AdditionalLanguages": 1,
"Speed": 50
},
{
"Race": "Aasimar (Fallen)",
"Strength": 1,
"Dexterity": 0,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 2,
"Languages": [
"Celestial"
],
"AdditionalLanguages": 1,
"Speed": 30,
"Resistances": ["Radiant Damage", "Necrotic Damage"]
},
{
"Race": "Aasimar (Protector)",
"Strength": 0,
"Dexterity": 0,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 1,
"Charisma": 2,
"Languages": [
"Celestial"
],
"AdditionalLanguages": 1,
"Speed": 30,
"Resistances": ["Radiant Damage", "Necrotic Damage"]
},
{
"Race": "Aasimar (Scourge)",
"Strength": 0,
"Dexterity": 0,
"Constitution": 1,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 2,
"Languages": [
"Celestial"
],
"AdditionalLanguages": 1,
"Speed": 30,
"Resistances": ["Radiant Damage", "Necrotic Damage"]
},
{
"Race": "Bugbear",
"Strength": 2,
"Dexterity": 1,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Goblin"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Centaur",
"Strength": 2,
"Dexterity": 0,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 1,
"Charisma": 0,
"Languages": [
"Sylvan",
"Elvish"
],
"AdditionalLanguages": 0,
"Speed": 40
},
{
"Race": "Dwarf (Duergar)",
"Strength": 1,
"Dexterity": 0,
"Constitution": 2,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Dwarvish",
"Undercommon"
],
"AdditionalLanguages": 0,
"Speed": 25
},
{
"Race": "Dwarf (Hill)",
"Strength": 0,
"Dexterity": 0,
"Constitution": 2,
"Intelligence": 0,
"Wisdom": 1,
"Charisma": 0,
"Languages": [
"Dwarvish"
],
"AdditionalLanguages": 0,
"Speed": 25
},
{
"Race": "Dwarf (Mountain)",
"Strength": 2,
"Dexterity": 0,
"Constitution": 2,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Dwarvish"
],
"AdditionalLanguages": 0,
"Speed": 25
},
{
"Race": "Dragonborn",
"Strength": 2,
"Dexterity": 0,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 1,
"Languages": [
"Draconic"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Elf (Drow)",
"Strength": 0,
"Dexterity": 2,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 1,
"Languages": [
"Elvish",
"Undercommon"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Elf (Eladrin)",
"Strength": 0,
"Dexterity": 2,
"Constitution": 0,
"Intelligence": 1,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Elvish"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Elf (High)",
"Strength": 0,
"Dexterity": 2,
"Constitution": 0,
"Intelligence": 1,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Elvish"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Elf (Sea)",
"Strength": 0,
"Dexterity": 2,
"Constitution": 1,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Elvish",
"Undercommon"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Elf (Shadar-Kai)",
"Strength": 0,
"Dexterity": 2,
"Constitution": 1,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Elvish",
"Undercommon"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Elf (Wood)",
"Strength": 0,
"Dexterity": 2,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 1,
"Charisma": 0,
"Languages": [
"Elvish"
],
"AdditionalLanguages": 0,
"Speed": 35
},
{
"Race": "Firbolg",
"Strength": 1,
"Dexterity": 0,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 2,
"Charisma": 0,
"Languages": [
"Sylvan"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Genasi (Air)",
"Strength": 0,
"Dexterity": 1,
"Constitution": 2,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Primordial"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Genasi (Earth)",
"Strength": 1,
"Dexterity": 0,
"Constitution": 2,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Primordial"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Genasi (Fire)",
"Strength": 0,
"Dexterity": 0,
"Constitution": 2,
"Intelligence": 1,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Primordial"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Genasi (Water)",
"Strength": 0,
"Dexterity": 0,
"Constitution": 2,
"Intelligence": 0,
"Wisdom": 1,
"Charisma": 0,
"Languages": [
"Primordial"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Githyanki",
"Strength": 2,
"Dexterity": 0,
"Constitution": 0,
"Intelligence": 1,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Gith"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Githzerai",
"Strength": 0,
"Dexterity": 0,
"Constitution": 0,
"Intelligence": 1,
"Wisdom": 2,
"Charisma": 0,
"Languages": [
"Gith"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Gnome (Deep)",
"Strength": 0,
"Dexterity": 1,
"Constitution": 0,
"Intelligence": 2,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Gnomish",
"Undercommon"
],
"AdditionalLanguages": 0,
"Speed": 25
},
{
"Race": "Gnome (Forest)",
"Strength": 0,
"Dexterity": 1,
"Constitution": 0,
"Intelligence": 2,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Gnomish"
],
"AdditionalLanguages": 0,
"Speed": 25
},
{
"Race": "Gnome (Rock)",
"Strength": 0,
"Dexterity": 0,
"Constitution": 1,
"Intelligence": 2,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Gnomish"
],
"AdditionalLanguages": 0,
"Speed": 25
},
{
"Race": "Goblin",
"Strength": 0,
"Dexterity": 2,
"Constitution": 1,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Goblin"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Goliath",
"Strength": 2,
"Dexterity": 0,
"Constitution": 1,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Giant"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Halfling (Lightfoot)",
"Strength": 0,
"Dexterity": 2,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 1,
"Languages": [
"Halfling"
],
"AdditionalLanguages": 0,
"Speed": 25
},
{
"Race": "Halfling (Stout)",
"Strength": 0,
"Dexterity": 2,
"Constitution": 1,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Halfling"
],
"AdditionalLanguages": 0,
"Speed": 25
},
{
"Race": "Half-Orc",
"Strength": 2,
"Dexterity": 0,
"Constitution": 1,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Orc"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Hobgoblin",
"Strength": 0,
"Dexterity": 0,
"Constitution": 2,
"Intelligence": 1,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Goblin"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Human",
"Strength": 1,
"Dexterity": 1,
"Constitution": 1,
"Intelligence": 1,
"Wisdom": 1,
"Charisma": 1,
"AdditionalLanguages": 1,
"Speed": 30
},
{
"Race": "Kenku",
"Strength": 0,
"Dexterity": 2,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 1,
"Charisma": 0,
"Languages": [
"Auran"
],
"AdditionalLanguages": 1,
"Speed": 30
},
{
"Race": "Kobold",
"Strength": -2,
"Dexterity": 2,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Draconic"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Lizardfolk",
"Strength": 0,
"Dexterity": 0,
"Constitution": 2,
"Intelligence": 0,
"Wisdom": 1,
"Charisma": 0,
"Languages": [
"Draconic"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Minotaur",
"Strength": 2,
"Dexterity": 0,
"Constitution": 1,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Giant"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Orc",
"Strength": 2,
"Dexterity": 0,
"Constitution": 1,
"Intelligence": -2,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Orc"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Shifter (Beasthide)",
"Strength": 0,
"Dexterity": 1,
"Constitution": 2,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Sylvan"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Shifter (Longtooth)",
"Strength": 2,
"Dexterity": 1,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Sylvan"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Shifter (Swiftstride)",
"Strength": 0,
"Dexterity": 2,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 1,
"Languages": [
"Sylvan"
],
"AdditionalLanguages": 0,
"Speed": 35
},
{
"Race": "Shifter (Wildhunt)",
"Strength": 0,
"Dexterity": 1,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 2,
"Charisma": 0,
"Languages": [
"Sylvan"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Tabaxi",
"Strength": 0,
"Dexterity": 2,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 1,
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Tiefling",
"Strength": 0,
"Dexterity": 0,
"Constitution": 0,
"Intelligence": 1,
"Wisdom": 0,
"Charisma": 2,
"Languages": [
"Infernal"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Tiefling (Dispater)",
"Strength": 0,
"Dexterity": 1,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 2,
"Languages": [
"Infernal"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Tiefling (Glasya)",
"Strength": 0,
"Dexterity": 1,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 2,
"Languages": [
"Infernal"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Tiefling (Feral)",
"Strength": 0,
"Dexterity": 2,
"Constitution": 0,
"Intelligence": 1,
"Wisdom": 0,
"Charisma": 0,
"Languages": [
"Infernal"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Tiefling (Fierna)",
"Strength": 0,
"Dexterity": 0,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 1,
"Charisma": 2,
"Languages": [
"Infernal"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Tiefling (Levistus)",
"Strength": 0,
"Dexterity": 0,
"Constitution": 1,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 2,
"Languages": [
"Infernal"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Tiefling (Zariel)",
"Strength": 1,
"Dexterity": 0,
"Constitution": 0,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 2,
"Languages": [
"Infernal"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Triton",
"Strength": 1,
"Dexterity": 0,
"Constitution": 1,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 1,
"Languages": [
"Aquan"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Vedalken",
"Strength": 0,
"Dexterity": 0,
"Constitution": 0,
"Intelligence": 2,
"Wisdom": 1,
"Charisma": 0,
"Languages": [
"Vedalken",
"Undercommon"
],
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Warforged (Juggernaut)",
"Strength": 2,
"Dexterity": 0,
"Constitution": 1,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Warforged (Skirmisher)",
"Strength": 0,
"Dexterity": 2,
"Constitution": 1,
"Intelligence": 0,
"Wisdom": 0,
"Charisma": 0,
"AdditionalLanguages": 0,
"Speed": 30
},
{
"Race": "Yuan-Ti Pureblood",
"Strength": 0,
"Dexterity": 0,
"Constitution": 0,
"Intelligence": 1,
"Wisdom": 0,
"Charisma": 2,
"Languages": [
"Abyssal",
"Draconic"
],
"AdditionalLanguages": 0,
"Speed": 30
}
]
Loading…
Cancel
Save