Reputation: 15
I really never bothered to learn classes in Python because all the docs I find are a bit too technical for me. So, yet again I have sat down to try to conquer them. I would love to be able to use classes for the text based games that I make, so that is how I try every time.
My class code (its messy now because I have been trying everything I can think of) is
class enemy:
def __init__(self, name, weapon, hp, attack, defense, xp):
self.self = self
self.name = name
self.hp = hp
self.attack = attack
self.defense = defense
self.xp = xp
#self.attack_text1 = attack_text1
self.attack_text1 = name, " attacks you with ", weapon, "."
#self.attack_damage = attack_damage
self.attack_damage = random.randint(0,2) + attack
#self.total_damage = total_damage
self.total_damage = self.attack_damage - player.defense
if self.total_damage < 1:
self.total_damage = 0
#self.attack_text2 = attack_text2
self.attack_text2 = name, " deals ", self.total_damage, " to you."
@staticmethod #tried this from a solution found on stack overflow
def combat_roll(self):
self.roll = random.randrange(0,20) + attack
combat_roll(self)
I have a function called combat()
that pits the player against an instance of the enemy class.
The instance is called like in that function:
def combat():
goblin_weapon = weapon("goblin dagger", 1, 5)
goblin = enemy("ugly goblin", goblin_weapon, 3,2,1,150)
goblin_damage = goblin.attack - player.defense
print "a ", goblin.name, " attacks you with ", goblin_weapon, "."
print goblin.combat_roll
if goblin.roll > player.defense:
print goblin.name, "does ", goblin_damage, " damage."
else:
print goblin.name, "misses."
My goal is essentially somewhat of a d20 feel to the combat. attack bonus + d20 rolls vs armor class. I was hoping that the enemy class could have its own function that could handle its own dice rolls.
I've lost the original state of my code. I have checked google and searched here for solutions but none of them worked. I am sure it is because I haven't seen the solution in a way that works with my brain, because this can't be that complicated. Why can't I just call the function like I reference class variables?
enemy.combat_roll()
you know?
Anyway, thanks for the help!
Upvotes: 0
Views: 108
Reputation: 2545
As you say, your code is a little all over the place, and it isn't entirely complete. I've tried to rewrite and fill it out a bit in the spirit of what I think you were going for:
import random
#dice roll for dealing damage as a global function
def get_damage(dice_size, bonus_damage):
return random.randrange(dice_size) + bonus_damage
#class for a player
class Player:
#initialises the player's name, defense value and hp
def __init__(self, name, defense, hp):
self.name = name
self.defense = defense
self.hp = hp
#when something wants a string representation of a player (like format()
#might) it just uses the player's name
def __str__(self):
return self.name
#a method where a player takes damage from some enemy (if it quacks like an
#enemy..). This is where your attack_text2 has gone.
def take_damage(self, enemy, dmg):
self.hp -= dmg
print("{} deals {} damage to {}".format(enemy, dmg, self))
#class for a weapon
class Weapon:
#__init__ taking 4 arguments, like in your code, except it wasn't clear what
#the last two arguments were.
def __init__(self, name, foo, bar):
self.name = name
self.foo = foo
self.bar = bar
#as with Player
def __str__(self):
return self.name
#class for an enemy
class Enemy:
#this has changed: init only needs to *init*ialise the object not do any
#more, so all it does is stored relevant info as a field.
def __init__(self, name, weapon, hp, attack, defense, xp):
self.self = self
self.name = name
self.weapon = weapon
self.hp = hp
self.attack = attack
self.defense = defense
self.xp = xp
#as with Weapon
def __str__(self):
return self.name
#this is roughly where the second half of your init has gone. Engages in
#combat with a player, generating a random amount of damage, and doing all
#of the defense/attack malarkey. The damage is not stored as a field (using
#self.) as it is only needed for the duration of the combat
def combat(self, player):
print("{} attacks {} with {}.".format(self, player, self.weapon))
damage = get_damage(20, self.attack)
total_damage = damage - player.defense
if total_damage < 0:
total_damage = 0
player.take_damage(self, total_damage)
#function constructing a couple of objects and using them to do a 'fight'
#I've used some key word arguments with the goblin and the player. I'd advise
#you to keep doing the same, as it helps a lot with clarity.
def play():
dagger = Weapon("a goblin dagger", 1, 5)
goblin = Enemy("an ugly goblin", dagger, hp=3, attack=2, defense=1, xp=150)
aragorn = Player("Aragorn", defense=3, hp=100)
goblin.combat(aragorn)
print("{} now has {} hp".format(aragorn, aragorn.hp))
play()
I've included some comments trying to explain what's changed and what does what, and why, hopefully.
I hope it's stuck to your vision of the code. The main changes were to just refactor your bits of code around a bit. In your __init__
for the enemy, you originally had the code that's now ended up in Enemy.combat, for example. You also hadn't included a Weapon or Player class, although your code constructed a weapon and referred to player
, so I've added those in. Let me know if you'd like any more clarification.
Here is a sample of this code in action:
an ugly goblin attacks Aragorn with a goblin dagger.
an ugly goblin deals 10 damage to Aragorn
Aragorn now has 90 hp
Upvotes: 0
Reputation: 1498
You're declaring the method only within __init__
, instead of within enemy. To my understanding, it will only be available if you declare it within the enemy
class itself.
class enemy:
def __init__(self, name, weapon, hp, attack, defense, xp):
self.self = self
self.name = name
self.hp = hp
self.attack = attack
self.defense = defense
self.xp = xp
#self.attack_text1 = attack_text1
self.attack_text1 = name, " attacks you with ", weapon, "."
#self.attack_damage = attack_damage
self.attack_damage = random.randint(0,2) + attack
#self.total_damage = total_damage
self.total_damage = self.attack_damage - player.defense
if self.total_damage < 1:
self.total_damage = 0
#self.attack_text2 = attack_text2
self.attack_text2 = name, " deals ", self.total_damage, " to you."
combat_roll(self)
def combat_roll(self):
self.roll = random.randrange(0,20) + attack
Upvotes: 1