How to re-initialize a class object - python

I'm making the typical text game program and I'm stuck on the restart function. I want to restart the room instances, but when I try to delete the object I get AttributeError: room1. Here's some pseudo-ish code:
class Room:
inventory = []
__init__(self, itemsInRoom, doors):
#makes a room instance and puts some items and doors into the room
self.roomItems = []
self.roomDoor = []
for item in itemsInRoom:
#puts initial items into the room
self.roomItems.append(item)
for eachDoor in doors:
#tells the instance what doors there are
self.roomDoor.append[doors]
Def functionsBlahBlah():
Pass
class RoomNumber:
room1 = Room(['stool', 'tavern wench', 'bar keep'], ['north', 'east'])
room2 = Room(so on and so forth)
def functionsBlahBlah():
Pass
def restartFunction():
del RoomNumber.room1
del RoomNumber.room2
startGame()
def startGame():
RoomNum()#initializes rooms
main()
startGame()
So anyway, I try to delete RoomNumber.room1 in the restart function so I can turn around and initialize it again with it's original items and stuff. As I said though, I get an error. Any ideas on where I'm going wrong?

Related

How can I Create a quest menu for my Text-RPG

i want to create a quest menu for my text rpg, it should be a list of all quests and after completion the finished quest should be removed fromt the menu. I tried it with a class but i get this error:
IndexError: list assignment index out of range
<main.quest_menu object at 0x000001D4F8EC3FD0>
#generate a class for my quest menu
class quest_menu():
def __init__(self, quests):
self.quests = quests
generate functions to remove single quests from the menu
def delete_quest_1(self):
del self.quests[0]
def delete_quest_2(self):
del self.quests[1]
generate quests in a list
quests = quest_menu( ["Quest: Murder: kill Rottger = exp: 100, gold 100",
"\nQuest: Ring of strenght: Find the ring of strenght= : exp 50"])
commands to delete quest from inventory when quest is completed
quests.delete_quest_1()
print(quests)
quests.delete_quest_2()
print(quests)
What am I doing wrong? Does anybody have some tips to improve the code?
Thx in advance!
I think what's wrong is that, You deleted a quest first then the only Quest that remains is the second one, this makes that quest first item in the list so using the function to delete the quest will result in IndexError as the quest is now at Index 0. Try to this instead.
class quest_menu():
def __init__(self, quests):
self.quests = quests
def delete_quest_1(self):
del self.quests[0]
def delete_quest_2(self):
del self.quests[1]
quests = quest_menu( ["Quest: Murder: kill Rottger = exp: 100, gold 100", "\nQuest: Ring of strenght: Find the ring of strenght= : exp 50"])
quests.delete_quest_1()
print(quests.quests)
quests.delete_quest_1()
print(quests.quests)

Trying to get keys from a dictionary into a class for exploration game

I am having an issue with getting the key from the value of a dictionary into my class. So far I am able to get the values of what I want but can't seem to also obtain the key from where they come from. I think it is because of the way the class is instantiated. I am simply passing the key as the argument but I cannot seem to save the key.
There are constraints to this project. I cannot change the way that the rooms are linked to one another or the methods. There are three files right now that I am working with to try to solve this problem.
#I am using this to get the room set to the player
class Player:
def __init__(self, room, **kwargs):
self.room = room
self.key = str(kwargs)
def getRoom(self):
return self.room, self.key
so as you can see this is a simple class. I have tried using **kwargs here to obtain what is being passed in, although I may not understand how that works correctly and fully. I have sifted through documentation but can't seem to find an answer that makes sense to me. On to the others
#Again a simple class
class Room:
def __init__(self, name, desc):
self.name = name
self.desc = desc
Finally, where the magic is happening:
from room import Room
from player import Player
# Declare all the rooms
room = {
'outside': Room("Outside Cave Entrance",
"North of you, the cave mount beckons"),
'foyer': Room("Foyer", """Dim light filters in from the south. Dusty
passages run north and east."""),
'overlook': Room("Grand Overlook", """A steep cliff appears before you, falling
into the darkness. Ahead to the north, a light flickers in
the distance, but there is no way across the chasm."""),
'narrow': Room("Narrow Passage", """The narrow passage bends here from west
to north. The smell of gold permeates the air."""),
'treasure': Room("Treasure Chamber", """You've found the long-lost treasure
chamber! Sadly, it has already been completely emptied by
earlier adventurers. The only exit is to the south."""),
}
# Link rooms together
room['outside'].n_to = room['foyer']
room['foyer'].s_to = room['outside']
room['foyer'].n_to = room['overlook']
room['foyer'].e_to = room['narrow']
room['overlook'].s_to = room['foyer']
room['narrow'].w_to = room['foyer']
room['narrow'].n_to = room['treasure']
room['treasure'].s_to = room['narrow']
def load_room():
return player.getRoom()
def update_room(room):
global player
player = Player([room])
print("\n*** Welcome to the room explorer")
print("*** You can enter 1, 2, 3, 4 to navigate the corresponding cardinal direction")
print("*** Select 9 to quit\n")
current_room = load_room()
print("this is current room: %s" % (player.key))
print("*** Choose a direction: ***")
user = int(input("[1] North [2] South [3] East [4] West [9] Quit\n"))
while not user == 9:
if user == 1:
if room[current_room.key[0]].n_to:
update_room(room[str(current_room[0])].n_to)
elif user == 2:
if room[current_room.key[0]].s_to:
update_room(room[str(current_room[0])].s_to)
elif user == 2:
if room[current_room.key[0]].e_to:
update_room(room[str(current_room[0])].e_to)
elif user == 2:
if room[current_room.key[0]].w_to:
update_room(room[str(current_room[0])].w_to)
else:
print("\nThere is dead-end, try again")
print(current_room)
print("Please choose to continue...")
user = int(input("[1] North [2] South [3] East [4] West [9] Quit\n"))
I'm sure that there is something that I am overlooking. The logic in the while loop will change once I am able to actually access the key name.
The Player object doesn't need a key attribute and doesn't need **kwargs based on the code I've seen.
The Room objects need a key attribute which can be initialized to None in the __init__ method (not necessary but good practice).
Regardless if previously initialized the rooms can get their keys after the room dictionary was set with:
for k, v in room.items():
v.key = k
After that you can e. g. use current_room.key to ask for the key of the current room object (as long as it was contained in the room dictionary).

How to properly call a class

I'm a Python (and programming in general) newbie and I'm trying to make a text-based, endless rpg with random rooms/encounters based on a list. This code is (of course) not completed yet, It's just for testing. Note that I imported Enemies from another .py file:
import Enemies
import random
class Room:
# template definition to define all rooms
def __init__(self, intro):
self.intro = intro
class VsRoom(Room):
# room with an enemy
def __init__(self, enemy):
self.enemy = random.choice(Enemy_List)
super().__init__(intro = "There's an enemy here!")
class NullRoom(Room):
# empty, boring room
def __init__(self):
super().__init__(intro = "Nothing Interesting here.")
Rooms = [VsRoom, NullRoom] # All future room "types" will go here
def print_room():
# Tells the player which kind of room they are
print("You enter the next room...")
Gen_Room = random.choice(Rooms)
print(Gen_Room.intro)
I wanted print room() to print "You enter on the next room...", randomly pick a room from the list, and print its intro, but when I try to run it I get this:
You enter the next room...
[...]
print(Gen_Room.intro)
AttributeError: type object 'NullRoom' has no attribute 'intro'
Process finished with exit code 1
I'm trying to learn how classes work and any help would be great for me. I tried to follow PEP8 as much as I could, and I also tried to find similar questions, without success.
From what I observe you have a list of where you choose the enemies, so you do not need to enter that parameter:
class VsRoom(Room):
# room with an enemy
def __init__(self):
self.enemy = random.choice(Enemy_List)
super().__init__(intro = "There's an enemy here!")
To create an instance you must do it as follows:
{class name}()
So you must change:
Gen_Room = random.choice(Rooms)
To:
Gen_Room = random.choice(Rooms)()
Complete code:
import Enemies
import random
class Room:
# template definition to define all rooms
def __init__(self, intro):
self.intro = intro
class VsRoom(Room):
# room with an enemy
def __init__(self):
self.enemy = random.choice(Enemy_List)
super().__init__(intro = "There's an enemy here!")
class NullRoom(Room):
# empty, boring room
def __init__(self):
super().__init__(intro = "Nothing Interesting here.")
Rooms = [VsRoom, NullRoom] # All future room "types" will go here
def print_room():
# Tells the player which kind of room they are
print("You enter the next room...")
Gen_Room = random.choice(Rooms)()
print(Gen_Room.intro)

Better way to create my lists in classes?

I've been working on making my text based game more realistic, and one design I would like to implement is to make sure the rooms stay 'static' to a point (i.e. a player uses a potion in the room, if they come back to that room that potion should no longer be there.)
This is how my code is basically set up (I have been using "Learn Python The Hard Way" by Zed Shaw so my code is set up much in the same way):
class Scene(object):
def enter(self):
print "This scene is not yet configured. Subclass it and implement enter()."
class Room(Scene):
potions = []
for i in range(3):
potions.append(Potion())
def enter(self):
...
When I run this, I get a NameError: global name 'potions' is not defined. I know I can fix this one of two ways: 1. make potions a global variable, but then I would have to make a new list for each room that contains potions (There are 36 rooms in total, set up as a 6x6 grid) OR
2. Put this line of code in the enter function, but that would cause the list to reset to 3 potions each time the user enters the room.
potions = []
for i in range(3):
potions.append(Potion())
If there's no other way, I suppose declaring a new variable for all the rooms that contain potions (There's only 5). But my question is if there's another way of making this work without making it a global.
Thanks for your help!
First, let's look at your example (I'll simplify it):
class Room(Scene):
potions = [Potion() for x in range(3)]
What you have done there is create a class attribute potions that are shared among all instances of Room. For example, you'll see my potions in each of my rooms are the same instances of potions (the hex number is the same!). If I modify the potions list in one instance, it modifies the same list in all of the Room instances:
>>> room1.potions
[<__main__.Potion instance at 0x7f63552cfb00>, <__main__.Potion instance at 0x7f63552cfb48>, <__main__.Potion instance at 0x7f63552cfb90>]
>>> room2.potions
[<__main__.Potion instance at 0x7f63552cfb00>, <__main__.Potion instance at 0x7f63552cfb48>, <__main__.Potion instance at 0x7f63552cfb90>]
>>>
It sounds like you want potions to be a unique attribute of each instance of a Room.
Somewhere you will be instantiating a room, e.g., room = Room(). You need to write your constructor for your Room in order to customize your instance:
class Room(Scene):
def __init__(self): # your constructor, self refers to the Room instance.
self.potions = [Potion() for x in range(3)]
Now when you create your room instance, it will contain 3 potions.
You now need to think about how you will make your rooms instances persist between entrances by your characters. That will need to be some sort of variable that persists throughout the game.
This idea of object composition will extend through your game. Perhaps you have a Dungeon class that has your 36 rooms:
class Dungeon(object):
def __init__(self):
self.rooms = [[Room() for x in range(6)] for x in range(6)]
Or perhaps your rooms have up to four doors, and you link them up into something potentially less square:
class Room(Scene):
def __init__(self, north_room, east_room, south_room, west_room):
self.north_door = north_room
self.east_door = east_room
[... and so on ...]
# Note: You could pass `None` for doors that don't exist.
Or even more creatively,
class Room(Scene):
def __init__(self, connecting_rooms): # connecting_rooms is a dict
self.connecting_rooms = connecting_rooms
Except both examples will get you a chicken and egg problem for connecting rooms, so it is better to add a method to add each room connection:
class Room(Scene):
def __init__(self):
self.rooms = {}
# ... initialize your potions ...
def connect_room(self, description, room):
self.rooms[description] = room
Then you could do:
room = Room()
room.connect_room("rusty metal door", room1)
room.connect_room("wooden red door", room2)
room.connect_room("large hole in the wall", room3)
Then perhaps your dungeon looks like this:
class Dungeon(Scene):
def __init__(self, initial_room):
self.entrance = initial_room
Now in the end, you just have to hold onto your dungeon instance of Dungeon for the duration of the game.
btw, this construct of "rooms" connected by "paths" is called a Graph.

Creating dynamic variables for a class from within the class

For context, I'm working on an inventory system in an RPG, and I'm prototyping it with python code.
What I don't understand is how to make separate variables for each instance of an item without declaring them manually. For a short example:
class Player(object):
def __init__(self):
self.Items = {}
class Item(object):
def __init__(self):
self.Equipped = 0
class Leather_Pants(Item):
def __init__(self):
#What do i place here?
def Pick_Up(self, owner):
owner.Items[self.???] = self #What do i then put at "???"
def Equip(self):
self.Equipped = 1
PC = Player()
#Below this line is what i want to be able to do
Leather_Pants(NPC) #<-Create a unique instance in an NPC's inventory
Leather_Pants(Treasure_Chest5) #Spawn a unique instance of pants in a treasure chest
Leather_Pants1.Pick_Up(PC) #Place a specific instance of pants into player's inventory
PC.Items[Leather_Pants1].Equip() #Make the PC equip his new leather pants.
If I did something silly in the above code, please point it out.
What I want to do if the code doesn't make it clear is that I want to be able to dynamically create variables for all items as I spawn them, so no two items will share the same variable name which will serve as an identifier for me.
I don't mind if I have to use another class or function for it like "Create_Item(Leather_Pants(), Treasure_Chest3)"
What's the best way to go about this, or if you think I'm doing it all wrong, which way would be more right?
As a general rule, you don't want to create dynamic variables, and you want to keep data out of your variable names.
Instead of trying to create variables named pants0, pants1, etc., why not just create, say, a single list of all leather pants? Then you just do pants[0], pants[1], etc. And none of the other parts of your code have to know anything about how the pants are being stored. So all of your problems vanish.
And meanwhile, you probably don't want creating a Leather_Pants to automatically add itself to the global environment. Just assign it normally.
So:
pants = []
pants.append(Leather_Pants(NPC))
pants.append(Leather_Pants(chests[5]))
pants[1].pickup(PC)
The pants don't have to know that they're #1. Whenever you call a method on them, they've got a self argument that they can use. And the player's items don't need to map some arbitrary name to each item; just store the items directly in a list or set. Like this:
class Player(object):
def __init__(self):
self.Items = set()
class Item(object):
def __init__(self):
self.Equipped = 0
class Leather_Pants(Item):
def __init__(self):
pass # there is nothing to do here
def Pick_Up(self, owner):
self.owner.Items.add(self)
def Equip(self):
self.Equipped = 1
Abernat has tackled a few issues, but I thought I weigh in with a few more.
You appear to be using OOP, but are mixing a few issues with your objects. For example, my pants don't care if they are worn or not, I care though for a whole host of reasons. In python terms the Pants class shouldn't track whether it is equipped (only that it is equippable), the Player class should:
class CarryableItem:
isEquipable = False
class Pants(CarryableItem):
isEquipable = True
class Player:
def __init__(self):
self.pants = None # Its chilly in here
self.shirt = None # Better take a jumper
self.inventory = [] # Find some loot
def equip(self,item):
if is.isEquipable:
pass # Find the right slot and equip it,
# put the previously equipped item in inventory, etc...
Also, its very rare that an item will need to know who its owner is, or that its been grabbed, so verbs like that again should go onto the Player:
class Player:
maxCarry = 10
def take(Item):
if len(inventory) < maxCarry:
inventory.append(item)
Lastly, although we've tried to move most verbs on to actors which actually do things, sometimes this isn't always the case. For example, when instantiating a chest:
import random
class StorageItem:
pass
class Chest(StorageItem):
__init__(self):
self.storage = random.randint(5)
self.loot = self.spawnLoot()
def spawnLoot(self):
for i in range(self.storge):
# Lets make some loot
item = MakeAnItem # Scaled according to type level of dungeon, etc.
loot.append(item)
def remove(item):
self.loot[self.loot.index(item)]=None
Now the question about what to do when a Player wants to plunder a chest?
class Player:
def plunder(storage):
for item in storage.loot:
# do some Ui to ask if player wants it.
if item is not None and self.wantsItem(item) or \
(self.name="Jane" and self.wantsItem(item) and self.doesntWantToPay):
self.take(item)
storage.remove(item)
edit: Answering the comment:
If you are curious about calculating armor class, or the like, that again is a factor of the user, not the item. For example:
class Player:
#property
def clothing(self):
return [self.pants,self.top]
#property
def armorClass(self):
ac = self.defence
for item in self.clothing:
def = item.armorClass
if self.race="orc":
if item.material in ["leather","dragonhide"]:
def *= 1.5 # Orcs get a bonus for wearing gruesome dead things
elif item.material in ["wool","silk"]:
def *= 0.5 # Orcs hate the fineries of humans
ac += def
return ac
pants = Pants(material="leather")
grum = Player(race="orc")
grum.equip(pants)
print grum.armorClass
>>> 17 # For example?

Categories