-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathdnd_character_creator.py
More file actions
executable file
·390 lines (359 loc) · 17.8 KB
/
Copy pathdnd_character_creator.py
File metadata and controls
executable file
·390 lines (359 loc) · 17.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
from dnd5.DnD5Character import DnD5Character
from databases.dnd5.dnd5_backgrounds_db import get_all_background_names, get_background_by_name
from databases.dnd5.dnd5_classes_db import get_all_classes_names, get_class_by_name
from databases.dnd5.dnd5_languages_db import get_all_languages, get_all_unrestricted_languages
from databases.dnd5.dnd5_races_db import get_all_races_names, look_for_race_by_name
from databases.dnd5.dnd5_spell_db import get_all_spells_of_class_and_level
from dnd5.dnd5_constants import GENERATION_TYPES
from utils.utilities import is_valid_choice, dict_to_str, list_to_str_with_number_and_line, get_modifier
def cli_display(character):
"""
Displays the character chosen in stdout through prints
"""
print("Name: " + character.name)
print("Hit Points: " + str(character.hit_points))
print("Race: " + character.race.name)
print("Class: " + character.dnd_class.name)
print("Background: " + character.background)
print("Alignment: " + character.alignment)
print("Size: " + character.size)
print("Age: " + str(character.age))
print("Vision: " + ", ".join(character.vision))
# Todo: change this into a function for attributes str result (like saving throws)
print("Attributes:")
for attribute in ["Strength", "Dexterity", "Constitution", "Intelligence", "Wisdom", "Charisma"]:
att_score = character.attributes[attribute]
att_mod = get_modifier(att_score)
print(f"\t{attribute}: {att_score} ({att_mod})")
print("Saving Throws: " + character.saving_throws_to_str())
print("Saving Throws Proficiencies: " + ", ".join(character.proficient_saving_throws))
for proficiency in [
("Languages", character.languages),
("Skill Proficiencies", character.skill_proficiencies),
("Tool Proficiencies", character.tool_proficiencies),
("Armor Proficiencies", character.armor_proficiencies),
("Weapon Proficiencies", character.weapon_proficiencies)
]:
p_str = proficiency[0]
p_values = proficiency[1]
if len(proficiency_values) > 0:
print(f"{p_str}: " + ", ".join(p_values)
print(character.race.racial_traits_to_string())
if len(character.cantrips) > 0:
print("Known Cantrips: ")
known_cantrips = "\t" + ", ".join(character.cantrips)
print(known_cantrips)
if len(character.spells) > 0:
print("Known Spells: ")
known_spells = "\t" + ", ".join(character.spells)
print(known_spells)
print("Class Features: ")
print(character.dnd_class.class_features_to_string())
print("Personality traits: " + ", ".join(character.personality_traits))
print("Bonds: " + ", ".join(character.bonds))
print("Flaws: " + ", ".join(character.flaws))
print("Ideals: " + ", ".join(character.ideals))
print("Equipment:")
print(character.equipment_to_string())
def dnd_character_creation():
# getting all lists for backgrounds, races, languages and classes
background_name_list = get_all_background_names()
race_name_list = get_all_races_names()
language_list = get_all_languages()
classes_list = get_all_classes_names()
unrestricted_language_list = get_all_unrestricted_languages()
# Name choice
print("Choose character name:")
character_name = input()
# Stat generations
choosing_attributes = True
while choosing_attributes:
print("How do you want the stats to be generated ?\n" + dict_to_str(GENERATION_TYPES))
generation = ""
while not generation.isdigit():
generation = input()
attributes = []
if int(generation) == 4:
print("Please input the 6 stats you want to use in order, for Strength, Dexterity, Constitution, "
"Intelligence, Wisdom, and Charisma")
while len(attributes) < 6:
att = ""
while not att.isdigit():
att = input()
int_att = int(att)
if int_att < 5 or int_att > 20:
print("Your attributes should not go lower than 5 or higher than 20")
else:
attributes.append(int_att)
dnd_character = DnD5Character(character_name.strip(), int(generation), stats=attributes)
print("Your attributes are: " + dnd_character.attributes_to_str())
print("If you accept these attributes, enter yes")
acceptance = input().strip()
if acceptance == "yes":
choosing_attributes = False
# Race choice
choice_not_validated = True
while choice_not_validated:
print("Choose your race:\n" + ", ".join(race_name_list))
race_choice = input().strip()
if is_valid_choice(race_name_list, race_choice):
race = look_for_race_by_name(race_choice)
print("This is what this race would give you:")
print(race.to_cli_string())
print("Do you confirm this choice?")
confirm = input().strip()
if confirm == "yes":
dnd_character.set_race(race)
print("You have chosen the race: " + race.name)
choice_not_validated = False
# Racial trait choices
racial_traits_choices_nb, racial_traits_choices_list = race.get_racial_traits()
if racial_traits_choices_nb > 0:
print("This race offers traits to choose from: ")
for i in range(racial_traits_choices_nb):
print(racial_traits_choices_list[i]["name"])
# Racial tool choices
tool_choices_nb, tool_choices = race.get_racial_tools()
if tool_choices_nb > 0:
print("Your race offers tool proficiency choices: pick "
+ str(tool_choices_nb) + " choices among the following list: ")
print(", ".join(tool_choices))
tool_choice = input().strip()
for i in range(tool_choices_nb):
while not is_valid_choice(tool_choices, tool_choice):
print("Choose a tool kit that is in the list above")
tool_choice = input().strip()
dnd_character.tool_proficiencies.add(tool_choice)
# Racial cantrip choices
cantrip_choice_nb, cantrip_choice_list = race.get_racial_cantrips()
if cantrip_choice_nb > 0:
print("Your race offers cantrip choices: pick " + str(cantrip_choice_nb) + " choices among the following list: ")
print(", ".join(cantrip_choice_list))
cantrip_choice = input().strip()
for i in range(cantrip_choice_nb):
while not is_valid_choice(cantrip_choice_list, cantrip_choice):
print("Choose a cantrip that is in the list above")
cantrip_choice = input().strip()
dnd_character.add_cantrip(cantrip_choice)
# Skill choice from race possibilities
skill_choice_number, skill_choice_options = race.get_racial_skills_choices()
if skill_choice_number > 0:
print("You have bonus proficiencies, pick " + str(skill_choice_number)
+ " among the following:\n" + ", ".join(skill_choice_options))
proficiency_choices = []
for i in range(skill_choice_number):
prof_choice = input().strip()
if is_valid_choice(skill_choice_options, prof_choice):
proficiency_choices.append(prof_choice)
dnd_character.set_bonus_skill_proficiencies(proficiency_choices)
# Language choice from race possibilities
if dnd_character.race.bonus_languages > 0:
print("You have bonus languages, pick " + str(dnd_character.race.bonus_languages)
+ " among the following:\n" + ", ".join(unrestricted_language_list))
language_choices = []
for i in range(race.bonus_languages):
lang_choice = input().strip()
if is_valid_choice(unrestricted_language_list, lang_choice):
language_choices.append(lang_choice)
dnd_character.set_bonus_languages(language_choices)
# Age choice
print("Pick your age, " + race.name +
" are usually between " + race.age_bracket[0] + " and " + race.age_bracket[1]
+ " years old.")
age_choice = input()
dnd_character.set_age(age_choice)
# Alignment choice
print("Choose your alignment:\n LG for Lawful Good, NG for Neutral Good, CG for Chaotic Good\n"
+ " LN for Lawful Neutral, TN for True Neutral, CN for Chaotic Neutral\n LE for Lawful Evil"
+ ", NE for Neutral Evil, CE for Chaotic Evil")
alignment_choice = input()
dnd_character.set_alignment(alignment_choice.strip())
# Background choice
print("Choose your background:\n" + ", ".join(background_name_list))
background_choice = input().strip()
background_accepted = False
while not background_accepted:
while not is_valid_choice(background_name_list, background_choice):
background_choice = input().strip()
background = get_background_by_name(background_choice)
print(background.to_string())
print("Do you accept this background?")
accept = input().strip()
if accept == 'yes':
background_accepted = True
dnd_character.set_background(background)
if background.feature_choice != '':
print("Your background has the following feature: " + background.feature_choice +
"you can choose from the following table: ")
print(list_to_str_with_number_and_line(background.feature_choice_table))
if background.bonus_languages > 0:
print("You have " + str(background.bonus_languages) + " bonus languages to pick: ")
print(", ".join(language_list))
while background.bonus_languages > 0:
language_choices = []
language_input = input().strip()
if is_valid_choice(unrestricted_language_list, language_input):
language_choices.append(language_input)
background.bonus_languages -= 1
dnd_character.set_bonus_languages(language_choices)
# choose personality trait
print("You may choose one of these personality traits or type your own: ")
print(list_to_str_with_number_and_line(background.personality_traits))
personality_choice = input().strip()
if personality_choice.isdigit():
if int(personality_choice) < len(background.personality_traits) + 1:
dnd_character.personality_traits.append(background.personality_traits[int(personality_choice)-1])
else:
dnd_character.personality_traits.append(personality_choice)
print("You may choose a second personality trait")
personality_choice = input().strip()
if personality_choice.isdigit():
if int(personality_choice) < len(background.personality_traits) + 1:
dnd_character.personality_traits.append(background.personality_traits[int(personality_choice)-1])
else:
dnd_character.personality_traits.append(personality_choice)
# choose ideal
print("You may choose one of these ideals or type your own: ")
print(list_to_str_with_number_and_line(background.ideals))
ideal_choice = input().strip()
if ideal_choice.isdigit():
if int(ideal_choice) < len(background.ideals) + 1:
dnd_character.ideals.append(background.ideals[int(ideal_choice)-1])
else:
dnd_character.ideals.append(ideal_choice)
# choose bond
print("You may choose one of these bonds or type your own: ")
print(list_to_str_with_number_and_line(background.bonds))
bond_choice = input().strip()
if bond_choice.isdigit():
if int(bond_choice) < len(background.bonds) + 1:
dnd_character.bonds.append(background.bonds[int(bond_choice)-1])
else:
dnd_character.ideals.append(bond_choice)
# choose flaw
print("You may choose one of these flaws or type your own: ")
print(list_to_str_with_number_and_line(background.flaws))
flaw_choice = input().strip()
if flaw_choice.isdigit():
if int(flaw_choice) < len(background.flaws) + 1:
dnd_character.flaws.append(background.flaws[int(flaw_choice)-1])
else:
dnd_character.flaws.append(flaw_choice)
# Class choice
choice_not_validated = True
while choice_not_validated:
print("Choose your class:\n" + ", ".join(classes_list))
class_choice = input().strip()
if is_valid_choice(classes_list, class_choice):
dnd_class = get_class_by_name(class_choice)
print("This is what this class would give you:")
print(dnd_class.to_cli_string())
print("Do you confirm this choice?")
confirm = input().strip()
if confirm == "yes":
dnd_character.set_class(dnd_class)
print("You have chosen the class: " + dnd_class.name)
choice_not_validated = False
# Cantrip and spells choice from class
# Cantrip
class_cantrip_choice_nb = dnd_character.dnd_class.cantrips_choice["number"]
class_cantrip_choice = dnd_character.dnd_class.cantrips_choice["cantrips"]
if class_cantrip_choice_nb > 0:
print("You can choose " + str(
class_cantrip_choice_nb) + " cantrip(s) from the following list:\n" + ", ".join(
class_cantrip_choice))
for i in range(class_cantrip_choice_nb):
choice = input().strip()
dnd_character.add_cantrip(choice)
# Spell lvl 1
class_spell_choice_nb = dnd_character.dnd_class.level_one_choice["number"]
class_spell_choice = dnd_character.dnd_class.level_one_choice["spells"]
if class_spell_choice_nb > 0:
print("You can choose " + str(
class_spell_choice_nb) + " spell(s) from the following list:\n" + ", ".join(
class_spell_choice))
for i in range(class_spell_choice_nb):
choice = input().strip()
dnd_character.add_spell(choice)
# adding all the divine spells of lvl 1 to the known list
if dnd_class.is_divine_spellcaster:
for spell in get_all_spells_of_class_and_level(dnd_class.spellcaster_class, 1):
dnd_character.add_spell(spell)
dnd_character.prepared_spell_number = get_modifier(dnd_character.attributes[dnd_class.spell_casting_ability]) \
+ dnd_character.level
# Skill choice from class possibilities
skill_choices = dnd_character.dnd_class.skill_proficiency_choices["number"]
skill_options = dnd_character.dnd_class.skill_proficiency_choices["skill_list"]
if skill_choices > 0:
print("You already have these proficiencies: " + ", ".join(dnd_character.skill_proficiencies))
print("You have bonus proficiencies, pick " + str(skill_choices)
+ " among the following:\n" + ", ".join(skill_options))
proficiency_choices = set([])
chosen_skills = skill_choices
while chosen_skills > 0:
print("You have " + str(chosen_skills) + " skills left to pick.")
prof_choice = input().strip()
for j in dnd_character.skill_proficiencies:
if prof_choice == j:
print("You already have this skill, choose another")
prof_choice = input().strip()
# if the skill has been added to the chosen list we ask for another choice
if is_valid_choice(proficiency_choices, prof_choice):
print("You already picked this skill, choose another")
prof_choice = input().strip()
if is_valid_choice(skill_options, prof_choice):
proficiency_choices.add(prof_choice)
chosen_skills -= 1
dnd_character.set_bonus_skill_proficiencies(proficiency_choices)
# Adding Tools proficiencies from class
tool_choices = dnd_character.dnd_class.tool_proficiency_choices["number"]
tools_options = dnd_character.dnd_class.tool_proficiency_choices["tool_proficiencies"]
if tool_choices > 0 and tool_choices != len(tools_options):
if len(dnd_character.tool_proficiencies) > 0:
print("You already have these tool proficiencies: " + ", ".join(dnd_character.tool_proficiencies))
print("You can choose " + str(tool_choices) + " tool proficiencies among the following:\n"
+ tools_options)
tool_prof_choices = []
for i in range(tool_choices):
prof_choice = input()
if is_valid_choice(tools_options, prof_choice):
tool_prof_choices.append(prof_choice)
dnd_character.set_bonus_tool_proficiencies(tool_prof_choices)
elif tool_choices > 0:
dnd_character.set_bonus_tool_proficiencies(tools_options)
print("You gain the following tool proficiencies: " + ", ".join(tools_options))
# Check for choices of class feature
features = dnd_character.dnd_class.class_feature_choices
if len(features) > 0:
for _, feature in enumerate(features):
print("You get the following feature: " + feature["name"])
print(feature["description"])
choices = feature["choice_table"]
for j in choices:
print("\t" + j["name"])
print("\t\t" + j["description"])
choice = input()
dnd_character.dnd_class.choose_feature(feature["name"], choice)
# Calculate HP at the end
dnd_character.calc_hp_first_lvl()
# Equipment choice
equipment_choices = len(dnd_character.dnd_class.equipment_choice)
if equipment_choices != '':
choices = dnd_character.dnd_class.equipment_choice.split('#')
for choice in choices:
print("Choose one of these options: ")
options = choice.split('/')
opt_str = ''
for option in options:
opt_str += option + ' or '
opt_str = opt_str[:-3]
print(opt_str)
eq_choice = input().strip()
dnd_character.add_equipment(eq_choice)
# Display character
cli_display(dnd_character)
# Save character to a json format
print("Do you want to save your character?")
answer = input().strip()
if answer == "yes":
dnd_character.export_json()