Thursday, January 4, 2018

CAOS Notes: FACE, LIMB, and a little CHAR

Lately I've felt like I've wanted to write a little more in-depth about certain CAOS commands and techniques. I don't really have an order or priority for these things, so my plan is to just work on my stuff normally, and if in my CAOSing travels I come across something that might be of use to other people, I'll try to write about it in the clearest manner that I can.

The Conundrum 

Like a lot of things I look to develop, this one seeks to solve a specific problem. Take a look at little Miss Baker here, a survivor from my last batch of SERU creatures. She's got a lovely Dustdevil Grendel head and a fierce personality, but she's actually a norn, according to her genus. I decide to export her and bring her into a world with more of her kind, but what's this?

When I go to import her, I don't see the face I expected! Instead, there's a Harlequin face where a Grendel face should be! This seems to be an unfortunate bug in the creature import script. I could have sworn that there was a patch for this, somewhere, at some point, but I haven't for the life of me been able to find it. Maybe I imagined it, but if anyone can find the original fix for this and who did it first, I'd like to credit them. Update: This fix is among one of the many enhancements included in Apollo's GUI Update! But in the meantime I thought I'd write my own fix and document exactly why it works in the process.

About FACE

Before we get into the import code itself, let's take a quick look at the FACE command. There are a number of versions of FACE, but the one we're looking at here is the string version:

You really only need to worry about the highlighted bit here because the rest of the command was never implemented. This is pretty straightfoward-- you TARG a creature, and then FACE will equal the filename of the headsprite in its baby form.

As an example, this simple command prompts all creatures to proudly say their (baby) head sprite filenames. FACE is a unique command in that it's the only command (to my knowledge) that actually gets any information about an actual living creature's actual sprites at all. (It's a little frustrating because I personally would love to be able to get information about the rest of a creature's body parts, but sadly the head sprite information seems to be the only thing we can get). 

When a creature gets exported, a lot of information about it gets saved to its prayfile, including its FACE sprite filename (in "Head Gallery"), genus, gender, and life stage. This is the information that the import script looks for when it goes to import a creature. Before we get too deep into that though, let's look at another way to get a sprite filename.

Looking at LIMB

LIMB differs from FACE primarily in that it can return the filename of any body part, but it can only return them when it is given the exact parameters of what to return. It cannot return the filename of a part of an actual living creature.

You might be tempted to reference the Sprite file format to figure out which parameters to stick where to get want you want, but LIMB actually does things a little differently. All the parameters must be integers, so you can't rely on using 'a' for the head or 'c' for the breedslot. The conversion, thankfully, is just a matter of using integers 0-25 instead of a-z

Additionally, you'll notice that genus and gender are separate parameters, while the breed filenames combine the two into one. With all these differences, it might just be easier to reference a table like this to find the numbers you need when looking to define LIMB:

So for example, LIMB 1 1 3 4 1 would return the filename for the sprite containing the body of a norn who is female, of adult age, and in slot B. If you wanted the head sprite of an old male banshee grendel, you'd use LIMB 0 2 1 5 1. All in all, LIMB is pretty straightforward, but its star feature is its ability to approximate. If you enter a slot that a breed doesn't exist in, or look for baby sprites in a breed that has no baby sprites, LIMB will return the closest match, much like what happens when you send a treehugger norn to a friend who might not have treehuggers installed.

If' you're following closely, you might already be able to guess what the problem is with the import script. Let's take a look.

This looks pretty straightforward, right? In this script, ov99 refers to the exported creature, and you can see that the LIMB parameters are being pulled from the PRAY information. Genus, gender, and life stage are set in variables that are used to find the face sprite with LIMB in the very last line.

If you can already see the problem, be patient one moment while we talk about what's going on in the middle there, where va04, the breed slot, is being set. After all, we can get the breed slot letter from the head sprite filename, but remember that LIMB takes numbers, not letters. CHAR holds the solution to that conversion.

Cheers For CHAR

Before delving into this script, I don't think I had ever even used CHAR, not once! At a glance, it's a pretty straightforward.

Makes sense, right? So if you used CHAR "norn" 2 you'd get 'o', right? That was my first instinct, as someone with very little programming experience outside of CAOS. But actually, you get 111. CHAR does not return the actual character; instead, it returns the ASCII decimal code of that character.

You can find a nice ASCII chart and lookup tool here, but you don't necessarily need it to understand why this is useful. In the import script above, you can see that va04 is being set to the fourth character of the head sprite filename, which is the breed slot. Now that va04 contains the breed slot, or at least, the decimal code for the breed slot, the final line subv va04 'a' subtracts the decimal code for 'a' from the decimal code for the breed slot, leaving you with the number between 0 and 25 that LIMB is looking for!

If you're not quite getting this, it can help to know that the decimal code for 'a' is 97, the code for 'b' is 98, and so on. If you have the code for 'c' (99) and subtract the code for 'a' (97), you'll get 2, which translates to breed slot C as far as LIMB is concerned. You can use this same trick to convert the body part letters to numbers if you need to.

Thank you for holding out through that little detour. Now let's get back to the import script and finding our problem.

The Guilty Genus

Let's recap really quick. When we export a norn with a grendel head, the import dialogue shows her face as being that of a norn instead of a grendel. Have you glimpsed the bug?

That's right. The import script is getting the genus parameter for LIMB from the creature's genus instead of the genus the sprite is using. So in the case of our dustdevil-headed norn, the import dialogue is looking for slot X in the norn genus (which it approximates as the harlequin's O since I haven't added any other norn breeds to this install) instead of the grendel genus, where the dustdevils reside.

To fix this, we need to get the genus from the head sprite filename instead of the creature itself. According to the breed sprite naming convention, the second character of the filename holds information about both the genus and the gender of the creature. To find just the genus, all we need to do is subtract 4 from it if it's a girl, and then add 1 to it, to make up for the fact that LIMB requires genus indices to start at 1. The repaired script looks something like this:

And our beloved miss Baker can display her grendliness proudly:

If you're feeling audacious, try applying this fix to your own file yourself! Otherwise, you can just download the Import Faces Patch here. It's a cosfile meant to be dropped in the bootstrap folder.

Whew, I know that was a little long winded, but I hope this makes some things clearer regarding these CAOS commands. See if you can get creative with FACE and LIMB! Pilla's using them to make spooky ghosts of the dead!

If you have any questions, got confused at any point, or have any insights, corrections, or things that I missed, please leave a comment and let me know! Furthermore, if there's any CAOS commands or techniques in particular that you would like to see explained or clarified, let me know too. I can't make any promises that I'll get around to replying to them as I've got a lot on my plate already, but sometimes getting inquiries like that can help to inspire me out of a rut, so it never hurts to ask!