Python CMD module quit - python

I'm programming a simple text adventure game with Python 3 and the cmd module.
I need to somehow trigger the game over method but I didn't find a solution on document.
The CMD module got the do_quit() function, but that needs user input, and quit() or exit() kills the whole program, whereas I just need to get out of cmdloop()
Any idea how to deal with this?
Thanks in advance!
def moveDirection(direction):
global location
if direction in rooms[location]:
if rooms[rooms[location][direction]].get(UNLOCKED, True) == True:
print('You move to the %s.' % direction)
location = rooms[location][direction]
if location == 'Hallway' and bGuardAlive == True:
print("Game over! Guard caught you!")
printLocation(location)
else:
print("Door is locked")
else:
print('You cannot move in that direction')
def main():
printLocation(location)
GameLoop().cmdloop()
class GameLoop(cmd.Cmd):
prompt = '\n> '
def do_quit(self, arg):
"""Quit the game."""
return True

Usually (if I understand correctly), you create you own class derived from Exception, you throw the exception at the place you want to exit, and you will have a try clause where you want to land.

After trial and error i get it working. I needed use postcmd()
Here is my code:
def postcmd(self, stop, line):
if bGuardAlive == False and location == 'Hallway':
print("Game over! Guard caught you!")
return True
elif location == 'Tower Ruins':
print("You won!")
return True
return stop
Hopefully this will help somebody

Related

Creating a function to restart while loop

I'm creating a text based adventure game and when the user's health gets to 0, I ask them if they want to restart the game. This works fine - however, I am duplicating my code a lot inside this while loop and want to know how to create a function which I can call to restart the game.
This is the code I use to restart:
if health <= 0:
print('You died. Do you want to restart? (y/n)')
ans = input().lower()
if ans == 'y':
continue
else:
break
There are a lot of ways you could do this, but this is one.
The following function will return True if the user enters 'yes', and False otherwise:
def continue_prompt():
typewriter('You now have 0 health and lose the game.')
print('\nDo you want to restart? (yes/no)')
return input().lower() == 'yes':
The below code will short circuit if health isn't 0, so the function will only be called in the event that the character has died. Then it will continue or break depending on the return value of continue_prompt.
if health <= 0 and continue_prompt():
continue
else:
break
You could also customize the prompt by having continue_prompt accept one or more arguments, if you wanted it to say different things for different causes of death, for instance.
You could use a custom exception and raise it when healths is 0. Then it's possible to move all the health affecting to a reusable function that handles death. Just call the function to change health instead of adding or subtracting
Define the exception:
class DeceaseException(Exception):
pass
And a function for handling health
def affect_health(gain):
global health
health += gain
if health <= 0:
raise DeceaseException
Wherever the health is affected you put for example:
# health decreases
affect_health(-10)
And in main function:
while True:
try:
# main game code
except DeceaseException:
print('You died. Do you want to restart? (y/n)')
ans = input().lower()
if ans == 'y':
continue
else:
break
I'm assuming this is just sitting inside of a while loop?
If so, one option could be
if not health:
typewriter('You now have 0 health and lose the game.')
restart = input('\nDo you want to restart? (yes/no)')
if restart.lower() == 'yes':
continue

How would I effectively lock a room for a text based game?

I'm using python 2.7 for this game. I have looked at other answers and questions similar to this but since I'm a python beginner with some experience with python I don't really understand some of the answers and some of the answers I saw weren't that clear. Because of the current code I have, it created a problem where when I got the item necessary to unlock the room it says the room has not been found. This is the code:
## checks which connecting rooms player.currentRoom has available and updates currentRoom on player choice.
def navigate(player,enemyToken):
os.system("clear")
# print available rooms to navigate to
i = 0
for room in player.currentRoom.connectingRooms:
print(str(i) + ": " + room.name)
i = i + 1
try:
navigate = input("Choose room to navigate to [type its number]: ")
# change players current room to selected room and contains the locking code after the "and".
if(navigate <= len(player.currentRoom.connectingRooms) and player.items[0].unlocks == room == True):
player.currentRoom = player.currentRoom.connectingRooms[navigate]
else:
print("room not found!")
time.sleep(1)
except NameError:
print("that was not a number!")
time.sleep(1)
except SyntaxError:
print("that was not a number!")
time.sleep(1)
except IndexError:
print("that was not an option!")
time.sleep(2)
how would I make a lock that would succesfully lock the player from accessing that room untill they have grabbed the object that is required to open this room. If you need more code to help me I would provide it.
Based on my comment, this code should word(Untested as I do not know where the locking mechanism should go)
Code:
x = True
while x = True:
if LockRoom != RoomUnlock:
Code here
else:
Code here when you unlock the room
x = False
player.items[0].unlocks == room == True
This part looks weird to me. player.items[0].unlocks == room should be sufficient to check if the two numbers match.

Why cant cant i kill this loop and why does 0 does not equal 0?

Hello I am just starting to try to teach my self python and with one of the resources I read, I saw this dice game to make. So I did the basic but then I wanted to make it more full. My idea was to add a loop and have after each round it would prompt the user to enter at first q but now 0 to try to determine if it is an error in my input.
def gamestate():
print('enter 0 if you would like to quit anything else to continue')
game = input()
print(game == 0) # diagnostic to check if value is correct
print(type(game)) #diagnostic to make sure type is correct
print(game != str(0))
def play():
print('do you want to play a game enter yes to start')
game = '1' #filler value
game=input()
str(game)
if game == "yes": #confirms start of the game
Dice()
else:
print('Ok Goodbye') #plays game anyways will fix after loop issue
gamestate()
______________________________________________________________
while game !=str(0): #cannot escape loop for some reason
if game == str(0) :
break #to break
Dice()
gamestate()
print('ok good bye')
___________________________________________________________
play()
First, sorry if code long for this, but what I expect is 0 as an input to break the loop, what I get is having to kill my console process in spyder in order to stop this from looping
You have the variable name game at 2 different variable scopes and so they have different state. Try returning a game from gamestate() and comparing the value
Short description of the scoping rules?
def gamestate():
print('enter 0 if you would like to quit anything else to continue')
game = input()
print(game == 0) # diagnostic to check if value is correct
print(type(game)) #diagnostic to make sure type is correct
print(game != str(0))
return game
while game !=str(0): #cannot escape loop for some reason
if gamestate() == str(0) :
break #to break
Dice()
print('ok good bye')
You have to return game value from gamestate function and assign it in while loop. Check below code:
def gamestate():
print('enter 0 if you would like to quit anything else to continue')
game = input()
print(game == 0) # diagnostic to check if value is correct
print(type(game)) #diagnostic to make sure type is correct
print(game != str(0))
return game
def play():
print('do you want to play a game enter yes to start')
game = '1' #filler value
game=input()
str(game)
if game == "yes": #confirms start of the game
Dice()
else:
print('Ok Goodbye') #plays game anyways will fix after loop issue
gamestate()
while game !=str(0): #cannot escape loop for some reason
if game == str(0) :
break #to break
Dice()
game = gamestate()
print('ok good bye')
play()
In order to compare with zero as a string you need merely do something like if game == "0":. The issue you may be running into is that of extra whitespace chars like "\n". If you use input().trimspace() you'll remove extraneous chars and do comparisons with the values you want to.
Also another problem in the code is that it will enter the while loop if game does not equal "0" and so the if condition that follows will automatically not be met. So break is never hit.
You need to modify your program to convert input to int and not converting 0 to string at multiple places.changes needs to be done in while loop and gamestate function

Variable is not updating in function

I'm new in Python but bear with me.
In my code, I am trying to make variable room to 2, via west() function.
Code:
EDIT: I have isolated most of the non-essential code.
room = 1
cmds = 'west'.lower()
def isValidCMD(cmd):
if cmd in cmds:
return True
else:
print("Unknown command. For help type /help, for available options type /options")
cmd = input(">> ")
if isValidCMD(cmd):
runCMD(cmd)
return False
def runCMD(cmd):
if cmd == '/help':
help()
elif cmd == '/exit':
exit()
elif cmd == '/about':
about()
elif cmd == '/stats':
stats()
elif cmd == '/options':
options()
elif cmd == 'north':
north()
elif cmd == 'south':
south()
elif cmd == 'east':
east()
elif cmd == 'west':
west()
elif cmd == '/lookaround':
look_around()
def west():
if room == 1:
print("You head on over to the lab, to get some advice from Professor Andrew.")
return 2 #LINE 40 < -------
elif room == 7:
print("You head back to Auderban Square feeling primed for battle.")
else:
print("You cannot go west.")
cmd = input(">> ")
if isValidCMD(cmd):
runCMD(cmd)
def main():
while True:
# Town
if room == 1:
print("\nYou are at the centre of town, Auderban Square.".upper())
print("\nYou look at the signpost and see 4 signs.")
print("\t- North - Twinleaf Forest")
print("\t- South - Store of Celestia")
print("\t- East - Deskemon Training Ground")
print("\t- West - Auderban's Deskemon centre")
# Lab
elif room == 2:
print("You are at Auderban's Deskemon Centre")
AndrewConv()
print("\nYou see the exit at the door.")
print("\t- East - Auderban Square")
cmd = input(">> ")
if isValidCMD(cmd):
runCMD(cmd)
main()
Output:
But room keeps its value, 1.
Please give some advice for the future so I won't make the same mistake twice.
Replace west() function with this:
def west():
global room
...
Global variables are widely considered bad programming practice because it is extremely difficult to determine where and when they might be modified in a large program. They also make thread-safe and reentrant code almost impossible to write.
A simple approach would be to have each function accept the room as a parameter and return the “new room.” You can then always update the room in your main function every time you invoke a command.
You will probably end up keeping track of more than the room, though. Consider using a mutable data structure like a dictionary or a class to store the game state, and then passing it into your command functions. That way, it is just as simple to keep up with many state variables as one, and you still do not need global variables.
def main():
state = {'room': 1}
while True:
[...]
if isValidCMD(cmd, state):
runCMD(cmd, state)
def west(state):
thisroom = state['room']
if thisroom == 1:
print("You head on over to the lab, to get some advice from Professor Andrew.")
state.update(room=2)
elif thisroom == 7:
print("You head back to Auderban Square feeling primed for battle.")
else:
print("You cannot go west.")
cmd = input(">> ")
if isValidCMD(cmd):
runCMD(cmd)
There are some additional issues with this code. For example, you duplicate the command prompt code in each command prompt, which is brittle and error prone, and unnecessary since you will be returning to main() anyway.
Edited: Here is a minimal, runnable example:
def main():
state = {'room': 1}
for i in range(20):
oldroom = state['room']
nextroom(state)
print("Went from room {} to room {}.".format(oldroom, state['room']))
def nextroom(state):
state['room'] += 2

Create a text menu in Python3x that is always available

I am new to python and learning quickly. Thank you all for the help.
I am attempting to create a text menu that will always run in the background of a storytelling text rpg. I have searched and cannot find an explanation of how to create an "always on" menu or how one would work.
I would like the player to be able to hit "m" at any time in the game and have the menu prompt show up.
So far, I have created a "userinput" function as well as a "menu" function that will be deployed each time the game prompts the user/player for input.
def menu():
print('Press "1" for map >>> "2" for stats >>> "3" for exit')
choice = input()
if choice == '1':
print('map needs to be made and shown')
elif choice == '2':
print('stats need to be made and assinged to choice 2 in def menu')
elif choice == '3':
print('You are exiting the menu. Press "M" at any time to return to the menu')
return
else:
print('I did not recognize your command')
menu()
def userinput():
print('Press 1 to attack an enemy >>> 2 to search a room >>> 3 to exit game')
print('Press "M" for menu at any time')
inputvalue = input()
if inputvalue == 'm':
menu()
elif inputvalue == '1':
print('attack function here')
elif inputvalue == '2':
print('search function here')
elif inputvalue == '3':
exit
else:
userinput()
This does not appear to be an ideal solution because the user cannot choose to view a map or exit the game at any time they want.
Is there a way to have a menu always running in the background?
I thought of using a while loop that would never close and all of the game would be held within that while loop but that doesn't seem economical by any means.
Any thoughts or help would be appreciated.
I took a stab at it. This is perhaps not the best structure for doing what you're looking for but I don't want my reply to get too complicated.
The "standard" approach for anything with a UI is to separate the model, the view and the control. Check out MVC architecture online. While it adds complexity at the start it makes life much simpler in the long run for anything with a non trivial UI.
Other points of note are:
you're not stripping whitespace from your input (potentially problematic "3 " won't do what you want)
you're input is case sensitive (you ask for "M" but check for "m") .. maybe use choice = choice.strip.lower()??
there's a difference between the way raw_input and input work between Python 2 and Python 3 which means your code doesn't work in python 2. What's the difference between raw_input() and input() in python3.x? I've changed my example to use raw_input. You may want to use this work around http://code.activestate.com/recipes/577836-raw_input-for-all-versions-of-python/ near the top of your code for portability.
Some code
# flag we set when we're done
finished = False
def finish():
# ask the user for confirmation?
global finished
finished = True
return
def handle_menu_input(choice):
handled = True
if choice == '1':
print('map needs to be made and shown')
elif choice == '2':
print('stats need to be made and assinged to choice 2 in def menu')
else:
handled = False
return handled
def menu():
finished_menu = False
while not finished_menu:
print('Press "1" for map >>> "2" for stats >>> "3" for exit')
choice = raw_input() # NOTE: changes behaviour in Python 3!
if handle_menu_input(choice):
# done
pass
elif choice == '3':
print('You are exiting the menu. Press "M" at any time to return to the menu')
finished_menu = True
else:
print('I did not recognize your command')
menu()
return
def userinput():
print('Press 1 to attack an enemy >>> 2 to search a room >>> 3 to exit game')
print('Press "M" for menu at any time')
choice = raw_input() # NOTE: changes behaviour in Python 3!
if choice == 'm':
menu()
elif choice == '1':
print('attack function here')
elif choice == '2':
print('search function here')
elif choice == '3':
finish()
# elif handle_menu_input(choice):
# # delegate menu functions?? ..
# # do this if you want to see maps anytime without going through the menu?
# # otherwise comment this elif block out.
# # (Problem is 1, 2 etc are overloaded)
# pass
else:
print('I did not recognize your command')
return
def main():
# main loop
while not finished:
userinput()
return
if __name__ == "__main__":
main()

Categories

Resources