PDA

View Full Version : Dice rolling, with dice...



celestian
February 17th, 2018, 04:53
So this is probably something I'm just missing that's simple. I'm trying to roll 2d6 and 2d4 and get the result. The dice roll and a result shows in chat but... I can't programmatically get the value of the rolled result. Here is how I do the rolls. (I've tried performAction and actionDirect).



local rTurnHDRoll = { sType = "dice", sDesc = "Turn Undead", aDice = aTurnDice, nMod = 0 };
--ActionsManager.performAction(nil, nil, rTurnHDRoll);
ActionsManager.actionDirect(nil, "dice", { rTurnHDRoll });


When I view rTurnHDRoll in debug



Debug.console("manager_action_turnundead.lua","onRoll","rTurnHDRoll",rTurnHDRoll);


I see...



Runtime Notice: s'manager_action_turnundead.lua' | s'onRoll' | s'rTurnHDRoll' | { s'sType' = s'dice', s'aDice' = { #1 = s'd6', #2 = s'd6', #3 = s'd4', #4 = s'd4' }, s'nMod' = #0, s'sDesc' = s'Turn Undead' }


You'll notice there is not a "result = #SomeNumber" there. What I want to do is make those rolls and get the value. I've reviewed various functions that do rolls and use rRoll style and they all seem to get a "result" key in the end run...

Is there a another function I'm missing that will do this? I can write something to do this but surely I'm just blind?

Trenloe
February 17th, 2018, 13:26
That debug looks like no results are available - individual dice nor the total result. Where do you have the debug code? You’ll need to look in the final result handler in a different function to where you call the actionDirect function. Rolling is asynchronous, FG doesn’t stop a function waiting for the result of the roll, it needs to be looked at in the result handler function.

Trenloe
February 17th, 2018, 13:29
See step 5 here: https://www.fantasygrounds.com/forums/showthread.php?35531-Fantasy-Grounds-v3-X-CoreRPG-based-Actions-(dice-rolling)&p=307397&viewfull=1#post307397

Bidmaron
February 17th, 2018, 15:17
Trenloe, that is an outstanding post. I agree with Dulux that it should be in the wiki, but I think it needs to be in a "useful forum posts" kind of section that links back to it rather than trying to duplicate posts onto the Wiki.

celestian
February 17th, 2018, 16:36
That debug looks like no results are available - individual dice nor the total result. Where do you have the debug code? You’ll need to look in the final result handler in a different function to where you call the actionDirect function. Rolling is asynchronous, FG doesn’t stop a function waiting for the result of the roll, it needs to be looked at in the result handler function.

It's there, it's just in the "code" mode and doesn't wrap.

Runtime Notice: s'manager_action_turnundead.lua' | s'onRoll' | s'rTurnHDRoll' | { s'sType' = s'dice', s'aDice' = { #1 = s'd6', #2 = s'd6', #3 = s'd4', #4 = s'd4' }, s'nMod' = #0, s'sDesc' = s'Turn Undead' }

2d6 and 2d4.


See step 5 here: https://www.fantasygrounds.com/forums/showthread.php?35531-Fantasy-Grounds-v3-X-CoreRPG-based-Actions-(dice-rolling)&p=307397&viewfull=1#post307397

I'll check it out, thanks ;)

So, I've done this before (infact the turn undead does just what you're suggesting) but I don't think I need the onRoll bit unless that hook somehow is setting rRoll.result?

"local nTotal = ActionsManager.total(rTurnHDRoll);"

This part fails for rTurnHDRoll after "ActionsManager.performAction(nil, rSource, rTurnHDRoll);" runs. rTurnHDRoll does not have rTurnHDRoll.result set.

celestian
February 17th, 2018, 17:00
Okay, so I created another onRoll_TurnCount and added the handler for this and it does set the .result values there... I was hoping I could handle the output for the results in the same place as the other but guess that is not going to be possible.

This is from within the "turnundead" onRoll:
Runtime Notice: s'manager_action_turnundead.lua' | s'onRoll' | s'rTurnHDRoll' | { s'aDice' = { #1 = s'd6', #2 = s'd6', #3 = s'd4', #4 = s'd4' }, s'nMod' = #0, s'sType' = s'turnundead_count', s'bSecret' = bFALSE, s'nTarget' = #99, s'sDesc' = s'Turn Undead' }

This is in the onRoll_TurnCount for type turnundead_count.:
Runtime Notice: s'manager_action_turnundead.lua' | s'onRoll_TurnCount' | s'rRoll' | { s'aDice' = { #1 = { s'result' = #2, s'type' = s'd6' }, #2 = { s'result' = #6, s'type' = s'd6' }, #3 = { s'result' = #2, s'type' = s'd4' }, #4 = { s'result' = #3, s'type' = s'd4' } }, s'nMod' = #0, s'sType' = s'turnundead_count', s'sDesc' = s'Turn Undead', s'nTarget' = s'99', s'bSecret' = bFALSE }
Runtime Notice: s'manager_action_turnundead.lua' | s'onRoll_TurnCount' | s'nTotal' | #13

So it seems it doesn't even get the result until after the fact so... I'll see what I can do ;)

Thanks for the pointer and insight.

Trenloe
February 17th, 2018, 17:48
This is in the onRoll_TurnCount for type turnundead_count.:
Runtime Notice: s'manager_action_turnundead.lua' | s'onRoll_TurnCount' | s'rRoll' | { s'aDice' = { #1 = { s'result' = #2, s'type' = s'd6' }, #2 = { s'result' = #6, s'type' = s'd6' }, #3 = { s'result' = #2, s'type' = s'd4' }, #4 = { s'result' = #3, s'type' = s'd4' } }, s'nMod' = #0, s'sType' = s'turnundead_count', s'sDesc' = s'Turn Undead', s'nTarget' = s'99', s'bSecret' = bFALSE }
Yeah, you see you have the result for each individual dice as well as the total. This is only available after the dice have fully landed, and not in the same function as when the roll is initiated.

celestian
February 18th, 2018, 04:28
Yeah, you see you have the result for each individual dice as well as the total. This is only available after the dice have fully landed, and not in the same function as when the roll is initiated.

Is there some similar magic to get "rTarget" to be populated? The action doesn't seem to populate rTarget even if a target(s) are selected by the actor.

onRoll and modRoll both show rTarget = nil. I've been going over manager_action_attack and _damage but can't seem to see the immediate cause yet.

Trenloe
February 18th, 2018, 13:31
Is there some similar magic to get "rTarget" to be populated? The action doesn't seem to populate rTarget even if a target(s) are selected by the actor.
Targeting is usually encapsulated in the draginfo data structure - for both dragging and the targeting system.

ActionsManager.actionDirect does not use targeting.

ActionsManager.performAction does use targeting if the draginfo data structure is included.

In the 5E ruleset, have a look at how the attack or damage actions are initiated from the weapon record. Look at campaign\scripts\char_weapon.lua - the onAttackAction and onDamageAction functions, these both call the relevant action handler "performRoll" functions including draginfo.

celestian
February 18th, 2018, 18:36
Targeting is usually encapsulated in the draginfo data structure - for both dragging and the targeting system.

ActionsManager.actionDirect does not use targeting.

ActionsManager.performAction does use targeting if the draginfo data structure is included.

In the 5E ruleset, have a look at how the attack or damage actions are initiated from the weapon record. Look at campaign\scripts\char_weapon.lua - the onAttackAction and onDamageAction functions, these both call the relevant action handler "performRoll" functions including draginfo.

Good point, I did note the draginfo portion, I'll poke around that. What I ended up doing in the meantime was pulling the <targets> node from the rSource. It worked but I'll see if I can work in rTarget instead.

celestian
February 18th, 2018, 20:53
Okay, so figured out what I was missing.

manager_gamesystem.lua, specifically "actions" and "targetactions" needed to have the "turnundead" type added.

Trenloe
February 18th, 2018, 20:59
See the bottom of post #1 from "Note:" onwards: https://www.fantasygrounds.com/forums/showthread.php?35531-Fantasy-Grounds-v3-X-CoreRPG-based-Actions-(dice-rolling)

celestian
February 18th, 2018, 21:55
See the bottom of post #1 from "Note:" onwards: https://www.fantasygrounds.com/forums/showthread.php?35531-Fantasy-Grounds-v3-X-CoreRPG-based-Actions-(dice-rolling)

Yes, I completely skimmed over that. I glanced at the CoreRPG version and it didn't ring any bells, when I looked over the 5E version I immediately realized what I needed to do.

The problem is now it seems to be that each rTarget is pushed into the "registerResultHandler" function (onRoll() in this case) one at a time. I need them en masse so I can sort by HD, flip through lowest HDs and manage turns. I looked over the sTargeting = "all" for gamesystem setting but didn't seem to change anything. Going to dig through the CoreRPG code for the sTargeting handling and see if I am missing something.

Grabbing the <targets> from rSource works for the "en masse" but I'm having permission issues when trying to apply damage and/or effects from the PC side when I do that. I know how to fix it (or kludge around it) by temporarily giving the User permission to the node but there has got to be a better way.

Trenloe
February 18th, 2018, 22:10
...but I'm having permission issues when trying to apply damage and/or effects from the PC side when I do that. I know how to fix it (or kludge around it) by temporarily giving the User permission to the node but there has got to be a better way.
The main rulesets always hand this part of the process off to the GM instance using OOB messaging. Look at the 5E handleApplyDamage OOB messaging in manager_action_damage.lua, which is initiated through the notifyApplyDamage function.

celestian
February 18th, 2018, 23:27
The main rulesets always hand this part of the process off to the GM instance using OOB messaging. Look at the 5E handleApplyDamage OOB messaging in manager_action_damage.lua, which is initiated through the notifyApplyDamage function.

That was exactly what I needed! Thanks.

It's a bit convoluted but it works. Here is what I ended up with if anyone cares.

Problem, need to apply damage or effects to nodes. CAn't do that as a player so you have to send the commands to "OOBManager" who DOES have access.


Notify(): the part where you tell OOBManager to take it
Handle(): The part where OOB takes the options and sends to apply() (at this point you have all the access you need to nodes)
Apply(): Perform actual action to the node you wanted (you could probably merge apply() into handle() if you wanted).



Here are the registers.



OOB_MSGTYPE_APPLYOBLITERATE = "applyobliterate";
OOB_MSGTYPE_APPLYTURN = "applyturn";

function onInit()
OOBManager.registerOOBMsgHandler(OOB_MSGTYPE_APPLY OBLITERATE, handleApplyObliteration);
OOBManager.registerOOBMsgHandler(OOB_MSGTYPE_APPLY TURN, handleApplyTurned);

ActionsManager.registerModHandler("turnundead", modRoll);
ActionsManager.registerResultHandler("turnundead", onRoll);
end


And the register code.



-- handle turning a creature
function handleTurn(rSource, nodeTurn,rMessage,bDestroy)
Debug.console("manager_action_turnundead.lua","handleTurn","nodeTurn",nodeTurn);
local rTarget = ActorManager.getActor("ct",nodeTurn);

local sName = DB.getValue(nodeTurn,"name","NO-NAME");
if (bDestroy) then
notifyApplyObliteration(rSource,rTarget);
rMessage.text = rMessage.text .."\r\nObliterated " .. sName .. "!";
else
notifyApplyTurn(rSource,rTarget);
rMessage.text = rMessage.text .."\r\nTurned " .. sName .. "!";
end
end

function notifyApplyObliteration(rSource, rTarget)
local msgOOB = {};
msgOOB.type = OOB_MSGTYPE_APPLYOBLITERATE;

msgOOB.sSourceNode = ActorManager.getCTNodeName(rSource);
msgOOB.sTargetNode = ActorManager.getCTNodeName(rTarget);

Comm.deliverOOBMessage(msgOOB, "");
end
function handleApplyObliteration(msgOOB)
local rSource = ActorManager.getActor(msgOOB.sSourceType, msgOOB.sSourceNode);
local rTarget = ActorManager.getActor(msgOOB.sTargetType, msgOOB.sTargetNode);
if rTarget then
rTarget.nOrder = msgOOB.nTargetOrder;
end

local nTotal = tonumber(msgOOB.nTotal) or 0;
applyObliteration(rSource, rTarget);
end
function applyObliteration(rSource, rTarget)
-- obliterate undead
local nodeTurn = ActorManager.getCTNode(rTarget);
local nHPMax = DB.getValue(nodeTurn,"hptotal",0);
DB.setValue(nodeTurn,"wounds","number",nHPMax+1);
end

function notifyApplyTurn(rSource, rTarget)
local msgOOB = {};
msgOOB.type = OOB_MSGTYPE_APPLYTURN;

msgOOB.sSourceNode = ActorManager.getCTNodeName(rSource);
msgOOB.sTargetNode = ActorManager.getCTNodeName(rTarget);

Comm.deliverOOBMessage(msgOOB, "");
end
function handleApplyTurned(msgOOB)
local rSource = ActorManager.getActor(msgOOB.sSourceType, msgOOB.sSourceNode);
local rTarget = ActorManager.getActor(msgOOB.sTargetType, msgOOB.sTargetNode);
if rTarget then
rTarget.nOrder = msgOOB.nTargetOrder;
end

local nTotal = tonumber(msgOOB.nTotal) or 0;
applyTurnedState(rSource, rTarget);
end
function applyTurnedState(rSource, rTarget)
-- turn undead
if not EffectManager5E.hasEffect(rTarget, "Turned") then
EffectManager.addEffect("", "", ActorManager.getCTNode(rTarget), { sName = "Turned", nDuration = 0 }, true);
end
end

Bidmaron
February 18th, 2018, 23:35
Thanks, Celestian.

Trenloe
February 18th, 2018, 23:37
It's a bit convoluted but it works.
Yeah, when I'm developing and I realise I need to offload some stuff to an OOB process I sigh and lookup how it's done to remind myself... :D

celestian
February 18th, 2018, 23:40
Yeah, when I'm developing and I realise I need to offload some stuff to an OOB process I sigh and lookup how it's done to remind myself... :D

Definately going to bookmark this thread for when I need it down the road again ;)

Moon Wizard
February 18th, 2018, 23:48
Well done. I had bookmarked this thread to come back and respond when I was at my computer, but you and Trenloe figured it out.

Cheers,
JPG

celestian
February 19th, 2018, 00:07
Well done. I had bookmarked this thread to come back and respond when I was at my computer, but you and Trenloe figured it out.


The only bit I'm still trying to figure out is rTarget. Right now if I use rTarget it sends one at a time to onRoll. Is that how it's going to work for turnactions/actions? Is there no way to send an array/table/something ?

The way I get around this right now is get the <targets> for the rSource and everything does work... I just think folks might be confused that the drag/drop the dice on the target not working.

The way turn undead works in AD&D I really need the entire list of npcs, sorted by HD (low to high). The player rolls a dice, I sort through a table and see if that roll turns X HD then turn/destroy it (or add bonus dice if it's a easy one)... all of which is about impossible to do if I only get them one at a time in onRoll().

Here is the "turn undead" table if it helps ;)

https://i.imgur.com/mwGC3MZ.png

If it's not possible then I'm good cause it's working but if there is a way to get a "list" of targetd nodes through rTarget style to make it more normalized I'll do that.

Moon Wizard
February 19th, 2018, 00:24
By default, the actions system returns the modified roll for each target, because effects can vary the final roll result for each target. Just think about conditional effects based on size/race/alignment, etc.

Because of the way that turn rolls work, I would actually grab the targets when the roll is initiated and not use the targeting system at all. (i.e. rTarget is always null)
Then, I would pass the information as part of the roll structure. When, the roll resolves to the final number, I would then send a custom OOB message to the GM client, which encapsulated all roll information, source actor information (using current method), and the variant targeting information we stored in the roll structure. Then, the GM client can handle the OOB message to create the group of targets, determine their HD, sort the NPCs by HD, and begin applying effects/damage to the NPCs based on the roll until it's used up.

Regards,
JPG

celestian
February 19th, 2018, 02:45
Sounds much like what I did so I'll call it good!

Thanks for the details ;)