I'm new to coding, using sololearn and trying to make some changes to the code in a simple python game to do with injuring a goblin. It takes two words, the first is the verb and there are a few options of what you can do. Then there is the noun, and only class of character here is the goblin.
Two things I am stuck on:
I am wanting to print out the goblin's health and then the comment
(e.g. "Tis but a flesh wound") after each time he is hit.
I was also wanting to add a generic verb that allows for other types of injury; stroke, stab, and have one class that logs that as
a hit too.
Appreciate any feedback
#simple game
class GameObject:
class_name = ""
desc = ""
objects = {}
def __init__(self, name):
self.name = name
GameObject.objects[self.class_name] = self
def get_desc(self):
return self.class_name + "\n" + self.desc
class Goblin(GameObject):
def __init__(self, name):
self.class_name = "goblin"
self.health = 3
self._desc = "A foul creature"
super().__init__(name)
#property
def desc(self):
if self.health >= 3:
return self._desc
elif self.health == 2:
health_line = "Tis but a flesh wound"
elif self.health == 1:
health_line = "He's not looking good"
elif self.health <= 0:
health_line = "It is dead"
return self._desc + "\n" + health_line
#desc.setter
def desc(self, value):
self._desc = value
def hit(noun):
if noun in GameObject.objects:
thing = GameObject.objects[noun]
if type(thing) == Goblin:
thing.health = thing.health -1
print(thing.health)
if thing.health <= 0:
msg = "You killed the Goblin"
else:
msg = "You hit the {}".format(thing.class_name)
else:
msg = "There is no {} here".format(noun)
return msg
goblin = Goblin("Gobbly")
def examine(noun):
if noun in GameObject.objects:
return GameObject.objects[noun].get_desc()
else:
return "What do you mean, there is no {} here".format(noun)
def get_input():
command = input(": ").split()
verb_word = command[0]
if verb_word in verb_dict:
verb = verb_dict[verb_word]
else:
print("Unrecognised verb {}, not in our incredibly limited dictionary".format(verb_word))
return
if len(command) >= 2:
noun_word = command[1]
print(verb(noun_word))
else:
print(verb("Nothing. Nada"))
def say(noun):
return "You said {}".format(noun)
verb_dict = {"say": say,
"examine": examine,
"hit": hit,
# "stab": stab,
# "stroke": stroke
}
while True:
get_input()
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 tried to make a "typing game" and at first, it worked out pretty nice. But when I translated my code to English (variable names, class names, function names etc.) it gave me the warning "Object int is not callable". How can I solve this?
Here's my code:
import time
import random
import sys
class Player():
def __init__(self, name, health = 5, energy = 10):
self.name = name
self.health = health
self.energy = energy
self.hit = 0
def inf(self):
print("Health: ", self.health, "\nEnergy: ", self.energy, "\nName: ", self.name)
def attack(self, opponent):
print("Attacking")
time.sleep(.300)
for i in range(3):
print(".", end=" ", flush=True)
x = self.randomAttack()
if x == 0:
print("Nobody attacks.")
elif x == 1:
print("{} hits {} !".format(name, opponentName))
self.hit(opponent)
opponent.health -= 1
elif x == 2:
print("{} hits {}!".format(opponentName, name))
opponent.hit(self)
self.health -= 1
def randomAttack(self):
return random.randint(0, 2)
def hit(self, hit):
hit.hitVariable += 1
hit.energy -= 1
if (hit.hitVariable % 5) == 0:
hit.health -= 1
if hit.health < 1:
hit.energy = 0
print('{} won the game!'.format(self.name))
self.exit()
#classmethod
def exit(cls):
sys.exit()
def run(self):
print("Running...")
time.sleep(.300)
print("Opponent catch you!")
#######################################################
print("Welcome!\n----------")
name = input("What's your name?\n>>>")
opponentName = input("What's your opponent's name?\n>>>")
you = Player(name)
opponent = Player(opponentName)
print("Commands: \nAttack: a\nRun: r\nInformation: i\nExit: e")
while True:
x = input(">>>")
if x == "a":
you.attack(opponent)
elif x == "r":
you.run()
elif x == "i":
you.inf()
elif x == "e":
Player.exit()
break
else:
print("Command not found!")
continue
It gives me the error at line 24 (self.hit(opponent)).
Your hit function is the problem. You have member and a function with the same name. Change one of them.
Also rename the hit argument of the hit(). You call it via self.hit(opponent) so I would rename it to def hit(self, opponent):.
def __init__(self, name, health = 5, energy = 10):
self.hit = 0
def hit(self, hit):
hit.hitVariable += 1
hit.energy -= 1
if (hit.hitVariable % 5) == 0:
hit.health -= 1
if hit.health < 1:
hit.energy = 0
print('{} won the game!'.format(self.name))
self.exit()
While coding my game, I've ran into problems when running it. For example, the zombie attack doesn't come out correctly, when using the store the gold value and health value do not update. When running the battle part, the first time the zombie has less health, then more health, and more damage. I don't know what I've messed up on. Any help/tips?
import time
import sys
import random
cls = ("\n"*100)
class Mage:
def __init__(self):
self.maxhp = 50
self.attack = 3.33
self.name = "Mage"
class Warrior:
def __init__(self):
self.maxhp = 70
self.attack = 2.5
self.name = "Warrior"
class Thief:
def __init__(self):
self.maxhp = 35
self.attack = 5
self.name = "Thief"
class Zombie:
def __init__(self):
self.maxhp = 10
self.attack = 1
self.name = "Zombie"
def heal(character_health):
if character_health < character_health:
character_health += 5
print("Healed. Health is now " + character_health + " +5.")
time.sleep(2)
else:
print("No healing available.")
time.sleep(2)
def battle(character_health, character_attack, monster_health, monster_attack, gold):
while True:
character_health_max = character_health
monster_name = "Zombie"
choice1 = input("\nPress 1 to Attack: ")
if choice1 == "1":
monster_health -= character_attack
print("\n" + str(monster_name) + "'s health is now " + str(monster_health))
time.sleep(1)
character_health -= monster_attack
print("\nThe hero's health is now " + str(character_health))
time.sleep(1)
if character_health <= 0:
print("\nThe hero is dead.")
sys.exit("\nThe End")
if monster_health <= 0:
print("\nThe monster is dead.")
time.sleep(2)
print("Your gold has increased by: 5")
gold += 5
monster_health = 10
character_health = character_health_max
time.sleep(2)
menu_list(character_health, character_attack, monster_health, monster_attack, gold)
def store(gold, character_health):
print("\nWelcome to my shop of wonders! My name is Hanz, what can I aid you with today? We have...\nPotions: [1.] EEK")
buy = input("\nWhat will it be? ")
if gold < 5:
print("Sorry, you don't have any gold!")
time.sleep(2)
if buy == "1" and gold >= 5:
print("\nYou now own the Potion EEK! Health increased by 5!")
character_health += 5
gold -= 5
time.sleep(2)
def menu_list(character_health, character_attack, monster_health, monster_attack, gold):
while True:
print(cls)
menu = input("---> Fight [1.] \n---> Heal [2.] \n---> Store [3.] \n---> Quit [4.] \n---> Gold: " + str(gold) + " \n---> ")
if menu == "4":
sys.exit()
if menu == "2":
heal(character_health)
if menu == "1":
battle(character_health, character_attack, monster_attack, monster_health, gold)
if menu == "3":
store(gold, character_attack)
if menu == "Gold":
print("\nNot valid hackerman.")
time.sleep(1)
class Main:
print(cls)
name = input("What is your name: ")
character = input("\nChoose your class: \n----------------- \nMage [1.] \nWarrior [2.] \nThief [3.] \n---> ")
if character == "1":
character_health = Mage().maxhp
print("\nHealth " + str(character_health))
character_attack = Mage().attack
print("\nAttack " + str(character_attack))
character_name = Mage().name
print("\nClass " + str(character_name))
time.sleep(3)
monster_health = Zombie().maxhp
monster_attack = Zombie().attack
gold = 0
menu_list(character_health, character_attack, monster_health, monster_attack, gold)
if character == "2":
character_health = Warrior().maxhp
print("\nHealth " + str(character_health))
character_attack = Warrior().attack
print("\nAttack " + str(character_attack))
character_name = Warrior().name
print("\nClass " + str(character_name))
time.sleep(3)
monster_health = Zombie().maxhp
monster_attack = Zombie().attack
gold = 0
menu_list(character_health, character_attack, monster_health, monster_attack, gold)
if character == "3":
character_health = Thief().maxhp
print("\nHealth " + str(character_health))
character_attack = Thief().attack
print("\nAttack " + str(character_attack))
character_name = Thief().name
print("\nClass " + str(character_name))
time.sleep(3)
monster_health = Zombie().maxhp
monster_attack = Zombie().attack
gold = 0
menu_list(character_health, character_attack, monster_health, monster_attack, gold)
if __name__ == '__main__':
Main()
I think this is a good time to go over what happens when you pass variables to functions in Python.
Firstly, everything in Python is an object! Primitives too (numbers are wrapped as an object in Python). Every class of objects inherit from the object class in Python.
Now, what happens when you pass a primitive to a function and change the value?
To illustrate:
def foo(a):
a = 5
b = 1
foo(b)
print(b) # b is still 1! Some objects in Python are immutable including integers, strings, and booleans.
Now I suspect your gold and health values aren't changing because you're passing in immutable objects which cannot be changed!
How to resolve?
You want to pass in a mutable object! Instead of passing an integer object (which is immutable) for a character's health, pass in the character object (which is mutable). You can set the new health of that character object.
To illustrate:
class Warrior:
def __init__(self):
self.maxhp = 70
self.attack = 2.5
self.name = "Warrior"
self.currenthp = 55 # arbitrary number but you may want to have something like this
def heal(warrior):
warrior.currenthp += 5
# somewhere in your Main function
warrior1 = Warrior()
heal(warrior1) # currenthp of this warrior should be 60!
It's important that you implement OOP correctly when you are creating your game. Similarly try debugging your other issues paying attention to how you implement OOP.
I'm relatively new to python and I've been trying to practice OOP in python with this example:
def get_input():
command = input(':').split()
verb_word = command[0]
if verb_word in verb_dict:
verb = verb_dict[verb_word]
else:
print('Unkown verb "{}"'.format(verb_word))
return
if len(command) >= 2:
noun_word = command[1]
print(verb(noun_word))
else :
print(verb('nothing'))
def say(noun):
return "You said '{}'".format(noun)
class GameObject:
class_name = ""
_desc = ""
health_line = ""
objects = {}
def __init__(self,name):
self.name = name
GameObject.objects[self.class_name] = self
def desc(self):
return self.class_name + "\n" + self._desc + "\n" + self.health_line
class Goblin(GameObject):
def __init__(self,name):
self.class_name = "goblin"
self.health = 3
self._desc = 'A foul creature'
super().__init__(name)
#property
def desc(self):
if self.health >= 3:
return self._desc
elif self.health == 2:
health_line = 'It is badly bruised'
elif self.health == 1:
health_line = 'It is barely standing'
elif self.health <= 0:
health_line = 'It is dead'
return self._desc +'\n'+ self.health_line
#desc.setter
def desce(self,value):
self.__desc = value
goblin = Goblin("Gobbly")
def hit(noun):
if noun in GameObject.objects:
thing = GameObject.objects[noun]
if type(thing) == Goblin:
thing.health = thing.health - 1
if thing.health <= 0:
msg = "You killed it"
else:
msg = "You hit the {}".format(thing.class_name)
else:
msg = "There is no {} here".format(noun)
return msg
def examine(noun):
if noun in GameObject.objects:
return GameObject.objects[noun].desc()
else:
return "There is no '{}' here".format(noun)
verb_dict ={"say":say,"examine":examine,"hit":hit}
while True :
get_input()
It seems that this line:
return GameObject.objects[noun].des()
returns the Type Error. I'm not sure why this is, and I've been at this for a while. Any help is much appreciated.
If you want to call the desc function, you will have to do it as such:
GameObject.desc(parameter)
where the parameter can be object[noun]. This is because the desc method belongs to the GameObject class.