PDA

View Full Version : Expecting nil when first attempting to access node but it exists and has a default



Varsuuk
July 24th, 2020, 06:51
[EDIT: IGNORE THREAD - I forgot the fact that if a control is a dbsourced control it will create the XML fields when OPENED not just imported, the rest makes sense once remembered order of actions and this whole thread might confuse more than helps but can't delete it or my contents - if did would orphan responses. and prob be rude :) ]


I have a PreGen setup for this MoreCore extension (originally based off OSE and Tutorial)
The pregen does not have the ac.xxx fields nor the aac.xxxx fields in it. When I import from pregen and do /save I do not see any "ac" or "aac" entries - which is exactly what I expect.

But when I click on it, the behavior and logging indicates that it is not returning a nil from my "check"


What is the best way to check if a node exists? I presumed:

if DB.getChild(nodeChar, "ac.armour") == nil then


The code I have is confusing me, in some previous incarnation (before rearranged) I was getting "nil" when doing:

DB.getValue(dbNode, "ac.armour")



Here is the log part that matters:


Runtime Notice: s'---> onInit()'
Runtime Notice: databasenode = { charsheet.id-00001 }
Runtime Notice: bFALSE
Runtime Notice: s'initACFields'
Runtime Notice: databasenode = { charsheet.id-00001.ac.armour }
Runtime Notice: s'initAACFields'
Runtime Notice: databasenode = { charsheet.id-00001.aac.armour }
Runtime Notice: s'displayACSystemUsed'
Runtime Notice: s'---> DONE: onInit()'



The code is on the record_char_more.xml:


<root>
<!-- New WindowClass "charsheet_more" -->
<windowclass name="charsheet_more" merge="join">

<script>
function onInit()
Debug.console("---> onInit()")
if super.onInit() then
super.onInit()
end

local nodeChar = getDatabaseNode()
Debug.console(nodeChar)


local bIsAACEnabled = OptionsManager.isOption("AlternateRule_UseAscendingAC", "on")
Debug.console(bIsAACEnabled)

CharacterUpdate.initACFields(nodeChar)
CharacterUpdate.initAACFields(nodeChar)

OptionsManager.registerCallback("AlternateRule_UseAscendingAC", onARUseAscendingACChanged);
displayACSystemUsed(bIsAACEnabled)
Debug.console("---> DONE: onInit()")
end


The field I am checking first, for example, is:


function initACFields(nodeChar)
Debug.console("initACFields")
Debug.console(DB.getChild(nodeChar, "ac.armour"))
if DB.getChild(nodeChar, "ac.armour") == nil then
DB.setValue(nodeChar, "ac.armour", "number", 9)
DB.setValue(nodeChar, "ac.dex", "number", 0)
DB.setValue(nodeChar, "ac.bonus", "number", 0)
end
updateAC(nodeChar)
end


And by this point, the Debug prints that ac.armour node seems to exist if I read this right?
How, I thought getChild does not create it if not found?

The rest falls apart because I wanted to only reset fields on first creation. IF there is another way, it's fine to suggest it :) but still want to know why getChild returns a valid child.

Later in the XML (I had removed the onInit() for example: (I checked the chain of templates - I THINK - and see no auto setting of default or whatever)


<!-- Replace AC fields -->
<number_ctlink name="defence" merge="replace">
<anchored to="combatframe" position="insidetopright" offset="15,49" />
<tooltip textres="pc_tooltip_defence" />
</number_ctlink>

<!-- Extra AC fields -->
<totnumber name="ac_armour" source="ac.armour">
<anchored to="combatframe" position="insidetopright" offset="96,49" width="18"/>
<tooltip textres="char_label_armour_value"/>
<script>
function onValueChanged()
local nodeWin = window.getDatabaseNode();
Debug.console("AV update");
CharacterUpdate.updateAC(nodeWin);
end
</script>
</totnumber>
<totnumber name="ac_dex" source="ac.dex">
...

damned
July 24th, 2020, 06:59
I dont think getChild will return the same result as getValue?

And good to see you can spell Armour!

Varsuuk
July 24th, 2020, 07:02
Giving up for now. If I put in a typo, like search on "ac.armourr" it correctly returns nil.

SOMETHING is creating things like "ac.armour" before my check. But looking at campaign db (post /save) post import pregen shows NO "ac" fields.

But it is somewhere and being 2am I am guessing I just won't see it tonight ;)

Varsuuk
July 24th, 2020, 07:08
(didn't see your response till now)

I'm sorry Damned
I hate ta breakittoya ... but I'm a gonna be NUKING the heckle out of the British English ;) wherever I am ADDING code and already did on displayed code (strings override few) 'cos sorry my Revolutionary crew will just not let me abide the spelling of King George! I only do not change your existing code since that would necessitate changing things in MoreCore and that ain't right... you win THIS round you mental subject of the Queen!


:)

getChild returns the node (or nil if not found - CLEARLY it is finding it)
getValue on node returns the value.

I KNOW somewhere in this code I am creating ac.armour but ... not seeing it yet. Only explanation is it is created after import but it IS created. Or... gremlins!?

Varsuuk
July 24th, 2020, 07:21
OK - did one last sanity check after a global search on "ac.armour" failed me:

I checked import, no ac.armor...


...
<charsheet>
<id-00001>
<aac>
<armour type="number">0</armour>
<bonus type="number">0</bonus>
<dex type="number">0</dex>
</aac>
<ac>
<armour type="number">0</armour>
<bonus type="number">0</bonus>
<dex type="number">0</dex>
</ac>
<attack_label type="string">Attacks</attack_label>
<cas1_label type="string">Attributes</cas1_label>
<cas1a_label type="string">Attacks</cas1a_label>
<cas2_label type="string">Saving Throws</cas2_label>
<cas2a_label type="string">Melee Damage</cas2a_label>
<cas3_label type="string">Exploration</cas3_label>
<cas3a_label type="string">Ranged Damage</cas3a_label>
<cas4_label type="string">Spells</cas4_label>
<cas5_label type="string">Powers</cas5_label>
<clilist1>
<cha>
...



Then I modified by initACFields method to just return garbage:



function initACFields(nodeChar)
Debug.console("initACFields")
return 10/0
end
--[[
Debug.console(DB.getChild(nodeChar, "ac.armour"))
--local CHECK = DB.getValue(nodeChar, "ac.armour")
--Debug.console(CHECK)
if DB.getChild(nodeChar, "ac.armour") == nil then
--if CHECK == nil then
DB.setValue(nodeChar, "ac.armour", "number", 9)
DB.setValue(nodeChar, "ac.dex", "number", 0)
DB.setValue(nodeChar, "ac.bonus", "number", 0)
end
updateAC(nodeChar)
end
--]]

(I didn't mangle the initAACFields() method...)

And I see see this after it runs:


<charsheet>
<id-00001>
<aac>
<armour type="number">0</armour>
<bonus type="number">0</bonus>
<dex type="number">0</dex>
</aac>
<ac>
<armour type="number">0</armour>
<bonus type="number">0</bonus>
<dex type="number">0</dex>
</ac>
<attack_label type="string">Attacks</attack_label>
<cas1_label type="string">Attributes</cas1_label>
<cas1a_label type="string">Attacks</cas1a_label>
<cas2_label type="string">Saving Throws</cas2_label>
<cas2a_label type="string">Melee Damage</cas2a_label>
<cas3_label type="string">Exploration</cas3_label>
<cas3a_label type="string">Ranged Damage</cas3a_label>
<cas4_label type="string">Spells</cas4_label>
<cas5_label type="string">Powers</cas5_label>
<clilist1>
<cha>

Varsuuk
July 24th, 2020, 07:32
[EDIT] - nevermind, the ctlink field is for the defence[sic ;P] so still no idea.

This is why I never sleep when I code at night ;P ideas keep popping into head.

This is a "number_ctlink" field - which, if I get right is linked (I mean I see this) to CT. Maybe because of this something automatically creates it once the character is loaded. Will have to try same check on neighbor control see if different. But will try tomorrow.

Sigh...

damned
July 24th, 2020, 14:46
Ok I have some vague recollection - maybe in the DbD extension I may have...

created 3 additional ac fields to collect Armour, Dex and any Bonus AC.
then there might be a handler or more likely just an onValueChanged that checks for any changes on those fields and updates the Defense value...

something like that...
not in MoreCore but in DbD which is Im guessing where the code base you are working from got the code....

Varsuuk
July 24th, 2020, 15:27
Yeah, I guess I get part of it now.

Since there is a UI element that has a DBsource, as soon as you OPEN the UI element it populates all the xml/db fields.
That's why when I import, before opening it I see only the programmatically created fields.

Stepping back to what I thought I was covering was:
First time I startup, I can assign a value to the Armour field on onInit()

Butt onInit() will be called again when I restart FG and open this sheet again. I don't want it resetting the value.
I could initialize it out of range and check for that (dislike this) - what I thought (incorrectly) to do was to find if the field exists then initialize it if it doesn't. Thing is, it exists before onInit() if it is in the sheet.


So, what I am asking most simply, is how do I best do a "one time" init of a field? If I do nothing, the field is created with value of 0 ... which is indistinguishable from AC 0. Subsequent starts and loads should, of course, keep whatever value was actually entered or defaulted in initial load.

Varsuuk
July 24th, 2020, 15:35
So, to move on - I added a
<default></default> to one of the fields in each that I examine. I just wanted it to be done in code vs XML but I am not seeing a way to do so. This solves it, I should have just moved on with this last night but I was forgetting that xml was created on load not import so was thinking I was doing something else wrong since it wasn't on the sheet when checked after import and yet found when looked for nil programmatically.

Moving on with it doing what I want, even if not in way I intended at first. It's way API intended and I am OK with following that once I realized that: "it is the way" (Mando ftw)

Varsuuk
July 24th, 2020, 15:51
Since I missed that little connection literal and figurative in my head - it kind of makes this whole thread meaningless since it wasn't what I was coding wrong, it was that it could NEVER give me nil in the first place due to it being a Control for a DBField (ie with explicit or implicit source= attrib)

damned
July 25th, 2020, 02:06
Ok so I added those three fields - again Im referencing my DbD and not necessarily what you are building from - to cover most situations in a clear simple way.
The only automation is summing of those three fields to the Defense field where other Rolls could apply some automation.

My suggestion is - dont auto set this value.
When the player upgrades from Chain Shirt to Plate +1 they can adjust the armour field themselves
or
Add Armour as a type to Items and when someone Equips some armour have it unequip other armour AND set the ac.armour field.
You would need to ensure that you only list Armour as Armour and you dont include something like Braces+1 as Armour - it goes in the third field.

Thats my suggestion...

Varsuuk
July 25th, 2020, 03:52
Yeah - will likely do that stuff with items in the "real" one this is a quick thing with very little automation.

The reason I was defaulting the armour section is that otherwise it will automatically initialize to 0. Which is pretty damn good AC for normal and out of bounds for AAC. Both those issues bother me. I am used to always initializing things when I create them. In any event, my problem was not understanding why the find action did not return nil. I get that now. Once realized that - I did it in a different way. Now AC flavor armour is started at 9 and AAC at 10. So if the player does nothing, he will be easy to hit ;)