A Guide to Mac Agenteering
(17 Aug 2006)
This guide is presented, unedited except for a few links, from when it was published in 2006. It's mostly here for archival purposes. It's possible that some of it may be out of date.
I was invited to write a tutorial for the CCSF 2006, and I ended up going a little overboard! There has hitherto been very little information about developing agents on a Mac, but this (perhaps exhaustive) guide should cover everything you need to know. In fact, most of the stuff is cross-platform, so it may be worth a look no matter what platform you play Creatures on.
Table of Contents
- Make an Alias
- Get Your CAOS Guide
- Install the Tools
- Reserve Some Scripts
Look Smart with Sprites
- Come Up with a Concept
- Do Some Modeling
- Tweak the Images
- Create a Sprite File
Stick with the Script
- Get Ready to Test
- Your First Script
- Inject Your Agent
- Remove It Again
- Pick-Up Pose
- Back on the Floor
- Blow Some Bubbles
- Make Them Float
- Blow More Bubbles
- Touch-Up and Tweak
Time to PRAY
- Clean Up
- Create Agent Help
- Write PRAY Source
- Compile the Agent
- One Last Test
- Zip and Share
I. Get Prepared
1. Make an Alias
The first thing you need is gain access to the Creatures data files. Control-click (or right-click) the Docking Station app in your Applications directory and choose "Show Package Contents." From there, go to Contents/MacOS and make an alias (ctrl-click and choose "Make Alias") of the data folder there. You can put this alias on the desktop or wherever you like; it's just to make it easy to get at your agents, images, etc.
2. Get Your CAOS Guide
In Creatures, press control-shift-c to open the CAOS command line. This is where you can write code that immediately affects your game, but for now we'll just use it to generate the CAOS guide. Type:
file oope 1 "CAOS alphabetical.html" 0 dbg: html 0 file oclo
and hit return. Then type:
file oope 1 "CAOS categorical.html" 0 dbg: html 1 file oclo
and hit return again. In [Home]/Library/Preferences/Creature Labs/Docking Station/data/Journal, you'll find two html files. Open them in Safari (or your browser of choice) and you get a full listing of the CAOS commands, plus a lot of other useful stuff. This will be indispensable once you start making your own agents.
3. Install the Tools
Every agenteer needs his tool box. There aren't many Creatures development tools for the Mac, but a Java library called Jagent does the job admirably. First you need the latest version of Java, then go ahead and get Jagent. It includes Edos, a sprite editor, and Monk, a PRAY compiler and decompiler.
A solid text editor is also a must. You can use TextEdit, but make sure you go to the Format menu and select "Make Plain Text" whenever you work with Creatures files. I prefer to use a dedicated plain text editor like Visual Studio Code, which has cool features like tabbed editing.
To create good-looking graphics for your agents, you'll want to spend some time learning Blender, a 3D modeler, and the GNU Image Manipulation Program, a Photoshop-like image editor (which requires X11 be installed from your Mac OS X install disks).
If you want to make your own sound effects, you'll need a sound editor. Audacity will do nicely. I won't talk much about sounds later, so here's what you need to know: save files in WAV format, and give them four-character names (no more, no less, and no spaces; for whatever reason sound files alone suffer this filename limitation).
This may seem like a lot of programs to install, but each one pulls its weight. And best of all, they're all free!
4. Reserve Some Scripts
Before you start distributing agents, you need to reserve some script numbers. Every agent is uniquely identified by a classification number, and if yours uses a number already in somebody's world, it'll cause some weird things to happen. I'll talk more about classifiers later, but for now be aware that you'll need to reserve a range at some point. (UPDATE 2022 - I don't think anyone's maintaining a reservation list at this point, so just be aware of the classification numbers that are already being used out there.)
II. Look Smart with Sprites
1. 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 waste time drawing sprites you won't need. You should also start a folder dedicated to all the files for your agent, just to keep things nice and organized.
2. Do Some Modeling
As I said before, some of the best sprites begin their lives as 3D models. I obviously can't give you a full tutorial on how to model your agent here, but there are some tricks for making it look right in Creatures. You'll want a light shining behind your agent, one in the upper right corner (forward slightly), and a little dim blue- or orange-colored light in the bottom left for ambience (in Blender these can be simple lamps; you may have to adjust the intensities a bit). The camera should be set to orthographical so there's no perspective. Make the background completely black, then render and save each frame in PNG format. Don't worry about getting the size right as you'll need to do some post-render editing anyway.
3. Tweak the Images
Open your PNG's in your favorite image editor. First of all, resize the images until they're the right scale for your norns, and crop them if necessary. If your agent will animate or change pose at all, each of its sprites must be the same width and height. Select all the parts you want to be transparent and fill it in with some color you aren't using elsewhere in your agent, something like hot pink. With that same color, use the pencil tool (no fuzzy anti-aliasing) to smooth out any jagged edges. The next part is important: any parts of your agent that are black need to be replaced with a slightly off-black color. Creatures makes all true black pixels transparent, and you certainly don't want holes showing up in the game! GIMP's color-select tool is perfect for this. Finally, replace your hot pink with pure black -- these are the areas you actually want to be transparent.
4. Create a Sprite File
Now that your images are ready to go, you just need to save them in the correct format. Load up Edos (the sprite editor that comes with Jagent) and drag your finished PNG files one by one into the empty window that appears. Keep in mind what order the sprites are in, as you'll be referring to them by their number in the sequence, starting with zero. Go to the menu, choose File -> Save, and save it with a ".c16" extension.
... Or, if you're lazy and just want to get on with the tutorial, download the bubble blower kit and grab the C16 file contained therein.
III. Stick with the Script
1. Get Ready to Test
A copy of your finished C16 file needs to get into the [Creatures Data]/Images directory. In the [Creatures Data]/Bootstrap directory, make a new folder called "Testing". Scripts you put in there will run automatically when you load a world, so you'll want to move the folder out of the Bootstrap directory if you take a break from testing. For now, go ahead start (or restart) Docking Station and create a new world for agent testing purposes. From the Comms room, inject the Autonamer or any other agent you like -- this preps the world so you can manually inject your agent from the CAOS command line.
2. Your First Script
Create a new text file and save it as "test.cos" in [Creatures Data]/Bootstrap/Testing. Type in the following code (or just copy and paste it if you're lazy):
inst new: simp 2 21 999 "bubble blower" 5 0 1000 attr 199 *bhvr 33 elas 0 aero 2 fric 100 accg 3 perm 60 mvsf game "CreatorX" game "CreatorY"
This is a series of CAOS commands. I'm making a bubble blower as an example, but most agents will begin much the same way. Let's examine what each command does:
INST tells the game to run the rest of the script in a single tick, or unit of game time.
NEW: SIMP creates a new simple object, nothing fancy like vehicles or complex machinery. The classification number for this agent is 2 21 999: family 2 genus 21 is for toys, 2 11 for food, 2 23 for vendors, etc. The last number, 999 in this case, denotes the species -- it's this number that must be unique for each agent within the same family and genus. (Note: the species numbers I use here are for testing purposes only.) Next is a string, which is just a technical name for a piece of text enclosed in quotes. The string "bubble blower" is the name of the sprite file being used, without the ".c16" extension. The next two numbers mean that the agent will use 5 sprites starting with sprite 0 (remember that the numbering starts at zero). The last number determines what layer the agent lives on. Low numbers are closer to the background, while high numbers get drawn on top of other things. 1000 will be in front of your norns and 500 will be behind them -- feel free to experiment with this number!
ATTR sets the attributes for your agent. Each attribute setting has a number associated with it, and you just have to add up the numbers for the settings you want in order to get a single value for ATTR. In this case, 199 = 1 (can be carried by other agents) + 2 (can be picked up by the Hand) + 4 (can be activated by the Hand) + 64 (will collide with walls) + 128 (will be affected by physics). The CAOS guide has a complete listing of these attribute flags.
An asterisk marks the rest of the line as a comment, to be ignored by the game. This is important because BHVR determines what creatures can do with your agent, and the game won't inject the agent if required event scripts are missing. We'll remove the asterisk later. For now, know that BHVR uses the same add-up-the-numbers system as ATTR -- you will find this a lot in CAOS. The value 33 = 1 (creatures can push, or activate 1, the agent) + 32 (creatures can pick it up). Other flags include 2 (they can pull/activate 2 the agent), 4 (they can deactivate it), 8 (hittable), and 16 (edible).
The next five commands determine the agent's physical properties. ELAS is how bouncy or elastic it is, AERO is how greatly air friction affects it, FRIC is how much friction it has, ACCG is how heavy it is, and PERM determines what walls and floors it can hit. The values of ELAS, AERO, and FRIC are integers (whole numbers, no decimals allowed) between 0 and 100. ACCG's value is a float, which can be any positive, negative, or decimal number. PERM's value is an integer between 1 and 100, the lower the more permeable. Go ahead and experiment with these values. You might end up with some very wacky behaviors!
MVSF moves the agent to a new location. It gets two parameters, which normally looks like "mvsf [x] [y]". In this case, though, we want to put the agent next to the injector, for which the coordinates are handily stored in some game variables. Variables are like little boxes that store values for later. Creatures has many such boxes holding useful values like where the Creator (agent injector) is, and you use GAME to grab such a game variable and return its value. The variables we want are called "CreatorX" and "CreatorY", so we call GAME twice, and it fills in the coordinates of MVSF for us.
3. Inject Your Agent
Phew! Now we can finally see our new agent in action. Save your script, switch to Creatures, and hit control+shift+c to bring up the CAOS command line. Type:
ject "test.cos" 7
JECT will execute the script "test.cos". 7 is another one of those flag values, where 1 runs the removal script, 2 runs the install script, and 4 installs the event scripts (for a total of 7). We've only written the install script so far, but this'll work just the same. Press return and viola! Your first agent appears, ready to pick up and toss around.
4. Remove It Again
Since we will be re-injecting the agent a lot, we need to add a removal script. Add this code to "test.cos":
rscr enum 2 21 999 kill targ next
RSCR marks the beginning of the removal script. ENUM enumerates over all agents with the classifier 2 21 999, running the next chunk of code for each one. KILL destroys the agent identified by its parameter, which in this case is TARG, the currently targeted agent. NEXT marks the end of the ENUM code block.
5. Pick-Up Pose
Now it's time to add an event script. Insert some new code right above your removal script:
scrp 2 21 999 4 *pickup pose 1 endm
SCRP marks the beginning of an event script. The agent that owns this script is marked by the classifier (2 21 999), and the event we're looking at is number 4, the pick-up script. This script is run whenever you or a creature picks up the agent. POSE changes the agent's current sprite. We wrap it up nicely with ENDM, which ends the event script.
When you run JECT again, the old version will disappear and get replaced by this nice new version. Try picking it up!
6. Back on the Floor
You may notice that your agent doesn't change pose again when it's dropped. Fixing this bug is very simple, just by adding a new event script right after the last one:
scrp 2 21 999 5 *drop pose 0 endm
Event script number 5 is called when you or your creatures drop the agent. (There are many other script numbers listed in the CAOS guide, and we'll be using several more in this tutorial.) The default pose is 0, so to set it back when the agent is dropped, just use the command "pose 0". Simple, no?
7. Blow Some Bubbles
Now for the tricky part. This being a bubble blower, we want bubbles to actually appear when clicked. Add a new event script for script number 1, which is called when someone pushes the agent:
scrp 2 21 999 1 *activate 1 lock stim writ from 97 1 anim [1 2 3 4] over *** inst setv va01 posx setv va02 posy new: simp 2 21 1000 "bubble blower" 1 5 2000 attr 199 *bhvr 33 elas 0 aero 2 accg .1 fric 50 perm 60 mvsf va01 va02 *** targ ownr anim [1 0] endm
This looks rather complicated, but much of it isn't. LOCK just prevents the script from being called again while it's running, ensuring that norns don't activate it rapid-fire. STIM WRIT sends a stimulus to the creature that activated the agent, denoted by FROM. 97 is the stimulus for pushing a toy, decreasing boredom, with a strength of 1 (which is plenty). ANIM animates the agent through a series of sprites, blowing a bubble in this case, and OVER waits until the animation finishes before continuing.
The next chunk of code should look familiar. It creates a new agent, just like what we did in our install script. The only difference is the introduction of variables. SETV sets a local variable to some value -- local variables, denoted VA01, VA02, VA03, etc., only keep their values until the end of the current script. You use them to store information temporarily. If you want a variable to hold onto its value for the life of the agent, you'll want to use persistent variables, which are attached to the agent itself (not the currently running script), and are labelled OV01, OV02, etc. Also note that you can reuse VA's and OV's by re-assigning their values sometime later. Right now we're just assigning two local variables to the values of POSX and POSY, commands which return the current position of your agent. Later in the code, MVSF moves the newly created bubble to the same place as the bubble blower by referring to those local variables.
But why can't we just say "mvsf posx posy"? Well, up until NEW: SIMP, the owner of the script has been the targeted agent. Most commands, including POSX and POSY, refer to or act upon the currently targeted agent. Remember that in the removal script, ENUM changed the target for the duration of its code block. NEW: SIMP does this too, targeting the newly created agent until the end of the script. So "mvsf posx posy" would just move the bubble to where it already was, which was nowhere at all! We have to store the position of the bubble blower in variables before the bubble gets targeted.
You can also change the target manually by giving TARG a parameter (without a parameter it just returns the currently targeted agent). OWNR refers to the owner of the script, so we can go back to targeting the bubble blower and animate it falling down. Go ahead and inject this new version, and check out the awesome bubble-blowing action!
8. Make Them Float
Alright, so it isn't that awesome yet. The bubbles just fall to the floor and sit around. We need to add event scripts for the bubbles so that they float around and pop:
* BUBBLE scrp 2 21 1000 1 *activate 1 lock stim writ from 97 1 sndc "pop_" kill targ endm scrp 2 21 1000 4 *pickup tick 0 endm scrp 2 21 1000 5 *drop tick rand 1 15 endm scrp 2 21 1000 9 *timer velo rand -2 2 rand -2 0 doif rand 0 10 eq 0 sndc "pop_" kill targ endi tick rand 1 15 endm
These new event scripts are labeled with the classifier 2 21 1000, to mark their owner as the bubble agents rather than the bubble blower. There are some new CAOS commands here, too: SNDC plays a sound effect, the file named without the ".wav" extension. TICK starts a timer, its parameter determining how often the timer event script (script number 9) is called; "tick 0" turns the timer off. Instead of plain numbers, however, I've opted to use RAND, which chooses a random integer between two values.
VELO gives the agent some velocity, a jolt of speed, just what we need to keep our bubbles afloat. The syntax for VELO is "velo [x] [y]", but by using RAND we can make the bubble go randomly left or right, and give it a little push up once in a while.
DOIF executes a chunk of code only if some condition is true. The basic syntax of a condition is "[value 1] [comparison] [value 2]", where the comparison can be EQ (equal to), NE (not equal to), GT (greater than), and LT (less than), among others. ENDI marks the end of the DOIF code block. Look up DOIF in the CAOS guide sometime; you'll probably end up using conditionals a lot.
We want the bubbles to start floating right away, so we need to activate the timer when we create them. Add these two lines after "mvsf va01 va02" in the bubble blower activate 1 script:
velo rand -2 2 rand -2 0 tick rand 1 15
To remove all the old bubbles, add a little bit to the remove script:
enum 2 21 1000 kill targ next
There we go! Now our bubbles have some life to them. You can even remove the asterisks before the BHVR's now that the activate and pick-up scripts are in place, re-inject the agent, and give it to your norns to play with.
9. Blow More Bubbles
A great feature to add would be to make bubbles while you hold the agent, making it act more like a real bubble wand. Instead of keeping the bubble-making code in two places, we can make a new event script just for blowing bubbles:
scrp 2 21 999 1000 inst setv va01 posx setv va02 posy new: simp 2 21 1000 "bubble blower" 1 5 2000 attr 199 bhvr 33 elas 0 aero 2 accg .1 fric 50 perm 60 mvsf va01 va02 velo rand -2 2 rand -2 0 tick rand 1 15 endm
Event number 1000 isn't used by any actual game events, so it will only be called when we want it. (You can define your own events with any script numbers higher than 255.) Back in the bubble blower activation script, delete everything between the asterisks, plus the "targ ownr" line, and replace it all with a single line of code:
mesg writ ownr 1000
This, simply enough, calls event script 1000 on the OWNR agent. We use this trick again in a new timer script for the bubble blower:
scrp 2 21 999 9 *timer anim [2 3 4] over mesg writ ownr 1000 pose 1 tick rand 8 15 endm
We want to activate the timer when the agent is picked up and stop the timer when it's dropped, so we need to add a few things to our original pick-up and drop scripts:
scrp 2 21 999 4 *pickup pose 1 stim writ from 97 1 tick 5 endm scrp 2 21 999 5 *drop pose 0 tick 0 endm
See, wasn't that cool? We added a whole new feature with hardly any new commands! Now the bubble blower is a perfectly functional little toy.
10. Touch-Up and Tweak
We're not done yet! We'll want to sprinkle in some final lines of code to bring out the full flavor. You may have noticed, for example, that bubbles don't appear quite where they're supposed to. The SUBV command will take a variable and subtract some number from it (ADDV adds to the variable instead), so we can use it to adjust their initial position. Add this code after the two SETV's:
subv va01 7 subv va02 13
Next on the agenda is setting the pick-up point. Normally the Hand and creatures hold onto the top of the agent, but for the bubble blower it would look better if they held the stem. PUHL does the trick; the first parameter says which pose to set the handle for (-1 to set it for all sprites), and the next two are the handle's x, y coordinates. Insert the command after all those the physical properties in the installation script:
puhl -1 17 40
Lastly, we can make those plain bubbles really colorful by tinting them. TINT takes five parameters; the first three are the red, green, and blue values of a color (integers between 0 and 255), and the last two can just be set to 128 and ignored (they only matter for creatures). To give each bubble a different color, add this line after "mvsf va01 va02":
tint rand 130 200 rand 130 200 rand 130 200 128 128
Okay, now we're really, truly done with the script. But don't let that stop you from messing around with it! The best way to learn is by making mistakes.
... If you want a clean copy of the finished script, download the bubble blower kit and get "test.cos".
IV. Time to PRAY
1. Clean Up
Move your finished script, sprite, and sound files to your agent folder. You can keep the Testing folder around if you want, for the next agent you work on. If you're using a sound or sprite file that came with the game (like the "pop_.wav" I used in the bubble blower), you don't need to touch it -- you only need to distribute new files with your agent. Now rename "test.cos" to something more identifiable, like "bubble blower.cos", and you're on the home stretch.
2. Create Agent Help
Agent Help works by reading special text files with a ".catalogue" extension. Create a new text file in your agent folder, naming it something like "bubble blower.catalogue". Its contents will be a series of short text blocks like this:
TAG "Agent Help 2 21 999" "Bubble Blower" "This simple toy creates bubbles when held by a creature or the Hand."
You'll want one TAG block for each species number used in your agent.
3. Write PRAY Source
The PRAY compiler will take all your scripts, sprites, etc. and create a single handy ".agents" file. It does this by reading a PRAY source file, a simple text file listing all details and dependencies of your agent. Here's a simple template to follow:
"en-GB" group AGNT "[agent name}
" "Agent Type" 0 "Agent Description" "[agent description]" "Agent Animation File" "[sprite file with .c16 extension]" "Agent Animation Gallery" "[sprite file without .c16 extension]" "Agent Animation String" "0" "Remove script" "enum [classifier] kill targ next" "Script Count" 1 "Script 1" @ "[script file with .cos extension]" "Dependency Count" [total number of dependency files] "Dependency 1" "[filename with extension]" "Dependency Category 1" [file category number] "Dependency 2" "[another filename with extension]" "Dependency Category 2" [another file category number] [etc.] group DSAG "[agent name] " "Agent Type" 0 "Agent Description" "[agent description]" "Web Label" "[website name]" "Web URL" "[website address]" "Agent Animation File" "[sprite file with .c16 extension]" "Agent Animation Gallery" "[sprite file without .c16 extension]" "Agent Animation String" "0" "Agent Sprite First Image" 0 "Remove script" "enum [classifier] kill targ next" "Script Count" 1 "Script 1" @ "[script file with .cos extension]" "Dependency Count" [total number of dependency files] "Dependency 1" "[filename with extension]" "Dependency Category 1" [file category number] "Dependency 2" "[another filename with extension]" "Dependency Category 2" [another file category number] [etc.] inline FILE "[filename]" "[filename]" [etc.]
There are three main sections: information for Creatures 3, information for Docking Station, and a list of files to include in the compiled agent file. The inline files only need to be listed once at the end, but each information section has its own dependency list. A dependency is a C16, WAV, or catalogue file. The category number identifies what kind of file it is: 2 for images, 1 for sounds, and 7 for catalogue files.
... A sample PRAY source file for the bubble blower can be found in the bubble blower kit.
4. Compile the Agent
It's finally time to compile your agent. Make sure all your files are in the same folder, otherwise they won't get included in the finished product. Load up Monk ("PRAY chunk" should be selected), drag your PRAY source file onto the blue box, and with any luck you'll have a shiny new agent file waiting in your folder! Kind of anticlimactic, isn't it?
5. One Last Test
It's a good idea to test the final agent file before you distribute it. Delete any files that are supposed to be included from the Creatures data folders, then place the ".agents" file in the [Creatures Data]/My Agents directory. Start (or restart) Docking Station and load any world you like. Go to the Creator and find your agent, then inject it. Does it work? Good!
The Agent Help, however, will not work automatically on a Mac. For whatever reason, catalogue files are put in the [Home]/Library/Preferences/Creature Labs/Docking Station/data/Catalogue directory instead of the [Creatures Data]/Catalogue directory. Just copy your catalogue file from one to the other, and reload your world.
6. Zip and Share
Congratulations! Your agent is ready to share with the world! Drag your ".agents" file into YemuZip, and save the ZIP file with the rest of your agent stuff. If you don't have your own website on which to post your agent, Creatures Caves will let you upload it to theirs. Don't worry that you made it on a Mac -- no one will ever know! It will work just fine on Windows and Linux, too.
V. Moving On
So now that you're an agenteer, what will you do next? You can find more info and tutorials on the Creatures Wiki. If you feel particularly brave, you can delve into the various Bootstap folders that contain the scripts for the original games. You can even decompile other people's agents to see what they're made of -- open Monk, select "PRAY source", and drag the ".agents" file into the blue box.
There are plenty of resources out there, and not nearly enough cool agents: so go forth, agenteer, and show the world your stuff!
Thanks to Moe, Spook, RProgrammer, and Malkin!