PDA

View Full Version : Trying to dynamically change token image on map



alloowishus
July 29th, 2023, 01:42
My eventual goal is that I want to add a drop down "primary_hand_equipped" for NPCs the same as for PCs and use that to dynamically change the image on the map. I will store the appopriate image path and name in the notes section of item. When the the equipped drop down is changed, the token image on the map changes as well to reflect the weapon (i.e. /campaign/tokens/orc_archer.png for missile weapons, /campaign/tokens/orc_scimitar.png for melee).

I am trying to reverse engineer the DB.xml table and how the tokens relate to the combat tracker. From what I can the tokens on the CT have an ID

<token type="token">tokens/MM/gnoll.png</token>
<tokenrefid type="string">53</tokenrefid>
<tokenrefnode type="string">image.id-00253.image</tokenrefnode>

Not sure what the "tokenrefnode" refers to, I think that's the id node of the map image that the token is on?

And so the ID corresponds to a layer for the map image

For example:

<layer>
<name>tokens/MM/gnoll.png</name>
<id>16</id>
<parentid>-10</parentid>
<type>token</type>
<token>
<prototype>tokens/MM/gnoll.png</prototype>
<prototype3Dflat />
<id>53</id>
<fowenabled />
<color>#FFFF0000</color>

So I should be able to grab the ID from the CT and then update the layer.name and layer.token.prototype values using DB.setValue?


I guess my question is, how to I translate this: image.id-00253.image into a node to set the value? Is it just as simple as setting sImageNode = "image.id-00253.image";
Then I have to loop through the layers to find the correct token?


Thanks!

superteddy57
July 29th, 2023, 02:27
The combat tracker uses the tokenrefid and tokenrefnode to ensure the token in the combat tracker matches what is displaying on the maps that actor is showing. There are examples of using CoreRPG > scripts > manager_token.lua (TokenManager) to acquire and the use of those two children. The CoreRPG > ct > scripts > ct_entry.lua shows how they link up as well.

alloowishus
July 29th, 2023, 09:02
Ok thanks, I think this is the function I should use:

CombatManager.replaceCombatantToken

superteddy57
July 29th, 2023, 09:22
That would replace the token in the combat tracker (if it finds the correct actor) and would then update the token on any map that it's connected to

alloowishus
July 29th, 2023, 20:29
That would replace the token in the combat tracker (if it finds the correct actor) and would then update the token on any map that it's connected to

Yes, that's what I want. Only thing is it is using this function call:

draginfo.getTokenData()

But I need to simulate that with code since I am not dragging. Any ideas? Thanks!

superteddy57
July 30th, 2023, 03:45
If it's the PCs, then changing it is just changing the token on the character sheet and it would update the rest. For NPCs, based in the combat tracker, I would have that functionality actually in the combat tracker entry as that would make it much easier to manipulate the token and then it would make all the relevant changes based on that actor. Adding it to ct_entry_section would make it available to the GM to make the changes and grabbing the CT node is just grabbing the window's database node. So a more focused approach would be more beneficial than a global option, especially if you are using static paths for the tokens. At least that is what it sounds like you are attempting.

YAKO SOMEDAKY
July 30th, 2023, 04:08
Did I understand right?
Do you intend to make a token changer that allows you to change according to equipped weapon?
If so! That would be awesome! And I would love to be able to use this and even better serve NPCs and PCs!

alloowishus
August 1st, 2023, 01:31
If it's the PCs, then changing it is just changing the token on the character sheet and it would update the rest. For NPCs, based in the combat tracker, I would have that functionality actually in the combat tracker entry as that would make it much easier to manipulate the token and then it would make all the relevant changes based on that actor. Adding it to ct_entry_section would make it available to the GM to make the changes and grabbing the CT node is just grabbing the window's database node. So a more focused approach would be more beneficial than a global option, especially if you are using static paths for the tokens. At least that is what it sounds like you are attempting.

I would like to make the token change part of the "primary hand equipped" drop down and then adding that to the NPCs sheet. THe weapon will then define the token used since I just need to copy the path of the token into the item notes. There is a function called setTokenData() but it requires me to pass a draginfo object. Since I am not draggin the token but rather changing it based on a drop down selection, how can I "create" a draginfo object in lua script?

Interestingly I tried outputting was being passed into the ChangeCOmbatToken function and it spat out some wierd data like "user data: A1040399C" which kind of looks like hex or something.

Thanks!

Trenloe
August 1st, 2023, 09:44
There is a function called setTokenData() but it requires me to pass a draginfo object. Since I am not draggin the token but rather changing it based on a drop down selection, how can I "create" a draginfo object in lua script?
You can't create a dragdata object from a script. Recently discussed here: https://www.fantasygrounds.com/forums/showthread.php?78647-Can-dragdata-objects-be-created-from-scratch

But, do you need draginfo to set a token from a LUA script? You've mentioned the CoreRPG CombatManager.replaceCombatantToken function earlier in this thread - that doesn't use draginfo, its input parameters are nodeCT and the new token instance.

This is that function:


function replaceCombatantToken(nodeCT, newTokenInstance)
local oldTokenInstance = CombatManager.getTokenFromCT(nodeCT);
if oldTokenInstance and oldTokenInstance ~= newTokenInstance then
if not newTokenInstance then
local nodeContainerOld = oldTokenInstance.getContainerNode();
if nodeContainerOld then
local x,y = oldTokenInstance.getPosition();
TokenManager.setDragTokenUnits(DB.getValue(nodeCT, "space"));
newTokenInstance = Token.addToken(DB.getPath(nodeContainerOld), DB.getValue(nodeCT, "token", ""), x, y);
TokenManager.endDragTokenWithUnits();
end
end
oldTokenInstance.delete();
end

TokenManager.linkToken(nodeCT, newTokenInstance);
TokenManager.updateVisibility(nodeCT);
TargetingManager.updateTargetsFromCT(nodeCT, newTokenInstance);
end

It doesn't look like you need to pass newTokenInstance, as that will be created based off the nodeCT "token" field - so you could try setting that field with the token prototype string (the path to the token - have a look at some examples in the combattracker section of the campaign database) before calling CombatManager.replaceCombatantToken(nodeCT). Although I'm not sure if changing that DB field will trigger some other code - you'll probably see the token in the CT change, but you'll then be able to call CombatManager.replaceCombatantToken(nodeCT) to setup the other links etc..

alloowishus
August 1st, 2023, 19:20
Yes, I was looking that function and tried to find what exactly comprised "NewTokeninstance". It seems it is coming from draginfo.getTokenData(). When I try and output it using a tostring function I get that wierd "user data: AC1039AFF" or whatever so I have no idea what exactly is in NewTokenInstance.

Trenloe
August 1st, 2023, 19:43
tokeninstance is an API object so, yes, it is a user data record - and in this case, FG hasn't been programmed to output anything more than "user data" via a debug command. Some of the FG API Object have been programmed to output meaningful data - databasenode and windowinstance, for example; but not all have.

The tokeninstance is documented in the FG Wiki here: https://fantasygroundsunity.atlassian.net/wiki/spaces/FGCP/pages/996644788/tokeninstance If you want to look at it's contents, use the getXXXXX API commands.

If you look closely at the code I provided above, you will see a token instance being created:


newTokenInstance = Token.addToken(DB.getPath(nodeContainerOld), DB.getValue(nodeCT, "token", ""), x, y);

This has nothing to do with dragdata - this is all to do with the token control existing in the creature CT entry (the database node representing the image control that shows the token) and the value of the "token" field within nodeCT. As I suggested in my previous post, have a look at a campaign db.xml file for what that field can contain - it's the FG path to a token file.

Have you tried what I suggested in my previous post? Setting the "token" value in nodeCT and then calling CombatManager.replaceCombatantToken(nodeCT)?

Moon Wizard
August 1st, 2023, 20:13
You are probably best off changing the token field in the CT node for the given creature; and letting the existing code propagate the change.

Regards,
JPG

Trenloe
August 1st, 2023, 20:30
Have you tried what I suggested in my previous post? Setting the "token" value in nodeCT and then calling CombatManager.replaceCombatantToken(nodeCT)?
As mentioned - give this a go!

Assuming you have the CT node of the actor and the name and FG path of the token stored in sTokenPathName, use this:


DB.setValue(nodeCT, "token", "token", sTokenPathName);
CombatManager.replaceCombatantToken(nodeCT);

Looking in the campaign database I can see example of the format of sTokenPathName, you can do the same in a test campaign db.xml file. For example, this token is assigned to an entry in the combattracker:


<token type="token">tokens/Giant Badger.png@Pathfinder Second Edition Bestiary 2</token>