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
Prepare Yourself
Get the Tools
- Theist
- A code-friendly text editor (such as VSCodium or another free text editor, or even Notepad in a pinch)
- (Optional) A graphics editor (such as Blender for 3D, GNU Image Manipulation Program for 2D, or a pixel art editor like Aseprite for pixel art)
- (Optional) A sound editor (such as Audacity)
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.
- Sprites: Docking Station/Images
- Sounds: Docking Station/Sounds
- Catalogues: Docking Station/Catalogue
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:
- Delete the original agent file from Docking Station/My Agents.
- 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.
- Add the new agent file to Docking Station/My Agents.
- 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:
For 3D models, set your camera to orthographic.
For lighting, set up lights in your 3D modeling software or, in 2D graphics software, use a soft brush on a layer with an additive blend-mode. Give your object a cool white light coming from above or upper-right, and a dim blue or orange under-glow for ambience.
Take screenshots of the game to reference or use as a background layer to see what your agent will look like in the world.
It’s ok if your sprites aren’t perfect, or don’t fit the game’s official style. There’s a wide variety of art styles in community creations, and players are always happy to have new stuff in the game.
It’s a good idea to use rougher sprites while first creating and testing the scripts for your agent, and then come back and add polish when you have your agent working the way you want.
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:
Avoid extra blank space around your image. Many editors have a "trim" function that will automatically do a tight crop.
If your agent will change pose or animate, make sure each sprite in the sequence is the same width and height.
Creatures 3/Docking Station don’t support anti-aliasing/semi-transparency, so make sure all pixels are fully opaque or fully transparent. You’ll probably need to clean up the edges - it’s common to use a darker color around the edges of your sprites to help them look more polished, while avoiding an "outlined" look (but it really depends on the style you’re going for).
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 anim
ation.
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 anim
ate blowing a bubble, and when that animation is over
, a new bubble will be created by call
ing 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 rand
om number between 0 and 9 is eq
ual 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:
Your name (the one you use in the community, doesn’t have to be your real name)
Your website URL, if you have one
Name and description for each agent
The version number - start at 1.0, and if you need to make changes in the future, you can bump it up to 1.1, 1.2, etc. and list the changes for each version
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:
Discord - Creatures Discord and The Norn Nebula
EemFoo Archive - right now you can add things by sharing in the EemFoo Archive Discord
Learn More
- Creatures Development Network
- Awesome Creatures Development Resources
- Creatures Development Standards
- CAOS Coding Cave (Discord)
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!