PDA

View Full Version : Finding Base Definitions...AC, HP, etc...



tcosta1982
August 13th, 2013, 22:36
Hi, I am trying to modify the Pathfinder ruleset for 3.5 with some player asked specifics. I have all of the visuals perfect, but I need to know where in the world is the file that defines things like the following :

hp.total, hp.wounds, ac.total.general, ac.touch, etc...

If anyone can help you would be a life (and patience) saver!!

Thanks,

Tony, a long time FG DM!

Trenloe
August 13th, 2013, 23:42
Hint: Use a good editor (Notepad++ is free) and use the "find in files" functionality with the directory set to the ruleset root. This will allow you to track down where things are hiding.

To answer your question though: ac.totals.general, ac.totals.touch etc. are tied to the GUI control XML definitions in \charsheet\charsheet_combat.xml

hp.total etc. is in \charsheet\charsheet_main.xml

tcosta1982
August 14th, 2013, 06:01
I understand that and I do use Notepad++. I found the files you are talking about around the first hour of this. However, all it gives me is

source = "hp.total"

That is not really a definition of hp.total. I can't modify it or find a way to add another variable to the outcome of hp.total. Any ideas how I could do this?

Moon Wizard
August 14th, 2013, 06:38
The best way to understand what a control does is to traverse the template chain. In the case of total HP, the templates used are:
number_charadd (template_charsheet_general.xml)
basicnumber (template_common.xml)
number (template_common.xml)
numberfield (FG base object)

At each level of template, there can be changes to the attributes, child XML tags and scripts.

The source attribute of a window control just specifies where the data is stored in the database. Without a source attribute, the name of the control is used.
(Ex: charsheet.id-00001.hp.total)

In the case of the total HP field, the field is a just a numerical field with no calculations.

If you look at the AC field, you will see an example of a field that is read only and completely derived from other fields.

Regards,
JPG

Trenloe
August 14th, 2013, 06:40
I'm not exactly sure what you're trying to do so I'll try to give a bit of info and hopefully that will help you, or at least allow you to define more about what you are needing to do.

The "source" field defines where in the campaign database data displayed in the GUI field will be stored. To see this, open the db.xml file in a test campaign and look at all of the fields within the <charsheet> tag - there will be one <id-xxxxxx> tag within <charsheet> for each PC record in the campaign.

As far as definitions go, these are usually obvious: hp.total is the total HP that a PC has (the maximum HP they can have). Remember that in Fantasy Grounds when a PC or NPC takes damage their total HP is not reduced, but wounds are applied to the hp.wounds field. This allows the max hp to be kept in the PC/NPC record to keep healing from going over mximum, etc..

ac.total.general is the usual AC.
ac.total.touch is the touch AC.
ac.total.flatfooted is the flatfooted AC.

When you say " I can't modify it or find a way to add another variable to the outcome of hp.total" what, exactly are you trying to do? In FG a lot of operations are done on the underlying database via the databasenode object: https://www.fantasygrounds.com/refdoc/databasenode.xcp

If any databasenode is changed (usually using the setValue method) all GUI fields that have their "source" as this field (e.g. hp.total) will automatically update to the new value.

I hope the above helps you. If not, perhaps you could explain in more detail about what you are trying to do?

tcosta1982
August 14th, 2013, 16:08
Thank you all so much for your help so far. I will try to explain further in detail.

Ok, so I have added a couple of fields. One for negative levels and one for a miscellaneous modifier to HP. This is the first step to other changes my players are requesting. Initially I want to be able to simply place a number in my hp modifier field and have it put in the calculations for total hp. The main use is in negative levels, which are a real hassle, and not temporary hp. Last session I had a player that should have died but everyone forgot about the negative levels.

So basically, all I am trying to do is learn how to add a new field into the equation to calculate HP.total.
How would I go about this? I also need to be able to use basic math to fill this field. (NegLevel x 5)

I have found all the information that has been supplied. However, that information simply tells me what hp.total comes from but doesn't give me the point that it is instanced into existence as HP.

Trenloe
August 14th, 2013, 17:31
I have found all the information that has been supplied. However, that information simply tells me what hp.total comes from but doesn't give me the point that it is instanced into existence as HP.
The "HP" field has a source of "hp.total". This is defined in \charsheet\charsheet_main.xml:

<number_charadd name="hp" source="hp.total">
<anchored>
<to>hpframe</to>
<position>insidetopleft</position>
<offset>20,27</offset>
<size>
<width>40</width>
<height>28</height>
</size>
</anchored>
<script>
function onValueChanged()
window.wounds.onValueChanged();
end
</script>
</number_charadd>
This "number_charadd" control this is actually a numberfield control - as M_W mentioned in post #4 above the numberfield is defined by a series of cascading template definitions: number_charadd (template_charsheet_general.xml) -> basicnumber (template_common.xml) -> number (template_common.xml) -> numberfield (FG base object).

numberfield controls are defined in the ruleset reference here: https://www.fantasygrounds.com/refdoc/numberfield.xcp, they inherit "numbercontrol" which is where all of the info is: https://www.fantasygrounds.com/refdoc/numbercontrol.xcp

As M_W mentioned in post #4 above "In the case of the total HP field, the field is a just a numerical field with no calculations." It is just a field that the user modifies manually. When the Character sheet main tab is opened, the "hp" field (which has a source of "hp.total") is initialised and the charsheet.id-0000x.hp.total (where X is a number value - 1 would be the first PC created, 2 would be the second PC created) field in the campaign database is checked, if there is a value there it will be populated into the control. If there is not a value the default of 0 will be used.

If you select and type any number into the HP field the underlying "hp.total" database entry is updated. This also triggers the LUA script onValueChanged (shown in the code above) - this is where code that updates other fields when this field is changed is written.

The following is a modified Subdual/nonlethal field - replace the current code in \charsheet\charsheet_main.xml with this (take a copy of the old code so you can put it back afterwards).

<number_charadd name="nonlethal" source="hp.nonlethal">
<anchored>
<to>hptemp</to>
<position>right</position>
<offset>10</offset>
<size>
<width>40</width>
</size>
</anchored>
<hideonvalue>0</hideonvalue>
<script>
function onValueChanged()
Debug.console("Running onValueChanged for nonlethal numberfield");
local currenthp = window.hp.getValue();
local neglevelsvalue = window.nonlethal.getValue();
local neglevelshp = currenthp - (neglevelsvalue * 5);
Debug.console("Current HP = " .. currenthp .. ", Neg levels values = " .. neglevelsvalue .. ", New HP with neg levels = ".. neglevelshp);
window.hp.setValue(neglevelshp);
end
</script>
</number_charadd>
I've added Debug.console code so that info is written to the console window, bring this up by typing /console in the chat window.

This code is provided as a basic example of how you might start using neg levels to update the current HP.

The onValueChanged code is executed when the value of "Subdual" (nonlethal control) is changed, it gets the current HP, gets the current value of nonlethal, multiplies this by 5 and subtracts this from the current HP as neglevelshp, then this neglevels HP variable is used to updated (setValue) the HP field.

Of course, the problem here is that each time you change the nonlethal field it will subtract this x 5 from current HP - not the original HP. I'll leave that to you to find a solution to... :) The purpose of the above code is to show you how to get and set values when a value changes.

Hope the above helps.

If you haven't done so already, look at this thread: https://www.fantasygrounds.com/forums/showthread.php?19033-Modifying-the-3-5e-PFRPG-ruleset It gives a lot of pointers on how to start modifying a ruleset - including reference documents to read.

tcosta1982
August 14th, 2013, 18:19
Thank you for your help Trenloe. By gutting your post, I was able to attach the code to the negative levels field I have made and it now modifies total hp correctly whenever I update neg levels.

Thank you so much!

This will act as a springboard for all of my other little tweaks I need to make all of my players much happier and make the system more user friendly!!

Trenloe
August 14th, 2013, 18:34
Thank you for your help Trenloe. By gutting your post, I was able to attach the code to the negative levels field I have made and it now modifies total hp correctly whenever I update neg levels.

Thank you so much!

This will act as a springboard for all of my other little tweaks I need to make all of my players much happier and make the system more user friendly!!
Great! Glad I was able to point you in the right direction. :)

tcosta1982
August 14th, 2013, 19:52
Ok, so I am back. I am attempting from the character main page to access the combat page and change values. Is there a simple way to do this because I am stuck? It keeps saying "attempt to access global (nil value)"

tcosta1982
August 14th, 2013, 19:54
And for the sake of any help here is what I want to do.

use getValue() to get the ac.source.armor value.
Compare with my "buff" field
Whichever is greater gets added to the ac.general.total
this accomodates for spells and other effects that don't stack with regular armor.

Thanks in advance.

Trenloe
August 14th, 2013, 20:46
The best way to access most data is in the underlying database structure - all controls that use the database field in question as their source will be updated from the DB when changes are made. And, the database structure once setup doesn't tend to change much - whereas GUI controls can get changed around and break code you have written.

Use the getDatabaseNode command in the first number control to get the current database node: https://www.fantasygrounds.com/refdoc/databasecontrol.xcp#getDatabaseNode

Then use this databasenode to get the parent database node - you may need to do this a number of times to get to the right parent database node to give you access to the data you are looking for: https://www.fantasygrounds.com/refdoc/databasenode.xcp#getParent

Then you can read values from the database with databasenode.getValue https://www.fantasygrounds.com/refdoc/databasenode.xcp#getValue and set data with databasenode.setValue: https://www.fantasygrounds.com/refdoc/databasenode.xcp#setValue

Open up your campaign db.xml file and see the <charsheet> database structure so you know how to move between parent and child database nodes and what the nodes are called.

For example, this is the beginning of a PC entry in the database:

<charsheet idcounter="5">
<id-00001>
<holder name="Player" owner="true" />
<abilities>
<holder name="Player" owner="true" />
<charisma>
<holder name="Player" owner="true" />
<bonus type="number">0</bonus>
<bonusmodifier type="number">0</bonusmodifier>
<damage type="number">0</damage>
<score type="number">10</score>
</charisma>
<constitution>
<id-00001> is the top level of this specific character sheet - and is the first charsheet in the database, <id-00002> would be the second PC, etc.. Once you get this parent databasenode you have access to the whole database for this specific PC - using the databasenode.getChild command: https://www.fantasygrounds.com/refdoc/databasenode.xcp#getChild. Much easier than having to try to connect to controls on other tabs.

See more info about the FG database in general here: https://www.fantasygrounds.com/modguide/database.xcp

tcosta1982
August 14th, 2013, 20:56
I am a bit confused by the last post. I know what my variable is called that I need to access, but I can't access it across character sheet pages. Am I missing something about your post?

tcosta1982
August 14th, 2013, 21:03
And when I try to access the databasenode for ac I still get that I am trying to access a global (nil value)

Trenloe
August 14th, 2013, 21:53
I have to be very quick as I have to head off to GenCon now in 1 hour...

I think you really need to spend some time reading the documentation about modifying rulesets - especially the database and how databasenodes tie into it all. Sorry - there is simply no quick way to get into this programming. Also, make frequent use of Debug.chat or Debug.console to output variables and their contents - this can help a lot in identifying where something may be going wrong.

To get you started, if you want to get the underlying databasenode that the "hp" control in the charsheet main tab is sourced from use:

local hpdbnode = window.hp.getDatabaseNode( );
Remember that all of these commands (getValue, setValue, getDatabaseNode, etc.) are all tied to an object - just using "getDatabaseNode" will fail because you are not telling FG which object to get the database node for! Hence, in my code above I pass "window.hp" as the numberfield object and use <numberfield>.getDatabaseNode.

now that you have the database node (stored locally in the "hpdbnode" variable) that the "hp" control is sourced from you can use the databasenode commands: https://www.fantasygrounds.com/refdoc/databasenode.xcp

In our example, you can check exactly what databasenode we have by using:

hpdbnode.getName();

Details of getName here: https://www.fantasygrounds.com/refdoc/databasenode.xcp#getName

This will return something like: charsheet.id-00001.hp.total which points to the following XML field in the campaign database:

<charsheet>
<id-00001>
<hp>
<total type="number">0</total>
See the "examples of node identifiers" section here: https://www.fantasygrounds.com/modguide/database.xcp

Open up your db.xml file for your campaign and see how data is stored here when you change it in FG (remember to type /save in the chat window to update db.xml).

Trenloe
August 15th, 2013, 00:03
I am a bit confused by the last post. I know what my variable is called that I need to access, but I can't access it across character sheet pages. Am I missing something about your post?

To clarify, what I was trying to say was don't access the GUI control to get the data, access the underlying database node (the source) of the data. Virtually every GUI field that is not a field calculated from other fields will have a database source where the value will be stored. If not, the data will be lost when the windows is closed or when the campaign is exited.

tcosta1982
August 15th, 2013, 19:38
Ok, thanks for the resources. I have been studying them and experimenting. Here is my roadblock, maybe you can help.

I am able to get the DatabaseNode, Name, and NodeName for ac. However, when I get the node, it is just pointing me to {charsheet.id.00001.ac.totals.general}. I understand that is the ac for the 1st character sheet. However, I know that the source for armor is ac.sources.armor. I don't want to change it in one character sheet, but the entire database. When I try to get the node for ac.sources.armor, all I get is (nil value).

So, how would I go about getting the information stored in the variable for that? I don't see any keys to this that are readily available. Am I missing something?

gmkieran
August 15th, 2013, 20:49
This may be a silly question, but is it possible that the ac.sources.armor node is only created after some other criteria on the character sheet is met (like ticking the Armor box on the inventory tab) and your code is giving a nil value because it hasn't yet been created for the record you're looking at, tcosta?

tcosta1982
August 15th, 2013, 20:53
I wish it were that simple gmkieran. armor is on the combat page, which is just one tab away from the main tab. I can access and play with it from the combat tab, but I need to do a calculation from the main tab, and I can't access any children of ac. Here is a simplified hierarchy:

AC-->Sources-->Shield, Armor, Deflection, Dodge, etc...

So from the main tab I can access the AC function, but nothing underneath it...

Trenloe
August 16th, 2013, 02:50
I am able to get the DatabaseNode, Name, and NodeName for ac. However, when I get the node, it is just pointing me to {charsheet.id.00001.ac.totals.general}. I understand that is the ac for the 1st character sheet. However, I know that the source for armor is ac.sources.armor. I don't want to change it in one character sheet, but the entire database. When I try to get the node for ac.sources.armor, all I get is (nil value).
OK, we still need to get across the idea of GUI control sources.

*EVERY* control in the character sheet is sourced on a database field within the campaign db.xml. The root of these database fields is charsheet.id-0000x. None of these controls have sources outside of their own charsheet.id-0000x node. ac.sources.armor does not exist in the whole database. What does exist is charsheet.id-00001.ac.sources.armor exists for PC #1, charsheet.id-00002.ac.sources.armor for PC # 2, etc...

To say again - EVERYTHING in a PC character sheet gets it's data from the charsheet.id-0000X FG database node.

Question - the ac.sources.armor is the AC bonus for the armour worn by that specific PC. Why would you want to change this on the entire database when it is completely specific to each character?

(Before some smart alec comments on the above saying that not "everything" on a PC charsheet is stored in the database - 99.9% is and I am simplifying things here to make sure the point of character sheet information is stored in the database at charsheet.id-0000X).

Trenloe
August 16th, 2013, 03:23
I wish it were that simple gmkieran. armor is on the combat page, which is just one tab away from the main tab. I can access and play with it from the combat tab, but I need to do a calculation from the main tab, and I can't access any children of ac. Here is a simplified hierarchy:

AC-->Sources-->Shield, Armor, Deflection, Dodge, etc...

So from the main tab I can access the AC function, but nothing underneath it...
This is what I was trying to explain above - once you have a specific database node you can access the parent node or any child nodes.

If you have charsheet.id.00001.ac.totals.general as the acgeneraldb node then "actotalsdbnode = acgeneral.dbnode.getParent" will return the databasenode object pointing to charsheet.id-00001.ac.totals. Do you understand the concept of a parent-child relationship in terms of database object?

Once you have the actotalsdbnode that points to charsheet.id.00001.ac.totals then you can access all of the dbnodes under charsheet.id-00001.ac.totals with getChild(<dbnode name>). Here is an example charsheet.id.00001.ac.totals from one of my own campaign db.xml file:

<totals>
<holder name="Player" owner="true" />
<cmd type="number">15</cmd>
<flatfooted type="number">12</flatfooted>
<general type="number">15</general>
<touch type="number">13</touch>
</totals>
If you want to get the flatfooted AC use actotalsdbnode.getChild("flatfooted") to return the dbnode for the charsheet.id-00001.ac.totals.flatfooted database entry and then use .getValue to return the value - or use it all in on command: actotalsdbnode.getChild("flatfooted").getValue();

Have you looked at how the data is stored in one of your own campaign db.xml files? Open the file in an editor like Notepad++ and it will highlight the XML syntax for you and make it easier to read. This will show you how the data is stored and also the hierarchy so you can navigate the structure with getParent and getChild commands.

To take your example from earlier:

use getValue() to get the ac.source.armor value.
Compare with my "buff" field
Whichever is greater gets added to the ac.general.total

Assuming you start with a GUI control (probably a number field) whose source is ac.sources.armor and this control is called "acarmor" (as it is on the combat tab). Assuming this code is being executed against an event on the combat tab, and your "buff" field is in the PC character sheet database as charsheet.id-00001.buff:


local dbnodeacsourcesarmor = window.acarmor.getDatabaseNode();
local acsourcesarmourValue = dbnodeacsourcesarmor.getValue();
local dbnodeaccources = dbnodeacsourcesarmor.getParent();
local dbnodeac = dbnodeaccources.getParent();
local dbnodeacgeneraltotal = dbnodeac.getChild("general.total");
local acgeneraltotalValue = dbnodeacgeneraltotal.getValue();
local dbnodecharsheetroot = dbnodeac.getParent();
local dbnodebuff = dbnodecharsheetroot.getChild("buff");
local buffValue = dbnodebuff.getValue();

if buffValue > acsourcesarmourValue then
dbnodeacgeneraltotal.setValue(dbnodeacgeneraltotal + buffValue);
else
dbnodeacgeneraltotal.setValue(dbnodeacgeneraltotal + acsourcesarmourValue);
end

The above code has not been tested, so there could be minor syntax errors.

Do you see how I started with getting the databasenode that pointed to the source of window.acarmor = charsheet.id-00001.ac.sources.armor.

One I had this I used to getParent command to get a databasenode pointing to charsheet.id-00001.ac.sources, then getParent again to point to charsheet.id-00001.ac then getParent again to get to charsheet.id-00001.

Once at charsheet.id-00001 we can use the getChild command to get to any dbnode within the charsheet.id-00001 database - I did this to get the "buff" value.

Note I also use getChild("general.total") on the "ac" database node to get the "ac.general.total" database node.

Basically:

getParent removes the last level of a database node: charsheet.id-00001.ac.sources.armor has a parent of charsheet.id-00001.ac.sources.
getChild can be used to return any level under the databasenode used as the reference object: getChild("ac.sources.armor") against the charsheet.id-00001 dbnode would return charsheet.id-00001.ac.sources.armor


Note: The above code is provided as an example and an overview of how getParent and getChild works. The above would not be recommended for a production ruleset (too many database nodes use up memory), but the above present how the charsheet DB can be navigated. In production using <dbnode>.getParent.getValue() etc. without using intermediate dbnodes will help to reduce memory usage. Only create actual databasenode variables if you intend to use them a lot - see post #22 below for a good way to get the base databasenode for a window and then you can use <windowdbnode>.getChild("<childname>").getValue, setValue, etc. to access specific database fields.

Trenloe
August 16th, 2013, 03:32
Or, instead of using the getParent command - use the getDatabaseNode() command to return the base database node that the window instance is tied to: https://www.fantasygrounds.com/refdoc/windowinstance.xcp#getDatabaseNode

Then use getChild to navigate to any database node underneath this node.

This process is a little simpler than using consecutive getParent commands as I showed in post #21 - but you need to be sure which databasenode you are actually returning with this command.

During development make use of the databadenode.getName command to tell you exactly which dbnode you are working against - write this to chat or console using the Debug commands: https://www.fantasygrounds.com/refdoc/Debug.xcp

Moon Wizard
August 16th, 2013, 07:20
A couple other things that may help,

* The sources variable you are seeing is a script generated table variable generated for the number_linked template, so is not the same structure as the database.
* Make sure to open the campaign db.xml file to view how the data is laid out in the database file, and that will help you understand the database structure better (vs. the window/control display structures).

Regards,
JPG

tcosta1982
August 16th, 2013, 15:40
Ok, so my root problem still exists. I understand everything that has been addressed so far, but when I try to access armor from the main tab using :

local dbnodeacsourcesarmor = window.acarmor.getDatabaseNode();

I get :

Script Error: [string "charsheet_main:tArmor"]:1: attempt to index field 'acarmor' (a nil value)

With this root problem still here, nothing can be done about the issue I am having.

Trenloe
August 16th, 2013, 16:10
Ok, so my root problem still exists. I understand everything that has been addressed so far, but when I try to access armor from the main tab using :

local dbnodeacsourcesarmor = window.acarmor.getDatabaseNode();

I get :

Script Error: [string "charsheet_main:tArmor"]:1: attempt to index field 'acarmor' (a nil value)

With this root problem still here, nothing can be done about the issue I am having.
My advice to you since post #12 has been to *not* try to do it this way (accessing a GUI control in another window) but to access the data in the underlying database.

The GUI control "acarmor" is tied to (sourced on) charsheet.id-0000X.ac.sources.armor. Access this data directly in the database *not* in the control and it doesn't matter which window you are on you will get the data. If you change the data in the database, every GUI control that is sourced on this database field will be updated.

Try this from within any charsheet window:


local dbnodecharsheet = window.getDatabaseNode();
Debug.chat("Got a database node of: " .. dbnodecharsheet.getNodeName());
local dbnodeacarmor = dbnodecharsheet.getChild("ac.sources.armor");
Debug.chat("Got a database node of: " .. dbnodeacarmor.getNodeName());

This gets the databasenode of the main charsheet (should be charsheet.id-0000X), then gets the child of that node with the name ac.sources.armor.

dbnodeacarmor will be the database node for charsheet.id-0000X.ac.sources.armor and you can use getValue or setValue against this this dbnode variable.

tcosta1982
August 16th, 2013, 16:47
Thank you so much!!

That unlocks so much for me. I think I understand what you have been talking about now.