Pokemon game in python: classes/objects, battle and deepcopy - python

I'm new on python and I'm trying to do a Pokemon game (like the gameboy and nds games). I've created the pokemon and trainer classes and I want to implement the battle mechanics. I thought it was working fine, but then I found that if I lose the battle the program enters in an infinite loop.
I tried a lot to found the error and I discovered that when it exits the 'while alive(pokemon1) and alive(pokemon2)' loop, the pokemon1 hp returns to full hp but the pokemon2 remains with the current hp (I've put a print to show it). It makes non sense for me because the code is identical for both trainers. Anyone knows why is it happening? I want it to continue with the current hp of both pokemon at the end of the loops and battle.
Here is a sample of my code:
import copy
import random
class Pokemon(object):
def __init__(self, name, hp):
self.name = name
self.hp = hp
def ataque(self, oponent):
oponent.hp = oponent.hp - 150 #just for a test
class Trainer(object):
def __init__(self, name, *pokemon):
self.name = name
self.pokemon, self.pokemonname = [], []
for pkmn in pokemon:
self.pokemon.append(copy.deepcopy(pkmn))
self.pokemonname.append(pkmn.name)
weavile = Pokemon ('Weavile', 150) #change the hp to more than 150 if you want to win
garchomp = Pokemon ('Garchomp', 250)
roserade = Pokemon ('Roserade', 160)
ambipom = Pokemon ('Ambipom', 160)
me = Trainer('You', weavile) #or choose ambipom to win
cynthia = Trainer('Cynthia', garchomp)
def alive(pokemon): #check if the pokemon is alive
if pokemon.hp>0:
return True
if pokemon.hp<=0:
pokemon.hp=0
return False
def battle(trainer1, trainer2): #battle between two trainers
fight1, fight2 = True, True
while fight1 and fight2:
print ('Choose a pokemon:', trainer1.pokemonname)
pokemon1 = eval(input())
while not alive(pokemon1):
print (pokemon1.name, 'is out of batlle. Choose another pokemon')
pokemon1 = eval(input())
pokemon2 = random.choice(trainer2.pokemon)
while not alive(pokemon2):
pokemon2 = random.choice(trainer2.pokemon)
print (trainer1.name, 'chose', pokemon1.name, '\n', trainer2.name, 'chose', pokemon2.name)
while alive(pokemon1) and alive(pokemon2):
pokemon1.ataque(pokemon2)
if alive(pokemon2):
pokemon2.ataque(pokemon1)
print (pokemon1.name, pokemon1.hp)
print (pokemon2.name, pokemon2.hp)
print (trainer1.pokemon[0].name, trainer1.pokemon[0].hp) #here its returning the original hp
print (trainer2.pokemon[0].name, trainer2.pokemon[0].hp) #here its returning the current hp, as it should
if not any(alive(pokemon) for pokemon in trainer1.pokemon):
fight1 = False
if not any(alive(pokemon) for pokemon in trainer2.pokemon):
fight2 = False
battle(me, cynthia)
If you run the code in the way I wrote here, you need to choose one of your pokemon on the list (there's only one: weavile - to simplify), so just type weavile. After that, weavile will attack and then be attacked by garchomp. Weavile will be defeated (0 hp) in the first hit but after the loop 'while alive(pokemon1)...' it will show that weavile still has 150 hp and it will continue to ask you to choose a pokemon even if it's already dead.
If you want to win: choose ambipom instead of weavile in 'me' object or change the weavile hp to more than 150 in weavile object. If you do this it will run as I want and end the battle.

Related

How do I change variables in this program for certain user choices/locations?

Background
Recently I simplified a text-only game I was making:
Here is the code:
import time
#
# Declaration of classes -- game logic
#
class Action:
def __init__(self, description, newLocation):
self.description = description
self.newLocation = newLocation
class Location:
def __init__(self, name, description):
self.name = name
self.description = description
self.actions = []
def addAction(self, action):
self.actions.append(action)
def arrive(self):
print("----------------------------------------")
print('You arrived to: {}'.format(self.name))
print(self.description)
i = 0
print(" (0. Exit game)")
for action in self.actions:
i = i + 1
print(" {}. {}".format(i, action.description))
validChoice = False
while not validChoice:
try:
index = int(input("? : "))
if index == 0:
print("Abandoning your quest... :(")
return
if 0 < index and index <= len(self.actions):
validChoice = True
except ValueError:
pass
self.actions[index - 1].newLocation.arrive() # indexing is 0-based, but we get 1-based index from the user
#
# Declare your locations here -- data
#initial rooms
house = Location("house", "Inside the house there is a sweet aroma of rolls being baked.")
field = Location("field", "Grass swishes as you walk through it. a solitary horse is grazing in the field.")
stable = Location("stable", "You are greeted by the sound of various animal noises and the smell of various animal odors")
#secondary rooms-house
#declare location actions here
spawnPosition = Location("Spawn position", "You wake up in a sunny morning. After you get out of your bad, you decide to:")
spawnPosition.addAction(Action("for house", house))
spawnPosition.addAction(Action("for field", field))
spawnPosition.addAction(Action("for stable", stable))
#house options
house.addAction(Action("leave the house",field))
#
# The game starts here
#
print ("Cool Cousins Studios Presents...")
time.sleep(2) # Sleep for 2 seconds
print ("With use of Python Code...")
time.sleep(2) # Sleep for 2 seconds
print ("Adventure In Saldica")
time.sleep(2) # Sleep for 2 seconds
print ("(cue dramatic music)")
time.sleep(3) # Sleep for 3 seconds
spawnPosition.arrive() # This is all you need to do to initiate the game. When this function returns, your journey has concluded.
print("Bye-bye")
However, I don't know how I can make it change variable values based on the options/locations the user chooses. I've tried putting if statements in the Location.arrive function, but I'm wondering if there is a simpler way.
What I need to know:
How do I make and edit variables based on my location, and what is the simplest way to do it?
You should define a class for your character, where you would store their current location and you can present choices based on the current location or history of actions that the character has taken.
The Location class should contain the available actions you can make from that location and a function to present them when needed.
This way, you will only need to define each room once.
import time
#
# Declaration of classes -- game logic
#
class Character:
def __init__(self, name, location):
self.name: str = name
self.location: Location = location # initialize with some starting location
self.actions = [] # Store all the actions this player has taken
# Here we will have a never ending loop to get inputs from the user
while True:
newLocation = self.location.arrive()
self.actions.append(newLocation)
self.location = newLocation
if sum([1 for loc in self.actions if loc == house]) >= 2:
house.description = "Why are you back home? Go somewhere else."
if self.location == exitLocation:
break
print("\n\nYou visited:")
for i in self.actions:
print(i.name)
class Location:
def __init__(self, name, description, actions:list = []):
self.name = name
self.description = description
self.actions = actions # this should be a list of locations that can be visited from here
def arrive(self):
print("----------------------------------------")
print('You arrived to: {}'.format(self.name))
print(self.description)
i = 0
print(" (0. Exit game)")
for action in self.actions:
i = i + 1
print(" {}. for {}".format(i, action.name))
validChoice = False
while not validChoice:
try:
index = int(input("? : "))
if index == 0:
validChoice = True
print("Abandoning your quest... :(")
return exitLocation
if 0 < index and index <= len(self.actions):
validChoice = True
return self.actions[index - 1] # indexing is 0-based, but we get 1-based index from the user
except ValueError:
pass
#
# Declare your locations here -- data
#initial rooms
field = Location("field", "Grass swishes as you walk through it. a solitary horse is grazing in the field.")
stable = Location("stable", "You are greeted by the sound of various animal noises and the smell of various animal odors")
house = Location("house", "Inside the house there is a sweet aroma of rolls being baked.")
spawnPosition = Location("Spawn position", "You wake up in a sunny morning. After you get out of your bed, you decide to:", [field, stable, house])
exitLocation = Location("Exit Game", "Bye-bye")
#secondary rooms-house
# Declare location actions here
field.actions = [stable, house, spawnPosition]
stable.actions = [field, house, spawnPosition]
house.actions = [field, stable, spawnPosition]
#
# The game starts here
#
print ("Cool Cousins Studios Presents...")
time.sleep(2) # Sleep for 2 seconds
print ("With use of Python Code...")
time.sleep(2) # Sleep for 2 seconds
print ("Adventure In Saldica")
time.sleep(2) # Sleep for 2 seconds
print ("(cue dramatic music)")
time.sleep(3) # Sleep for 3 seconds
# Create a character and initialize with spawn position
character = Character("John", spawnPosition) # This is all you need to do to initiate the game. When this function returns, your journey has concluded.
print("----------------------------------------")
print("Bye-bye")
If you want to change the description of the room based on events that have occurred, you can read self.actions within the character object and modify the descriptions of the rooms there. Same goes for changing the available actions from a room. You would simply modify house.actions in that while loop, if you want to change which rooms you can visit from there after the user has completed some set of actions.

How to take away health points when using a class?

I'm working on a game in python and I can't figure out how to take away health once attack function has taken place. I can run the program and the attack function works fine, it shows a random integer between 1 and 50 but doesn't actually take away health from castlehealth = 100
Underneath print("You attacked for " + str(self.attack)) I left the next line blank because I don't know what to type in, I tried a lot of different things and just can't get the attack to take away from castlehealth.
Here is my code:
import os
import time
from random import randint
class GameActions:
def __init__(self):
castlehealth = 100
self.castlehealth = castlehealth
def health(self):
print("Castle health is: " + str(self.castlehealth))
print()
def attack(self):
attack = randint(0, 50)
self.attack = attack
print("You attacked for " + str(self.attack))
def game():
while True:
game_actions = GameActions()
print("What do you want to do?")
print()
print("attack, view hp")
ans = input()
if ans == "hp":
game_actions.health()
if ans == "attack":
game_actions.attack()
You want the following:
self.castlehealth -= attack
Try something like self.castlehealth -= attack. I also fixed some potential indentation issues for you.
Your full code sample could look this this:
import os
import time
from random import randint
class GameActions:
def __init__(self):
castlehealth = 100
self.castlehealth = castlehealth
def health(self):
print("Castle health is: " + str(self.castlehealth))
print()
def attack(self):
attack = randint(0, 50)
self.attack = attack
print("You attacked for " + str(self.attack))
self.castlehealth -= attack
def game():
while True:
game_actions = GameActions()
print("What do you want to do?")
print()
print("attack, view hp")
ans = input()
if ans == "hp":
game_actions.health()
if ans == "attack":
game_actions.attack()
Explanation: self.castlehealth is an instance variable of your GameActions class. The function GameActions.attack() creates a new attack variable as a random integer and then subtracts that value from the instance variable self.castlehealth of the GameActions class. Now self.castlehealth will be the updated value. Consider also tracking the various attacks and resulting healths in a data structure, since every time you have a new attack self.castlehealth and self.attack will change values and you will lose the ability to access the previous values.

Call a class function in a self in another function so that the attributes only include one and the variable not included but is self function?

This code is in the main function:
Player and Computer are lists in this format:
player = ["name", 10, 20, 30]
10 is the health, 20 is the strength, and 30 is the dexterity
# Get the character for the user and the computer.
player = character_choices.get_and_remove_character(choice)
computer = character_choices.get_random_character()
# Preparation for the battle
print ("You have picked a " + player.name)
print ("The computer picked " + computer.name)
print ("Let's battle!\n")
# Battle Loop
rnd = 1
while (player.hit_points > 0 and computer.hit_points > 0):
print ("Round: " + str(rnd))
player.attack (computer)
computer.attack (player)
This is the function:
def attack (self, enemy):
self.player = [self]
if self.player[3] == enemy[3]:
I do not know how to call the player variable within the attack function in this format I can not change the attributes and I do not know how to get the player list items to compare to the enemies list items and fight.
self is a variable commonly related to objects in python by convention.
In your case, to make use of self, you should read up on python object oriented programming.
https://realpython.com/python3-object-oriented-programming/
Go through the tutorial in the link and once you are done, you will have a better understanding of what you want to achieve using your code. Have fun!

Adding a combat system to a text adventure game; confused by the structure of the code I'm using

Through some educational materials I've been tasked to use the below structure (the classes) for a text adventure game and am required to add a simple combat system for battle between a hero and an enemy.
Currently I am able to have an enemy created in each room and move between the start room(corridor) to the bathroom and back, but at this point I'm stuck. I can't determine where I should be creating my 'hero' or how I'd communicate the changes I'd need to make to the health attributes etc.
If I could structure the code in another way, I would be able to complete the game, but as it is there is a gap in my understanding of how to enable various sections of code communicate with each other.
Thanks,
Dave
# text based adventure game
import random
import time
from sys import exit
class Game(object):
def __init__(self, room_map):
self.room_map = room_map
def play(self):
current_room = self.room_map.opening_room()
while True:
next_room_name = current_room.enter()
current_room = self.room_map.next_room(next_room_name)
class Character(object):
def __init__(self, name, health, attack):
self.name = name
self.health = health
self.attack = attack
class Hero(Character):
def __init__(self, name):
super(Hero, self).__init__(name, 10, 2)
def __str__(self):
rep = "You, " + self.name + ", have " + str(self.health) + " health and " + \
str(self.attack) + " attack."
return rep
class Enemy(Character):
ENEMIES = ["Troll", "Witch", "Ogre", "Jeremy Corbyn"]
def __init__(self):
super(Enemy, self).__init__(random.choice(self.ENEMIES),
random.randint(4, 6), random.randint(2, 4))
def __str__(self):
rep = "The " + self.name + " has " + str(self.health) + \
" health, and " + str(self.attack) + " attack."
return rep
class Room(object):
def __init__(self):
self.commands = ["yes", "no"]
self.rooms = ["\'corridor\'", "\'bathroom\'", "\'bedroom\'"]
self.enemy = Enemy()
def command_list(self):
print("Commands: ", ", ".join(self.commands))
def enter_room_question(self):
print("Which room would you like to enter?")
print("Rooms:", ", ".join(self.rooms))
def leave_room_question(self):
print("Do you want to leave this room?")
print("Commands:", ", ".join(self.commands))
class Bathroom(Room):
def enter(self):
print("You enter the bathroom. But, wait! There is an", \
self.enemy.name, "!")
print(self.enemy)
print("You are in the bathroom. Need to take a dump? ")
self.command_list()
response = input("> ")
while response not in self.commands:
print("Sorry I didn't recognise that answer")
print("You are in the bathroom. Need to take a dump?")
self.command_list()
response = input("> ")
if response == "yes":
print("Not while I'm here!")
return "death"
elif response == "no":
print("Good.")
self.leave_room_question()
response = input("> ")
if response == "yes":
return "corridor"
else:
return "death"
class Bedroom(Room):
def enter(self):
pass
class Landing(Room):
def enter(self):
pass
class Corridor(Room):
def enter(self):
print("You are standing in the corridor. There are two rooms available to enter.")
self.enter_room_question()
response = input("> ")
if response == "corridor":
print("You're already here silly.")
else:
return response
class Death(Room):
QUIPS = ["Off to the man in sky. You are dead",
"You died, no-one cried.",
"Lolz. You're dead!"]
def enter(self):
time.sleep(1)
print(random.choice(Death.QUIPS))
exit()
class Map(object):
ROOMS = {"corridor": Corridor(),
"bathroom": Bathroom(),
"death": Death(),
"landing": Landing(),
"bedroom": Bedroom()}
def __init__(self, start_room):
self.start_room = start_room
self.hero = hero
def next_room(self, room_name):
return Map.ROOMS.get(room_name)
def opening_room(self):
return self.next_room(self.start_room)
a_hero = Hero("Dave")
a_map = Map("corridor")
a_game = Game(a_map, a_hero)
a_game.play()
If I were you, I would set out a game schema. You could find out asking yourself questions like this:
What are the really important entities?
In your case, as you have done, I would consider Character, Enemy, Room and Map, inheriting when it would be appropiate, like Character-> Hero and Enemy, and several types of room from Room as Bathroom, Corridor, ...
If I were you a consider using a data structure to represent the Map. For example, if you are considering do a text game adventure, you could think in different rooms as different states in your game. If you are in the bathroom, you could be attacked by an enemy and if you are in the bedroom, you can retrieve your hitpoints (life) so these places can be thought as different states.
As an example, you would an array for group all your different rooms (states)
rooms = ["bedroom", "bathroom", "corridor", "kitchen", "living_room"]
and other rooms that you can think about.
(there is probably a better example, more efficient and so on, so this example is to help you about not giving up when you gets stuck about an problem.
According to this example, if you use an array, you can assign a value to each room (equal to each position in the array)
Moreover, you will need to know the hero's position, so you could assign a random value to it using rand(). You can read links below for more information:
random docs python
stackoverflow answer
At last, you also would find useful to compare the hero's position, which would have a random assigned value previously with every position of your array or rooms
In this cases, you could use a if... elif.. elif... to compare those values and do something according to the room where your hero would be.
I hope this answer will be useful for you.
Let me know if you have any doubt about my answer.
Cheers

Python: Making my adventure game code, begin to "do something."

absolute beginner here. I am making a text adventure game to sharpen beginner skills. Can someone give me an example of what could go in my
"def firstBattle", function?
Something like a small example of a battle, and updating the Stats and Inventory? Thanks
def displayIntro():
# I will update this as I think of more to add
print(""" You are lord Deadra. You have been sent to Citiel to
overthrow the current King Navator. Throughout your
travels, you will encounter various enemies of all
types. Good luck. """)
def displayInventory():
# Keeps a list of stuff in a dictionary. Because I returned
# stuff, I can use this function in other functions to update
print("Inventory:")
stuff = {"health potions": 5,
"poison": 5,
"stamina potions": 5,
"go crazy potion": 5,
"arrows": 50,
"hunting bow": 1,
"hunting knife": 1,
"big sword": 1,
"magic shield": 1}
return stuff
def displayStats():
# Displays initial health stats
print()
print("Stats:")
health = 100
stamina = 100
confidence = 100
return "health:",health, "stamina:",stamina, "confidence:",confidence
def firstBattle():
# First encounter with an enemy. After battle, update inventory
# and health stats
You need a damage variable.
Implement an enemyDamage, enemyHealth and yourDamage variable.
def battleScene():
print("ENTER to Attack.")
input()
health = health - enemyDamage
enemyHealth = enemyHealth - yourDamage
stamina = stamina - # What ever number you want stamina to go down
print("Your HP: " + health)
print("Enemy HP: " + enemyHealth)
To implement the weapons change their damage values using the a class block.

Categories

Resources