Difference between revisions of "VariablesWML/How to use variables"

From The Battle for Wesnoth Wiki
m
(A few more lines and some edit)
Line 1: Line 1:
 
== WML Variables HowTo (or Descent into Darkness) ==
 
== WML Variables HowTo (or Descent into Darkness) ==
 
In this document, we shall try to explain WML variables and their use with some details.  We’ll start under the burning sun of lawful ordinary use, but, step by step, we shall go deeper  in the shadows of necromancy, exploring undocumented features and hidden pits as we may.  The first part should be understandable by any beginner, but the last one most probably  requires a good WML understanding.
 
In this document, we shall try to explain WML variables and their use with some details.  We’ll start under the burning sun of lawful ordinary use, but, step by step, we shall go deeper  in the shadows of necromancy, exploring undocumented features and hidden pits as we may.  The first part should be understandable by any beginner, but the last one most probably  requires a good WML understanding.
===Under the burning sun ===
+
 
==== Variable definitions ====
+
=== <u>Under the burning sun</u> ===
 +
 
 +
 
 +
==== <u>Variable definitions</u> ====
 
This section and the next one can be skipped if you already know what variables are and how  to use them.  Variables are some kind of container a programmer can use to store pieces of information  (s)he needs to manipulate : numbers, names, sentences, and anything else. In most  programming languages, variables must be declared before they can be used. Declaration is an  instruction giving a name (used later to refer to the variable) and a type, which defines the  kind of content of the variable (number, characters strings, and so on).  Later in the program, instructions can be used to store and retrieve the content of the  container, which is most often called the value of the variable.  In WML, variables need no declaration and their value have no precise type<sup>1)</sup>. This means a  new variable will be created at the first time the programmer stores something in it. And that  (s)he can store anything in it.  Variables use memory, so it’s good practice to clear them when they’re not needed anymore.
 
This section and the next one can be skipped if you already know what variables are and how  to use them.  Variables are some kind of container a programmer can use to store pieces of information  (s)he needs to manipulate : numbers, names, sentences, and anything else. In most  programming languages, variables must be declared before they can be used. Declaration is an  instruction giving a name (used later to refer to the variable) and a type, which defines the  kind of content of the variable (number, characters strings, and so on).  Later in the program, instructions can be used to store and retrieve the content of the  container, which is most often called the value of the variable.  In WML, variables need no declaration and their value have no precise type<sup>1)</sup>. This means a  new variable will be created at the first time the programmer stores something in it. And that  (s)he can store anything in it.  Variables use memory, so it’s good practice to clear them when they’re not needed anymore.
 
Variables names are freely chosen by the programmer with some restrictions. They should not be the name of a language instruction (keyword) or operator. In WML, you can use quite any name or sentence to name a variable, but you shouldn’t if you want to shun subtle problems. A classical rule is :
 
Variables names are freely chosen by the programmer with some restrictions. They should not be the name of a language instruction (keyword) or operator. In WML, you can use quite any name or sentence to name a variable, but you shouldn’t if you want to shun subtle problems. A classical rule is :
Line 11: Line 14:
 
: “name_of_the_gyu_who_killed_the_orc_on_last_turn”, but it’s not really obvious at first glance.
 
: “name_of_the_gyu_who_killed_the_orc_on_last_turn”, but it’s not really obvious at first glance.
 
It’s a common error to type wrongly a variable name: in WML this don’t rise any  error message, but the variable will have no value, giving most probably what you don’t expect. Last but not least, variables names are case sensitive: in other words, ‘aVar’ is not the same as ‘avar’.
 
It’s a common error to type wrongly a variable name: in WML this don’t rise any  error message, but the variable will have no value, giving most probably what you don’t expect. Last but not least, variables names are case sensitive: in other words, ‘aVar’ is not the same as ‘avar’.
==== Variables creation and manipulation ====
+
 
Even if WML variables contents have no precise types<sup>1)</sup>, we shall discuss two kinds:
+
 
 +
==== <u>Variables creation and manipulation</u> ====
 +
Even if WML variables contents have no precise types.[[In computering words, they are not '''strongly typed.'''|<sup>1)</sup>]], we shall discuss two kinds:
 
: - variables holding a single value, like a number, a character string
 
: - variables holding a single value, like a number, a character string
 
: - variables holding a compound value, i.e. a pack of single values.
 
: - variables holding a compound value, i.e. a pack of single values.
Line 51: Line 56:
 
  [/set_variable]
 
  [/set_variable]
 
We shall not use  '''[set_variable]''' tag anymore. Instead, we shall use the '''VARIABLE''' shortcut:
 
We shall not use  '''[set_variable]''' tag anymore. Instead, we shall use the '''VARIABLE''' shortcut:
 
____________________________
 
 
:<sup>1)</sup> In computering words, they are not '''strongly typed.'''
 
  
 
  {VARIABLE simpleVariable "Delfador the Great"}
 
  {VARIABLE simpleVariable "Delfador the Great"}
Line 84: Line 85:
 
     name=simpleVariable
 
     name=simpleVariable
 
  [/clear_variable]
 
  [/clear_variable]
: # or using the following macro to delete more than one variable                                                                                      {CLEAR_VARIABLE simpleVariable,anotherOne,count}<sup>2)</sup>
+
: # or using the following macro to delete more than one variable                                                                                      {CLEAR_VARIABLE simpleVariable,anotherOne,count} [[Please note the CLEAR_VARIABLE macro will not work if your variables names contain spaces or commas. It’s one good reason to avoid them.|<sup>2)</sup>]]
 
 
____________________________
 
  
:<sup>2)</sup> Please note the CLEAR_VARIABLE macro will not work if your variables names contain spaces or commas. It’s one good reason to avoid them.
 
  
==== Containers ====
+
==== <u>Containers</u> ====
What is a container ? It is a variable holding more than a simple value. A good example is the unit variable created automatically in '''moveto''' and '''attack''' events. It contains the full description of a unit, not only its name and its id. Containers are useful to store related values in a pack. All these different values are called “members” of the created container. Instead of writing this:
+
What is a container?
 +
It is a variable holding more than a simple value.
 +
A good example is the unit variable created automatically in '''moveto''' and '''attack''' events. It contains the full description of a unit, not only its name and its id. Containers are useful to store related values in a pack. All these different values are called “members” of the created container. Instead of writing this:
 
  {VARIABLE heroName "Delfador"}
 
  {VARIABLE heroName "Delfador"}
 
  {VARIABLE heroGold 250}
 
  {VARIABLE heroGold 250}
Line 106: Line 106:
 
     [/value]
 
     [/value]
 
  [/set_variables]
 
  [/set_variables]
Then, to get the values stored in the container, we shall use the $ sign as before, but appending the member name and a dot<sup>3)</sup>:
+
Then, to get the values stored in the container, we shall use the $ sign as before, but appending the member name and a dot:[[That’s why dots are forbidden in variable names : they are used to specify members.|<sup>3)</sup>]]
 
  $hero.name -> Delfador
 
  $hero.name -> Delfador
 
  $hero.gold -> 250
 
  $hero.gold -> 250
Line 121: Line 121:
 
  {VARIABLE hero.hasStaff yes}
 
  {VARIABLE hero.hasStaff yes}
 
this creates the member hasStaff and set it to yes.
 
this creates the member hasStaff and set it to yes.
 
____________________________
 
 
:<sup>3)</sup>That’s why dots are forbidden in variable names : they are used to specify members.
 
 
  
  
== A glance into the pit ==  
+
=== <u>A glance into the pit</u> ===  
  
 
All this will be clearer if we take a look at the way variables are stored. Opening a savegame with a text editor, we should find a part like this one:
 
All this will be clearer if we take a look at the way variables are stored. Opening a savegame with a text editor, we should find a part like this one:
Line 152: Line 147:
  
 
Here are our variables ! We can see simple ones are a pair name/value separated with an equal  
 
Here are our variables ! We can see simple ones are a pair name/value separated with an equal  
sign<sup>4)</sup> . Container are stored in a WML block whose name is the variable name.   
+
sign.[[That’s why = signs are forbidden in variables names : it corrupts savegames.|<sup>4)</sup>]]
 +
 
 +
Container are stored in a WML block whose name is the variable name.   
 
Actually, it’s just like folders and files on your hard disk. Each name/value pair is like a file,   
 
Actually, it’s just like folders and files on your hard disk. Each name/value pair is like a file,   
 
and other tags like folders. This explains the syntax used: '''set_variable''' and '''clear_variable''' operate on name/value pairs, and you use the dot to specify the path to the line you want to create or modify, for example '''hero.name'''.
 
and other tags like folders. This explains the syntax used: '''set_variable''' and '''clear_variable''' operate on name/value pairs, and you use the dot to specify the path to the line you want to create or modify, for example '''hero.name'''.
Line 196: Line 193:
 
We can delete members, values or even whole blocks in the same way:   
 
We can delete members, values or even whole blocks in the same way:   
 
  {CLEAR_VARIABLE aVar.filter.type}
 
  {CLEAR_VARIABLE aVar.filter.type}
will remove the key ‘type’ in the filter block:   
+
will remove the key ‘type’ in the filter block:
 +
[aVar] 
 +
    name=capture 
 +
    first_time_only=no 
 +
    [filter] 
 +
        side=3 
 +
    [/filter] 
 +
    [set_variable] 
 +
        name=tmp 
 +
        rand=1..2 
 +
    [/set_variable] 
 +
[/aVar] 
 +
 
 +
{CLEAR_VARIABLE aVar.filter } will remove the whole filter block: 
 +
 
 +
[aVar] 
 +
    name=capture 
 +
    first_time_only=no 
 +
    [set_variable] 
 +
        name=tmp 
 +
        rand=1..2 
 +
    [/set_variable] 
 +
[/aVar]
 +
This example is rather confusing because this variable looks much more like a piece of code 
 +
than data (and it’s part of the content of an event, of course). But, if you want to follow us to 
 +
the deeper of darkness, you should already face this ominous truth: data and code are not 
 +
separated in WML, and it’s possible to modify the code with data manipulation instructions. 
 +
Fortunately with some limits. Actually, you can only modify from WML what can be put into 
 +
a variable: units, locations, and some code blocks, but you can’t directly access to scenario 
 +
level.
 +
 
 +
A more usual example is the unit container. '''Moveto''' events create a unit variable holding the 
 +
full description of the moving unit. When pushed in your torture room (the ‘unit’ variable) 
 +
you’re allowed to access any field of the unit. Exact composition of a unit block can be 
 +
fetched in a savegame or with ''':inspect''' in debug mode. It’s rather complex. Here is an 
 +
example (many lines have been deleted, particularly animations):
 +
[unit] 
 +
    flying=yes 
 +
    gender="female" 
 +
    hitpoints=26 
 +
    id="Lestiviel" 
 +
    image="units/elves-wood/shaman.png" 
 +
    max_experience=26 
 +
    max_hitpoints=26 
 +
    max_moves=5 
 +
    moves=5 
 +
    name=_"Lestiviel" 
 +
    overlays="misc/hero-icon.png" 
 +
    profile="portraits/Lestiviel-y.png" 
 +
    race="elf" 
 +
    [attack] 
 +
        damage=3 
 +
        description=_"staff" 
 +
        icon="attacks/druidstaff.png" 
 +
        name="staff" 
 +
        number=2 
 +
        range="melee" 
 +
        type="impact" 
 +
    [/attack] 
 +
    [attack] 
 +
        damage=3 
 +
        description=_"entangle" 
 +
        name="entangle" 
 +
        number=2 
 +
        range="ranged" 
 +
        type="impact" 
 +
        [specials] 
 +
            [slow] 
 +
                description=_"Slow:" 
 +
                id="slow" 
 +
                name=_"slows" 
 +
            [/slow] 
 +
        [/specials] 
 +
    [/attack] 
 +
    [modifications] 
 +
        [trait] 
 +
            description=_"Zero upkeep" 
 +
            female_name=_"female^loyal" 
 +
            id="loyal" 
 +
            male_name=_"loyal" 
 +
            [effect] 
 +
                apply_to="loyal" 
 +
            [/effect] 
 +
        [/trait] 
 +
        [trait] 
 +
            female_name=_"female^intelligent" 
 +
            id="intelligent" 
 +
            male_name=_"intelligent" 
 +
            [effect] 
 +
                apply_to="max_experience" 
 +
                increase="-20%" 
 +
            [/effect] 
 +
        [/trait] 
 +
    [/modifications] 
 +
[/unit]
 +
Here we have a problem: this unit has two attack blocks and two traits blocks. How can we 
 +
access them ? Writing only '''$unit.attack.name''' can’t be correct since we have two blocks. We 
 +
have here our first example of arrays. Arrays are lists of WML blocks sharing the same name (here '''attack''' or '''modifications.trait'''). The blocks in arrays are implicitly numbered in the
 +
order they are written, and we can use this index to state which one we want:
 +
 
 +
$unit.attack[0].name -> "staff" 
 +
$unit.attack[1].name -> "entangle" 
 +
       
 +
$unit.modifications.trait[0].id -> "loyal" 
 +
$unit.modifications.trait[1].id -> "intelligent"
 +
 
 +
Mark indexes begins with 0. So, can we modify the value of the intelligent trait using 
 +
VARIABLE ? Yes, just do it: 
 +
 
 +
{VARIABLE $unit.modifications.trait[1].increase "-50%"} 
 +
 
 +
Does this modification apply to the unit ? Not immediately. You should use '''[unstore_unit]''' 
 +
first to pull them out of your torture room, and then… well, it works for some values, but not 
 +
all of them. There is an automatic healing process at work and some unit properties are 
 +
overwritten when '''[unstore_unit]''' happens, but the variable itself is really changed. You can 
 +
verify this using ''':inspect'''.  
  
____________________________
 
  
:<sup>4)</sup>That’s why = signs are forbidden in variables names : it corrupts savegames.
+
==== <u>More with arrays</u> ====

Revision as of 17:43, 8 October 2013

WML Variables HowTo (or Descent into Darkness)

In this document, we shall try to explain WML variables and their use with some details. We’ll start under the burning sun of lawful ordinary use, but, step by step, we shall go deeper in the shadows of necromancy, exploring undocumented features and hidden pits as we may. The first part should be understandable by any beginner, but the last one most probably requires a good WML understanding.

Under the burning sun

Variable definitions

This section and the next one can be skipped if you already know what variables are and how to use them. Variables are some kind of container a programmer can use to store pieces of information (s)he needs to manipulate : numbers, names, sentences, and anything else. In most programming languages, variables must be declared before they can be used. Declaration is an instruction giving a name (used later to refer to the variable) and a type, which defines the kind of content of the variable (number, characters strings, and so on). Later in the program, instructions can be used to store and retrieve the content of the container, which is most often called the value of the variable. In WML, variables need no declaration and their value have no precise type1). This means a new variable will be created at the first time the programmer stores something in it. And that (s)he can store anything in it. Variables use memory, so it’s good practice to clear them when they’re not needed anymore. Variables names are freely chosen by the programmer with some restrictions. They should not be the name of a language instruction (keyword) or operator. In WML, you can use quite any name or sentence to name a variable, but you shouldn’t if you want to shun subtle problems. A classical rule is :

- variable name should begin with a letter
- variable names should only contain letters (not accented) and numbers and the underscore _ character.

No spaces, no accented letters, no special characters, no minus and plus signs, etc… Those names are always safe and correctly interpreted by the engine as variables names. Note that some special characters are forbidden in variable names: $ , . | {} [] = because they have a special meaning we shall see later. I would strongly suggest to avoid common tags names like “event” “side” and too long names like:

“name_of_the_guy_who_killed_the_orc_on_last_turn” which is not the same as:
“name_of_the_gyu_who_killed_the_orc_on_last_turn”, but it’s not really obvious at first glance.

It’s a common error to type wrongly a variable name: in WML this don’t rise any error message, but the variable will have no value, giving most probably what you don’t expect. Last but not least, variables names are case sensitive: in other words, ‘aVar’ is not the same as ‘avar’.


Variables creation and manipulation

Even if WML variables contents have no precise types.1), we shall discuss two kinds:

- variables holding a single value, like a number, a character string
- variables holding a compound value, i.e. a pack of single values.

They’re often called containers in the documentation. Simple variables are created using the tag [set_variable]:

[set_variable]
    name=simpleVariable
    value=36
[/set_variable]

The tag defines the name and the value of the variable.

Next, we can access the variable value using the variable name prefixed with a dollar sign $.

[modify_unit]
    [filter]
        id=$unit.id
    [/filter]
    moves=$simpleVariable
[/modify_unit]

This sets the moves of the unit to 36 since simpleVariable holds 36.

When the line is executed, the value 36 is substituted to $simpleVariable, so it works as if we wrote:

[modify_unit]
    [filter]
        id=$unit.id
    [/filter]
    moves=36
[/modify_unit]

Using the same tag, we can change the value of simpleVariable, or make some arithmetic (see the tag documentation for the whole list).

For example:

[set_variable]
    name=simpleVariable
    sub=30
[/set_variable]

will change the value to 6 of course. We can even set the variable to another value type:

[set_variable]
    name=simpleVariable
    value="Delfador the Great"
[/set_variable]

We shall not use [set_variable] tag anymore. Instead, we shall use the VARIABLE shortcut:

{VARIABLE simpleVariable "Delfador the Great"}

stands for:

[set_variable]
    name=simpleVariable
    value="Delfador the Great"
[/set_variable]

We shall not use the arithmetic variations of set_variable either. Instead we shall use the formulaAI syntax which is much more natural. Instead of:

[set_variable]
     name=simpleVariable
     value=35
[/set_variable]
[set_variable]
      name=simpleVariable
      add=$anotherVariable
[/set_variable]

we shall write:

[set_variable]
    name=simpleVariable
    value="$(35 + $anotherVariable)"
[/set_variable]
# or
{VARIABLE simpleVariable "$(35 + $anotherVariable)"}

The formulaAI syntax is easy to use, the important thing is to always put the formula in this sequence: “$( … here comes the formula … )” In other words, $simpleVariable can be written everywhere you want to use the value of simpleVariable. Clearing variables can be done using the [clear_variable] tag:

[clear_variable]
    name=simpleVariable
[/clear_variable]
# or using the following macro to delete more than one variable {CLEAR_VARIABLE simpleVariable,anotherOne,count} 2)


Containers

What is a container? It is a variable holding more than a simple value. A good example is the unit variable created automatically in moveto and attack events. It contains the full description of a unit, not only its name and its id. Containers are useful to store related values in a pack. All these different values are called “members” of the created container. Instead of writing this:

{VARIABLE heroName "Delfador"}
{VARIABLE heroGold 250}
{VARIABLE heroFame 127}
{VARIABLE heroFullName "Delfador the Great"}

we can pack all this in a “hero” variable using [set_variables] (mark the ‘s’)

[set_variables]
    name=hero
    [value]
        name="Delfador"
        gold=250
        fame=127
        fullName="Delfador the Great"
    [/value]
[/set_variables]

Then, to get the values stored in the container, we shall use the $ sign as before, but appending the member name and a dot:3)

$hero.name -> Delfador
$hero.gold -> 250

And if we want to change a value, the “gold” member for instance:

[set_variable]
    name=hero.gold
    add=100
[/set_variable]

It’s important to note that here, we changed the “gold” member as if it was a single variable whose name is “hero.gold”. We can also clear a member of the container in the same way:

{CLEAR_VARIABLE hero.fullName}

This will delete the fullName member permanently. Note it will not only clear the value, but clear the member itself. Clearing the value would be:

{VARIABLE hero.fullName ""}

Can we add later a member to an existing container ? Yes, it can be done:

{VARIABLE hero.hasStaff yes}

this creates the member hasStaff and set it to yes.


A glance into the pit

All this will be clearer if we take a look at the way variables are stored. Opening a savegame with a text editor, we should find a part like this one:

[replay_start]  
    id=""
    [variables]  
        damage_inflicted=18
        heal_amount=10  
        side_number=1  
        turn_number=26  
        x1=8  
        x2=0  
        y1=8  
        y2=0  
        simpleVariable=35  
        [hero]  
            name="Delfador"  
            gold=250  
            fame=127  
            fullName="Delfador the Great"  
        [/hero]  
        ...  

Here are our variables ! We can see simple ones are a pair name/value separated with an equal sign.4)

Container are stored in a WML block whose name is the variable name. Actually, it’s just like folders and files on your hard disk. Each name/value pair is like a file, and other tags like folders. This explains the syntax used: set_variable and clear_variable operate on name/value pairs, and you use the dot to specify the path to the line you want to create or modify, for example hero.name. Using set_variable creates a line if it exists not. So we can use it to add lines to the hero container using hero.something name, just as we can add a new line at the first level. Now, we can understand better what a container is. It’s a WML block, just as an ordinary tag, and can hold any valid WML content. Look at this:

[set_variables]  
    name=aVar  
    [value]  
        name=capture
        first_time_only=no  
        [filter]  
            side=3  
            type=orc           
        [/filter]  
        [set_variable]  
            name=tmp  
            rand=1..2  
        [/set_variable]  
    [/value]  
[/set_variables]                    

This is perfectly valid and creates this container variable:

[aVar]  
    name=capture  
    first_time_only=no  
    [filter]  
        side=3  
        type=orc  
    [/filter]  
    [set_variable]  
        name=tmp  
        rand=1..2  
    [/set_variable]  
[/aVar]                                                    

We can modify members in the sub blocks too, using the full path to them, separated with dots. For instance:

{VARIABLE aVar.set_variable.rand “1..5”}  

or

{VARIABLE aVar.filter.side 2}.  

Capito ?

We can delete members, values or even whole blocks in the same way:

{CLEAR_VARIABLE aVar.filter.type}

will remove the key ‘type’ in the filter block:

[aVar]  
    name=capture  
    first_time_only=no  
    [filter]  
        side=3  
    [/filter]  
    [set_variable]  
        name=tmp  
        rand=1..2  
    [/set_variable]  
[/aVar]  
 
{CLEAR_VARIABLE aVar.filter } will remove the whole filter block:  
 
[aVar]  
    name=capture  
    first_time_only=no  
    [set_variable]  
        name=tmp  
        rand=1..2  
    [/set_variable]  
[/aVar] 

This example is rather confusing because this variable looks much more like a piece of code than data (and it’s part of the content of an event, of course). But, if you want to follow us to the deeper of darkness, you should already face this ominous truth: data and code are not separated in WML, and it’s possible to modify the code with data manipulation instructions. Fortunately with some limits. Actually, you can only modify from WML what can be put into a variable: units, locations, and some code blocks, but you can’t directly access to scenario level.

A more usual example is the unit container. Moveto events create a unit variable holding the full description of the moving unit. When pushed in your torture room (the ‘unit’ variable) you’re allowed to access any field of the unit. Exact composition of a unit block can be fetched in a savegame or with :inspect in debug mode. It’s rather complex. Here is an example (many lines have been deleted, particularly animations):

[unit]  
    flying=yes  
    gender="female"  
    hitpoints=26  
    id="Lestiviel"  
    image="units/elves-wood/shaman.png"  
    max_experience=26  
    max_hitpoints=26  
    max_moves=5  
    moves=5  
    name=_"Lestiviel"  
    overlays="misc/hero-icon.png"  
    profile="portraits/Lestiviel-y.png"  
    race="elf"  
    [attack]  
        damage=3  
        description=_"staff"  
        icon="attacks/druidstaff.png"  
        name="staff"  
        number=2  
        range="melee"  
        type="impact"  
    [/attack]  
    [attack]  
        damage=3  
        description=_"entangle"  
        name="entangle"  
        number=2  
        range="ranged"  
        type="impact"  
        [specials]  
            [slow]  
                description=_"Slow:"  
                id="slow"  
                name=_"slows"  
            [/slow]  
        [/specials]  
    [/attack]  
    [modifications]  
        [trait]  
            description=_"Zero upkeep"  
            female_name=_"female^loyal"  
            id="loyal"  
            male_name=_"loyal"  
            [effect]  
                apply_to="loyal"  
            [/effect]  
        [/trait]  
        [trait]  
            female_name=_"female^intelligent"  
            id="intelligent"  
            male_name=_"intelligent"  
            [effect]  
                apply_to="max_experience"  
                increase="-20%"  
            [/effect]  
        [/trait]  
    [/modifications]  
[/unit]

Here we have a problem: this unit has two attack blocks and two traits blocks. How can we access them ? Writing only $unit.attack.name can’t be correct since we have two blocks. We have here our first example of arrays. Arrays are lists of WML blocks sharing the same name (here attack or modifications.trait). The blocks in arrays are implicitly numbered in the order they are written, and we can use this index to state which one we want:

$unit.attack[0].name -> "staff"  
$unit.attack[1].name -> "entangle"  
       
$unit.modifications.trait[0].id -> "loyal"  
$unit.modifications.trait[1].id -> "intelligent"

Mark indexes begins with 0. So, can we modify the value of the intelligent trait using VARIABLE ? Yes, just do it:

{VARIABLE $unit.modifications.trait[1].increase "-50%"}  
 

Does this modification apply to the unit ? Not immediately. You should use [unstore_unit] first to pull them out of your torture room, and then… well, it works for some values, but not all of them. There is an automatic healing process at work and some unit properties are overwritten when [unstore_unit] happens, but the variable itself is really changed. You can verify this using :inspect.


More with arrays