Python-turtle: From math library: dist() causing loop to exit/freeze - python

I am trying to make a game using Python (with turtle)
the aim of the game is to shoot the other person
The problem comes with the collision code. I am checking collisions with bullets using dist(), but that seems to cause the loop to exit/freeze (I don't really know which).
I've tried using distance formula instead of the function but that didn't change anything
Here is my code:
bullet.forward(10)
distancetop1 = dist(player1.pos(),bullet.pos())
if self != player1 and distancetop1 < 2:
bullet.clear()
print("orange won!")
exit()
distancetop2 = dist(player1.pos(),bullet.pos())
if self != player2 and distancetop2 < 2:
bullet.clear()
print("blue won!")
exit()
My full code, if needed, is here

With turtle don't put your key checks in a loop. Set them once then call listen. Use mainloop to keep the game running.
Try this code:
import turtle,random, math
sc = turtle.Screen()
sc.bgcolor("#000")
player1 = turtle.Turtle()
player1.color("#00f")
player1.speed(0)
player1.up()
player1.goto(-256,0)
player2 = turtle.Turtle()
player2.color("#ffa500")
player2.speed(0)
player2.up()
player2.goto(256,0)
player2.seth(180)
bullet1 = turtle.Turtle()
bullet1.color("#fff")
bullet1.speed(0)
bullet1.ht()
bullet1.up()
bullet1.active = False
def dist(c1,c2):
return math.sqrt((c1[0]-c2[0])**2 + (c1[1]-c2[1])**2)
def shoot(self):
bullet = bullet1.clone()
bullet.active = True
bullet.goto(self.xcor(),self.ycor())
bullet.down()
bullet.seth(self.heading())
while (bullet.xcor() < 600 and bullet.xcor() > -600) and (bullet.ycor() < 256 and bullet.ycor() > -256):
bullet.forward(10)
distancetop1 = dist(player1.pos(),bullet.pos())
if self != player1 and distancetop1 < 5:
bullet.clear()
print("orange won!")
exit()
distancetop2 = dist(player2.pos(),bullet.pos())
if self != player2 and distancetop2 < 5:
bullet.clear()
print("blue won!")
exit()
bullet.clear()
def p1right():
player1.seth(0)
player1.forward(4)
def p1left():
player1.seth(180)
player1.forward(4)
def p1up():
player1.seth(90)
player1.forward(4)
def p1down():
player1.seth(270)
player1.forward(4)
def p1shoot():
shoot(player1)
def p2right():
player2.seth(0)
player2.forward(4)
def p2left():
player2.seth(180)
player2.forward(4)
def p2up():
player2.seth(90)
player2.forward(4)
def p2down():
player2.seth(270)
player2.forward(4)
def p2shoot():
shoot(player2)
#while True:
sc.onkey(p1right,"D")
sc.onkey(p1left,"A")
sc.onkey(p1up,"W")
sc.onkey(p1down,"S")
sc.onkey(p1shoot,"space")
sc.onkey(p2right,"Right")
sc.onkey(p2left,"Left")
sc.onkey(p2up,"Up")
sc.onkey(p2down,"Down")
sc.onkey(p2shoot,"Return")
sc.listen()
sc.mainloop()

Related

[textRPG]How to keep random creating of class and class atrributes every time i run a program[Python]

I am trying some text based rpg game as a beginner in python. But i am struggling to get done one thing.
If i use while loop to run program 5 times. So i want repeat killing monster but without saving his attributes.
If you run this code, character kills a monster in couple of moves and appends his experience to himself and monster hp decreases to <= 0 and dies.
Looping whole program does not work, randomly created monster is still the same, i just want to create new monster with new random attributes every time i loop program. It is possible? I am new to this and can't figure it out at this moment. Some tips ?
Here is some code but without while loop: final output is to loop this menu and fight simulator to gain exp and items from random monsters.
import random
import time
# List of items to drop
normal_items = ['Copper ore', 'Apple', 'Animal skin', 'Stone', 'Feather', 'Rotten egg', 'Bag of sand', "Simple dagger", "Blue flower"]
rare_items = ['Energized wand', 'Staff of purity', 'Enhanced gloves', 'Adamant chest plate']
legendary_items = ['Crown of Immortality', 'Robe of fire-dragon']
drop_chance_dice = random.randint(1, 100)
# Simple drop chance function
def dice():
if drop_chance_dice <= 70:
random_choice = (random.choice(normal_items))
print(f"You got: {random_choice} ")
if 70 <= drop_chance_dice <= 98:
random_choice = (random.choice(rare_items))
print(f"You got: {random_choice} ")
if 99 <= drop_chance_dice <= 100:
random_choice = (random.choice(legendary_items))
print(f"Congratulations! You got an legendary item: {random_choice}")
# Instances and mobs
rat_nest= ['Rat', 'Giant Rat', 'Leader of Rats']
northern_forest = ['Snake', 'Wolf', 'Witch']
# My Character Class
class YourCharacter:
def __init__(self, intro, name, attack, exp, level, hp):
self.intro = intro
self.name = name
self.attack = attack
self.exp = exp
self.level = level
self.hp = hp
# Creating my character(preset)
my_character = YourCharacter("Your character \n", 'FroGres', 16, 0, 1, 100)
# Introduction
def introduction_of_player(my_character):
print(f"{my_character.intro}")
print(f"{my_character.name}")
print(f"Attack: {my_character.attack}")
print(f"Experience: {my_character.exp}")
print(f"Level: {my_character.level}")
print(f"HP: {my_character.hp}")
# Monsters class build
class Monster:
def __init__(self, intro, name, attack, exp, level, hp):
self.intro = intro
self.name = name
self.attack = attack
self.exp = exp
self.level = level
self.hp = hp
# Monsters attributes + list of mobs (for testing - to be upgraded)
# rat nest
rat = Monster("You fight vs: \n", "Rat", random.randint(4, 6), random.randint(8, 14), random.randint(1, 3),
random.randint(50, 100))
giant_rat = Monster("You fight vs: \n", "Giant Rat", random.randint(6, 8), random.randint(10, 18), random.randint(2, 4),
random.randint(80, 130))
rat_boss = Monster("You fight vs: \n", "Leader of Rats", random.randint(4, 6), random.randint(8, 14),
random.randint(1, 3),
random.randint(50, 100))
# northern forest
#Witch = Monster("You fight vs: \n", "Witch", random.randint(8, 12), random.randint(12, 20), random.randint(3, 6), random
# .randint(120, 200))
list_of_mobs = [rat, giant_rat, rat_boss]
event_mob = random.choice(list_of_mobs) # Random pick monster , USED in function
# Introduction of Monster
def introduction_of_monster_ratnest(list_of_mobs):
print(f"{list_of_mobs.intro}")
print(f"{list_of_mobs.name}")
print(f"Attack: {list_of_mobs.attack}")
print(f"Experience: {list_of_mobs.exp}")
print(f"Level: {list_of_mobs.level}")
print(f"HP: {list_of_mobs.hp}")
def escape_or_fight():
take_input = input("[a]ttack or [r]un?")
if take_input == 'a':
return attack()
if take_input == 'r':
print("You run as fast as possible.. ")
print("You returning to your hideout..")
else:
print("Something wrong")
# Menu of actions
def menu_dungs():
asking = input("Where do you want to go?: 1.Rat Nest or 2.Northern Forest :")
if asking == "1":
print("You entering rat nest.. good luck!\n")
time.sleep(1)
print("Some ugly creature stays on your way!")
print(f"{event_mob.name} is looking at you!")
if event_mob == rat:
introduction_of_monster_ratnest(rat)
escape_or_fight()
elif event_mob == giant_rat:
introduction_of_monster_ratnest(giant_rat)
escape_or_fight()
elif event_mob == rat_boss:
introduction_of_monster_ratnest(rat_boss)
escape_or_fight()
else:
print("Something went horribly wrong.. Don't even ask..")
elif asking == "2":
print("You entering northern forest.. good luck!\n")
print("Dungeon unavailable at this moment, try another one")
pass
# Not in use
else:
print("Try again and choose correct location\n")
menu_dungs()
def attack():
gain_exp = event_mob.exp + my_character.exp
rounds = 0
while event_mob.hp > 0:
event_mob.hp = event_mob.hp - my_character.attack
rounds += 1
print(f"You hit with: {my_character.attack} damage. Enemy HP is {event_mob.hp}")
print(f"Enemy HP after your attack is {event_mob.hp}", "\n")
if event_mob.hp <= 0:
print(f"{event_mob.name} has died..")
print(f"It tok you: {rounds} moves to kill that creature! \n")
print("Congratulations! Here is your loot")
dice()
print(f"You got: {event_mob.exp} experience from that fight.")
print(f"Your experience is now: {gain_exp}")
menu_dungs()
I tried: to create new unique monster with new randomly created attributes every time i run program. I used while loop but monster is not "respawning"
I expect: Some sort of simulator, after i kill monster, program creates new one and my character gains experience and items every fight.
I wonder: If there is some method to makes this class unique every loop.
Here is HOW-TO to achieve all goals in your question:
each time generate monsters with different parameters
respawn monsters
First you create 3 sepreate functions that would return a new monster - the class of returned value is always the same (Monster) but they return new instances on each call:
def get_rat():
return Monster("You fight vs: \n", "Rat", ...)
def get_giant_rat():
return Monster(...)
def get_rat_boss():
reutrn Monster(...)
You will also need to modify how you select monsters. I would suggest to create list of functions - so instead of selecting a monster you select a function, that generates monster:
# This should replace the list_of_mob
list_of_mob_generators = [get_rat, get_giant_rat, get_rat_boss]
And the last - you should select monster on each loop interation in main menu (so the monster could respawn). The shortest way is to change your global variable:
event_mob = None # we change event_mob initially to None - we will select in later
def menu_dungs():
global event_mob # this is new
asking = input("Where do you want to go?: 1.Rat Nest or 2.Northern Forest :")
if asking == "1":
event_mob_generator = random.choice(list_of_mob_generators) # get one of the functions
event_mob = event_mob_generator() # call the function to get monster
print("You entering rat nest.. good luck!\n")
time.sleep(1)
print("Some ugly creature stays on your way!")
print(f"{event_mob.name} is looking at you!")
# and this condition has changed, since we do not have one instance of each monster anymore
if event_mob.name == 'Rat':
introduction_of_monster_ratnest(event_mob)
escape_or_fight()
elif event_mob.name == 'Giant Rat':
introduction_of_monster_ratnest(event_mob)
escape_or_fight()
elif event_mob.name == 'Rat Boss':
introduction_of_monster_ratnest(event_mob)
escape_or_fight()
else:
print("Something went horribly wrong.. Don't even ask..")
... # and so on
and of course do not forget a while loop for main menu =)
while True:
menu_dungs()
Thanks for help, program works as i wanted but still shows me 8 yellow errors in attack() function. Cannot find reference 'hp' in 'None' etc.
maybe because this event_mob = None ?
Could you run this code and see what is going on ? very likely i did put something in wrong place..
import random
import time
# List of items to drop
normal_items = ['Copper ore', 'Apple', 'Animal skin', 'Stone', 'Feather', 'Rotten egg', 'Bag of sand', "Simple dagger", "Blue flower"]
rare_items = ['Energized wand', 'Staff of purity', 'Enhanced gloves', 'Adamant chest plate']
legendary_items = ['Crown of Immortality', 'Robe of fire-dragon']
drop_chance_dice = random.randint(1, 100)
# Simple drop chance function
def dice():
if drop_chance_dice <= 70:
random_choice = (random.choice(normal_items))
print(f"You got: {random_choice} ")
if 70 <= drop_chance_dice <= 98:
random_choice = (random.choice(rare_items))
print(f"You got: {random_choice} ")
if 99 <= drop_chance_dice <= 100:
random_choice = (random.choice(legendary_items))
print(f"Congratulations! You got an legendary item: {random_choice}")
# Instances and mobs
rat_nest= ['Rat', 'Giant Rat', 'Leader of Rats']
#not in use
northern_forest = ['Snake', 'Wolf', 'Witch']
# My Character Class
class YourCharacter:
def __init__(self, intro, name, attack, exp, level, hp):
self.intro = intro
self.name = name
self.attack = attack
self.exp = exp
self.level = level
self.hp = hp
# Creating my character(preset)
my_character = YourCharacter("Your character \n", 'FroGres', 16, 0, 1, 100)
# Introduction
def introduction_of_player(my_character):
print(f"{my_character.intro}")
print(f"{my_character.name}")
print(f"Attack: {my_character.attack}")
print(f"Experience: {my_character.exp}")
print(f"Level: {my_character.level}")
print(f"HP: {my_character.hp}")
# Monsters class build
class Monster:
def __init__(self, intro, name, attack, exp, level, hp):
self.intro = intro
self.name = name
self.attack = attack
self.exp = exp
self.level = level
self.hp = hp
# Monsters getting functions
# rat nest
def get_rat():
return Monster("You fight vs: \n", "Rat", random.randint(4, 6), random.randint(8, 14), random.randint(1, 3),
random.randint(50, 100))
def get_giant_rat():
return Monster("You fight vs: \n", "Giant Rat", random.randint(6, 8), random.randint(10, 18), random.randint(2, 4),
random.randint(80, 130))
def get_rat_boss():
return Monster("You fight vs: \n", "Rat Boss", random.randint(4, 6), random.randint(8, 14),random.randint(1, 3),
random.randint(50, 100))
# northern forest
# def get_witch():
# return Monster("You fight vs: \n", "Witch", random.randint(8, 12), random.randint(12, 20), random.randint(3, 6), random
# .randint(120, 200))
list_of_mobs_generators = [get_rat, get_giant_rat, get_rat_boss]
def escape_or_fight():
take_input = input("[a]ttack or [r]un?")
if take_input == 'a':
return attack()
if take_input == 'r':
print("You run as fast as possible.. ")
print("You returning to your hideout..")
else:
print("Something wrong")
# Menu of actions
event_mob = None
def menu_dungs():
global event_mob
asking = input("Where do you want to go?: 1.Rat Nest or 2.Northern Forest :")
if asking == "1":
event_mob_generator = random.choice(list_of_mobs_generators)
event_mob = event_mob_generator()
def introduction_of_monster_ratnest(event_mob):
print(f"{event_mob.intro}")
print(f"{event_mob.name}")
print(f"Attack: {event_mob.attack}")
print(f"Experience: {event_mob.exp}")
print(f"Level: {event_mob.level}")
print(f"HP: {event_mob.hp}")
print("You entering rat nest.. good luck!\n")
time.sleep(1)
print("Some ugly creature stays on your way!")
print(f"{event_mob.name} is looking at you!")
if event_mob.name == 'Rat':
introduction_of_monster_ratnest(event_mob)
escape_or_fight()
elif event_mob.name == 'Giant Rat':
introduction_of_monster_ratnest(event_mob)
escape_or_fight()
elif event_mob.name == 'Rat Boss':
introduction_of_monster_ratnest(event_mob)
escape_or_fight()
else:
print("Something went horribly wrong.. Don't even ask..")
elif asking == "2":
print("You entering northern forest.. good luck!\n")
print("Dungeon unavailable at this moment, try another one")
pass
# Not in use
else:
print("Try again and choose correct location\n")
def attack():
gain_exp = event_mob.exp + my_character.exp
rounds = 0
while event_mob.hp > 0:
event_mob.hp = event_mob.hp - my_character.attack
rounds += 1
print(f"You hit with: {my_character.attack} damage. Enemy HP is {event_mob.hp}")
print(f"Enemy HP after your attack is {event_mob.hp}", "\n")
if event_mob.hp <= 0:
print(f"{event_mob.name} has died..")
print(f"It tok you: {rounds} moves to kill that creature! \n")
print("Congratulations! Here is your loot")
dice()
print(f"You got: {event_mob.exp} experience from that fight.")
print(f"Your experience is now: {gain_exp}")
while True:
menu_dungs()

Complete the while loop

#Code Project : Shooting game.
You are creating a shooting game!
The game has two types of enemies, aliens and monsters. You shoot the aliens using your laser, and monsters using your gun. Each hit decreases the lives of the enemies by 1. The given code declares a generic Enemy class, as well as the Alien and Monster classes, with their corresponding lives count. It also defines the hit() method for the Enemy class.
You need to do the following to complete the program:
1. Inherit the Alien and Monster classes from the Enemy class.
2. Complete the while loop that continuously takes the weapon of choice from user input and call the corresponding object's hit() method.
Sample Input:
laser
laser
gun
exit
Sample Output:
Alien has 4 lives
Alien has 3 lives
Monster has 2 lives
I completed 1st part , but need help with part 2.
class Enemy:
name = ""
lives = 0
def __init__(self, name, lives):
self.name = name
self.lives = lives
def hit(self):
self.lives -= 1
if self.lives <= 0:
print(self.name + ' killed')
else:
print(self.name + ' has '+ str(self.lives) + ' lives')
class Monster(Enemy):
def __init__(self):
super().__init__('Monster', 3)
class Alien(Enemy):
def __init__(self):
super().__init__('Alien', 5)
m = Monster()
a = Alien()
while True:
x = input()
if x == 'exit':
break
Please follow the community guidelines while asking any question on stackoverflow. Please check out this link How do I ask and answer homework questions?
Check out this code :
while True:
x = input()
if x == 'exit':
break
elif x == 'laser':
a.hit()
elif x == 'gun':
m.hit()

How can I alternate between a Computer turn and a Player turn in a card game?

This is my first project using Pygame, and I've already taken a lot of inspiration from others' codes while trying to adapt it to my own purposes.
Game Rules:
I'm writing a card game that will be the Player vs the Computer. It is similar to Solitaire in that there are 4 play-piles that will take a sequence of cards from Ace-Queen (King being a wildcard that can be anything except a 7).
Each round starts with either the Player or Computer drawing cards to make a hand of 5.
The Player and Computer have a deck of 26 cards (the game is played with 2 standard decks), the objective is to play the top card on one of the 4 play piles and finish the deck before the other Player does.
To end a turn, a card from the hand must be thrown onto one of four bone piles, after which the next player's turn starts.
My Problem:
The Computer successfully draws a hand to make 5 cards, and then will randomly choose a card to throw on to the bone pile. The issue is that the Computer will continue to draw cards and play them onto the bone pile until the main deck is empty, at which point an error is raised (IndexError: pop from empty list).
From my understanding, the issue is that the draw_hand() function for the Computer continues to loop while the main loop runs.
My question is how to implement a code that will recognize when a card has been thrown onto a bone pile and then switch to the next player.
My code:
In the Deck class:
def draw_card(self):
return self.cards.pop()
In the Computer class:
def draw_hand(self, deck):
while len(self.hand) < self.max_hand:
self.hand.append(deck.draw_card())
return self
In the Main file:
def computer_turn():
computer.turn = True
player.turn = False
time.sleep(1)
def computer_end_turn():
pile_choice = randint(1, 5)
card_choice = randint(1, (len(computer.hand) - 1))
throw_card = computer.hand.pop(card_choice)
if pile_choice == 1:
comp_bp1.cards.append(throw_card)
elif pile_choice == 2:
comp_bp2.cards.append(throw_card)
elif pile_choice == 3:
comp_bp3.cards.append(throw_card)
elif pile_choice == 4:
comp_bp4.cards.append(throw_card)
def player_turn():
global app_running
global moving
computer.turn = False
player.turn = True
main_deck_rect = Rect(main_deck.rect)
for event in pygame.event.get():
if event.type == QUIT:
app_running = False
if event.type == MOUSEBUTTONDOWN:
if main_deck_rect.collidepoint(event.pos):
player.draw_hand(game_deck)
pygame.display.update()
Mainloop:
while app_running:
first_player()
if computer.first_turn:
if drawing == 0:
computer.draw_hand(game_deck)
computer_turn()
else:
computer_end_turn()
drawing += 1
drawing = drawing % 2
else:
player_turn()
I tried to implement different states for when the Computer is drawing a card, and when it's playing, but that still didn't work. I have a feeling that the issue is with the draw_hand() method that keeps running even after a card has been played from the hand, and I'm unsure as to how I can stop that from happening.
Any help would be greatly appreciated.
Edit:
Here is the code I wrote to determine which player goes first:
def first_player():
if comp_top_card.name == 'king' or player_top_card.name == 'king':
if comp_top_card.name == 'king':
computer.first_turn = True
player.first_turn = False
# print('computer goes first')
elif player_top_card.name == 'king':
computer.first_turn = False
player.first_turn = True
# print('player goes first')
elif comp_top_card.name and player_top_card.name == 'king':
comp_choice = randint(0, 52)
play_choice = randint(0, 52)
if comp_choice > play_choice:
computer.first_turn = True
player.first_turn = False
# print('computer goes first')
else:
computer.first_turn = False
player.first_turn = True
# print('player goes first')
else:
if comp_top_card.value > player_top_card.value:
computer.first_turn = True
player.first_turn = False
# print('computer goes first')
elif comp_top_card.value < player_top_card.value:
computer.first_turn = False
player.first_turn = True
# print('player goes first')
else:
comp_choice = randint(0, 52)
play_choice = randint(0, 52)
if comp_choice > play_choice:
computer.first_turn = True
player.first_turn = False
# print('computer goes first')
else:
computer.first_turn = False
player.first_turn = True
# print('player goes first')
(I'm sure this code if pretty messy and there's a more efficient way of doing things...but this is what worked for me hahahah)
I experimented with various alterations to the code and I got it to work the way I want by moving the first_player() function out of the main loop as that function should only be called once at the beginning of the game.
So now my code looks like this:
first_player()
while app_running:
if computer.turn:
if drawing == 0:
computer.draw_hand(game_deck)
else:
computer_turn()
check_for_turn_end()
drawing += 1
drawing = drawing % 2
else:
player_turn()

calling function several times

I have another problem with my text game. I have written a function that generates a random mob depending on the roll.
def random_mob():
roll = twenty_sided_die.roll()
if roll <= 5 :
return Zombie()
elif roll <= 10:
return Ghul()
elif roll <= 15:
return Skeleton()
elif roll <= 19:
return Ghost()
else:
return Slime()
mob = random_mob()
Than I have a function called encounter:
def encounter():
for command, action in hero.COMMANDS.items():
print("Press {} to {}".format(command, action[0]))
while True:
command = input("~~~~~~~Press key to continue~~~~~~~")
if command not in hero.COMMANDS:
print("Not a valid command")
continue
print("You are fighting " + mob.name)
print("")
time.sleep(1)
break
while True:
if command:
hero.COMMANDS[command][1]()
PlayerAttack()
time.sleep(1)
if mob.hp > 0:
MonsterAttack()
time.sleep(1)
if hero.hp <= 0:
print("++++++You were killed++++++")
break
time.sleep(1)
else:
continue
When calling the function, random monster is being generated,fight and rolls begins. After each successful roll, monster looses its HP.
After the function ends I would like to call next encounter in the way that again a random mob is being generated and the fight starts over
Problem I have, that if I call encounter() again, it generates the same monster, with HP from previos fight, and the function ends after one roll.
How to deal with it?
You are not initializing hit points for the monster. Maybe mob should be an array, where you append/push new monster by encounter() method/function. Then, if during the fight the monster is killed you remove/pop it. For example (the monster to fight next is on top of the stack in this example, if the stack is empty fight is over):
#begin game
mob = []
...
# add monster object to the stack
mob.push(random_mob())
...
if mob.hp > 0:
#do fighting
else:
# remove monster object from the stack
mob.pop()
First, I think you've to learn how Python works and how variables manage their scope inside packages, classes and functions.
You should also learn more about general programming with objects to get started on a good foundation. You can find lots of tutorials on the web.
As said in the comments, your main problem is that your variable mob is never modified!
Here's an example of a factory that can randomly generate monsters when you call the function encounter():
from random import randint
class Zombie(object):
pass
class Ghul(object):
pass
class Skeleton(object):
pass
class Ghost(object):
pass
class Slime(object):
pass
class MobFactory(object):
# create() function will return a mob depending of roll value
#staticmethod
def create(roll):
if roll <= 5:
return Zombie()
elif roll <= 10:
return Ghul()
elif roll <= 15:
return Skeleton()
elif roll <= 19:
return Ghost()
else:
return Slime()
def encounter():
roll = randint(1, 20)
mob = MobFactory.create(roll)
print(mob.__class__)
if __name__ == '__main__':
# Here I simulate multiple call of encounter()
for _ in range(0, 3):
encounter()
I hope it will help you.

How to make a save/load game for a text based python rpg?

EDIT: I am using python 3.2! rest of post below...
I am finishing my text based RPG in python, and I need some help. I need to make a save/load game system. I read that I can use pickle a few other methods but thats not entirely what I want. Basically, I want to be able to save my variables into a text file. If the file exists, load the variables, and skip over the introduction where it asks the player for a name. I will give the pickle method and others try and see how they work. If someone would be kind enough to show me how I would do this with .txt files, I would be very grateful! I will continue digging and post my solution once I have found it.
EDIT:
I have removed the irrelevant parts of my original post. The following code is the WORKING game.py file. I no longer use a separate class module. Topic solved, now I can work on a storyline! :D
#A text based RPG
#Import required modules
import jsonpickle
import os
import sys
import time
from random import randint
#main game
#Variables
go = True
IsShopLocked = False
IsDaggerEquipped = False
IsSwordEquipped = False
IsLeatherHideEquipped = False
SAVEGAME_FILENAME = 'savegame.json'
game_state = dict()
### Classes ###
class Human(object):
#Represents the human player in the game
def __init__(self, name, health, strength, gold):
self.name = name
self.health = health
self.strength = strength
self.gold = gold
class AI(object):
#Represents the enemy player in the game
def __init__(self, name, health, strength):
self.name = name
self.health = health
self.strength = strength
class Item(object):
#represents any item in the game
def __init__(self, name, hvalue, strvalue):
self.name = name
self.hvalue = hvalue
self.strvalue = strvalue
###end classess###
###functions for loading, saving, and initializing the game###
def load_game():
"""Load game state from a predefined savegame location and return the
game state contained in that savegame.
"""
with open(SAVEGAME_FILENAME, 'r') as savegame:
state = jsonpickle.decode(savegame.read())
return state
def save_game():
"""Save the current game state to a savegame in a predefined location.
"""
global game_state
with open(SAVEGAME_FILENAME, 'w') as savegame:
savegame.write(jsonpickle.encode(game_state))
def initialize_game():
"""If no savegame exists, initialize the game state with some
default values.
"""
global game_state
player = Human('Fred', 100, 10, 1000)
enemy = AI('Imp', 50, 20)
state = dict()
state['players'] = [player]
state['npcs'] = [enemy]
return state
###End functions for loading, saving, and initalizing the game###
###Main game functions###
#Function for the shop
def Shop():
global game_state
player = game_state['players'][0]
dagger = Item('Dagger', 0, 5)
sword = Item('Sword', 0, 10)
leather_hide = Item('Leather Hide', 5, 0)
if IsShopLocked == True:
print("The shop is locked!\nPlease go back and continue your adventure!")
else:
print()
print("Welcome to the Larkville shop! What would you like to buy?\n1. Weapons\n2. armor\n3. Go back")
selection = int(input("Enter a value: "))
if selection == 1:
if player.gold >= 50:
print("Weapons shop")
print("1. Bronze Dagger: $20\n2. Bronze Sword: $50")
wpnselection = int(input("Enter a value: "))
if wpnselection == 1:
global IsDaggerEquipped
global IsSwordEquipped
if IsDaggerEquipped == True or IsSwordEquipped == True:
print("You already have this or another weapon equipped...")
Game_Loop()
else:
dagger = Item('Dagger', 0, 5)
IsDaggerEquipped = True
player.strength += dagger.strvalue
player.gold -= 20
print("strength increased to: {}".format(player.strength))
Game_Loop()
elif wpnselection == 2:
if IsDaggerEquipped == True or IsSwordEquipped == True:
print("You already have this or another weapon equipped...")
Game_Loop()
else:
sword = Item('Sword', 0, 10)
IsSwordEquipped = True
player.strength += sword.strvalue
player.gold -= 50
print("strength increased to: {}".format(player.strength))
Game_Loop()
elif wpnselection == 3:
Game_Loop()
elif selection == 2:
if player.gold >= 20:
print ("Armor Shop")
print ("1. Leather hide\n2. Go back")
armselection = int(input("enter a value: "))
if armselection == 1:
global IsLeatherHideEquipped
if IsLeatherHideEquipped == True:
print("You are already wearing armor!")
Game_Loop()
else:
leather_hide = Item('Leather Hide', 5, 0)
IsLeatherHideEquipped = True
player.health += leather_hide.hvalue
player.gold -= 20
print("Health increased to: {}".format(player.health))
Game_Loop()
elif armselection == 2:
Game_Loop()
elif selection == 3:
Game_Loop()
#Function for combat
def Combat():
global game_state
player = game_state['players'][0]
enemy = game_state['npcs'][0]
global go
while go == True:
dmg = randint (0, player.strength)
edmg = randint (0, enemy.strength)
enemy.health -= dmg
if player.health <= 0:
os.system('cls')
print()
print("You have been slain by the enemy {}...".format(enemy.name))
go = False
leave = input("press enter to exit")
elif enemy.health <= 0:
os.system('cls')
print()
print("You have slain the enemy {}!".format(enemy.name))
go = False
leave = input("press any key to exit")
else:
os.system('cls')
with open("test.txt", "r") as in_file:
text = in_file.read()
print(text)
player.health -= edmg
print()
print("You attack the enemy {} for {} damage!".format(enemy.name, dmg))
print("The enemy has {} health left!".format(enemy.health))
print()
print("The enemy {} attacked you for {} damage!".format(enemy.name, edmg))
print("You have {} health left!".format(player.health))
time.sleep(3)
#The main game loop
def Game_Loop():
global game_state
while True:
print()
print("You are currently in your home town of Larkville!")
print("What would you like to do?")
print("1. Shop\n2. Begin/continue your adventure\n3. View player statistics\n4. save game")
print()
try:
selection = int(input("Enter a value: "))
except ValueError:
print()
print("You can only use the numbers 1, 2, or 3.")
print()
Game_Loop()
if selection == 1:
Shop()
elif selection == 2:
Combat()
elif selection == 3:
player = game_state['players'][0]
print()
print("Your players stats:\nHealth: {}\nStrength: {}\nGold: {}".format(player.health, player.strength, player.gold))
if IsDaggerEquipped == True:
print("You have a dagger equipped")
elif IsSwordEquipped == True:
print ("You have a sword equipped")
elif IsLeatherHideEquipped == True:
print("You are wearing a leather hide")
elif selection == 4:
game_state = save_game()
else:
print()
print("Oops! Not a valid input")
print()
###End main game functions###
###The "main" function, not to be confused with anything to do with main above it###
def main():
"""Main function. Check if a savegame exists, and if so, load it. Otherwise
initialize the game state with defaults. Finally, start the game.
"""
global game_state
if not os.path.isfile(SAVEGAME_FILENAME):
game_state = initialize_game()
else:
game_state = load_game()
Game_Loop()
if __name__ == '__main__':
main()
###end main function###
You can use jsonpickle to serialize your object graph to JSON. jsonpickle is not part of the standard library, so you'll have to install it first, for example by doing easy_install jsonpickle.
You could also achieve the same using the standard library json module, but then you'd have to implement your own JSONEncoder to deal with your custom objects. Which isn't hard, but not as easy as just letting jsonpickle do it for you.
I used simplified examples of your player classes to demonstrate how you could implement load and save functionality for the objects that constitute your game state (completely ignoring any story line):
import jsonpickle
import os
import sys
SAVEGAME_FILENAME = 'savegame.json'
game_state = dict()
class Human(object):
"""The human player
"""
def __init__(self, name, health, gold):
self.name = name
self.health = health
self.gold = gold
class Monster(object):
"""A hostile NPC.
"""
def __init__(self, name, health):
self.name = name
self.health = health
def load_game():
"""Load game state from a predefined savegame location and return the
game state contained in that savegame.
"""
with open(SAVEGAME_FILENAME, 'r') as savegame:
state = jsonpickle.decode(savegame.read())
return state
def save_game():
"""Save the current game state to a savegame in a predefined location.
"""
global game_state
with open(SAVEGAME_FILENAME, 'w') as savegame:
savegame.write(jsonpickle.encode(game_state))
def initialize_game():
"""If no savegame exists, initialize the game state with some
default values.
"""
player = Human('Fred', 100, 10)
imp = Monster('Imp', 50)
state = dict()
state['players'] = [player]
state['npcs'] = [imp]
return state
def attack():
"""Toy function to demonstrate attacking an NPC.
"""
global game_state
imp = game_state['npcs'][0]
imp.health -= 3
print "You attacked the imp for 3 dmg. The imp is now at %s HP." % imp.health
def spend_money(amount):
"""Toy function to demonstrate spending money.
"""
global game_state
player = game_state['players'][0]
player.gold -= amount
print "You just spent %s gold. You now have %s gold." % (amount, player.gold)
def game_loop():
"""Main game loop.
This loop will run until the player exits the game.
"""
global game_state
while True:
print "What do you want to do?"
choice = int(raw_input("[1] Save game [2] Spend money "
"[3] Attack that Imp! [4] Load game "
"[5] Exit game\n"))
if choice == 1:
save_game()
elif choice == 2:
spend_money(5)
elif choice == 3:
attack()
elif choice == 4:
game_state = load_game()
else:
print "Goodbye!"
sys.exit(0)
def main():
"""Main function. Check if a savegame exists, and if so, load it. Otherwise
initialize the game state with defaults. Finally, start the game.
"""
global game_state
if not os.path.isfile(SAVEGAME_FILENAME):
game_state = initialize_game()
else:
game_state = load_game()
game_loop()
if __name__ == '__main__':
main()
Note the global game_state variable. You need something like that to keep track of all the objects that define your game state and keep them together for easy serialization / deserialization. (It doesn't necessarily have to be global, but it's definitely easier, and a game state like this is one of the few cases where it actually makes sense to use globals).
Saving the game using this code will result in a savegame.json that looks like this:
{
"npcs": [
{
"health": 41,
"name": "Imp",
"py/object": "__main__.Monster"
}
],
"players": [
{
"gold": 5,
"health": 100,
"name": "Fred",
"py/object": "__main__.Human"
}
]
}

Categories