I've been learning Python by doing random projects here and there. My newest project is a simple text roguelike RPG. The player starts with base stats and just has to survive
Players can attack, heal or run. Which for the most part does work, however, I'm trying to display a kill count beside the player name and visible stats(exp and HP). I'm pretty sure my count variable is just misplaced as it resets to 0 after every enemy death. I want this because it SHOULD mimic b_count for boss appearance. My code is as follows:
import random
import math
import time
# Define base character class amd attributes
class Base:
def __init__(self, name, lvl, max_hp, hp, strength, defense, wpn):
self.name = name
self.lvl = lvl
self.max_hp = max_hp
self.hp = hp
self.wpn = wpn
self.strength = strength
self.defense = defense
# Set Player class as subclass of base, add exp and lvlUp attributes.
class Player(Base):
def __init__(self, exp, lvlUp, **kwargs):
super().__init__(**kwargs)
self.exp = exp
self.lvlUp = lvlUp
# Define LevelUp
def LevelUp(self):
while self.exp >= self.lvlUp:
self.lvl += 1
self.exp -= self.exp
self.lvlUp *= 1.125
hp_gain = round(self.max_hp * 0.125)
str_gain = round(self.strength * 0.25)
dfn_gain = round(self.defense * 0.25)
self.max_hp *= 1.125
self.hp == self.max_hp
self.strength += str_gain
self.defense += dfn_gain
print("You leveled up and gained {} Hp, {} Strength, and {} Defense. \n You feel rejuvenated".format(hp_gain, str_gain, dfn_gain))
else:
pass
# Define heal
def heal(self):
gain = random.randrange(4 , math.ceil(self.max_hp * 0.75), 2)
if self.hp + gain >= self.max_hp:
max_gain = self.max_hp - self.hp
self.hp = self.max_hp
return max_gain
else:
self.hp += gain
return gain
# Define attack
def attack(self, other):
# Define damage based on strength and wpn
dmg = math.floor(random.uniform(self.strength * self.wpn, (self.strength * self.wpn) * 2) - other.defense)
time.sleep(0.2)
print("You dealt {} damage".format(dmg))
other.hp -= dmg
if other.hp > 0:
print("{} has {} health remaining".format(other.name, other.hp))
# Define exp gain and player heal upon enemy death
else:
new_exp = random.randrange(2, 16, 2)
heal = self.heal()
print(f"You killed {other.name}. You healed {heal} HP and gained {new_exp} Exp")
self.exp += new_exp
self.LevelUp()
print("Level {}: [{}/{}]".format(self.lvl + 1, self.exp, self.lvlUp))
# Set Mob class
class Mob(Base):
def __init__(self, *args):
super().__init__(*args)
# Define Mob attack
def attack(self, other):
dmg = math.floor(random.uniform(self.strength * self.wpn, (self.strength * self.wpn) * 2) - other.defense)
if dmg <= 0:
dmg = 0
print("{} dealt {} damage".format(self.name, dmg))
elif dmg >= other.hp:
print("{} dealt {} damage and killed you.".format(self.name, dmg))
other.hp -= dmg
else:
other.hp -= dmg
print("{} dealt {} damage".format(self.name, dmg))
print("You have {} health remaining".format(other.hp))
#Set Boss class
#NOT DONE
class Boss(Base):
def __init__(self, *args):
super().__init__(*args)
# Set Player Name
hero_name = input("Enter your name...")
# Define base hero stats
hero = Player(exp=0, lvlUp=32, name=hero_name, lvl=1, max_hp=64, hp=64, strength=8, defense=4, wpn=1.125)
cmdlist = [
["a", "attack"],
["h", "heal"],
["r", "run"]]
# Set mob list
mobs = [
Mob("Goblin", 1, 16, 16, 4, 2, 1),
Mob("Wolf", 1, 24, 24, 6, 2, 1),
Mob("Imp", 1, 16, 16, 4, 2, 1.125),
Mob("Minotaur", 1, 32, 32, 4, 4, 1.25),
Mob("Bandit", 1, 24, 24, 8, 4, 1.125),
Mob("Succubus", 1, 24, 24, 4, 4, 1.25),
Mob("Gargoyle", 1, 32, 32, 6, 2, 1.25),
Mob("Bear", 1, 48, 48, 6, 4, 1.375),
Mob("Chimera", 1, 48, 48, 6, 4, 1.375),
Mob("Necromancer", 1, 32, 32, 6, 4, 1.5)]
# Set boss list
bosses = [
Boss("Minotaur", 1, 32, 32, 4, 4, 1.25),
Boss("Bandit", 1, 24, 24, 8, 4, 1.125),
Boss("Bear", 1, 48, 48, 6, 4, 1.375),
Boss("Chimera", 1, 48, 48, 6, 4, 1.375),
Boss("Necromancer", 1, 32, 32, 6, 4, 1.5)]
# Define battle sequence and count
def battle(player, enemy):
count = 0
print("A {} charges towards you!".format(enemy.name))
# Allows for attack/run each turn
while player.hp > 0 and enemy.hp > 0:
count = 0
print("[{}] Kills: {}".format(player.name, count))
print("[HP: {}] [Next Level {}: [{}/{}]".format(player.hp, player.lvl + 1, player.exp, player.lvlUp))
command = input("(A)ttack, (H)eal or (R)un? \n")
if command.lower() in cmdlist[0]:
player.attack(enemy)
print("---------------------")
time.sleep(.5)
if enemy.hp <= 0:
count += 1
return count
enemy.attack(player)
print("---------------------")
time.sleep(.2)
elif command.lower() in cmdlist[1]:
heal = player.heal()
print("You heal for {} HP".format(heal))
continue
elif command.lower() in cmdlist[2]:
chance = random.randint(1, 20)
if chance in range(11, 21):
print("You got away without a scratch")
break
elif chance in range(1, 10):
dmg = round(random.uniform((enemy.strength * enemy.wpn / 4), (enemy.strength * enemy.wpn) / 2))
player.hp -= dmg
print("You got away, but with minor injuries.[-{} HP] \nYou have {} HP remaining".format(dmg, hero.hp))
time.sleep(0.5)
break
if __name__ == "__main__":
b_count = 0
if b_count < 5:
while hero.hp > 0:
b_count +=1
battle(hero, random.choice(mobs))
elif b_count > 5 and b_count % 3 == 0:
if b_count % 3 == 0:
while hero.hp > 0:
b_count +=1
print("That one looks bigger")
battle(hero, random.choice(bosses))
else:
while hero.hp > 0:
b_count +=1
battle(hero, random.choice(mobs))
Inside the battle function, you're setting the count variable at the beginning of the function, but also resetting it in a loop before it gets displayed.
def battle(player, enemy):
count = 0
...
# Allows for attack/run each turn
while player.hp > 0 and enemy.hp > 0:
count = 0 # remove this line
print("[{}] Kills: {}".format(player.name, count))
Removing the marked line will display the kills for that battle (the duration of the loop in the battle function). If you want to keep track of the payers kills for the entire game, I'd make the count variable an attribute of the Player class.
One last note, count is not the best variable name here. You're keeping track of several different counts in your game, so each one should have a distinct name that tells you at a glance what it refers to. In this case kill_count would be better.
Related
I'm making good progress on a basic turn-based RPG battle system in Python. I'm trying to create the program using object-oriented programming so I can easily add new classes, attacks, and enemies as needed. I've implemented most of the features I'd like to, but one goal I'm struggling with is the implementation of a cooldown system for certain attacks. Here is the code I've written:
import random
class Class:
def __init__(self, name, health, attacklist):
self.name = name
self.health = health
self.attacklist = attacklist
class Enemy:
def __init__(self, name, health, attacklist):
self.name = name
self.health = health
self.attacklist = attacklist
class Attack:
def __init__(self, name, base_damage, max_damage, healing, stun, chance, reduce_chance, cooldown, on_cooldown):
self.name = name
self.base_damage = base_damage
self.max_damage = max_damage
self.healing = healing
self.stun = stun
self.chance = chance
self.reduce_chance = reduce_chance
self.cooldown = cooldown
self.on_cooldown = on_cooldown
Punch = Attack("Punch", 50, 100, 0, "no_stun", 80, 0, 0, False)
Stunner = Attack("Stunner", 20, 30, 0, "stun", 70, 0, 0, False)
Bite = Attack("Bite", 30, 40, 0, "no_stun", 60, 0, 0, False)
Scratch = Attack("Scratch", 20, 30, 0, "no_stun", 70, 0, 0, False)
garbage_fling = Attack("Garbage Fling", 5, 10, 0, 0, 80, 20, 2, False)
fighter_attacklist = [Punch, Stunner]
vermen_dreg_attacklist = [Bite, Scratch]
vermen_scrounger_attacklist = [garbage_fling, Bite]
Fighter = Class("Fighter", 500, fighter_attacklist)
vermen_dreg = Enemy("Vermen Dreg", 100, vermen_dreg_attacklist)
vermen_scrounger = Enemy("Vermen Scrounger", 100, vermen_scrounger_attacklist)
enemy_list = [vermen_scrounger]
stun_cooldown = 0
enemy_cooldown = 0
while True:
print("Choose your class: Fighter (1)")
choice = input()
if choice == "1":
player_class = Fighter
print("You have chosen:", player_class.name)
enemy = random.choice(enemy_list)
enemy_attacks = enemy.attacklist
print("Your enemy is:", enemy.name)
else:
print("Error, invalid input!")
continue
while True:
cooldown_list = []
print(cooldown_list)
enemy_stunned = False
#Player Attack
print("Your health:", player_class.health)
print("Enemy health:", enemy.health)
print("Attacks:", player_class.attacklist[0].name, "(1)", player_class.attacklist[1].name, "(2)")
choice = input()
if choice == "1":
player_attack = player_class.attacklist[0]
elif choice == "2":
player_attack = player_class.attacklist[1]
else:
print("Please enter a valid number!")
continue
diceroll = random.randint(1, 100)
if diceroll <= player_attack.chance:
player_damage = random.randint(player_attack.base_damage, player_attack.max_damage)
if player_damage > 0:
enemy.health -= player_damage
print("You hit", enemy.name, "for", player_damage)
if player_attack.stun == "stun":
if stun_cooldown > 0:
print("The enemy resisted your stun attempt!")
if stun_cooldown == 0:
print("You stunned the enemy.")
enemy_stunned = True
stun_cooldown = 3
player_healing = player_attack.healing
player_class.health += player_healing
if player_healing > 0:
print("You healed for", player_healing)
elif diceroll > player_attack.chance:
print("You missed!")
# Enemy Turn
if enemy_stunned == False:
enemy_move = random.choice(enemy.attacklist)
diceroll = random.randint(1, 100)
if diceroll <= enemy_move.chance:
enemy_damage = random.randint(enemy_move.base_damage, enemy_move.max_damage)
if enemy_damage > 0:
player_class.health -= enemy_damage
print(enemy.name, "hit you with", enemy_move.name, "for", enemy_damage)
reduce_chance = enemy_move.reduce_chance
for Attack in player_class.attacklist:
player_class.attacklist[0 - 2].chance -= reduce_chance
if player_class.attacklist[0 - 2].chance < 50:
player_class.attacklist[0 - 2].chance = 50
if reduce_chance > 0:
print("Your chance was reduced by", enemy_move.reduce_chance)
if enemy_move.cooldown > 0:
enemy.attacklist.remove(enemy_move)
enemy_move = on_cooldown
elif diceroll > enemy_move.chance:
print("The enemy attack missed!")
elif enemy_stunned == True:
print("The enemy was stunned and could not attack.")
stun_cooldown -= 1
enemy_cooldown -= 1
if stun_cooldown < 0:
stun_cooldown = 0
My goal is to give the "Garbage Throw" attack for the "Vermen Scrounger" a cooldown so that the computer will not use it every single turn. I currently have the attack set to delete itself from the list of attacks after it is used, however, I don't have a clean solution for implementing it back into the enemy "Attack List" after 2 turns have passed. Preferably, I would like to have a function within the "Attack" class that initiates the cooldown for each iteration of my battle loop.
I tried to remove the attack from the enemy attack list and succeeded, however, I have no way of returning it to the attack list.
Here is the full code:
import random
import numpy as np
world = {}
class Player():
def __init__(self, health, maxHealth, baseDmg, dmg, name, weapons, items, isAlive, previousRoom, roomName):
self.health = health
self.maxHealth = maxHealth
self.baseDmg = baseDmg
self.dmg = dmg
self.name = name
self.weapons = weapons
self.items = items
self.isAlive = isAlive
self.previousRoom = previousRoom
self.room = world[roomName]
def Move(self, direction):
if direction not in self.room.exits:
print("Cannot Move In That Direction!")
return
newRoomName = self.room.exits[direction]
self.previousRoom = world[self.room.name]
print("Moving to", newRoomName)
self.room = world[newRoomName]
def MoveBack(self):
self.room = world[self.previousRoom.name]
print("Moving to", self.room.name)
class Enemy():
def __init__(self, health, dmg, hasLoot, lootItem, isAlive):
self.health = health
self.dmg = dmg
self.hasLoot = hasLoot
self.lootItem = lootItem
self.isAlive = isAlive
class Weapon():
def __init__(self, name, dmg, description):
self.name = name
self.dmg = dmg
self.description = description
class Item():
def __init__(self, name, amt, description):
self.name = name
self.amt = amt
self.description = description
class Room():
def __init__(self, name, description, exits, hasWeapon, weapon, hasItem, item, hasEnemy, enemy, isFirstVisit, coords):
self.name = name
self.description = description
self.exits = exits
self.hasWeapon = hasWeapon
self.weapon = weapon
self.hasItem = hasItem
self.item = item
self.hasEnemy = hasEnemy
self.enemy = enemy
self.isFirstVisit = isFirstVisit
self.coords = coords
#######################Dungeon Generation###################
rooms = np.zeros((11, 11))
maxRooms = 7
possibleNextRoom = []
def startLevel():
for r in range(len(rooms[0])):
for c in range(len(rooms[1])):
rooms[r][c] = 0
possibleNextRoom.clear()
halfHeight = int(len(rooms[1]) / 2)
halfWidth = int(len(rooms[0]) / 2)
rooms[halfWidth][halfHeight] = 1
def resetLevel():
for r in range(len(rooms[0])):
for c in range(len(rooms[1])):
rooms[r][c] = 0
possibleNextRoom.clear()
def countRooms():
roomCount = 0
for r in range(len(rooms)):
for c in range(len(rooms)):
if rooms[r][c] == 1:
roomCount += 1
return roomCount
def findPossibleRooms():
for r in range(len(rooms) - 1):
for c in range(len(rooms) - 1):
if rooms[r][c] == 1:
if rooms[r][c+1] != 1:
possibleNextRoom.append((r, c+1))
if rooms[r][c-1] != 1:
possibleNextRoom.append((r, c-1))
if rooms[r-1][c] != 1:
possibleNextRoom.append((r-1, c))
if rooms[r+1][c] != 1:
possibleNextRoom.append((r+1, c))
def addRoom():
x = random.randrange(0, len(possibleNextRoom))
rooms[possibleNextRoom[x][0]][possibleNextRoom[x][1]] = 1
possibleNextRoom.pop(x)
def generateLevel():
global x, possibleNextRoom
startLevel()
while countRooms() < maxRooms:
countRooms()
findPossibleRooms()
addRoom()
def makeRoomsForLevel():
counter = 1
for r in range(len(rooms)):
for c in range(len(rooms)):
if rooms[c][r] == 1:
world[f"room{counter}"] = Room(
f"room{counter}",
"",
{},
False,
None,
False,
None,
False,
None,
True,
(r, c)
)
counter += 1
def findRoom(x, y):
for i in range(len(world)):
if world[f"room{i+1}"].coords == (x, y):
return f"room{i+1}"
return None
def findExits():
for i in range(len(world)):
x, y = world[f"room{i+1}"].coords
exits = dict()
#east
if rooms[x, y+1] == 1:
exits["E"] = findRoom(x, y+1)
#south
if rooms[x+1, y] == 1:
exits["S"] = findRoom(x+1, y)
#west
if rooms[x, y-1] == 1:
exits["W"] = findRoom(x, y-1)
#north
if rooms[x-1, y] == 1:
exits["N"] = findRoom(x-1, y)
world[f"room{i+1}"].exits = exits
############################################################
generateLevel()
makeRoomsForLevel()
findExits()
WoodenSword = Weapon("Wooden Sword", 5, "A wooden sword. Looks like a kid's toy.")
IronDagger = Weapon("Iron Dagger", 8, "Small, sharp, and pointy. Good for fighting monsters!")
HealthPot = Item("Health Potion", 1, "A Potion of Instant Health. Restores 10 Health.")
goblin1 = Enemy(25, 2, True, [HealthPot, IronDagger], True)
player = Player(10, 10, 5, 5, "", [], [], True, "room1", "room1")
def ShowInv():
print("*******************************")
print("Name:", player.name)
print("Health:", player.health)
print("Weapons:")
for i in player.weapons:
print(" ===============================")
print(" Weapon:", i.name)
print(" Description:", i.description)
print(" Damage:", i.dmg)
print(" ===============================")
print("Items:")
for i in player.items:
print(" ===============================")
print(" Item:", i.name)
print(" Amount:", i.amt)
print(" Description:", i.description)
print(" ===============================")
print("*******************************")
def testItems(item):
exists = item in player.items
return exists
def fight(enemy):
print("Your Health:", player.health)
print("Enemy Health:", enemy.health)
ans = input("What would you like to do?\n>>")
if ans == "attack":
chance = random.randrange(1, 20)
if chance >= 10:
enemy.health -= player.dmg
else:
print("You did not roll high enough...\nYour turn has been passed...")
if ans == "heal":
chance = random.randrange(1, 20)
if testItems(HealthPot):
if chance >= 10:
x = 0
for item in player.items:
if item == HealthPot:
player.health += 10
if player.health > player.maxHealth:
player.health = player.maxHealth
item.amt -= 1
if item.amt <= 0:
player.items.pop(x)
break
x += 1
else:
print("You did not roll high enough...\nYour turn has been passed...")
if ans == "run":
chance = random.randrange(1, 20)
if chance >= 10:
player.MoveBack()
else:
print("You did not roll high enough...\nYour turn has been passed...")
if enemy.health > 0 and player.health > 0:
chance = random.randrange(1, 20)
if chance >= 10:
player.health -= enemy.dmg
else:
if enemy.health <= 0:
enemy.isAvile = False;
def testRoom():
if player.room.hasWeapon:
if player.room.isFirstVisit:
player.weapons.append(player.room.weapon)
if player.room.hasItem:
if player.room.isFirstVisit:
player.items.append(player.room.item)
if player.room.hasEnemy:
if player.room.isFirstVisit:
while player.room.enemy.health > 0:
fight(player.room.enemy)
player.room.isFirstVisit = False
while True:
command = input(">>")
if command in {"N", "S", "E", "W"}:
player.Move(command)
testRoom()
elif command == "look":
print(player.room.description)
print("Exits:", *','.join(list(player.room.exits.keys())))
elif command == "inv":
ShowInv()
elif command == "heal":
if testItems(HealthPot):
player.health += 10
if player.health > player.maxHealth:
player.health = player.maxHealth
else:
print("You don't have any", HealthPot.name, "\bs")
else:
print("Invalid Command")
And here is the problem:
Everything seems to work fine, until a couple moves in when it breaks and gives me a "KeyError: None" for the room I just walked in. I have no idea what could be causing this, and I am fairly new, so please simplify the explanations for me. I think it has something to do with the findExits() function and findRoom() function, but idk.
Here is the TraceBackError:
Traceback (most recent call last):
File "main.py", line 287, in <module>
player.Move(command)
File "main.py", line 26, in Move
self.room = world[newRoomName]
KeyError: None
I've tried fiddling with the function, but nothing i've tried worked. Here is the repl.it link:
https://replit.com/#samsonsbrother0/Dungeon-Crawler#main.py
your code is accessing a key before it exists, thus the error. to fix it, you need to assign the newroomname to the world dict as you move, like so:
print("Moving to", newRoomName)
world[newRoomName] = newRoomName
self.room = world[newRoomName]
I am trying to use minimax algo to find a best move for a game.
The game is 2 players take turns to pick a number from a pile [0,1,2,,,8]
Winning Condition: player wins the game if the player contains three numbers and their sum is 14.
The initial game state is given by the argument like:
4 1 2 3 4
The first number indicate the total length and the following numbers are the numbers taken by player each turn. In this example the player A has [1,3] and player B has [2,4]
My problem is the algo can't give the correct answer:
Like when the input is 4 4 1 7 8 my program cannot gives the correct move: it takes 0 not 3 for next move.
import sys
import math
totalMoves = int(sys.argv[1])
pile = [0, 1, 2, 3, 4, 5, 6, 7, 8]
# who are u
you = []
opponent = []
# cards in hand
playerA = []
playerB = []
# get all the cards into hand
for i in range(totalMoves):
# save card into playerB
if i % 2 != 0:
playerB.append(int(sys.argv[i+2]))
# save card into playerA
if i % 2 == 0:
playerA.append(int(sys.argv[i+2]))
# remove sent card in list
pile.remove(int(sys.argv[i+2]))
# identify which player you are
if totalMoves % 2 == 0:
you = playerA
opponent = playerB
else:
you = playerB
opponent = playerA
def find3Numbers(player): # calcluate the card in hand is equal to 14
arr_size = len(player)
if (len(player) >= 3):
for i in range(0, arr_size-2):
for j in range(i + 1, arr_size-1):
for k in range(j + 1, arr_size):
if (player[i] + player[j] + player[k] == 14):
return True
else:
return False
def isNumberLeft(board):
if (len(board) == 0):
return False
else:
return True
def evaluate(player, oppo):
if (find3Numbers(player) == True):
return 10
elif (find3Numbers(oppo) == True):
return -10
else:
return 0
def minimax(board, player, oppo, depth, isMax):
score = evaluate(player, oppo)
if (score == 10):
return score
if (score == -10):
return score
if (isNumberLeft(board) == False):
return 0
if (isMax):
best = -math.inf
for card in board:
player.append(card)
board.remove(card)
best = max(best, minimax(board, player, oppo, depth+1, not isMax))
board.append(card)
player.remove(card)
return best
else:
best = +math.inf
for card in board:
oppo.append(card)
board.remove(card)
best = min(best, minimax(board, player, oppo, depth+1, not isMax))
board.append(card)
oppo.remove(card)
return best
def bestMove():
bestScore = -math. inf
bestNum = -math.inf
for card in pile:
you.append(card)
pile.remove(card)
score = minimax(pile, you, opponent, 0, False)
pile.append(card)
you.remove(card)
if (bestScore < score):
bestNum = card
bestScore = score
return bestNum
you.append(bestMove())
I am not able to find the error in this. It gives the error that you have not created the function life_left or it is not able to find it.
How many times do you want them to fight ? 5
Error:
Traceback (most recent call last):
File "main.py", line 42, in <module>
start(7)
File "main.py", line 39, in start
arr[number].attack(guns[guns_number])
File "main.py", line 19, in attack
life_left(self.life)
NameError: name 'life_left' is not defined
Code:
import random
class Enemy:
def __init__(self):
self.life = 20
def attack(self,gun):
if (self.life <= 0):
print("Dead")
else:
if gun is "AK47":
self.life = self.life - 5
life_left(self.life)
elif gun is "Magnum":
self.life = self.life - 4
life_left(self.life)
else:
self.life = self.life - 1
life_left(self.life)
def life_left(life):
print ("Life : " , str(life))
def start(players):
a = 1
arr = []
while a <= players:
arr.append("player" + str(a))
arr[a-1] = Enemy()
#print (arr[a-1])
a += 1
enemy = int(input("How many times do you want them to fight ? "))
fight = 1
guns = ["AK47" , "Magnum" , "other"]
while fight <= enemy:
number = random.randint(0,players-1)
guns_number = random.randint(0,len(guns)-1)
arr[number].attack(guns[guns_number])
fight += 1
start(7)
you have to use self in the method definition and in calling the methods inside the class. here is the fixed code:
import random
class Enemy:
def __init__(self):
self.life = 20
def attack(self,gun):
if (self.life <= 0):
print("Dead")
else:
if gun is "AK47":
self.life = self.life - 5
self.life_left(self.life)
elif gun is "Magnum":
self.life = self.life - 4
self.life_left(self.life)
else:
self.life = self.life - 1
self.life_left(self.life)
def life_left(self,life):
print ("Life : " , str(life))
def start(players):
a = 1
arr = []
while a <= players:
arr.append("player" + str(a))
arr[a-1] = Enemy()
#print (arr[a-1])
a += 1
enemy = int(input("How many times do you want them to fight ? "))
fight = 1
guns = ["AK47" , "Magnum" , "other"]
while fight <= enemy:
number = random.randint(0,players-1)
guns_number = random.randint(0,len(guns)-1)
arr[number].attack(guns[guns_number])
fight += 1
start(7)
I am new to programming in python and, I started writing a simple text based adventure game. I came across a problem when passing an object from one function to another. Here is my code:
import random
import time
num = random.randint(0,2)
xp1 = random.randint(1,2)
class player:
def __init__ (self, name, health, strength, defense, potion, xp, level):
self.__health = health
self.__strength = strength
self.__defense = defense
self.__name = name
self.__potion = potion
self.__xp = xp
self.__level = level
def getName(self):
return self.__name
def getHealth(self):
return self.__health
def getStrength(self):
return self.__strength
def getDefense(self):
return self.__defense
def getPotion(self):
return self.__potion
def getXP(self):
return self.__xp
def getLevel(self):
return self.__level
def setHealth(self):
self.__health = 10
def setLevel(self):
self.__level = 1
def subHealth(self, num):
self.__health -= num
def subPotion(self):
self.__potion -= 1
return self.__health
def addPotion(self, num1):
self.__potion += num1
def addHealth(self):
self.__health +=2
def addStrength(self):
self.__strength += 1
def addDefense(self):
self.__defense += 1
def addXP(self):
self.__xp += xp1
def addLevel(self):
self.__level += 1
self.__addHealth += 1
self.__defense += 1
self.__strength += 1
def battle(enemy, player1, name1):
player1 = player(name1, player1.getHealth(), player1.getStrength(), player1.getDefense(), player1.getPotion(), player1.getXP(), player1.getLevel())
enemy = player('Dongus', enemy.getHealth(), enemy.getStrength(), enemy.getDefense(), enemy.getPotion(), enemy.getXP(), enemy.getLevel())
s = 0
while s == 0:
time.sleep(1)
attack =int(input("Type 1 to attack, type 2 to use a potion."))
if attack == 1:
time.sleep(1)
print("Dongus's health is", enemy.subHealth(num))
print("Dongus hit you and your health is now at", player1.subHealth(num-player1.getDefense()))
elif attack == 2:
time.sleep(1)
print("You used a potion.")
player1.addHealth(), player1.subPotion()
if player1.getHealth() > 10:
player1.setHealth()
print("Dongus hit you and your health is now at", player1.subHealth(num-player1.getDefense()))
if enemy.getHealth()<=0:
print("Congratulations, you won! You recieved", xp1, "xp!")
player.addXP()
s = 2
def main():
name1 = input("What would you like your name to be?")
time.sleep(1)
print("Hello,", name1, "you are on a quest to save otis from the evil Dongus. You must slay him, or Otis will poop.")
time.sleep(2)
player1 = player(name1, 10, 2, 1, 0, 0, 1)
enemy = player('Dongus', 8, 4, 0, 0, 0, 0)
print("Your stats are, health:", player1.getHealth(), "strength:", player1.getStrength(), "and defense:", player1.getDefense())
time.sleep(2)
print("Fight!")
pick = input("You found a health potion! Press 'p' to pick it up.")
p = 0
while p == 0:
if pick == "p":
print("You added a potion to your inventory.")
player1.addPotion(1)
p = 2
else:
print("You have no potions, you should probably pick this one up.")
player1.addPotion(1)
p = 2
battle(enemy, player1, name1)
if self.__getXP() == 1:
print("You leveled up. You are now level 2.")
player1.addLevel()
print("Your stats are, health:", player1.getHealth(), "strength:", player1.getStrength(), "and defense:", player.getDefense())
loot1 = int(input("Type ''1'' to loot the enemy chest."))
if loot1 == 1:
print("You recieved two potions!")
player1.__addPotion(2)
enemy.setHealth(10)
battle(enemy, player1, name1)
main()
Now the problem is when I run the game, I get to a point where I type "1" to attack the enemy, but it says, for some reason, that after attacking the enemy, the enemies health is at "None". This is the same case when the enemy attacks player1, it says player1's health is at "None". I assume that "None" is the default value in python 3.4.1, so my thinking is that the player1's object from def main() are not being transferred over to def battle() and I cannot see the reason why this is happening. I most likely am missing something here, or it is something I do not already know about Python that is causing the issue. Does anybody know what I can do to fix this, and why it is doing this?
BTW some of the terms I am using may be wrong, so please correct me if they are... I have only been coding for 2 weeks :p.
Thanks!!!
First, received not recieved
2nd yes, If you have a Python function that does not return a value, the result is None
# dummy will return "Positive" or None
def dummy(x):
if X > 0:
return "Positive"
So, you probably want to change
def subHealth(self, num):
self.__health -= num
to
def subHealth(self, num):
self.__health -= num
return self.__health
Your question re: the "player" classes from def main() are not being transferred over to def battle() does not really make sense to me.
But, I see that in the first 2 lines of battle, you are replacing the formal parameters player1 and enemy with local variables, this seems like odd usage in your program.