I'm working on a choose-your-own-adventure game in Python to try to learn how to code. I might be doing this entirely wrong, but I thought rather than just nesting if-elif-else statements endlessly, I could write some sort of function that would be a template for all choices in the game.
My ideas was to have every decision in a given scene to generate two lists - choices and outcomes. The "multitemplate" function would then load the choose and outcomes lists, present the options to the player, take in the answer, and call the correct function for the outcome given.
My issue is that the outcome list is a list of functions, which Python doesn't seem to like. It says I've not defined the functions properly, but when I define my outcome functions before calling "multitemplate", it just prints them first.
Here's my code:
#Function to allow the adventurer to make choices
def refusal():
print("You stop at the roadsign you passed on your way into town. There are only two directions - towards Tarroway, or towards Angion, the town from whence you came.")
def guards():
print("The guards stop you.")
def theinn():
print("You follow the joyful chatter down the deserted street. Its source is a squat, one story building. A sign above the door reads \"The Forked Tongue\"")
choose = ["I walk towards the merry sounds.", "I turn on my heels and head back where I came from.","I stay where I am and watch the night quietly."]
outcome = [theinn(), refusal(), guards()]
def multitemplate(choose,outcome):
global mychoice
global carryon
for x in range(len(choose)):
print (f"{x+1}) " + choose[x], end="\n")
mychoice = (input())-1
while True:
if (mychoice) in range(len(choose)):
carryon = True
outcome[mychoice]
carrion()
else:
print("Please enter the number of the choice you wish to make.")
carryon = False
mychoice = int((input()))-1
I'd appreciate any input on how this should work properly, or if I'm going down a completely blind alley here.
Thanks!
Related
SOLVED: I read through my code, it was a 'bug'. When I copied the dice roll method from the 'player character', since it uses the same mechanics for the enemies, I set the damage to 0 if it rolls with one die on accident.
Beginner here. (Python crash course halfway of chapter 9)
I am trying to build a simple turn based text game to practice (classes,if statement, modifying dictionaries/lists etc).
I will copy two snippets from my code, so you can understand my problem better.
(I'm really sorry that I can't give a short description, my best try was the title, but that still doesn't make it good enough. If you want an abridged tldr, go to the bottom with the bold texts.)
First, I have two characters, that you can choose from as an if-elif-else statement.
I used the same "player_xy" (xy being like health, damage etc) for the two characters, but assigning different values to them based on the player's choice. (My reasoning being is so I only have to reference the same variable in the code later in the battle system, making my job easier.)
(The variables fighter_max_hp.. etc are defined earlier, but it doesn't matter (tried moving it to before/inside the if statements.)
while select_repeat == True:
print("Type 'f' for fighter , 'm' for mage, or 'q' to quit!")
character = input("TYPE: ")
#player chooses fighter
if character == 'f':
player_max_hp = fighter_max_hp
player_max_mana = fighter_max_mana
#this goes on for a while, setting up all the stats
#player chooses mage
elif character == 'm':
player_max_hp = mage_max_hp
player_max_mana = mage_max_mana
#this goes on for a while, setting up all the stats
#player chooses to quit
elif character == 'q':
select_repeat = False
#invalid input
else:
print("\nPlease choose a valid option!")
Later in the code, I have a part where a randomizer sets up enemies to fight.
I used the same "enemy_xy" (xy being like health, damage etc) for the enemies. (My reasoning was the same here as for the characters.)
(Same, as with the player variables (tried moving it to before/inside the if statements.)
while enemy_select == True:
#game chooses an enemy to fight!
min = 1
max = 3
enemy_chooser = int(random.randint(min, max))
if enemy_chooser == 1:
#choose werewolf
enemy_hp = werewolf_hp
enemy_dice = werewolf_dice
#this goes on for a while, setting up all the stats
if enemy_chooser == 2:
#choose lesser mimic
enemy_hp = int(player_max_hp / 2)
enemy_dice = player_dice
elif enemy_chooser == 3:
#choose zombie
enemy_hp = zombie_hp
enemy_dice = zombie_dice
#this goes on for a while, setting up all the stats
Keep in mind, all of these enemies use the same "enemy_hp", "enemy_dice" etc. variables, within the same battle system, just assigned as "enemy_hp = werewolf_hp" or "enemy_hp = "zombie_hp".
The fight happens, and:
If your enemy is the werewolf:
you deal damage to it
you receive damage from it
you can kill it
you can get killed by it
If your enemy is the lesser mimic:
you deal damage to it
you can ONLY receive damage from it if you are a fighter (mage's hp doesn't decrease)
you can kill it
you can ONLY get killed by it if you are a fighter (obviously, since it doesn't deal damage to mage hp)
If your enemy is the zombie:
you deal damage to it
you CAN NOT receive damage from it (not the fighter, or the mage)
you can kill it
you can not get killed by it (obviously, since no damage)
Otherwise, it prints out the different variable values as assigned (different stats for each monster) as expected, and it uses correct calculations to deal damage.. it just can't in the two cases mentioned above.
Now comes the main part of my question...
If I change the variables like this:
elif enemy_chooser == 2:
#choose zombie
enemy_hp = werewolf_hp ##CHANGE
enemy_dice = werewolf_dice ##CHANGE
#this goes on for a while, setting up all the stats
Then the zombie can finally deal damage to the player (with the werewolf's stats).
It's as if because the lines
enemy_hp = werewolf_hp
enemy_dice = werewolf_dice
#etc
are written earlier than:
enemy_hp = zombie_hp
enemy_dice = zombie_dice
#etc
it somehow effects the variable (regardless or not if the "if" statement is true).
because werewolf_xy was defined earlier than zombie_xy
#enemy werewolf defined first in the code
werewolf_hp = 20
werewolf_dice = 2
#etc
#enemy zombie defined right after
zombie_hp = 35
zombie_dice = 1
#etc
Same happens with the fighter and mage selection.
Somehow the player_hp = xy_hp only works if xy = fighter, because the fighters variables are defined earlier in the code, and thus making the "lesser mimic" deal damage only to the fighter.
My question is "simply".. why?
I tried everything in my power, to no avail.
As you have seen, I could identify what causes the problem (and thus I >could< potentionally work around it), but I still don't know why Python does what it does, and that bothers me.
Any help or input from more experienced users would be greatly appreciated.
Thank you in advance!
Tankerka
You have a bug.
There's not enough details in this (long!) narrative to identify the bug.
Here's how you fix it:
breakpoint()
Put that near the top of your code,
and use n next, plus p print var,
to see what your code is doing.
It is quicker and more flexible than print( ... ).
Read up on that pair of commands here:
https://docs.python.org/3/library/pdb.html
Separate item: refactor your code as you go along.
You're starting to have enough if / elif logic
that it won't all fit in a single screenful
with no scrolling.
That suggests that it's a good time to use def
to break out a helper function.
You might def get_enemy_hp( ... ):, for example,
and also define get_enemy_dice().
Other things you might choose to study:
a class can be a good way to organize the variables you're defining -- embrace the self syntax!
a dict could map from enemy type to hp, or to dice
The nice thing about helper functions is they're
the perfect target for unit tests.
It takes a minute to write a test, but it winds up saving you time.
https://docs.python.org/3/library/unittest.html
When you identify and fix the problem, let us know!
https://stackoverflow.com/help/self-answer
I've started to make a cmd-based minigame, and I wanna implement a feature, where you come across choices which you have to decide that what option will you choose. My problem however is that in my code, if you type anything other than the two options listed, than the game will just 'end' there.
print('Welcome to \'The Exchange\'.')
print('This game is all about making wise decisions with your money.')
print('At the beginning, you\'ll start out with 10$, and from here,')
print('Everything is YOUR choice! Have fun!\n')
# Starter informations. #
yourMoney = 100
# First choise part of the game. #
print('You\'ve come to your first decision of the game -')
print('Do you want to make an insurance for 5 dollars, or you just wanna skip it for now?')
firstDecision = input('Type \"make\" to make one, and \"skip\" to just skip it.\n')
if(firstDecision == "make"):
print("Fine.")
elif(firstDecision == "skip"):
print("Not fine.")
else:
print("You've misspelled it, try again!")
But I want to make it that if you type anything other than the two options, then the game would simply ask the question again, and again, until you type any of the two optins, and then, it would move on. I know, that I have to use some kind of loop, or function, and I also tried these in my code, but it haven't turned out too great. I'd greatly appreciate the help.
My suggestion with minimal change in the code.
print('Welcome to \'The Exchange\'.')
print('This game is all about making wise decisions with your money.')
print('At the beginning, you\'ll start out with 10$, and from here,')
print('Everything is YOUR choice! Have fun!\n')
# Starter informations. #
yourMoney = 100
# First choise part of the game. #
print('You\'ve come to your first decision of the game -')
print('Do you want to make an insurance for 5 dollars, or you just wanna skip it for now?')
firstDecision = input('Type \"make\" to make one, and \"skip\" to just skip it.\n')
while(firstDecision != 'make' or firstDecision != 'skip'):
if(firstDecision == "make"):
print("Fine.")
### Do here all your logics and in the end add the line below
break
elif(firstDecision == "skip"):
print("Not fine.")
### Do here all your logics and in the end add the line below
break
else:
print("You've misspelled it, try again!")
firstDecision = input('Type \"make\" to make one, and \"skip\" to just skip it.\n')
Please let me know if there were problems or this is not what you wanted.
I am making a text-based game; I am trying to figure out a way to have multiple endings and certain percentages for each to happen, but when I run this, it comes up with weird letters and sometimes multiple endings.
choice1_wakeup = input ("Wake Up? Y or N:")
if choice1_wakeup == 'y' or choice1_wakeup == 'Y':
print ("Placeholder")
else:
import random
for x in range(100):
ending_percent = (random.randint(1,10))
if ending_percent > 2:
choice1_ending_common = ("You are woken a while later and see the priest holding a knife to your throat for a moment before he slits it and you bleed out.")
print (random.choice(choice1_ending_common))
elif ending_percent < 2 and ending_percent >0.5:
choice1_ending_rare = ("You wake up a little while later and find yourself dangling over the mouth of the sacrificial volcano while your tribe chants the name of the fire goddess, kahuahuahua, kahuahuahua, kahuahuahua. “What’s happening?” you ask the priest. “You are being sacrificed for your crimes” he replies and at that he tosses you into the fiery abyss.","A few minutes later you are woken by the suddenly extremely cold temperatures. You look around and spot the god of death daharasus. “Why haven’t you completed your rituals to me yet?” he asks you in a stone cold voice. “I’m sorry, I fell asleep” you frightendly reply. “I don’t want excuses!” he screams, he levels his finger at you and you are instantly killed, your soul is forever trapped in the same spot reliving that moment over and over forever.")
print (random.choice(choice1_ending_rare))
else:
choice1_ending_impossible = input ('You are woken up by a stranger a few hours later. "Who are you?" you ask the strange man standing over you. "My name is Jeff Probst" he replies. "I was wondering if you would like to be on my new TV show?" Y or N:')
if choice1_ending_impossible >= 'y' or choice1_ending_impossible >= 'Y':
print ("impossible test")
Please read the documentation for the choice method. That method picks a random element from the iterable sequence you give it. In this case, the sequence you provide is the text of a single ending. The available choices are the individual letters of that ending, so ... you get a single, random character.
If you want to choose a random text, you need to give it a list of strings, such as
ending_list = [
["You and your team vote Jeff Probst off the island.",
"You eat five ugly things and win the immunity challenge.",
"The show is canceled for lack of geologically stable shooting locations."]
Now you can pick one element from ending_list. Is that enough to get you going?
if schoice == 1:
print "You walk right up to the rat and proceed to BEAT THE SHIT OUT OF IT AHHHHHH. Ahem. Anyway, you look at your blood-covered fists and feel good about yourself. You know that you just leveled up your Unarmed to 11. BOOYA!"
skills("Unarmed") = 11
else:
"You proceed to be a little bitch and sneak past the rat. Even though you know that you are being a total coward, you feel good, and you know that you leveled up your sneak to 11. Oh Yeah!"
skills("Sneak") = 11
First off, I would like to say that I have the raw_input stuff with everything else set up, but I was just wondering if I HAVE to split off from here, and then have to write the same thing a gazillion times, or I could make both of these choices, no matter which is picked, to proceed to a shared new choice?
You don't have to split everything every time there is a choice, no.
Consider this:
print('This happens first')
choice = raw_input('Make a choice (1 or 2)')
if choice == 1:
print('Conditional event no1')
else:
print('Conditional event no2')
print('This happens after the choice, no matter what happened')
The story can go on from there. You can visualize this as a flowchart resembling this:
/------ Choice 1 -------\
Starting point / \____ Happens in either case
\ /
\------ Choice 2 -------/
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
I am not that great with OOP but I am stuck right now. First off, I don't think I set the damage correctly and I am trying to figure out how to output the damage to the user. Any help would be appreciated.
#Pokemon Battle
import random
from time import sleep
from array import *
class Pokemon(object):
def __init__(self, xname, xhealth):
self.name = xname
self.health = xhealth
def damage1(self,Charmander):
Squirtle.health - self.damage
def damage2(self,Charmander):
self.health - Squirtle.damage
print ('What is your name?')
name = input()
print ('Hello '+name+'! You are about to enter a pokemon battle.')
sleep(1)
print ('A wild Charmander appeared!')
sleep(1)
print ('You sent out Squirtle!')
sleep(1)
print ('Do you want to fight(1) or run away(2)?')
choice = input()
damage = random.randint(1,50)
damage = str(damage)
if choice == '1':
print ('You dealt '
sleep(1)
print ('Charmander did ')
if choice == '2':
print ('You ran away.')
else:
print ('Not a valid response.')
Right off the bat, you can use String Formatting to insert variables in strings.
#old way
some_string = "the value of 2+2 = %i",4
#new way
some_string = "the value of 2+2 = {}".format(4)
For your code, try:
if choice == '1':
print("You dealt {}".format(damage_goes_here))
However there's deeper issues with your code. Let me look more and I'll edit.
Object Oriented Programming
Okay so the first problem you have is that you never actually MAKE anything. When you write class SomeClassLikePokemonOrWhatever: what you're doing is making a template of something. It's like making a cast or a mold of an item before you make it -- you want all your Pokemon (or whatever) to be alike, so you make a mold of them and cast them all from the same mold. You can decorate and unique-ify them after that, but we want them all to be the same, basically. So instead, you should have something like this:
class Pokemon:
def __init__(self,name,base_hp):
self.name = name
self.base_hp = base_hp
#the __init__ function gets called when you "instantiate" (e.g. actually MAKE)
#whatever object the class is describing. In most cases, all it does it set
#the starting properties of the object based on how you define it (like this)
#you could also say all pokemon are beautiful, and add something like
self.description = "Absolutely GORGEOUS darling!"
#that will be constant for every pokemon you make through this definition.
#you said you wanted damage to be random between 1-50, so we don't need to add
#that statistic to the class.
That covers the definition of the object, but it still doesn't DO anything. In fact, let's let it do something, shall we? We want it to attack. What's a pokemon that doesn't fight? So let's give it a function (in a class, we call functions "methods.")
def attack(self,target):
#in this method we'll teach the pokemon how to fight
damage = random.randint(1,50) #don't forget to import random to do this
target.hp -= damage
Now you need to make some stuff. You defined what a Pokemon is and what it can do, but you haven't made one. Let's make some. Luckily it's easy.
my_awesome_pokemon = Pokemon("Charizard",200) #you give the args in the same order __init__ takes them
your_sucky_pokemon = Pokemon("Magikarp",20) #same deal here.
That makes two pokemon, one for you and one for them. If you wanted a whole belt full, you could define an array all_my_pokemon and fill it with Pokemon objects defined in this way. Just something to think about.
To actually fight, you'd tell your pokemon to attack.
my_awesome_pokemon.attack(your_sucky_pokemon)
#just that easy, now display how much damage it did....WAIT STOP WE HAVE A PROBLEM!
since you want random damage every time, you can't access it with something like my_awesome_pokemon.damage, since it's a local variable it dies when the attack method ends. You can, however, return that value in the method and use that.... Let's change our method.
def attack(self,target):
damage = random.randint(1,50)
target.hp -= damage
return damage #now we have some way to access how much damage was done from our main thread
Now to display it, we can do
damage_done = my_awesome_pokemon.attack(your_sucky_pokemon) #since .attack() returns the damage it deals, this sets damage_done to a sane amount.
print("My pokemon {} dealt {} damage to {}".format(my_awesome_pokemon.name,damage_done,your_sucky_pokemon.name))
Does that make sense?
I really think you should brush up on your OOP and then come back to this problem, because this is definitely a decent problem to practice on.
First of all, you set damage, and then set it again randomly:
self.damage = xdamage
self.damage = random.randint(1,50)
And this function is left open, which is going to cause compile issues, besides for the fact that you're missing any actual data!
print ('You dealt '
sleep(1)
print ('Charmander did ')
You're going to want to call your damage variable and Charmander's damage variable; think about how that is accomplished in OOP.