Skip to content

Tuning XML

When writing tuning XML, nodes are written as a single letter based on their type. There are 2 top level node types and 6 regular node types.

I - Instance - Add new features
M - Module - Define values of global variables

Most mods will add or update Instance tuning, but overriding Module tuning is possible. Since it is not possible to partially override tuning, a mod that overrides a Module tuning will need to set all values.

T - Tunable - A single value
E - Enum - An enum value
L - List - A lists of values
U - Tuple - An object with key->value pairs
V - Variant - A single value with multiple valid types
C - Class - Used when defining enums, not seen often

Multiple field types use the same node letter, so their usage is defined as a type. For example in a trait tuning, both display_name and icon are single values, so they use the T tag, but they store different data types. display_name is a TunableLocalizedString and stores a string key, while icon is a TunableReference and stores a resource key for an icon.

Almost all nodes will have an n node defining the name, which is used to map nodes between tuning XML and tuning description.

A tuning file’s root node (I or M) contains an attribute i that points to a python module. Let’s take a look using a Trait tuning using the disable_aging node. Here’s what the description says:

  • disable_aging - If enabled, aging out of specific ages can be disabled.
  • disable_aging has an enabled child node, which in turn has an allowed_ages node.
  • allowed_ages - A list of ages that the Sim CAN age out of.

Using that information, let’s create a “ForeverYoung” trait that would disable aging once a sim becomes a Young Adult.

ForeverYoung.xml
<?xml version="1.0" encoding="utf-8"?>
<I c="Trait" i="trait" m="traits.traits" n="ZMilla:ForeverYoung" s="3678950568">
<V n="disable_aging" t="enabled">
<U n="enabled">
<L n="allowed_ages">
<E>BABY</E>
<E>TODDLER</E>
<E>CHILD</E>
</L>
</U>
</V>
</I>

Can we verify this is set up correctly? The i node is traits.traits. If we resolve that to the python script traits/traits.py, then search for the disable_aging node from earlier, we find a function called can_age_up.

Comments have been added to explain the code if you aren’t familiar with python.

traits/traits.py
# Can a sim age up when they are 'current_age'?
def can_age_up(cls, current_age):
# If 'disable_aging' is not defined, yes
if not cls.disable_aging:
return True
# If 'disable_aging' is defined, only allow aging
# if the 'allowed_ages' list contains 'current_age'.
return current_age in cls.disable_aging.allowed_ages

Alas, proof! Young Adult is not in the allowed_ages list and thus, youth is eternal.

This should really solidify the big picture though. Tuning files are XML that defines data for use in a corresponding python file. We can use tuning descriptions to know the exact XML structure, as well as understand how the fields will be used without needing to look at the python code. However, we can still look at the code with some extra work if we’re curious.