PDA

View Full Version : How do you use drag and drop in an extension?



SilentRuin
June 11th, 2020, 14:40
I've seen examples in the 5e/CoreRPG and actually used OnDamageAction as an attempt to use draginfo in the same manner but it must be populating that structure someplace else. All I get is the hand and when I button down it disappears and no draginfo is brought into my function. Yeah I was hoping for under the hood magic there.

Anyway, I figured maybe someone could spare me yet another deep dive trial and error adventure into the code.

Here is what I'm currently doing in one of my .xml's

function onDoubleClick(x,y)
return window.STUFF();
end

function onDragStart(button, x, y, draginfo)
return window.STUFF(draginfo);
end

I'm guessing using the OnDamageInfo has magic populating the draginfo - so what I need to know is how I do that in a raw extension I'm creating. I see examples for onDrag, onHover, etc. but nowhere in the 5e/CoreRPG unpacked files can I find an example of where the draginfo is actually populated. Nor could I find any documents/videos specifically addressing how this should be done.

Advice?

Trenloe
June 11th, 2020, 15:54
So, yes, the draginfo data is "magically" populated with onDragStart - info on that event, with a link to the dragdata object, here: https://fantasygroundsunity.atlassian.net/wiki/spaces/FGU/pages/4162011/windowcontrol#onDragStart

But, that magic population of data is pretty minimal - use some debug code in your event to see what it contains: Debug.console("draginfo = ", dragingo); will output the draginfo object to the FG console. Open the console using /console in the chat window.

It's up to your code to populate the rest of the dragdata - like the icon and text to display while dragging, etc.. And, of course, to program what happens when the drag is dropped.

The encodeActionForDrag function in the CoreRPG scripts\manager_actions.lua file has the usual things that get added to the dragdata object as part of a standard CoreRPG based ruleset action process. If you use this action process, then it will get populated for you.

The onDamageAction function you mentioned does this - it sets up the rAction record (LUA table) that has the damage details in it, which then calls the performRoll function in 5E scripts\manager_action_damage.lua which sets up the rRoll data based off the rAction info passed in. It's the rRoll data that CoreRPG will use to setup the dragdata icons etc..

So, yeah, pretty complex - especially if you're defining a new action. If you're actually creating a whole new action then you'll need to make sure you adhere to the CoreRPG action structure to take advantage of a lot of the process - but it's still not simple.

The whole action process, with an example, is described here: https://www.fantasygrounds.com/forums/showthread.php?35531-Coding-dice-rolls-(actions)-in-CoreRPG

SilentRuin
June 11th, 2020, 17:25
Yeah its not triggered by an rRoll. I have a character sheet generic button that uses the characters target (like applying damage does). When double clicking on button, it completely looks up the target successfully etc. - I had logic in it looking to see if draginfo was defined to use that to get the combat tracker target. Unfortunately, as I stated, the draginfo was empty.

Which I suppose explains why i always get nil (no info as I said in first post). So I'm one step back further than you are starting at, where I don't even get the structure defined. I'm going to assume that the "magic" will have to be done by me completely (like implement my own onDrag) ? Or did I misunderstand your examples?

It seems all the examples you gave involve being part of the rRoll logic. I'm looking for generic click down on button - drag it over a target on map or combat tracker - release button and it starts the process with draginfo populate with the target - which I use just like I do when I look it up myself.

I'll look at the encodeActionForDrag but I did not see anything in my past searches for draginfo creation - probably named something else. Thanks! Very helpful. If you have any raw button from scratch dragging to find a target examples - let me know.

SilentRuin
June 11th, 2020, 17:36
Well crap. Turns out if I drag I do have the structure (thanks to your print) its just doing the onDragStart when I mouse move, and that structure has no data. I'm an idiot. Ok I have something to look at now.

This is what happens when you copy the wrong code doing a different task than you are :)

SilentRuin
June 11th, 2020, 23:52
Yeah well that sucks. Not going to be able to do what I wanted - something above charsheet_actions_contents (which I joined to the bottom of for my new category of actions) is eating OnDrop so I can never actually get it. Someone probably stuck a return true when they should have put return false (so future additions could be added), or so I'm guessing - could be wrong. Point being no matter what I do I never see an onDrop.

So my plans to create a fake OnDragStart to drag an icon (d20icon) and drop it over something without doing anything, just to get the x,y from OnDrop and determine if a target pc/npc can be obtained from that window, is over. I have to do a number of checks on the source AND the target before the first die roll - which means I have to have the target when the main function gets kicked off. On a double click - I just go determine it from combat tracker and it all works great - but I wanted the cool ability to simply drop my fake dice over a valid target and kick it off with that dummy target (not listed in combat tracker as target) like attack and damage do. But it appears that won't be possible where my buttons live.

If I'm right in all this theorizing I'm stuck with access to only OnDragStart as an option where my buttons live. And since I'll never see the OnDrop x/y coords I'm stuck with rRoll to have the dice dropped over the target. Then eat the fake die roll? And proceed with my checks and modifications before the real source vs target dice get done? Ugh. I may just live with only the double click functionality without that cool ability to pick a target that was not really a target in combat tracker.

Given what I'm seeing - is there a way to get the rRoll to give me a target and ActionsManager.registerResultHandler it so I can just kick of my main function without the rRoll actually rolling any dice? Pretty sure it does not write to chat unless I do the writing as I have two rRoll's in my code already.

Is there a secret way or trick to make rRoll do the target acquisition but not actually display any dice rollling around? I can live with a fake hidden roll that I don't use.

I should mention - all this code is in Unity.

SilentRuin
June 13th, 2020, 04:53
Solved it. A kludge for sure. I had the doublclick functionality fully working to start with, then created the OnStartDrag functionality to kick off a dummy role for "attack".



function onInit()
...
-- Need to intercept the "attack" rolls.
ActionsManager.registerResultHandler("attack", onDummyRoll);
ActionsManager.registerResultHandler("firststuffroll", onStuffRoll);
...
end

function onDummyRoll (rSource, rTarget, rRoll)
--- Need to insure you pass on any real "attack" rolls that are not yours. I use a made up global internal flag I track.
if not processattack then
ActionAttack.onAttack(rSource, rTarget, rRoll);
return;
end

-- Then you save the dummy dice you rolled. Another global internal variable.
dummydice = rRoll.aDice;

-- Then I save the target CT from the magic "attack" logic that let the dice drop over it and pull it out of CT or the map.
local sTargetActorCT = ActorManager.getCTNodeName(rTarget);

-- Then I call my stuff
STUFF(nil, ..., sTargetActorCT);
end

function onStuffRoll (rSource, rTarget, rRoll)
if dummydice then
rRoll.aDice = dummydice;
end
-- do normal double click logic
end

function STUFF (draginfo, ..., sTargetActorCT)
...
if draginfo or sTargetActorCT then
if not sTargetActorCT then
local rRoll = {};
rRoll.sType = "attack";
rRoll.aDice = { "d20" };
rRoll.nMod = 0;
rRoll.bWeapon = 0;
rRoll.sDesc = "";
processattack = true;
dummydice = nil;
ActionsManager.performAction(draginfo, rSourceActor, rRoll);
return true;
else
-- store sTargetActorCT to replace the one double click would normally look up in CT targets
...
end
else
dummydice = nil;
-- find first target myself for double click logic
end
...
-- Do double click logic including the "firststuffroll" normal double click roll - which will be overridden in click
...
end



What a pain to figure out.

But the kludge actually presents my button double click or drag transparently where the end user sees exactly the same things (without knowing the back flips I had to do to accomplish it).

Learning thought. May not be "legal" in how it's meant to be done - but given the limits I have to work within - works.

P.S. no idea how to get indentation in - replies do not seem to support it. Done enough work.

damned
June 13th, 2020, 05:14
use [ code ] and [ /code ] around your code (sans the spaces)

SilentRuin
June 13th, 2020, 11:29
Learned something new again :) Thanks!

Really wish there was a way to define rRoll with some flag that said "targeting" or something so I did not have to override the existing "attack" roll. I can see problems down the line if another extension overrode it and ate mine without passing it on (as I would their's). I'll take one more deep dive to see if I can get my own registered name and still get the targeting to work just in case I missed something.

SilentRuin
June 13th, 2020, 15:06
I found something that I think should work, but doesn't. Using Fantasy Grounds Unity, I put in the additional line to my onInit...

GameSystem.actions["dummyroll"] = { sIcon = "action_attack", sTargeting = "each", bUseModStack = true };

and then I replace my "attack" handler with this...

ActionsManager.registerResultHandler("dummyroll", onDummyRoll);

and also replace

rRoll.sType = "dummyroll";

and run my test to avoid overriding the existing action "attack"...

And onDummyRoll is never called. It's dragging the dice but when it's dropped - nothing. I put "attack" back in and when I drop the dice onDummyRoll is called. Does this functionality not work or am I'm missing another key undocumented "gotcha" with targeting on a roll?

I know the dummyroll was in the system as I printed out all the GameSystem.actions right before I performed the roll.

[6/13/2020 8:40:39 AM] s'actions name, features: dice, table: 000001C2AAD6F830'
[6/13/2020 8:40:39 AM] s'actions name, features: save, table: 000001C2AAD6F470'
[6/13/2020 8:40:39 AM] s'actions name, features: skill, table: 000001C2AAD705F0'
[6/13/2020 8:40:39 AM] s'actions name, features: cast, table: 000001C2AAD70230'
[6/13/2020 8:40:39 AM] s'actions name, features: table, table: 000001C2AAD6F880'
[6/13/2020 8:40:39 AM] s'actions name, features: recovery, table: 000001C2AAD6FF10'
[6/13/2020 8:40:39 AM] s'actions name, features: damage, table: 000001C2AAD6FA10'
[6/13/2020 8:40:39 AM] s'actions name, features: recharge, table: 000001C2AAD6FBA0'
[6/13/2020 8:40:39 AM] s'actions name, features: castsave, table: 000001C2AAD6F970'
[6/13/2020 8:40:39 AM] s'actions name, features: dummyroll, table: 000001C2A68955B0'
[6/13/2020 8:40:39 AM] s'actions name, features: systemshock, table: 000001C2A6894DE0'
[6/13/2020 8:40:39 AM] s'actions name, features: systemshockresult, table: 000001C2A6895240'
[6/13/2020 8:40:39 AM] s'actions name, features: effect, table: 000001C2AAD6FB50'
[6/13/2020 8:40:39 AM] s'actions name, features: heal, table: 000001C2AAD70410'
[6/13/2020 8:40:39 AM] s'actions name, features: init, table: 000001C2AAD6FE20'
[6/13/2020 8:40:39 AM] s'actions name, features: death, table: 000001C2AAD705A0'
[6/13/2020 8:40:39 AM] s'actions name, features: check, table: 000001C2AAD6FE70'
[6/13/2020 8:40:39 AM] s'actions name, features: attack, table: 000001C2AAD6FB00'
[6/13/2020 8:40:39 AM] s'actions name, features: concentration, table: 000001C2AAD6F420'
[6/13/2020 8:40:39 AM] s'actions name, features: powersave, table: 000001C2AAD6FD80'


Any clue? Or am I stuck with having to override "attack"?