diff --git a/player.py b/player.py new file mode 100644 index 0000000..4f115a3 --- /dev/null +++ b/player.py @@ -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 +}