Figured I would put up a little "guide" to the wrapper script, and how to use it.
The main function of wrapper.lua is to be able to select targets for interactions with more options than provided by the in-game system. The basic structure of the command to use the script is
wrapper -userSource UNIT_ID -userTarget UNIT_ID -script [ script information goes in here, see examples below ]
These are the only required inputs, where -userSource is the unit doing the interaction and -unitTarget is the target unit that is first receiving the interaction (i.e. the target that the game first picks out when running an interaction).
For an example, lets look at a simple projectile script.
modtools/interaction-trigger -onAttackStr "shoots a bolt of steel" -command [ special/projectile -unit_source \\ATTACKER_ID -unit_target \\DEFENDER_ID -item AMMO:ITEM_AMMO_BOLTS -mat STEEL -number 1 ]
This will cause the unit performing the interaction to "shoot" a steel bolt at the target. For the exact same results using the wrapper script we would use.
modtools/interaction-trigger -onAttackStr "shoots a bolt of steel" -command [ wrapper -unitSource \\ATTACKER_ID -unitTarget \\DEFENDER_ID -script [ special/projectile -unit_source !SOURCE -unit_target !TARGET -item AMMO:ITEM_AMMO_BOLTS -mat STEEL -number 1 ] ]
Notice that the -unit_source and -unit_target have changed now that they are inside the wrapper's -script. This is an important change, because it allows for some of the more interesting options that I will mention later.
So far we haven't gained anything from using the wrapper script. Both of the above examples will preform exactly the same. So now let's talk about what makes the wrapper script so useful. Options! The following is a list of currently available options;
-chain
-maxtargets
-delay
-value
-radius
-target
-aclass
-acreature
-asyndrome
-atoken
-iclass
-icreature
-isyndrome
-itoken
-physical
-mental
-skills
-traits
-age
-speed
-noble
-profession
-entity
-reflect
-silence
-counters
-plan
-center
You can basically split all of these options into four categories, Number Based, Token Based, Target Manipulation, and Script Manipulation
1. Number Based
The number based options are
-age
-speed
-physical
-mental
-skills
-traits
Each of these options has the requirements min, max, greater, less. Min and max are straight forward, they tell the script that for a target to be acceptable they must have a minimum or maximum amount of a certain type.
Greater and less perform slightly differently. They take the ratio unitSource/unitTarget and compare it to a given value. Examples to follow
These can further be broken down into two separate groups
i. No sub-types
These are -age and -speed. They don't have any sub-types associated with them and so have the format
-age min:10
This means that the script will only accept the target if it is older than 10. Multiple requirements for the same option can be included for more configuration. For example
-age [ min:10 max:20 ]
This will only accept the target if they are older than 10 but less than 20 years old.
ii. Sub-Types
The rest of the number based options all require an additional input of a sub-type. This takes the form
-physical STRENGTH:min:2000
Which should be fairly straightforward. So, for instance, if you would like an interaction to affect the target only if the user is twice as strong as the target you would use
-physical STRENGTH:less:0.5
Or only if the user is at least as strong as the target, and the target isn't super tough
-physical [ STRENGTH:less:1 TOUGHNESS:max:2000 ]
The possibilities are endless (ok not actually endless, but there are a LOT of possibilities). A full list of sub-types for each option is available on my github
Token Based
The token based options are
-aclass
-acreature
-asyndrome
-atoken
-iclass
-icreature
-isyndrome
-itoken
-noble
-profession
-entity
These can further be broken up into two groups
i
-noble, -profession, and -entity all require an additional input, namely 'required' or 'immune'. So to make an interaction that can only target your leader you would use
-noble required:MONARCH
Nothing particularly fancy about these. Just like the number based options, multiple specifications can be placed, so if you would only like an interaction to target carpenters or masons
-profession [ required:CARPENTER required:MASON ]
ii
The rest do not need the 'required' or 'immune' designation, as it is already built into their function (this was done for several reasons that I would be happy to discuss with people, but for now it is just how it is). As you can probably guess all of the i* options are the immune versions, and the a* options are the required (or allowed as the a stands for in this case) versions.
-aclass and -iclass check the units [CREATURE_CLASS:] tokens and subsequently allow or deny a creature to be targeted. They can be invoked by using
-aclass GENERAL_POISON
-acreature and -icreature check the actual creature and caste to see if the unit can be targeted. They are used with
-icreature [ DRAGON:MALE DRAGON:FEMALE ]
-asyndrome and -isyndrome check for any actives syndromes [SYN_CLASS]. Used just the same as -aclass and -iclass.
-atoken and -itoken, these are probably one of the more interesting options, they check the unit for a myriad of a number of tokens ranging from FLIER to MEGABEAST to AMPHIBIAN, basically anything that is specified as a single token in the creatures raws. A full list of supported tokens can be found on my github.
Note that none of these options are required in any way, and the logic behind using them is the same as the in-game logic behind the ALLOWED and IMMUNE options in interactions.
** There is another token based option that just needs a little bit more work/testing before it is implemented, and that is body checking. Basically it will be possible to check if a creature has a tail, or horns, or whatever you want, and will allow a spell to only target them/not target them based on these parts. (For instance you could have an interaction that a creature with a shell is immune to, or one that requires the target to have a stinger, and if the stinger is cut off, the creature is no longer targetable)
Target Manipulation
Now we get into the more advanced options. These options are
-radius
-plan
-maxtargets
-target
-reflect
-silence
Each one is fairly different, so lets take them one at a time.
-radius allows for selecting multiple targets in a given area around the -unitTarget. This means that you could have all units within 10 tiles, all units in a single square, or all units in a line be effected. The default value for this is -1,-1,-1 which means just the -unitTarget is effected. Change this by using
-radius 10,10,0
Which, as you might guess, is the radius around which a unit can be affected (in the typical x,y,z coordinates).
-plan functions similarly to -radius but allows for more interesting shapes. It requires an external text file, located in the hack/scripts folder, for instance my example allows units within an X pattern of the -unitTarget to be affected. 0's mean not allowed, 1's are allowed, and the 'X' is the location of the -unitTarget. Note that this currently only supports the current z-level of the -unitTarget
1,0,0,0,1,
0,1,0,1,0,
0,0,X,0,0,
0,1,0,1,0,
1,0,0,0,1
This option is invoked by using
-plan 5x5_X
-maxtargets is useable with -radius and -plan to limit the number of targets that can be selected. If no -maxtargets option is selected, all the targets found will be targeted, otherwise a random sample, the size of -maxtargets will be selected from the list of available targets. This option is used by specifying
-maxtargets 10
-target is a rather difficult to use option, I have altered the logic behind this option more times than I can count, and am still not entirely happy with it. The gist of the option is to allow configurable targeting based on the relationship between the -unitSource and -unitTarget. The valid options for -target are
invasion
civ
population
race
sex
caste
enemy
Which, if you know how DFHack structures are enumerated you will see that there are id numbers associated with each creature for each of these options (except for enemy, which is basically just the inverse of civ).
-target civ
This would mean that only creatures that have the same civ_id as the -unitSource are eligible for targeting. More work needs to be done on this option, but for now these are the only options available.
-reflect and -silence both take [CREATURE_CLASS] and [SYN_CLASS] tokens as their arguments, but check differently.
-reflect checks the -unitTarget's creature classes and any active syndrome classes, and if any are found to match the given token the -unitTarget will be changed to be the -unitSource, and as long as the -unitSource passes the other options, the script will treat the -unitSource as the -unitTarget and the -unitTarget as the -unitSource (for functions where both are needed to be different, like special/projectile). An example would be;
-reflect [ REFLECT_FIRE REFLECT_ELEMENTAL REFLECT_ALL ]
-silence checks the -unitSource's creature classes and any active syndrome classes, and if any are found to match the given token the interaction simple won't be cast, effectively "silencing" the unit (or disabling if you prefer not to think of the classic magic system).
-silence SILENCE_ALL
Script Manipulation
The final group of options are, possibly, the most unique.
-chain
-center
-delay
-value
-chain allows for "chaining" of spells. By default spells do not chain (i.e. -chain 0), but say you want the steel bolt from the above examples to hit the first target and then hit another target (from the acceptable target list) you would use
-chain 1
Note that this means you MUST HAVE a -radius or -plan option specified, otherwise it will just continually hit the same target (as there is no one else to chain to). Also note that by default this example
-radius 5,5,5 -chain 1
Will hit all units within a block of 5x5x5 around the target AND then each one of those will chain to another target (thus if there are 5 illegible units it will target all 5, then each of those 5 will chain to a new set of units within 5x5x5 of them). To change this behavior so that it still checks the targets in range, but only actually hits the -unitTarget, you must use the -center option, so that
-radius 5,5,5 -chain 1 -center
Would only hit the -unitTarget and then select a random unit from those otherwise illegible to hit next.
-center forces the script to ignore any previous options and only target the -unitTarget (note that it still keeps a list of otherwise illegible targets for use in other options, like -chain).
-delay simply delays the effect of the script by a specified amount of in-game ticks.
-delay 100
This would tell the wrapper script to calculate all of the illegible targets now, but wait to apply the actual affect for 100 ticks.
-value, this is personally my favorite option, and probably the most complex. It effectively allows you to pass different arguments to scripts based on the units targeted and unit using the interaction. My go-to example is if you want your warrior to have a "battle shout" type ability that gives their willpower to all nearby friendly units you can do it with this option.
To break it down, this option required four different specifications
TYPE:SUB_TYPE:VALUE:OFFSET
There are 4 valid types stacking, destacking, self, and target. Stacking and destacking form one group of types and self and target form another.
Valid sub types for stacking and destacking are; total, allowed, and immune
Valid sub types for self and target are; strength, agility, endurance, toughness, resistance, recuperation, analytical, focus, willpower, creativity, intuition, patience, memory, linguistic, spatial, musicality, kinesthetic, empathy, social, web, stun, winded, unconscious, pain, nausea, dizziness, paralysis, numbness, fever, exhaustion, hunger, thirst, sleep, infection, and blood
Stacking and destacking work by checking the targets list and manipulating the value based on the number of targets. It starts with the given value and increases it by the offset. So, for example, if you wanted to give a value of 100 + 10 for each creature targeted you would use
-value stacking:allowed:100:10
destacking works the same way, except it decreases the value by the offset instead of increases.
Self and target work by taking the -unitSource or -unitTarget's value for a given sub type, taking a percentage of that value and then increasing or decreasing it by a given offset. Thus, to give the unit the same willpower as the -unitSource you would do
-value self:willpower:100:0
Or to take the targets strength
-value target:strength:100:0
Then anywhere you put !VALUE in the command line, it would be replaced by these calculations.
Those are all the "basic" options (I list them as "basic" only because they are all fairly straight forward). There is also the "special" option; -counters, this allows for scripts to be triggered only once certain conditions are met. And is to be used in conjunction with the special/counters script. See the -help documentation for that script to understand the use of the -counters option.
EXAMPLES:
Ok, now that was a lot of information. So how about some examples! Let's take our original example
modtools/interaction-trigger -onAttackStr "shoots a bolt of steel" -command [ wrapper -unitSource \\ATTACKER_ID -unitTarget \\DEFENDER_ID -script [ special/projectile -unit_source !SOURCE -unit_target !TARGET -item AMMO:ITEM_AMMO_BOLTS -mat STEEL -number 1 ] ]
And add some options to it
modtools/interaction-trigger -onAttackStr "shoots a bolt of steel" -command [ wrapper -unitSource \\ATTACKER_ID -unitTarget \\DEFENDER_ID -script [ special/projectile -unit_source !SOURCE -unit_target !TARGET -item AMMO:ITEM_AMMO_BOLTS -mat STEEL -number 1 ] -radius 3,3,0 -maxtargets 5 ]
Now it will shoot a steel bolt at up to 5 targets within a 3x3x0 block around the target. But this includes friendly units too! Well I don't want that so I use
modtools/interaction-trigger -onAttackStr "shoots a bolt of steel" -command [ wrapper -unitSource \\ATTACKER_ID -unitTarget \\DEFENDER_ID -script [ special/projectile -unit_source !SOURCE -unit_target !TARGET -item AMMO:ITEM_AMMO_BOLTS -mat STEEL -number 1 ] -radius 3,3,0 -maxtargets 5 -target enemy ]
Now, instead, I want to just shoot one bolt, but have it chain to one of the 5 targets
modtools/interaction-trigger -onAttackStr "shoots a bolt of steel" -command [ wrapper -unitSource \\ATTACKER_ID -unitTarget \\DEFENDER_ID -script [ special/projectile -unit_source !CENTER -unit_target !TARGET -item AMMO:ITEM_AMMO_BOLTS -mat STEEL -number 1 ] -radius 3,3,0 -maxtargets 5 -target enemy -chain 1 -center ]
Notice that I added -center, but I also changed !SOURCE to !CENTER. This means that the script knows the bolt should go from the source to the target, then from the target to the new, chained, target. If I had left !CENTER as !SOURCE it would have, instead, shot a bolt from the source to the target and then another from the source to the new target.
Now, what if I want to shoot a number of arrows, and a single target, based on the number of allies around the unit?
modtools/interaction-trigger -onAttackStr "shoots a bolt of steel" -command [ wrapper -unitSource \\ATTACKER_ID -unitTarget \\DEFENDER_ID -script [ special/projectile -unit_source !SOURCE -unit_target !TARGET -item AMMO:ITEM_AMMO_BOLTS -mat STEEL -number !VALUE ] -radius 3,3,0 -maxtargets 5 -center -target civ -value stacking:allowed:0:1 ]
Ok, so there are some offensive examples, but what about defensive examples? How about my above mentioned example of giving willpower to all nearby friendly units.
modtools/interaction-trigger -onAttackStr "shouts a rallying battle cry" -command [ wrapper -unitSource \\ATTACKER_ID -unitTARGET \\ATTACKER_ID -script [ unit/attribute-change -unit !TARGET -set !VALUE -mental WILLPOWER -dur 1200 ] -radius 5x5x0 -value self:willpower:100:0 -target civ ]
Simple really!
I think that is enough information for now. Hopefully this is useful for people attempting to use the wrapper script, I know it can seem very daunting, but please feel free to ask, and please, post any of your uses here so people have more examples to look at.