Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  

Author Topic: PSA: How creature variations work  (Read 2206 times)

voliol

  • Bay Watcher
    • View Profile
    • Website
PSA: How creature variations work
« on: October 30, 2021, 03:01:20 pm »

The Dwarf Fortress wiki is not always complete. This is not unexpected when it comes to such a massive game nor a wiki, and as this lack of information affects all parts of the wiki it also means there are some holes when it comes to modding information. One such hole is the article on  creature variations. In this PSA I will compound both well documented information (from the wiki/vanilla raws) and "new" information (my own observations, from reading other people's raws* and confirming it with !science!). As it turns out, creature variations have several functions that are mostly/fully undocumented, and thus likely underutilized.

Creature variations are templates that creatures (CREATURE objects) may use.

Creature variations are not the only kind of templates for creatures, there are also tissue templates (TISSUE_TEMPLATE objects using tissue definition tokens, material templates (MATERIAL_TEMPLATE objects using material definition tokens), and body detail plans (BODY_DETAIL_PLAN objects using body detail plan tokens). Creature variations are the newest one of these, from 2009, and also the most advanced of the four. The reason they are called "creature variations" is presumably because they were initially made for the giant animals and animal people, variations of existing creatures, but this name is misleading. Creature variations are very general type of template, and creatures using creature variations do not need to be based on any other like the giant animals and animal people are. More examples will be given below, but creature variations are already used in the vanilla raws for gaits and (sometimes) attacks.

Chapter 1 - How to use creature variations, and their basic tokens:
Creature variations may be used in two ways. They may either appear as fully fletched CREATURE_VARIATION objects in their own files (the default being c_variation_default.txt) and called using APPLY_CREATURE_VARIATION, or their tokens may live "freely" inside creature raws and called use APPLY_CURRENT_CREATURE_VARIATION. The latter is for when you would like to use the powers of creature variations, like removing tokens or "converting" parts of them, without having to define a new object for it. There are 11 creature definition tokens (not counting those applying them, they are creature tokens, being called on the creature level), but almost half of them are copies of the other with the difference that they are "conditional" (see Chapter 2), and as three of them are there for the completion of another one (and it's conditional twin), really there are only 3 functions performed by the creature variations: adding tokens, removing tokens, and "converting" tokens.

Adding tokens is done using CV_NEW_TAG or CV_ADD_TAG. CV_NEW_TAG takes any token (with arguments) as its own argument and adds it to the target creature. CV_ADD_TAG is seemingly an alias for CV_NEW_TAG, so it is unclear why they both exist. E.g. [CV_NEW_TAG:BIOME:ANY_FOREST] gives the creature [BIOME:ANY_FOREST].

Removing tokens is done using CV_REMOVE_TAG. CV_REMOVE_TAG takes whole token (names and) arguments, and removes tokens that start that way. So [CV_REMOVE_TAG:BODY:HUMANOID_SIMPLE] would remove [BODY:HUMANOID_SIMPLE:3_EYES], but [CV_REMOVE_TAG:BODY:3_EYES] would not. Neither would [CV_REMOVE_TAG:BODY:HUMANOID_SIMPLE] be able to remove [BODY:HUMANOID_SIMPLE_NECK:3_EYES], as it looks for whole arguments. [CV_REMOVE_TAG:BODY] would remove all examples above, as they start with "BODY".

"Converting" tokens is done using CV_CONVERT_TAG, CVCT_MASTER, CVCT_TARGET, and CVCT_REPLACEMENT. These are used in a block, with one of each in each block. CV_CONVERT_TAG starts the block. CVCT_MASTER selects which tokens may be converted, by looking at full arguments at the start of said token (like CV_REMOVE_TAG). If no CVCT_MASTER is given, it is given no arguments, or the only argument it is given is blank (i.e. [CVCT_MASTER:]), all tokens of the target creature are selected.
CVCT_TARGET and CVCT_REPLACEMENT are a search-and-replace for strings within the selected tokens. This means the targeted part of a token can be changed anywhere in the token, so e.g.
Code: [Select]
[CV_CONVERT_TAG]
[CVCT_MASTER:BODY]
[CVCT_TARGET:2EYES]
[CVCT_REPLACEMENT:2EYESTALKS]
would affect both [BODY:QUADRUPED_NECK:2EYES:NOSE:2LUNGS:...] and [BODY:INSECT:2EYES:HEART:GUTS:BRAIN:MOUTH:2WINGS], converting them into [BODY:QUADRUPED_NECK:2EYESTALKS:NOSE:2LUNGS:...] and [BODY:INSECT:2EYESTALKS:HEART:GUTS:BRAIN:MOUTH:2WINGS] respectively.
Colons can be included as part of both the target and the replacement string, e.g. given
Code: [Select]
[CV_CONVERT_TAG]
[CVCT_MASTER:BODY]
[CVCT_TARGET:BASIC_1PARTBODY:BASIC_HEAD]
[CVCT_REPLACEMENT:HUMANOID:3FINGERS]
and [BODY:BASIC_1PARTBODY:BASIC_HEAD:HEART:GUTS:BRAIN:MOUTH:2EYESTALKS], you will get [BODY:HUMANOID:3FINGERS:HEART:GUTS:BRAIN:MOUTH:2EYESTALKS].
All occurrences of the target string are replaced, e.g. given
Code: [Select]
[CV_CONVERT_TAG]
[CVCT_MASTER:DESCRIPTION]
[CVCT_TARGET:TRAIT]
[CVCT_REPLACEMENT:modderiffic]
and [DESCRIPTION:This is an example creature. It is TRAIT, very very TRAIT.], you will get [DESCRIPTION:This is an example creature. It is modderiffic, very very modderiffic.].
If no CVCT_TARGET is given, it is given no arguments, or the only argument it is given is blank (i.e. [CVCT_TARGET:]), the game will freeze when loading the creature.
If no CVCT_REPLACEMENT is given, the target string is simply removed.

Creature variations have an unusual order of application. First, remove tokens are applied (bottom-up according to Toady's notes, but I don't think this could affect anything). Then, convert tokens are applied bottom-up (in "reverse" order). Finally, add tokens are applied from the top. This means that CV_REMOVE_TAG won't remove any token added by the same creature variations. It is also why more general conversions can (must) be higher up when overlapping CVCT_MASTERs are used. If they were not read bottom-up, e.g.
Code: [Select]
[CV_CONVERT_TAG]
[CVCT_MASTER:BODY]
[CVCT_TARGET:QUADRUPED]
[CVCT_REPLACEMENT:HUMANOID]
would convert [BODY:QUADRUPED_FRONT_GRASP:...] and [BODY:QUADRUPED_NECK:...] into [BODY:HUMANOID_FRONT_GRASP:...] and [BODY:HUMANOID_NECK:...] respectively, before
Code: [Select]
[CV_CONVERT_TAG]
[CVCT_MASTER:BODY]
[CVCT_TARGET:QUADRUPED_FRONT_GRASP]
[CVCT_REPLACEMENT:HUMANOID]
[CV_CONVERT_TAG]
[CVCT_MASTER:BODY]
[CVCT_TARGET:QUADRUPED_NECK]
[CVCT_REPLACEMENT:HUMANOID_NECK:3FINGERS]
could convert them into the expected [BODY:HUMANOID:...] and [BODY:HUMANOID_NECK:3_FINGERS:...].

APPLY_CURRENT_CREATURE_VARIATION takes all creature variation tokens before it in the creature raws (and after previous APPLY_CURRENT_CREATURE_VARIATION tokens, if they exist) and applies them. When tokens are added through APPLY_CURRENT_CREATURE_VARIATION, they are added in the place of APPLY_CURRENT_CREATURE_VARIATION.


Chapter 2 - Arguments and conditional tokens:
APPLY_CREATURE_VARIATION may be given arguments. These arguments will replace instances of "!ARGn", where n is the index of the argument given to APPLY_CREATURE_VARIATION; the first argument will replace any "!ARG1", the second any "!ARG2" and so on. You may use any number of arguments**.
If you have an "!ARGn" of a higher number than the argument given the replacements will act oddly, depending on if n has more digits than the number of arguments given. E.g. [APPLY_CREATURE_VARIATION:EXAMPLE_CV:one:two:three], which has three arguments given, will leave all "!ARG5" in EXAMPLE_CV intact as "!ARG5", but "!ARG10" will become "one0".

The pipe character "|" is turned into ":" when inserted, so single arguments in APPLY_CREATURE_VARIATION may be turned into multi-argument segments in the output. E.g. given
Code: [Select]
[CREATURE_VARIATION:DIMORPHIC_FEATHER_COLORS]
[CV_NEW_TAG:SELECT_CASTE:FEMALE]
[CV_NEW_TAG:SET_TL_GROUP:BY_CATEGORY:ALL:FEATHER]
[CV_NEW_TAG:TL_COLOR_MODIFIER:!ARG1]
[CV_NEW_TAG:TLCM_NOUN:feathers:PLURAL]
[CV_NEW_TAG:SELECT_CASTE:MALE]
[CV_NEW_TAG:SET_TL_GROUP:BY_CATEGORY:ALL:FEATHER]
[CV_NEW_TAG:TL_COLOR_MODIFIER:!ARG2]
[CV_NEW_TAG:TLCM_NOUN:feathers:PLURAL]
[CV_NEW_TAG:SELECT_CASTE:ALL]
and [APPLY_CREATURE_VARIATION:DIMORPHIC_FEATHER_COLORS:BROWN|1:BLUE|10|GREEN|1|BLACK|1] we get
Code: [Select]
[SELECT_CASTE:FEMALE]
[SET_TL_GROUP:BY_CATEGORY:ALL:FEATHER]
[TL_COLOR_MODIFIER:BROWN:1]
[TLCM_NOUN:feathers:PLURAL]
[SELECT_CASTE:MALE]
[SET_TL_GROUP:BY_CATEGORY:ALL:FEATHER]
[TL_COLOR_MODIFIER:BLUE:10:GREEN:1:BLACK:1]
[TLCM_NOUN:feathers:PLURAL]
[SELECT_CASTE:ALL]
as the tokens added to the target creature.

The conditional tags (CV_NEW_CTAG/CV_ADD_CTAG, CV_REMOVE_CTAG and CV_CONVERT_CTAG) are copies of CV_NEW_TAG/CV_ADD_TAG, CV_REMOVE_TAG and CV_CONVERT_TAG, except they only work if a numbered argument of APPLY_CREATURE_VARIATION has an arbitrary value. E.g. [CV_NEW_TOKEN:2:HUMANOID:CAN_SPEAK] will only add [CAN_SPEAK] if argument number two is "HUMANOID".
CV_CONVERT_CTAG still uses CVCT_MASTER, CVCT_TARGET, and CVCT_REPLACEMENT.
 

Epilogue:
Hopefully, that should be enough, a complete description. Reiterating what is written in the header/intro/preface, the wiki article on creature variations is at the time of writing not perfect. It is at the best of times incomplete, not explaining CV_CONVERT blocks are string-based, and at the worst of times incorrect or misleading, claiming "YES" is always the value to be matched in conditional tokens, or creature variations having to be based off other creatures. How rough it was was something I discovered during my own modding, but I doubt I was the first to, and I am sure other modders have discovered some of the claims made above before (since I learned some of it from other people's raws). The reason for this PSA is of course to bring information about how creature variations work, as the wiki article does not fulfill that purpose.
I have attempted to be rigorous both in testing and in presentation, but as with any !science!, mistakes can not be ruled out. I encourage anyone to verify my claims on their own, so these possible errors aren't perpetuated. In any case playing around with these functions should be enjoyable.

Some tokens are not creature variation tokens, but often used in conjunction with them, such as COPY_TAGS_FROM and GO_TO_START. I am leaving them aside now though, as I feel their descriptions on the wiki are more complete, and should they not be, that !science! to further investigate them I feel falls outside the scope of making this PSA focused on creature variations. What should be known though is that COPY_TAGS_FROM copies tokens from other creatures, and the three GOTO tokens change where tokens are inserted, also by creature variations. It is likely they were introduced along with creature variations, but I would like to stress that even if creatures using COPY_TAGS_FROM gave birth to the need of creature variations, and are the reason behind the name, creature variations are not the creatures, but the templates they use. And these templates can be used for much more than just that. I hope you have learned some from this, and regardless, thanks for reading!


*Special thanks go to Hetsin!
**Functionally. I tested up to 65537=216+1, with no problems other than a long load time. My bets are on the actual limit being 264 in 64-bit versions of Dwarf Fortress.

Mobbstar

  • Bay Watcher
  • aka Mossbird
    • View Profile
    • my website
Re: How creature variations work
« Reply #1 on: October 31, 2021, 03:26:25 am »

Thank you for the very concise manual.  It even fit on one page!  Overall, the splendid source of information.

If I understand correctly:
  • Multiple creature variations can be used in sequence, in the usual top-to-bottom order.
  • Conversion can affect any token, including those previously added or converted by other variations.
  • Therefore, it is possible to add or convert other APPLY_CREATURE_VARIATION tokens (if they haven't been applied yet).

Did you have any problems with recursion during your experiments?  e.g.
Code: [Select]
[CV_CONVERT_TAG]
[CVCT_MASTER:BODY]
[CVCT_TARGET:HUMANOID]
[CVCT_REPLACEMENT:HUMANOID_NECK]

voliol

  • Bay Watcher
    • View Profile
    • Website
Re: PSA: How creature variations work
« Reply #2 on: October 31, 2021, 05:56:15 am »

Thank you for the very concise manual.  It even fit on one page!  Overall, the splendid source of information.

If I understand correctly:
  • Multiple creature variations can be used in sequence, in the usual top-to-bottom order.
  • Conversion can affect any token, including those previously added or converted by other variations.
  • Therefore, it is possible to add or convert other APPLY_CREATURE_VARIATION tokens (if they haven't been applied yet).

Did you have any problems with recursion during your experiments?  e.g.
Code: [Select]
[CV_CONVERT_TAG]
[CVCT_MASTER:BODY]
[CVCT_TARGET:HUMANOID]
[CVCT_REPLACEMENT:HUMANOID_NECK]

Both 1. and 2. are correct, at least for the tokens I've tested. As for 3. I'll have to look into it... turns out the answer is no, you can't add, remove, or convert APPLY_CREATURE_VARIATION, at least not without using some strange undiscovered loophole, but probably not at all. This also means there is one example of 2. not being true, so there could be more of them... Looks like creature variations also can't target COPY_TAGS_FROM, as in the token itself, not the tokens that are copied over.

I have had no recursion problems, though I suspect the freeze with an empty CVCT_TARGET could be one. Also, if you already have "HUMANOID_NECK", applying your example will give "HUMANOID_NECK_NECK", so that's worth looking out for.

Hetsin

  • Bay Watcher
    • View Profile
Re: PSA: How creature variations work
« Reply #3 on: December 13, 2021, 04:47:07 am »

There is a small PSA I'd like to add, in regards to stability.

As of 47.04, the 64-bit version will start crashing after a certain number of either creature variations have loaded or have been applied, I'm not sure which is the case. While developing my custom mod the utilizes CVs very heavily, the more CVs I applied to the sum total of creatures, the more unstable the game became while loading (arena and world creation). I have long passed the point where the game doesn't CTD.

However! The 32-bit version will load the exact same raws without issue, if slowly. I did an amateurish trace on the issue and my interpretation was that it led to a function that wasn't fully updated to 64 bit. It was a basic copying function, IIRC - it's been a while. I did do a bug report on Mantis, but since it's a modding issue I'm not holding my breathe.

TL;DR: Don't use an absurd amount of CVs in 64-bit DF without flattening the raws (I recommend DF Diagnosipack's CVunpack tool).

Addendum: IIRC, because I had to make this a workaround in my modding, it seems CV_CONVERT does not respect SELECT_CASTE if the SELECT is before it or after it. This may have changed or I messed up token orders some how, but my dimorphic creatures needed to have a gender specific token in a caste specific BODY that the CONVERT could latch on to for horns, tusks, etc.
« Last Edit: December 13, 2021, 05:12:45 am by Hetsin »
Logged