I'm relatively new to Python and OOP, I'm trying to write a mini adventure game with classes and have gotten stuck with my BattleEngine class.
The idea is to have options to fight or outwit an opponent based on your characters and the opponents 'strength' and 'wit'.
I get an error when I try to call my attack method here:
class Armory(Scene):
def enter(self):
print "This room appears to be some kind of armory. There are shelves full of weaponry lining"
print "the walls. You walk around admiring the shiny weapons, you reach out to pick up a"
print "massive battleaxe. Right as your fingers touch it you hear voices from behind the"
print "next door. They sound like they're getting closer. As the voices grow nearer you must make"
print "a decision. Will you stand and fight (enter 'fight') or will you use your wit to outsmart"
print "your opponent(enter 'wit')?"
decision = raw_input("> ")
battle = BattleEngine()
if decision == "fight":
attack(self, Player.strength, 3)
if player_wins:
print "A man in light armour walks in and sees you with your sword drawn. A look of"
print "shock and disbelief is on his face. You act quickly and lunge at him."
print "The soldier struggles to unsheath his sword as you run him through."
print "He collapses to the ground wearing the same look of disbelief."
print "Your strength has increased by 1."
Player.strength += 1
elif decision == "wit":
outwit(self, Player.wit, 3)
Here is where I defined my BattleEngine class:
class BattleEngine(object):
def attack(self, player_strength, nonplayer_strength):
player_roll = randint(1,6)
nonplayer_roll = randint(1,6)
if (player_roll + player_strength) >= (nonplayer_roll + nonplayer_strength):
return player_wins
else:
return 'death'
def outwit(self, player_wit, nonplayer_wit):
player_roll = randint(1,6)
nonplayer_roll = randint(1,6)
if (player_roll + player_wit) >= (nonplayer_roll + nonplayer_wit):
return player_wins
else:
return 'death'
Once I get to this point in my program is receive the error that : 'attack global name is not defined'
I'm not sure what I'm doing wrong exactly. Any help would be fantastic!
You need to call attack on your BattleEngine instance, and you do not need to pass in self:
battle = BattleEngine()
if decision == "fight":
player_wins = battle.attack(Player.strength, 3)
Note that you need to receive the return value of the .attack() method.
The same applies to the .outwit() method further on:
elif decision == "wit":
player_wins = battle.outwit(Player.wit, 3)
You probably need to fix the return values in the .attack() and .outwit() methods; instead of return player_wins and return 'death', return True or False perhaps.
The self parameter is taken care of for you by Python, and will refer to the specific BattleEngine instance.
Not that you really need classes here, your BattleEngine() class currently has no per-instance state, for example. You don't use self in any of the methods, because there is nothing on the instance to refer to.
Related
background: I'm currently writing a text-based adventure and each enemy has a certain amount of turns you can attack it before it attacks back.
So to handle this the code sets an argument in the function for the fight dictating how many times you can attack.
def fight_sequence(rounds):
while rounds > 0:
attack = input()
if attack == magic:
magic("you teleport away to safety. Congratulations you have stayed alive through your journey and found a few souvenoirs. nice job!", 1, "you muster up all of your energy, chant the spell.... and nothing happens.Cthulu... seems unimpressed", 1, "")
elif attack == sword:
sword(1)
def magic(teleportmessage, teleportsuccess, firemessage, firefail, winmessage):
x = 0
while x == 0:
fightorflight = input("""you open the book to cast a spell
Do you want to try teleporting or use a fireball?""").lower()
if "teleport" in fightorflight:
if teleportsuccess = 1:
print(teleportmessage)
x = 1
else:
choice = input("You can't teleport out of this battle. Would you like to try a fireball?")
if choice == yes:
fightorflight = "fireball"
else:
x = 1
elif "fire" in fightorflight:
print(firemessage)
if firefail == 1:
choice = input("do you want to try to teleport instead?").lower()
if "yes" in choice:
fightorflight = "teleport"
else:
x = 1
else:
print(winmessage)
else:
print("Sorry not sure what you mean")
def sword(attacksuccess):
if attacksuccess == 1:
print("You pull out the sword and swing at the monster damaging it severely.")
else:
print("You pull out the sword and swing at the monster, but its immune to blunt objects.")
fight_sequence(3)
both magic() and sword() need to be able to decrease rounds by 1, originally i just did that before entering the magic or sword function. however some items to attack with allow you to attack more than once if you want so that won't work for them. Such as magic if they also choose to teleport. Is there a way to allow me to change the variable rounds while inside of another function?
I think using a return value might help but I'm not sure how to go about it
You can simply add a new argument to the magic function, and pass the 'rounds' variable through when you call it.
e.g.
def fight_sequence(rounds):
...
magic("some message", false, "fired", false, "you won", rounds)
def magic(teleportmessage, teleportsuccess, firemessage, firefail, winmessage, rounds):
Your passing through the variable (not just the value) so it will change in every context where rounds can be seen.
HTH.
I would recommend using classes to create this game rather than lots of functions, an example of a class in a hero game below.
class Hero:
def __init__(self):
self.health = 10
def eatApple(self):
self.health += 1
def takeDamage(self):
self.health -= 1
init function runs as class is initialized.
player = Hero()
print(player.health) # will print 10
player.takeDamage()
print(player.health) # will print 9
This way you can have global variables for you functions which can be changed in each function and is much more organised.
I am having a hard time tracking and adjusting player["health"] I created a function reduce_health(): that lowers the player health based on enemy attack, but when I run a fight the health does not work. I just simply win the fight or when I edit the code it just goes back and forth attacking forever. How can I create a function the reduce health and tracks it after each attack until the player dies? Note the code may not look well structured because I'm still working on it and will clean it up after I figure this out.
import random
import time
#Tracking weapon and player health
player = {"weapon":None, "health": None}
#function for questions avoide repeat
def ask(question):
answer = input(question + " [y/n]")
return answer in ["y", "Y", "Yes", "YES", "yes"]
def game_over():
print ("You Lose")
#initial question to start
print ("The adventures Of Magical Nadia")
#Question to start game or end game
if ask("Do you wish to embark on this great adventure?"):
print ("You have accepted the adventure. God Speed my young rass!")
player["health"] = 100
else:
print ("You are a coward and shall not in bark on a great adventure!")
#Dic of all the weapons in the game
WEAPONS = {
"Spear": (3, 10), None:(1,3), "knife":(4,16), "Gun":(16,25), "Glass Bottle":(4,16)
}
#to give the player weapons code
#player["weapon"] = "Spear"
#Enemys type
enemy = {"name":None, "health":None, "attack":None }
Gaint_spider = {"name":"Spider","health":(10), "attack":(7, 10) }
Dogs = {"name":"Dogs","health": (50), "attack":(4,15)}
Dragon = {"name":"Dragon","health": (150), "attack":(35,45)}
def reduce_health():
healthcheck = int(player["health"])
enemyattack = int("enemy_damage")
player["health"] = healthcheck - enemyattack
print (player["health"])
if player["health"] <= 0:
game_over()
#Function each fight gives random dmg, have a player and enemy, winner and loser
def combat (player, enemy):
player_damage = random.randint (*WEAPONS[player["weapon"]])
enemy_damage = random.randint(*enemy["attack"])
player_win = player_damage >= enemy["health"]
enemy_win= enemy_damage >= player["health"]
return player_damage, player_win , enemy_damage, enemy_win
#Structure of a fight
Sample_FIGHT = {
"player_damage": "You desperately try to stop the %s for %i damage",
"enemy_damage": "%s gores you for %i damage",
"player_win": "The %s collapses with a thunderous boom",
"enemy_win": "You are squished"
}
# describe the fight in a function
def describe_combat(player, enemy, fight_description,reduce_health):
player_damage, player_win , enemy_damage, enemy_win = combat(player, enemy)
print (fight_description["player_damage"] % (enemy["name"], player_damage))
time.sleep(1.0)
print (fight_description["enemy_damage"] % (enemy["name"], enemy_damage) )
return reduce_health
if player_win:
print (fight_description["player_win"] % enemy["name"])
return True
if enemy_win:
print (fight_description["player_win"] % enemy["name"])
return False
return None # fight is a draw
fight_result = describe_combat(player, Gaint_spider, Sample_FIGHT, reduce_health)
while fight_result is None:
describe_combat(player, Gaint_spider, Sample_FIGHT,reduce_health)
if True:
print ("You have won the fight")
else:
print ("You lost")
Returns this:
The adventures Of Magical Nadia
Do you wish to embark on this great adventure? [y/n] Y
You have accepted the adventure. God Speed my young rass!
You desperately try to stop the Spider for 2 damage
Spider gores you for 7 damage
You have won the fight
Goal:
The adventures Of Magical Nadia
Do you wish to embark on this great adventure? [y/n] Y
You have accepted the adventure. God Speed my young rass!
You desperately try to stop the Spider for 2 damage
Spider gores you for 7 damage
Player health 93
You desperately try to stop the Spider for 2 damage
Spider gores you for 7 damage
Player health 86
Instead of using a dict to store player attributes, why not use a class?
class Player:
def __init__(self, weapon, health):
self.weapon = weapon
self.health = health
def reduce_health(amount):
self.health -= amount
You can add additional methods like calculate_damage() to the Player class that take into account the type of weapon the player has. If you also create a monster class, your fight sequence could look something like
def fight():
monster.reduce_health(player.calculate_damage())
monster.check_dead()
player.reduce_health(monster.calculate_damage())
player.check_dead()
...
I made a simple program but when my monster dies the stats don't reset (hp mainly) I am lost In how to make it reset every time the monsters hp reaches 0 and the xp is awarded. I know that I can wright the code over again and again but I would like to be able to make it continue is as little amount of code as possible. I'm still learning python so I don't really know as much as everyone else here. Ive gotten to classes but not so much in depth here is the code:
import random
def title():
print"hello Hero, welcome to staghold"
print"you have traveld along way, and you find yourself"
print"surrounded by and army of monsters as far as the eye can see"
print"begin to draw your sword.....you run full speed towards the army"
print"how many monsters can you kill before the inevatable comes?"
raw_input("(press enter to continue)")
def stats():
print"you have 200 health"
print"your level is 1"
print"you have 0 exp"
raw_input("(press enter to continue)")
class monster:
hp=50
monsterattack=random.randint
xp=random.randint(20,50)
health=200
level=1
exp=0
wave=1
title()
stats()
print"you run into a wave"
while level==1:
if monster.hp<=0:
print"you have defeated this wave of monsters"
wave+=1
exp+=monster.xp
print" you get, "+str(monster.xp)+" exp from the monster"
print"you now have, "+str(exp)+" exp"
if exp>=300:
level+=1
if level==2:
print"CONGRADULATIONS YOU HAVE REACHED LEVEL 2"
elif monster.hp>=0:
choice=raw_input("Will you 'fight' or 'run' from this horde?")
if choice=='fight':
print"you swing your sword at the monster"
att=random.randint(2, 13)
health-=monster.monsterattack(2,15)
monster.hp-=att
hp=200-health
print"you do, "+str(att)+" damage to the monster"
print"the monster does, "+str(hp)+" damage to you"
print"you have, "+str(health)+" health left"
print"the monster has, "+str(monster.hp)+" health left"
elif choice=="run":
print"you got away from this wave safely"
else:
print"NOT A VALID CHOICE"
I can see you're pretty early in your programming journey-
in your example, monster is a class. This means it is a definition of how an object will behave. That is good- but you never define an example of a monster. That would be something like
lion = monster()
which would create a new monster named lion. You need to set up a constructor in the monster class that tells the program how to build a new monster, for example
class Monster:
def __init__(self):
self.hp = 50
self.xp = random.randint(20,50)
def monsterattack(self):
return random.randint()
This would allow you to create a monster, and allow you to have that monster attack with
damage = lion.monsterattack
You could then create a new lion, of class monster, during each loop - and have your hero fight it. The lion would only exist within the current run through of the loop, so each time you create a lion, it would be a completely new monster.
I like your dedication- keep at it, read some basic tutorials!
Hi I am having problems writing this simple program. I am just starting out with Python and was hoping for some help. When I run the start() function at the bottom of the programme, everything works fine until after the first raw_input(). If the user types "get coffee" for example, the string "Fair enough take a break" is printed but after this, rather than running the coffee() function like I would like, it just loops through to the start() function again.
Would someone be able to help please?
Thanks a lot.
def engine(next_scene):
scenes = {"start":start(),"coffee":coffee(),"work":work()}
return scenes[next_scene]
def start():
print "you are in the office"
print "you wonder what to do"
action = raw_input("what do you do? Get coffee or work?")
if action == "get coffee":
print "Fair enough take a break"
next_scene = "coffee"
engine(next_scene)
if action == "work":
print "Good man, you are well on your way to being a coder"
next_scene = "work"
engine(next_scene)
def coffee():
print "You walk out of the room"
print "You head down the stairs and into the cafe"
print "You order an espresso"
print "You neck it down"
print "Yumm"
print "You are wired"
action = raw_input("Now what? Work or go home? > ")
if action == "work":
print "You head back upstairs"
next_scene = "work"
engine(next_scene)
if action == "go home":
print "You lazy git"
def work():
print "You beaver away and become a cool coder"
next_scene = "start"
engine(next_scene)
start()
This
scenes = {"start":start(),"coffee":coffee(),"work":work()}
should be
scenes = {"start":start,"coffee":coffee,"work":work}
You called the functions in the dictionary definition, but you just want to get the function object.
Your engine function should like.
def engine(next_scene):
scenes = {"start":start,"coffee":coffee,"work":work}
scenes[next_scene]()
I'm making a python text adventure. It is based off of ex41 in Learn Python the Hard Way, so it is somewhat similar. My question, however, has nothing to do with that exercise. I'm trying to make an inventory so that an item can be picked up and used (i.e. a key or febreeze).
At first my plan was to use a Boolean variable so that when the item was 'picked up' it would set a value to True, but it doesn't seem to be working. I think that the problem is that the value resets once I leave the room.
Now I'm trying a list and when the item is 'picked up' the item is appended into the inventory list.
How can I make an inventory, or at least 'pick up' an item and then later 'use' it?
The lines of code that I think are important to look at are 18-20 (under the def __init__(self, start)), 77(under the def cell(self)), 161-162(under the def janitor(self)).
from sys import exit
from random import randint
import time
prompt = '> '
class Game(object):
def __init__(self, start):
self.quips = [
"Way to go, you died."
"Now you're dead. Sweet.",
"Well isn't this just peachy? You're dead. (It's not peachy.)"
]
self.start = start
#self.smell = 0
#self.Febreeze = False
#self.key = False
self.inventory = []
#if self.smell >=2:
# return 'death'
def play(self):
next = self.start
while True:
print "\n-------"
room = getattr(self, next)
next = room()
def death(self):
print self.quips[randint(0, len(self.quips)-1)]
exit(1)
def intro(self):
print "You wake up."
print "You're in a dark cell."
print "You have no idea who you are or where you are."
print "The door is slightly open."
print "You stagger through the door. The light is blinding."
print "You have just escaped imprisonment and you're on the run."
return 'central_corridor'
def central_corridor(self):
print "In front of you is a long corridor with no doors on the side, but you think you can make out a door at the very end."
print "Behind you is the cell that you have just escaped."
next = raw_input(prompt)
if "cell" in next:
print "You decide to go back into your cell."
return 'cell'
elif "forward" in next:
print "You travel down the corridor towards the door."
return 'front_corridor'
else:
print "That command doesn't exist."
return 'central_corridor'
def cell(self):
print "You're standing in the middle of a musty cell."
print "There is a bed in the corner with a rotting mattress."
print "Under the bed the bricks are loose."
print "In the opposite corner there is a dirty toilet that implies that prison food is even worse than Taco Bell."
print "There are some scratches on the wall next to the toilet."
print "Behind you is an exit into the corridor."
next = raw_input(prompt)
if "toilet" in next:
print "It'd probably be best if this toilet wasn't described."
#self.smell = self.smell + 1
return 'cell'
elif "febreeze" in next and "Febreeze" in self.inventory #and self.Febreeze = True:
print "You use the Febreeze on the toilet to get rid of the odor."
print "Now you can go behind the toilet to read the rest of the scratches."
elif "scratches" in next:
print "The scratches on the wall seem to be tally marks. It goes up to 123. I wonder what it means."
print "You see more scratches behind the toilet, but the stench is too much for you to handle."
print "If only you could get rid of the smell..."
#self.smell = self.smell + 1
return 'cell'
elif "bed" in next:
print "There are various stains on the mattress. Some of the springs are poking up into the mattress. Ouch."
print "Buried between the wall and the mattress is a stuffed animal."
return 'cell'
elif "bricks" in next:
print "You pull the bricks out of the floor and find a few pieces of toilet paper."
print "There is a note written on them in what you hope is dried blood."
print "The note reads:\n -------------------------\nthe closet!! the closet in the walls i'm not \nsure\twhich one it is but its defin-\nly in the hall. i hear it in the bricks!\n---------------------------"
print "Hmm, maybe it's a hint or something."
elif "corridor" in next:
return 'central_corridor'
else:
print "I do not understand how to %s" % next
return 'cell'
def front_corridor(self):
print "You are standing in front of a door."
print "On the side of the door is a keypad."
next = raw_input(prompt)
if "keypad" in next:
return 'keypad'
elif "wall" in next:
return 'wall'
elif "back" in next:
return 'central_corridor'
else:
print "I don't understand %s" % next
return 'front_corridor'
def wall(self):
print "Which wall do you want to check?"
next = raw_input(prompt)
if "left" in next:
return 'left'
elif "right" in next:
return 'right'
elif "back" in next:
return 'front_corridor'
def right(self):
print "You examine the wall carefully, running your fingers across each of the bricks."
print "Unfortunately it doesn't look like anything of value is in this wall."
print "Well, you just wasted some time."
return 'wall'
def left(self):
print "You examine the wall carefully, running your fingers across each of the bricks."
print "One of the bricks seems to be protruding from the wall."
print "Do you push it?"
next = raw_input(prompt)
if next[0] == "y":
print "A few of the bricks shift, revealing a secret door way."
return 'janitor'
elif next[0] == "n":
print "You decide not to push the brick. Good thinking, it may have been a booby trap."
return 'front_corridor'
else:
print "That doesn't exactly make sense..."
return 'wall'
def janitor(self):
print "You are in a room filled with janitorial tools."
print "On your left you see a few cans of Febreeze, a plunger and a Playboy magazine."
next = raw_input(prompt)
if "febreeze" in next:
print "You pick up some Febreeze and put it in your back pocket."
print "Maybe this will be useful somewhere down the line."
self.inventory.append("Febreeze")
#self.Febreeze = True
return 'janitor'
elif "plunger" in next:
print "You try to pick up the plunger but it appears to be stuck in the ground."
print "After tugging for a few minutes the handle comes out, leaving the rubber suction cup plastered to the floor."
print "Who knows what's keeping it there."
print "You decide not to touch it."
return 'janitor'
elif "playboy" in next:
print "Well isn't that nice."
print "These janitors certainly have good taste."
return 'janitor'
elif "back" in next:
return 'front_corridor'
else:
print "Do WHAT with WHAT?"
return 'janitor'
def keypad(self):
print "Above the keypad there is a sign that reads:\n-----------\nInput a 3 digit code.\nWarning: If code is incorrect 3 times, keypad will self-destruct.\n-----------"
code = "%d%d%d" % (randint(1,9), randint(1,9), randint(1,9))
guess = raw_input("Password: ")
guesses = 0
while guess != code and guesses < 2:
print "BZZZZZEDD!"
guesses += 1
guess = raw_input("Password: ")
if guess == code:
print "The keypad beeps in acceptance. Wow, that was a good guess"
print "The door swings open."
print "Behind the door is a long bridge suspended over a lake of lava."
return 'bridge'
elif "key" in guess and key == True:
print "You flash your card key across the keypad."
print "There is a beep as the door swings open."
print "Behind the door is a long bridge suspended over a lake of lava."
return 'bridge'
else:
print "The keypad buzzes one last time and then you hear a sickening melting"
print "sound as the lock mechanism fuses together."
print "There is a small clicking while the keypad countsdown."
print "3"
time.sleep(1)
print "2"
time.sleep(1)
print "1"
time.sleep(1)
print "There is a large explosion and you are caught right in the middle of it."
print "The fiery blast tears your skin from your body as you scream in agony."
return 'death'
def bridge(self):
print "You carefully walk onto the bridge."
print "One false move and you could be dead."
print "Across the bridge is a door leading to the outside world."
next = raw_input(prompt)
if "jump" in next:
print "You jump to your death."
print "Probably not the best idea."
elif "run" in next:
print "You run"
a_game = Game("intro")
a_game.play()
Your approach seems to work fine, but you have a couple of bugs. In cell(), you need a : after the elif "febreeze"... statement (before the comment starts). Also, at the end of that elif block, you need to return 'cell'. With these changes, I can pick up the Febreeze and use it.
If you define the inventory as a list(that's what I did), then you can do:
class Attributes:
def __init__(self, inventory):
self.inventory = inventory
Player = Attributes([])
Player.inventory.append("Febreeze")
The square brackets make the inventory, and the "append" adds Febreeze to it.
if you tryed to define it as a list e.g (guessing this is on python)
def inventory[]
inventory.append
add item (inventory)
cannot rember how to add it to the inventory but there is the basics