[Tutorial] Making <Calculate/> work for you!

To really make you trust me, let me throw this out there: 
    I don't know exactly what the code that's processing the Calculate elements is doing. As in, I don't know where it's storing its variables, if they're on the heap or the stack, etc. I am pretty confident about the inputs and outputs of the black box, though, so I'm going to try and keep this post at that level. If it sounds like I'm hand-waving some of the technical "why does it do that," well - I am.

  Calculate elements show up everywhere in the XML in GameModifier elements in spell definitions. They describe how the game should determine the Value attribute of the GameModifier as some combination of stats from the Caster and Target at the time the spell is cast. Usually, it's pretty straightforward - copy a value or multiply a value by .75. But if you dig into the files a bit, you'll find some more complicated scenarios.

Diagram of the Calculate tag:

Code: xml
  1. <Calculate InternalName="EffectStrength" ValueOwner="CastingUnit">
  2.  <Expression><![CDATA[[UnitStat_Intelligence]*[UnitStat_NumFireShards]]]></Expression>
  3. </Calculate>


Calculate.InternalName. Like almost everywhere else this is set, it gives a name that you will use to refer to this value other places in your xml. It appears that the name you choose is only "in scope" in the GameModifier element the Calculate lives in. When you don't specify a "ValueOwner," and set this to "Value," it uses the result of this calculation as the Value for the containing GameModifier.

Calculate.Expression
. This weirdo attribute includes a CDATA section that the game engine uses to determine how to carry out your calculation. It can take one of a couple of forms (notice that you can't add three numbers at once, for example):
 1: [VariableName]
 2: [VariableName1] operator [VariableName2]
 3: [VariableName] operator Constant
 4: Constant operator [VariableName]
* Oddly, when I've tried with no variables at all, it's actually crashed the game. Now, why you would want to do that is actually a bit of a mystery.
It appears to accept the operators: *, /, +, and -
The constants are Real values.

Calculate.ValueOwner. This one is crucial - be very careful to have this set correctly! Three common values are: Nothing at all, CastingUnit and TargetUnit. When the value is set, the engine tries to get the value for the variable names from the "owner" before looking for a value from an InternalName (like the result of a previous).
  Let's say you have the variable [UnitStat_Attack] in an expression. If you set ValueOwner=CastingUnit, then when the expression is processed, [UnitStat_Attack] is replaced with the Attack strength of the unit that's casting the spell. If you'd used ValueOwner=TargetUnit, it would instead use the attack value of the unit the spell was being cast on.
  What happens when you don't set ValueOwner? That's a problem - it's not really clear. It seems like the value isn't "none." Apparently, there is always an inferred owner that's checked for the values first. Because of this, never leave out ValueOwner when you're referring to a variable on a Unit (or something else) in your expression. You know the whole "Shards aren't increasing spell damage correctly" bug? That's what happened (read more on that HERE). Also, be careful when assigning InternalName. You don't want it to conflict with an actual property of something else.

So let's do a few examples to help it sink in.

Example 1
Let's say you're creating a spell that does 5x the caster's Intelligence as damage.

Here's what you need to do: Grab the CastingUnit's intelligence score, multiply it by -5 (since you're taking health away), and then assign that as the "Value" for the modifier. Here's the xml:

Code: xml
  1.   <GameModifier InternalName="ApplyDamage">
  2.    <ModType>Unit</ModType>
  3.    <Attribute>DefendableDamage</Attribute>
  4.    <Calculate InternalName="CalculatedDamage" ValueOwner="CastingUnit">
  5.     <Expression><![CDATA[[UnitStat_Intelligence] * -5.0]]></Expression>
  6.    </Calculate>
  7.    <Calculate InternalName="Value">
  8.    <Expression><![CDATA[[CalculatedDamage]]]></Expression>
  9.    </Calculate>
  10.   </GameModifier>

 
Here's how it works: The first calculate gets the value of UnitStat_Intelligence from CastingUnit (the one who's casting the spell or using the ability). It mutiplies this value by -5, then stores it in a variable named "CalculatedDamage" that lives... somewhere. Honestly, who cares where it lives - you've got it's name, and that's good enough.
  Now, the CalculatedDamage variable is used as the value to assign to "Value." And that's the part that says, "use this value for my GameModifer please!"

Example 2
Let's try another example. In this case, I want the spell to decrease the target's Strength by 50%.

Code: xml
  1.   <GameModifier InternalName="ApplyWeaken">
  2.    <ModType>Unit</ModType>
  3.    <Attribute>AdjustUnitStat</Attribute>
  4.    <StrVal>UnitStat_Strength</StrVal>
  5.    <Calculate InternalName="StrengthPenalty" ValueOwner="TargetUnit">
  6.     <Expression><![CDATA[[UnitStat_Strength] * -0.50]]></Expression>
  7.    </Calculate>
  8.    <Calculate InternalName="Value">
  9.    <Expression><![CDATA[[StrengthPenalty]]]></Expression>
  10.    </Calculate>
  11.   </GameModifier>


So here, I grab the target's current strength value, multiply by -0.5 to both half it and make it negative (so it's a penalty), and then I assign it as the value for the GameModifier.

Example 3
For the final example, let's get a little fancier. This spell heals a unit like this: Heals 30% of the damage the unit has taken +2% per point of caster's Intelligence. Yikes. Who the heck would write such a thing?

Here's the code.
Code: xml
  1.   <GameModifier InternalName="ApplyWeaken">
  2.    <ModType>Unit</ModType>
  3.    <Attribute>CurHealth</Attribute>
  4.   
  5.    <Calculate InternalName="ActualTargetDamage" ValueOwner="TargetUnit">
  6.     <Expression><![CDATA[[UnitStat_HitPoints] - [CurHealth]]]></Expression>
  7.    </Calculate>
  8.    <Calculate InternalName="CasterIntBonus" ValueOwner="CastingUnit">
  9.     <Expression><![CDATA[[UnitStat_Intelligence] * 0.02]]></Expression>
  10.    </Calculate>
  11.    <Calculate InternalName="HealingFactor">
  12.     <Expression><![CDATA[[CasterIntBonus] + 0.30]]></Expression>
  13.    </Calculate>
  14.    <Calculate InternalName="Value">
  15.    <Expression><![CDATA[[HealingFactor] * [ActualTargetDamage]]]></Expression>
  16.    </Calculate>
  17.   </GameModifier>


Happy modding,

Gnilbert

 

23,390 views 25 replies
Reply #1 Top

Awesome. Thank you for this tutorial.

Reply #2 Top

No worries - as a random aside, if anyone wants some space to try out other "Calculate" examples, I'll be happy to give 'em a crack, and I bet others who've read this would like the practice as well!

Gnilbert

Reply #3 Top

Oh god, I thought CurHealth was an attribute for Cure Health (like IncreaseMorale)... of course it's current health.

Reply #4 Top

Heh, dunno if I'd want to write out a Tutorial on it, but my mod here can serve as an example of using Calculate with custom Unit Stats to create a quasi-conditional statement: Reworked Imbue Champion.

I might give a crack at writing a more in depth guide to what I was doing, but the xml files themselves do have a lot of comments to explain what is going on, particularly with the Buggy SetUnitStat attribute...

Reply #5 Top

Good guide. Do you have any idea how to make a mod that will use CDATA for sovereign talents?

For example I tried to use CDATA to make a talent that would buff the sovereigns mana regen at 25% of the casters intelligence.

Reply #6 Top

Quoting jereome, reply 5
Good guide. Do you have any idea how to make a mod that will use CDATA for sovereign talents?

For example I tried to use CDATA to make a talent that would buff the sovereigns mana regen at 25% of the casters intelligence.

Not everything seems to be able to use the <Calculate> tag, and Talents are one of those unlucky things :(

This may change in a future patch, though.

Reply #7 Top

All this XML horror makes me wish for the Python API. But hey, it's great that the game is already so moddable.
Thanks for the tutorial Gnilbert!

Reply #8 Top

Hey there, nice tutorial. Do you have any idea how a calculate value could be applied to a history or trait. Take the merchant, for example, how could I apply this:

            <GameModifier>
                <Target>Unit</Target>
                <ModType>Resource</ModType>
                <Attribute>Gold</Attribute>
                <Calculate InternalName = "Value" ValueOwner="CastingUnit">
                    <Expression><![CDATA[[UnitStat_Intelligence]+[UnitStat_Charisma]]]></Expression>
                </Calculate>
                <PerTurn>1</PerTurn>
            </GameModifier>

If both INT and CHAR are 10 then this should be returning 20 gold per turn. As of yet, I haven't gotten it to work and was wondering if you had any input on my problem. I'm testing something new based on what you've said here, I hope it works.

Thanks for explaining this better!

Reply #9 Top

Great tutorial. I find myself thinking of magical counter spells against the much feared ogre, the one with 300 strength that can use that stat to fire off a boulder at your Sov. I am thinking a strength zapping spell would me a smart counter. This helps.

Reply #10 Top

Quoting James009D, reply 8
Hey there, nice tutorial. Do you have any idea how a calculate value could be applied to a history or trait. Take the merchant, for example, how could I apply this:

            <GameModifier>
                <Target>Unit</Target>
                <ModType>Resource</ModType>
                <Attribute>Gold</Attribute>
                <Calculate InternalName = "Value" ValueOwner="CastingUnit">
                    <Expression><![CDATA[[UnitStat_Intelligence]+[UnitStat_Charisma]]]></Expression>
                </Calculate>
                <PerTurn>1</PerTurn>
            </GameModifier>

If both INT and CHAR are 10 then this should be returning 20 gold per turn. As of yet, I haven't gotten it to work and was wondering if you had any input on my problem. I'm testing something new based on what you've said here, I hope it works.

Thanks for explaining this better!

With my (current) understanding of how the GameModifiers work, I'm not sure it can be done. Here's why: Different "objects" that have GameModifiers seem to have events that trigger the application of the associated GameModifiers. For items, it appears to be "OnEquip," and the effect is rolled back when it's "unequipped." Spells have "OnCast" and units have "OnCreated." When that event happens, the calculations for all GameModifiers are performed, and one of two things happens: If the modifier is of a limited duration, an instance of the Modifier (which the values that it just calculated) "decorates" the target, so that it can be accurately rolled back when the effect expires. If the modifier has no duration, I believe it simply adjusts the target's values/properties and then moves on (or creates a permanent instance - it's the same to us).

With what you're doing, I think you want to change the unit's attribute "Gives +X resource" based on another attribute. With the current system, when you apply the modifier to the unit (on creation, when you equip an item, etc), the values of your calculations would be updated. But they wouldn't stay current as intelligence continues to change unless you unequipped and re-equipped the item granting the ability or something similar.

If you want to go really hardcore, you could still pretty much make it happen by digging out every place where Intelligence is gained/lost for a unit and adjusting the Resource boost accordingly.

Now, if SD tells us there's a way to catch "OnAttributeChanged" events or maybe binding of some sort, it'll be a completely different story, since you could define modifiers to apply at that point. (fingers crossed).

Gnilbert

Reply #11 Top

Example 1
Let's say you're creating a spell that does 5x the caster's Intelligence as damage.

Here's what you need to do: Grab the CastingUnit's intelligence score, multiply it by -1 (since you're taking health away), and then assign that as the "Value" for the modifier. Here's the xml:

Shouldn't you be multiplying by -5? Your code seems to do 1x the caster's intelligence in damage, not 5x as you stated your intention to be. I hope that's a typo, otherwise I'm misunderstanding something very simple :P

Reply #12 Top

Thanks for the catch, Austinvn! I've updated the OP with the -5 instead of the -1.

Gnilbert

Reply #13 Top

Quoting Gnilbert, reply 10



Quoting James009D,
reply 8
Hey there, nice tutorial. Do you have any idea how a calculate value could be applied to a history or trait. Take the merchant, for example, how could I apply this:

            <GameModifier>
                <Target>Unit</Target>
                <ModType>Resource</ModType>
                <Attribute>Gold</Attribute>
                <Calculate InternalName = "Value" ValueOwner="CastingUnit">
                    <Expression><![CDATA[[UnitStat_Intelligence]+[UnitStat_Charisma]]]></Expression>
                </Calculate>
                <PerTurn>1</PerTurn>
            </GameModifier>

If both INT and CHAR are 10 then this should be returning 20 gold per turn. As of yet, I haven't gotten it to work and was wondering if you had any input on my problem. I'm testing something new based on what you've said here, I hope it works.

Thanks for explaining this better!



With my (current) understanding of how the GameModifiers work, I'm not sure it can be done. Here's why: Different "objects" that have GameModifiers seem to have events that trigger the application of the associated GameModifiers. For items, it appears to be "OnEquip," and the effect is rolled back when it's "unequipped." Spells have "OnCast" and units have "OnCreated." When that event happens, the calculations for all GameModifiers are performed, and one of two things happens: If the modifier is of a limited duration, an instance of the Modifier (which the values that it just calculated) "decorates" the target, so that it can be accurately rolled back when the effect expires. If the modifier has no duration, I believe it simply adjusts the target's values/properties and then moves on (or creates a permanent instance - it's the same to us).

With what you're doing, I think you want to change the unit's attribute "Gives +X resource" based on another attribute. With the current system, when you apply the modifier to the unit (on creation, when you equip an item, etc), the values of your calculations would be updated. But they wouldn't stay current as intelligence continues to change unless you unequipped and re-equipped the item granting the ability or something similar.

If you want to go really hardcore, you could still pretty much make it happen by digging out every place where Intelligence is gained/lost for a unit and adjusting the Resource boost accordingly.

Now, if SD tells us there's a way to catch "OnAttributeChanged" events or maybe binding of some sort, it'll be a completely different story, since you could define modifiers to apply at that point. (fingers crossed).

Gnilbert

First off let me say I am in no way an expert, but heres my stab at what going on.

1. It could be that your trying to tie <ModType>Resource</ModType> to a <Target>Unit</Target>. I think resources are only tied to cites, not units. maybe Im wrong. So maybe try <Target>City</Target> or <Target>Player</Target>, see if that works.

2. I can see where you are trying to define the value with the expression. which you might want to try to seperate the two cacluations like Gnilbert did earlier in his examples, I dont know why this should matter but you never know.

3. After your expression gets its CDATA and puts it into the "value", what does it do with it? its supposed to Modtype, gold. but how? maybe throw an <operator>+</operator> in there. Again not sure why it should matter, but its not working currently so being extra clear to the engine, might be better for it. Also try putting the <operator> before the calculation, it shouldnt make a differance, but I have seen it work when defining the operator before the value.

Finally to Gnilberts point of GameModifiers having triggers, I would think with him defining <PerTurn>, that his effect should trigger once a turn, every turn.

I hope this helps and good coding. ^_^

w34sl3

Reply #14 Top

Excellent Tut :) Thank you my friend. This will come in very handy indeed.

Reply #15 Top

Does calculate work in items such as weapons? I've been tinkering with making elemental weapons that grow in attack value based on the number of shards controlled. I actually thought I had this working last night but after trying to adjust the values it doesn't seem to work at all (I'm hoping that I wasn't thinking I had it working but really didn't).

Also, along with this would I need the value owner to be PlayerSovereign rather than CastingUnit?

Thanks for the guide, it definitely is helpful.

Reply #16 Top

I've noticed an uptick in modding since the release of 1.1. A quick bump for those who haven't seen it. It's pretty helpful.

Reply #17 Top

Just a quick note.

I've tried several iterations, but have NOT been able to get calculate to work outside of the spell environment.  Not saying it can't be done, just that I've tried, and Heavenfall apparently has too...

I'd absolutely love to make that Mage's cloak that gives the wearer an Int/3 bonus to his defense... instead of a set value.

Reply #18 Top

I was thinking of modding some spells myself and I had a question about random numbers.  Is it okay to use certain math functions in the expression?  Like RND() for random numbers?  Also how do you reference the caster's level instead of his intelligence? 

Reply #19 Top

I was thinking of modding some spells myself and I had a question about random numbers. Is it okay to use certain math functions in the expression? Like RND() for random numbers? Also how do you reference the caster's level instead of his intelligence?

I don't think it's possible to do random numbers this way. That said, You can always try using maxvalue and minvalue to randomize the output, though I have only seen this used on damage effects. As for caster level, you may want to try [Level] though I am not sure that this works.

Reply #20 Top

Thanks.  I believe you're right on.  I'll give it a try and report back.

Reply #21 Top

2 different attempts and both fail.  No crash but spell doing 0 dmg is FAIL.

Just for kicks here is the latest I've tried.

Code: xml
  1. &lt;GameModifier InternalName="DamageModifier"&gt;
  2.       &lt;ModType&gt;Unit&lt;/ModType&gt;
  3.       &lt;Attribute&gt;CurHealth&lt;/Attribute&gt;
  4.       
  5.       &lt;Calculate InternalName="CasterCurrentLevel" ValueOwner="CastingUnit"&gt;
  6.         &lt;Expression&gt;&lt;![CDATA[[Level] * 1]]&gt;&lt;/Expression&gt;
  7.       &lt;/Calculate&gt;
  8.      &lt;Calculate InternalName="MinValue"&gt;
  9.         &lt;Expression&gt;&lt;![CDATA[[CasterCurrentLevel] * -1]]&gt;&lt;/Expression&gt;
  10.       &lt;/Calculate&gt;
  11.       &lt;Calculate InternalName="MaxValue"&gt;
  12.         &lt;Expression&gt;&lt;![CDATA[[CasterCurrentLevel] * -6]]&gt;&lt;/Expression&gt;
  13.       &lt;/Calculate&gt;
  14.       
  15.     &lt;/GameModifier&gt;

Reply #22 Top

Yeah, I don't think that you can reference the caster's level inside the calculate tag. It seems silly, I know.

Reply #23 Top

I just want to add here that calculate works in non-damage type spells like enchants.  I didn't get minvalue or maxvalue to work, but I did when I used just internalname="Value" ,  I had a base of 10 adding to it a variable amount.  Hope this helps.  Happy modding.

Reply #24 Top

I am trying to make a regen that scales now that hitpoints have gone up so much. Objective is 3% of total hitpoints per tactical turn. It's not working (no regen effect at all), anyone have any ideas?

Code: xml
  1.       &lt;GameModifier&gt;
  2.         &lt;ModType&gt;Unit&lt;/ModType&gt;
  3.         &lt;Attribute&gt;AdjustUnitStat&lt;/Attribute&gt;
  4.         &lt;StrVal&gt;UnitStat_TacticalHealthRegen&lt;/StrVal&gt;
  5.   &lt;Calculate InternalName="Value"&gt;
  6.    &lt;Expression&gt;&lt;![CDATA[[UnitStat_HitPoints] * 0.03]]&gt;&lt;/Expression&gt;
  7.    &lt;/Calculate&gt;
  8.       &lt;/GameModifier&gt;

Reply #25 Top

Quoting idontcareaboutyou, reply 24
I am trying to make a regen that scales now that hitpoints have gone up so much. Objective is 3% of total hitpoints per tactical turn. It's not working (no regen effect at all), anyone have any ideas?

Try:

  <GameModifier>
        <ModType>Unit</ModType>
        <Attribute>AdjustUnitStat</Attribute>
        <StrVal>UnitStat_TacticalHealthRegen</StrVal>

        <Calculate InternalName="TargetHP" ValueOwner="TargetUnit">
             <Expression><![CDATA[[UnitStat_HitPoints]]]></Expression>
        </Calculate>

        <Calculate InternalName="Value">
            <Expression><![CDATA[[TargetHP] * 0.03]]></Expression>
        </Calculate>
  </GameModifier>

Basically, anytime you want to get a value from somewhere, you gotta supply what object owns the Value you want, in this case "TargetUnit". There are others, like "PlayerSovereign" or "CastingUnit".