PDA

View Full Version : Items in windowlist not "refreshing"



DNH
May 31st, 2007, 19:41
I am working on a ruleset for 2e AD&D and am currently trying to get a working drag-and-drop interface for proficiencies. I have module data which works as reference material but also includes the likes of stat used, modifier, number of slots required. This data should be taken over to the character sheet in the drag-and-drop ... and it is. So far, so good.

The thing is, when I drag a proficiency entry into the character sheet for the first time, the entry displays only the name correctly. The remaining fields (slots, stat label, stat value, check modifier and total) are all "set to zero". That is, the slots shows as 0, the stat label and stat value fields are blank, and the check modifier shows as 0. The final field - the total - does not calculate.

I would be prepared to accept that there is something wrong with the script/xml (adapted from the d20 ruleset) BUT some items show correctly upon reloading the character. The slots and stat label both display the correct values. It is as though the windowclass (for this is what it is) needs "refreshing" in order to display correctly.

It still won't display/compute the other fields though.

Any thoughts anyone?

Thanks.

Goblin-King
June 1st, 2007, 05:53
One thing that comes to mind is that the drag only updates the data base, and there is something wrong with the scripts/XML that connects the data base data to the actual controls.

The "statlabel", "ranks" and "stat" controls in the d20 skill list are stringcontrol/numbercontrol types, not stringfield/numberfield. The difference is that the latter take the data from the data base automatically, and the former don't. The reason for this is simply that the d20 ruleset does some intermediate logic on the values, but must take care to update the values itself. (The logic is something like e.g. keeping track of both cross class ranks and class ranks using just one control.)

You would need to switch from controls to fields, or if you need custom processing, make sure to use the onUpdate handler event to keep track of changes.

DNH
June 2nd, 2007, 10:39
thanks for that. i almost have this, in that most things work now (using fields instead of controls), except for the stat. despite my best efforts, i cannot get this to display the value from the off. in fact, it won't display ANY value; it's just blank until i reload FG2 and thenit displays correctly. hmm.

i include the relevant code here, in case anyone has any suggestions:


<numberfield name="statvalue">
<anchored>
<to>name</to>
<position>insidetopleft</position>
<offset>139,-3</offset>
<size>
<width>21</width>
<height>14</height>
</size>
</anchored>
<frame>
<name>textlinesmall</name>
<offset>0,0,0,0</offset>
</frame>
<hideonvalue>0</hideonvalue>
<font>sheetlabelsmall</font>
<disabled />
<script>
function onInit()
statabbrnode = window.getDatabaseNode().getChild("ability");
statabbrvalue = statabbrnode.getValue();

abilities = window.windowlist.window.getDatabaseNode().getChil d("abilities");

for k, v in pairs(abilities.getChildren()) do
if v.getChild("abbr").getValue() == statabbrvalue then
statscore = v.getChild("score").getValue();
statvaluenode = window.getDatabaseNode().createChild("statvalue", "number");
statvaluenode.setValue(statscore);
end
end
end
</script>
</numberfield>

there is a separate, though related, issue on getting the total to calculate without having to reload, but that has been posted under a separate thread.

any thoughts?
thanks

DNH
June 2nd, 2007, 17:18
the total now calculates. it was, i think, a problem with having to deal with a string/number thing. this has now been resolved but the total is calculated at 0 +/- the check modifier. ie the stat value is not being brought in to play.

TarynWinterblade
June 2nd, 2007, 17:39
I would change the code a bit:



<numbercontrol name="statvalue">
<anchored>
<to>name</to>
<position>insidetopleft</position>
<offset>139,-3</offset>
<size>
<width>21</width>
<height>14</height>
</size>
</anchored>
<frame>
<name>textlinesmall</name>
<offset>0,0,0,0</offset>
</frame>
<hideonvalue>0</hideonvalue>
<font>sheetlabelsmall</font>
<disabled />
<script>
statabbrnode = nil

function updatestat(source)
setValue(source.getChild("score").getValue())
end

function update()
local statabbrvalue = statabbrnode.getValue();

local abilities = window.windowlist.window.getDatabaseNode().getChil d("abilities");

for k, v in pairs(abilities.getChildren()) do
if v.getChild("abbr").getValue() == statabbrvalue then
v.onUpdate = updatestat
updatestat(v)
end
end
end

function onInit()
statabbrnode = window.getDatabaseNode().getChild("ability");

if statabbrnode then
statabbrnode.onUpdate = update
update()
end
end
</script>
</numbercontrol>

... and hopefully it should work.

Basically, what it does:

onInit: Finds the relevant abbreviation node and assigns it to a variable that we can use later. It then checks to see if the requested node is not nil (if statabbrnode then basically says "if the database node that statabbrnode is referencing exists") and then assigns an onUpdate handler to it (just to handle the event that it changes... somehow. Lastly, it forces a call to that update handler to make sure it's called at least once.

update: Handles the event that statabbrnode is changed. It gets the value of the abbreviation node, and finds the main window's ability node. After that, it finds the right ability node, and assigns an onUpdate handler to -it- (because it will, likely change). Then, like last time, it forces a call to it, passing a link to the right node as the source value.

updatestat: The last step in the code - anytime the stat is updated (or the abbreviation changes, in a roundabout process) it will get the value of the node that triggered the update and assign it to the number control.

Hope that helps. :)

DNH
June 4th, 2007, 23:58
Hmm, thanks Taryn. That was a big help BUT I seem to be having follow-on problems with the total now. What I am after is a simple totting up of the proficiency's associated ability score, the applicable check modifier and the number of slots greater than the first (not entirely accurate this last one, but it will do for now).

It looks to me very much as though the problem lies in the timing. That is, all the fields appear to be initialised at the same time and so any attempt to look up values and work with them is failing. I am sure there must be some way around this, but any attempts I make at forcing a "second look" or something end in failure. If I check to see if the total value is equal to -1 (which it will be if all the variables in the formula are nil, it gets stuck in an infinite loop.

Here is the code I am using. I would very much appreciate any pointers.


<script>
function updatetotal(source)
statscorenode = window.getDatabaseNode().getChild("statvalue");
slotsnode = window.getDatabaseNode().getChild("slots");
checkmodnode = window.getDatabaseNode().getChild("checkmodifier");

statscorevalue = statscorenode.getValue();
slotsvalue = slotsnode.getValue();
checkmodvaluetxt = checkmodnode.getValue();

if checkmodvaluetxt == "" then
checkmodvaluenum = 0;
else
checkmodvaluenum = checkmodvaluetxt + 0;
end

print("* statscorevalue = " .. statscorevalue .. "*");
print("* slotsvalue = " .. slotsvalue .. "*");
print("* checkmodvaluetxt = " .. checkmodvaluetxt .. "*");
print("* checkmodvaluenum = " .. checkmodvaluenum .. "*");

total = statscorevalue + checkmodvaluenum + math.floor(slotsvalue-1);

print("* total = " .. total .. "*");

setValue(total);

totalnode = window.getDatabaseNode().createChild("total", "number");
if totalnode.getValue() == "" then
totalnode.setValue(total);
end
end

function update()
totalnode.onUpdate = updatetotal;
updatetotal(totalnode);
end

function onInit()
totalnode = window.getDatabaseNode().createChild("total", "number");

totalnode.onUpdate = update;
update();
end
</script>

Thanks.

Foen
June 5th, 2007, 06:19
I don't think the Init order of controls is defined, other than the fact that all child controls Init before the containing parent.

You can use this by creating a windowclass wrapper and putting the Init code at the windowclass level rather than the numbercontrol/numberfield level.

You probably already have a windowclass defined (I presume you are using this mechanism for your drag and drop), so try moving the code to a script block at that level.

Cheers

Stuart
(Foen)

TarynWinterblade
June 5th, 2007, 07:24
DNH: Your code is a little... strange here.

Basically, you're saying: totalnode needs to call update every time it updates. Update then tells totalnode that it should call updatetotal every time it updates, effectively never calling update again.

The reason why nothing happens is because totalnode only gets modified once in this process. The onInit function calls update which then calls updatetotal, which then updates totalnode (and probably causes a recursion somewhere)

How to fix it:



statscorenode = nil
slotsnode = nil
checkmodnode = nil

function update()
local statscorevalue = statscorenode.getValue();
local slotsvalue = slotsnode.getValue();
local checkmodvaluetxt = checkmodnode.getValue();

if checkmodvaluetxt == "" then
checkmodvaluenum = 0;
else
checkmodvaluenum = checkmodvaluetxt + 0;
end

print("* statscorevalue = " .. statscorevalue .. "*");
print("* slotsvalue = " .. slotsvalue .. "*");
print("* checkmodvaluetxt = " .. checkmodvaluetxt .. "*");
print("* checkmodvaluenum = " .. checkmodvaluenum .. "*");

local total = statscorevalue + checkmodvaluenum + math.floor(slotsvalue-1);

print("* total = " .. total .. "*");

setValue(total);
end

function onInit()
statscorenode = window.getDatabaseNode().getChild("statvalue");
slotsnode = window.getDatabaseNode().getChild("slots");
checkmodnode = window.getDatabaseNode().getChild("checkmodifier");

statscorenode.onUpdate = update;
slotsnode.onUpdate = update;
checkmodnode.onUpdate = update;

update()
end


That changes it so that each of your source nodes call update every time they're updated (which should update the total). Then, it does the proper math, and ends up with a total, which it just puts into the value field.

A note: It doesn't store the total anywhere in the db, because, imo, totals like this don't need to be stored in the db, it only serves to bulk up the database and god knows we have enough in there as it is :D. So, if you need it stored for some reason (as opposed to just being calculated when necessary, then you'll need to put the totla node code back in.

Hope that helps :)


Also, a final note: Local variables are your friend. They only exist in the scope in which they are called in (though variables can't truly be global in FG. Any 'global' variables that an object has are only available to that object's functions or called through dot notation from another object), and they will go 'poof' nicely when their scope is no longer active.

This doesn't play much of a part in FG, it's mostly just for sanity's sake - using local variables prevents you from later accessing a value you didn't intend to because you re-used the same variable name in a different function. In other programming environments (C, Java, etc), it's essential for memory management as well. If a variable isn't removed once it's useful, it's then just sitting around taking up extra memory - which eventually will lead to a lack of memory for something else, or a memory leak.

So... long story short: local variables are a good thing :)

DNH
June 5th, 2007, 11:52
Job done! Thanks Taryn. It looks as though I need to think more logically about these things, with the occasional sidestep into pseudocode mode.

There are a couple of additional things I would like to add to this proficiencies page but this is fine for now.

Thanks again.

TarynWinterblade
June 5th, 2007, 14:09
Job done! Thanks Taryn. It looks as though I need to think more logically about these things, with the occasional sidestep into pseudocode mode.

There are a couple of additional things I would like to add to this proficiencies page but this is fine for now.

Thanks again.

np. Glad to help.