Archive for June, 2009|Monthly archive page

commands (a roguelike in Python #9)

I’ve been taking a stab at how to structure commands and effects of commands…Up to now I’ve done something simple where the command processing is all done in a function contained in the instance of Command.

So the other day I started trying something like this:

class Command(object):
    def __init__(self):   
        self.rulebook = {
                        'move' : ('cell has monster', 'cell is unwalkable')}
                        
        self.rules = {
                        'cell has monster' : 'game.world.cell_has_monster(thing.x+dx, thing.y+dy)',
                        'cell is unwalkable' : 'game.world.cell_is_unwalkable(thing.x+dx, thing.y+dy)'}

        
    def north(self, thing):
            self.move(thing, 0, -1)          
          
          
    def south(self, thing):
            self.move(thing, 0, 1)          
       
        
    def east(self, thing):
            self.move(thing, 1, 0)          
       
        
    def west(self, thing):
            self.move(thing, -1, 0)  


    def move(self, thing, dx, dy):
        if True in [eval(self.rules[rule]) for rule in self.rulebook['move']]:
            pass
        else:
            thing.x = thing.x + dx
            thing.y = thing.y + dy

The structure of commands/rules/rulebook is a little hazy at the moment, but the idea is that you write a command in the rulebook with a structure of keys. Each key in the rules points to a function, and some functions return True if it’s a simple check — if any are true, the command fails. However some functions could affect the game world, schedule events, create new objects, and so on as well.

This is basically the same as making these checks in the function of the command — calling the functions there. It’s a little easier for me to read the rulebook though to see what rules each command uses, and the list comprehension in the function of the command takes care of adding new rules.

I don’t really want to get too crazy with processing commands (such as calling before and after routines, or checking a bunch of generic ‘can I/am I’ functions for each command), though it remains to be seen if the idea above will be easy enough to work with as I start adding commands and effects.

Advertisements

better coloring (a roguelike in Python #8)

I’ve started to experiment more with cell coloring. Up to now I’ve defined cell colors explicitly — if a cell is of the ground type and visible for example, it was a ‘visible ground’ color, and similarly for a ‘dark wall’ and so on. However I felt this wasn’t a very good way to do colors, especially when you start mixing light and dark and other affects, like mist, smoke, fire, and so on. I don’t want to get too crazy here but I do like the look of colors and it’s one of libtcod’s strengths.

So after a few experiments I have a first pass at what I want to do. It looks like this:

scalelight

If you look at the samples.py file included with the libtcod Python wrapper you’ll see a similar thing going on in the field-of-view sample with the torchlight (though that is more sophisticated, using noise — I hope to do that soon).

My colors dictionary now looks like this:

        self.cell_colors = {
                            'wall' : libtcod.Color(67, 65, 52),      
                            'ground' : libtcod.Color(145, 140, 140),
                            'dark': libtcod.Color(20, 20, 24),
                            'lit': libtcod.Color(255, 255, 33),
                            'visible': libtcod.Color(254, 254, 233)} 

And what I do now when figuring out the color of a cell is find the distance of that cell to the field-of-view origin (for example, the player) and use that distance as a scalar for the affect color. I should note that affects are colors like ‘dark’, ‘lit’, and so on. Also you don’t really need to find the distance, just the distance squared to get the appropriate scalar — this will save a bit on computation, or so I’ve heard.

In other words, the ‘visible’ affect is most intense at its point of origin, and least at the maximum distance of the field-of-view radius. I think it does look better than using hard edges on affect boundaries.

This scalar is linear at the moment, so it creates a somewhat odd but not displeasing affect to my eyes. However I think I do want to randomize it a little with noise as done with the torchlight for samples.py.

saving part one-and-a-half (a roguelike in Python…#7)

I knew there was a reason I liked Python. In the last post I was going back and forth some on the readability of pickled files, so later tonight I looked a little closer at the PyYAML module. All I needed to do was change the pickle function calls to yaml function calls (as in, change pickle.dump to yaml.dump — that’s it!) and the files now look like this:

!!python/object:__main__.Actor
brain: &id001 !!python/object:__main__.Brain
  fov_map: 9773936
  handlers:
  - !!python/object:__main__.Fov
    brain: *id001
    fov_map: 9773936
    fov_radius: 8
    light_map: 9773904
  light_map: 9773904
  speed: normal
name: player
speed: normal
x: 32
y: 16

Of course I don’t know very much about the differences of pickle and yaml at this point (I knew I liked yaml from earlier exposure to it in some mud codebases) but this file format is at least looking much more to my taste!

saving part one (a roguelike in Python #7)

I’ve been having a go with saving and loading in the Python demo. It may seem a little silly to do this before I have a game or for that matter, any content at all, but I’m following a bit of advice I read on rgrd and I’m glad I’m doing it…especially with loading the save state back in, it makes you think of how you structure the data to be saved in the program in the first place.

Luckily this first try is rather simple given Python’s pickle module. To save on exit I put this in the main loop:

            if player.input.key.vk == libtcod.KEY_ESCAPE:
                file = open('centaur.sav', 'w')
                file2 = open('player.sav', 'w')
                pickle.dump(game.world.level_state, file)
                pickle.dump(player.thing, file2)
                file.close()
                file2.close()
                break

This saves the level data and the player object to two separate files, then closes the game — though game.world.level_state doesn’t actually change at all currently, the x,y position of the player object does change, and saving it allows you to start the demo, move the player, then restart the demo with the player in the new spot.

For a quick test I just did this in place of the creation of the player thing object;

        if os.path.isfile('player.sav'):
            print 'player file found'
            file = open('player.sav', 'r')
            self.thing = pickle.load(file)
            game.world.things.append(self.thing)
            file.close()
        else:
            self.thing = Actor('player', 26, 16, Fov)

Note that I needed to add the player object back to the game.world.things list — otherwise, the player object brain’s update method will never be called (nor its field-of-view handler), as you aren’t adding it to the list by instancing the Actor class! Not doing this at first was a strange sight, as I moved and changed the player’s position without the screen updating.

As I mentioned, this test was a good thing to do early, as now I’m looking at how to arrange these saving and loading methods in the code. It seems like it would be a good idea to consolidate the saving and especially the loading as much as possible. Furthermore I’m not completely sold on the pickle module, as it creates files that look like this (in ASCII mode):

ccopy_reg
_reconstructor
p1
(c__main__
Actor
p2
c__builtin__
object
p3
NtRp4
(dp5
S'y'
I6
sS'x'
I18
sS'speed'

I’m envisioning a case where I have a save file and I want to examine it without too much fuss. A simple text format would be much more readable. On the other hand, the pickle module is dead simple, and it is readable (and unpickle-able, of course).

updates in a minor key (a roguelike in Python #6)

The Python demo has seen a lot of small changes as I attempt to drag it kicking and screaming into something a little more usable for a real game.

centaur01

It’s at about 500 LOC at the moment and not yet incomprehensible to me — a good thing I think since I’m not working on it every day — and posted in full below, but I’ll try to highlight the bigger changes first.

Continue reading

rogue speed (roguelike in Python, #5)

Tonight I made a rough draft of the phase order speed system I talked about earlier and described by Jeff Lait here.

roguedemo

You can see that the phase count (the turns in ‘update time’) is higher than the turn count (‘game time’) as phase count increments with the fast and quick phases.

Right now the implementation is pretty simple…I’m trying to keep everything readable, somewhat verbose and obvious. So here is what I put in the game class:

        self.phases = ['fast', 'normal', 'slow', 'quick', 'normal']
        self.phase_dict = {
                            'fast' : ('fast', 'normal', 'slow'),
                            'normal' : ('normal', 'slow'),
                            'slow' : ('normal'),
                            'quick' : ('normal', 'slow', 'quick'),
                            'fastquick' : ('fast', 'normal', 'slow', 'quick'),
                            'fastslow' : ('fast', 'normal'),
                            'quickslow' : ('quick', 'normal'),
                            'fastquickslow' : ('fast', 'normal', 'quick')}
                            
        self.phase = self.phases[0]
        self.phase_count = 0

Then after you give a brain a speed like ‘normal’ or ‘slow’ you can test if a thing takes a turn on a particular phase with this conditional:

if game.phase in game.phase_dict[brain.speed]

Probably a little crude, and it may get a little convoluted to change speeds later (from fastquickslow, say, to fastslow), but this was a simple way to get the ball rolling.