PDA

View Full Version : Getting the Sum of several Fields and applying to another Field



damned
September 6th, 2014, 09:24
Disclaimer - this is not being written by a programmer... Im fumbling around here by match light and Im keen to learn from all you smart peoples out there...

I have 6 Wounds Fields - cleverly labelled



<!-- Wounds 1 -->
<number_wound name="wound1" source="wounds.wound1">
<anchored to="woundsframe" position="insidetopleft" offset="65,15" width="20" height="20" />
<frame name="fieldlight" offset="4,4,4,4" />
<labelres>char_label_wounds</labelres>
</number_wound>

....

<!-- Wounds 6 -->
<number_wound name="wound6" source="wounds.wound6">
<anchored to="wound5" position="right" offset="2,0" width="20" />
<frame name="fieldlight" offset="4,4,4,4" />
</number_wound>


In the template for number_wound I have the following code:



<template name="number_wound">
<basicnumber>
<tooltip><text>Wound Value. Each Wound heals by 1hp overnight. Click to Edit.</text></tooltip>
<default>0</default>
<script>
function onValueChanged()
onUpdateWounds();
end

function onUpdateWounds()
local nWounds1 = tonumber(wound1.getValue());
local nWounds2 = tonumber(wound2.getValue());
local nWounds3 = tonumber(wound3.getValue());
local nWounds4 = tonumber(wound4.getValue());
local nWounds5 = tonumber(wound5.getValue());
local nWounds6 = tonumber(wound6.getValue());
local wounds.nWoundsTotal = nWounds1 + nWounds2 + nWounds3 + nWounds4 + nWounds5 + nWounds6;
window.wounds.total.setValue(nWoundsTotal);
end

</script>

</basicnumber>
</template>


I get the following errors on loading the ruleset and I nothing happens on updating any of the values...

Script Error: [string "charsheet_main:wound1"]:1: unexpected symbol near '.'
Script Error: [string "charsheet_main:wound2"]:1: unexpected symbol near '.'
Script Error: [string "charsheet_main:wound3"]:1: unexpected symbol near '.'
Script Error: [string "charsheet_main:wound4"]:1: unexpected symbol near '.'
Script Error: [string "charsheet_main:wound5"]:1: unexpected symbol near '.'
Script Error: [string "charsheet_main:wound6"]:1: unexpected symbol near '.'
Script Error: [string "wound1"]:1: unexpected symbol near '.'
Script Error: [string "wound2"]:1: unexpected symbol near '.'
Script Error: [string "wound3"]:1: unexpected symbol near '.'
Script Error: [string "wound4"]:1: unexpected symbol near '.'
Script Error: [string "wound5"]:1: unexpected symbol near '.'
Script Error: [string "wound6"]:1: unexpected symbol near '.'

please forgive my absolute ignorance!

Trenloe
September 6th, 2014, 11:25
Change local wounds.nWoundsTotal = ... to local nWoundsTotal = ...

damned
September 6th, 2014, 11:33
Thanks Trenloe - that fixed the above warning - I wasnt looking at that line because I was seeing 6 warnings so i was looking at the 6 lines above it...

On mkaing that change it load without error but on changing one of the 6 fields (in this case wounds2) I get:

Runtime Notice: Reloading ruleset
Script Error: [string "wound2"]:1: attempt to index global 'wound1' (a nil value)

Actually any of the 6 I change generates an error referencing 'wound1' (a nil value)

Runtime Notice: Reloading ruleset
Script Error: [string "wound2"]:1: attempt to index global 'wound1' (a nil value)
Script Error: [string "wound1"]:1: attempt to index global 'wound1' (a nil value)
Script Error: [string "wound3"]:1: attempt to index global 'wound1' (a nil value)

why is it calling it a string value? Ive used tonumber(); so maybe its erroring before that...

local nWounds2 = tonumber(window.wound2.getValue());

Ive also tried with:

local nWounds2 = tonumber(wound2.getValue());

damned
September 6th, 2014, 11:34
Change local wounds.nWoundsTotal = ... to local nWoundsTotal = ...

doh! Im looking at that again now... dopey!

Trenloe
September 6th, 2014, 11:47
string "wound2" is just part of the error handling and it is telling you the name of the control where the error is occurring.

The error you are getting:attempt to index global 'wound1' (a nil value), means that FG can't find the wound1 control and errors out at that point (no code gets ran after the error). Does window.wound1.getValue() work? You'll need to work out the exact control hierarchy and test it against wound1 (as this is the first of your 6 controls you access in the code). Once you get that working (you'll then get an error for wound2) you can code up the rest of the woundX.getValue() correctly.

damned
September 6th, 2014, 12:06
what are some other code hierarchy options that might work?

damned
September 6th, 2014, 12:15
so this debug:



Debug.console("Hello World!");
Debug.console("Does the next line even run?");
local sMyWounds1 = window.wound1.getValue();
local sMyWounds2 = window.wound2.getValue();
local sMyWounds3 = window.wound3.getValue();
local sMyWounds4 = window.wound4.getValue();
local sMyWounds5 = window.wound5.getValue();
local sMyWounds6 = window.wound6.getValue();
Debug.console("Wound1:" .. sMyWounds1 .. ":" .. sMyWounds2 .. ":" .. sMyWounds3 .. ":" .. sMyWounds4 .. ":" .. sMyWounds5 .. ":" .. sMyWounds6);


puts out:



Runtime Notice: Reloading ruleset
Runtime Notice: s'Hello World!'
Runtime Notice: s'Does the next line even run?'
Runtime Notice: s'Wound1:433100'
Script Error: [string "wound4"]:1: attempt to index global 'wound1' (a nil value)


so it looks like it needs window.wound6.getValue(); but then it doesnt seem to be changing to an int?

Trenloe
September 6th, 2014, 12:16
what are some other code hierarchy options that might work?
Look at how your XML is used to define the window. I notice you use window.wounds.total in post #1, would window.wounds.wound1 work?

You should be able to work it out from your XML specification of the controls. Without seeing all of your XML all I can do is guess.

Trenloe
September 6th, 2014, 12:20
so this debug:



Debug.console("Hello World!");
Debug.console("Does the next line even run?");
local sMyWounds1 = window.wound1.getValue();
local sMyWounds2 = window.wound2.getValue();
local sMyWounds3 = window.wound3.getValue();
local sMyWounds4 = window.wound4.getValue();
local sMyWounds5 = window.wound5.getValue();
local sMyWounds6 = window.wound6.getValue();
Debug.console("Wound1:" .. sMyWounds1 .. ":" .. sMyWounds2 .. ":" .. sMyWounds3 .. ":" .. sMyWounds4 .. ":" .. sMyWounds5 .. ":" .. sMyWounds6);


puts out:



so it looks like it needs window.wound6.getValue(); but then it doesnt seem to be changing to an int?
I don't understand what you're asking here.

Trenloe
September 6th, 2014, 12:22
I think things might be made a little easier for you to debug if you moved your code out of the <script> section of the XML and I to a .LUA file.

Code in a .LUA file is easier to debug as FG's error handler will tell you the line where the error is actually occurring. Plus you can easily put comments in the code.

Trenloe
September 6th, 2014, 12:24
Look at how your XML is used to define the window. I notice you use window.wounds.total in post #1, would window.wounds.wound1 work?
Obviously not, as I think that is the cause of your error in post #7.

damned
September 6th, 2014, 13:12
I think things might be made a little easier for you to debug if you moved your code out of the <script> section of the XML and I to a .LUA file.

Code in a .LUA file is easier to debug as FG's error handler will tell you the line where the error is actually occurring. Plus you can easily put comments in the code.

do share how one might achieve such a feat?

Anyways... it looks like I can retrieve window.wounds.wound1 as a string value?
I then tried to use the code:

local nWounds1 = tonumber(sMyWounds1);

to convert that value to a number...

but I dont think its doing that.... its referencing string "wound2" and then its talking about a global 'wounds' that I dont know where it is getting it from...?

Runtime Notice: Reloading ruleset
Runtime Notice: s'Hello World!'
Runtime Notice: s'Does the next line even run?'
Runtime Notice: s'Wound1:3:3:2:0:0:0'
Runtime Notice: s'Wound1:3:3:2:0:0:0'
Runtime Notice: s'nWound1:3:3:2:0:0:0'
Script Error: [string "wound2"]:1: attempt to index global 'wounds' (a nil value)

Trenloe
September 6th, 2014, 13:30
do share how one might achieve such a feat?

See the "Using Scripts" section of this page: https://www.fantasygrounds.com/modguide/scripting.xcp


Anyways... it looks like I can retrieve window.wounds.wound1 as a string value?
This is causing an error - see below.


but I dont think its doing that.... its referencing string "wound2" and then its talking about a global 'wounds' that I dont know where it is getting it from...?
As mentioned in post #5 above, the reference to string is not telling you that wound2 is a string type - it is telling you that the error is being caused in the "wound2" control. The mention of string is misleading.


Script Error: [string "wound2"]:1: attempt to index global 'wounds' (a nil value)
The error tells you the issue - "wounds" doesn't exist. The only place you are using "wounds" is in window.wounds.wound1. I only mentioned this because you had used this in your first post - but it is obviously not valid (as I mentioned in post #11 above).

Recommendations:

Move your code to a LUA file.
Take a step back and map out your control hierarchy on a piece of paper. At the moment you are just making changes and hope they will work. Look at your <windowclass> XML specification and map out the control hierarchy.
Learn to interpret the error messages. For example, Script Error: [string "wound2"]:1: attempt to index global 'wounds' (a nil value) is telling you the error is occurring in the script of control wound2 - this is the error location. The actual error is attempt to index global 'wounds' (a nil value) which is telling you that wounds is not a valid variable/object at this point in the code. Moving the code to a LUA file will also give you a meaningful line number as to exactly where the error is occurring - coding directly in the <scripts> section of a control always indicates the error is at line 1 - which is no help.

Step #2 is a typical newbie approach - keep changing stuff until it works, but then you have no idea why it worked. Take a step back and map out your controls - the time you spend to do that now will save you lots of time (and frustration) when you're actually coding. I'm guessing it's a very simple hierarchy - even so, you need to get it clear in your head (and on paper).

damned
September 6th, 2014, 13:48
Gaaaargh!

I stuck this in a new file: woundscalc.lua



function onValueChanged()
onUpdateWounds();
end

function onUpdateWounds()

Debug.console("Hello World!");
Debug.console("Does the next line even run?");
local sMyWounds1 = window.wound1.getValue();
local sMyWounds2 = window.wound2.getValue();
local sMyWounds3 = window.wound3.getValue();
local sMyWounds4 = window.wound4.getValue();
local sMyWounds5 = window.wound5.getValue();
local sMyWounds6 = window.wound6.getValue();
Debug.console("Wound1:" .. sMyWounds1 .. ":" .. sMyWounds2 .. ":" .. sMyWounds3 .. ":" .. sMyWounds4 .. ":" .. sMyWounds5 .. ":" .. sMyWounds6);


local nWounds1 = tonumber(sMyWounds1);
local nWounds2 = tonumber(sMyWounds2);
local nWounds3 = tonumber(sMyWounds3);
local nWounds4 = tonumber(sMyWounds4);
local nWounds5 = tonumber(sMyWounds5);
local nWounds6 = tonumber(sMyWounds6);
Debug.console("Wound1:" .. sMyWounds1 .. ":" .. sMyWounds2 .. ":" .. sMyWounds3 .. ":" .. sMyWounds4 .. ":" .. sMyWounds5 .. ":" .. sMyWounds6);
local nWoundsTotal = nWounds1 + nWounds2 + nWounds3 + nWounds4 + nWounds5 + nWounds6;
Debug.console("nWound1:" .. nWounds1 .. ":" .. nWounds2 .. ":" .. nWounds3 .. ":" .. nWounds4 .. ":" .. nWounds5 .. ":" .. nWounds6);
wounds.wtotal.setValue(nWoundsTotal);
end

In my template_char.xml I used:


<template name="number_wound">
<basicnumber>
<tooltip><text>Wound Value. Each Wound heals by 1hp overnight. Click to Edit.</text></tooltip>
<default>0</default>
<script file="woundscalc.lua" />
</basicnumber>
</template>

But now nothing seems to be being executed… Im not seeing any debug etc… or errors….

So back to your very astute observation about my n00bie flailings...


Take a step back and map out your control hierarchy on a piece of paper. At the moment you are just making changes and hope they will work. Look at your <windowclass> XML specification and map out the control hierarchy.

<windowclass name="charsheet_main">
<number_wound name="wound1" source="wounds.wound1">
and
<number_woundstotal name="woundstotal" source="wounds.wtotal">

wounds as a db entry doesnt exit. wounds.wound1-6 exist, as does wounds.wtotal

wounds.wtotal.setValue(nWoundsTotal);
or
window.wounds.wtotal.setValue(nWoundsTotal);

or one of my many other flailings (I did change wounds.total to wounds.wtotal since the beginning of this thread) is generating that error - or was before I split my code into the separate LUA...
wounds is part of the db entry name (I think thats correct?)

Trenloe
September 6th, 2014, 14:06
<script file="woundscalc.lua" /> needs to use the full path (within your ruleset). e.g. campaign\scripts\woundscalc.lua or wherever you put it. Do a "find in files" in CoreRPG for <script file and you'll see plenty of examples.


So back to your very astute observation about my n00bie flailings...

<windowclass name="charsheet_main">
<number_wound name="wound1" source="wounds.wound1">
and
<number_woundstotal name="woundstotal" source="wounds.wtotal">

wounds as a db entry doesnt exit. wounds.wound1-6 exist, as does wounds.wtotal

wounds.wtotal.setValue(nWoundsTotal);
or
window.wounds.wtotal.setValue(nWoundsTotal);

or one of my many other flailings (I did change wounds.total to wounds.wtotal since the beginning of this thread) is generating that error - or was before I split my code into the separate LUA...
wounds is part of the db entry name (I think thats correct?)
You need to separate your thinking of GUI control elements and database elements.

GUI Elements
window.<anything> will always refer to GUI control elements - window. is essentially referencing the windowinstance that is created by <windowclass> in your XML file.

Therefore, from the small portion of your <windowclass> defintion above, the following are valid ways of getting access to a specific GUI control:

window.wound1 Accesses this control using the name field as the reference: <number_wound name="wound1" source="wounds.wound1">
window.woundstotal Accesses this control using the name field as the reference: <number_woundstotal name="woundstotal" source="wounds.wtotal">

You can then use API calls from the "Elements" section here: https://www.fantasygrounds.com/refdoc/ The API calls you can use will depend on the base FG control type.

Database Elements
You can't just reference database elements without first having a databasenode object to work against: https://www.fantasygrounds.com/refdoc/databasenode.xcp More info here: https://www.fantasygrounds.com/modguide/database.xcp

This is why you keep getting attempt to index global 'wounds' (a nil value) error messages when you try to use wounds to access values stored in the database, e.g. wounds.wound1 is the name of the field within the Fantasy Grounds database structure, but you can't just reference it with that name - you need to get a databasenode object before you can start interacting with the database.

I'd recommend you just initially work against one type of FG element - the GUI controls or the database. You seem to have a better (?) grip on the GUI side at the moment so just work with that for the time being. At some point you'll need to move into the database side, but leave that for later - it will be too confusing for you at this point.

damned
September 6th, 2014, 14:08
<script file="woundscalc.lua" /> needs to use the full path (within your ruleset). e.g. campaign\scripts\woundscalc.lua or wherever you put it. Do a "find in files" in CoreRPG for <script file and you'll see plenty of examples.


I put it in teh same folder as the other files. hence no path.

damned
September 6th, 2014, 14:09
ok - i added the folder name as even though they are in the same folder they ARE in a folder...
now its being referenced.

Trenloe
September 6th, 2014, 14:11
I put it in teh same folder as the other files. hence no path.
Use the full path within the ruleset.

Trenloe
September 6th, 2014, 14:14
ok - i added the folder name as even though they are in the same folder they ARE in a folder...
now its being referenced.
So, you actually believe what I was saying now then? :p

Once FG starts going through all of the XML definitions it isn't aware of the location of the file where the XML definition came from. XML definitions can be expanded with merge rules from many different places so the final XML could be made up of bits-and-bobs from different files in different locations. Hence why you need to use the full path within the ruleset to get to the LUA file. There was a reason why I said you had to do that! ;)

Trenloe
September 6th, 2014, 14:19
I put it in teh same folder as the other files. hence no path.
FG sees no path as the root directory of the ruleset.

damned
September 6th, 2014, 14:39
So, you actually believe what I was saying now then? :p

Occasionally.
When you hit me in the head with the info enough times... I just might believe you.

damned
September 6th, 2014, 14:42
I'd recommend you just initially work against one type of FG element - the GUI controls or the database. You seem to have a better (?) grip on the GUI side at the moment so just work with that for the time being. At some point you'll need to move into the database side, but leave that for later - it will be too confusing for you at this point.

So... I thought I had to reference the database node... so i referenced the GUI control instead.... walah!
So I owe you (another) beer!


window.woundstotal.setValue(nWoundsTotal);

And it seems to still save it in the DB...

Stay tuned... I think Im going to need some help again shortly... new topic though!

Trenloe
September 6th, 2014, 19:42
And it seems to still save it in the DB...
Your GUI controls have their database sources defined, so the GUI controls are linked to the database. If you update the control the database will be automatically updated and if you update the database the GUI control will be automatically changed to reflect the database change.

Usually, you don't need to have the <source> defined for each control they will use the name of the control as default for the related entry in the database. See the third paragraph of the generic "Window Control" element description: https://www.fantasygrounds.com/refdoc/windowcontrol.xcp

The exact location of the the data in the database is the <windowclass> <datasource> entry, see the "definition" section of the <windowclass> element: https://www.fantasygrounds.com/refdoc/windowinstance.xcp

Also see the third paragraph in the windoinstance description: https://www.fantasygrounds.com/refdoc/windowinstance.xcp A windowinstance is the resulting FG element created from the <windowclass> definition.


Stay tuned... I think Im going to need some help again shortly... new topic though!
I guessed as much... ;)