1. ## xml/script math questions

I've completed my character sheets for my ruleset for the most part, the only challenge I've had is some math with ability bonuses and such. The d20 default uses the following script, which is in the charsheet_templates.xml, for calculating ability bonuses.
Code:
```			<script>
function onSourceUpdate()
setValue(math.floor((sources[scorefield[1]].getValue() - sources[damagefield[1]].getValue() - 10) / 2) + getModifier());
end

function onInit()

super.onInit();
end
</script>```
d20 D&D ability bonus is easy, Ability Score - 10 divide by 2.

With my ruleset it is not that simple. A vital statistic (ability) can have several bonuses or related values.
Here is a screenshot of the main charsheet to illustrate what I mean...

i.e. Strength has three encumbrance scores, damage bonus, skill bonus; IQ has Power Points, Max Lang, skill bonus. The skill bonus from Strength will not necessarily equal the skill bonus from IQ of the same score. A Strength of 100 will not give the same skill bonus as a IQ score of 100. Vital stats can range from 1 to 150.

I thought the best way to handle this is with a lot of if x=>1, but <=20, y=5 type functions, but do not know enough about the math scripting to describe this.

Any assistance is appreciated...

2. Did you arrive at your ruleset by modifying the d20 ruleset, or did you start from scratch? If you're using the d20 ruleset as a basis, you can define the fields to the right of the base scores using the "linkednumber" template. You can then specify the source field as
Code:
`<source><name>name of source field</name></source>`
You would then need to define a custom update function for each:
Code:
```<script>
function update()
-- put the guts of the function here
-- To reference a source field, use sources["name of source field"].getValue()
end
</script>```
As for the specifics of using the scripting system, it works just like Lua. There are links to a Lua tutorial in the library (go to the scripting subsection in the ruleset modification guide).

3. Originally Posted by Insanity
I thought the best way to handle this is with a lot of if x=>1, but <=20, y=5 type functions, but do not know enough about the math scripting to describe this.
As Dachannien said using "linkednumber"'s for your derived fields will help keep the calculations separate.
In regards to the calculations if/elseif would work but could get very messy. As an alternative you might be able to make use of a static table

Here's a very simple example that should calculate a strength skill bonus of:
0 for a strength score less than 10
2 for strength 10-59
3 for strength 60-99
4 for strength >= 130
(note: the code may not be perfect as my lua skills aren't that great and I'm not able to test it right now)

Code:
```

local strengthSkillTable = { [10]=1, [60]=2, [100]=3, [130]=4};

function calculateStrengthSkillBonus(strengthvalue)
local skillBonus;

skillBonus= 0;

for each k, v in strengthSkillTable
if strengthvalue >= k then
skillBonus = v;
end
end

return skillBonus;
end```

Code:
```

local strengthSkillTable = { [10]=1, [60]=2, [100]=3, [130]=4};

function calculateStrengthSkillBonus(strengthvalue)
local skillBonus;

skillBonus= 0;

for each k, v in pairs(strengthSkillTable) do
if strengthvalue >= k then
skillBonus = v;
end
end

return skillBonus;
end```
You always want to enclose a table in pairs() (or ipairs, but that wouldn't work in this instance) if you're iterating over it with a for loop. And there's also the necessity for a "do" statement.

Now to hope that I didn't miss anything...

5. Ah, now that I can test it there were a few more flaws...
However, this code works:

Code:
```
function calculateStrengthSkillBonus(strengthvalue)
local strengthSkillTable = { {10,1}, {60,2}, {100,3}, {130,4} };

local skillBonus;

skillBonus= 0;

for k, v in pairs(strengthSkillTable) do
if strengthvalue >= v[1] then
skillBonus = v[2];
end
end

return skillBonus;
end```

what i've done with my ruleset so far, using the d20 default as a guide, I have a template prepared for vital stats as follows:

Code:
```	<template name="vitalstat">
<numberfield>
<anchored>
<position>belowleft</position>
<offset>0,7</offset>
<size>
<width>32</width>
<height>20</height>
</size>
</anchored>
<frame>
<name>bonus</name>
<offset>5,5,5,5</offset>
</frame>
<keyeditframe>
<name>sheetfocus</name>
<offset>5,5,5,5</offset>
</keyeditframe>
<font>sheetnumber</font>
<script>
function onInit()
if getValue() == 0 then
setValue(50);
end
end
</script>
</numberfield>
</template>```
and then for each vital stat I have assigned a source name, I won't show the full code, but looks like this:

Code:
```<vitalstat name="strength" source="vital.strength.score">

<vitalstat name="manualdexterity" source="vital.manualdexterity.score">```
Much the same for all 10 stats, and done the same for the bonuses as well, again using a template:

Code:
```<vitalbonus name="strengthskillbonus" source="vital.strength.skillbonus">

<vitalbonus name="rangedbonus" source="vital.manualdexterity.rangedbonus">```
Strength score ranges from 0 to 150, with values 40-60 having a skill bonus of 0, and in this example, lets then assume scores 40-60 have +0, 61-70 have +1, 71-80 +2, 81-90 +3, 91-100, +4, 101-110 +5, 111-120 +6, 121-130 +7, 131-140 +8, 141-150 +9...

My code would look like this?

Code:
```
function calculatevital.strength.skillbonus(vital.strength.score)
local strengthSkillTable = { {61,1}, {71,2}, {81,3}, {91,4}, {101,5}, {111,6}, {121,7}, {131,8}, {141,9} };

local skillBonus;

skillBonus= 0;

for k, v in pairs(strengthSkillTable) do
if strengthvalue >= v[1] then
skillBonus = v[2];
end
end

return skillBonus;
end```

7. I'm still a bit of an lua noob and am having trouble getting my head around how the linkednumberfield works. So heres a simpler bit of code that will work for a single field.

Code:
```<template name="vitalstat">
<numberfield>
<anchored>
<position mergerule="replace">insidetopleft</position>
<offset mergerule="replace">32,20</offset>
<size mergerule="replace">
<width>32</width>
<height>20</height>
</size>
</anchored>
<frame mergerule="replace">
<name>bonus</name>
<offset>5,5,5,5</offset>
</frame>
<keyeditframe mergerule="replace">
<name>sheetfocus</name>
<offset>5,5,5,5</offset>
</keyeditframe>
<font mergerule="replace">sheetnumber</font>
<script>
local strengthSkillTable = { {61,1}, {71,2}, {81,3}, {91,4}, {101,5}, {111,6} };
function recalculate(source)
local sourceValue = source.getValue();
local skillBonus = 0;
for k, v in pairs(strengthSkillTable) do
if sourceValue >= v[1] then
skillBonus = v[2];
end
end
setValue(skillBonus);
end
function onInit()
if source then
sourcenode = window.getDatabaseNode().getChild(source[1]);
if sourcenode then
sourcenode.onUpdate = recalculate;
end
end
end
</script>
</numberfield>
</template>```
An example of the template being used on the charsheet
Code:
```
<vitalstat name="strength_vitalstat">
<source>abilities.strength.score</source>
<anchored>
<to>strength</to>
<position>left</position>
</anchored>
</vitalstat>```
Also, you might want to remove the anchored node from the template and just define it when you use the template. The "anchored" behaviour is based on the control it is anchored to. If no "to" anchor is specified it would try to anchor itself to it's container (which may well be the charactersheet itself - in which case it would resize itself to be as tall as the whole sheet).

8. Psst... merge rules default to replace, so you don't need to add in all of the mergerule="replace".

What I would suggest is changing the template a bit to make it more generic:

First, add the following in the template's body:
Code:
```	<table>
</table>```
Next, we put change the script a bit:
Code:
```	local strengthSkillTable = { {61,1}, {71,2}, {81,3}, {91,4}, {101,5}, {111,6} };

local sourcetable = {};

function recalculate(source)
local sourceValue = source.getValue();
local skillBonus = 0;
for k, v in pairs(sourcetable) do
if sourceValue >= v[1] then
skillBonus = v[2];
end
end
setValue(skillBonus);
end

function buildTable()
if table and type(table) == "table" then
for _, v in pairs(table) do
if v.value and v.score then
table.insert(sourcetable,{v.source[1],v.score[1]})
end
end
end
end

function onInit()
buildTable()

if source then
sourcenode = window.getDatabaseNode().getChild(source[1]);
if sourcenode then
sourcenode.onUpdate = recalculate;
end
end
end```

Now... what that should do... you can build a table in the xml side without having to deal with modifying the script, as such:

Code:
```<vitalstat>
<table>
<entry>
<value>61</value>
<score>1</score>
</entry>

<entry>
<value>71</value>
<score>2</score>
</entry>

<entry>
<value>81</value>
<score>3</score>
</entry>
</table>
</vitalstat>```
Hopefully, I think that works... but it's been a 15 hour work day so far, so... I'm sleepy... >.<

Edit: As an example of my sleepiness, I forgot to include that, in the above code: blue means remove and red means add... I know, I'm backwards...

9. Nicely done Taryn. We like code that is generic. Just hard to figure it out sometimes

Psst... merge rules default to replace, so you don't need to add in all of the mergerule="replace".
You sure bout this? The documentation says that 'merge' is the default behaviour.

You sure bout this? The documentation says that 'merge' is the default behaviour.
Hmm... that it does. I wonder what the difference between "merge" and "replace" is then...?

Aha... the difference is that with merge, if you have a template with tags named table with child elements chair and lamp, and an instance of that with only table and lamp, you'd still get a chair in there. On the other hand, with replace, you'd end up only with table and lamp.

I learn something new every day... (now if only I'd remember half of it... )

There are currently 1 users browsing this thread. (0 members and 1 guests)

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•