PDA

View Full Version : Best way to display “derived” data?



Varsuuk
January 22nd, 2020, 13:51
I am putting on a npc sheet a numeric field that contains AC in descending (as god so intended...) representation and also have in the npc sheet/DB a field for ascending (heretical) AC.

I only want to display the AC on the sheet and for editing (since ascending AC can be derived as a function of descending AC) but would like it to look like this on the sheet:

AC: 8 [11]

My xml has an overall script=... referencing an npc.lua file with the handlers and code for the camp.

So I expected I’d use a string control (or derived from string control with features I also wanted) And would just add an onInit which initialized acasc to a value from ac. Then I could add an onValueChanged handler to ac to update acasc.

Thing is, on that lua script, how do I access acasc_control (for bland example name)? I saw on another npc.lua that folks did self[sControl].update(arg1, arg2)

The index, sControl, was a string with the xxxx portion of the xml attribute: name=“xxxx”.

But if I try:
self[acasc_control].setValue(“...”);

It is rejected. I played with other combos to no avail.


That was the background and what I tried, is there a better (correct) way to populate string controls with label-like values but ones not constant, instead dependent on the particular npc?


And finally, I want the answer above, but I wondered also if I SHOULD include the “formatted” ac field as a string in the npc dv. To me it did not sit well since it is purely derived and never used in play, just for visual formatting.

Trenloe
January 22nd, 2020, 14:25
Use a stringfield or numberfield control (data is stored in the database) and do all of this work at the database level not at the GUI control level.

Varsuuk
January 22nd, 2020, 18:06
Weirdly enough, I received two updates for replies by you. The first being a great lead on where to look to learn how to do this. (I still have the mail text so after get home and try it, will post it with my success story ;) )

The second being the one I see above which is also helpful as a reply to my desk one question - SHOULD I do it in the UI.

I considered the same thing Trekkie[TRENLOE, I hate autocorrect], that’s why asked (though still wanted to know how to do the other way even if don’t do so now). The only reason didn’t just crest a field (so much easier) is that I envisioned the DB entry filling up with stuff only there for UI display like “ACUIText” => “8 [11]” which if the only one, is no big. But if end up creating like 5-6 or more “concatenated data fields” x 100s of monsters, it seems like quite a bloat - if not in bytes but in lines in the xml files. Makes looking at the raw xml a little more cluttery too.


Thanks for both answers. I atm, only have gotten to one other “derived field” my “attacks” field will probably be a concatenated result of scanning all attack types with some decoration.

Trenloe
January 22nd, 2020, 20:23
I deleted the first post after re-reading your post and seeing it was a single field for the NPC - based off inverting the usual AC field. So didn't think the specific total template I mentioned would help. If it does, then go nuts! :)

Varsuuk
January 22nd, 2020, 22:33
I dig. Well, didn’t try grokking it as I saw it at office without benefit of my code access. But will look tonight. What I didn’t get in a more general sense was how to populate a string control “programmatically”, ie . dependent on the dB record’s current state.

The attempts I made to access the field (which might have been way off, even pathetically so probably) didn’t work so I was confused. Even if your example isn’t what I asked about it seems to discuss setting a string control ;) will check later.

Trenloe
January 22nd, 2020, 22:41
Like I said in my replaced post - use "field" controls - which store their data in the database. Then you can code to go direct to the database field - which should always be in the same place in the database hierarchy. This is much more reliable than using GUI hierarchy references - i.e. you can acces it from code that doesn’t have to be running in the GUI, or the same window.

Then you can use standard DB and database node API functions to read/populate the node in he database, and the field control will auto updated to display the value of the DB field it’s anchored on.

If you’re not familiar with how to access the FG database through the API then it’s time to read up on that in the developers guide. This is the best way to handle data access, updates, etc..

celestian
January 22nd, 2020, 22:50
If it's just for visual display and not for actual reference and you know it based on descending AC just create a label control object and set it to "20-nAC" when nAC (probably something like npc-001.ac) is updated. I'd probably attach the update to a handler in the npc_main.lua or something (whatever you use for your lua in your npc.xml).

This presumes you want to only allow the descending AC to be the source of truth that you generate the "display" of ascending AC.

I did a lot of this type of stuff in AD&D Core for Ascending AC. Infact if you grep for "ascending" you'll see most of the code is still there, just commented.

Varsuuk
January 23rd, 2020, 00:43
Thanks Celestian, I just started looking at AD&D Core - I searched on ascending but the first thing I ran into was:

The setting of the handler is commented out but this is the method it would call if it wasn't.
This is similar to what I am trying to do but it looks like here you are setting a DB node.

What I thought made sense for a made-up visual element (I DO store ac in both ascending and descending AC both) which is intended to display both in a formatted way "8 [11]" for example.
I thought of a "label" but those values every time I saw an example are set in the XML explicitly or through string.xml resources. I want to be able update a "readonly" field from both of those fields.




function updateAscendingAC(node)
-- check and see if this is npc.id-XXXXXX.ac, if so drop back a node
if (not node.getPath():match("id%-%d+$"))then
node = node.getParent();
end
local nAC = DB.getValue(node,"ac",10);
local nAscendingAC = DB.getValue(node,"ac_ascending",10);
local newAC = 20 - nAC;
if (nAC < 10 and (newAC ~= nAscendingAC)) then
DB.setValue(node,"ac_ascending","number",newAC);
end
end

Varsuuk
January 23rd, 2020, 01:07
Going back to Trenloe's comments on 3.5, it looks like it just use a database node to hold the value and adjustments together, which I can do - but I THOUGHT it might be "bad" to fill an NPC record with derived data in string form that I am already storing in numeric form

<ac type="string">20 (-1 size, -1 Dex, +9 natural, +3 hide armor), touch 8, flat-footed 20</ac>


In the end, I will have instead of:


<defenses>
<ac type="number">8</ac>
<acasc type="number">11</acasc>
</defenses>


it will be:




<defenses>
<ac type="number">8</ac>
<acasc type="number">11</acasc>
<accombined type="string">8 [11]</acasc>
</defenses>


It just bugged my fixation on keeping things "clean" and "just what is needed" in the data part.
But I haven't yet found any code to even change the value on a non-db control. I should keep looking through code, it HAS to exist, just don't know what to look for. That self[controlname] seemed a good lead.

I'm probably just not asking my question clearly enough :(

celestian
January 23rd, 2020, 03:57
Thanks Celestian, I just started looking at AD&D Core - I searched on ascending but the first thing I ran into was:

The setting of the handler is commented out but this is the method it would call if it wasn't.
This is similar to what I am trying to do but it looks like here you are setting a DB node.

What I thought made sense for a made-up visual element (I DO store ac in both ascending and descending AC both) which is intended to display both in a formatted way "8 [11]" for example.
I thought of a "label" but those values every time I saw an example are set in the XML explicitly or through string.xml resources. I want to be able update a "readonly" field from both of those fields.


Yes, what you are wanting to do was different than what I was doing. I was maintaining both in node values. You said you just want to display it. I mentioned it mostly because of the handlers and various other locals that I found needed tweaks for ascending AC.

Varsuuk
January 23rd, 2020, 04:15
Yuppers, I am definitely will be able to use that as well. Because I am also maintaining both internally. I just wanted to have an AC display that does not display either directly - just combines them into one string (original intended as a UI only control but for now giving up since haven’t see code to update a control for some reason anywhere yet)

In dB, as I listed above - 2 seperatr sub fields to defenses. In UI, a single displayed value: “8 [11]”, which for now ... I’ll deal with it being another stringFIELD instead. For now.

Varsuuk
January 23rd, 2020, 04:27
Of course, now the I go to my NEXT UI element I see I need to again switch from my intention of UI element to DB field.

I store attacks in DB where there may be multiple attack types and my intent was to present this to users in UI front page (vs when USING them and they list separately) summary as:
"2 Claws (1d6), 1 Bite (1d8)"

Of course, after writing this, I realize it will be a pain to ensure plural handling well... my initial writing (which I have never run since still building out) was done quickly without considering not everything is bite/claw/kick/etc (was looking at limited monsters)



function onAttacksChanged()
local aAttacks = DB.getChildren(nodeChar, "attacks");
local nTypesOfAttacks = #aAttacks;
local sAttacks = "";


for idx,attack in ipairs(aAttacks) do
local nNumberOfAttacks = DB.getValue(attack, "numberOfAttacks", 1);
local bIsMoreThanOneAttack = (nNumberOfAttacks > 1);

sAttacks = bIsMoreThanOneAttack and toString(nNumberOfAttacks) or ""
.. DB.getValue(attack, "name") .. bIsMoreThanOneAttack and "s" or ""
.. " (" .. DB.getValue(attack, "damage") .. ")";

if idx ~= nTypesOfAttacks then
sAttacks = sAttacks .. ", ";
end
end
end


So, I will not autopen it but include it as a DB field in monster manual to be displayed. The DOWNSIDE of this is twofold chances of user error. I can enter two non-matchin settings. The entry might say "1 Bite(1d8)" and the body like:



<attacks>
<bite>
<name type="string">Bite</name>
<damage type="string">1d6</damage>
<numberOfAttacks>1</numberOfAttacks>
</bite>
<claw>
<name type="string">Claw</name>
<damage type="string">1d8</damage>
<numberOfAttacks>2</numberOfAttacks>
</claw>
</attacks>


Thing is anyone who codes a lot of data knows typos or mistakes happen and the two entires which should be 100% identical, can be inconsistent or even more likely, drift apart if someone edits one without remembering to edit the other matching field.




As I wrote this ... I realized I COULD create a simple plural map config table where did. Plurals["Claw"] = "Claws". etc. but I digress ... will make a note of it for later...

Trenloe
January 23rd, 2020, 08:39
But I haven't yet found any code to even change the value on a non-db control. I should keep looking through code, it HAS to exist, just don't know what to look for. That self[controlname] seemed a good lead.
To answer this question - see the API documentation: https://www.fantasygrounds.com/refdoc/textbasecontrol.xcp#setValue

To access controls in the GUI hierarchy use <scope>.<control name>

Where scope is detailed here: https://www.fantasygrounds.com/wiki/index.php/Developer_Guide_-_Rulesets_-_Scripting#Script_Block_Scope

For example, if you wanted to access a control called acasc within the same window where the code is running use window.acasc

So, to set a number control to 10: window.acasc.setValue(10);