Glottys - an event-driven, python based text adventure engine

Daniel - Mar 12, 2012 - Games Code

This is something I spent the weekend working on: it's an event-driven, python based text adventure engine. I built it for my brother who's interested in learning to write python. I figured I'd write some quick docs for it here, and if you're interested in more features or even contributing, please comment!

It's written to be very new-user friendly and also as powerful as you need it to be -- hopefully, my brother's success with it having never programmed before should be proof of this.

Here's the python module: glottys.zip

If you're looking for an extensive example, here's the game my brother created: fatal_tryst.zip

So, let's launch into creating a text adventure with glottys!

Example game: Trapped!

First things first, create a file called trapped.py, and put it in the same directory as the glottys folder from glottys.zip above.

First things first, import everything you need from the glottys module:

from glottys import *

Great! Now we can create a new game:

Trapped = Game('Trapped!')

And some areas:

Cell = Area('Cell')
Street = Area('Street')

Now let's link the two areas:

Cell.add_path(North, Street)

Because our cell is locked, we want to disable the escape route for now!

Street.disable()

Now let's create our protagonist:

Convict = MainCharacter('Convict', game=Trapped, startlocation=Cell)

And some items for our area, along with the descriptions for our first puzzle:

Window = StaticItem('Window', owner=Cell)
Wall = StaticItem('Wall', owner=Cell)
Wall.description = 'This wall is made up of some pretty loose bricks. I wonder if I can move them?'
Bricks = StaticItem('Bricks', owner=Cell)
Bricks.description = 'These {self} look pretty loose!'
Bricks.use_text = 'You break through the loose {self} easily, revealing an escape route to the street'
Bricks.hide()

Now let's add some of the mechanics of our game. First, we need to reveal the bricks when the wall is looked at, using the onLook event:

@Wall.onLook
def revealbricks():
  Bricks.show()

Now, we need to let the player use the bricks to break through the wall:

@Bricks.onUse
def createhole():
  Street.enable()

Now, all we need to do is finish the game when the user moves into the street!

@Street.onEnter
def endgame():
  Trapped.endgame()

Great! Now we've declared our game, let's run it:

Trapped.run()

The full source for this example is available at http://bluesuncorp.co.uk/files/articles/glottys-event-driven-python-based-text-adventure-engine/trapped.zip

Key Concepts

Let's take a look at some of the concepts we've dealt with in making our game. First, we have game objects, which we create. So:

Cell = Area('Cell')

The first parameter of a game object will always be its name. Other parameters may be available or required, depending on the type of object. (see below)

Next, we have object attributes, which determine how individual objects behave. Most of these at present allow you to change the default text which appears when something happens in relation to the object. So, for example:

Bricks.description = 'These {self} look pretty loose!'

Note that the {self} in this string refers to the name of the object, which is automatically filled out for you.

Next, we have object methods, which allow us to "do" things with the object. For example:

Street.enable()

Finally, we have events, which allow us to perform actions whenever something happens in relation to an object:

@Wall.onLook
def revealbricks():
  Bricks.show()

If you want to cancel the default action for an event (for example, if you want to prevent a character from looking at an item) just return False in your event function.

Commands

There are a number of commands built into the engine, and you can also define your own. The defaults are:

  • Use <item1> [item2] [etc]
  • Look [item]
  • Get <item>
  • Move <direction>
  • Open <item>
  • Talk <character>
  • Drop <item>
  • Inventory
  • Help

Defining your own commands couldn't be easier:

@Command('sleep'):
def dosleep():
  MyGame.echo('You doze off for a few hours and awake refreshed')

Conversations

Defining a conversation is as simple as creating a character, and defining the conversation threads:

Zombie = Character('Zombie', location=Crypt)
Hello = Thread('Hello Zombie', 'Brraaaaaaaiins', character=Zombie)
Escape = Thread("I'm getting out of here...", 'Waaaaaagh', parent=Hello)
Respond = Thread("I don't have any brains...", 'Mmmhghhh', parent=Hello)

Use / Combinations

If you want to use two or more objects together, the syntax is simple:

@Use(Rake, Leaves)
def tidylawn():
  MyGame.echo('The lawn is tidy now!')

Alternatively you can have a combination of items return another item:

@Use(Flour, Milk, result=Pancake)
def makepancake():
  MyGame.echo('Yum, pancake!')

Available objects, attributes, methods and events

In order to really flesh out your game, you'll want to know the full range of available object types, attributes, methods and events. Here they are!

Game

Parameters:

  • name: the name of your game

Attributes:

  • intro_text = 'Welcome to... {self}'
  • end_text = 'End of game {self}'

Methods:

  • run(): run your game after creating it
  • help(): print out help text
  • endgame(): end the game

Events:

  • onRun: when the game is run
  • onExit: when the game is exited
  • onEndGame: when the user reaches the end of the game

Area

Parameters:

  • name: the name of the area

Attributes:

  • first_enter_text = None
  • enter_text = 'You enter {self}'
  • enter_fail_text = 'You can not currently enter {self}'

  • look_area_text = 'You are in {self}'

  • look_inventory_text = 'You can see the following items: {items}'
  • look_character_text = 'You can see the following people: {self.characters}'
  • look_direction_text = 'To the {direction} is {location}'

Methods:

  • add_path(direction, area): Create a path from direction to area
  • enable(): Enable area
  • disable(): Disable area
  • look(): Look at area
  • enter(character): Have the character enter the area

Events:

  • onLook: when the player looks at the area
  • onFirstEnter: when the player first enters the area
  • onEnter: when the player enters the area
  • onExit: when the player leaves the area

MainCharacter

Parameters:

  • name: the name of the character
  • game: the game the character is associated with
  • startlocation: the area the player will start in

Attributes:

  • move_text = 'You move {direction}'
  • inventory_text = "I'm carrying {items}"

Methods:

  • move(direction): move the character in the given direction
  • pickup(item): have the character pick up the given item
  • open(item): have the character open the item
  • look(): have the character look at the current area
  • talk(character): have the character talk to the given character
  • checkinv(): list the character's inventory
  • discard(item): have the character discard the given item
  • has(item): check if the player has the given item
  • drop(item): have the character drop the given item
  • give(item): give the character the item
  • use(*items): have the character use the given items together

Events:

  • onMove: when the character moves
  • onPickup: when the character picks an item up
  • onLook: when the character looks
  • onOpen: when the character opens an item
  • onCheckInv: when the character checks their inventory
  • onUse: when the character uses an item
  • onDiscard: when the character discards an item

Character

Parameters:

  • name: the name of the character
  • location: the location of the character

Attributes:

  • description = "It's {self}"
  • talk_fail = "I don't think I want to talk to {self}"

Methods:

  • talk(): begin talking to the character
  • look(): look at the character

Events:

  • onLook: when the character is looked at
  • onTalk: when the character is talked to

InventoryItem / StaticItem

Parameters:

  • name: the name of the item
  • owner: the owner of the item (a character, area, or container item)
  • synonyms: a list of synonyms
  • container: whether the item is a container or not (may contain other items and be opened, etc.)

Attributes:

  • description = 'This is a {self}'

  • use_text = 'You can not use {self}'

  • pickup_text = 'You pick up {self}'

  • pickup_fail_text = 'You can not pick up {self}'

  • open_text = 'You open {self}'

  • locked_text = '{self} is locked'
  • empty_text = '{self} is empty '
  • not_container_text = '{self} is not a container'

  • contains_text = '{self} contains {items}'

  • discard_text = 'You discard {self}'

  • discard_fail_text = 'You might need the {self}, probably best to keep it for now'

Methods:

  • look(): look at the item
  • open(inventory, staticitems): open the item
  • pickup(location, inventory): pick up the item
  • discard(): discard the item
  • use(): use the item

Events:

  • onPickup: when the item is picked up
  • onLook: when the item is looked at
  • onFirstLook: when the item is first looked at
  • onUse: when the item is used
  • onOpen: when the item is opened
  • onDiscard: when the item is discarded

Thread

Parameters:

  • query: text which is said to the character
  • response: text response to the main character
  • parent: parent thread
  • persistent: whether or not the thread remains after being activated
  • character: the character the thread applies to (only necessary for top level thread)
  • uplevel: whether or not the thread takes the conversation up a level
  • end: whether or not the thread ends the conversation
  • auto: whether or not the thread is automatically selected if it is the only remaining option

Methods:

  • initiate(): initiate the conversation thread
  • endconversation(): end the conversation

Events:

  • onInitiate: when the thread is initiated
  • onDialogue: after the query and response, before the options are presented
  • onEnd: when the conversation is ended

Robert Ian Hawdon

Wow, a new post!

I'll have to check this out :D

Tarball Mcgee

Wow, Interesting. I'll have to check this out! Any way that games made with Glottys can play sound &/or display graphics? I know Pygame can do this, but is there any way I can do this with Glottys? Thanks in advance, Tarball.

Karl

Nice!

But your brother's game gives me an exception when using the keywords 'up' or 'down' in combination with 'manhole':

down manhole Traceback (most recent call last): File "game.py", line 240, in <module> Fataltryst.run() File "/home/karl/glottys/game.py", line 50, in run Command.run_command(commandstring) File "/home/karl/glottys/command.py", line 31, in run_command options[command].call(args) File "/home/karl/glottys/command.py", line 70, in call self.callback(args[:self.maxargs]) File "/home/karl/glottys/maincharacter.py", line 88, in <lambda> Command.register(direction.name.lower(), lambda direction=direction: Command.run_command('move %s' % direction.name.lower()), synonyms=direction.synonyms) AttributeError: 'str' object has no attribute 'name'

Bill

This is so fun! I've been learning Python the last couple of weeks and this is a great way for me to tinker around. Thanks so much!

Ronald

Thanks for the Engine will be sure to use it in my future builds and such

-Ronald Weasley

Ronald

Thanks for the Engine will be sure to use it in my future builds and such

-Ronald Weasley

Hermione

A deer friend of mine told me about this, i shall have to have a look in future!

-Granger

Hello There!

Cool

Stanley Waring

Stupid!

x

<?php