5E Character Create Playlist
  1. #1
    DNH's Avatar
    Join Date
    Apr 2007
    Location
    Edinburgh, UK
    Posts
    288

    Items in windowlist not "refreshing"

    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.
    DNH
    "Lost in Karameikos"

  2. #2
    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.
    Tero Parvinen
    Fantasy Grounds Guru

  3. #3
    DNH's Avatar
    Join Date
    Apr 2007
    Location
    Edinburgh, UK
    Posts
    288
    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:

    Code:
    			<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().getChild("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
    "Lost in Karameikos"

  4. #4
    DNH's Avatar
    Join Date
    Apr 2007
    Location
    Edinburgh, UK
    Posts
    288
    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.
    DNH
    "Lost in Karameikos"

  5. #5
    I would change the code a bit:

    Code:
    <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().getChild("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.
    "He is everything I have ever aspired to be."
    "Your aspiration is to be impaled on a halberd? Your parents must be proud."

  6. #6
    DNH's Avatar
    Join Date
    Apr 2007
    Location
    Edinburgh, UK
    Posts
    288
    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.

    Code:
    <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.
    DNH
    "Lost in Karameikos"

  7. #7
    Foen's Avatar
    Join Date
    Jan 2007
    Location
    Suffolk, England
    Posts
    2,007
    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)

  8. #8
    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:

    Code:
    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 . 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
    Last edited by TarynWinterblade; June 5th, 2007 at 07:31.
    "He is everything I have ever aspired to be."
    "Your aspiration is to be impaled on a halberd? Your parents must be proud."

  9. #9
    DNH's Avatar
    Join Date
    Apr 2007
    Location
    Edinburgh, UK
    Posts
    288
    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.
    DNH
    "Lost in Karameikos"

  10. #10
    Quote Originally Posted by DNH
    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.
    "He is everything I have ever aspired to be."
    "Your aspiration is to be impaled on a halberd? Your parents must be proud."

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Dungeons & Dragons 2024 Core Rulebooks Pre-Order

Log in

Log in