Newer
Older
class GameObject:
'''
This is a base class for game objects which all other item 'types'
are based on.
You shouldn't use this base class to generate objects unless it is an interactionless
item, instead use a class that inherits <class GameObject>
'''
id = ""
name = ""
can_pickup = False
can_place = False
spawnable = {} # Place Map class as key and probability as value that an item will spawn in a room
on_interaction = None # The function in the class that is reponsible for carrying out an interaction
Thomas Glasper
committed
equippable = False
conflict = False # This state is changed if the id has been updated due to two items having the same id
def __init__(self, id, name, description, pickup=True, place=True):
'''
This is the init method, so the method which is called when a new GameObject is generated
When creating a new GameObject, pass values through GameObject() so that they become properties
'''
self.can_pickup = pickup
self.can_place = place
self.description = description
self.name = name
self.id = id
Thomas Glasper
committed
def inspect(self):
print(self.name)
print(self.description)
print("")
def _interaction(self):
'''
If you want an item with a special purpose (other than a generic purpose, like a weapon)
you should inherit GameObject and implement this method, also setting on_interaction to this method
'''
pass
def dispose(self, rooms, player):
# Destroys the item from anywhere where it may exist in the game space
location = self.get_location(rooms, player)
if location == "INVENTORY":
place_in_list = player.inventory.index(self)
del player.inventory[place_in_list]
elif location == "EQUIPPED":
for category in player.equipped:
item = player.equipped[category]
if self == item:
player.equipped[category] = None
else:
place_in_list = rooms[location].items.index(self)
del rooms[location].items[place_in_list]
def get_location(self, rooms, player):
'''
This function will return the location of a specific (not general) item.
As it only expects an item to exist in one location at a time, it will not
return multiple locations. You may also pass just inventory in the case of an interaction
of an item in the inventory
If you want multiple versions of one item, consider creating many instances of the class
'''
if rooms:
for room in rooms:
if self in rooms[room].items:
return room
for category in player.equipped:
item = player.equipped[category]
if self == item: return "EQUIPPED"
# If the item can't be found in a room, it must be in someone's inventory
if self == item:
return "INVENTORY"
# Else, return nothing as this object does not exist in the game space
return None
class DurableItem(GameObject):
'''
DurableItem is an intermediate class for items (such as defense or attack items) that have durability
'''
durability = 0
def __init__(self, id, name, description, dura, pickup=True, place=True):
super().__init__(id, name, description, pickup, place)
self.durability = dura
def checkout_dura(self, player, rooms, durability_loss):
For DurableItem, checkout_dura(rooms, player, x: int) will take an integer and remove the amount
of durability from the item. If the item reaches 0, then the class should be removed from the game space
'''
self.durability -= durability_loss
if self.durability <= 0:
print(f"{self.name} has broken!")
self.dispose(rooms, player)
print(f'{self.name} has lost {durability_loss} durability!')
class Weapon(DurableItem):
attack = 0
wobble = 0.1
Thomas Glasper
committed
equippable = True
def __init__(self, id, name, description, attack, dura, wobble=0, pickup=True, place=True):
super().__init__(id, name, description, dura, pickup, place)
self.attack = attack
self.wobble = wobble
Thomas Glasper
committed
def inspect(self):
print(self.name)
print(self.description)
print("It is a weapon, and has " + str(self.attack) + " attack power.")
print("It has a wobble stat of " + str(self.wobble) + ".")
print("It has " + str(self.durability) + " durability left.\n")
Thomas Glasper
committed
def get_attack(self):
'''
This function is designed to get the attach amount of usage of this item
Wobble is a percentage of how much the damage will variate around the base value attack
For example, a wobble of 0.1 (10%) means the value will variate -10% / +10% the attack value
'''
lower_value = round(self.attack - (self.attack * self.wobble))
higher_value = round(self.attack + (self.attack * self.wobble))
return random.randint(lower_value, higher_value)
class Defense(DurableItem):
Thomas Glasper
committed
defense = 0 # defense is a base value between 0-1 which is a percentage of how much the damage will be reduced
wobble = 0.0 # wobble is percentage variation (+/-) around the baseline defense percentage
Thomas Glasper
committed
equippable = True
def __init__(self, id, name, description, defense, dura, wobble=0.0, pickup=True, place=True):
super().__init__(id, name, description, dura, pickup, place)
self.defense = defense
self.wobble = wobble
Thomas Glasper
committed
def inspect(self):
print(self.name)
print(self.description)
print("It is a defense item, and has " + str(self.defense) + " defense power.")
print("It has a wobble stat of " + str(self.wobble) + ".")
print("It has " + str(self.durability) + " durability left.\n")
def get_defense(self, base_defense, damage_amount):
'''
get_defense(x: int) is designed to see how much of the attack will be defended, aligning to the % defense and
how much wobble will be applied
'''
p_defense_lower = round(self.defense - (self.defense * self.wobble))
p_defense_higher = round(self.defense + (self.defense * self.wobble))
percentage_defense = random.randint(p_defense_lower, p_defense_higher)
final_damage = damage_amount - base_defense - (damage_amount * percentage_defense)
# magic items increase luck
Thomas Glasper
committed
class Magic(GameObject):
magic = 0
on_interaction_description = "to use this item"
equippable = True
def __init__(self, id, name, description, magic, pickup=True, place=True):
super().__init__(id, name, description, pickup, place)
Thomas Glasper
committed
self.magic = magic
Thomas Glasper
committed
def inspect(self):
print(self.name)
print(self.description)
print("It is a magic item, and has " + str(self.magic) + " magic power.\n")
class HealthItem(GameObject):
health = 0
on_interaction_description = "to use this item"
def __init__(self, id, name, description, health, pickup=True, place=True):
super().__init__(id, name, description, pickup, place)
self.health = health
Thomas Glasper
committed
def inspect(self):
print(self.name)
print(self.description)
print("It is a health item, and has " + str(self.health) + " health value.\n")
Thomas Glasper
committed
def _interaction(self, player):
# We don't need to heal if the player's health is more than 100
print(f"You can't use {self.name} - your health is already at 100 HP!")
player.hp += self.health
# Don't allow the player's health to get higher than 100
if player.hp >= player.base_hp:
player.hp = player.base_hp
print(f'Success, your health is now {player.hp} HP!')
self.dispose(None, player)
on_interaction = _interaction
class Chest(GameObject):
contains = None # contains is expected to be a subclass of GameObject, a list or a NoneType
requires = None # None means no key or anything is needed, else this should be set to Unlocks class
opened = False
on_interaction_description = "to open the chest"
def __init__(self, id, name, description, contains, requires=None, pickup=False, place=False):
super().__init__(id, name, description, pickup, place)
self.contains = contains
self.requires = requires
def _interaction(self, player):
# Upon interacting with a chest item, the player should be awarded the items inside
# One should pass the inventory list to the function and expect to receive the updated inventory back
if self.opened:
print(f'This {self.id.upper()} has already been opened')
else:
# Check if the player has the item required to unlock the chest, if needed
if self.requires:
if not self.requires in player.inventory:
print(f"This {self.id.upper()} is locked. You need something to open it...")
else:
# We need to remove the item if it's an item that destroys itself after use
if self.requires.perish_on_open:
self.requires.dispose(None, player)
contains_type = type(self.contains)
print(f"The {self.id.upper()} was weirdly empty...")
elif issubclass(contains_type, GameObject):
print(f'You found {self.contains.name} in the {self.id.upper()}')
player.inventory.append(self.contains)
elif contains_type == list:
# Creates a line that lists out all the items found in the chest. Adds them to inv
items_string = "You found "
player.inventory += self.contains
for item in self.contains:
items_string += f'{item.name}, '
print(items_string[:-2] + f' in the {self.id.upper()}')
self.opened = True
on_interaction = _interaction
class Unlocks(GameObject):
'''
Unlocks is a special class which is used to unlock locked items, like chests
'''
perish_on_open = False # Should this item get destroyed when it unlocks its target?
def __init__(self, id, name, description, perish_on_open=False, pickup=True, place=True):
super().__init__(id, name, description, pickup, place)
self.perish_on_open = perish_on_open
class GiantSword(Weapon):
def __init__(self, id):
super().__init__(
id,
name="giant sword",
description="The swords barely fits in your hand. Surely a relic of a grand warrior",
attack=40,
dura=100,
wobble=0.12,
)
class WornDagger(Weapon):
def __init__(self, id):
super().__init__(
id,
name="worn dagger",
description="The blade of this thing has seen better days",
attack=20,
dura=25,
wobble=0.3,
)
class PlasticSpoon(Weapon):
def __init__(self, id):
super().__init__(
id,
name="plastic spoon",
description="I don't think it'll have much use defending against monsters...",
attack=2,
dura=10,
wobble=0.8,
)
class GolfClub(Weapon):
def __init__(self, id):
super().__init__(
id,
name="golf club",
description="Turns out the people who lived here were avid golf players.",
attack=10,
dura=50,
wobble=0.2,
)
class Handgun(Weapon):
def __init__(self, id):
super().__init__(
id,
name="old handgun",
description="Does this thing even work?",
attack=30,
dura=10,
wobble=0.9,
)
class Whip(Weapon):
def __init__(self, id):
super().__init__(
id,
name="creaky whip",
description="I don't want to know what this was used for... horses?",
attack=5,
dura=20,
wobble=0.1,
)
class Crocs(Defense):
def __init__(self, id):
super().__init__(
id,
name="pair of crocs",
description="I doubt these will actually soften a blow. Yet their ugly style may distract the monsters",
defense=0.05,
dura=20,
wobble=0.15,
)
class SturdyShield(Defense):
def __init__(self, id):
super().__init__(
id,
name="sturdy shield",
description="Seems like it can take a blow",
defense=0.25,
dura=100,
wobble=0.05,
)
class Apron(Defense):
def __init__(self, id):
super().__init__(
id,
name="well used apron",
description="Covered in cooking stains. Clearly not cleaned all too well.",
defense=0.1,
dura=30,
wobble=0.2,
)
class SuitofArmour(Defense):
def __init__(self, id):
super().__init__(
id,
name="pristine suit of armour",
description="Whoever owned this before took great care of it. It is still shiny!",
defense=0.6,
dura=150,
wobble=0.05,
)
class Cookies(HealthItem):
def __init__(self, id):
super().__init__(
id,
name="pack of cookies",
description="Who cares how old these are? All I can think of is the taste of chocolate chip cookies!",
health=40,
)
class FirstAidKit(HealthItem):
def __init__(self, id):
super().__init__(
id,
name='first aid kit',
description="This can heal any ailment at a whim!",
health=100,
)
class Apple(HealthItem):
def __init__(self, id):
super().__init__(
id,
name="apple",
description="An apple a day keeps the doctors away.",
health=20,
)
class StrangePotion(Magic):
def __init__(self, id):
super().__init__(
id,
name="strange potion",
description="A vile of unknown contents. Doesn't smell of anything.",
magic=20,
)
class Wine(Magic):
def __init__(self, id):
super().__init__(
id,
name="bottle of wine",
description="Bourgogne Pinot Noir 2003. Exquisite.",
magic=10,
)
spawnable_items = {
"weapons": [ GiantSword, WornDagger, PlasticSpoon, GolfClub, Handgun, Whip ],
"defense": [ Crocs, SturdyShield, Apron, SuitofArmour ],
"health": [ Cookies, FirstAidKit, Apple ],
"magic": [ StrangePotion, Wine ]
}