Adding a "Cooldown" function to an attack in a turn based RPG - python

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.

Related

Why does my movement system randomly break?

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]

Counting player kills in text rpg python

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.

TypeErr: Object "int" is not callable

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()

Loops incorrectly then crashes

I've got a piece of code I'm working on for a school project and the basic idea is that there's a battle between two characters where the user can input 2 attributes to each character: Strength and Skill. Now there are also modifiers for skill and strength which is the difference of the player's skill and strength attributes, divided by 5 and then rounded down respectively. Then each player has a dice roll, depending on who got the higher roll, that player gets the skill and strength modifiers added to their given attributes whilst the one that lost gets the modifiers deducted from their score. This then repeats until the strength attribute of one of them reaches 0 where that player then dies and the game ends.
In my code, the dice rolling function runs twice, and then crashes for an unknown reason I cannot identify.
import random
import time
import math
import sys
strength_mod = 0
skill_mod = 0
def delay_print(s):
for c in s:
sys.stdout.write( '%s' % c )
sys.stdout.flush()
time.sleep(0.05)
def str_mod(charone_str,chartwo_str):
if charone_str > chartwo_str:
top = charone_str
bottom = chartwo_str
calc = top - bottom
calc = calc / 5
calc = math.floor(calc)
return calc
elif chartwo_str > charone_str:
top = chartwo_str
bottom = charone_str
calc = top - bottom
calc = calc / 5
calc = math.floor(calc)
return calc
elif charone_str == chartwo_str:
top = charone_str
bottom = chartwo_str
calc = top - bottom
calc = calc / 5
calc = math.floor(calc)
return calc
def skl_mod(charone_skl, chartwo_skl):
if charone_skl > chartwo_skl:
top = charone_skl
bottom = chartwo_skl;
calc = top - bottom
calc = calc / 5
calc = math.floor(calc)
return calc
elif chartwo_skl > charone_skl:
top = chartwo_skl
bottom = charone_skl
calc = top - bottom
calc = calc / 5
calc = math.floor(calc)
return calc
elif charone_skl == chartwo_skl:
top = charone_skl
bottom = chartwo_skl
calc = top - bottom
calc = calc / 5
calc = math.floor(calc)
return calc
def mods():
global strength_mod
global skill_mod
strength_mod = str_mod(charone_strength, chartwo_strength)
skill_mod = skl_mod(charone_skill, chartwo_skill)
print "\nFor this battle, the strength modifier is:",strength_mod
time.sleep(0.20)
print "For this battle, the skill modifier is: ",skill_mod
time.sleep(0.20)
diceroll(charone, chartwo)
print "\n"+str(charone)+"'s","dice roll is:",player1
time.sleep(1)
print "\n"+str(chartwo)+"'s","dice roll is:",player2
def diceroll(charone, chartwo):
print "\n"+str(charone)+" will roll the 6 sided dice first!"
time.sleep(0.5)
global player1
player1 = random.randint(1,6)
delay_print("\nRolling dice!")
global player2
player2 = random.randint(1,6)
time.sleep(0.5)
print "\nNow",chartwo,"will roll the 6 sided dice!"
time.sleep(0.5)
delay_print("\nRolling dice!")
def battle(charone_str, chartwo_str, charone_skl, chartwo_skl, str_mod, skl_mod):
global charone_strength
global charone_skill
global chartwo_strength
global chartwo_skill
if player1 == player2:
print "\nThis round is a draw! No damage done"
elif player1 > player2:
charone_strength = charone_str + str_mod
charone_skill = charone_skl + skl_mod
chartwo_strength = charwo_skl - str_mod
chartwo_skill = chartwo_skl - skl_mod
print "\n"+charone+" won this round"
print "\n"+"Character 1:",charone
print "Strength:",charone_strength
print "Skill:",charone_skill
time.sleep(1)
print "\nCharacter 2:",chartwo
print "Strength:",chartwo_strength
print "Skill:",chartwo_skill
elif player2 > player1:
chartwo_strength = chartwo_str + str_mod
chartwo_skill = chartwo_skl + skl_mod
charone_strength = charone_str - str_mod
charone_skill = charone_skl - skl_mod
print "\n"+chartwo+" won this round"
print "\nCharacter 2:",chartwo
print "Strength:",chartwo_strength
print "Skill:",chartwo_skilll
time.sleep(1)
print "\n"+"Character 1:",charone
print "Strength:",charone_strength
print "Skill:",charone_skill
if charone_skill >= 0:
charone_skill = 0
elif chartwo_skill >= 0:
chartwo_skill = 0
if charone_strength <= 0:
print charone,"has died!",chartwo,"wins!"
elif chartwo_strength <= 0:
print chartwo,"has died!",charone,"wins!"
charone = raw_input("Enter the name of character one: ")
chartwo = raw_input("Enter the name of character two: ")
time.sleep(1.5)
print "\n",charone,"encounters",chartwo
delay_print("\nBattle Initiated!")
charone_strength = int(raw_input("\nEnter the strength score for "+str(charone)+" (between 50 and 100): "))
while charone_strength > 100 or charone_strength < 50:
print "That number is not between 50-100"
charone_strength = int(raw_input("\nEnter the strength score for "+str(charone)+" (between 50 and 100): "))
else:
pass
charone_skill = int(raw_input("Enter the skill score for "+str(charone)+" (between 50 and 100): "))
while charone_skill > 100 or charone_skill < 50:
print "That number is not between 50-100"
charone_skill = int(raw_input("Enter the skill score for "+str(charone)+" (between 50 and 100): "))
else:
pass
time.sleep(1.0)
chartwo_strength = int(raw_input("\nEnter the strength score for "+str(chartwo)+" (between 50 and 100): "))
while chartwo_strength > 100 or chartwo_strength < 50:
print "That number is not between 50-100"
chartwo_strength = int(raw_input("\n Enter the strength score for "+str(chartwo)+" (between 50 and 100): "))
else:
pass
chartwo_skill = int(raw_input("Enter the skill score for "+str(chartwo)+" (between 50 and 100): "))
while chartwo_skill > 100 or chartwo_skill < 50:
print "That number is not between 50-100"
chartwo_skill = int(raw_input("Enter the skill score for "+str(chartwo)+" (between 50 and 100): "))
else:
pass
time.sleep(2)
print "\nCharacter 1:",charone
print "Strength:",charone_strength
print "Skill:",charone_skill
time.sleep(1)
print "\nCharacter 2:",chartwo
print "Strength:",chartwo_strength
print "Skill:",chartwo_skill
time.sleep(1)
while charone_strength != 0 or chartwo_strength != 0:
ent = raw_input("Press Enter to roll! ")
mods()
diceroll(charone,chartwo)
battle(charone_strength, chartwo_strength, charone_skill, chartwo_skill, str_mod, skl_mod)
else:
play = raw_input("\nWould you like to play again?")
if play in ["yes","y","Yes","Y"]:
execfile("gcse.py")
else:
print "Goodbye"
This code is an excellent example of how not to program:
heavy use of global variables
multiple variables with very similar names (ie charone_strength, charone_str)
reuse of names in different contexts (in global scope, str_mod is a function, but in function battle it is supposed to be an integer
Your immediate problem: in line 182, you call
battle(charone_strength, chartwo_strength, charone_skill, chartwo_skill, str_mod, skl_mod)
which should be
battle(charone_strength, chartwo_strength, charone_skill, chartwo_skill, strength_mod, skill_mod)
but is confused because in the function strength_mod is referred to as str_mod.
Here is a greatly cleaned-up version. (Further suggestions for improvement are welcome).
from __future__ import division, print_function
from random import randint
import sys
from time import sleep
# Python 2/3 compatibility shim
if sys.hexversion < 0x3000000:
# Python 2.x
inp = raw_input
rng = xrange
else:
# Python 3.x
inp = input
rng = range
PRINT_DELAY = 0.02
PAUSE_DELAY = 0.2
TF_VALUES = {
'y': True, 'yes': True, 't': True, '': True,
'n': False, 'no': False, 'f': False
}
def get_int(prompt="Enter an integer: ", lo=None, hi=None):
while True:
try:
i = int(inp(prompt))
if (lo is None or lo <= i) and (hi is None or i <= hi):
return i
except ValueError:
pass
def get_tf(prompt="Yes or no? ", tf_values=TF_VALUES):
while True:
s = inp(prompt).strip().lower()
tf = tf_values.get(s, None)
if tf is not None:
return tf
def pause(delay=PAUSE_DELAY):
sleep(delay)
def roll(die_sides=6):
return randint(1, die_sides)
def slow_print(s, delay=PRINT_DELAY):
for ch in s:
print(ch, end='', flush=True)
sleep(delay)
print('') # end of line
def wait_for_enter(prompt):
inp(prompt)
class Fighter:
#classmethod
def get_fighter(cls, prompt):
print(prompt)
name = inp ("Name: ")
health = get_int("Health: (50-100) ", 50, 100)
skill = get_int("Skill: (50-100) ", 50, 100)
return cls(name, health, skill)
def __init__(self, name, health, skill):
self.name = name
self.health = health
self.skill = skill
def is_alive(self):
return self.health > 0
def health_mod(self, other_fighter):
delta = abs(self.health - other_fighter.health)
return int(delta / 5)
def skill_mod(self, other_fighter):
delta = abs(self.skill - other_fighter.skill)
return int(delta / 5)
def attack(self, other_fighter):
wait_for_enter("Hit Enter to fight!")
# figure out mod values
health_mod = self.health_mod(other_fighter)
skill_mod = self.skill_mod (other_fighter)
self_roll = roll()
other_roll = roll()
slow_print(
"Health mod: {} Skill mod: {} {} rolls {} {} rolls {}"
.format(
health_mod, skill_mod,
self.name, self_roll,
other_fighter.name, other_roll
)
)
# figure out who won this round
if self_roll == other_roll:
print("Draw! No damage done.")
else:
winner, loser = (self, other_fighter) if self_roll > other_roll else (other_fighter, self)
print("{} hits {}!".format(winner.name, loser.name))
winner.health += health_mod
winner.skill += skill_mod
loser.health -= health_mod
loser.skill -= skill_mod
# show results
print('')
print(self)
print(other_fighter)
print('')
def __str__(self):
return "{}: health {}, skill {}".format(self.name, max(self.health, 0), max(self.skill, 0))
def fight():
f1 = Fighter.get_fighter("\nFirst fighter:")
pause()
f2 = Fighter.get_fighter("\nSecond fighter:")
pause()
slow_print("\n{} encounters {}\nBattle Initiated!".format(f1.name, f2.name))
while f1.is_alive() and f2.is_alive():
f1.attack(f2)
winner, loser = (f1, f2) if f1.is_alive() else (f2, f1)
print("{} has died; {} wins!".format(loser.name, winner.name))
def main():
while True:
fight()
if not get_tf("Would you like to play again? (Y/n)"):
print("Goodbye!")
break
if __name__=="__main__":
main()

Passing Objects Between functions?

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.

Categories

Resources