I have been working on a Zork-like text-based adventure game as a personal project to kind of "Crash course" teach myself python. I'm new to coding in general, so I'm fuzzy on the fundamentals.
I have reached the point in my game where I can successfully navigate the map I've created, and can add new rooms/items freely. I'm currently working on making the "Inventory" system work properly.
Currently, I have a dictionary called "roominv" within my Room class which works as the inventory for each specific room. I also have a dictionary called "bag" within the player class which works as the player inventory.
Currently the game is buggy and unfinished, so to pick up an item you have to pick up ALL the items currently in your room, but that's not what I'm having trouble with.
I can't figure out how to empty the roominv dictionary once the player picks up the items in that room. Right now I can add the items to the player bag but it creates a copy without removing them from the roominv.
I've tried using del, delattr, and pop but either I'm not using them properly (which is what I'm assuming) or that's not the correct way. I also tried .remove which I left in the code below. It returns this error message
Traceback (most recent call last):
File "C:/Users/Daniel/Desktop/PythonPR/Flubbo'sLatestBuild.py", line 104, in <module>
player = Player("Jeff", 100, [], 'introd', command)
File "C:/Users/Daniel/Desktop/PythonPR/Flubbo'sLatestBuild.py", line 97, in __init__
addToInventory(self.room.roominv)
File "C:/Users/Daniel/Desktop/PythonPR/Flubbo'sLatestBuild.py", line 82, in addToInventory
Room.roominv.remove(item)
AttributeError: type object 'Room' has no attribute 'roominv'
This is the same error that appears when using del or delattr. Any tips, advice, or pseudo-code would be much appreciated, and if I'm just going about this the complete wrong way please let me know haha.
To start the game, you have to type either n, w, e, or s 3 times (Bug), you can then walk around using those keys or pick up the items in a room with "Take Items".
world = {}
command = input('>>> ')
class Items:
def __init__(self, name, info, weight, position):
self.name = name
self.position = position
self.info = info
self.weight = weight
class Weapon(Items):
def __init__(self, name, info, damage, speed, weight, position):
super().__init__(name, info, weight, position)
self.damage = damage
self.speed = speed
sword = Weapon("Sword", "A sharp looking sword. Good for fighting goblins!", 7, 5, 5, 0)
knife = Weapon("Knife", "A wicked looking knife, seems sharp!", 5, 7, 3, 5)
stick = Weapon("Stick", "You could probably hit someone with this stick if you needed to", 2, 3, 3, 2)
shackkey = Items("Shack Key", "A key! I wonder what it opens.", .01, 3)
cottagekey = Items("Cottage Key", "An ornate key with an engraving of a small cottage on one side", .01, 5)
Moonstone = Items("Moonstone", "A smooth white stone that seems to radiate soft white light", .05, 6)
flower = Items("Flower", "A beautiful wildflower", .001, 1)
class Room:
def __init__(self, name, description, exits, actions, roominv): # Runs every time a new room is created
self.name = name
self.description = description
self.exits = exits
self.actions = actions
self.roominv = roominv
world['introd'] = Room('introd', "You are in a forest, you can hear wildlife all around you. There seems to be a clearing in the distance.", {'n' or 'north' or 'go north': "clearing"}, {"Search the ground", "Go North"}, {'sword': sword})
world['clearing'] = Room('clearing', "You are in a clearing surrounded by forest. Sunlight is streaming in, illuminating a bright white flower in the center of the clearing. \
To the South is the way you entered the forest. A well worn path goes to the East. In the distance a harp can be heard.", {'s' or 'south' or 'go south': "introd", 'e' or 'east' or 'go east': "forest path"}, {"Take flower", "Go south", "Go East"}, {'flower': flower})
class Player:
def __init__(self, name, health, bag, room_name, move):
self.name = name
self.health = health
self.bag = bag
self.room = world[room_name]
self.move = move
def travel(self, direction):
if direction not in self.room.exits.keys():
print("You can't go that way!")
else:
new_room_name = self.room.exits[direction]
print("moving to", new_room_name)
self.room = world[new_room_name]
print(self.room.description)
print(self.room.actions)
def addToInventory(item):
self.bag.append(item)
Room.roominv.remove(item)
command = input('>>> ')
while command != "":
command = input('>>> ')
if command in {'n', 'e', 's', 'w', 'north', 'south', 'east', 'west', 'go north', 'go south', 'go east', 'go west'}:
travel(self, command)
elif command == 'look':
print(self.room.description)
print('Exits', self.room.exits.keys())
elif command == '':
print('You have to say what it is you want to do! Unfortunately due to a bug you must now restart the game. We are working on fixing this as soon as possible. Sorry!')
elif command == 'search':
print(self.room.roominv)
elif command == 'Take Items':
addToInventory(self.room.roominv)
elif command == 'Inventory':
print(self.bag)
else:
print('Invalid command')
player = Player("Jeff", 100, [], 'introd', command)
Also feel free to critique my code! I'm trying to learn and any advice/comments from more experienced persons would be great.
While not a code review, I'll add a few pointers to fix your other bugs also, but first, the problem at hand:
Room.roominv.remove(item)
Room
is a class, not an object, and so you can't ask for its roominv
instead you'll need self.room.roominv
, however that won't work as .remove
is not a member of dict
, I suggest the following changes:
Your 'Take Items'
command should be:
elif command.split()[0] == 'Take':
for key in list(self.room.roominv.keys()):
if self.room.roominv[key].name == command.split()[1]:
addToInventory(key)
This will allow users to take only the specific items available as well as allowing the user to specify which item they want to pick up.
And then your addToInventory
function can be:
def addToInventory(self,key):
self.bag.append(self.room.roominv[key])
del self.room.roominv[key]
This will handle deleting only the given item if there are multiple items in a room.
The del
keyword deletes a given key/item pair from a dictionary.
Relating to your other problems, your bug here:
elif command == '':
print('You have to say what it is you want to do! Unfortunately due to a bug you must now restart the game. We are working on fixing this as soon as possible. Sorry!')
can be fixed simply by changing what command
was:
elif command == '':
print('You have to say what it is you want to do!')
command = '#'
To fix your needing to input the instruction multiple times, I suggest you do the following:
Remove command = input('>>> ')
from the top of your code.
Replace command = input('>>> ')
above the while command != ""
loop with command = ' '
and update your Player
to not take a move
(this will mean editting the __init__
function as well as the initial creation of player
at the bottom of your code: player = Player("Jeff", 100, [], 'introd')
)
Lastly, nitpicking, why not put your while
loop in a function?, all of this results in:
class Player:
def __init__(self, name, health, bag, room_name):
self.name = name
self.health = health
self.bag = bag
self.room = world[room_name]
def travel(self, direction):
if direction not in self.room.exits.keys():
print("You can't go that way!")
else:
new_room_name = self.room.exits[direction]
print("moving to", new_room_name)
self.room = world[new_room_name]
print(self.room.description)
print(self.room.actions)
def addToInventory(self, key):
self.bag.append(self.room.roominv[key])
del self.room.roominv[key]
def play(self):
command = " "
while command != "":
command = input('>>> ')
if command in {'n', 'e', 's', 'w', 'north', 'south', 'east', 'west', 'go north', 'go south', 'go east', 'go west'}:
self.travel(command)
elif command == 'look':
print(self.room.description)
print('Exits', self.room.exits.keys())
elif command == '':
print('You have to say what it is you want to do!')
command = '#'
elif command == 'search':
print(self.room.roominv)
elif command.split()[0] == 'Take':
itemTaken = False
for key in list(self.room.roominv.keys()):
if self.room.roominv[key].name == command.split()[1]:
self.addToInventory(key)
itemTaken = True
if not itemTaken:
print("I can't find that")
elif command == 'Inventory':
print(self.bag)
else:
print('Invalid command')
player = Player("Jeff", 100, [], 'introd')
player.play()
These changes would result in needing a few other changes like when looking at your inventory, print out the .name
s of each item, rather than the object themselves.
There are also more changes that could be made with a full code review, however for that you should post your code on Code Review, note that Code Review should only be used for complete, working code, so make sure there aren't any game breaking bugs in it before posting there.
An example run:
>>> n
moving to clearing
You are in a clearing surrounded by forest. Sunlight is streaming in, illuminating a bright white flower in the center of the clearing. To the South is the way you entered the forest. A well worn path goes to the East. In the distance a harp can be heard.
{'Go East', 'Take flower', 'Go south'}
>>> s
moving to introd
You are in a forest, you can hear wildlife all around you. There seems to be a clearing in the distance.
{'Search the ground', 'Go North'}
>>> n
moving to clearing
You are in a clearing surrounded by forest. Sunlight is streaming in, illuminating a bright white flower in the center of the clearing. To the South is the way you entered the forest. A well worn path goes to the East. In the distance a harp can be heard.
{'Go East', 'Take flower', 'Go south'}
>>> s
moving to introd
You are in a forest, you can hear wildlife all around you. There seems to be a clearing in the distance.
{'Search the ground', 'Go North'}
>>> search
{'sword': <__main__.Weapon object at 0x00000000040B9470>}
>>> Take sword
I can't find that
>>> Take Sword
>>> Inventory
[<__main__.Weapon object at 0x00000000040B9470>]
>>> search
{}
>>>