I am in the midst of making an RPG game in Python.
I have made different classes, but I am having problems with one of my enemy types. It is a spider, and to spice things up, I tried to make the spider do dot (damage over time). It is not guaranteed poison damage, but when it does poison you, it stacks.
This is my parent class (enemy):
class Enemy():
def __init__(self, number_of, name):
self.number_of = int(number_of)
self.name = name
self.hp = 20 * self.number_of
self.dmg = 2 * self.number_of
def attack(self):
print(f"you now have {round(class1.hp)} health" + "\n")
def appearing(self):
if self.number_of > 1:
print (f"{self.number_of} {self.name}s have appeared")
else:
print(f"A {self.name} has appeared")
print (f"They have {self.hp} health")
Note: the class1 is the player
This is my spider class:
class Spider(Enemy):
posion_dmg = 0
def __init__(self, number_of, name):
Enemy.__init__(self, number_of, name)
self.posion_dmg = 0
def attack(self,player):
if self.posion_dmg > 0:
dot = 2 ** (self.poison_dmg + 1)
player.hp -= dot
print ("you are posioned" + "\n")
print (f"it deals {round(dot)} damage")
dmg = random.uniform(1.2 * self.dmg, 1.8* self.dmg)
player.hp -= dmg
print ("The spider(s) bite(s) you. ")
print(f"It deals {round(dmg)} damage")
if randint(1,4) == 1:
self.poison_dmg += 1
if self.number_of == 1:
print ("The spider poisons you")
else:
print ("The spiders poison you")
return Enemy.attack(self)
def appearing(self):
print ("*Spiders have a chance to hit you with poison that deals damage over time - this stack exponentially*")
return Enemy.appearing(self)
When I go in combat with the spider, and the randint is 1, it says that "Spider" has no attribute "poison_dmg", but I made it an attribute, right?
im kind of a newbie to python but i've successfully gone through the "Make Your Own Python Text Adventure" guide and i got a basic grip of how this works, although i do not completely understand how you're making the dot work, i think your problem is:
class Spider(Enemy):
posion_dmg = 0
def __init__(self, number_of, name):
Enemy.__init__(self, number_of, name)
self.posion_dmg = 0 <-----------------------HERE
in combination with this:
def attack(self,player):
if self.posion_dmg > 0:
dot = 2 ** (self.poison_dmg + 1)
player.hp -= dot
print ("you are posioned" + "\n")
print (f"it deals {round(dot)} damage")
dmg = random.uniform(1.2 * self.dmg, 1.8* self.dmg)
player.hp -= dmg
print ("The spider(s) bite(s) you. ")
print(f"It deals {round(dmg)} damage")
if randint(1,4) == 1: <----------------------------HERE
self.poison_dmg += 1
if self.number_of == 1:
print ("The spider poisons you")
else:
print ("The spiders poison you")
The if statement is indented within a def that begins with another if poison_dmg > 0, and is not because you've already defined it to be 0 in the init.
i would invert the order of the if statements within the attack function, so you first generate a poison_dmg value, and then you evaluate wether or not that value is greater than 0.
Hope it works!
PD1: This is my firs stackoverflow comment ever, sorry if i missed some answering standards.
PD2: English is not my mother tongue, please let me know if i didn't make myself clear at any point.
Related
I tried to make a simple combat system but it isn't working how I want it to. Eventually when I get near zero im stuck at number 4 usually. And what I want it to do is that if d_damage equals 0 to print out that the person won. Im mostly struggling on the damage for the opponent. I havent worked on the users health. But if someone could help I would dearly appreciate it.
Here is my code:
import random
import os
health = [ '100' ]
d_health = [ '100' ]
damage = random.randint(0, 7)
def clear():
os.system("cls")
def health_damage():
sum = int(d_health[0]) - damage
if sum > 0:
d_health.remove(d_health[0])
d_health.append(str(sum))
begin_game()
if int(d_health[0]) <= 0:
clear()
print( "You defeated the dragon!" )
def begin_game():
clear()
print( "Dragon Health: " + str(d_health[0]) + "")
print()
print( "Your Health: " + str(health[0]) )
x = input( "What do you wish to do?" )
if x.lower() == "1":
health_damage()
begin_game()
def before_game():
print( "Welcome to The Beginning: Fight to Survive" )
x = input( "Are you sure you want to fight?" )
if x.lower() == "yes":
clear()
begin_game()
before_game()
you only lower the health if health is above 0, so it's going to repeat forever for no reason
def health_damage():
sum = int(d_health[0]) - damage
if sum > 0:
d_health.remove(d_health[0])
d_health.append(str(sum))
begin_game()
if int(d_health[0]) <= 0:
clear()
print( "You defeated the dragon!" )
just remove the sum part and directly remove the if statment. it doesnt help with anything.
you should instead do this:
d_health = 100
damage = random.int(1, 7)
def health_damage():
d_health -= damage
# the -= is a better looking version of d_health = d_health - damage
if int(d_health) <= 0:
clear()
print( "You defeated the dragon!" )
while True:
if input(""):
quit()
else:
clear()
begin_game()
(btw a bit unrelated, but please learn object oriented programming. it sounds hard at first, but it makes everything way easier to work with)
I am creating my first python program and have been struggling with a "TypeError: 'bool' object is not callable" error. I have only been studying for a few weeks so any assistance would be great! Also, if there are any tips on how to reduce some of the code that'd be great! Thanks!
import random
class Spacecraft:
def __init__(self, type, health):
self.type = type
self.health = health
self.ship_destroyed = False
def ship_destroyed(self):
self.ship_destroyed = True
if self.health != 0:
self.health = 0
print("Your spacecraft has been destroyed!")
def ship_destroyed_def(self):
self.ship_destroyed = True
if self.health != 0:
self.health = 0
print("Your enemy spacecraft has been destroyed! YOU WON!!")
def lose_health(self, amount):
self.health -= amount
if self.health <= 0:
self.ship_destroyed()
else:
print("Your spacecraft now has {health} hit points remaining.".format(health=self.health))
def lose_health_def(self, amount):
self.health -= amount
if self.health <= 0:
self.health = 0
self.ship_destroyed()
else:
print("The enemy spacecraft now has {health} hit points remaining".format(health=self.health))
print()
def attack(self, enemy_ship):
while True:
damage_fighter = random.randrange(2, 14)
damage_defender = random.randrange(4, 10)
if self.type == "fighter":
print(
'Your {type} spacecraft attacked the enemy ship for {damage} damage and the enemy {enemy_ship} spacecraft attacked your ship for {damage2} damage.'.format(
type=self.type,
damage=damage_fighter,
enemy_ship=enemy_ship.type,
damage2=damage_defender))
self.lose_health(damage_defender)
enemy_ship.lose_health_def(damage_fighter)
elif self.type == "defender":
print(
'Your {type} spacecraft attacked the enemy ship for {damage} damage and the enemy {enemy_ship} spacecraft attacked your ship for {damage2} damage.'.format(
type=self.type,
damage=damage_defender,
enemy_ship=enemy_ship.type,
damage2=damage_fighter))
self.lose_health(damage_fighter)
enemy_ship.lose_health_def(damage_defender)
class Player:
def __init__(self, type):
self.type = type
self.current_type = 0
def attack_enemy_ship(self, enemy_ship):
my_ship = self.type[self.current_type]
their_ship = enemy_ship.type[enemy_ship.current_type]
my_ship.attack(their_ship)
a = Spacecraft("fighter", 40)
b = Spacecraft("defender", 50)
print()
player_name = input('Welcome to Space Warriors! Please enter your name and hit enter. ')
player_style = input('''
Welcome ''' + player_name + '''! Space Warriors is a game that allows you to chose between two classes of spacecraft. If you select a
fighter spacecraft when you will fight again a defender spacecraft. If you choose a defender space craft
then you will fight a fighter spacecraft. Please select "Fighter" or "Defender" and press enter. ''').lower()
player_selected = []
computer_selected = []
if player_style == 'fighter':
player_selected.append(a)
computer_selected.append(b)
else:
player_selected.append(b)
computer_selected.append(a)
live_player = Player(player_selected)
computer_player = Player(computer_selected)
print()
print("Let's get ready to fight! Both ships are launched!")
print()
live_player.attack_enemy_ship(computer_player)
Once one of the two ships reaches zero hit points I am attempting to call ship_destroyed or ship_destroyed_def, to end the game; however the program stops once one of the ships hits "0". This is when I receive the error.
def ship_destroyed(self):
self.ship_destroyed = True
You're trying to make a function and an attribute that are both named ship_destroyed. You can't do that. Pick a different name for one of them.
from random import randint
from time import sleep
pminatk = 0
pmaxatk = 4
playerhp = 15
def atk(minatk, maxatk):
return randint(minatk, maxatk)
def playerAtk(monsterhp):
dmg = atk(pminatk, pmaxatk)
monsterhp -= dmg
print ("Du gjorde %i skade. Monsteret har nå %i liv igjen" % (dmg, monsterhp))
sleep(1)
return monsterhp
def monsterAtk(mminatk, mmaxatk):
global playerhp
dmg = atk(mminatk, mmaxatk)
playerhp -= dmg
print ("Monsteret gjorde %i skade. Du har nå %i liv igjen" % (dmg, playerhp))
sleep(1)
def fight(monsterhp, mminatk, mmaxatk):
global playerhp
while monsterhp > 0 and playerhp > 0:
playerAtk(monsterhp)
if monsterhp > 0:
monsterAtk(mminatk, mmaxatk)
if playerhp > 0:
print ("Gratulerer! Du beseiret monsteret!")
else:
print ("Du døde!")
fight(5, 1, 2)
fight(6, 0, 2)
This is supposed to be a simple battle system in a text based adventure. Now my problem is that monsterhp always goes back to its original valye after playerAtk is executed. If I choose to have monsterhp as a global variable it will remain 0 after fight() is finished, leaving the hp of all OTHER monster equal to zero as well. Now i could have more than one variable to assign different hp-values to different monster, but is there any way I can do this using parameters to the fight() function?
Your immediate problem is in your while loop when you call playerAtk(), you return monsterhp from it, but do not actually use it in that loop and that is why you see monster's health points to go back up to the original value. Line 28 needs to read:
monsterhp = playerAtk(monsterhp)
instead of:
playerAtk(monsterhp)
As it was suggested in a comment though, It's worth looking into defining your custom classes. I've thrown together following example based on your code to whet your appetite:
from random import randint
from time import sleep
PLAYERNAME = "Player1"
PLAYERHP = 15
PMINATK = 0
PMAXATK = 4
class CharacterDied(Exception):
def __init__(self, msg):
self.msg = msg
class Character:
def __init__(self, name, initial_hp, minatk, maxatk):
self.name = name
self.hp = initial_hp
self.minatk = minatk
self.maxatk = maxatk
def take_damage(self, damage_hp):
self.hp -= damage_hp
msg = "{} takes {:d}HP damage and has {:d} left."
print(msg.format(self.name, damage_hp, self.hp))
if self.hp < 0:
msg = "{} died."
raise CharacterDied(msg.format(self.name))
def attack(self, other):
dmg = randint(self.minatk, self.maxatk)
sleep(1)
other.take_damage(dmg)
def fight(char1, char2):
try:
while True:
char1.attack(char2)
char2.attack(char1)
except CharacterDied as death_exception:
print(death_exception.msg)
if __name__ == "__main__":
player = Character(PLAYERNAME, PLAYERHP, PMINATK, PMAXATK)
fight(player, Character("Monster1", 5, 1, 2))
if player.hp > 0:
fight(player, Character("Monster2", 6, 0, 2))
There are many ways to do this. For simplicity, I've written just one generic Character class we can use for player and monsters, but even if we started customizing them with subclasses, for instance the fight is now a bit more generic and we can also have a monster attack the player as it just became function of two fighting characters.
To your original question though the benefit sought after here is that attributes are kept and persistent with their instance objects which is generally much easier to follow than to try to deal with and track global variables.
I am quite new to python, having only toyed with it for a few days now. I am trying to cobble together a program to show off a battle system I had in mind. My issue is that I keep getting "None" produced when I try to print
import os
class Player():
def __init__(self, name, hp, maxhp, strength, intel, charm, level):
self.name = name
self.hp = hp
self.maxhp = maxhp
self.strength = 10
self.intel = intel
self.charm = charm
self.level = level
def attack(self, Enemy):
Enemy.hp -= self.strength
class Steve():
def __init__(self, name, hp, maxhp, strength, intel, charm, level):
self.name = name
self.hp = hp
self.maxhp = maxhp
self.strength = strength
self.intel = intel
self.charm = charm
self.level = level
class Barry():
def __init__(self, name, hp, maxhp, strength, intel, charm, level):
self.name = name
self.hp = hp
self.maxhp = maxhp
self.strength = strength
self.intel = intel
self.charm = charm
self.level = level
def Start():
Player.hp = 100
Player.maxhp = 200
Player.strength = 30
Player.intel = 10
Player.charm = 43
Player.level = 23
nameSelection()
def nameSelection():
os.system('cls')
Player.name = input("Please enter your name\n==>")
print("==>")
gameStart()
def gameStart():
os.system('cls')
global Enemy
print ("Player Name:",Player.name)
print ("Who would you like to fight?")
print ("1.)Steve")
print ("2.)Barry")
print ("3.)Change your name")
option = input("==>")
if option == "1":
Enemy = Steve("Steve", 100, 200, 10, 20, 30, 50)
fight()
elif option == "2":
Enemy = Barry("Barry", 100, 200, 10, 20, 30, 50)
fight()
elif option == "3":
nameSelection()
def attack():
Enemy.hp -= Player.strength
def fight():
os.system('cls')
while Enemy.hp > 0:
os.system('cls')
print(CharacterStats())
print ("1.) Attack")
print ("2.) Run")
option = input("==>")
if option == "1":
attack()
print (Enemy.hp)
print ("You did it! You have defeated", Enemy.name,"!")
gameStart()
def CharacterStats():
print ("You now face", Enemy.name)
print ("His current health is", Enemy.hp,"/",Enemy.maxhp)
print ("His strength is", Enemy.strength)
print ("His intelligence is", Enemy.intel)
print ("His charm is", Enemy.charm)
print ("He is level", Enemy.level)
Start()
When I get to a fight encoutner with one of the two options, I get
You now face Steve
His current health is 100 / 200
His strength is 10
His intelligence is 20
His charm is 30
He is level 50
None
1.) Attack
2.) Run
==>
I have read that return could fix it, but I can't seem to get return to give me the desired results I was looking for, both how it looks different went printed in to the player, and it only returns one of these lines of stats. I may be getting some of my terms wrong, I hope I am being clear on what my issue is.
You are getting None because you are printing the function, where you should just call the function, your function doesn't return anything and that is why you are getting None.
Change this line:
print(CharacterStats())
to:
CharacterStats()
In Python, when you call a function, that function does its work and then returns a value. For instance,
def add(x, y):
print("Working on it...")
answer = x + y
print("Got it!")
return answer
When called, this function will do four things. It will print "Working on it..." to the terminal. It will create a variable called answer, and assign it to the sum of x and y. It will print "Got it". And then, it will silently return that answer.
What does return mean? It means two things: it tells Python to return control to the place where the function was called, and it also says: wherever I was called, replace me with a certain value.
So if I write
print(add(2,3))
the function will be called and do its thinking, printing "working" and "got it" to the terminal. It will return 5, so now Python comes back to the print call and replaces add(2, 3) with 5:
print(5)
which will print 5. Similarly, I could do:
x = add(4,6) + add(5,2)
This would print:
Working on it...
Got it!
Working on it...
Got it!
And then x would be set to 10 + 7, or 17.
In your code, since you don't explicitly return anything from your function, Python uses the default, implicit return of None when it reaches the last line of your function. That means that
print(MyFunc())
actually is understood as, do the function, then
print(None)
Hope that clears things up!
As a side note, it will be more suitable if you use inheritance (use the Player class as base class eg: class Steve (Player):pass ) in your game : https://docs.python.org/2/tutorial/classes.html
I'm not really sure how to word this, but I'll try my best. I've created a function for a zombie, and another one for attacks. But I don't know how to pass on the parameters of the zombie function into the attack function. Also if there is a more technical way to word this please let me know. Here is my test code for it, I'm sure this community will be able to figure out what I mean. The end goal is to create a function where I can plug in a monster name and have it's assigned parameters (health, defense, etc..) be run in through the combat function. ie def combat(monster_name): Any and all advice is much appreciated. Thank you!
#Functions
def zombie():
global zombie_hp
zombie_hp = 10
print "Zombie encounter"
print "Current Health:", zombie_hp
def attack(monster):
if monster > 0:
while monster > 0:
user_action = raw_input("Do you attack the zombie? [y]: ")
if user_action == "y":
monster_hp = monster_hp - 1
print "Health remaining: ", monster_hp
def user_action():
global user_action
user_action = raw_input("Do you attack the zombie? [y]: ")
# Zombie Encounter (attack_testing)
attack(zombie())
if zombie_hp == 0:
print "Zombie Defeated"
I suggest you use a class:
class Zombie:
def __init__(self):
self.defense = 10
self.hp = 100
def hit(self, hp):
self.hp-=hp
def upgrade(self, level):
self.defense+=level
This will remember the hp and defense for every zombie that you create
>>> Max = Zombie()
>>> Max.hit(17)
>>> Max.upgrade(2)
>>> Max.hp
83
>>> Max.defense
12
>>>