PDA

View Full Version : Help with charsheet_skills.xml



GoOrange
August 26th, 2007, 01:08
Okay, I've got the skillsheet for my Star Wars Sage Edition ruleset almost perfect.

The hang up is the column for (1/2 the character's heroic level).

Right now, I've got it working where the user types in the value for each skill, and it gets tabulated nicely in the total column. (This was basically achieved by copying the format of the "misc" column").

What I want to do is have this value entered automatically, but I'm not having any luck. I can't figure out how to automatically set the value for the data in that column. I can't even get it to automatically enter a static number (like "3").

I've replaced the "ranks" column with a custom column "halflevel". I've created a node "halflevelnode". I can't seem to enter anything into the node (like trying "setValue(3);"). Ideally I'd like to set the value to a mathematical expression:

math.floor(x/2) where x is the variable defined on the main character sheet "classes.totallevel.level".

Is anyone out there familiar enough with XML/lua to help me perfect this skills page?

Thanks,
Jeff

joshuha
August 26th, 2007, 01:26
You'll need to do this in the <script> tag of the control

Something like:


<script>
function onInit()
setValue(3);
end
</script>

GoOrange
August 26th, 2007, 02:35
OK, got that part - thanks.

Now for the next step. How do I replace the number 3 in our example with a variable from the charsheet_main.xml file.

Specifically, a character level field.

Something like this:

setValue(window.level1.getValue());

On the main page, this would return the level of the class listed first in the class box. If I try this function on the skill page, I get an error "...attempt to index field 'level1' a nil value".

How can I "port over" data from the main page and stick it into the values on the skill sheet?

Thanks again,
Jeff

joshuha
August 26th, 2007, 03:11
Well the ideal way is to actually port the data over from the DB.xml that the charctersheet is stored in. This obviously won't work for fields that aren't tied to the DB but level should be.

Generally, window.getDatabaseNode() will return you a dbnode that you can start working with to navigate to the value you want.

So ideally (and this heavily depends on the field you are coming from), window.getDabasenode() will return you a reference to your character node in the DB. And then from there you can navigate to the appropiate field.

Level should be something like window.getDatabaseNode().getChild("characterlevel").getValue()

Usually the cases that doesn't work is if you are in some sort of control that has its own parent databasenode (which is usually the case of windowlists) and then you have to throw in a getParent() or two before the getChild().

GoOrange
August 26th, 2007, 03:34
Below is pasted the part of the main page where the total character level is defined.

So, to get at it on the skills page, I do this:

<script>
function onInit()
setValue(window.getDatabaseNode().getChild("characterlevel" ).getValue());
end
</script>

But it returns a "attempt to index a nil value" error.

Edit: If you or anyone has another idea of how I can get a value of 1/2 the total character level added as a variable in the equation for total skill rank, let me know. So far I am completely stumped on this one.


<numberfield name="characterlevel" source="classes.totallevel.level">
<anchored>
<top>
<parent>classanchor</parent>
<anchor>bottom</anchor>
<relation>relative</relation>
<offset>3</offset>
</top>
<left>
<parent>classframe</parent>
<anchor>right</anchor>
<offset>-46</offset>
</left>
<size>
<width>32</width>
<height>20</height>
</size>
</anchored>
<font>sheetnumber</font>
<readonly />
<frame>
<name>bonus</name>
<offset>5,4,5,4</offset>
</frame>
<script>
function updateValue()
setValue(window.level1.getValue() + window.level2.getValue() + window.level3.getValue());
end
</script>
<readonly />
</numberfield>

Foen
August 26th, 2007, 05:59
If you are using source="...", the name of the DB node is not the same as the name of the control. If your example, the control is called characterlevel, but the DB node is called classes.totallevel.level, so the script should be something like:



<script>
function onInit()
local lvl = window.getDatabaseNode().getChild("classes.totallevel.level").getValue();
setValue(math.floor(lvl/2));
end
</script>


Hope that helps

Stuart
(Foen)

GoOrange
August 26th, 2007, 12:40
OK, I put in the part about the DB lookup on the skills page, but I'm getting an error.

Script Error [String "charsheet_skilllistitem:halflevel"]:1: Attempt to index a nil value.

I don't get this error if I use a static value like "setValue(3);" in the script below.

Below is the segment of code where I record the "halflevel" variable for each skill.

Thanks!



<numberfield name="halflevel">
<anchored>
<to>label</to>
<position>insidetopleft</position>
<offset>130,-3</offset>
<size>
<width>21</width>
<height>14</height>
</size>
</anchored>
<frame>
<name>textlinesmall</name>
<offset>0,0,0,0</offset>
</frame>
<displaysign />
<hideonvalue>0</hideonvalue>
<font>sheetnumbersmall</font>
<disabled />
<script>
function onInit()
local lvl = window.getDatabaseNode().getChild("classes.totallevel.level").getValue();
setValue(math.floor(lvl/2));
end
</script>
</numberfield>

GoOrange
August 26th, 2007, 15:36
Making progress

I added code (at the very bottom of this post) to the charsheet_skill page and stuck it into the lower window. This shows me that I am "getting" the character level, and properly calculating 1/2 round down. Works fine.

Now, I have the halflevel coulmn (of the main skills section, replacing what used to be "ranks" set up with this code:


<numbercontrol name="halflevel" source="classes.halflevel.level">
<anchored>
<to>label</to>
<position>insidetopleft</position>
<offset>130,-3</offset>
<size>
<width>21</width>
<height>14</height>
</size>
</anchored>
<frame>
<name>textlinesmall</name>
<offset>0,0,0,0</offset>
</frame>
<displaysign />
<hideonvalue>0</hideonvalue>
<font>sheetnumbersmall</font>
<disabled />
</numbercontrol>

It now adds the sum up properly in the totals column, adding in one half of the characters level. But, for some reason, it won't actually display the 1/2level value in it's column. It's adding it up properly in the total, but just not displaying it in it's own column.

Any idea why nothing is being displayed in this column?



<numberfield name="half" source="classes.halflevel.level">
<anchored>
<to>label</to>
<position>insidetopleft</position>
<offset>80,0</offset>
<size>
<width>12</width>
<height>12</height>
</size>
</anchored>
<script>
function onInit()
local lvl = window.getDatabaseNode().getChild("classes.totallevel.level").getValue();
setValue(math.floor(lvl/2));
end
</script>
<readonly />
</numberfield>

joshuha
August 26th, 2007, 15:58
I think its missing a font tag.

GoOrange
August 26th, 2007, 16:15
It's got the following in there:

<font>sheetnumbersmall</font>

On further review, it's not totaling things properly. It's just adding "3". This seemed to work perfectly when my test numbers had a total character level of 6, making 1/2 6 = 3 look like everything was working perfectly.

Even when I reload things, it still adds 3 to the total column of the skills. Not sure where that is coming from. Earlier I did a setValue(3) in various places to test, perhaps that got written in the DB as the value, and none of my new additions are re-updating.

The problem in addition is coming from the halflevelnode in this summation statement in the "totals" column. Total is reduced by 3 when the halflevelnode part is removed. Not sure why halflevelnode is stuck at 3 and not updating with the new changes.


setValue(halflevelnode.getValue() + miscnode.getValue() + trainednode.getValue() + focusnode.getValue() + window.stat.getValue() + armorchecknode.getValue() * armorcheckmodifiernode.getValue());

joshuha
August 26th, 2007, 16:23
It's got the following in there:

<font>sheetnumbersmall</font>



I see that in the first control but not the second control (unless you added it already). Also I see a disabled tag and wasn't sure if you intended that to be there.

GoOrange
August 26th, 2007, 16:59
I see that in the first control but not the second control (unless you added it already). Also I see a disabled tag and wasn't sure if you intended that to be there.

I added a font in the second control, it just changed the font that that number was displayed in. The second control puts up a singular instance of (1/2 character level round down) in the lower left corner. This displays properly.

The first control, up with the rest of the columns in skill db display, is supposed to display the (1/2lvl) value for each skill. If I use a function like setValue(1) then it displays 1 properly. If I use setValue(window.getDatabaseNode().getChild("classes.halflevel.level").getValue()); then it just displays a blank.

The disabled tag just prevents the user from typing stuff into that column manually (and overwriting the default value) AFAIK - I could be wrong about this.

Thanks.

GoOrange
August 26th, 2007, 17:10
I think it's displaying properly, since it will show numbers if I do a setValue(2) or something static. It breaks down with the database call to, well, pretty much anything I put in.



<numberfield name="halflevel">
<anchored>
<to>label</to>
<position>insidetopleft</position>
<offset>130,-3</offset>
<size>
<width>21</width>
<height>14</height>
</size>
</anchored>
<frame>
<name>textlinesmall</name>
<offset>0,0,0,0</offset>
</frame>
<displaysign />
<hideonvalue>0</hideonvalue>
<font>sheetnumbersmall</font>
<disabled />
<script>
function onInit()
setValue(window.getDatabaseNode().getChild("classes.halflevel.level").getValue());
end
</script>

the setValue(...) part is returning nothing, which is probably why nothing is being displayed, and nothing gets added in.

If that expression is replaced by setValue(5), then 5 gets displayed in that column for each skill and 5 gets added to the total.

So, it appears to be a problem in "importing" that datapoint, defined later on on the same page/file.

GoOrange
August 26th, 2007, 17:23
Pondering...(may be totally off base here becuase I'm not familiar with lua)

It seems that the database call to getchild("classes.halflevel.level") is failing. Perhaps this is becuase the field that it's being called from "halflevel" is somewhere else on the db tree and "classes.halflevel.level" is not a child of "halflevel" it's a child of something else.

If so, should the syntax of the db lookup be different to navigate back to the beginning and specify which parent/child to look for?

Foen
August 26th, 2007, 17:42
I think the problem is that you are confusing calculated fields with stored fields.

A calculated field is a control that isn't bound to the database, and is rendered using a 'numbercontrol' rather than a 'numberfield'. Because is isn't bound, it doesn't have a source attribute.

With a stored field, you generally don't recalculate it.

Perhaps you should modify the first peice of your code to remove the source='...' attribute?

Cheers

Stuart
(Foen)

Foen
August 26th, 2007, 17:46
Hi GoOrange. If you are calling the code from a skills list, which is generally a windowlist control, the window.getDatbaseNode won't work properly. You might try to insert a 'parent' or 'windowlist' in the syntax.

I think it is something like window.parent.getDatabaseNode or windowlist.window.getDatabaseNode (I don't have the exact syntax to hand and it isn't well documented).

If these don't work, I'll try to look something out and post it as soon as I can (I'm on holiday at the moment!).

Cheers

Stuart
(Foen)

joshuha
August 26th, 2007, 18:27
Yep, as I mentioned earlier some controls have their own databasenode that is a child of the charsheet node.

The easiest way to find that out is do a print(window.getDatabaseNode().getNodnName()); and make sure you have the /console up.

If it returns you deeper that the top level the the topsheet you will need to throw in getParent() to move up a node in the tree i.e. window.getDatabaseNode().getParent().getChild(...) , etc.

GoOrange
August 26th, 2007, 19:15
Some progress -

Note: using the print command with the console is extremely useful.

I put up the print -node function on both instances where I was using the (1/2level) variable and found the place where it wasn't reading the variable was not on the same level of the tree as the place where it was working.

So, it now displays calculates properly (from within the numbercontrol field "halflevel" - the column on the skill list) 1/2 character level. I had to add in two getParent functions.



<script>
function onInit()
print(window.getDatabaseNode().getParent().getPare nt().getChild("classes.halflevel.level").getValue())
setValue(window.getDatabaseNode().getParent().getP arent().getChild("classes.halflevel.level").getValue());
end
</script>

GoOrange
August 26th, 2007, 19:34
Making progress. Tidied up a bit, functions properly for the most part.

One minor issue - getting this value to update when the character levels are changed on the main page.



function onInit()
local lvl = window.getDatabaseNode().getParent().getParent().g etChild("classes.totallevel.level").getValue();
setValue(math.floor(lvl/2));
end

with this onInit function, things update only when I close the character sheet and character selection page and reopen them. Then any changes made previously get applied.

I tried changing onInit() to onUpdate(), but that didn't update the value ever.

What function call do I need to update this whenever a level gets added or changed?

joshuha
August 26th, 2007, 19:46
Thats a bit more complicated and gets into database node event handlers, in this case update event.

I don't have the time at the moment but I did post in another thread showing how to do this. Will dig it up in a bit.

Foen
August 27th, 2007, 07:34
Hi

As Joshuha mentioned, you need to set up a handler for the onUpdate event of the right database nodes.

The event is fired whenever the underlying database node has its value changed. This doesn't happen for calculated controls (as they don't have an underlying database node) but does happen for bound controls when the value on the face of the character sheet changes.

I'm guessing you have multiple controls (like classes.class1.level, classes.class2.level etc) so you will need to add an event handler to each of these. I also note that you store the total level in the database (rather than just calculating it on the fly), so that probably needs to be updated as well.

If the assumptions are correct, you should be able to do the following:

If you have a level total control (which displays "classes.totallevel.level"), add a recalc() function to its script block, if not you will need to create one at the page level on your character sheet. We'll come back to the recalc function later.
For each of the individual level controls, add an onUpdate function which calls the recalc() function, using window.totallevel.recalc() or window.recalc(). If the function already exists (because you are using it for something else) just add the recalc line to it, otherwise you will need to add the function yourself.
In the recalc function, update classes.totallevel.level using setValue() by adding up each of the individual level values. This keeps the total value up to date when the user changes any of the individual level values hint: you can also call recalc from the control's onInit and only have to write the update code once.

If the skill values are on a separate tab, I don't think you will need to do anything else (I think onInit is called for controls on a tab whenever you change from one tab to another). I am a bit rusty on this though, so please post another message if this doesn't work :)

Cheers

Stuart
(Foen)

GoOrange
August 27th, 2007, 14:12
I'm not quite grasping this, so I'll detail the setup a little bit.

The total level gets calculated and displayed on the "main" page. This is also where the individual class levels are manually entered in by the user. The total level displayed currently updates properly whenever the individual levels are changed.

Here is what the codes for individual levels and total level looks like on that page (minus anchor, font info etc.)



<levelnumber name="level3" source="classes.slot3.level">
</levelnumber>

<numberfield name="characterlevel" source="classes.totallevel.level">
<script>
function updateValue()
setValue(window.level1.getValue() + window.level2.getValue() + window.level3.getValue());
end
</script>
</numberfield>

Now, where things are not updating properly is on the charsheet skills page. The important bits of the code where "characterlevel"/"classes.totallevel.level" is being called up are here:



<numbercontrol name="halflevel">
<script>
function onInit()
local lvl = window.getDatabaseNode().getParent().getParent().g etChild("classes.totallevel.level").getValue();
setValue(math.floor(lvl/2));
end
</script>
</numbercontrol>

So, the actual display of "characterlevel" on the main page updates fine. When the control on the skills page tries to use the value for calculations, it only uses the initial value, and not the changed value if the user has altered the fields while the character sheet was open.

I'm not certain exactly where to put in the recalc() function. Let me see if I'm understanding you correctly:

For the individual levels, change them to look like this?



<levelnumber name="level3" source="classes.slot3.level">
<script> <----- add this script and function?
function onUpdate()
window.characterlevel.recalc()
end
</script>
</levelnumber>

And stick this into the total level control?



<numberfield name="characterlevel" source="classes.totallevel.level">
<script>
function updateValue()
setValue(window.level1.getValue() + window.level2.getValue() + window.level3.getValue());
end

function recalc() <-----add this?
setValue(window.level1.getValue() + window.level2.getValue() + window.level3.getValue());
end
</script>
</numberfield>

My guess is I'm completely misunderstanding what you are trying to say.

Thanks, your help is appreciated!
Jeff

joshuha
August 27th, 2007, 15:50
Ok I'll approach this a different way than Stuart. Currently the total levels (the numberfield called characterlevel) works fine and is itself a databasenode.

So what we need to do is for your halflevel control create a handler there that basically looks for any changes on the characterlevel field in the DB and updates itself. Right now since its in onInit it really only works when the control is first initialized, i.e when you open and close your sheet.

To do this the halflevel would look like so:


<numbercontrol name="halflevel">
<script>
function update()
setValue(math.floor(lvlsource.getValue()/2));
end
function onInit()
lvlsource = window.getDatabaseNode().getParent().getParent().g etChild("classes.totallevel.level");
lvlsource.onUpdate = update;
update();
end
</script>
</numbercontrol>


So what this is doing is first getting a dbnode reference called lvlsource. Then it creates an handler that says when THAT control (characterlevel) is update call my function update. I then call update() manually just to initialize the control the first time.

So whenever the characterlevel is changed now (which saves to the DB since it's a numberfield), the halflevel control will see that, fire off its update() function and set the new value.

Let me know if that makes sense.

Foen
August 27th, 2007, 16:47
*takes hat off to Joshuha*

A far simpler solution.

Stuart
(Foen)

GoOrange
August 27th, 2007, 17:07
Seems to work!

So what I'm doing is:

- defining a new function called "update"
- when "update" runs, it sets the value of the window "halflevel" to one half the value of "lvlsource" rounded down.

- Next, upon opening the charactersheet,
- we link "lvlsource" to the value of the db node"classes.totallevel.level"
- then well tell the program that whenever "lvlsource" is updated, to run our newly defined "update" function.
- and we run "update" once at the beginning for good measure

I think I got it. (Regardless, it seems to work great!)

I appreciate all the answers I've gotten from both of you. It's been a great help!

-Jeff

GoOrange
August 27th, 2007, 17:13
BTW, I hope these questions aren't holding anyone up from getting the Savage Worlds ruleset for FG2 released for download to the general public.

Not that I'm eagerly waiting or anything...

Hmm. The vicious cycle - No Savage Worlds ruleset to play with, so I work on Star Wars homebrew ruleset. Ask questions about Star Wars which get answered by guy working on Savage Worlds, delaying release of Savage ruleset, creating more time for me to work on Star Wars, leading to more questions, leading to more delays...

Foen
August 27th, 2007, 17:20
Hehe, you might be delaying Joshuha, but Savage Worlds isn't my baby. Now if you were waiting for Call of Cthulhu it might be a different matter...

Stuart
(Foen)

joshuha
August 27th, 2007, 17:34
Actually no delay for me helping out. My final build of the ruleset has been submitted. We are waiting on some other technical details to come together but rest assured it will be very soon.