Skip to content

Commit 444eeb0

Browse files
committed
Mickey's refactor.
1 parent bd5b807 commit 444eeb0

File tree

7 files changed

+291
-30
lines changed

7 files changed

+291
-30
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
# Python-Character-Creator
22
Python for a DnD character creator.
33
Code is supposed to receive inputs from a user so they may be walked through the creation of a DnD character.
4+
5+
TODO:
6+
- critical hits
7+
- critical damage
8+
- more content

character.py

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import math
2+
from random import randint
3+
from dataclasses import dataclass
4+
5+
from entity import Entity
6+
from equipment import armors, weapons
7+
from dice import roll
8+
9+
CHARACTER_ATTRIBUTES = ("Strength", "Dexterity", "Constitution", "Intelligence", "Wisdom", "Charisma")
10+
11+
@dataclass
12+
class PlayerClass:
13+
name: str
14+
starting_hp: int
15+
hit_die: int
16+
17+
classes = list()
18+
classes.append(PlayerClass("Fighter", 6, 10))
19+
20+
# Class to represent a base D&D character.
21+
class Character(Entity):
22+
def __init__(self):
23+
Entity.__init__(self, input("Name your character: "))
24+
self.level = 1
25+
self.picker("class", classes)
26+
self.reset_attributes()
27+
self.pick_attributes(26)
28+
self.max_hp = self.player_class.starting_hp + \
29+
self.get_attribute_mod(CHARACTER_ATTRIBUTES[2]) * self.level
30+
self.current_hp = self.max_hp
31+
print(self.get_attrs_str())
32+
self.picker("armor", armors)
33+
self.picker("weapon", weapons)
34+
35+
def get_attribute_mod(self, attribute):
36+
return math.floor((self.attributes[attribute] - 10) / 2)
37+
38+
def get_attribute_mod_cost(self, attribute):
39+
a = self.attributes[attribute]
40+
if a < 14:
41+
return 1
42+
elif a == 14:
43+
return 2
44+
elif a > 14:
45+
return "MAX"
46+
47+
def reset_attributes(self):
48+
self.attributes = dict()
49+
for a in CHARACTER_ATTRIBUTES:
50+
self.attributes[a] = 8
51+
52+
def pick_attributes(self, points):
53+
numbers = range(1, len(CHARACTER_ATTRIBUTES) + 1)
54+
error = ""
55+
56+
while points > 0:
57+
print(" Attribute\tValue\tModifier\tCost")
58+
for n, a in zip(numbers, CHARACTER_ATTRIBUTES):
59+
print(f"{n}: {a}\t{self.attributes[a]}\t{self.get_attribute_mod(a)}\t{self.get_attribute_mod_cost(a)}")
60+
print()
61+
print(f"Attribute Points: {points}")
62+
print(error)
63+
choice = int(input("Choose an attribute to increase: "))
64+
print()
65+
if choice in numbers:
66+
choice -= 1
67+
a = CHARACTER_ATTRIBUTES[choice]
68+
cost = self.get_attribute_mod_cost(a)
69+
if cost == "MAX":
70+
error = f"{CHARACTER_ATTRIBUTES[choice]} is at maximum"
71+
elif cost <= points:
72+
self.attributes[a] += 1
73+
points -= cost
74+
error = ""
75+
else:
76+
error = f"Not enough points to increase {a}"
77+
else:
78+
error = f"Please pick a number between {min(numbers)} and {max(numbers)}"
79+
80+
def get_attack_bonus(self):
81+
return self.get_attack_attr_bonus() + self.get_proficiency_bonus()
82+
83+
def get_attack_attr_bonus(self):
84+
return max(self.get_attribute_mod["Strength"],
85+
self.get_attribute_mod["Dexterity"]) \
86+
if self.weapon.finesse else self.get_attribute_mod("Strength")
87+
88+
def get_proficiency_bonus(self):
89+
return math.floor(2 + ((self.level - 1) * 0.25))
90+
91+
def roll_weapon_damage(self):
92+
return roll(*self.weapon.damage) + self.get_attack_attr_bonus()
93+
94+
95+
# Report back character name, species, job, stats, and equipment.
96+
def __str__(self):
97+
return f"{self.name} is a level {self.level} {self.player_class.name}\n" \
98+
f"{self.get_health_str()}\n" \
99+
f"Armor: {self.armor.name} AC: {self.armor.armor_class} Weapon: {self.weapon.name}" \
100+
f"{self.get_attrs_str()}"
101+
102+
# Display character's stats.
103+
def get_attrs_str(self):
104+
return ''.join([f"{a}: {self.attributes[a]}\n" for a in CHARACTER_ATTRIBUTES])
105+
106+
def picker(self, pick_type, pick_list):
107+
choices = [g.name for g in pick_list]
108+
numbers = range(1, len(pick_list) + 1)
109+
110+
for i, name in zip(numbers, choices):
111+
print(f"{i}: {name}")
112+
113+
prompt = f"Which {pick_type} would you like? "
114+
115+
while True:
116+
choice = int(input(prompt))
117+
if choice in numbers:
118+
break
119+
else:
120+
prompt = f"Please pick a number between {min(numbers)} and {max(numbers)}: "
121+
122+
if pick_type == "armor":
123+
self.armor = armors[choice - 1]
124+
print(f"You chose {self.armor.name}.\n")
125+
elif pick_type == "weapon":
126+
self.weapon = weapons[choice - 1]
127+
print(f"You chose {self.weapon.name}.\n")
128+
elif pick_type == "class":
129+
self.player_class= classes[choice - 1]
130+
print(f"You chose {self.player_class.name}.\n")
131+
132+
133+
def attack(self, enemy):
134+
attack_roll = roll(1, 20) + self.get_attack_bonus()
135+
print(f"{self.name} swings their {self.weapon.name} at the {enemy.name}!")
136+
if enemy.armor_class < attack_roll:
137+
print(f"{self.name} smacks the {enemy.name} a good one! {attack_roll} vs {enemy.get_ac()} AC")
138+
enemy.take_damage(self.roll_weapon_damage())
139+
else:
140+
print(f"{self.name} wiffs!")
141+
142+
def get_ac(self):
143+
return self.armor.ac + max(self.armor.max_dex_bonus, self.attributes["Dexterity"])

dice.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from random import randint
2+
3+
roll = lambda a, b: sum([randint(1, b) for i in range(a)])

entity.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
class Entity:
2+
def __init__(self, name):
3+
self.name = name
4+
self.max_hp = 0
5+
self.current_hp = 0
6+
7+
def get_hp_str(self):
8+
return f"{self.name} has {self.current_hp} out of {self.max_hp}"
9+
10+
def take_damage(self, amount):
11+
if self.current_hp <= amount:
12+
self.current_hp= 0
13+
print(f"{self.name}'s lifeless form crumples to the floor.")
14+
else:
15+
self.current_hp -= amount
16+
print(f"{self.name} takes {amount} damage and has {self.current_hp} hp remaining of {self.max_hp}.")

equipment.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from dataclasses import dataclass
2+
3+
# THIS NEEDS TO BE FIXED
4+
MAX_INT = 99999
5+
6+
@dataclass
7+
class Armor:
8+
name: str
9+
proficiency: str
10+
cost_gp: int
11+
ac: int
12+
max_dex_bonus: int
13+
min_str: int
14+
stealth_disadvantage: bool
15+
weight: int
16+
17+
armors = list()
18+
armors.append(Armor("Scale Mail", "medium", 50, 14, 2, 0, True, 45))
19+
armors.append(Armor("Studded Leather", "light", 10, 11, MAX_INT, 0, False, 13))
20+
21+
@dataclass
22+
class Weapon:
23+
name: str
24+
martial: bool
25+
ranged: bool
26+
cost: int
27+
damage: (int, int)
28+
damage_type: str
29+
finesse: bool
30+
heavy: bool
31+
light: bool
32+
loading: bool
33+
range_distance: (int, int)
34+
reach: bool
35+
thrown: bool
36+
two_handed: bool
37+
versatile: bool
38+
versatile_damage: (int, int)
39+
40+
weapons = list()
41+
weapons.append(Weapon("Club",
42+
False,
43+
False,
44+
1,
45+
(1, 4),
46+
"bludgeoning",
47+
False,
48+
False,
49+
False,
50+
False,
51+
(0, 0),
52+
False,
53+
False,
54+
False,
55+
False,
56+
(0, 0)))

main.py

100644100755
Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,27 @@
1-
from character_dnd import Character_DnD
2-
from character_dnd import Monster_DnD
3-
from random import randint
1+
#!/usr/bin/env python3
42

5-
# Getting input on character name.
6-
character_name = input(
7-
"Please type what you would like your character name to be? ")
8-
# Getting input on character species.
9-
character_species = input("Please type what you would like your character species to be? Please choose from Human, "
10-
"Elf, or Dwarf. Then hit enter. ")
3+
from character import Character
4+
from monster import monsters
115

12-
while character_species.lower() not in ["human", "elf", "dwarf"]:
13-
character_species = input("Whoops, looks like you didn't choose one of the previous species. Please choose from "
14-
"Human, Elf, or Dwarf. Then hit enter. ")
15-
# Getting input on character job.
16-
character_job = input("Please type what you would like your character's job to be? Please choose from Fighter, Rogue, "
17-
"or Wizard. Then hit enter. ")
186

19-
while character_job.lower() not in ["fighter", "rogue", "wizard"]:
20-
character_job = input("Whoops, looks like you didn't choose one of the previous jobs. PLease choose from Fighter, "
21-
"Rogue, or Wizard. Then hit enter. ")
22-
23-
my_character = Character_DnD(character_name, character_species, character_job)
24-
Kobold = Monster_DnD("Kobold", 5, 12, "a dagger", randint(1, 4), "1/8", -1, 4)
25-
red_dragon = Monster_DnD("the Ancient Red Dragon", 546, 22, "a Bite", randint(2, 10) + 24, 24, 9, 17)
26-
27-
my_character.change_attribute_points()
28-
my_character.weapon_choice()
29-
my_character.armor_choice()
30-
my_character.player_attack(Kobold)
31-
my_character.player_attack(red_dragon)
32-
red_dragon.monster_attack(my_character)
33-
Kobold.monster_attack(my_character)
7+
# my_character.change_attribute_points()
8+
# my_character.weapon_choice()
9+
# my_character.armor_choice()
10+
# my_character.player_attack(Kobold)
11+
# my_character.player_attack(red_dragon)
12+
# red_dragon.monster_attack(my_character)
13+
# Kobold.monster_attack(my_character)
3414
# print(my_character.attribute_points)
3515
# print(my_character)
16+
17+
def fight(p1, p2):
18+
while p1.current_hp > 0 and p2.current_hp > 0:
19+
p1.attack(p2)
20+
if p2.current_hp > 0:
21+
p2.attack(p1)
22+
23+
24+
if __name__ == "__main__":
25+
foo = Character()
26+
bar = monsters["Kobold"]
27+
fight(foo, bar)

monster.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from entity import Entity
2+
from dice import roll
3+
4+
class Monster(Entity):
5+
def __init__(self,
6+
name,
7+
hit_points,
8+
armor_class,
9+
attack_name,
10+
attack_bonus,
11+
damage_roll,
12+
damage_bonus):
13+
Entity.__init__(self, name)
14+
self.name = name
15+
self.max_hp = hit_points
16+
self.current_hp = self.max_hp
17+
self.armor_class = armor_class
18+
self.attack_name = attack_name
19+
self.attack_bonus = attack_bonus
20+
self.damage_roll = damage_roll
21+
self.damage_bonus = damage_bonus
22+
23+
def __repr__(self):
24+
return (f"\n {self.name} is a challenge rating {self.challenge_rating} monster with {self.hit_points} hit "
25+
f"points, {self.armor_class} armor class and that wields {self.weapon}. ")
26+
27+
def attack(self, enemy):
28+
attack_roll = roll(1, 20) + self.attack_bonus
29+
print(f"{self.name} swings their {self.attack_name} at the {enemy.name}!")
30+
if enemy.get_ac() < attack_roll:
31+
print(f"{self.name} smacks {enemy.name} a good one! {attack_roll} vs {enemy.get_ac()} AC")
32+
enemy.take_damage(roll(self.damage_roll) + self.damage_bonus)
33+
else:
34+
print(f"{self.name} wiffs!")
35+
36+
def get_ac(self):
37+
return self.armor_class
38+
39+
monsters = dict()
40+
monsters["Kobold"] = Monster("Kobold",
41+
5,
42+
12,
43+
"dagger",
44+
0,
45+
(1, 4),
46+
0)

0 commit comments

Comments
 (0)