Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I am making a text game for fun and can't find a pythonic way to update the player's stats.
I tried variables like h = 100 player = class(h,d,a,w) (health, defense, attack, weight) but then to have the players health change, I have to do this: h -= enemy attack (ea) player = class(h,d,a,w). Which is long and later on brakes when I add in defense and weapons. Variables work but are very long and unstable when I start to do a lot of math with them to make it more interesting. I also looked into class methods but couldn't find a way to pass player some stat as so that it would update.
import random as ran
class Client:
def __init__(self, health, defense, attack, weight):
self.health = health
self.defense = defense
self.attack = attack
self.weight = weight
class NPC:
def __init__(self, health, defense, attack):
self.health = health
self.defense = defense
self.attack = attack
#client inventory
inv = []
#a set of true or false statements to create a loop
alive = True
enemy_alive = False
while alive == True:
message = input()
player = Client(100, 0, 0, 0)
enemy = NPC(100, 0, 20)
# A way to brake the loop at any time
if message == "q":
alive = False
# Now we need a way to choice a wepon
if len(inv) == 0:
if message == "pick up bow":
print("The bow is now in your inventory.")
inv.append("Bow")
# This was my latest atempt to set player attack to the damage of the bow
player.attack += 25
combat = True
if len(inv) > 0 and combat == True:
if enemy_alive == False:
print("""A enemy is chargeing at you!
HP: 100""")
#We start the fight now that the player has a bow
enemy_alive = True
if "Bow" in inv:
#This is where I said to my self what if I could have attack directly effect health so that when the fight loop is broke the players stats stay with them and so that the math is more set and stone
if minotaur.defense == 0:
if message == "shoot":
hit = ran.randint(0,9)
if hit == 9:
print("Head Shot")
enemy.health = 0
if hit <= 4:
print("Miss")
player.health = player.health-enemy.attack
print("HP :"+str(player.health))
if hit >= 5:
print("HIT!")
enemy.health = enemy.health-player.attack
print("Enemy HP: "+str(enemy.health))
if enemy.defense > 0:
#I made this so I could see if it worked but like above nothing saves correctly
player.attack = player.attack/minotar.defense
if message == "shoot":
hit = ran.randint(0,9)
if hit == 9:
print("Head Shot")
enemy.health = 0
if hit <= 4:
print("Miss")
player.health = player.health-enemy.attack
print("HP :"+str(player.health))
if hit > 4:
print("HIT!")
enemy.health = enemy.health-player.attack
print("Enemy HP: "+str(enemy.health))
if enemy.health <= 0:
print("The Minotaur died a painful death.")
minotaur_alive = False
combat = False
if player.health <= 0:
print("You died!")
alive = False
When I execute the code the only thing that doesn't work is the stat updates. I have a debug layer on my real code that allows me to see if the current state of the game so I know for sure that it isn't updating.
You could maybe consider have every object in the game handle its own behavior: for instance, a Player object could have a Stats object that gets updated when some event happens.
When this works well with one type of Player, you can consider subclassing to modify the behavior; make it harder to kill, of with faster recovery, etc...
Maybe something like this:
class Player:
def __init__(self, name, stats):
self.name = name
self.stats = stats
def get_hit(self, hit_value):
self.stats.update_health(-hit_value)
def rest(self):
self.stats.update_health(10)
def __str__(self):
return f'Player {self.name}: {self.stats}'
class FastRecoveryPlayer(Player):
def rest(self):
self.stats.update_health(20)
class Stats:
"""maintains the Player's stats up to date
"""
def __init__(self, health=100, defense=100, attack=100):
self.health = health
self.defense = defense
self.attack = attack
def update_health(self, value):
self.health += value
self.health = max(0, self.health)
self.health = min(100, self.health)
def __str__(self):
return f'health: {self.health}, defense: {self.defense}, attack: {self.attack}'
hero = Player('Python King', Stats())
print(hero)
print('the Hero gets hit hard')
hero.get_hit(30)
print(hero)
print('the Hero rests a little bit')
hero.rest()
print(hero)
print()
hero2 = FastRecoveryPlayer('Python Emperor', Stats())
print(hero2)
print('the Hero2 gets hit hard')
hero2.get_hit(30)
print(hero2)
print('the Hero2 rests a little bit')
hero2.rest()
print(hero2)
output:
Player Python King: health: 100, defense: 100, attack: 100
the Hero gets hit hard
Player Python King: health: 70, defense: 100, attack: 100
the Hero rests a little bit
Player Python King: health: 80, defense: 100, attack: 100
Player Python Emperor: health: 100, defense: 100, attack: 100
the Hero2 gets hit hard
Player Python Emperor: health: 70, defense: 100, attack: 100
the Hero2 rests a little bit
Player Python Emperor: health: 90, defense: 100, attack: 100
This is generally related to OO design, I suggest that you have a base class of Character (although not essential) and have Client and NPC inheriting that base class, then have an attack and receive_attack method.
class Character():
def __init__(self, health, defense, damage, weight):
self.health = health
self.defense = defense
self.damage = damage
self.weight = weight
def attack(self,target):
target.receive_attack(self.damage)
def receive_attack(self,damage):
self.health -= damage
class Client(Character):
pass
class NPC(Character):
pass
class NPC_harder_to_take_down(Character):
def receive_attack(self,damage):
self.health -= (damage/2)
me = Client(100,100,100,100)
other = NPC(10,10,10,10)
print(me.health)
>>>100
other.attack(me)
print(me.health)
>>>90
Related
I stuck, namely i have a class in two other files.py from named. I would that self.health has been taken from monster = Monster.monster(). Currently the value is taken from main class Monster not inherited for example mob = Bear(). The problem is in player_skills.py where this file take a values from monster = Monster() in this file.
I would like, when I use FireBall skill substract a health from mob for example mob = Rat()
well_monster.py
class Monster:
def __init__(self, health=2500, mana=0, defence=0, attack_min=0, attack_max=0, magic=0, experience=0, coins=0):
self.health = health
self.mana = 0
self.defence = 0
self.attack_max = 0
self.attack_min = 0
self.magic = 0
self.experience = 0
self.coins = 0
def draw_monster(self):
from player_skills import testing_skill
a = testing_skill
monster = Monster.monster()
if monster == "Rat":
mob = Rat()
mob.fight()
if monster == "Wolf":
mob = Wolf()
mob.fight()
if monster == "Bear":
mob = Bear()
mob.fight()
if monster == "Tiger":
mob = Tiger()
mob.fight()
player_skills.py
from well_monster import Monster
monster = Monster()
class PlayerSkill():
def __init__(self, mana=0, min_attack=0, max_attack=0, health=0):
self.mana = mana
self.health = health
self.min_attack = min_attack
self.max_attack = max_attack
class FireBallSkill(PlayerSkill):
def __init__(self, mana=0, min_attack=0, max_attack=0, health=0):
super().__init__(mana, min_attack, max_attack, health)
self.mana = 50
self.health = health
self.min_attack = random.randint(
player.min_attack, player.min_attack*2)
self.max_attack = random.randint(
player.min_attack, player.min_attack*3)
#skill_name
def fire_Ball(self):
attack = [self.min_attack, self.max_attack]
if player.mana >= self.mana:
hit = random.choice(attack)
monster.health -= hit
player.mana -= self.mana
clearConsole()
print(100*'-')
print(
f"The {self.__class__.__name__} took the monster {hit} health points. LEFT: {monster.health} Health Points. MANA:{player.mana} ")
print(100*'-')
else:
print(
f"You cannot use this skill becouse your mana is to low. [{player.mana}/{self.mana}]")
i wanted to make the calculation stop on zero (self.health == 0), but it keeps subtract until below the zero. the subtraction is impossible to reach 0. How do i make the calculation, so the code doesn't reach the negative numbers?
class Hero:
def __init__(self, name, health, damage, armor, m_speed):
self.name = name
self.health = health
self.damage = damage
self.armor = armor
self.m_speed = m_speed
def attack(self, enemy):
print(self.name + " has attacked " + enemy.name)
enemy.attacked(self, self.damage)
def attacked(self, enemy, damage_enemy):
print(self.name + " has been attacked by " + enemy.name)
attack_received = (damage_enemy/(2.5*self.armor))
print(str(attack_received) + " is taken")
self.health -= attack_received
print(self.name + " health is now " + str(self.health))
def dead(self, enemy):
while self.health > 0:
h1.attack(h2)
print("\n")
h2.attack(h1)
print("\n")
if self.health == 0:
break
h1 = Hero("Hero1", 532, 129, 5, 310)
h2 = Hero("Hero2", 476, 176, 4, 296)
h1.dead(h2)
print("\n")
h2.dead(h1)
Define a method alive (maybe worth defining as a property if you are familiar with it):
def alive(self):
if self.health > 0:
return True
return False
You had h1 and h2 inside the dead method, you wanted to refer to self and enemy.
Change the dead method to something like this (dead is a bad name, use something else):
def combat(self, enemy):
while enemy.alive() and self.alive():
if enemy.alive():
enemy.attack(self)
if self.alive():
self.attack(enemy)
print("\n")
Also worth putting
if not self.alive():
print(self.name + " is dead.")
to the end of attacked method. There are more things to improve, but I think this should be enough to get you started.
I have the following code:
import options
import random
class Player():
def __init__(self):
self.name = None
self.gold = 100
self.maxhealth = 100
self.health = self.maxhealth
self.level = 1
self.exp = 0
self.levelUp = 50
self.gainedexp = self.levelUp - self.exp
def get_name(self):
self.name = input("Hey there, traveller! What's your name?\n~~>")
print("Since you are new around here, 100 gold doubloons have been given to you, {}!".format(self.name))
def gold_counter(self):
print("You currently have {} gold!".format(player.gold))
class Dragon():
def __init__(self):
self.name = "Dragon"
self.dropgold = random.randint(13,20)
self.minexp = int(15 * round(player.level * 1.5))
self.maxexp = int(30 * round(player.level * 1.5))
self.expgain = random.randint({}, {}.format(self.minexp, self.maxexp))
self.maxhealth = 80
self.health = self.maxhealth
def intro():
wrong_input = 0
nar_name = "Narrator"
print("{}: Uhhhm...".format(nar_name))
print("{}: Let me check my list...".format(nar_name))
print("{0}: Ah! Yes! {1}, that's right. I heard you were supposed to be arriving today.".format(nar_name, player.name))
I am also using two other modules, but I'm 99% sure they don't affect this. I get the following output:
Hey there, traveller! What's your name?
~~>Savage Potato
Since you are new around here, 100 gold doubloons have been given to you, Savage Potato!
Do you want to see your balance?
~~> Yes
You currently have 100 gold.
Narrator: Uhhhm...
Narrator: Let me check my list...
Narrator: Ah! Yes! None, that's right. I heard you were supposed to be arriving today.
In the last line, it is printing out the Narrator's name, but not the user's inputted name. I also looked at the python documents on their website, but I couldn't find a fix. Any ideas on how I could stop it from outputting None as the user's name?
EDIT #1: I have player = Player() written later in the module.
EDIT #2: This is all the code I used:
Module 1 (main.py)
import prints
import random
class Player():
def __init__(self):
self.name = None
self.gold = 100
self.maxhealth = 100
self.health = self.maxhealth
self.level = 1
self.exp = 0
self.levelUp = 50
self.gainedexp = self.levelUp - self.exp
def get_name(self):
self.name = input("Hey there, traveller! What's your name?\n~~>")
print("Since you are new around here, 100 gold doubloons have been given to you, {}!".format(self.name))
class Dragon():
def __init__(self):
self.name = "Dragon"
self.dropgold = random.randint(13,20)
self.minexp = int(15 * round(player.level * 1.5))
self.maxexp = int(30 * round(player.level * 1.5))
self.expgain = random.randint({}, {}.format(self.minexp, self.maxexp))
self.maxhealth = 80
self.health = self.maxhealth
#while player.exp >= player.levelUp:
#player.levelUp += 1
#player.exp = player.exp - player.levelUp
#player.levelUp = round(player.levelUp * 1.5)
#print("Congrats! You just levelled up to level {} by gaining {} experience!".format(player.level, player.gainedexp))
def start():
player.get_name()
prints.gold_counter()
prints.intro()
prints.encounter()
player = Player()
start()
Module 2 (prints.py)
import options
import random
class Player():
def __init__(self):
self.name = None
self.gold = 100
self.maxhealth = 100
self.health = self.maxhealth
self.level = 1
self.exp = 0
self.levelUp = 50
self.gainedexp = self.levelUp - self.exp
def get_name(self):
self.name = input("Hey there, traveller! What's your name?\n~~>")
print("Since you are new around here, 100 gold doubloons have been given to you, {}!".format(self.name))
def gold_counter(self):
print("You currently have {} gold!".format(player.gold))
class Dragon():
def __init__(self):
self.name = "Dragon"
self.dropgold = random.randint(13,20)
self.minexp = int(15 * round(player.level * 1.5))
self.maxexp = int(30 * round(player.level * 1.5))
self.expgain = random.randint({}, {}.format(self.minexp, self.maxexp))
self.maxhealth = 80
self.health = self.maxhealth
def intro():
wrong_input = 0
nar_name = "Narrator"
print("{}: Uhhhm...".format(nar_name))
print("{}: Let me check my list...".format(nar_name))
print("{0}: Ah! Yes! {1}, that's right. I heard you were supposed to be arriving today.".format(nar_name, player.name))
print("{}: Welcome to... THE DRAGON FIGHTER GAME!".format(nar_name))
print("{}: I know, it isn't the most imaginative name.".format(nar_name))
print("{}: Don't look at me like that, I tried my hardest!".format(nar_name))
print("{}: Anyhoo, let's carry on.".format(nar_name))
print("{}: For some stupid reason, the creator of this game didn't give me an actual name, so\nmy name is just \"Narrator\" or \"N\", but you can call me Larry.".format(nar_name))
while True:
option = input("Narrator: Actually, which name would you prefer to call me?\n").upper()
if option in options.nar_larry_opt:
nar_name = "Larry"
elif option in options.nar_narrator_opt:
nar_name = "Narrator"
while True:
ask = input("{}: Maybe \"N\" for short?".format(nar_name)).upper()
if ask in options.inp_yes_opt:
nar_name = "N"
elif ask in options.inp_no_opt:
break
else:
wrong_input += 1
if wrong_input == 1:
print("Please try again.")
elif wrong_input == 2:
print("Try to not put the same thing in next time.")
elif wrong_input == 3:
print("This isn't funny.")
elif wrong_input == 4:
print("Seriously.")
elif wrong_input == 5:
print("OKAY! THIS IS IT! GO BACK TO THE BEGINNING!")
intro()
continue
break
else:
print("Please try again.")
continue
break
print("{}: So, as I was saying, this game is basically just some dragon quest thingy.".format(nar_name))
print("{}: You'll probably get tips from me every now and again if I can be bothered.".format(nar_name))
print("{}: I'll get an test encounter ready.".format(nar_name))
def gold_counter():
while True:
option = input("Do you want to see your balance?\n~~> ").upper()
if option in options.inp_yes_opt:
print("You currently have {} gold.".format(player.gold))
elif option in options.inp_no_opt:
print("You can check your balance later in the game.")
else:
print("Please try again.")
continue
break
def encounter():
while True:
dragon_appear = random.randint(1,2)
if dragon_appear == 1:
print("What's that? Looks like a huge bir... \nA DRAGON! A MAJESTIC DRAGON JUST FLEW DOWN FROM THE SKY!")
else:
print("What's that? Looks like a huge bir... \n Yeah. Just a giganta-bird.")
while encounter().dragon_appear != 2:
print("So that's the message you'll get when a dragon appears.")
print("And you will be prompted whether you want to run or fight, like so:")
while True:
wrong_input = 0
ask = input("Run away like a coward, or fight the majestic beast?")
if ask in options.enc_run_opt:
escape = random.randint(1,2)
if escape == 1:
print("You managed to get away!")
else:
print("You didn't get away. Better luck next time!")
elif ask in options.enc_attack_opt:
pass
else:
wrong_input += 1
if wrong_input == 1:
print("Please try again.")
elif wrong_input == 2:
print("Try to not put the same thing in next time.")
elif wrong_input == 3:
print("This isn't funny.")
elif wrong_input == 4:
print("Seriously.")
continue
break
player = Player()
Module 3 (options.py)
inp_yes_opt = {"Y", "YE", "YES", "YEAH", "PLEASE", "YES PLEASE"}
inp_no_opt = {"N", "NO", "NOPE", "NAH"}
nar_larry_opt = {"LARRY", "LARR", "LAR", "LA", "L", "LARRY PLEASE"}
nar_narrator_opt = {"NARRATOR", "NARR", "N", "NAR", "NARRATE", "NOT LARRY"}
enc_run_opt = {"RUN", "RU", "R", "SCRAM", "RUN AWAY", "RUUUUN"}
enc_attack_opt = {"ATTACK", "ATTAK", "A", "FIGHT", "F", "ATTACK", ""}
If you want to print out the name of the player , you need to pass in the player object to the intro function as a parameter. That assumes intro is not capturing the player object and the player object is not global
At the moment , it seems there is no player object accessible to the scope of the function which is why it outputs None
I set damage to 3 at the top but when I type damage += 3 at the bottom it says damage is not referenced, why does this happen?
import random, time
inventory = ['dagger','torch']
hp = 50
maxhp = 50
damage = 3
ac = 4
gold = 10
in_combat = False
def choice():
choose = input(">> ")
if choose == "stats":
print("Health:",hp,", Damage:",damage,", Armour: ",ac,", Gold:",gold)
elif choose == "backpack":
print(inventory)
elif choose == "help":
print("Keywords:\nstats | view your stats\nbackpack | view your inventory\nhelp | view keywords to input\nattack | attack an enemy when in combat")
else:
print("Invalid Input")
class Enemy:
def __init__(self, name, attack, armour, health):
self.name = name
self.attack = attack
self.armour = armour
self.health = health
def attack_enemy(self):
time.sleep(1)
print("What action do you want to make?\nType 'help' for a list of actions\n")
answer = input(">> ")
if answer == "attack":
self.health = self.health - damage
print(self.name,"health is: ",self.health)
def main():
while hp > 0:
if 'dagger' in inventory:
damage += 3
print(damage)
choice()
main()
also if I change the code to dagger = 6 at the bottom it will print 6 but when I type stats it will say damage = 3
You can read global variables, but if you wish to assign (rebind) to them, you'll need to tell Python you mean to using the global keyword.
In this case there's no need to make those variable global at all.
You should move those attributes into a class. In this example I called it Player
import random, time
class Player:
def __init__(self):
self.inventory = ['dagger','torch']
self.hp = 50
self.maxhp = 50
self.damage = 3
self.ac = 4
self.gold = 10
self.in_combat = False
def choice(self):
choose = input(">> ")
if choose == "stats":
print("Health:", self.hp, ", Damage:", self.damage,
", Armour:", self.ac, ", Gold:", self.gold)
elif choose == "backpack":
print(inventory)
elif choose == "help":
print("Keywords:\nstats | view your stats\nbackpack | view your inventory\nhelp | view keywords to input\nattack | attack an enemy when in combat")
else:
print("Invalid Input")
class Enemy:
def __init__(self, name, attack, armour, health):
self.name = name
self.attack = attack
self.armour = armour
self.health = health
def attack_enemy(self):
time.sleep(1)
print("What action do you want to make?\nType 'help' for a list of actions\n")
answer = input(">> ")
if answer == "attack":
self.health = self.health - damage
print(self.name,"health is: ",self.health)
def main():
pl = Player()
while pl.hp > 0:
if 'dagger' in pl.inventory:
pl.damage += 3
print(pl.damage)
pl.choice()
main()
Aside: Since you are probably going to be printing lots of multiline blocks, look up the dedent function in textwrap. You could use it something like this:
from textwrap import dedent
def deprint(s):
print(dedent(s))
...
elif choose == "help":
deprint("""
Keywords:
stats | view your stats
backpack | view your inventory
help | view keywords to input
attack | attack an enemy when in combat""")
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.