PDA

View Full Version : Having two fields reference one another with scripts



cscase
August 23rd, 2013, 06:26
Hey all,
I'm trying to put two numberfields on a character sheet and have their scripts reference one another, but having trouble getting things to work. I think this is a pretty straightforward example and I suspect one of you will be able to easily point out where I'm going wrong (knock on wood!).

The values are a rating (i.e. maximum value) and a pool (i.e. current value). So, what I'm trying to do in my script is just some basic sanity checking, like in this example, check to see if incrementing the pool value with scroll wheel would increase it above the max. But when I do things as I have it here, I get the error:

attempt to index field 'stats' (a nil value)

Here's how I'm trying to do it:


<numberfield name="SanPool" source=".stats.Sanity.pool">
... (various unrelated stuff here, position etc.) ...
<script>
function onWheel(notches)
if (getValue() + notches) &lt;= window.stats.Sanity.rating.getValue()then
setValue(getValue() + notches);
else setValue(window.stats.Sanity.rating.getValue());
end
return true;
end

function onValueChanged()
if getValue() &gt; window.stats.Sanity.rating.getValue() then
setValue(window.stats.Sanity.rating.getValue());
end
end
</script>
</numberfield>


And here's what the relevant portion of my database looks like:


<root version="2.9" release="1">
<charsheet>
<id-00001>
<stats>
<Sanity>
<pool type="number">13</pool>
<rating type="number">3</rating>
</Sanity>
</stats>


If I Debug.chat(getDatabaseNode()) from this control, the output says:

databasenode = { charsheet.id-00001.stats.Sanity.pool }

And if I say Debug.chat(window.getDatabaseNode()), it says:

databasenode = { charsheet.id-00001 }

If I do Debug.chat(window.stats.getDatabaseNode()) I get the error message.

If I try to use getParent() I just get an error. Maybe I'm calling that function incorrectly or it's somehow out of scope?

Tell me I'm doing something really silly. You have my thanks for reading this!

Scott

Trenloe
August 23rd, 2013, 13:53
window.stats is looking for a control called "stats" - I'm guessing the control is not called that? You don't include the XML for that control so I don't know if this is right or not.

Use window.getDatabaseNode.getChild("stats.Sanity.rating") to return the database node for rating.

cscase
August 23rd, 2013, 15:44
Hrmm, aha, well maybe I am missing some important understanding here. There isn't a control called stats. I just set the sources that way so that, in my database, sanity and hit points would be grouped together in a neat little group called stats, in the same way that skills are nicely grouped under a database heading called skills. But it sounds like I need to tie that to an actual control or something? Maybe I could rename the frame that these controls appear in to stats, so that stats is an actual control and not just a heading in the db.xml?

Trenloe
August 23rd, 2013, 16:24
You don't specifically need a control in the GUI to get to the data. It is just that window.XXXXX is looking for a control called XXXX in the window So when you are using window.stats it is looking for a control called "stats" in the "window".

Your database structure is fine, it is just that you need to reference the database to access it, not trying to get to it from the window. As you saw above window.getDatabaseNode is a good place to get the whole database node for the charsheet and then use getChild commands to get specific data. See this thread for information on doing exactly this:

https://www.fantasygrounds.com/forums/showthread.php?19364-Finding-Base-Definitions-AC-HP-etc&highlight=Databasenode

cscase
August 25th, 2013, 04:43
Trenloe, thank you so much for explaining these things to myself and others, both here and in your linked post. I recognize that you're not google, spitting out answers to my questions in an effortless and robotic fashion, but a real person taking time out of your real life to help me understand this stuff so that I can complete my project, and I heartily thank you. A simple "Thanks!" seems inadequate and I want to make sure you know that I appreciate your help greatly. (This goes for you too, Dakadin and MoonWizard, if you see this.)

I think what was my real problem here was, once again, a poor understanding of scope as it applies. I saw a list of functions and I didn't understand why getDatabaseNode() would work, but just saying getParent() wouldn't. (I needed to call getParent() in the appropriate scope/context by prefacing it with a node, if I now understand correctly.) I think you've rectified that with your explanations, and I ought to be able to proceed. Thank you once again, so much.

Scott

Trenloe
August 25th, 2013, 05:04
Trenloe, thank you so much for explaining these things to myself and others, both here and in your linked post. I recognize that you're not google, spitting out answers to my questions in an effortless and robotic fashion, but a real person taking time out of your real life to help me understand this stuff so that I can complete my project, and I heartily thank you. A simple "Thanks!" seems inadequate and I want to make sure you know that I appreciate your help greatly. (This goes for you too, Dakadin and MoonWizard, if you see this.)
No problem at all - I'm glad I can help, and thanks for the thank you. :)


I think what was my real problem here was, once again, a poor understanding of scope as it applies. I saw a list of functions and I didn't understand why getDatabaseNode() would work, but just saying getParent() wouldn't. (I needed to call getParent() in the appropriate scope/context by prefacing it with a node, if I now understand correctly.)
Yep, your understanding is correct - most of the functions (commands) have to be called with the package, object or element variable first <variable>.<function>. getDatabaseNode() is one of the few functions that that be called on its own, but may not return a value if it is being referenced in a function/event that does not have a database node associated with it.

One thing Moon_Wizard mentioned to me the other day - he makes use of the DB class (https://www.fantasygrounds.com/refdoc/DB.xcp) quite a lot when he knows exactly the whole name of the DB sourcenode he wants to reference. For example, using one of the new fields in your database, to get the sanity.pool value for charsheet id-00001 use:

DB.getValue("charsheet.id-00001.stats.Sanity.pool)

https://www.fantasygrounds.com/refdoc/DB.xcp#getValue

This just returns the just the value and there is no need to get a databasenode and then get the value from the databasenode - this would be a quick lookup and would not create a databasenode, saving time and memory.