Home Sweet Albia
Creatures 1 | Creatures 3 & Docking Station | Miscellaneous
Favorites | Agents | Tools | Agenteering

A Guide to Agenteering

(12 May 2023)

A guide to making agents for Creatures 3 and Docking Station using Theist.

I've archived the original 2006 Mac-centric version of the guide here in case you're feeling extra nostalgic.

Table of Contents

  1. Prepare Yourself

    1. Get the Tools
    2. Reserve Classifiers
  2. Agent-Making Time

    1. Start Theist
    2. Add a Tag
    3. Add a Sprite File
    4. Add a Script File
    5. Add Catalogue Entries
    6. Compile the Agent
    7. Try It Out
    8. Updating Files
    9. Advanced Testing
  3. Look Smart with Sprites

    1. Come Up with a Concept
    2. Do Some Drawing (or Modeling or Photography)
    3. Tweak the Images
  4. Stick to the Script

    1. Order From CAOS
    2. Create a New Object
    3. Activation Script
    4. Pick-Up Script
    5. Drop Script
    6. Timer Script
    7. Blowing Bubbles
    8. Bubble Scripts
    9. Remove Script
  5. Moving On

    1. Make a README File
    2. Zip It Up
    3. Share It Far and Wide
    4. Learn More
    5. Many Thanks

Prepare Yourself

Get the Tools

References to bookmark:

Reserve Classifiers

Every type of object in the game is identified by a unique classification number. If your agent uses a number already being used by another agent in somebody's world, it'll cause some weird things to happen.

To avoid conflicts, it’s best practice to reserve some scripts for your agents at the Creatures Caves website. (Note: You’ll need to make an account to reserve script numbers. For the best security, remember to use a unique password and change it regularly.)


Agent-Making Time

Start Theist

To make our first agent, we’ll be using Theist. When you first open it, you’ll get a new, unsaved Theist file. Go ahead and save it to whichever folder you’re going to store all your agent files in (scripts, sprites, sounds, etc). Since we’re going to start by making a Bubble Blower toy, name it bubble_blower.the.

This file keeps track of all the files your agent needs, as well as settings like its name and description. Creatures can’t read Theist files, but we can compile a Theist file into a Creatures-native Agent file when everything’s ready.

Add a Tag

A single Theist file can hold multiple agents. Each one is called a tag. There are also egg tags, but for now we’re going to stick to agents. You can add one by clicking the + button. Now you can see a file list to the left, and the agent properties to the right.

Might as well fill out the agent properties for our Bubble Blower first. Its name is Bubble Blower and its description can be something like Let’s have fun with bubbles! The version number is just for us to keep track of things if we update it in the future. As for Game, Injector Preview, and Remove Script, we’ll leave those as the defaults for now (unless you really want to make your agent only injectable from the C3 or the DS injector but not both for some reason).

Add a Sprite File

Let’s add our sprites. Go ahead and download these sample images for our bubble blower for now. As you can see, it’s just a series of PNG image files. Normally Creatures uses its native S16 and C16 sprite files, each of which let you have multiple images per file, but Theist will convert our PNGs to the right format for us. Just drag the PNGs into Theist, which automatically puts them all in a single C16 sprite - or use the Add New File button to add the first PNG, and then after selecting the C16 sprite from the file list, press the + button next to the Frames header to add the remaining PNGs.

Note that the default name for the sprite will be the name of the first PNG file. We can go ahead and change that from bubble_blower-0 to just bubble_blower to make it a bit nicer.

In the tag properties, set the Injector Preview to Auto which will use the first frame in the sprite in the in-game agent injector.

Add a Script File

Next up, we can add our script file. What script file? Why, this script file! That’s right, I’ve already written a Bubble Blower script to get us started. Once again you can drag it into the Theist window or use the Add New File button.

In the tag properties, set the Remove Script to Auto which will use the script's rscr code to generate the script that the in-game agent injector uses to remove the agent when you press the "⊘" button.

Add Catalogue Entries

This last part is not strictly necessary, but it will make your agent much easier for other people to understand in the game: adding a catalogue entry. This is the text that comes up when you right click on an agent with the "?" turned on. Normally you have to make a separate .catalogue file, but Theist lets you define catalogue entries right in the tool using the Add Inline Catalogue button.

Since our Bubble Blower has two parts - a wand and the bubbles - we need two catalogue entries. Use the + button add a second entry and fill them out. Bubble Blower Wand with the classifier 2 21 999 (each agent has a unique classifier - we’ll talk more about these later on), and Bubble with classifier 2 21 1000.

Compile the Agent

Time to compile our Theist file into a Creatures Agent file. Just press the Compile button in the upper-right corner, and save your agents file into your project folder.

Try It Out

Now let’s try it out in the game. Copy your agent file to the Docking Station/My Agents folder, wherever you’ve installed your copy of the game. When you start the game, you should be able to find the Bubble Blower in the Docking Station comms room. Press the green check button, and et voila, your bubble blower should magically appear!

For Creatures 3, the steps are the same, except you copy your agent file to Creatures 3/My Agents instead. Now it will show up in the Creatures 3 injector in the ship’s engineering bay even in undocked worlds.

Updating Files

An agent file is kind of like a zip file - it compresses all the files an agent needs into a single file. When you first inject an agent, the game extracts all the files and puts them in the right folders. Except for scripts, which get put into the world itself. From then on, the agent file itself is just used to show the agent in the injector. That means that if you change the sprites, sounds, or catalogues for your agent after you’ve injected it into any world, you have to find and delete the old versions so the game can replace them with your new versions - or replace them manually if you prefer.

Note that if you want to see the new version of your agent show up in the Docking Station injector - even you just changed the name, description, or injector preview - you need to do the following dance:

  1. Delete the original agent file from Docking Station/My Agents.
  2. In the Comms room, switch views from the injector to something else and back again. The agent will be removed from the list, forcing the game to re-scan the file when you add it again.
  3. Add the new agent file to Docking Station/My Agents.
  4. Switch views in the Comms room again. Your agent will be back in the list, and this time it will be the updated version.

Advanced Testing

It can be annoying to have to re-compile and re-inject your agent every time you update the script, especially in the early stages when you might need to make lots of small changes. There’s a trick you can do to get your script in the game faster: put your ".cos" file directly in the game’s bootstrap folder and inject it manually.

Move your script file to Docking Station/Bootstrap/010 Docking Station (or any folder in Bootstrap, you can even make a new one for testing purposes). In the game, you can open the CAOS command line with CTRL+SHIFT+S and type

ject "bubble_blower.cos" 7

(or whatever your script file is named). This will run the remove script and re-inject the agent - assuming you’ve injected it before, or at least copied the sprites and sound files manually into their proper game folders. You can then edit the script from there, and keep ‘jecting it all you want.

Just remember to move your script file back into your project folder when you’re done, otherwise it won’t get included in your compiled agent.

Also note that all scripts in the Bootstrap folder will be injected into any new worlds you create, so make sure you delete your test script from the Bootstrap folder when you’re done and avoid making new worlds while you’re in the middle of testing.


Look Smart with Sprites

Come Up with a Concept

Every agent starts as an idea. It helps to sketch pictures of what you want your agent to look like, and think about how your agent will behave. If you outline the poses and animations your agent will use, you won't have to spend as much time drawing sprites you won't need. You can also start a folder dedicated to all the files for your agent, just to keep things nice and organized.

Do Some Drawing (or Modeling or Photography)

The official Creatures 3 and Docking Station sprites use 3D models that have been exported as 2D sprites, sometimes with additional polish added on top of that. You don’t have to start with a 3D model if you don’t want to, though. You can edit a photo of an object, scan a hand-made drawing or painting, or draw your agent digitally.

Tips:

Tweak the Images

The important thing is that you end up with one PNG file per frame, with a transparent background. Most graphics editors will let you export your work as PNG files, so that shouldn’t be a problem. The Creatures games actually have their own image formats (S16 and C16), but Theist will take care of the conversion for you.

Tips:


Stick to the Script

Order From CAOS

When we put together the Bubble Blower, we used a pre-made script. Go ahead and open it up in a text or code editor: you’ll see it’s just a lot of comments (the lines that start with asterisks) and short, mysterious commands (the lines that start with four-letter words followed by numbers).

The mystery commands are the actual code that makes the agent function. The comments are just for us. The Creatures game engine uses its own scripting language called CAOS, for Creatures Agent Object Script. It’s simple and efficient for the game, but not very readable for humans, so it’s best to have a copy of the CAOS Docs on hand to look up what the (many, many) commands do.

Let’s walk through the Bubble Blower script line by line so you understand all the parts well enough to mess around with it or make something from scratch.

Create a New Object

The first command in most scripts is inst, which tells the game to do everything that follows in one game tick - practically instantly. That way nothing else can interrupt it while it’s creating the object and setting all its properties.

* everything that follows happens in one tick (instantly)
				inst

Next, we’ll create the actual object. It doesn’t have any moving parts or anything, so we’ll use new: simp to create a simple object. Unlike inst, new: simp has a number of arguments that follow - numbers and strings (bits of text enclosed in quotes) that specify details about the command.

* create new object
new: simp 2 21 999 "bubble_blower" 5 0 4000

The first three numbers, 2 21 999, represent the unique classifier for our object. The first number, 2, is the family. In this case it’s an object that lives in the world. The second number, 21, is the genus, which is basically what word a norn would use for it. In this case, it’s a toy. Finally the third number, 999, is the species. This is unique to the bubble blower wand. There could be a different object in 2 11 999, but if anything else uses 2 21 999, the game will think they both share the same properties and scripts. That’s why it’s a good idea to reserve classifiers for the stuff you make. Don’t worry though - there are plenty to go around! We won’t run out anytime soon.

The next argument is a string, "bubble_blower". This is the name of the sprite file this object will use. The 5 means it’ll use 5 frames, and the 0 is the base, meaning frame 0 is the first of those five frames (the rest counting up from there, so 1, 2, 3, and 4).

The last argument, 4000, is the plane the object sits on. The higher the number, the closer to the front of the screen it is. It’ll appear in front of any object with a lower plane. This is just a good number for toys, since it’s kind of in the middle: in front of the norns and most plants and environmental objects.

ATTR and BHVR

Agents have two properties that determine what the Hand/the world can do with it, and what creatures can do with it: ATTR and BHVR.

* set attributes: can be carried by agents (+1),
* hand can pick it up (+2) and activate it (+4),
* and affected by collisions (+64) and physics (+128)
attr 199

* set behaviors: creatures can active 1 (push) it (+1),
* and pick it up (+32)
bhvr 33

The value of these properties is determined by adding together a bunch of numbers representing individual things that can affect the agent. It’s not worth memorizing this system, just use an ATTR + BHVR calculator.

For the bubble blower wand, we’re going to use some pretty common values for basic toys.

Physics Properties

The Creatures engine has a 2D physics system, so we need to set a bunch of properties on our agent so it behaves the way we want when it’s dropped or thrown.

* set gravity
accg 3

* set permeability
* (what kinds of surfaces it will fall through)
perm 60

* set elasticity
* (how much it bounces)
elas 0

* set friction
* (how much it slides on the ground, eg. when dropped on slope)
fric 100

* set aerodynamics
* (how quickly it slows when going through air, eg. when thrown)
aero 2

There’s also the puhl command for setting the x/y offset on the sprite to a more reasonable place for the hand to pick it up from. This puts the opening of the wand above the hand, so it looks more like how it would be used in real-life.

* set the offset for where the hands picks it up
* (-1 = set for all sprites)
puhl -1 20 55

Injection Boilerplate

To make the agent appear in the right spot from both the C3 and DS injectors - and not error out if you only have C3 installed - there’s some standard code that we can use.

* boilerplate for placing agent after being injected
* from either C3 or DS

doif game "CreatorX" ne 0 and game "CreatorY" ne 0
    mvsf game "CreatorX" game "CreatorY"
else
    mvsf 5440 3580
    velo rand 30 40 -5
endi

doif room targ eq grap 5440 3580
    mvsf 5440 3580
    velo rand 30 40 -5
endi

That’s it for getting the agent into the world. Next up, we’re going to add some scripts to get it to do stuff when the Hand or a creature interacts with it.

Activation Script

When the Hand or a creature pushes an agent, its Activate 1 script is called. Scripts start with the command scrp, followed by the agent’s classifier, followed by the script number - in this case, 1. The end of the script is marked by endm.

* activate 1 script
scrp 2 21 999 1
    ...
endm

So what do we put inside? Well, we definitely want creatures to know they’ve played with a toy so they get those happy chemicals released.

* reward creature for playing with a toy
stim writ from 97 1

We also want to animate the bubble blower wand by telling it to move through a series of sprite frames - it stands upright and then shows the bubble inside getting larger and larger, before returning to the original bubble-less frame. The bubble is now free to be its own separate agent - but first we need to tell the script to wait for the animation to finish with the over command.

* animate wand
anim [1 2 2 3 3 4 4 1]

* wait for animation to stop
over

Now that the bubble is fully grown, it’s time to create a new agent for the bubble. Since there are several ways to create bubbles with the wand - another is to hold it and wave it around to auto-generate bubbles on a timer - I’ve put the code for this in a custom script. User-defined scripts like this are safest to start at script number 1000, well away from any system-defined scripts (like this very Activate 1 script). We’ll get to the definition of that later - for now we just want to call it.

* call create-bubble script
call 1000 0 0

With the bubble on its way, the wand can collapse to the ground again by changing its frame with pose. We’ll just wait a few ticks first so it feels more natural.

* wait 5 ticks
wait 5

* change sprite
pose 0

That’s it! Not the simplest script, but with a more basic toy you can always get away with just writing a stim and running an animation.

Pick-Up Script

When the bubble blower is picked up by Hand or creature, script number 4 is called. We want to change the frame to the upright wand, and start blowing those bubbles. In the timer script we’ll start making bubbles automatically, so here we just need to set the rate at which the timer script is called with tick.

* pick-up script
scrp 2 21 999 4

    * change sprite
    pose 1

    * start timer at a rate of every 5 ticks
    tick 5

endm

Drop Script

The opposite of the pick-up script, the drop script - number 5 - needs to stop the timer and change the frame so the wand lies on the ground again. (Once again we’re using wait to make the frame-change feel more natural.)

* drop script
scrp 2 21 999 5

    * stop timer
    tick 0

    * wait 5 ticks
    wait 5

    * change sprite
    pose 0

endm

Timer Script

The bubble blower is going to blow bubbles continuously while it’s being held. That’s why we set the timer rate with tick 5 in the pick-up script, and stopped the timer with tick 0 in the drop script. That way the timer script - script number 9 - is called every five ticks while the Hand or a creature is holding the wand.

The code is going to look similar to the activate script. The wand will animate blowing a bubble, and when that animation is over, a new bubble will be created by calling our custom script.

* timer script
scrp 2 21 999 9

    * animate wand
    anim [2 3 4 1]

    * wait for animation to stop
    over

    * call create-bubble script
    call 1000 0 0

endm

Blowing Bubbles

Now for the big one: our custom script for creating bubbles, script number 1000. This is going to look similar to how we created the bubble blower wand, starting with an inst to make sure the rest of the script can’t get interrupted halfway through.

* custom create-bubble script
scrp 2 21 999 1000

    * everything that follows in this script
    * happens in one tick (instantly)
    inst

Before we can create the bubble itself, we have to store the wand’s current position so the bubble can show up in the right spot. The reason we have to do this ahead of time is because once the bubble is created with the new: command, all further commands in the script target the new agent.

We can store the wand’s positions in some local script variables, va01 and va02, so we can use them later. Script variables are attached to the script, not the object, so they don’t care about the target object. They do disappear once the script ends, though. (If you do want to store variable data in the object instead, you can use ov01 - ov99. Just be aware that each agent has its own set of object variables, so if you switch targets, you’re going to be accessing a different set of object variables.) The command setv takes a variable and then a value to store in it, in this case the positional data from posx and posy.

* set variables 1 and 2 to the wand's x and y positions
setv va01 posx
setv va02 posy

That’s the center of the sprite, though, and won’t place the bubble at the opening of the wand. We have to do some math. CAOS provides addv and subv to add and subtract from the value stored in a variable.

* subtract some values from variables 1 and 2
* so bubble will appear in the right place
subv va01 7
subv va02 13

Ok, now it’s time for new: simp. We need a different classifier from the wand, so we’ll use 2 21 1000. And since bubbles only need one sprite frame - the sixth frame in the sprite file - and we want to put the bubbles a little in front of the wand, the full line looks like this:

* create bubble (this changes target
* of commands to the newly-created bubble)
new: simp 2 21 1000 "bubble_blower" 1 5 4100

Next up is our regular bunch of attributes, behaviors, and physics properties, albeit with some slightly different values from the wand since bubbles are practically weightless and are meant to just float around:

* set attributes: hand can pick it up (+2) and activate it (+4),
* and affected by collisions (+64)
attr 70

* set behaviors: creatures can active 1 (push) it (+1),
* and pick it up (+32)
bhvr 33

* set physics properties
accg .1
perm 60
elas 0
fric 50
aero 0

Remember those local script variables holding onto the x and y positions for the new bubble? Now it’s time to use them. The move-safely command, mvsf (this makes sure it won’t end up stuck in a wall by accident), conveniently takes an x and a y argument. So we can plug in the values stored in va01 and va02 to move the bubble to the right spot.

* move to the x, y coordinates stored in variables 1 and 2
mvsf va01 va02

Once the bubble is positioned let’s give it a little push in a random direction by using the velo command to set the x and y parts of its velocity. The rand command lets us use a random number between -1 and 1 for each part.

* set a random initial velocity
velo rand -1 1 rand -1 1

To add some continuous movement - and an eventual pop - we’ll use a timer script for the bubble and set the rate to something random.

* start timer
tick rand 10 20

When we’re done with the bubble, we can target the original owner of this script again - the wand - with targ ownr. This may not be strictly necessary at the end of a script, but I included it here in case you want to mess around with the script and add additional wand-targeted code after the bubble is created and sent on its way.

* return target of commands from bubble
* back to wand (the owner of this script)
targ ownr

And that’s it for the last of the bubble blower wand scripts. On to the scripts for the bubble itself!

endm

Bubble Scripts

You now know everything you need to understand most of the bubble scripts.

* activate 1 script
scrp 2 21 1000 1
    * call pop-bubble script
    call 1000 0 0
endm

* pick-up script
scrp 2 21 1000 4
    * stop timer
    tick 0
endm

* drop script
scrp 2 21 1000 5
    * start timer at a rate of every 10-20 ticks
    tick rand 10 20
endm

In the timer script, we introduce a bit of flow control, some branching code. Doif will only run the commands under it if some condition is met, in this case when a random number between 0 and 9 is equal to 0 - in other words, a 1 in 10 chance. Anything under else will run if that initial condition is not true, so the other 9 in 10 chances. Finally it’s wrapped up with endi - any code after that runs normally.

* timer script
scrp 2 21 1000 9
    * 1 in 10 chance for bubble to pop
    doif rand 0 9 eq 0
        * call pop-bubble script
        call 1000 0 0
    else
        * if bubble doesn't pop,
        * change velocity in random direction
        velo rand -1 1 rand -1 1
        * reset timer at a new rate of every 10-20 ticks
        tick rand 10 20
    endi
endm

When the bubble pops, we play a sound effect with sndc and then destroy the bubble - the current target object - with kill targ.

* custom pop-bubble script
scrp 2 21 1000 1000
    * play popping sound effect
    sndc "pop_"

    * wait 5 ticks (for sound to finish playing)
    wait 5

    * delete bubble
    kill targ
endm

Remove Script

The last step is to create a remove script to fully delete the agents and their scripts from the world when the player presses the remove button on the injector.*

The remove script starts simply enough:

rscr

To remove all the wands and bubbles, we use the command enum to look at all the agents with a particular classifier, one at a time, like it’s going through a checklist. The current item in the list is the target of the following commands, which means we can remove the agent with kill targ. Then next picks the next agent in the list, until there aren’t any more agents with the specified classifier.

* remove wand
enum 2 21 999
    kill targ
next

* remove bubbles
enum 2 21 1000
    kill targ
next

That takes care of the agents themselves. We also want to remove the scripts we created for them, which we can do with scrx (basically the inverse of scrp).

* remove wand scripts
scrx 2 21 999 1
scrx 2 21 999 4
scrx 2 21 999 5
scrx 2 21 999 9
scrx 2 21 999 1000

* remove bubble scripts
scrx 2 21 1000 1
scrx 2 21 1000 4
scrx 2 21 1000 5
scrx 2 21 1000 9
scrx 2 21 1000 1000

Removing scripts is especially important to do while developing agents to avoid unexpected behaviors. Once you create a script, it sticks around in your world’s scriptorium and continues to affect any agents with its classifier until you overwrite or remove it. For example, if you want to let bubble timer keep running even while the bubble is being held, you don’t need the pick-up or drop scripts anymore - but you would need to run scrx on those scripts to stop them from affecting your bubbles. In the final version of your cos file you shouldn’t remove scripts you aren’t also defining, you just need to keep this in mind while you’re still messing around. You can also run scrx from the CAOS command line.

* Traditionally the remove script here in the script file only gets called when using the ject command from the CAOS command line. You’d need to separately define the one used by the in-game injector in the PRAY source file, which usually just meant copying it from the script file and pasting it into the PRAY file (and removing all line breaks). Theist makes it easy to just write it once by setting the Remove Script property to Auto. It will scan the first script file for the remove script, and do the copy-paste-line-break-removal dance for you.


Moving On

It’s time to strike off on your own agenteering adventures!

Make a README File

When you share your agent, you probably want to let people know what they’re getting into. It’s best practice to include a text file, readme.txt, with the following info:

Zip It Up

With your agent file (or files) and readme.txt, zip them up so you can distribute them together.

Share It Far and Wide

There are three main places you can share your work:

Learn More

Many Thanks

Original 2006 guide: Thanks to Moe, Spook, RProgrammer, and Malkin

Updated 2023 guide: Thanks to Amaikokonut for some awesome CAOS tools, 20kdc for help with Theist, and EemFoo for support and encouragement!