PyGame: Returning to Items

23 April 2012

Where am I? Here!

Buffing up items

At the moment, Items are rather bland: they're just a title and a description. We want them to actually mean something, though, so it's time to give them a bit more shape.

class Treasure(object):
  ''' Things that can be picked up. 
  '''
  def __init__(self, title="Nada", description="", type="trash", armor=0, buff=0, attack=0):
    self.title = title
    self.description = description
    self.type = type
    self.armor = armor
    self.buff = buff
    self.attack = attack

Okay, not the most exciting upgrade ever, since we're only making armor and swords, but we're going with baby steps here. Though I've added three attributes, we'll only really be using two: armor and attack. Now that the item can have a bit more oomph, let's look at the Player again.

Getting Player ready

Right now, Dudeguy is pretty basic. I need to get him ready to deal with not only carrying things, but having those things matter.

class Player(object):
  """The player class. Contains level, HP, stats, and deals with combat."""
  def __init__(self):
    self.level = 1
    self.stats = {
      'strength': 1,
      'attack': 5,
      'defense': 5
    }
    self.current_hp = 10
    self.name = "Dudeguy McAwesomesauce"
    self.equipped = {}

    for treasure in EQUIPMENT_TYPES:
      self.equipped[treasure] = None

I decided to make stats a dictionary, since I might want to give some classes a stat that others didn't, and this seems like the easier way of doing this. Also, it's easier to iterate for my interface, once I get to that.

I've also added a dictionary for equipped items. He starts off with the standard equipment slots:

EQUIPMENT_TYPES = ('hat', 'shirt', 'pants', 'shoes', 'back', 'neck', 'hands', 'weapon')

but no equipment, of course. Naked adventuring, FTW!

Managing items

Now that I was buffing up items, I needed a better way to manage them. Looks like my game will need an admin tool. Enter admin.py:

import sys, pickle
import sys, pickle

sys.path.append("roguey/classes")

from items import Treasure
from constants import *

class Admin(object):
  def __init__(self):
    f = open("roguey/resources/items.pk")
    try:
      self.treasures = pickle.load(f)
    except:
      print "No treasures!"
      self.treasures = []
    f.close()
    self.main()

  def new_treasure(self):
    for treasure in TREASURE_TYPES:
      print "%s. %s" % \
              (TREASURE_TYPES.index(treasure)+1, treasure)
    choice = raw_input("Pick a type [1-9]: ")
    type = TREASURE_TYPES[int(choice)-1]
    title = raw_input("Give it a title: ")
    desc = raw_input("Give it a description: ")
    attack = 0
    armor = 0
    if type == 'weapon':
      attack = raw_input("How much damage will it add? [1-999]: ")
      attack = int(attack)
    else:
      armor = raw_input("How much armor will it add? [1-999]: ")
      armor = int(armor)
    tr = Treasure(title=title, \
               description=desc, \
               type=type, \
               armor=armor, \
               attack=attack)
    self.treasures.append(tr)

  def list_treasures(self):
    for treasure in self.treasures:
      print treasure.title

  def save(self):
    f = open("roguey/resources/items.pk", "w")
    pickle.dump(self.treasures, f)
    f.close()

  def main(self):
    while 1:
      print "1. Make a new treasure"
      print "2. List current treasures"
      print "0. Quit"
      c = raw_input("Make a choice [1-2, 0]: ")
      if c[0] == "1": self.new_treasure()
      if c[0] == "2": self.list_treasures()
      if c[0] == "0": 
        self.save()
        return

if __name__ == "__main__":
  a = Admin()

It's simple, but it made managing my items so much easier. Now, rather than maintaining a text file (or *gasp* a spreadsheet) of items, I could deal with them through this script. My items could be saved as a Pickle and checked into the repo.

Wait, a Pickle?

Pickles!

Rogue guy has found some pickles in a treasure chest. He doesn't look happy.

Now that we have all this data, we need to save it somehow. In this instance, I've chosen to use Pickles.

Pickles get a bad rap, mostly due to the fact that they're not very secure. It's almost a knee-jerk reaction at this point. Go ahead, test it: walk into any Python discussion, and suggest that they use Pickles. Watch them foam at the mouth.

Pickles are inherantly insecure. You should never accept a Pickle from a source you can't trust (this is still true if talking about lower-case pickles). In this case, we know who made the Pickle, so we're good. If you decide to fork my code and turn my roguelike into something where people would be swapping these piles of items... well, you'll have a bit more work cut out for you.

Giving the player items

Now that the items are worth having, and we have a selection of them, let's have the player pick them up.

For now, I only have one of each type of item, so when the player comes to an item and doesn't have anything in that slot, it's automatically equipped. If something is already there, into the backpack it goes, because as we know, all players are cleptomaniacs.

def add_to_inventory(self, item, player):
  ''' Adds an item to the inventory
  '''
  if item.type == "trash":
    return
  if player.equipped[item.type]:
    try:
      self.inventory[item] += 1
    except:
      self.inventory[item] = 1
  else:
    player.equip_item(item)

Now that the player can equip items, we need to update our status screen area to reflect that:

def draw_equipment(self, equipment=START_EQUIPMENT):
  ''' Renders the equipment. Expect it to be exchanged for something
    awesomer
  ''' 
  self.screen.blit(self.equipment_screen, (1008, 200))
  for i in range(equipment.keys().__len__()):
    line = self.small_font.render(LONG_STRING, True, BLACK, BLACK)
    self.screen.blit(line, (1008, ((i+1)*15)+200))
  pygame.display.flip()
  i = 1
  for slot in EQUIPMENT_TYPES:
    try:
      line_text = slot + ":  " + equipment[slot].title
    except:
      line_text = slot + ":  "
    line = self.small_font.render(line_text, True, WHITE, BLACK)
    self.screen.blit(line, (1008, i*15+200))
    i += 1
  pygame.display.flip()

Side note: I got a ten-minute lecture from my son about how 'awesomer' isn't a word. What are they teaching kids these days?!

Next time!

Combat needs to be updated, now that we have all these great items!

Share

Related tags: pygame python

Comments

1 Mike Driscoll says...

I noticed that you're overriding the "type" keyword in your Treasure class. Was that on purpose? Just curious. I realize most of the time you probably won't need type.

Posted at 1:40 p.m. on April 23, 2012

2 Katie Cunningham says...

Actually, it was an accident. I hate overriding things, even if I'm sure I'll never need them, so you'll probably see this updated in a later commit.

Posted at 1:58 p.m. on April 23, 2012

3 Ian Roberts says...

I always accidentally override type. I've taken to using "kind" these days.

Posted at 7:17 p.m. on April 23, 2012

4 Ian Witham says...

I'm not sure why you think using an admin interface is going to be easier than editing a text file. (maybe you use emacs </jk>) In fact you could still use an admin interface with a text file, but by choosing to Pickle your data you have become reliant on it.

I think Pickle could be a good choice for a "Save Game" function, but your game data such as pre-configured in-game items should really be saved in a plain text file IMHO. XML or JSON could be used for this, but even a Python module would be an acceptable place to define your game items.

Also the Pickle format isn't exactly human readable for anyone (including you) browsing your repo. If you want to view the objects that have been created so far you are reliant on the admin interface once again.

Posted at 7:37 p.m. on April 23, 2012

5 Ian Witham says...

Oh, and I'm not foaming at the mouth or knee-jerking over Pickles per se, I just don't think they are the right tool for this particular problem.

Posted at 7:44 p.m. on April 23, 2012

6 Katie says...

@Ian

I've had ahem uneven results from hand-edited files, mostly due to developing on several machines at once. Pickling allows me to move from machine to machine with ease.

Once I add all my items, and I'm fairly certain they're not being changed again, I'll export them to something easier to deal with by hand. While I'm doing massive item creation, I'd rather have an admin module.

Posted at 7:58 p.m. on April 23, 2012

7 Ian Witham says...

As I said, there's no reason you can't keep the admin module and simply dump to XML or JSON instead of a Pickle. Just a suggestion anyway.

Posted at 8:23 p.m. on April 23, 2012

8 Temia says...

I dunno, I just use git to allow me to move from machine to machine with ease. ;P

Posted at 12:37 p.m. on April 25, 2012

9 Recher says...

Wops. My previous comment did not pass. Or did it ?

Let's give it a retry :

you don't need to write the ugly backslashes in these lines of code

tr = Treasure(title=title, \
    description=desc, \
    type=type, \
    armor=armor, \
    attack=attack)

newlines are accepted betwen parameters of a function.

Posted at 2:13 p.m. on April 30, 2012

Comments are closed.

Comments have been closed for this post.