Kehom / GodotAddonPack

A collection of pure GDScript addons for Godot
http://kehomsforge.com
MIT License
183 stars 15 forks source link

[Inventory] - Need assistance with manipulating mouse for manual drag & drop operations. #40

Open KometFox opened 2 years ago

KometFox commented 2 years ago

I have written a crude script for a manual drag & drop operation and I managed so far to access the currently held Item of the cursor but right now I'm stuck with my implementation. The reason I want to do the manual drag & drop operation is that I want to implement a S.T.A.L.K.E.R like shop system which your addon almost provides everything for it, the shop system in the before mentioned game has 4 elements where items appear under certain conditions.

With this call I can get the "drag" operation going:

{InventoryNode}.pick_item_from(Column, Row, -1) 
ItemDragged = InvEvent

Then with the following call I get a stack overflow (1024) error which it seems the add_item() part gets stuck in a loop and gets called multiple times yet when I do a basic print() call then the print() function only gets called once per mouse click which is odd.

    match (event.get_class()):
        "InputEventMouseButton":
            #Drop the item.
            if Input.is_action_just_pressed("mouse_left") && ItemDragged:

                if Bag._shared_data.is_dragging():
#                   print(ItemDragged.get("item_data"))
#                   var NewItem = ItemDragged.get("item_data")
#                   emit_signal("Self_AddItem", NewItem)
#                   print("True:", Bag)
                    pass

I did read your blog documentation page but I couldn't see a signal function or anything similar which lets me retrieve and manipulate the mouse during the "dragging" part so that it behaves almost same as if the Inventory mouse setting is not in "none" mode. I apologize in advance if I have missed something.

InventoryManager_DragnDrop.txt

Kehom commented 2 years ago

Hello,

I have never player S.T.A.L.K.E.R so I have no idea how its inventory system works. Please explain a little bit of it. Perhaps the desired can be achieved with a few tweaks using the internal drag & drop system. If not, maybe I could work on something that would allow such use case?

Nevertheless, taking a quick look at your code, there are a few things I want to comment.

  1. Accessing _shared_data outside of the inventory system is not exactly intended. When the system gets ported to Godot 4 (as a GDExtension) it wont even be possible to access that property because I wont expose it. Yet, I believe the ItemDragged within the above if statement is enough to tell that something is being dragged, no?
  2. Prior to calling add_item(), check if the column and row within the IData. Are you attempting to drop the item at the first fitting slot within the bag?
  3. Once the item is "dropped" I think you can reset the ItemDragged property.

Just to make it clear, I don't think any of those remarks will solve what is going on, although 2 might point towards a solution.

KometFox commented 2 years ago

I have never player S.T.A.L.K.E.R so I have no idea how its inventory system works. Please explain a little bit of it. Perhaps the desired can be achieved with a few tweaks using the internal drag & drop system. If not, maybe I could work on something that would allow such use case?

In S.T.A.L.K.E.R. there are 4 windows when the player trades with somebody (a NPC or Trader), there is the trader inventory window and the player inventory visible and 2 other windows. The items from the trader window can only be dragged to the "Backpack" window which goes to the player inventory when purchased or back to the trader inventory if the player doesn't want to purchase it anymore, the items from the player goes only to the "Your Inventory" window for selling it and can only be put back to the player inventory, it cannot be directly dragged to the trader inventory. So basically it has a allow/block list sort of system going on to implement this trade window.

Accessing _shared_data outside of the inventory system is not exactly intended. When the system gets ported to Godot 4 (as a GDExtension) it wont even be possible to access that property because I wont expose it. Yet, I believe the ItemDragged within the above if statement is enough to tell that something is being dragged, no?

Well I couldn't figure out exactly which nodes I have to call to find if the mouse is dragging a item or not before doing additional function calls, but yes right now I could use that unofficial method to add a boolean check if something is being dragged or not. I found out this part by looking at the KehUI node while the game was running and I noticed that there is a Node2D node and a Control node being added/removed which I tried to access it.

Prior to calling add_item(), check if the column and row within the IData. Are you attempting to drop the item at the first fitting slot within the bag?

I tried to find a way to read which inventory row and column was being highlighted but I couldn't find anything that lets me do that. Dropping the item at the first free found slot is not the intended behavior if anything it should be placed at the cursor position when its free or when the occupied slot is a item and its of the same type of the item being dragged then adding to its stack count.

Once the item is "dropped" I think you can reset the ItemDragged property.

Is the ItemDragged property part of the Inventory node?

*Footnote: Screenshot is not mine, its taken from here https://yt.artemislena.eu/watch?v=HhgeJ9U94jE&list=PLWIol4T7LuSh_vMEKIKrp4y0Xa0SQuMiK&index=1 30-11-21-1638256697_scrot

Kehom commented 2 years ago

OK, let see if I understood this correctly before I attempt to find a solution to your case. The Your Items bag is where you put the items you want to sell. The Backpack is the bag where you put the items you want to buy. Is that right?

Is the ItemDragged property part of the Inventory node?

This variable is in your snippet! Within the Inv_ItemClicked() function you have

ItemDragged = InvEvent

Within the _input() function you have this

if Input.is_action_just_pressed("mouse_left") && ItemDragged:

In this case if ItemDragged is valid then something is being dragged.

KometFox commented 2 years ago

OK, let see if I understood this correctly before I attempt to find a solution to your case. The Your Items bag is where you put the items you want to sell. The Backpack is the bag where you put the items you want to buy. Is that right?

That is correct.

This variable is in your snippet! Within the Inv_ItemClicked() function you have

Sorry you are right, I must have confused it with another variable and I initially thought it was not part of my script.

Kehom commented 2 years ago

Ok. I will work on something that should allow this kind of behavior.

While reviewing things here I have noticed I completely forgot to provide means to manually drop an item that is "attached" to the mouse cursor.

Yet, there is a work around that you can use in the meantime. The idea is that you listen to both "item_picked" and "item_dropped" signals. When the item is picked, you use the highlight feature to disable all slots of the bag that should not allow the item to be dropped in there. Once the item is dropped (either in the correct trading bag or back into the originating one), you re-enable the slots that have been previously disabled.

To enable or disable the slot through the highlight system:

# Disables the slot at column and row
[bag_instance].set_slot_highlight(column, row, InventoryCore.HighlightType.Disabled)

# Enables the slot at column and row
[bag_instance].set_slot_highlight(column row, InventoryCore.HighlightType.None)

Make sure to enable the Disabled Slots Block Items within the project settings. Already placed items will not be removed from the disabled slots.