Python/PyGame Creating Random Monsters with Random Attributes from Class/Method - python

I am attempting to create a text based RPG. I want to use a Class Monsters to create a random monster of a particular type. However I cannot seem to access the random variables associated with the method in the class. Here is a trimmed down version of the code:
import random
class Monsters():
def wolfEnemy(self):
self.hp = random.randint(10, 20)
self.attk = random.randint(1, 3)
self.gold = random.randint(2, 5)
self.xp = 100
monsters = Monsters()
print(monsters.wolfEnemy)
things = monsters.wolfEnemy.hp()
print(things)
I'm not sure how to access variables from within a instantiated method. print(monsters.wolfEnemy) just produces None and things = monsters.wolfEnemy.hp() errors with builtins.AttributeError: 'function' object has no attribute 'hp'. Is there a way to call up that wolfEnemy and the attributes outside the Class/Method.

Define a WolfEnemy class that inherits from the Monster class. In the Monster class you can define attributes and methods that every subclass should have, and override them to create the specific subclasses.
import random
class Monster:
def __init__(self):
self.hp = random.randint(10, 20)
self.attk = random.randint(1, 3)
self.gold = random.randint(2, 5)
self.xp = 100
class WolfEnemy(Monster):
def __init__(self):
# Call the __init__ method of the parent class, that means the
# wolf instance will get the attributes that we've defined there.
super().__init__()
# To override specific attributes, assign new values here.
self.hp = random.randint(20, 30)
wolf = WolfEnemy()
print(wolf.hp)

you can get the result you want like this:
import random
class Monsters():
def wolfEnemy(self):
self.hp = random.randint(10, 20)
self.attk = random.randint(1, 3)
self.gold = random.randint(2, 5)
self.xp = 100
monsters = Monsters()
# wolfEnemy() for the function call not wolfEnemy
monsters.wolfEnemy()
# monsters.hp get the attr not monsters.wolfEnemy.hp()
print(monsters.hp)

Related

How do you take an input and call an instance of a class based on the input?

I am currently developing a short text-based adventure so I can learn how to use Classes within Python. As part of this, I am trying to create a combat system where the player could choose an NPC to attack.
The aim is that the player can enter the name of the NPC and the weapon they want to use. A method in the target's class will then be called, to lose health based on the damage of the weapon.
My current code is below:
class npc:
def __init__(self, name, alliance):
self.name = name
self.alliance = alliance
def loseHealth(self, health, dmg):
self.dmg = dmg
self.health = self.health - dmg
def usePotion(self, health, pType):
if pType == "great":
self.health = min(self.health + 50,self.maxHealth)
elif pType == "normal":
self.health = min(self.health + 25,self.maxHealth)
else:
pass
def attack(self, target, weaponDmg):
if target in npcList:
target.loseHealth(self.health, weaponDmg)
class human(npc):
maxHealth = 100
health = 100
def __init__(self, name, alliance):
super().__init__(name, alliance)
class orc(npc):
maxHealth = 200
health = 200
def __init(self, name, alliance):
super().__init__(name, alliance)
weaponDmg = {'sword':10,'axe':20}
alice = human("alice","good")
bob = orc("bob","evil")
npcList = [alice, bob]
target = input("Enter Target:")
weapon = input("Enter weapon:")
for x in range(3):
alice.attack(target,weaponDmg[weapon]) #using alice temporarily until I have a person class sorted
print(target.health)
The simple and pythonic answer is to use a dict of NPCs keyed by name, the same way you’re already doing it with weapons:
npcs = {‘alice’: alice, ‘bob’: bob}
target = input("Enter Target:")
weapon = input("Enter weapon:")
for x in range(3):
alice.attack(npcs[target], weaponDmg[weapon])
print(target.health)
And if you want to look up the attacking NPC by user-supplied name as well as the attackee, you can do the same thing there:
npcs[attacker].attack(npcs[target], weaponDmg[weapon])
If you really want to do this inside the attack method you can keep passing in target as a name (string) and do this:
if target in npcs:
npcs[target].loseHealth(self.health, weaponDmg)
... but that probably isn’t a very good design. It means you’re sharing a global variable, and your NPC objects all “know” about that global dict and all the NPCs in it, which doesn’t seem like part of their responsibility.
You can make this a little less repetitive by creating the dict with a comprehension:
npcs = {npc.name: npc for npc in (alice, bob)}
... or by just creating them directly in the dict instead of in variables that you’re probably never going to otherwise use:
npcs = {}
npcs[‘alice’] = human("alice","good")
npcs[‘bob’] = orc("bob","evil")
You can call a method on an instance by using getattr, here is an example:
>>> class Test:
... def my_method(self, arg1, arg2):
... print(arg1, arg2)
...
>>> t = Test()
>>> getattr(t, 'my_method')('foo', 'bar')
foo bar

Changeable function call from dict

I'm relatively new with a decent amount of experience and I'm trying to make a text based adventure, I'm making a fighting system and wish to have enemy's that have different abilities. Instead of recreating the fight for a different enemy every time, I'm trying to use interchangeable dictionaries for each enemy. My goal is to create a function call that varies depending on what enemy is in the fight without getting into objects. I have an example below and would like to know if there is a way to do something similar.
wolf = {'ability': 'bite'}
bear = {'ability': 'claw'}
enemy = {}
def claw():
print('stuff')
def bite():
print('different stuff')
def use_ability():
enemy = wolf
enemy['ability']()
use_ability()
In python functions are first class objects. You can just use them as values in your dictionary.
wolf = {'ability': bite}
bear = {'ability': claw}
However be careful as there is no forward referencing in python. So make sure you define your functions before you assign them to a dictionary.
def claw():
print('stuff')
def bite():
print('different stuff')
wolf = {'ability': bite}
bear = {'ability': claw}
def use_ability():
enemy = wolf
enemy['ability']()
use_ability()
You can do it:
def claw():
print('stuff')
def bite():
print('different stuff')
wolf = {'ability': bite}
bear = {'ability': claw}
def use_ability(enemy):
enemy['ability']()
use_ability(wolf)
# different stuff
It really doesn't mean you should do it this way, though.
Use Object-Oriented programming. If you only want to use dicts and functions, you probably should write Javascript instead.
I can't help myself but to make a little program explaining how it should be done in an Object Orientated Language:
You should look up some guides how OOP-Languages work, because when making a game it will be really helpfull if you do it that way
http://www.python-course.eu/object_oriented_programming.php
# This is the SUPERCLASS it holds functions and variables
# that all classes related to this object use
class Enemy(object):
# Here we initialise our Class with varibales I've given an example of how to do that
def __init__(self, HP, MAXHP, ability):
self.HP = HP
self.MAXHP = MAXHP
self.ability = ability
# This function will be used by both Bear and Wolf!
def use_ability(self):
print(self.ability)
# This is our Wolf Object or Class
class Wolf(Enemy):
# Here we init the class inheriting from (Enemy)
def __init__(self, ability, HP, MAXHP):
super().__init__(HP, MAXHP, ability)
# Here we call the superfunction of this Object.
def use_ability(self):
super().use_ability()
# Same as Wolf
class Bear(Enemy):
def __init__(self, ability, HP, MAXHP):
super().__init__(HP, MAXHP, ability)
def use_ability(self):
super().use_ability()
# How to init Classes
wolf_abilities = 'bite'
w = Wolf(wolf_abilities, 10, 10)
bear_abilities = 'claw'
b = Bear(bear_abilities, 10, 10)
# How to use methods from Classes
b.use_ability() # This will print 'bite'
w.use_ability() # This will print 'claw'

Variables dont update to new values between classes

I am making a basic RPG style game. I have made different classes for the various parts of the code, one for each of the main items involved (hero, door, monsters etc.)
For both the hero and door, i assign them random locations, shown below in the code, but for the door I run a while loop which makes sure that the door is a certain distance from the hero (using pythagorus).
However the while loop in the door class won't work as it always uses a value of 0 for both heroC and heroR (row and column of the hero). I am relatively new to using classes, but it doesnt seem to make sense as in HeroLocation I assign a random integer to these variables, and HeroLocation is called before DoorLocation.
Any help would be greatly appreciated!!
class Hero(Character):
def __init__(self):
super(Hero, self).__init__(10, 10, 1, 1, 0, 1)
self.herolocations = list(range(1,6)) + list(range(10,14))
self.heroC = 0
self.heroR = 0
def HeroLocation(self):
#place hero
self.heroC = random.choice(self.herolocations)
self.heroR = random.choice(self.herolocations)
class Door:
def __init__(self):
self.hero = Hero()
self.doorC = 0
self.doorR = 0
def DoorLocation(self):
while ((self.hero.heroC-self.doorC)**2+(self.hero.heroR-self.doorR)**2) <= 128:
self.doorC = random.randint(1, 13)
self.doorR = random.randint(1, 13)
class game:
def __init__(self, parent):
self.hero = Hero()
self.door = Door()
def MakeMap(self):
self.hero.HeroLocation()
self.herol = self.Main_game.create_image(15+30*self.hero.heroC,15+30*self.hero.heroR, image = self.heroimage)
self.door.DoorLocation()
self.doorl = self.Main_game.create_image(15+30*self.door.doorC,15+30*self.door.doorR, image = self.exitdoor)
NB there is a lot more code, but i have only posted what i felt was the relevant stuff, if you need more to crack the puzzle message me!
You are not calling the good Hero instance in Door.DoorLocation.
Btw I really advice you to change class & methods name following Pep 8.
In Door.__init__, first line:
self.hero = Hero()
Here, you are instantiating a new Hero's instance. But, in game.MakeMap you are calling self.hero.HeroLocation().
This self.hero instance is not the same, because it was instantiated in game.__init__ and not in Door.__init__.
I didn't try, but check what behaviour gives this update:
class game:
def __init__(self, parent):
self.door = Door()
self.hero = self.door.hero
With this you now are calling the instance defined in Door.__init__, so when doing self.hero.HeroLocation() in game and (self.hero.heroC-self.doorC [...] in Door you are pointing the same instance.
Last thing, this solution may works, but is surely not what you really wants, I think a door should not store a hero, a hero should not store a door too, but here is more complex question about patterns.

Issue with passing attributes between classes in python

Ive made these classes below and I'm trying to have a tile in the game present a text based on an attribute in another class. I keep getting this error.
File "C:\Users\xxxxxxxx\PycharmProjects\Game.idea\Girls.py", line 20, in not_interested
return (self.interest < 10)
AttributeError: 'GirlTile' object has no attribute 'interest'
class Girls():
def __init__(self):
self.girlnames = ["Lucy", "Cindy", "April", "Allison", "Heather", "Andrea", "Brittany", "Jessica", "Lane", "Lauren", "Sabrina","Chelsea","Amber"]
self.name = random.choice(self.girlnames)
self.height = random.randrange(60, 72)
self.age = random.randrange(18, 25)
self.number = self.new_number()
self.interest = 0
def not_interested(self):
return (self.interest < 10)
from Girls import Girls
class GirlTile(MapTile):
def __init__(self,x,y):
self.enemy = Girls()
super().__init__(x, y)
def intro_text(self):
self.stance = Girls.not_interested(self)
if self.stance:
print("Hey whats up")
It looks like not_interested is an instance-level method, but you are trying to call it with a class (Girls). And the call is sort of "working" because you are passing the GirlTile instance in the call -- hence the error that the GirlTile has no interest attribute (because it does not).
Maybe you intended this instead?
def intro_text(self):
# Use an actual Girl instance to call not_interested().
self.stance = self.enemy.not_interested()
...

Referencing self variables outside of original class

class player(object):
def __init__(self):
self.health = 100
self.stats = {'STR': 0,
'DEF':0}
class create_character(object):
def choose_class(self):
inp = input("Please choose a class!: ").lower()
s = ("Knight, Archer, or Mage")
print(s)
if inp == 'knight':
self.stats['STR'] = 15
self.stats['DEF'] = 15
print(self.stats)
The problem I'm facing currently, is that when I reference self.stats under create_character, it tells me that specific class doesn't have a 'self.stats'. If I try player.self.stats or player.stats, it tells me the same thing, that the class doesn't have those attributes. How can I reference a dictionary or a variable from another class, and change its properties. Also, when I print self.health, or self.stats, or self.name or whatever properties the player class hold, it gives me a bunch of unneeded information. Is there a way to exclude the extra information?
I believe that this will do the job that you are looking for:
class player(object):
def __init__(self):
self.health = 100
self.stats = {'STR': 0,
'DEF':0}
def choose_class():
inp = input("Please choose a class (Knight, Archer, or Mage): ").lower()
if inp == 'knight':
# create the player object
p = player()
# changes the values for the attributes in the player object
p.stats['STR'] = 15
p.stats['DEF'] = 15
print(p.stats)
# calls the function to choose the class
choose_class()
This is not really a good coding style though, so I would recommend following an OOP Python tutorial.

Categories

Resources