PDA

View Full Version : Setting a value when another value changes...



Oberoten
July 23rd, 2007, 00:28
Okay, most basic of the basic here...

I am going to add a very simple control to a charactersheet.

Basically it will have three columns :

Name, Skill and XP-cost.

Name is of course the name of the skill,
Skill is the level (an Integer)
And XP-Cost... Well XP cost is calculated on (skill^2)/2 + Skill/2

(Triangular number... yay. Go wikipedia. ;) )

How would I go about working with this?

I have poked around the generic and the D20 ruleset and so far ... it just tends to make me growl and want to throw things in sheer frustration. I mean, fekt, setting a value when another updates SHOULD be childs-stuff, right?

joshuha
July 23rd, 2007, 00:39
Have you had a chance to look at this thread?
https://fantasygrounds.com/forums/showthread.php?t=6775

Essentially what you do is in the field you want based off another field is write an updatehandler. Its not too complicated but does involved an understanding as to how the database works.

Oberoten
July 23rd, 2007, 03:13
Yeah, I have read through it... and I still don't get it.
*sighs* It just makes me feel even more retarded.

Normally I don't have much of a problem to look through an example and make sense of it, but LUA seems to make as much sense as a porrige-knife to me...

Toadwart
July 23rd, 2007, 03:48
I wouldn't beat yourself up about it. I write code for a living and still took me awhile to figure out how to do this.

I'll try to post some script showing how to do this later (at work right now;))
However in simple terms:

-You create a function that calculates the XP field (by looking atthe current value in the Skill field)
-You tell FG (usually within the onInit function of your Skill field) that you want the calculation function to run whenever the value of your Skill field changes.
-FG takes care of the rest

something like this:



<numberfield name="xp_abc">
...
</numberfield>
<numberfield name="skill_abc">
...
<script>
function onInit()
getDatabaseNode().onUpdate = calculateXP;
end
function calculateXP(source)
local skillValue = source.getValue();
window.xp_abc.getDatabaseNode().setValue( ((skillValue*skillValue) / 2) + (skillValue / 2);
end
</script>
</numberfield>




A basic calculated field:



<numberfield name="skill_abc">
<bounds>10,20,20,20</bounds>

<script>
function onInit()
getDatabaseNode().onUpdate = calculateXP;
end
function calculateXP(source)
local skillValue = source.getValue();
window.getDatabaseNode().getChild("xp_abc").setValue( ((skillValue*skillValue) / 2) + (skillValue / 2) );
end
</script>
</numberfield>
<numberfield name="xp_abc">
<bounds>40,20,20,20</bounds>
</numberfield>

Oberoten
July 23rd, 2007, 04:03
<numberfield name="test1">
<bounds rect="153,366,24,16" />
<font name="smallcontrol" />

<description field="Test1" />
<tabtarget> <next>attribute11_name</next> <prev>attribute10_name</prev>
</tabtarget>
</numberfield>
<stringfield name="Test2" >
<bounds rect="12,385,139,21" />
<tabtarget> <next>attribute11_value</next> <prev>attribute10_value</prev>
</tabtarget>
<static>Changes Me</static>
</stringfield>
<numberfield name="test2">
<bounds rect="153,386,24,16" />
<font name="smallcontrol" />
<script>
function onValueChanged()
if getValue(test1) &lt; 0 then
setValue(25);
end
end
</script>
<description field="attribute11_name" />
<tabtarget> <next>attribute12_name</next> <prev>attribute11_name</prev>
</tabtarget>
</numberfield>



... should change Test2 when Test1 goes negative? Why doesn't it?

joshuha
July 23rd, 2007, 04:16
Try this for test2. It doesn't know to look for test1 changes unless you tell it to (called a handler):



<numberfield name="test2">
<bounds rect="153,386,24,16" />
<font name="smallcontrol" />
<script>
function onValueChanged()
if source.getValue() &lt; 0 then
setValue(25);
end
end
function onInit()
source = window.getDatabaseNode().getChild("test1");
source.onUpdate = onValueChanged
onValueChanged()
end
</script>
<description field="attribute11_name" />
<tabtarget> <next>attribute12_name</next> <prev>attribute11_name</prev> </tabtarget>
</numberfield>

Toadwart
July 23rd, 2007, 04:17
<numberfield name="test1">
<bounds rect="153,366,24,16" />
<font name="smallcontrol" />

<description field="Test1" />
<tabtarget> <next>attribute11_name</next> <prev>attribute10_name</prev>
</tabtarget>
</numberfield>
<stringfield name="Test2" >
<bounds rect="12,385,139,21" />
<tabtarget> <next>attribute11_value</next> <prev>attribute10_value</prev>
</tabtarget>
<static>Changes Me</static>
</stringfield>
<numberfield name="test2">
<bounds rect="153,386,24,16" />
<font name="smallcontrol" />
<script>
function onValueChanged()
if getValue(test1) &lt; 0 then
setValue(25);
end
end
</script>
<description field="attribute11_name" />
<tabtarget> <next>attribute12_name</next> <prev>attribute11_name</prev>
</tabtarget>
</numberfield>



... should change Test2 when Test1 goes negative? Why doesn't it?

The getValue function doesn't work like that I'm afraid.
Do you have the console open when changing the field value? (type /console into the chat window to open it). You should see an error like "blah blah getValue a nil value" or something to that effect because getValue by itself like that isn't recognised as a valid function.

getValue is defined function for databasenode objects. So you need a databasenode object before you can use it.
e.g.



<script>
function onValueChanged()
if getDatabaseNode().getValue() &lt; 0 then
setValue(25);
end
end
</script>

Toadwart
July 23rd, 2007, 04:18
Oh, hi Joshua. Fancy running into you here :D

Oberoten
July 23rd, 2007, 04:31
So lets say I just wish to retrieve the value of the stat Strength (which is on the first level of the charactersheet) and use that in a calculation...


test1 = getDatabaseNode(charsheet.strength).getValue() ;

?

joshuha
July 23rd, 2007, 04:52
One thing you have to remember is that functions are always relative to the calling control. Therefore getDatabaseNode() by itself is going to return the node you are calling it from.

On a charactersheet, any window you are on (besides within a windowlist), window.getDatabaseNode() will return the current character node. From there you can navigated to any DB node from there. So if your strength score sits at the top level, window.getDatabaseNode().getChild("strength").getValue() should work.

Note that if something is on the same window you can take a slight shortcut. So say strength was on the same window, window.strength.getDatabaseNode().getValue() would work.

In general doing it the first way is better even if it's a bit longer as if you ever move controls around you don't have to worry if they are on the same window.

Oberoten
July 23rd, 2007, 05:06
Okay. :)

Now I get how to fetch values...
The second question then : How do I put them back to another node?

I have the finished value and I wish to put it into Test2 ?

Oberoten
July 23rd, 2007, 05:22
Ahhhhhhhhhhhhhhhhhhhhhh.....

Epiphany moment. :)

window.getDatabaseNode().getChild("test1").setvalue(Valuehere)

*now* I get it.

Spyke
July 13th, 2008, 18:49
On a charactersheet, any window you are on (besides within a windowlist), window.getDatabaseNode() will return the current character node. From there you can navigated to any DB node from there. So if your strength score sits at the top level, window.getDatabaseNode().getChild("strength").getValue() should work.How do we navigate to other nodes if we are in a windowlist? I can get to the root using getParent() a few times, but when I try to use that it just gives me nil index errors.

I'm trying to get back to the other nodes on a character sheet from within a windowlist created on a minisheet. The minisheet has clearly got the same database source as the calling sheet, because the name field is linked correctly, but I can't figure out how to reference other fields outside the windowlist.

Any help gratefully received; I've been banging my head over this one all day!

Cheers,
Spyke

joshuha
July 14th, 2008, 00:55
Once you get at the list node it self you can put the children as objects in a LUA table using .getChildren(). Then you loop over children and get at the values. In the example below I use this to get the total weight of the items in a list. Assume source is your parent list node.



function total()
temp = 0;
templist = source.getChildren();
for i in pairs(templist) do
if templist[i].getChild("invweight") then
temp = temp + templist[i].getChild("invweight").getValue();
end
end
window.getDatabaseNode().getChild("weight.inv").setValue(temp);
end

Foen
July 14th, 2008, 06:11
From within a windowlist, you can access the containing node using:

windowlist.window.getDatabaseNode()

Hope that helps,

Foen

Spyke
July 14th, 2008, 07:37
Many thanks to both of you.

Foen, I'd been trying windowlist.getDatabaseNode(), but of course, that just gets the environment of the list, so you have to add .window to get to the environment of the window. One of those classic <doh> moments!

And Joshuha, great! That was my next task.

Cheers,
Spyke