MODULE: DragDrop 1.2.0: helps to drag things around your AGS game!

Started by Crimson Wizard, Mon 14/03/2016 00:09:54

Previous topic - Next topic

Crimson Wizard

DOWNLOAD DragDrop 1.2.0 MODULE
DOWNLOAD DragDropCommon 1.2.0 MODULE
DOWNLOAD Demo game

Additionally, latest sources of both the script module and the demo game may be found in this repository:
https://github.com/ivan-mogilko/ags-script-modules

Full documentation for this module is now available here:
https://github.com/ivan-mogilko/ags-script-modules/wiki/Drag-&-Drop-module

Module supports AGS 3.2.1 and higher.


DragDrop and DragDropCommon are two modules that make it possible to drag things around in AGS. What is the difference between these two?

DragDrop module implements an abstract drag-and-drop functionality. This means that the module does not drag any actual game object on its own, but rather calculates the dragging and dropping action, and tells you what and how happens, so that you could script the actual object movement. You might say, this module provides an idea of dragging, rather than dragging itself :).

The upside of such approach is that you may script dragging of anything, both standard AGS objects and your own custom things, even non-ordinary pseudo-objects. For example, you may use this module to script dragging a line from point A to B, or draw a rectangle by dragging one of it's corners. The downside is that you have to be ready to do some extra work, and understand scripting well.

When you need to just make normal ordinary game objects dragged around in your game, this is what DragDropCommon module is for. DragDropCommon supports drag-and-drop for Characters, Room Objects, GUIs and GUI controls, and inventory items, right out of the box, only with a minimal setup.

NOTE: DragDropCommon module actually depends on DragDrop module, so you will have to add both to your game if you want to use DragDropCommon.

selmiak

Now this sounds really useful! Especially for mobile games and even cooler ingame computerscreens with hacking!

Crimson Wizard

And hereby I release Drag & Drop module v1.0.0.
DOWNLOAD DragDrop 1.0.0 MODULE
DOWNLOAD DragDropCommon 1.0.0 MODULE
DOWNLOAD Demo game (needs AGS 3.2.1 or higher)
(Also updated first post)

Not sure how much this was popular, since I got only 1 response and no questions about module usage, but I keep hopes that it will be useful to some.

What's new in 1.0.0

This update was focused on making DragDropCommon module capable of dragging object images instead of objects themselves, which also let me implement dragging of InventoryItems.

1. Added DragDropCommon.DragMove property, which determines the way dragging is done. It can be:
- eDDCmnMoveSelf - drags the object itself at real time (does not work for Inventory Items);
- eDDCmnMoveGhostOverlay - drags overlay with object's image on it (won't work for GUI and Controls);
- eDDCmnMoveGhostGUI - drags supplied custom GUI with object's image on it (currently does not work for GUI and Controls, but this is ONLY way to make inventory items drag & drop);

2. Additionally to DragMove, following properties can be set:
- DragDropCommon.GhostTransparency - determines ghost mode image transparency;
- DragDropCommon.GhostAlpha - determines whether ghost mode uses images with alpha channel;
- DragDropCommon.GhostGUI - sets custom GUI to be used for eDDCmnMoveGhostGUI mode (this MUST be set, otherwise it won't work);

3. Following new properties are meant for reading current state:
- DragDropCommon._InvItem - pointer to inventory item (if one is being dragged);
- DragDropCommon.ObjectWidth - returns dragged object/representation width, either taken from its properties, or deduced from the image;
- DragDropCommon.ObjectHeight - returns dragged object/representation height, either taken from its properties, or deduced from the image;
- DragDropCommon.UsedGhostGraphic - returns actual graphic index used in ghost modes (or 0);

4. Added DragDropCommon.TryHookInventoryItem() function, which, naturally, tries to start dragging inventory item under DragDrop.DragStartX / DragStartY coordinates.


Extended and improved Demo Game. I was actually worried if those who downloaded it noticed there are more than 1 room. So this time I provided slightly better help messages and a kind of "startup menu".
Also, now there are 4 demo rooms.

katie08cd

thank you, but I can edit it like the deduction room, like Sherlock Holmes: Crimes & Punishments?

Crimson Wizard

Quote from: katie08cd on Fri 20/04/2018 17:08:47
thank you, but I can edit it like the deduction room, like Sherlock Holmes: Crimes & Punishments?

Yes of course. The module was created having extension in mind, that allows you to script dragging of both built-in AGS objects and also any kind of custom "entities" in your game, that you define yourself.

Before using it I recommend to first find out how do you set up the deduction room itself. After you know what kind of objects you will have there, and which AGS features will represent them, then I may be able to give more detailed advice for the use of this module.

Cassiebsg

Okay, I just installed this module as I got an idea where this will be perfect.
But after following your instrucs from the first post:
Quote
1. Add both DragDrop and DragDropCommon modules to your game. DragDrop should be higher in the module list, or your game won't compile.
2. In one of the rooms add following code to the "After Fade-in" event handler:
Code: Adventure Game Studio

      DragDrop.Enabled = true;
      DragDropCommon.ModeEnabled[eDragDropCharacter] = true;
      DragDropCommon.ModeEnabled[eDragDropRoomObject] = true;
     

3. Just in case, add following code to the "Leave room" event handler:
Code: Adventure Game Studio

      DragDropCommon.DisableAllModes();
      DragDrop.Enabled = false;
     

4. That's it! Now you can drag and drop characters and objects with your mouse in that room. Have fun :).

I immediately get a crash when trying to click on a character or object.
It fails on line 67, 147, 270 & 632 of DragDropCommon.asc with "Error running function 'repeatedly_execute_always': Error: Null pointer refenced

I'm using the latest AGS, 3.5.0.24

I haven't tried anything else or look at the demo yet... but since you wrote that was all that was needed to try it...  (roll)
I'll check the demo now.
There are those who believe that life here began out there...

Crimson Wizard

@Cassiebsg, looks like it works in "Ghost GUI" mode by default (don't know why :/), which requires you to set a GUI object to the module.

Change to another mode as
Code: ags

DragDropCommon.DragMove = eDDCmnMoveSelf;
   OR
DragDropCommon.DragMove = eDDCmnMoveGhostOverlay;


I must update this module when I get spare time, with fixes and maybe also better tutorial.

Cassiebsg

Thanks, I'll give a try later on, but will add the lines already before the forum crashes again.  :)

Edit: Works now! :) So guess I can now play with programming the game.  :-D
There are those who believe that life here began out there...

Amir

Can u drop and drag inventory items with the module and let them interact with other inventory items, hotspots, objects and characters?

I tried but I couldn't get it. Codes or modules for drop and drag of inventory items in other threads would also help although I couldn't find any.
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Crimson Wizard

Quote from: Amir on Thu 01/07/2021 18:11:54
Can u drop and drag inventory items with the module and let them interact with other inventory items, hotspots, objects and characters?

I tried but I couldn't get it. Codes or modules for drop and drag of inventory items in other threads would also help although I couldn't find any.

Inventory items themselves cannot be dragged, because they are not real on-screen objects. You need something that would represent them in game.

DragDropCommon module implements this using either a GUI or Overlay, but for items only feasible solution is GUI. If I remember correctly, Overlays don't work well because they are always appear behind GUI, which means they will be behind InventoryWindow too. Which is ugly. So best use GUI mode.

You may check how this is done in the Demo game's room 4 script (download link in the first post).

PS. For a brief example, here's how you set a GUI for representing item drag:
Code: ags

DragDropCommon.DragMove = eDDCmnMoveGhostGUI;
DragDropCommon.GhostGUI = MyGUI; // where MyGUI is the GUI you create yourself for this purpose


That may be enough for starters.

eri0o

 @Amir, are you trying to use this module on Android? It doesn't work with the allegro4 based engine with touchscreen devices.

Crimson Wizard

Quote from: eri0o on Thu 01/07/2021 18:38:45
Amir, are you trying to use this module on Android? It doesn't work with the allegro4 based engine.

What do you mean, why?

eri0o

There's no click and hold in allegro4 port - you can't check if a "mouse" button is down in the old allegro 4 Android port. This is the main thing I want to change with the new Android port (besides soon adding proper crossplatform multi-touch)

Edit: CW, I will not answer here to avoid complicating the topic, I just mentioned because Amir was asking about Android the other day. But in short we need proper way to support touch devices, including devices that have both, like laptop tablet hybrids. It's possible code wise with SDL, it's more about figuring the right design on how to handle this in AGS, I plan to open a ticket about this when I have at least a sketch of something.

Crimson Wizard

Quote from: eri0o on Thu 01/07/2021 18:40:43
There's no click and hold in allegro4 port. This is the main thing I want to change with the new Android port (besides soon adding proper crossplatform multi-touch)

If it's about controls and default ones don't work, this module allows to create custom ones. For example, if you check the demo game, there's one room where you press a key to start drag, and then press it again to stop drag.

I'd imagine there might be a way to figure out a solution on touch devices as well.

EDIT: I mean, that won't be literal "drag" anymore :), but rather click/touch to move, click/touch to drop workaround, or something similar.

Amir

@Crimson Wizard,  I checked room 4 script and created a gui like in ur module and I could drag the inventory items, but I couldn't let them interact with other inventory items, hotspots, objects and characters.

@eri0o  Oh, that's right. I'm trying to change a few things in my game so that it can be played on Android devices. All that remains is to drag the inventory items like other AGS games on Android, Whispers of a Machine, Blackwell series, etc.

if you are sure eri0o that this this module doesnt work on Android, is there some other code or method anywhere to do that?
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

eri0o

WoaM and Kathy Rain use a different code that works with the old android port - I actually have the script code because I asked by mail the dev, but I think you should just ask them yourself. If you want to use this module and use the same behavior for mouse and fingers, you need to use the Android SDL Port.

I have a little game that uses this module too here: https://github.com/ericoporto/dungeonhands

It has touch on the webport, but I don't know how well it runs on old devices. :/

Crimson Wizard

Quote from: Amir on Thu 01/07/2021 19:14:07
@Crimson Wizard,  I checked room 4 script and created a gui like in ur module and I could drag the inventory items, but I couldn't let them interact with other inventory items, hotspots, objects and characters.

You need to handle the "DragDrop.EvtWantDrop" event. For example, if you look into the room 4 script, there will be this piece of the code:
Code: ags

function room_RepExec()
{
  <...>
  else if (DragDrop.EvtWantDrop)
  {
    InvWindow* drop_to = GetInvWindowUnderObject(o_x, o_y, o_w, o_h);
    if (drop_to != null && ItemOrigin != null && drop_to != ItemOrigin)
    {
      ItemOrigin.CharacterToUse.LoseInventory(DragDropCommon._InvItem);
      drop_to.CharacterToUse.AddInventory(DragDropCommon._InvItem);
    }
  }
}


You write something similar in your "repeatedly_execute" function (e.g. in global script), and replace this with checking if there's a character, object, etc under the dragged item (or under the mouse x,y if you prefer), and if there's then, for example, call RunInteraction(eModeUseinv) for that object below.


Quote from: Amir on Thu 01/07/2021 19:14:07
if you are sure eri0o that this this module doesnt work on Android, is there some other code or method anywhere to do that?

This module is not strictly specific to desktop controls, it lets you customize itself to any control scheme you like. The problem is only in finding out what works with Android port, and applying here.

If the new Android port works better, 3.6.0 engine should be running games from previous versions well, you don't even have to recompile them in 3.6.0 (but you may).


I'd propose to separate this in two problems:
1. Making this interact with other objects after you drop the item;
2. Solving the Android controls.

Perhaps its best to test the first problem on desktop (like Windows) to make sure first part works.

Crimson Wizard

I might need to add another room to this demo showing how to script this kind interaction...

Quote from: eri0o on Thu 01/07/2021 18:40:43
There's no click and hold in allegro4 port - you can't check if a "mouse" button is down in the old allegro 4 Android port.

What happens when you press the finger and hold on Android, what kind of events does it send to AGS, if any?

Amir

Ahaaaa, I see.

I've tried something similar but not exactly as you described it. I will try it. Many Thanks.

QuoteI might need to add another room to this demo showing how to script this kind interaction

This is the best idea I ever heard  ;-D

QuoteI have a little game that uses this module too here: https://github.com/ericoporto/dungeonhands

I will check it out.

Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Amir

Quote
You write something similar in your "repeatedly_execute" function (e.g. in global script), and replace this with checking if there's a character, object, etc under the dragged item (or under the mouse x,y if you prefer), and if there's then, for example, call RunInteraction(eModeUseinv) for that object below.

Hi, I wrote something and I can now interact with hotspots,objects and characters but wrong interaction and inventory items don't interact with other inventory items. Do u know what's wrong?

Code: ags
function game_start() 
{ 

  DragDrop.Enabled = true;
  
  DragDropCommon.ModeEnabled[eDragDropInvItem] = true;
  DragDropCommon.DragMove = eDDCmnMoveGhostGUI;
  DragDropCommon.GhostGUI = gInvItemGhost;
  DragDropCommon.GhostTransparency = 0;
  DragDropCommon.GhostAlpha = false;
  DragDrop.DefaultHookKey = 0;
  DragDrop.DefaultHookMouseButton = eMouseLeft;
  DragDrop.DragMinDistance = 0;
  DragDrop.DragMinTime = 0;
  DragDrop.AutoTrackHookKey = true;
  DragDrop.DefaultUnhookAction = eDDUnhookRevert;
  }
  




Code: ags


function repeatedly_execute()
{
Character *chara = Character.GetAtScreenXY(mouse.x, mouse.y);
Object *obj = Object.GetAtScreenXY(mouse.x, mouse.y);
Hotspot *hot = Hotspot.GetAtScreenXY(mouse.x, mouse.y);
InventoryItem *inv = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);

if (DragDrop.EvtWantDrop)
{
  if ((chara != null) || (obj != null) || (hot != null) || (inv !=null))
  {
   Room.ProcessClick(mouse.x, mouse.y, eModeUseinv);
  }
}
}



Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Crimson Wizard

Quote from: Amir on Sun 04/07/2021 14:04:07
Hi, I wrote something and I can now interact with hotspots,objects and characters but wrong interaction and inventory items don't interact with other inventory items. Do u know what's wrong?

First of all, I imagine the code above is not your real code, because there are commands outside of a function?

Regarding the problem, Room.ProcessClick does not interact with the inventory items, because they are not inside the room. For them you got to do GUI.ProcessClick, or just call inv.RunInteraction(eModeUseinv);

I did not understand the part about "wrong interaction", could you explain more?

Amir

Oh, sorry, I made a mistake when I was trying to design my post here. I edited it.

GUI.ProcessClick is new to me but it dosn't work, I tried inv.RunInteraction(eModeUseinv); before but I'm getting an error "Null pointer referenced"
I tried
Code: ags

  if ((chara != null) || (obj != null) || (hot != null) || (inv !=null))
  {
   //Room.ProcessClick(mouse.x, mouse.y, eModeUseinv);
   //inv.RunInteraction(eModeUseinv);
   //ProcessClick(mouse.x, mouse.y, eModeUseinv);
   //cJesus.RunInteraction(eModeUseinv);
   //GUI.ProcessClick(mouse.x, mouse.y, eModeUseinv);
  }


Room.ProcessClick, ProcessClick, cJesus.RunInteraction work but wrong interaction I mean, when I have if, else if and else, it ignores the commands in if and else if and prints the commands in else, I mean it only sees "els" and  inventory items still don't interact with other inventory items.  ???
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Crimson Wizard

Quote from: Amir on Sun 04/07/2021 19:48:42
GUI.ProcessClick is new to me but it dosn't work, I tried inv.RunInteraction(eModeUseinv); before but I'm getting an error "Null pointer referenced"

I think at this point it's more a general question of scripting, rather than the use of this module.

You cannot call inv.RunInteraction(eModeUseinv) always, but only if "inv" is valid (inv !=null). You likely will need more if/elseif blocks to handle everything.


Code: ags

  if ((chara != null) || (obj != null) || (hot != null))
  {
    Room.ProcessClick(mouse.x, mouse.y, eModeUseinv);
  }
  else if (inv !=null)
  {
    inv.RunInteraction(eModeUseinv);
  }


Quote from: Amir on Sun 04/07/2021 19:48:42
Room.ProcessClick, ProcessClick, cJesus.RunInteraction work but wrong interaction I mean, when I have if, else if and else, it ignores the commands in if and else if and prints the commands in else

Wrong interactions, as in wrong verb, or wrong inventory item?

If last, how do you normally check for the used item? For example, if you check "player.ActiveInventory", then you simply may set it before running process click to whatever item is being dropped.
Code: ags

player.ActiveInventory = DragDropCommon._InvItem;

Amir

QuoteWrong interactions, as in wrong verb, or wrong inventory item?

Wrong verb.

But with player.ActiveInventory = DragDropCommon._InvItem; it works, cool  :)  inventory items still don't want to interact with other inventory items.

Code: ags

if (DragDrop.EvtWantDrop)
{
  cJesus.ActiveInventory = DragDropCommon._InvItem;
  
  if ((chara != null) || (obj != null) || (hot != null))
  {
   ProcessClick(mouse.x, mouse.y, eModeUseinv);
  }

  else if (inv != null) 
  {
    inv.RunInteraction(eModeUseinv);
  }
}


I made a video of whats happening. I've tried a lot of things but it still doesn't work. I think something is still missing in the code.


Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Crimson Wizard

Quote from: Amir on Mon 05/07/2021 10:50:26inventory items still don't want to interact with other inventory items.

More information is needed.
Does the code ever pass under "else if (inv != null)" ? You may test that either by placing a breakpoint there or "Display" command with some message.
You are running eModeUseinv interaction. Do you have event of that type ("use inventory item on") created for your items?
What is inside these event functions, are there more conditions? Can you post an example of your script?

Amir

QuoteDoes the code ever pass under "else if (inv != null)" ? You may test that either by placing a breakpoint there or "Display" command with some message.

Good question. I tried Display command, nothing happened, the Display message didn't appear.

QuoteYou are running eModeUseinv interaction. Do you have event of that type ("use inventory item on") created for your items?
What is inside these event functions, are there more conditions? Can you post an example of your script?

Yes, most of them have "use inventory item on" I tried many items with each other with an event and it happens the same as in the video. I'm not just trying money with carrot  ;-D
An example for useing an inventory item with another item: honey with bread.

Code: ags

function iBrot_UseInv()
{
if (cJesus.ActiveInventory == iHonig)
{
  aBrotmithonig.Play(eAudioPriorityNormal, eOnce);
  Wait(80);
  cJesus.LoseInventory(iBrot);
  cJesus.LoseInventory(iHonig);
  cJesus.AddInventory(iBrotmithonig);
  
}  
else
{
     int i;
    i = Random(3);
    if (i == 0) cJesus.Say("Das ist eine bizarre, teuflische Idee."); 
    if (i == 1) cJesus.Say("Wahrlich, wahrlich, ich sage dir: Das geht nicht.");
    if (i == 2) cJesus.Say("Versuche das nicht, sonst landest du in der Hölle.");
    if (i == 3) cJesus.Say("Du sollst den Herrn, deinen Gott nicht versuchen. Das geht doch nicht.");  
}  
}


I think it's up to the module. something is still missing something like player.ActiveInventory = DragDropCommon._InvItem; I read through ur module, tried to understand it, I got half of it but I couldn't find out why the inventory items don't interact with other inventory items.

Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Crimson Wizard

Quote from: Amir on Mon 05/07/2021 19:40:31
QuoteDoes the code ever pass under "else if (inv != null)" ? You may test that either by placing a breakpoint there or "Display" command with some message.

Good question. I tried Display command, nothing happened, the Display message didn't appear.

So, inv is always null, or condition does not work.
The question is why your script does not detect an inventory item at the place of the drop.
Maybe the detection is not correct. Or there's some extra code that prevents this to work.



I made a quick test with the existing Demo game, and added few lines in the 4th room script:
Code: ags

  else if (DragDrop.EvtWantDrop)
  {
    InventoryItem* item = InventoryItem.GetAtScreenXY(mouse.x, mouse.y); // <-------------
    if (item != null) // <-----------------------------------------------------------------------------
      Display("item under: %s",item.Name); // <-------------------------------------------------

    InvWindow* drop_to = GetInvWindowUnderObject(o_x, o_y, o_w, o_h);
    if (drop_to != null && ItemOrigin != null && drop_to != ItemOrigin)
    {
      ItemOrigin.CharacterToUse.LoseInventory(DragDropCommon._InvItem);
      drop_to.CharacterToUse.AddInventory(DragDropCommon._InvItem);
    }
  }


This displays inventory item's name under the mouse cursor every time you drop something on it.

Crimson Wizard

Hmm, I have got one idea.

Try changing the order of tests. Test inventory item first, then everything else:

Code: ags

  if (inv != null) 
  {
    inv.RunInteraction(eModeUseinv);
  }
  else if ((chara != null) || (obj != null) || (hot != null))
  {
   ProcessClick(mouse.x, mouse.y, eModeUseinv);
  }



EDIT Also I've just realized that the hotspot test is wrong. You should not compare hot with null, because Hotspot.GetAtScreenXY always returns something.
You got to compare it with hotspot[0], which is "no hotspot"/eraser:
Code: ags

  else if ((chara != null) || (obj != null) || (hot != hotspot[0]))

Amir

It's a good thing that I refreshed here and saw your edit. I almost wanted to try something complicated. Now it works  (laugh) ur right about hot != null, I have often read it here in the forum but forgot it. Such a little thing can cause disaster like a butterfly effect.

There are a few problems but it has nothing to do with the module. I think I can solve them on my own or I would create a new thread. the biggest problem would be the Android port but it doesn't matter if it doesn't work. Programming with AGS is fun.

Thank u so much for ur patience and help.
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Amir

Sorry for bothering again. I'm trying something but it dosn't work. I want the selected inventory item to disappear after the interaction or dropping, both in the inventory with inventory items and outside with objects.

I used if (DragDrop.EvtDragStarted) player.ActiveInventory = null; so that it's not chosen twice like in the video. This works fine.

in repeatedly execute
Code: ags

if ((DragDrop.EvtDragStarted) || (DragDrop.EvtDropped))
  {
    player.ActiveInventory = null;
  }


or alone

Code: ags

if (DragDrop.EvtDropped)
  {
   player.ActiveInventory = null;   
  } 


The inventory item doesn't go away.

Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Crimson Wizard

Quote from: Amir on Mon 05/07/2021 23:48:47
I want the selected inventory item to disappear after the interaction or dropping, both in the inventory with inventory items and outside with objects

When you say "dissapear" do you mean dissapear from cursor, or dissapear from player's inventory?

Amir

Quote from: Crimson Wizard on Tue 06/07/2021 00:33:50
Quote from: Amir on Mon 05/07/2021 23:48:47
I want the selected inventory item to disappear after the interaction or dropping, both in the inventory with inventory items and outside with objects

When you say "dissapear" do you mean dissapear from cursor, or dissapear from player's inventory?

From cursor  ;-D
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.


Amir

Quote from: Crimson Wizard on Tue 06/07/2021 12:33:27
I cannot tell without seeing full code of rep exec.

Ok.

Code: ags


Hotspot* prevH;

function repeatedly_execute() 
{  
  
 int x = mouse.x -280;
 int y = mouse.y -115; 
  InventoryItem*ii = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
  Label*lbl = gGui1.Controls[0].AsLabel;
  String text;
  if (ii) text = ii.Name;
  else text = Game.GetLocationName(mouse.x, mouse.y);
  
 gGui1.SetPosition(x, y);  // name over verbcoins
  

 
Character *chara = Character.GetAtScreenXY(mouse.x, mouse.y);
Object *obj = Object.GetAtScreenXY(mouse.x, mouse.y);
Hotspot *hot = Hotspot.GetAtScreenXY(mouse.x, mouse.y);
InventoryItem *inv = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);

if (DragDrop.EvtWantDrop)
{

  cJesus.ActiveInventory = DragDropCommon._InvItem;
  
  if ((chara != null) || (obj != null) || (hot != hotspot[0]))
  {
   ProcessClick(mouse.x, mouse.y, eModeUseinv);

  }
  
    else if (inv != null) 
  {
    
    inv.RunInteraction(eModeUseinv);
    
  }
}
 

else if (DragDrop.EvtDragStarted) // || (DragDrop.EvtDropped))
  {
    player.ActiveInventory = null;
  }
 
 /*
else
{
player.ActiveInventory = null;  // it works but not a good idea coz the name of objects over the verbcoins doesn't appear any more
}
*/





/////////// Pfeile an Hotspots


Hotspot* currentH = Hotspot.GetAtScreenXY(mouse.x, mouse.y);
if (currentH != prevH) {
int pfeil = currentH.GetProperty("Pfeil");
if (pfeil == 1)
{
mouse.ChangeModeGraphic(eModeWalkto, 236);  
mouse.ChangeModeView(eModeWalkto, 24);
cJesus.Clickable = false;
}  
if (pfeil == 2)
{
mouse.ChangeModeGraphic(eModeWalkto, 232);  
mouse.ChangeModeView(eModeWalkto, 23);  
cJesus.Clickable = false;
}  
if (pfeil == 3)
{
mouse.ChangeModeGraphic(eModeWalkto, 240);  
mouse.ChangeModeView(eModeWalkto, 25); 
cJesus.Clickable = false;
}
if (pfeil == 4)
{
mouse.ChangeModeGraphic(eModeWalkto, 228);  
mouse.ChangeModeView(eModeWalkto, 22);
cJesus.Clickable = false;
}

if (pfeil == 0 || currentH.ID == 0) 
{

mouse.ChangeModeGraphic(eModeWalkto, 217);
mouse.ChangeModeView(eModeWalkto, 21);
cJesus.Clickable = true;
} 
if ((gMainmenu2.Transparency == 0) && (pfeil == currentH.GetProperty("Pfeil")))
{
mouse.ChangeModeGraphic(eModeWalkto, 217);
}  

}
prevH = currentH;

}   


Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Amir

It works there.

Code: ags

function repeatedly_execute_always() 
{   
if (DragDrop.EvtDropped)
{
  player.ActiveInventory = null;
}

}


But I don't know if this is its right place.
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Crimson Wizard

Amir, sorry for not responding earlier.

I don't think the repeatedly_execute_always is a "wrong" place, with that it may work all the time regardless of other things you do in rep-exec.

Looking at the big repeatedly_execute() function, my first thought is that you could place it under the "if (DragDrop.EvtWantDrop)" section, after calling all the ProcessClick/RunInteraction:
Code: ags

if (DragDrop.EvtWantDrop)
{
  cJesus.ActiveInventory = DragDropCommon._InvItem;

  if ((chara != null) || (obj != null) || (hot != hotspot[0]))
  {
   ProcessClick(mouse.x, mouse.y, eModeUseinv); 
  }  
  else if (inv != null) 
  {
    inv.RunInteraction(eModeUseinv);
  }

  cJesus.ActiveInventory = null; // <---------------------
}


But maybe you tried that already and it did not work?

Amir

Thanks for ur returning and answer. I thought you gave up  ;-D

I think I've tried this before because what's happening with this method has happened to me before, and what's happening is that it's wrong interaction again. It goes in the function directly to ELSE again and ignores IF and ELSE IF. Our example: Bread with honey, Jesus says: it doesn't work, instead of combining them together.

QuoteI don't think the repeatedly_execute_always is a "wrong" place, with that it may work all the time regardless of other things you do in rep-exec.

Okay. I will leave it there then. It doesn't cause any problems so far. I think that is the only solution. I don't know why but that is what it looks like.
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Amir

There is also a problem that I didn't notice before. The inventory items interact with themselves (laugh) especially if you click on it once. I can't find where to check if an inventory item is on itself so that nothing happens.

I have this solution:

Code: ags

function ihoney_UseInv()
{
if (cJesus.ActiveInventory == ihoney)
{
 // do nothing  
}
}


But I have 60 inventory items. Do you have a quicker solution?
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Crimson Wizard

Quote from: Amir on Sun 11/07/2021 17:07:28
There is also a problem that I didn't notice before. The inventory items interact with themselves (laugh) especially if you click on it once. I can't find where to check if an inventory item is on itself so that nothing happens.

Ah right, so, you have this code above, under condition "if (DragDrop.EvtWantDrop)":
Code: ags

  else if (inv != null) 
  {
    inv.RunInteraction(eModeUseinv);
  }

so you could probably also test
Code: ags

  else if (inv != null && inv != cJesus.ActiveInventory) 
  {
    inv.RunInteraction(eModeUseinv);
  }

Amir

Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Amir

The module works as in the video with AGS engine Android port (the app). Not quite drag and drop ;-D  by pressing and holding an inventory item, but I like it that way. It's practical too. I made the mouse cursor transparent so that it looks like it does on smartphones or iPads.



Quote from: eri0o on Thu 01/07/2021 19:22:32
WoaM and Kathy Rain use a different code that works with the old android port - I actually have the script code because I asked by mail the dev, but I think you should just ask them yourself. If you want to use this module and use the same behavior for mouse and fingers, you need to use the Android SDL Port.

I have a little game that uses this module too here: https://github.com/ericoporto/dungeonhands

It has touch on the webport, but I don't know how well it runs on old devices. :/

What do you mean exactly by Android SDL Port? Do you mean by creating an APK with monkeys plugin or your way with Android Studio? I wanted to try that anyway.
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Crimson Wizard

Updated DragDropCommon module to 1.0.1, fixing default settings, to avoid people stumbling into a missing GUI crash if they forgot to explicitly set a drag mode.

Amir

Quote from: Crimson Wizard on Sun 18/07/2021 22:11:28
Updated DragDropCommon module to 1.0.1, fixing default settings, to avoid people stumbling into a missing GUI crash if they forgot to explicitly set a drag mode.

Thank u.
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

deadsuperhero

This is an amazing module, but I'm absolutely confused by the examples and the reference. Please do not take my following comments as hostile or critical - I have nothing but praise for what you're doing. What's confusing for me is this: the module does a fabulous job when the automation is turned on...but I'm having a very hard time grasping how to do the behavior without automation.

In a nutshell, what I'm trying to do is make draggable GUIs to create a fake desktop. However, I only want to target a specific handful of game GUIs, not all of them. If I have DragDrop.AutoTrackHookKey set to true in my script, every game GUI is draggable in the way that I expect...except, this works with every GUI in the game, not just some of them.

I've tried to follow the examples and use a little scripting to get it to work, but I'm stuck. Here's what I've managed to do so far:

Global Script:
Code: ags


function dragWindow(GUI* Window) { // This is wrong
  if (DragDrop.HookKeyDown()){
    DragDrop.HookObject(1, mouse.x, mouse.y, Window.ID);
  }
  else if (DragDrop.HookKeyUp())
    DragDrop.Drop();{
  }
}


function checkGUI() // running under repeatedly_execute_always{
  if (GUI.GetAtScreenXY(mouse.x, mouse.y)) {
    hoverOver = GUI.GetAtScreenXY(mouse.x, mouse.y);
      if ((hoverOver == gConfirmation)) {
        dragWindow(hoverOver);
      }
  }
  else {
    hoverOver = null;
  }
}



function game_start()
{
  Mouse.Mode = eModePointer;
  DragDrop.Enabled = true;
  DragDropCommon.ModeEnabled[eDragDropGUI] = true;
  DragDropCommon.DragMove = eDDCmnMoveSelf;
  DragDrop.AutoTrackHookKey = false;
  DragDrop.DefaultHookKey = 0;
  DragDrop.DefaultHookMouseButton = eMouseLeft;
  DragDrop.DragMinDistance = 10;
  DragDrop.DragMinTime = 0;
}




I've tried a few different variations for my dragGUI function. If I include the DragDrop.Drop() call, dragging doesn't work at all. If I omit it, the window instead just sticks to my cursor the minute I hover over it.
I've tried going over your code examples and post a couple of times, but I'm feeling pretty lost. What's the proper order of operations for hooking a GUI, dragging it, and dropping it?


I guess what's also confusing involves figuring out how to register when the player is holding down the mouse button and dragging the mouse. Is HookKeyDown supposed to be called from within on_mouse_click / on_key_press and nowhere else?
The fediverse needs great indie game developers! Find me there!

deadsuperhero

I ended up doing a dirty hack for the time being, but I hope to sit down and adapt it properly at some point. :)

Code: ags

function checkGUI() {
  if (GUI.GetAtScreenXY(mouse.x, mouse.y)) {
    hoverOver = GUI.GetAtScreenXY(mouse.x, mouse.y);
      if ((hoverOver == gExplorer)) {
        DragDrop.AutoTrackHookKey = true;
      }
      else if ((hoverOver == gDetails)) {
        DragDrop.AutoTrackHookKey = true;
      }
      else if ((hoverOver == gResume)) {
        DragDrop.AutoTrackHookKey = true;
      }
      else if ((hoverOver == gConfirmation)) {
       DragDrop.AutoTrackHookKey = true;
      }
      else if ((hoverOver == gDropdown)) {
       DragDrop.AutoTrackHookKey = false;
      }
      else if ((hoverOver == gMainMenu)) {
       DragDrop.AutoTrackHookKey = false;
      }
  }
  else {
    hoverOver = null;
    DragDrop.AutoTrackHookKey = false;
  }
}


Hacky, but it works for now.
The fediverse needs great indie game developers! Find me there!

Crimson Wizard

I'm sorry, I did not have time to look into this yet, and I definitely should have written a better documentation.

Quote from: deadsuperhero on Fri 07/01/2022 22:16:37
I ended up doing a dirty hack for the time being, but I hope to sit down and adapt it properly at some point. :)

Just as a note, you may use switch for simplier code:
Code: ags

switch (hoverOver)
{
case gDetails:
case gResume:
// etc
    DragDrop.AutoTrackHookKey = true;
    break;
default:
    DragDrop.AutoTrackHookKey = false;
    break;
}

deadsuperhero

Quote from: Crimson Wizard on Sat 08/01/2022 06:46:31
I'm sorry, I did not have time to look into this yet, and I definitely should have written a better documentation.
Hey, it's totally okay - again, I appreciate what you've made, and am getting great use out of it!

That switch example is nice - I didn't even know about those!
The fediverse needs great indie game developers! Find me there!

Crimson Wizard

Updated DragDrop & DragDropCommon modules to 1.1.0

* Introduced DragDrop.EvtCancelled attribute, telling that the action was cancelled and object "unhooked" even before the dragging itself started.
* Consequently, fixed a mistake in DragDropCommon when it did not reset some public attributes when the drag was cancelled.


PS. I still have to write a better documentation and examples...

PPS. Started rewriting module docs, I also found a number of logical mistakes in the module, so likely there will be 1.2 update after this...

Mehrdad

Thanks for update

In the game, I haven't items (objects) in room 3.
My official site: http://www.pershaland.com/


Mehrdad

Quote from: Crimson Wizard on Tue 12/07/2022 12:57:02
Quote from: Mehrdad on Tue 12/07/2022 12:08:06
In the game, I haven't items (objects) in room 3.

Sorry, what do you mean by this?

Room 3 is empty and doesn't have any items for drag
My official site: http://www.pershaland.com/

Crimson Wizard

Quote from: Mehrdad on Tue 12/07/2022 14:42:49
Room 3 is empty and doesn't have any items for drag

Are you talking about Demo Game? I don't observe this problem. Please tell, where did you download the game, and which version of AGS are you using to open it?
Does anyone else have same issue?

Mehrdad

Quote from: Crimson Wizard on Wed 13/07/2022 18:07:23
Quote from: Mehrdad on Tue 12/07/2022 14:42:49
Room 3 is empty and doesn't have any items for drag

Are you talking about Demo Game? I don't observe this problem. Please tell, where did you download the game, and which version of AGS are you using to open it?
Does anyone else have same issue?


Yes, Demo Game. I hadn't problem with previous versions. It happens for me in 1.1.0
I use 3.6 last version.
My official site: http://www.pershaland.com/

Crimson Wizard

Quote from: Mehrdad on Thu 14/07/2022 06:00:37
Yes, Demo Game. I hadn't problem with previous versions. It happens for me in 1.1.0
I use 3.6 last version.

So what happens, you download the demo game, open the game in the editor, go to room 3, switch to display room objects, and there are none? And when you run the game, there are also none?

Mehrdad

Quote from: Crimson Wizard on Thu 14/07/2022 07:31:47
Quote from: Mehrdad on Thu 14/07/2022 06:00:37
Yes, Demo Game. I hadn't problem with previous versions. It happens for me in 1.1.0
I use 3.6 last version.

So what happens, you download the demo game, open the game in the editor, go to room 3, switch to display room objects, and there are none? And when you run the game, there are also none?

Both. editor and run game. All images point to sprite 0. I could fix it manually and replace image 0 with other sprites.


My official site: http://www.pershaland.com/

Crimson Wizard

Quote from: Mehrdad on Thu 14/07/2022 13:01:38
Both. editor and run game. All images point to sprite 0. I could fix it manually and replace image 0 with other sprites.

Do I understand correctly, that objects themselves exist, but they lost their sprites?
Do you get any errors or other messages when opening the game in the editor? Which sprites are present in the sprite manager?

EDIT: alright, I finally reproduced this, if I save & rebuild whole game without opening a room first.
It appears that the game contains mistakes, where objects reference sprites which are no longer present in the sprite manager, but somehow remained present in the sprite file. The newer version of AGS 3.6.0 detects such case and cleans the sprite file.


Mehrdad

My official site: http://www.pershaland.com/

Crimson Wizard

NOTE: I reuploaded demo once more, fixing another problem that caused incorrect drawing colors in room 2.

Mehrdad

Quote from: Crimson Wizard on Thu 14/07/2022 16:00:35
NOTE: I reuploaded demo once more, fixing another problem that caused incorrect drawing colors in room 2.

The demo Game link is broken.
My official site: http://www.pershaland.com/


Crimson Wizard

Full rewritten documentation for this module is now available here:
https://github.com/ivan-mogilko/ags-script-modules/wiki/Drag-&-Drop-module

I tried to explain things in more simple words where possible, and give more practical script examples to illustrate the concepts.
Still might add more real use examples later.

vga256

Hi CW. This module has become one of the most important modules I'm using for an art project that has a fake macintosh-style OS.

I'm running 1.1.0 and I'm wondering if the limitation "eDDCmnMoveGhostGUI - drags supplied custom GUI with object's image on it (currently does not work for GUI and Controls, but this is ONLY way to make inventory items drag & drop)" can be overcome?

I've got a situation where I want to simulate dragging a GUIControl from one GUI to another. The GUIcontrol does not have to actually move from one GUI to another, I just need it to *appear* that way (e.g. show a graphic that follows the mouse cursor to its drop point). The usage scenario is dragging an icon from Window A (a remote FTP, gFTP) to Window B (a local hard drive, gHardDrive).

Currently, the DragDropCommon module allows me to drag a GUIControl, but the control is only moved within its parent GUI... it cannot move beyond the boundaries of the parent GUI. After spending a few hours reading through the DDC module, it appears that the eDDCmnMoveGhostGUI setting is ignored for GUIs and GUIControls.

And yet, according to the documentation, "GhostGUI" mode works with everything, and is the only way to drag Inventory Items. You must provide a GUI though, by setting DragDropCommon.GhostGUI. GhostGUI also uses GhostTransparency property.

Is this just an inconsistency between the documentation and the module code? Is there a conceptual workaround that would allow me to simulate dragging and dropping (via a GhostGUI) a GUIControl from one GUI to another?

Thanks for your help and the great module!

Crimson Wizard

@vga256,

The documentation appears to be wrong where it sais that "Ghost GUI" works with everything.

The reason why "Ghost GUI" does not work for GUI & controls is quite simple. With "Ghost" GUI/Overlay the module must draw the dragged object on that GUI/Overlay. With characters and objects this is straightforward: you draw their current sprite (or animation frame). But with GUI it's not easy: there's no way to ask AGS to draw a GUI or control on a drawing surface or a dynamic sprite, so I would have to reimplement virtually whole GUI drawing in script! Naturally, I decided to not do that.

One may speculate that this could be worked around using a screenshot feature, but this approach will be additionally complicated by other screen elements which would have to be hidden (and that's not reliably possible to script in the module, I think).

Another workaround would be to only support controls which are drawn using sprites:
* Empty GUIs with background image and nothing else;
* Buttons which have a graphic assigned to them.

With the current module though, you would have to resort to scripting a custom drag-drop mode. The easiest method may be to replicate "Ghost GUI" or "Ghost Overlay", but let it set any image instead of knowing what AGS object you're dragging. You may follow examples in documentation, or use either demo game or DragDropCommon module as an example.

vga256

Quote from: Crimson Wizard on Fri 23/12/2022 23:00:05@vga256,
Another workaround would be to only support controls which are drawn using sprites:
* Empty GUIs with background image and nothing else;
* Buttons which have a graphic assigned to them.

With the current module though, you would have to resort to scripting a custom drag-drop mode. The easiest method may be to replicate "Ghost GUI" or "Ghost Overlay", but let it set any image instead of knowing what AGS object you're dragging. You may follow examples in documentation, or use either demo game or DragDropCommon module as an example.

Thanks for the explanation - that all makes sense. Since I am specifically only trying to drag and drop buttons (with assigned graphics), I will go that route and try to come up with custom drag mode based on GhostGUI.

I'll provide an update here when I come up with something workable.

vga256

Update: I added a few lines that allow for a Button to be draggable using the GhostGUI/Overlay:

Code: ags
//===========================================================================
//
// DragDropCommon::TryHookGUIControl()
//
//===========================================================================
static bool DragDropCommon::TryHookGUIControl()
{
  if (!DragDrop.EvtWantObject)
    return false;
  GUIControl *gc;
  // TODO: pixel perfect detection
  gc = GUIControl.GetAtScreenXY(DragDrop.DragStartX, DragDrop.DragStartY);
  if (gc == null)
    return false;
  if (DDSet.TestClickable && !gc.Clickable)
    return false;
  DDState._GUIControl = gc;
  DragDrop.HookObject(eDragDropGUIControl, gc.X, gc.Y);
  // Allow for GhostGUI/GhostOverlay when dealing with GUIControls that 
  // are buttons
  if (DDSet.Move != eDDCmnMoveSelf)
  {
    if (gc.AsButton != null)
    {
      int sprite = gc.AsButton.Graphic;
      DDState.CreateRepresentation(DDSet.Move, gc.X, gc.Y, gc.OwningGUI.X, gc.OwningGUI.Y, sprite,
                                   DDSet.GhostTransparency, DDSet.GhostAlpha);                                   
    }

  }
  return true;
}

For anyone interested in using this code to make buttons draggable via ghostguis/overlays: of note are the offsets "gc.OwningGUI.X" and "gc.OwningGUI.Y" - control positions are always relative to their parent GUI. So I've used the parent GUI's current position as the offset, to ensure that the overlay is created at the right spot.

Crimson Wizard

Updated DragDrop & DragDropCommon modules to 1.2.0

* Added DragDropCommon.GhostZOrder attribute, letting you define which ZOrder to use in GUI and Overlay representation mode.
* Added DragDropCommon.GhostOverlay readonly attribute for accessing active "ghost overlay" (in respective drag mode).
* For AGS 3.6.0 and higher, "ghost overlay" representation now will use ZOrder setting, which makes this mode usable for dragging inventory items, because overlay will be able to stay above guis.
* Updated Demo Game, made it compile in newer versions of AGS without problems.

Download links:
DragDrop 1.2.0
DragDropCommon 1.2.0
Demo game 1.2.0

SMF spam blocked by CleanTalk