Archive for March, 2010|Monthly archive page

this is my mind right now

I’m still trying to crack this OpenGL nut for PyWeek. The horizon looks promising but at the moment I’m mired in a bed of needy kelp.

Advertisements

yes, it’s PyWeek

And yes, the winning theme was my bottom choice.

Time to make lemonade.

writing interactive fiction without a programming language

Warning ahead for a rambling post.

The English-like syntax of Inform 7 gets a lot of flak, mostly from programmers who say something like how programming languages should express concepts in concise and symbolic ways due to the nature of programming itself.

However one of my favorite things about Inform is not really the English-like expressions of ‘The Kitchen is a room’ or stuff like that, but how you can create new phrases. For example, from the I7 docs:

To make (character – a person) lose (point value – a number) points in the eyes of (voter – a person): …

To use that phrase, in your code you’d write something like ‘make Biff lose 10 points in the eyes of Buffy‘. Now if you were to translate that to a more conventionally symbolic language like Python for example, it might look like biff.score_points(-10, ‘Buffy’). In other words it’s a more verbose expression of the function.

It’s not that I necessarily prefer one syntax over the other — but what the first does is let you create a mini-language for describing that procedure of the program. Of course, that’s exactly what the Python function does as well. But because the first example is not necessarily couched in the syntax of I7 itself, I think the possibilities become much, much greater and more powerful.

Exactly how, well I’m still a little fuzzy on that. I’ve read a little recently about domain-specific languages, in particular I found this article about language-oriented programming. It’s rather out there but worth perusing.

I think I’ve said this before, but in using Leo recently it’s made me think more about what a program really is. It’s rather obvious it’s not a syntax file. However it seems, primarily, that few people examine and write programs in something other than a syntax file.

Leo takes that next step with its outline; I guess other tools such as debuggers and code browsers do something similar.

A question I seem to be orbiting lately is the somewhat unique case of how IF combines code and prose. In that sense IF isn’t too unlike a structured markup language like HTML, only markup languages rarely contain process — well, unless you count things like JavaScript. Regardless, language-oriented programming feels like it offers something to interactive fiction development. I think the synchronicity of the two terms is not a surprise. Dave Cornelson made an interesting post with regard to domain-specific languages at Intfiction. I don’t really like his choice of platforms but the core idea is worthwhile.

To get back to what a program is (forgetting the presumption of that statement for a moment) — an IF language that really was an IF-language creation language is another way of getting at that. If the IF author could specify how they create the work (and I mean really specify, not just within the specification of a syntax), is that another way of realizing the program?

A poet or a novelist is free to invent new constructs of language, new devices of storytelling or expression, in order to communicate the work. I guess an IF author does that by creating the process of the program — but is doing so within a defined syntax an unnecessary limitation?

A defined syntax obviously creates a framework an author can hang their hat on, and it makes it easier for authors to exchange examples and extensions to the core language. If every author created their own language for their work I can imagine any community collaboration could become difficult.

On the other hand it might turn out that certain mini-languages are more appropriate for some implementations than others. Does the barrier to entry become too high when, to write a work, you need to understand five or six mini-languages rather than just one syntax specification? Probably an IDE would obviate some of these difficulties…tools like the T3 Workbench or the I7 IDE do some of that already. But at the same time I’m not sure you’d want a very strictly defined IDE. Maybe something more like a Smalltalk environment? One with live code reloading…

Is it strange how these ideas keep turning in circles?

Bidden #8

I didn’t get back to Bidden until last Thursday (at least according to the commit log, I might have done a couple of things before then), but between Thursday and today I’ve:

* added levels and level switching
* added a datastore to make it easier to make new things after I’ve loaded everything in from level files
* added a basic animation system (X-com style with turn-based)
* tweaked the level generator a little to make it look nicer (to me)
* added a stairway driller to this generator
* along with the stairway added stair exits

For this level generator (the temple) the stairs work a little differently from a typical RL — there’s one stairway created (so far), and all the stairs are connected. When you walk over a stair you automatically descend/ascend, and are put in the middle of the staircase. At the top and bottom level you can’t go up or down anymore of course. I might change this to use an ascend/descend command, but I’m leaning toward not at the moment.

Ran into obvious but for a while insidious bug (aren’t they all) where the stair exit move event handlers were all firing, because I wasn’t modifying the event data packet properly…

I’m finding it’s very important to have a standard way of handling event data for each event handler. Better yet, I should standardize that somehow in something that takes care of that automatically. I don’t think I’m quite there yet though. With the pieces I have now there’s enough to hammer on to get things tight before I start to add much more.

Bidden 7DRL code review

While things are still fresh in my mind I want to review the somewhat bizarre code design I came up with during the 7DRL, if only to mark a way point to look back on as things change.

Here’s the code (Leo makes exporting this outline easy):

+ Code
	- TODO
	+ @thin bidden.py
		- << docstring >>
		- << import >>
		- << constants >>
		+ class Game
			- __init__
			- load
			- save
			- create_gid
			- register_gid
		+ class Event
			- __init__
			- broadcast
			- register_component
		+ class Control
			- __init__
			- action
			- switch_view
			- quit
		+ Controllers
			+ class Menu
				- __init__
				+ new_game
					- << make player >>
					- << make binding >>
					+ << load from .bid >>
						- << test >>
					- << put things in stage >>
			+ class Intro
				- __init__
			+ class Play
				- __init__
				- move
				- use_boon
				- wait
				- help
			+ class Coda
				- __init__
		+ class Component
			- __init__
			- __lt__
			- __gt__
		+ Components
			+ class Hunter
				- __init__
			+ class Container
				- __init__
			+ class Model
				- __init__
				- on_death
			+ class XY
				- __init__
				- on_move
			+ class Stage
				- __init__
				- create
			+ class Collision
				- __init__
				- on_move
			+ class Bump
				- __init__
				- on_move
			+ class Title
				- __init__
				- create
				- make
			+ class Hunted
				- __init__
				- on_death
			+ class Wounds
				- __init__
			+ Boons
				+ class Boon
					- __init__
				+ class Strike
					- __init__
					- on_boon
			+ AIs
				+ class AI
					- __init__
				+ class Zombie
					- __init__
					- decide
		+ class Prototype
			- __init__
		+ class UI
			- init
			+ class Pane
				- __init__
				- fade_in
			+ class Animation
				- __init__
			- input
			- view
			- menu_draw
			- intro_draw
			- play_draw
			- coda_draw
			- quit_draw
			- play_help_draw
		+ class Keyboard
			- __init__
			- check
		- << run game >>

Let’s look at the concise version:

+ @thin bidden.py
	- << docstring >>
	- << import >>
	- << constants >>
	+ class Game
	+ class Event
	+ class Control
	+ Controllers
	+ class Component
	+ Components
	+ class Prototype
	+ class UI
	+ class Keyboard
	- << run game >>

Going over things from the main loop:

    while not libtcod.console_is_window_closed() and not game.control == 'quit':
        keys.check()

        if game.control == 'play':
            for item in game.gids:
                thing = game.gids[item]
                for k in thing.__dict__:
                    c = thing.__dict__[k]
                    if isinstance(c, AI):
                        c.decide()
        ui.view()

The keys instance of Keyboard waits for a key press. If it gets an ‘x’ or the control key it waits for another key press. This is my somewhat hacked way to get key + direction key combinations. It checks if the key is in the configuration for the game, and sends a message (such as ‘up’ or ‘enter’) to the method UI.input.

That method passes along the input to the current game.control, including it in a dict and adding the enactor game ID (in the case of the player, 0). There’s a control basically for each state of the game (main menu, in-play, etcetera). I tried to make all arguments passed around in the form of a dictionary, using the same key names for like types of data.

Each control inherits an action method from the Control parent. This method checks the input message against an actions dictionary, and if the message is a key, it runs the corresponding value as a method on the control instance (for example, I had the ‘enter’ key mapped to a method to advance the state of the game arbitrarily, so I could restart the game without exiting/restarting the Python file). Individual control instances may map the same message to different methods of course.

This method gets the data in the dict described above. A good example is the move method (in the ‘play’ control instance, mapped to the ‘up/down/right/left’ message which is mapped to the arrow keys in the keys instance):

def move(self, data):
    self.directions = {
                        'up' : {'x':0, 'y':-1},
                        'down' : {'x':0, 'y':1},
                        'right' : {'x':1, 'y':0},
                        'left' : {'x':-1, 'y':0},
                        }

    data['event'] = 'on_move'
    data['outcome'] = 'continue'
    data.update(self.directions[data['input']])


    event.broadcast(data)

So this method basically adds data to the dictionary, and then sends it to the instance of Event.

Event , in the context of the 7DRL, probably was a big mistake…going into the week I had vague thoughts of trying out a message passing/broadcasting scheme for the first time, and this was the result. I spent a lot of time figuring this out.

The Event.broadcast method takes the data and sends it along to anything registered to listen for the event included, in this case ‘on_move’. So, when the player presses the up key, it’s not directly moving the player-character, but telling the game to announce that the player-character has the intention of moving…I know, I know.

To digress for a moment, each thing in the game is an instance of Prototype, which basically is a collection of Components. A component is a narrowly-defined piece of functionality, that registers itself with the event instance upon creation. For example, if the component has a method called on_move, the event instance will tell the component when an on_move event occurs.

There is a component called XY that holds the in-game position of a thing, and its on_move looks like this:

def on_move(self, data):
    if (data['enactor'] == self.gid) and (data['outcome'] == 'continue'):
        self.x += data['x']
        self.y += data['y'] 
    return data

When the player presses the arrow key and the event instance broadcasts ‘on_move’, the XY component of the player-character will take that data — if the ‘outcome’ is ‘continue’ — modify its x and y position, then pass the data along back to the broadcaster.

The reason for ‘outcome’, and passing the data back to the broadcaster, is that other components handle things like collision with walls and bumping into other things. They’ll have an on_move method, and it receives the data broadcast. For example, here is collision:

def on_move(self, data):
    enactor = game.gids[data['enactor']]
    dx = data['x']
    dy = data['y']
    xx = enactor.XY.x + dx
    yy = enactor.XY.y + dy 

    stage = game.gids[game.stage].Stage 

    if not stage.cells[yy][xx]['kind'] == 'floor':
        data['outcome'] = 'failure'
        return data

    return data

Now obviously the question came up — in which order is the event broadcast? In other words, if the XY of the player happened to get the event before collision, the player would move before the collision check even happened.

To make this work I gave each component a priority from 1 to 1000, with a default of 1000. The collision component’s priority is 100, and the XY priority is 1000. Then before event broadcasts, it sorts the list of components registered for the event. This is easy to do with Python by writing a method like so on the Component parent.

def __lt__(self, other):
    if self.priority < other.priority:
        return True
    else:
        return False

If the class defines __lt__, then calling sort() on a list of instances of that class will sort it appropriately.

That’s all there is to the event broadcasting, basically a chain of event filters that modify both the event data and game world data as the event propagates through the listening components. I suppose I’ll find out what problems this causes down the road!

NPC actions are basically the same, the only difference being in how they’re initiated. Going back to the game loop:

        if game.control == 'play':
            for item in game.gids:
                thing = game.gids[item]
                for k in thing.__dict__:
                    c = thing.__dict__[k]
                    if isinstance(c, AI):
                        c.decide()

This runs through each component, and if it’s an AI, it runs the decide method. This is all I have for decide at the moment (in the Zombie component):

def decide(self):
    choice = random.choice(self.actions)

    data = {'enactor' : self.gid, 'input' : choice}
    control = game.controllers[game.control]
    control.action(data)

Where its self.actions is just this list — [‘up’, ‘down’, ‘right’, ‘left’, ‘wait’].

This just gave me an idea for attaching AI components to the player…anyway.

After the player does their thing and the AI runs, the UI instance runs its view method, which looks like this:

def view(self):
    libtcod.console_clear(0)

    for item in self.views:
            func = getattr(self, game.control + item)
            func()

    libtcod.console_flush()

So, clear the console, and go through its list of views and run the function — for example, there’s one called ‘play_draw’, where ‘play’ is the game.control and the item is ‘_draw’.

Other conceivable ones might be ‘_log’ to capture the game state, or perhaps ‘_write’ to turn this into IF ;D. In any case, yet another example of severe over-engineering…

These methods are fairly straightforward…I did one weird thing where certain events could create ‘animations’, components that last for just one game loop and get added to the list of game objects to be drawn. That’s something I need to redo (I want to have multi-frame animations possible between each player turn). My current idea here is to make drawing a series of frames, where normally there’s just one frame as I have now in play_draw, but with the potential for adding frames to make the animations.

So that’s it. If I expand this I can see the component system getting really massive…on the other hand I don’t know that any game wouldn’t have a similar situation once you add a lot of stuff. I can derive children from component classes in some cases (for example with AI) so that might keep things more organized. I like the separation of input/views/logic. Right now the world state is woven into the game logic quite a bit, but I’m of mixed feelings of trying to make a hard separation between the two. In this application it may not be worth it.

Any comments or criticism is particularly welcome at this point, so feel free.

Bidden day #7

total time: 54 hours

Well it’s 10 AM, up all night, and it’s rather shocking given the time spent, but I didn’t finish. The still warm entrails are here:

http://sites.google.com/site/biddenrl

You’ll need Python 2.6 and Windows to play (I use the word play very loosely). Linux shouldn’t be that hard but I’m not sure if I have the correct DLLs in the zip — you’re welcome to check it out though to see (I did include some .so DLLs, so maybe that will work).

I got to the point where the player had a goal, but really no gameplay. I spent a lot of time messing around with programming and obscure code structures, where I should have ruthlessly simplified/hacked things to get the gameplay vision in place, since I had a very clear idea of where I wanted to go. On the other hand I’m definitely pleased to have spent so much focused time this week (more than twice what I’ve ever done for Pyweek or Ludum Dare). A lot of the time went to basic programming tasks, which will speed up with practice I think. In general I feel like I’ve crossed a hurdle of some kind in making stuff.

In any case, I’m still very into the Bidden idea, so I’ll continue working on it until it’s fully realized.

Bidden day #7 in progress

time so far: 44 hours

The RNG smiled on me this afternoon and I finished early at work, so got an extra few hours in this afternoon. About 12 hours left, and I’m still very far from a success I think. But the structure is almost completely there. Right now it’s 9 PM and:

* I have the house to myself
* I have a full can of tea
* soul on the radio
* nothing to do tomorrow

We’ll see what happens!

Bidden day #6

time so far: 38 hours

* the creature is corpse’d when you bump into it (decorpsed? corpsefied? ‘killed’ is a little strong given the state of the creature model at the moment).

* world creation occurs properly at game start.

* beginning of a goal.

* but I did spend 2/3 of the night on message passing and event filtering! I’m sure this will come in handy.

tomorrow:

* add more creatures

* add at least one character boon

* add everything else

Bidden day #5

time so far: 35 hours

For some reason I thought it was Thursday today. What luck!

Still avoiding gameplay by making intro and help screens. I’ve also been messing around too much with stuff like UI and game input structures. However tonight I’ve been getting more messy and loose, and progress is accelerating. The screens above are the basic outline of a single play through. All I have to do now is add everything else!

Bidden day #4

time so far: 30 hours

Yes it’s true…only three more days to go…still no goals, conflict, character advancement or content. But I made a lot of title screens!

Really I couldn’t resist. The above example is a kind of mash-up from messing around with ascii-paint, the wonderful tool by priomsrb. I did get some other things done — I’m on my way to a structure for a menu, state switching and so on. I have a feeling though that I’m avoiding some of the harder things by doing these things that are, really, not totally necessary to making a functional game. I think it’s OK in the end though, it’s kind of like a mid-term break, and it should add to the overall experience (assuming I have something playable to experience!).

Still with the goal of a playable run-through from start to finish — would like to get that done by tomorrow night. Then Friday is work all night to add things and release.