-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcharacter.py
296 lines (251 loc) · 8.81 KB
/
character.py
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
from Dice import Dice
import math
class Character:
"""
Class defines each PC or NPC, including generation and level up
"""
def __init__(self, name=None, char_class=None, race=None, verbose=False):
"""
Creates basic char, including race, name and basic stats
If inputs are empty, char will be generated by prompt
:param name: char name
:param char_class: his class
:param race: his race
:param verbose: whether prompt should explain steps
"""
self.MIND = 0
self.STR = 0
self.DEX = 0
self.level = 1
self.physical = 1
self.subterfuge = 1
self.knowledge = 1
self.communication = 1
self.attack_bonus = 0
self.damage_bonus = 0
self.wallet = 0
self.name = name
if self.name is None:
self.name_prompt()
self.race = race
if self.race is None:
self.race_prompt(verbose)
self.race_calc()
self.char_class = char_class
if self.char_class is None:
self.class_prompt(verbose)
self.class_calc()
self.assign_attributes(verbose)
def name_prompt(self):
"""
Gets char name
:return: sets name
"""
self.name = str(input("What is your characters name?"))
def race_prompt(self, verbose):
"""
User prompt for race choice
:param verbose: whether or not to explain each choice
:return: race
"""
while True:
if verbose:
print("\nRaces: \n \u2022 Humans, +1 to all skill rolls\n \u2022 Elves, +2 MIND"
"\n \u2022 Dwarves, +2 STR \n \u2022 Halflings, +2 DEX")
try:
resp = int(input("Are they a Human[0], Elf[1], Dwarf[2] or Halfling[3]?"))
if 4 > resp > -1:
self.race = resp
break
except ValueError:
continue
def class_prompt(self, verbose):
"""
User prompt for class choice
:param verbose: whether or not to explain each choice
:return: class
"""
while True:
if verbose:
print("\nClasses: \n \u2022"
" Fighters, "
"may wear any kind of armor and use shields, +3 bonus to Physical,"
" +1 to all attack and damage rolls"
"\n \u2022 "
"Rogues, "
"may use light armor, +3 bonus to Subterfuge, after successful sneak may add Subterfuge to damage"
"\n \u2022 "
"Magi, "
"may not wear armor, +3 bonus to Knowledge, may cast Magi spells "
"\n \u2022"
" Clerics, "
"may use light or medium armor, +3 bonus to Communication,"
" can turn undead with Magic Attacks and cast Divine spells")
try:
resp = int(input("Are they a Fighter[0], Rogue[1], Magi[2] or Cleric[3]?"))
if 4 > resp > -1:
self.char_class = resp
break
except ValueError:
continue
def race_calc(self):
"""
Calculates effect of race choice on stats
:return: Attribute changes made to class
"""
if self.race == 0:
self.physical += 1
self.subterfuge += 1
self.knowledge += 1
self.communication += 1
elif self.race == 1:
self.MIND += 2
self.race = 1
elif self.race == 2:
self.STR += 2
self.race = 2
elif self.race == 3:
self.DEX += 2
self.race = 3
def class_calc(self):
"""
Calculates effect of class choice on stats
:return: adjusts stats based on class
"""
if self.char_class == 0:
self.wallet += 150
self.physical += 3
self.attack_bonus += 1
self.damage_bonus += 1
elif self.char_class == 1:
self.wallet += 125
self.subterfuge += 3
elif self.char_class == 2:
self.wallet += 75
self.knowledge += 3
elif self.char_class == 3:
self.wallet += 125
self.communication += 3
def assign_attributes(self, verbose):
"""
Assigns attributes at generation, based on player choice
:return: nothing
"""
if verbose:
print("\nAttributes represent the overall physical and mental qualities of an individual."
" They define the raw potential an individual has regardless of actual skill.")
print("To define these Attributes, the computer will roll 4D6, dropping the lowest roll, and you"
" will choose which score to assign to 3 Attributes:\n \u2022 Strength(STR)"
"\n \u2022 Dexterity(DEX)\n \u2022 Mind(MIND)")
outs = Dice(4, 6, 0).calculate_rolls()
outs.remove(min(outs))
self.STR = int(input(f"Assign STR {outs[0]}, {outs[1]} or {outs[2]}"))
outs.remove(self.STR)
self.DEX = int(input(f"Assign DEX {outs[0]} or {outs[1]}"))
outs.remove(self.DEX)
print(f"Assigning {outs[0]} to MIND")
self.MIND = outs[0]
def level_up(self, choice=0, verbose=False):
"""
Levels character up, including recalculating stats dependant on the core stats
Accounts for both 3rd level extra attribute point, and fighter 5th level bonus
:return: New stats
"""
if verbose:
print("Congratulations! You have leveled up! Your skills and attack rolls have been increased by 1.")
self.level += 1
self.subterfuge += 1
self.knowledge += 1
self.communication += 1
self.physical += 1
self.attack_bonus += 1
if self.level % 3 == 0:
if verbose:
choice = self.make_choice()
if choice == 0:
self.STR += 1
elif choice == 1:
self.DEX += 1
elif choice == 2:
self.MIND += 1
if self.char_class == 0 and self.level % 5 == 0:
if verbose:
print("Congratulations Fighter, this level you get an extra bonus to damage and attack rolls!")
self.attack_bonus += 1
self.damage_bonus += 1
@staticmethod
def make_choice():
"""
Gives prompt to make choice
:return: attribute code
"""
print("As this is a level divisible by 3,"
" you may choose whether to allocate an extra point to STR, DEX or MIND")
while True:
choice = input("Allocate to STR[A], DEX[B] or MIND[C]?").lower()
if choice == 'a':
return 0
elif choice == "b":
return 1
elif choice == "c":
return 2
else:
continue
def hp(self):
"""
Calculate HP
:return: the hp value
"""
return self.STR + 6
def ac(self):
"""
Calculate AC from class, not including equipment
:return: The AC value
"""
return self.DEX + 10
def melee(self):
"""
Calculate ranged attack bonus
:return: the ranged sub attribute
"""
return self.STR + self.level
def ranged(self):
"""
Calculate ranged attack bonus
:return: the ranged sub attribute
"""
return self.DEX + self.level
def magic(self):
"""
Calculate ranged attack bonus
:return: the ranged sub attribute
"""
return self.MIND + self.level
@staticmethod
def calculate_attribute_bonus(attribute):
"""
Calculates attribute bonus value
:param attribute: STR/DEX/MIND value
:return: The value of the bonus
"""
return math.floor((attribute - 10) / 2)
def saving_throw(self, attribute):
"""
Calculate a saving throw
:return: the value of the saving throw
"""
return Dice(1, 20).calculate() + self.calculate_attribute_bonus(attribute) + (0.5 * self.level)
def skill_roll(self, skill, attribute):
"""
Calculate skill roll result
:param skill: the skill in question
:param attribute: the attribute
:return: the result of the skill roll
"""
return Dice(1, 20).calculate() + skill + self.calculate_attribute_bonus(attribute)
def initiative(self):
"""
returns initiative value
:return: initiative
"""
return Dice(1, 20).calculate() + self.DEX