Create player.py
Player class has it's own location now to maintain. Includes inventory and equipment as well as initialising items.
This commit is contained in:
584
player.py
Normal file
584
player.py
Normal file
@@ -0,0 +1,584 @@
|
||||
from enum import Enum, auto
|
||||
from random import randint
|
||||
|
||||
|
||||
class Player:
|
||||
"""Character Creation"""
|
||||
|
||||
# Default Character
|
||||
def __init__(self, name, gender, age, race, job):
|
||||
# Identity
|
||||
self.name = name
|
||||
self.gender = gender
|
||||
self.age = age
|
||||
self.race = race
|
||||
self.job = job
|
||||
# Health (move off Player, keep on Job)
|
||||
# self.hitDie = self.job.hd
|
||||
# self.currentHP = 100
|
||||
# self.maxHP = 100
|
||||
# Levels
|
||||
self.level = 1
|
||||
self.exp = 0
|
||||
self.maxEXP = 100
|
||||
# Magic (Not ready yet)
|
||||
# self.spells_known = []
|
||||
# self.spells_ready = []
|
||||
# Equipment
|
||||
self.weapon = rock
|
||||
self.armor = tornRags
|
||||
# Defence
|
||||
self.ac = 0
|
||||
self.elemental_resistance = {DamageType.FIRE: False, DamageType.WATER: False, DamageType.LIGHTNING: False}
|
||||
self.physical_resistance = {DamageType.SLASHING: False, DamageType.CRUSHING: False, DamageType.PIERCING: False}
|
||||
# Ability Scores
|
||||
self.stats = {"Strength": 0,
|
||||
"Dexterity": 0,
|
||||
"Constitution": 0,
|
||||
"Intelligence": 0,
|
||||
"Wisdom": 0,
|
||||
"Charisma": 0}
|
||||
# Ability Modifiers
|
||||
self.mods = {"Strength": 0,
|
||||
"Dexterity": 0,
|
||||
"Constitution": 0,
|
||||
"Intelligence": 0,
|
||||
"Wisdom": 0,
|
||||
"Charisma": 0}
|
||||
# Held items
|
||||
self.inventory = {rock: {"Count": 1,
|
||||
"object": Weapon,
|
||||
"equipped": True
|
||||
},
|
||||
paper: {"Count": 1,
|
||||
"object": Weapon,
|
||||
"equipped": False
|
||||
},
|
||||
tornRags: {"Count": 1,
|
||||
"object": Armor,
|
||||
"equipped": True
|
||||
},
|
||||
GP1: {"Count": 10,
|
||||
"object": Money,
|
||||
"equipped": False
|
||||
},
|
||||
}
|
||||
|
||||
def getModifier(self):
|
||||
"""Floor calculation to work out skill check modifiers"""
|
||||
self.mods["Strength"] = -5 + self.stats["Strength"] // 2
|
||||
self.mods["Dexterity"] = -5 + self.stats["Dexterity"] // 2
|
||||
self.mods["Constitution"] = -5 + self.stats["Constitution"] // 2
|
||||
self.mods["Intelligence"] = -5 + self.stats["Intelligence"] // 2
|
||||
self.mods["Wisdom"] = -5 + self.stats["Wisdom"] // 2
|
||||
self.mods["Charisma"] = -5 + self.stats["Charisma"] // 2
|
||||
|
||||
def set_stats_race(self):
|
||||
if self.race.lower() == "human":
|
||||
print("As a Human, two different ability scores of your choice increase by 1.")
|
||||
selection1 = input("Choose the first ability score to increase by 1.\n"
|
||||
"1) Strength\n"
|
||||
"2) Dexterity\n"
|
||||
"3) Constitution\n"
|
||||
"4) Intelligence\n"
|
||||
"5) Wisdom\n"
|
||||
"6) Charisma\n\n >> ").lower()
|
||||
while True:
|
||||
if selection1 in ("1", "strength"):
|
||||
self.stats["Strength"] += 1
|
||||
break
|
||||
elif selection1 in ("2", "dexterity"):
|
||||
self.stats["Dexterity"] += 1
|
||||
break
|
||||
elif selection1 in ("3", "constitution"):
|
||||
self.stats["Constitution"] += 1
|
||||
break
|
||||
elif selection1 in ("4", "intelligence"):
|
||||
self.stats["Intelligence"] += 1
|
||||
break
|
||||
elif selection1 in ("5", "wisdom"):
|
||||
self.stats["Wisdom"] += 1
|
||||
break
|
||||
elif selection1 in ("6", "charisma"):
|
||||
self.stats["Charisma"] += 1
|
||||
break
|
||||
else:
|
||||
selection1 = input("Sorry, I didn't recognise that. Please select from the following:\n"
|
||||
"1) Strength\n"
|
||||
"2) Dexterity\n"
|
||||
"3) Constitution\n"
|
||||
"4) Intelligence\n"
|
||||
"5) Wisdom\n"
|
||||
"6) Charisma\n >> ").lower()
|
||||
continue
|
||||
|
||||
selection2 = input("Choose the second ability score to increase by 1.\n"
|
||||
"1) Strength\n"
|
||||
"2) Dexterity\n"
|
||||
"3) Constitution\n"
|
||||
"4) Intelligence\n"
|
||||
"5) Wisdom\n"
|
||||
"6) Charisma\n\n >> ").lower()
|
||||
while True:
|
||||
if selection2 in ("1", "strength"):
|
||||
self.stats["Strength"] += 1
|
||||
break
|
||||
elif selection2 in ("2", "dexterity"):
|
||||
self.stats["Dexterity"] += 1
|
||||
break
|
||||
elif selection2 in ("3", "constitution"):
|
||||
self.stats["Constitution"] += 1
|
||||
break
|
||||
elif selection2 in ("4", "intelligence"):
|
||||
self.stats["Intelligence"] += 1
|
||||
break
|
||||
elif selection2 in ("5", "wisdom"):
|
||||
self.stats["Wisdom"] += 1
|
||||
break
|
||||
elif selection2 in ("6", "charisma"):
|
||||
self.stats["Charisma"] += 1
|
||||
break
|
||||
else:
|
||||
selection2 = input("Sorry, I didn't recognise that. Please select from the following:\n"
|
||||
"1) Strength\n"
|
||||
"2) Dexterity\n"
|
||||
"3) Constitution\n"
|
||||
"4) Intelligence\n"
|
||||
"5) Wisdom\n"
|
||||
"6) Charisma\n >> ").lower()
|
||||
continue
|
||||
|
||||
elif self.race.lower() == "elf":
|
||||
self.stats["Dexterity"] += 2
|
||||
|
||||
elif self.race.lower() == "dwarf":
|
||||
self.stats["Constitution"] += 2
|
||||
|
||||
def set_stats_job(self):
|
||||
if self.job.lower() == "warrior":
|
||||
self.hitDie = randint(1, 12)
|
||||
self.maxHP = (12 + self.mods["Constitution"])
|
||||
self.currentHP = (12 + self.mods["Constitution"])
|
||||
|
||||
elif self.job.lower() == "cleric":
|
||||
self.hitDie = randint(1, 10)
|
||||
self.maxHP = (10 + self.mods["Constitution"])
|
||||
self.currentHP = (10 + self.mods["Constitution"])
|
||||
|
||||
elif self.job.lower() == "mage":
|
||||
self.hitDie = randint(1, 8)
|
||||
self.maxHP = (8 + self.mods["Constitution"])
|
||||
self.currentHP = (8 + self.mods["Constitution"])
|
||||
|
||||
def current_stats(self):
|
||||
"""Prints a display of the user's current statistics."""
|
||||
print("Your current stats are:")
|
||||
print(f'Hit Points: {self.currentHP}/{self.maxHP}')
|
||||
print(f'Strength: {self.stats["Strength"]}')
|
||||
print(f'Dexterity: {self.stats["Dexterity"]}')
|
||||
print(f'Constitution: {self.stats["Constitution"]}')
|
||||
print(f'Intelligence: {self.stats["Intelligence"]}')
|
||||
print(f'Wisdom: {self.stats["Wisdom"]}')
|
||||
print(f'Charisma: {self.stats["Charisma"]}')
|
||||
|
||||
def current_equip(self):
|
||||
"""Prints a list of items currently equipped."""
|
||||
print(f"You have equipped:\n {self.armor.name}\n"
|
||||
f" {self.armor.description}"
|
||||
f"\n{self.weapon.name}\n"
|
||||
f" {self.weapon.description}")
|
||||
|
||||
def drop_item(self, object1):
|
||||
x = None
|
||||
for list_key, list_value in self.inventory.items(): # string, dictionary
|
||||
if object1 in list_key.name.lower(): # if user input is in the inventory list
|
||||
x = self.inventory.copy()
|
||||
del x[list_key]
|
||||
print("Did I drop it?")
|
||||
return x
|
||||
|
||||
# Add the inventory commands to parser // take off Player
|
||||
|
||||
def update_inventory(self, x):
|
||||
self.inventory = x
|
||||
|
||||
def loot_object(self, object1):
|
||||
for scene, room in Map.scenes.items(): # iterate map scenes
|
||||
if Engine.seed == scene: # set new Engine seed in each room.enter()
|
||||
for list_key, list_value in room.lootable_items.items(): # string, dictionary
|
||||
for var, count in list_value.items(): # variable/object, integer
|
||||
if object1 in list_key: # if user input is in the lootable items
|
||||
|
||||
if var in self.inventory: # if object is in inventory
|
||||
self.inventory[var]["Count"] += count # increase item count
|
||||
print(f'{var.name} x {count} has been added to your existing stack.')
|
||||
|
||||
elif var not in self.inventory[var]: # if variable not in inventory
|
||||
self.inventory[var] = {"Count": count, # add it in
|
||||
"object": var.type,
|
||||
"equipped": False}
|
||||
print(f'{var.name} x {count} has been added to your rucksack.')
|
||||
|
||||
room.lootable_items[object1][var] = 0 # set item to 0
|
||||
break
|
||||
else:
|
||||
print("You don't see one of those to loot.")
|
||||
break
|
||||
|
||||
def add_inventory(self, object1):
|
||||
for scene, room in Map.scenes.items(): # iterate map scenes
|
||||
if Engine.seed == scene: # set new Engine seed in each room.enter()
|
||||
for list_key, list_value in room.available_items.items(): # string, dictionary
|
||||
for var, count in list_value.items(): # variable/object, integer
|
||||
if object1 in list_key: # if user input is in the available items
|
||||
|
||||
response = input(f'There are {room.available_items[object1][var]}.\n'
|
||||
f'How many will you take?\n>> ').lower()
|
||||
if response in ("0", "none"):
|
||||
break
|
||||
elif response == "all":
|
||||
if var in self.inventory:
|
||||
self.inventory[var]["Count"] += count # increase item count
|
||||
print(f'{var.name} x {count} has been added to your existing stack.')
|
||||
room.available_items[object1][var] = 0
|
||||
|
||||
elif var not in self.inventory: # if objects not in inventory
|
||||
self.inventory[var] = {"Count": count, # add it in
|
||||
"object": var.type,
|
||||
"equipped": False}
|
||||
print(f'{var.name} x {count} has been added to your rucksack.')
|
||||
room.available_items[object1][var] = 0
|
||||
|
||||
elif int(response) <= count:
|
||||
if var in self.inventory:
|
||||
self.inventory[var]["Count"] += int(response) # increase item count
|
||||
print(f'{var.name} x {response} has been added to your existing stack.')
|
||||
room.available_items[object1][var] = \
|
||||
room.available_items[object1][var] - int(response)
|
||||
|
||||
elif var not in self.inventory: # if objects not in inventory
|
||||
self.inventory[var] = {"Count": response, # add it in
|
||||
"object": var.type,
|
||||
"equipped": False}
|
||||
print(f'{var.name} x {response} has been added to your rucksack.')
|
||||
room.available_items[object1][var] = \
|
||||
room.available_items[object1][var] - int(response)
|
||||
|
||||
else:
|
||||
print("You can't take more than exist.")
|
||||
|
||||
break
|
||||
else:
|
||||
print("You don't see any lying around..")
|
||||
break
|
||||
|
||||
def new_char(self):
|
||||
"""Outputs final stats, armour, and inventory"""
|
||||
self.allocation()
|
||||
self.set_stats_race()
|
||||
self.set_stats_job()
|
||||
self.getModifier()
|
||||
self.current_stats()
|
||||
print(' ')
|
||||
self.current_equip()
|
||||
print(' ')
|
||||
self.current_inventory()
|
||||
print(' ')
|
||||
|
||||
def health_check(self):
|
||||
"""Print out current/max HP"""
|
||||
print(f'You have {self.currentHP}/{self.maxHP} HP.')
|
||||
|
||||
def take_damage(self, DMGtype, size):
|
||||
"""Define the damage type and dice size"""
|
||||
damage = randint(1, size)
|
||||
if DMGtype in self.elemental_resistance or DMGtype in self.physical_resistance:
|
||||
damage //= 2
|
||||
self.currentHP -= damage
|
||||
return damage
|
||||
|
||||
def allocation(self):
|
||||
while True:
|
||||
self.stats["Strength"] = 0
|
||||
self.stats["Dexterity"] = 0
|
||||
self.stats["Constitution"] = 0
|
||||
self.stats["Intelligence"] = 0
|
||||
self.stats["Wisdom"] = 0
|
||||
self.stats["Charisma"] = 0
|
||||
rolls = []
|
||||
stats = []
|
||||
attributes = ["Strength", "Dexterity", "Constitution", "Intelligence", "Wisdom", "Charisma"]
|
||||
while len(stats) != 6:
|
||||
# roll 4d6
|
||||
for roll in range(4):
|
||||
r = randint(1, 6)
|
||||
if r < 6:
|
||||
r = randint(1, 6)
|
||||
rolls.append(r)
|
||||
# Drop the lowest number and then add to single value
|
||||
del rolls[rolls.index(min(rolls))]
|
||||
val = sum(rolls)
|
||||
stats.append(str(val))
|
||||
rolls = []
|
||||
|
||||
print(f"Please assign a stat to a selected attribute by entering the number then the attribute.\n"
|
||||
f"For example, '10 strength' will assign 10 to your strength, if you have a 10 available.\n\n"
|
||||
f"Please select a stat and an attribute.\n\n"
|
||||
f"Your rolled stats are:\n {', '.join(stats)}\n\n"
|
||||
f"Your attributes are:\n {', '.join(attributes)}\n")
|
||||
|
||||
# Allocate
|
||||
while len(stats) != 0:
|
||||
input_text = input(">> ").title()
|
||||
words = input_text.split()
|
||||
if words[0] in stats and words[1] in attributes:
|
||||
self.stats[words[1]] += int(words[0])
|
||||
stats.remove(words[0])
|
||||
attributes.remove(words[1])
|
||||
if len(stats) == 0:
|
||||
print("")
|
||||
break
|
||||
print("The remaining options are:\n")
|
||||
print(', '.join(stats))
|
||||
print(', '.join(attributes))
|
||||
else:
|
||||
print("Error. Input was not recognised. Please try again with 'Number' + 'Attribute'.")
|
||||
continue
|
||||
|
||||
print(f"Your current stats are:\n"
|
||||
f'Strength: {self.stats["Strength"]}\n'
|
||||
f'Dexterity: {self.stats["Dexterity"]}\n'
|
||||
f'Constitution: {self.stats["Constitution"]}\n'
|
||||
f'Intelligence: {self.stats["Intelligence"]}\n'
|
||||
f'Wisdom: {self.stats["Wisdom"]}\n'
|
||||
f'Charisma: {self.stats["Charisma"]}\n')
|
||||
|
||||
select = input("Are you happy with this selection? Y/N?\n"
|
||||
"WARNING: If you select 'N', your dice will be randomly rolled again. Proceed?\n"
|
||||
" >> ").lower()
|
||||
if select == "n":
|
||||
continue
|
||||
if select == 'y':
|
||||
break
|
||||
|
||||
elif select not in ("y", "n"):
|
||||
print("Error. Input was not recognised. Please select 'Y' or 'N'.")
|
||||
select = input("Are you happy with this selection? Y/N?\n"
|
||||
"WARNING: If you select 'N', your dice will be randomly rolled again. Proceed?\n"
|
||||
" >> ").lower()
|
||||
if select == "y":
|
||||
break
|
||||
else:
|
||||
continue
|
||||
|
||||
|
||||
class DamageType(Enum):
|
||||
SLASHING = auto()
|
||||
CRUSHING = auto()
|
||||
PIERCING = auto()
|
||||
FIRE = auto()
|
||||
WATER = auto()
|
||||
LIGHTNING = auto()
|
||||
|
||||
|
||||
class DamageMod(Enum):
|
||||
STRENGTH = auto()
|
||||
DEXTERITY = auto()
|
||||
CONSTITUTION = auto()
|
||||
INTELLIGENCE = auto()
|
||||
WISDOM = auto()
|
||||
CHARISMA = auto()
|
||||
|
||||
|
||||
class ItemType(Enum):
|
||||
ARMOR = auto()
|
||||
WEAPON = auto()
|
||||
MONEY = auto()
|
||||
ITEM = auto()
|
||||
|
||||
|
||||
class Slots(Enum):
|
||||
MainHand = auto()
|
||||
OffHand = auto()
|
||||
TwoHanded = auto()
|
||||
Helm = auto()
|
||||
Chest = auto()
|
||||
Wrists = auto()
|
||||
Feet = auto()
|
||||
Neck = auto()
|
||||
Cloak = auto()
|
||||
LeftRing = auto()
|
||||
RightRing = auto()
|
||||
Attunement = auto()
|
||||
|
||||
|
||||
class Item:
|
||||
"""The base class for all items"""
|
||||
|
||||
def __init__(self, name, description, value, magical):
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.value = value
|
||||
self.magical = magical
|
||||
self.type = Item
|
||||
self.count = 1
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.name}\n=====\n{self.description}\nValue: {self.value}\n"
|
||||
|
||||
|
||||
class Money(Item):
|
||||
"""The currency item used in the world of Kanjin"""
|
||||
|
||||
def __init__(self, name, amt, magical):
|
||||
self.name = name
|
||||
self.amt = amt
|
||||
self.magical = magical
|
||||
self.type = ItemType.MONEY
|
||||
super().__init__(name=self.name,
|
||||
description=f"A small round coin made of {self.name.lower()} "
|
||||
f"with the imperial city logo stamped on the face.",
|
||||
value=self.amt,
|
||||
magical=self.magical)
|
||||
|
||||
|
||||
class Weapon(Item):
|
||||
"""The base class for all weapons"""
|
||||
|
||||
def __init__(self, name, description, value, slot, damage1H, damage2H,
|
||||
dmgType, dmgMod, versatile, thrown, itemType, magical):
|
||||
self.slot = slot
|
||||
self.damage1H = damage1H
|
||||
self.damage2H = damage2H
|
||||
self.dmgType = dmgType
|
||||
self.dmgMod = dmgMod
|
||||
self.versatile = versatile
|
||||
self.thrown = thrown
|
||||
self.itemType = itemType
|
||||
super().__init__(name, description, value, magical)
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.name}\n=====" \
|
||||
f"\n{self.description}" \
|
||||
f"\nValue: {self.value}" \
|
||||
f"\nDamage: One Handed - {self.damage1H}" \
|
||||
f"\nDamage: Two Handed - {self.damage2H}" \
|
||||
f"\nDamage Type: {self.dmgType}" \
|
||||
f"\nMagical: {self.magical}"
|
||||
|
||||
|
||||
class Armor(Item):
|
||||
"""The base class for all armor"""
|
||||
|
||||
def __init__(self, name, description, value, grade, ac, disadvantage, dmgRes,
|
||||
itemType, magical):
|
||||
self.grade = grade
|
||||
self.ac = ac
|
||||
self.stealthDis = disadvantage
|
||||
self.dmgRes = dmgRes
|
||||
self.itemType = itemType
|
||||
super().__init__(name, description, value, magical)
|
||||
|
||||
def __repr__(self):
|
||||
if self.stealthDis:
|
||||
return f"{self.name}\n" \
|
||||
f"=====\n" \
|
||||
f"{self.description}\n" \
|
||||
f"Value: {self.value}\n" \
|
||||
f"AC: {self.ac}\n" \
|
||||
f"Magical: {self.magical}"
|
||||
elif not self.stealthDis:
|
||||
return f"{self.name}\n=====" \
|
||||
f"\n{self.description}\n" \
|
||||
f"Value: {self.value}\n" \
|
||||
f"AC: {self.ac}\n" \
|
||||
f"Disadvantage on Stealth checks: {self.stealthDis}\n" \
|
||||
f"Magical: {self.magical}\n"
|
||||
|
||||
|
||||
# Different types of coins
|
||||
GP1 = Money("Gold", 1, False)
|
||||
SP1 = Money("Silver", 1, False)
|
||||
CP1 = Money("Copper", 1, False)
|
||||
|
||||
# starting equip
|
||||
rock = Weapon(
|
||||
name="Rock",
|
||||
description="A fist-sized rock, suitable for bludgeoning.",
|
||||
value=None,
|
||||
slot=Slots.MainHand,
|
||||
damage1H='1d6',
|
||||
damage2H=None,
|
||||
dmgType=DamageType.CRUSHING,
|
||||
dmgMod=DamageMod.STRENGTH,
|
||||
versatile=False,
|
||||
thrown=True,
|
||||
itemType="Weapon",
|
||||
magical=False
|
||||
)
|
||||
|
||||
dagger = Weapon(
|
||||
name="Dagger",
|
||||
description="Pointy stabby-stab",
|
||||
value=None,
|
||||
slot=Slots.MainHand,
|
||||
damage1H='1d6',
|
||||
damage2H=None,
|
||||
dmgType=DamageType.SLASHING,
|
||||
dmgMod=DamageMod.DEXTERITY,
|
||||
versatile=False,
|
||||
thrown=True,
|
||||
itemType="Weapon",
|
||||
magical=False
|
||||
)
|
||||
|
||||
tornRags = Armor(
|
||||
name="Torn Rags",
|
||||
description="A ripped and worn-out outfit.",
|
||||
value=None,
|
||||
grade="Light",
|
||||
ac=0,
|
||||
disadvantage=True,
|
||||
dmgRes="None",
|
||||
itemType="Armor",
|
||||
magical=False
|
||||
)
|
||||
paper = Item(
|
||||
name="Paper",
|
||||
description="A blank piece of paper",
|
||||
value=None,
|
||||
magical=False
|
||||
)
|
||||
|
||||
Inventory = {
|
||||
rock: {"Count": 1,
|
||||
"object": Weapon,
|
||||
},
|
||||
dagger: {"Count": 1,
|
||||
"object": Weapon,
|
||||
},
|
||||
paper: {"Count": 1,
|
||||
"object": Item
|
||||
},
|
||||
tornRags: {"Count": 1,
|
||||
"object": Armor
|
||||
},
|
||||
GP1: {"Count": 10,
|
||||
"object": Money
|
||||
},
|
||||
}
|
||||
|
||||
Equipment = {
|
||||
"Main Hand": rock,
|
||||
"Off Hand": None,
|
||||
"Two Handed": None,
|
||||
"Helm": None,
|
||||
"Chest": tornRags,
|
||||
"Wrists": None,
|
||||
"Feet": None,
|
||||
"Neck": None,
|
||||
"Cloak": None,
|
||||
"Left Ring": None,
|
||||
"Right Ring": None,
|
||||
"Attunement": None
|
||||
}
|
||||
Reference in New Issue
Block a user