Player class has it's own location now to maintain. Includes inventory and equipment as well as initialising items.
585 lines
22 KiB
Python
585 lines
22 KiB
Python
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
|
|
}
|