PDA

View Full Version : Buttongroup_counter



statik37
November 6th, 2019, 15:57
I am using the buttongroup_counter template on the main desktop.

It looks great, and loads correct. The problem is, in the onInit, there is this section:



-- Synch to the data nodes
local nodeWin = window.getDatabaseNode();
if nodeWin then
local sLoadMaxNodeName = "";
local sLoadCurrNodeName = "";

if sourcefields then
if sourcefields[1].maximum then
sLoadMaxNodeName = sourcefields[1].maximum[1];
end
if sourcefields[1].current then
sLoadCurrNodeName = sourcefields[1].current[1];
end
end

if sLoadMaxNodeName ~= "" then
if not DB.getValue(nodeWin, sLoadMaxNodeName) then
DB.setValue(nodeWin, sLoadMaxNodeName, "number", 1);
end
setMaxNode(DB.getPath(nodeWin, sLoadMaxNodeName));
end
if sLoadCurrNodeName ~= "" then
setCurrNode(DB.getPath(nodeWin, sLoadCurrNodeName));
end
end


When I run the code, nodeWin comes up as nil for both player and host. How can I call this so that it will work for everyone?

I was thinking of throwing that section into a separate function, and when host call it at one point, and when player, call it when char sheet opens. If I do that, I feel like I may need to create a different nodeWin for player and host, but I'm not sure if this will work or not. I don't know if it will be as simple as that, since the file also has a few other functions that will do a DB.getValue and DB.setValue. Any insight would be appreciated.

statik37
November 6th, 2019, 16:41
Also, a thought, because this will have an effect on the dice roll, should I modify the buttongroup_counter.lua file and add the registerControl and updateControl functions from modifierstack.lua and then manipulate those somehow? If that is the answer, I will also need a little guidance. Basically, I want a 5 button system that just keeps track of a number 1 to 5, and when I roll the dice, I can then throw it into rRoll as another key value pair.

statik37
November 6th, 2019, 19:24
OK, update on what I've done. I initially used the buttongroup_counter template as is, but I had two groups on the desktop. Different windowsclasses though. but when I made them both the buttongroup template, they seemed to be linked and when clicking one, the other would also increase or decrease. So, I separated them into two different templates and I made two copies of the lua file unique to the template. Now, it kinda works. First off, it would error out after the first click because under the setCurrentValue function was this:



function setCurrentValue(nCount)
if sCurrNodeName ~= "" then
DB.setValue(sCurrNodeName, "number", nCount);
else
nLocalCurrent = nCurrent;
end
end


This was erroring out because this is the only place in the file nCurrent was listed, and I didn't know how to find it. So, I changed it from nCurrent to nCount. Now, with some Debugs I can see that the values increase and decrease separately and as expected, however, the pips themselves do not change. Whatever I change the current value to and reload is how many pips will be lit up, but they do not change from that state.

Moon Wizard
November 6th, 2019, 23:54
I didn't quite follow if you still had questions, or whether you were just documenting the steps you went through. If you have questions, just call them out in a bulleted list or in some way that it's obvious and myself or the community can try to answer.

Regards,
JPG

statik37
November 7th, 2019, 00:03
Sorry, I was not thinking of clearity as I was typing it up. I do still have questions.

1) The line:

local nodeWin = window.getDatabaseNode();

is throwing an error because it is on the desktop, and not in a window. Should I split it into two separate commands, one for host and one for player, or is there something I could put there to make it work for both?

2) the buttons are showing up and whatever I have the starting value at is what buttons are on and what are off (staring value of 2, first two are checked on last 3 are not). When I debug and click on them, the debug tells me the actual value that it should be, but the icons are not updating. How do I fix that?

3) Once I get this fixed, I want to be able to be able to add these as a key value pair to rRoll, once I initiate the roll. How do I do that? I assume it would be similar to the nMod pair, but I can't find where in the system that info is collected. Any help on that would be appreciated.

Moon Wizard
November 7th, 2019, 00:43
1) The controls on the desktop should still be encapsulated in a window instance. So, window.getDatabaseNode() should still work, and just return nil. What's the exact error message you are seeing in the console?

2) The template was really built to support database-linked capability in a sheet to which the user has access. Since you are making your own, I would copy the template and script; and modify what you need.

Since it is not linked to the database, you'll need to call the update() function for the control manually after changing either the current or max values, in order for the template to update it's visual display. That's what the addHandler/removeHandler functions set up to do automatically when this template is database-linked.

If this control is meant to be mirrored in values on both host and player, then you can create a global database node to hold the values; and have the template linked that way. Of course, since only one user can own a database node at a time, the reality is that only the GM will be able to update the values. If you want something that either the GM or players can update independently of each other, that's more complex, and would require OOB messaging to set that up.

If this control is meant to be unique in values for each user, then you would want to rip out all the database stuff in your copied version of the template script; and just make the setMaxValue and setCurrentValue functions perform the update call directly.

3) There is no place to inject values into a roll arbitrarily. You have to override the individual roll handling for rolls that are affected. This is how it's handled in the 5E ruleset for example to handle the ADV/DIS, +/-2, and +/-5 buttons.

Regards,
JPG

statik37
November 7th, 2019, 12:07
Hello,

Thank you for that help. I now have the physical buttons working. Here's a question to expand on #3. I know, if I type a number into the modifier box and then roll the dice, the system will add that number to the roll. From what I can tell, that box is not stored in the DB. I have been looking and having trouble finding the code that actually tells the system, if there is a number here, then use it as a modifier. I know it usually gets saved as rRoll.nMod, and then it is used however, once the roll is complete. But how does the system grab that number to then add it to the rRoll table? I looked in some action files, but I feel like I may be missing a step, as it doesn't seem complete. I also don't see any OOB messaging used for the modifier, unless that piece I'm missing uses it. I hope that makes sense, and I'm sorry if these are dumb questions.

Moon Wizard
November 7th, 2019, 17:27
That code is embedded in the ModifierStack and ActionsManager global scripts within CoreRPG ruleset.

As I mentioned, you should look at 5E, which has an example of pulling desktop button modifiers into rolls. See ActionsManager2.encodeDesktopMods(rRoll); calls throughout 5E ruleset.

Regards,
JPG

statik37
November 7th, 2019, 19:14
So, further questions. Upon research, I found this under desktop_template.xml



<script>
local bInit = false;
function onInit()
if ModifierStack.getModifierKey(getName()) then
setValue(1);
end
bInit = true;
end
function onValueChanged()
if bInit then
if getValue() ~= 0 then
ModifierStack.setModifierKey(getName(), true);
else
ModifierStack.setModifierKey(getName(), false);
end
end
end
Debug.chat(bInit);
</script>


I believe this is what would work for a simple single state switch. How would I modify this to work with a row of 5 pips that turn on and off, like the 5 pips under the modifier window.

Moon Wizard
November 7th, 2019, 19:19
The ModifierStack built-in functionality only knows about whether a button is pressed or not; there's no concept of a multi-state like you're trying to do. You could implement as five different "keys" that are true/false, based on the value. However, you could just have your own custom global script to track this that you reference in the roll modification code.

Regardless of how you do this, you will still need to handle this in your own custom roll modification code as mentioned in post #8 above.

Regards,
JPG

statik37
November 8th, 2019, 01:39
Ok, one more follow up question.


if ModifierStack.getModifierKey("things") then

returns true when a control has the name "things". Can I drill down? Like, under that control I have a values entry with a current entry under it with a number. Can I do a getValue or an if current == 1 then this, if current == 2, do this?

Trenloe
November 8th, 2019, 01:46
Can I drill down? Like, under that control I have a values entry with a current entry under it with a number. Can I do a getValue or an if current == 1 then this, if current == 2, do this?
Just like with any FG control - you can access the value through the GUI, or the database (if the control stores its value in the database).

For GUI controls: https://www.fantasygrounds.com/refdoc/textbasecontrol.xcp#getValue
For database: https://www.fantasygrounds.com/refdoc/DB.xcp#getValue or https://www.fantasygrounds.com/refdoc/databasenode.xcp#getValue

Moon Wizard
November 8th, 2019, 01:46
Nope, it's just a single boolean state.

There are a few key questions I think you need to answer before we go any farther:
* Please explain the general concept of what you're trying to do. It will help us answer. Don't worry about the details/APIs/templates, just the high-level concept.
* Does this control show up on GM side?
* Does this control show up on player side?
* If it shows up on both GM and player, does this control show up exactly the same on both GM and player, or different on each?
* If it shows up on both GM and player, can all users (GM and players) edit, or only the GM?

Thanks,
JPG

statik37
November 8th, 2019, 12:29
OK, It does show up to both player and GM. It is controllable by both player and GM, and it is different to both player and GM.

The basic concept is: I want the pips to represent how many dice can be rolled from 1 to 5. So, when I initiate a roll, I want it to go to the desktop and see how many pips are lit up, and take that number and add it to the roll.

I figured the way I would do it, is once I create the rRoll table, I could then pass it to a function that would then add a new table entry for how many pips are lit up, and pass rRoll back with the new entry added. The issue I am having is I can't figure out how to get it to work. I assume it's very much like the modifier number, where the system will grab the number and add it to rRoll.nMod, but that's the point I am having trouble with.

Trenloe
November 8th, 2019, 12:50
See this thread: https://www.fantasygrounds.com/forums/showthread.php?35531-Fantasy-Grounds-v3-X-CoreRPG-based-Actions-(dice-rolling) It breaks the whole action process down and gives example of a custom action. Where an "action" in FG is rolling dice for a specific game mechanic.

In step 3, where the custom modifiers are applied, you can add/remove dice from the LUA rRoll.aDice table as required, based off the number of pips. So I suggest you start the action with 1 dice in rRoll.aDice and then add additional dice for each pip above 1 in the step 3 modifier handler (function modRoll in most FG action scripts).

statik37
November 9th, 2019, 02:30
That was very helpful, but maybe I'm just not getting it.

Do, I went and looked again at modifierstack.lua Through experienting, I learned I can retrieve the number save there by calling ModifierStack.getSum().

Which is:

function getSum()
local total = freeadjustment;
Debug.chat(total)

for i = 1, #slots do
total = total + slots[i].number;
end

return total;
end


When I put that debug line in there, I see freeadjustment passes a value of whatever I type in the mod.

It looks like freeadjustment is a global variable. So, I set up a global variable, and whenever the pips are changed, it changes with them, however, for some reason, that variable is not carrying through out of that function. How is it that the modifiierstack variable is carrying over? what am I missing?

Moon Wizard
November 9th, 2019, 04:38
The ModifierStack script is implemented simply to add a fixed numerical value; not modify the number of dice rolled in any way.

As I mentioned previously, you should go back to the 5E roll handlers, and make sure that the modifiers are applied to any roll that you want them applied to in your system. You can also apply the modifiers to the general purpose die roll type ("dice"). Please see scripts/manager_action_general.lua in the 5E ruleset. Pay extra attention to the ActionsManager2.encodeDesktopMods(rRoll) call, which you can change in your own ruleset to modify the roll however you want based on any desktop controls.

Regards,
JPG

statik37
November 9th, 2019, 19:46
The ModifierStack script is implemented simply to add a fixed numerical value; not modify the number of dice rolled in any way.

This is what I want. I want a fixed numerical value. I already have the for loop to break it out into individual d20 entries as needed. I just need to get the value.

Moon Wizard
November 10th, 2019, 23:18
That number is already added to roll automatically via the ActionsManager script in CoreRPG.

If you want to change the behavior, you have to either change the ModifierStaci script; or just add the bonuses to the rolls directly. The latter is what 5E does with the desktop buttons. That’s why I’ve been suggesting using the model; since it doesn’t require you to overwrite any CoreRPG scripts.

Regards,
JPG

damned
November 11th, 2019, 02:17
look at ianmwards dice pool extension

statik37
November 11th, 2019, 06:19
I feel like such a pain now, but let me try to explain this a little better.

In order to create the pips on the desktop I am using the buttongroup_counter template and lua file from CoreRPG. The only difference is I stripped out all reference to the database. Once I did that, I was able to get the buttons to click on and off as expected. When I add debug commands into the lua file I can generate the correct value. The thing I'm struggling with is now how to I pull that info from the file? I tried registering controls. I tried the getmodifierkey like in 5e. Nothing I have tried will pull a value of 1 to 5 as I would like.

As of right now, the only change I have made that makes things work is stripping out the database stuff so the buttons will react. At this point I don't know what else to do to get the info out.

I am attaching the lua file here for reference. As I said, all I did was strip the db info. Any insight on how to now pull the value out of this file and store it in a variable in another lua file? I looked at the 5E code, and from what I can see, it's just looking for a single button to be on or off I tried to manipulate it to work for a variable button, but I couldn't figure it out.

for reference, here is the template:


<template name="dice_counter">
<genericcontrol>
<stateicons>
<on>button_checkon</on>
<off>button_checkoff</off>
</stateicons>
<script file="desktop/scripts/dice_counter.lua" />
</genericcontrol>
</template>


and here is the windowclass I am using it in:


<windowclass name="rollpanel">
<sizelimits>
<minimum width="64" height="52" />
</sizelimits>
<noclose />
<sheetdata>
<dice_counter name="diegroup">
<anchored position="insidetopleft" offset="4,50" width="60"/>
<allowsinglespacing />
<stateicons>
<on>button_checkon2</on>
<off>button_checkoff2</off>
</stateicons>
<values>
<maximum>5</maximum>
<current>2</current>
</values>
<sourcefields>
<current>curr</current>
</sourcefields>
<maxslotperrow>5</maxslotperrow>
</dice_counter>
</sheetdata>
</windowclass>


I have also added the file to base.xml.

right now, that's everything I have and did. I don't know what to do next so when I run this function in a different file:


function taskcheck(draginfo, winFrame, foc, tar)
local nodeWin = winFrame.getDatabaseNode();
local node = DB.findNode(".");
local rActor = ActorManager.getActor("pc", nodeWin);
local rolling20 = 0;
rolling20 =????????;
local sides = 20;
local TN = DB.getValue(nodeWin, tar);
local FC = DB.getValue(nodeWin, foc);
local nDiff = ActionsManager2.encodeDesktopDiff(nDiff);
local nComp = 1 -- nodeWin.getChild("rollable.comprange").getValue();
local comp = 21 - nComp
local sParams = rolling20.."d"..sides.."t"..TN.."f"..FC.."c"..comp.."d"..nDiff;
local msg = {font = "sheetlabel"};

msg.text = rActor.sName .. " rolls a task"
Comm.deliverChatMessage(msg);
local msg = {font = "sheetlabel"};
msg.text= "Target Number.." .. TN.."\nFocus Range.."..FC.."\nComplication Range.."..nComp.."\nDifficulty.."..nDiff.."\nRolling "..rolling20.. "d20\n";
Comm.deliverChatMessage(msg);
resetdice(winFrame);
DiceRoller.performAction(draginfo, rActor, sParams)
return true;
end


how do I get rolling20 to be the value 1 to 5, depending on how many pips are turned on?

I hope that all makes sense. I have been staring at this code for 2 weeks now, and I have to somehow get it to work.

statik37
November 11th, 2019, 19:49
OK, after searching the forums further, I found this:

https://www.fantasygrounds.com/forums/showthread.php?43598-Target-DC-on-the-Desktop

The number 2 version looks pretty much exactly what I want, but instead of entering a number, I want it to add up the value of the pips.

I put the functions in the dice_counter.lua file and added the script to the windowclass.

I then had rolling20 = DiceCounter.getDCValue. I changed the control names as appropriately. However, when I reload and try a roll, I get


attempt to call field 'getValue' (a nil value) This ultimately seems to be my issue. How do I make that not nil?

Trenloe
November 11th, 2019, 19:53
What code is running when you get that error? "nil value" means that getValue is being called against an invalid FG object. What object do you have before the getValue() code? Something like myControlName.getValue()

As I mention in this post: https://www.fantasygrounds.com/forums/showthread.php?43598-Target-DC-on-the-Desktop&p=387852&viewfull=1#post387852 "... uses control.examplenumber.getValue() to get the value stored in the examplenumber number control ..."

statik37
November 11th, 2019, 19:57
function getDCValue()
local numberValue = 0;

if control then
Debug.chat(control.diegroup);
numberValue = control.diegroup.getValue();
end

return numberValue;
end

And the debug gives me: "windowcontrol = {x,y,w,h = 4,50,50,10}

Trenloe
November 11th, 2019, 20:01
And the debug gives me: "windowcontrol = {x,y,w,h = 4,50,50,10}
What does debug for control give you?
What does debug for control.diegroup give you?

You're calling this: numberValue = control.diegroup.getValue(); so FG is looking for a GUI control called control.diegroup - does that exist? Is it accessible from where the code is running? Is getValue() a valid API call for that type of control?

Trenloe
November 11th, 2019, 20:04
Also please read, in detail, the information I provide in the forum posts you've linked. For example:

"note that control is actually a local variable declared at the stop of the script file - it is here that the reference to the desktop panel control will be stored when it is registered. This allows future function calls into this package to get access to the desktop panel control."

Do you have this local variable in your script? Do you register it to the actual desktop control?

statik37
November 11th, 2019, 20:05
Debug of control gives me:

windowinstance = { class = rollpanel, node = nil, x,y,w,h = 6,944,74,62 }


Debug for control.diegroup gives me:

windowcontrol = {x,y,w,h = 4,50,50,10}

For reference, rollpanel is the name of the windowclass and diegroup is the name of the genericcontrol

statik37
November 11th, 2019, 20:06
And for your second question, yes I added:


local control = nil;

function registerControl(ctrl)
control = ctrl;
end

to the start of the file.

And the windowclass has


<script>
function onInit()
DiceCounter.registerControl(self);
end

function onClose()
DiceCounter.registerControl(nil);
end
</script>

Trenloe
November 11th, 2019, 20:08
Is getValue() a valid API call for that type of control?


... diegroup is the name of the genericcontrol
getValue() is not a valid API call for genericcontrol : https://www.fantasygrounds.com/refdoc/genericcontrol.xcp

statik37
November 11th, 2019, 20:15
Well shoot.

Now I feel dumb.

Is there something I can do for it to look the same and be able to do what I want it to?

I want it to look like the file attached and click on and off sequentially.

Here is the code I am using now, for reference.



<template name="dice_counter">
<genericcontrol>
<stateicons>
<on>button_checkon</on>
<off>button_checkoff</off>
</stateicons>
<script file="desktop/scripts/dice_counter.lua" />
</genericcontrol>
</template>




<dice_counter name="diegroup">
<anchored position="insidetopleft" offset="4,50" width="60"/>
<allowsinglespacing />
<stateicons>
<on>button_checkon2</on>
<off>button_checkoff2</off>
</stateicons>
<values>
<maximum>5</maximum>
<current>2</current>
</values>
<sourcefields>
<current>curr</current>
</sourcefields>
<maxslotperrow>5</maxslotperrow>
</dice_counter>

Trenloe
November 11th, 2019, 20:26
In desktop/scripts/dice_counter.lua write some code (maybe call the function getPips ??) that calculates and returns the number of pips selected and then call that code.

statik37
November 11th, 2019, 20:42
So, I tried, out of curiosity, changing it from a generic control to a button control.

The errors went away, but I get 0 whenever I call it. I did try what you said, but I guess I don't know how to make it so a variable will be collectible from the outside.

Trenloe
November 11th, 2019, 20:48
I did try what you said, but I guess I don't know how to make it so a variable will be collectible from the outside.

Make a function in desktop/scripts/dice_counter.lua, something like:


function getPips()
local nPips = 0;

-- Write code that gets the number of pips and store that in nPips.
-- Then return nPips as follows:

return nPips;
end

Then, assuming that control.diegroup is valid where you run your code, call the function with: control.diegroup.getPips()

statik37
November 11th, 2019, 20:56
I thought I tried that and just kept getting either 0 or nil. But, as I'm typing, I am trying other things. For example. I realised that the getValue will return 0 because nowhere in my script am I calling a setValue.

So I have the beginning of a function here that I was trying:



function updateSlots()
if not bInit then
return;
end

Debug.chat("control", control);
checkBounds();

local m = getMaxValue();
local c = getCurrentValue();
if control then
Debug.chat(control);
Debug.chat(control.diegroup);
control.diegroup.setValue(c);
end


The problem is the if loop doesn't run because the control isn't carrying into the function. the first debug generates a nil.

Trenloe
November 11th, 2019, 21:11
the first debug generates a nil.
So control is nil then. You'll need to investigate why.

statik37
November 11th, 2019, 22:02
The reason that is happening semms to have been fixed by changing control to window, now it calls it up no problem.

Here's another issue. It seems like it was issue after issue piling up.

in https://www.fantasygrounds.com/refdoc/buttoncontrol.xcp#setValue It states that:


Sets the value of the button control. If the value specified is greater than the number of button states defined, then the value is set to zero instead.

I think I have to define that there are 5 stages of button press, but I don't know how to do that part.

Intead, I set a global variable nValue = 0 at the top of the file. Then, at the bottom of the update slots, I set nValue = c, which is the current value for the button. and returned nValue. But, when I call for the roll and getDCValue function, which right now only says Debug.chat(nValue)

I get a returned value of 0. I feel like I am missing a super simple step.

Moon Wizard
November 11th, 2019, 22:32
Don't use a buttoncontrol. That requires you to define all five states. Use a genericcontrol and define your own getValue. Make sure to liberally use Debug statements to make sure your variables are what they should be.

JPG

statik37
November 11th, 2019, 22:58
You are a godsend. You are all godsends. After messing with this code for, literally, 2 weeks, it's finally working. I can not thank you and Moon Wizard, and Damned enough for all the patience and tutelage you have given me. When I saw it working correctly, I almost cried.

Trenloe
November 11th, 2019, 23:00
When I saw it working correctly, I almost cried.
I don't help with crying. You're on your own there! ;)

Glad you got it working!