Drop inventory items in empty space and switch items?

Started by tilapisha, Fri 10/03/2023 17:35:05

Previous topic - Next topic

tilapisha

I would like to make the activeInventory = null when the player clicks on an empty space in the inventory GUI and have the activeInventory switch with what inventory they click on.

I assume in this function, I would have to find if the player activeInventory != null, then check where the cursor is. If in an empty space, activeInventory = null. If the cursor is on an item, then activeInventory = item, and the item gets added to inventory. Something like this:

Code: ags
function gIconbar_onClick(GUI *theGui, MouseButton button){
    if(player.ActiveInventory != null{
         if(InventoryItem.GetAtScreenXY(mouse.x,mouse.y) = null {
          inventory.AddActiveInventory
          player.ActiveInventory = null;
       } else {
       player.ActiveInventory = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
     }
   }
}




There's also this that is helpful, but I'm having a little of trouble interpreting it.
https://www.adventuregamestudio.co.uk/forums/advanced-technical-forum/putting-active-inventory-back-into-inventory-problems-solved/msg636473542/#msg636473542


eri0o

Uhm, I think you can do this simply by using

Code: ags
function gInventoryBar_OnClick(GUI *theGui, MouseButton button)
{
  player.ActiveInventory = null;
}

This is because, if something is on top of the gui that is clickable, it will run it's action instead of propagating the click to whatever is below.

I am going to comment the code you wrote, just to try to explain it - but I believe you should just use the code above.

Code: ags
// this is the OnClick event of the gIconbar GUI, it's on it's ⚡ event properties in the Editor
function gIconbar_onClick(GUI *theGui, MouseButton button){
    // the player has some item selected, so in the next block, we know this
    if(player.ActiveInventory != null{
        // There is no inventory item under the mouse (we use == for equality check)
        if(InventoryItem.GetAtScreenXY(mouse.x,mouse.y) == null {
          // I don't know what it was the idea in this code, so I am commenting it out of actions
          // inventory.AddActiveInventory
          // we set so there is no active item anymore, what was on player hand is back at the bag
          player.ActiveInventory = null;
      } else {
      // in case there was an inventory item below the mouse, we assign it as the active item for the player
      player.ActiveInventory = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
    }
  }
}

tilapisha

Hmm, this didnt work. I think its being called in the wrong function. I tried moving it, but still no results.

Code: ags
function btnIconCurInv_Click(GUIControl *control, MouseButton button)
{
  //if (player.ActiveInventory != null)
  //{
  // mouse.Mode = eModeUseinv;
  //} 
  
  if(cGoby.ActiveInventory != null){
  if(InventoryItem.GetAtScreenXY(mouse.x,  mouse.y) == null){
    cGoby.ActiveInventory = null;
      // switch to the interact cursor
      mouse.Mode = eModeInteract;
      // ...but override the appearance to look like the arrow
      mouse.UseModeGraphic(eModePointer);
    } else {
      cGoby.ActiveInventory = InventoryItem.GetAtScreenXY(mouse.x,  mouse.y);
        mouse.Mode = eModeUseinv;
      }
  }
}

eri0o

When you say drop inventory items in empty space, do you mean something like, an inventory where you can place items in any specific place?

Because previously I understood as just not having the item as active, meaning, the cursor returns to normal.

tilapisha

I mean, if you click on an empty space within the inventory GUI, and you have an activeInventory item, it goes back into your inventory and your cursor mode is now interact instead of useInventory. Additionally, if you click on another inventory item, your current activeInventory goes back in your inventory, and your activeInventory now becomes what you clicked on.

Khris

Detecting a click on an empty part of an InvWindow should work like this:

Code: ags
MouseButton button;

function on_event(EventType event, int data) {
  
  if ((event == eEventGUIMouseDown || eEventGUIMouseUp) && data == gInventoryBar.ID) {
    if (event == eEventGUIMouseDown) {
      for (int i = eMouseLeft; i <= eMouseMiddle; i++) if (Mouse.IsButtonDown(i)) button = i;
    }

    if (event == eEventGUIMouseUp && button == eMouseLeft) {
      int mx = mouse.x, my = mouse.y;
      GUIControl *gc = GUIControl.GetAtScreenXY(mx, my);
      if (gc == null) return;
      InvWindow* iw = gc.AsInvWindow;
      if (iw == null) return;
      InventoryItem* ii = InventoryItem.GetAtScreenXY(mx, my);
      if (ii == null) {
        // player clicked on empty part of inv window
        player.ActiveInventory = null;
      }
    }
  }
}


Khris



tilapisha

I took out your code and replaced it back with mine to try and problem solve. I think the issue is it's not receiving the click. Currently, when I click on the hand button, it does what I want it to do when it clicks on an empty space. So, I'm trying to figure out where that is, but I can't seem to locate it.


Code: ags
function btnInvSelect_Click(GUIControl *control, MouseButton button)
{
  // switch to the interact cursor
  mouse.Mode = eModeInteract;
  // ...but override the appearance to look like the arrow
  mouse.UseModeGraphic(eModePointer);
  
  if (player.ActiveInventory != null){
      mouse.Mode = eModeUseinv;
    if(InventoryItem.GetAtScreenXY(mouse.x, mouse.y) == null){
      player.ActiveInventory = null;
      }
    else {
      player.ActiveInventory = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
      mouse.Mode = eModeUseinv;
      }
  }
}


function btnIconCurInv_Click(GUIControl *control, MouseButton button)
{
  if (player.ActiveInventory != null){
      mouse.Mode = eModeUseinv;
    
    //if(InventoryItem.GetAtScreenXY(mouse.x, mouse.y) == null){
      //player.ActiveInventory = null;
      //}
    //else {
      //player.ActiveInventory = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
      //mouse.Mode = eModeUseinv;
      //}
  //}
 
}

tilapisha

I am trying to allow the player to drop the current active inventory item by clicking on an empty space within the Inventory bar and to swap the current active inventory item by clicking on an inventory item in the Inventory bar.

I've worked out the code to do this, but I believe it isn't being called in the correct location.I originally placed it in the gIconbar_onClick function but it didn't work. I think this should only work in the inventoryWindow, which is in the GUI template, but doesn't have an events properties panel.

Code: ags
     //on click, if the mouse is not over an inventory item
    if(InventoryItem.GetAtScreenXY(mouse.x, mouse.y) == null){
      //drop the current inventory item
      player.ActiveInventory = null;
      }
    else
      //change the active inventory to item in which the mouse is over
      player.ActiveInventory = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
      mouse.Mode = eModeUseinv;
      }
  }

Snarky

#11
I still think eri0o's first suggestion was basically correct. (I'm not sure I understand what Khris is doing, but it seems more complicated than necessary.) However, it could be affected by the project setting "Handle inventory clicks in script": if that is set to true, I think you might have to deal with it in on_mouse_click()?

I am also puzzled by your latest attempts. Going by the function names and other contents, they handle clicking on buttons on the inventory GUI for setting the cursor mode. Why would you put this code there? It needs to go in a function to handle clicking on the Inventory Window control.

Edit: Oh, I see, you couldn't find a way to add an event handler for that. It may not have an event to hook up. In that case, you do have to do it in on_mouse_click():

Code: ags
// called when a mouse button is clicked
function on_mouse_click(MouseButton button)
{
  // called when a mouse button is clicked. button is either LEFT or RIGHT
  if (IsGamePaused())
  {
    // game is paused, so do nothing (i.e. don't process mouse clicks)
  }
  else if(GUIControl.GetAtScreenXY(mouse.x, mouse.y) == invCustom) // Put the name of your Inventory Window here
  {
    if(InventoryItem.GetAtScreenXY(mouse.x, mouse.y) == null)
    {
      //drop the current inventory item
      player.ActiveInventory = null;
    }
    else
    {
      //change the active inventory to item in which the mouse is over
      player.ActiveInventory = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
      mouse.Mode = eModeUseinv;
    }
  }
  else if (button == eMouseLeft)
  {
    // left-click, so try using the current mouse cursor mode at this position
    Room.ProcessClick(mouse.x, mouse.y, mouse.Mode );
  }
  else if (button == eMouseRight)
  {
    // middle-click makes the character walk to clicked area, regardless of cursor mode
    Room.ProcessClick(mouse.x, mouse.y, eModeWalkto);
  }
}

Crimson Wizard

#12
Quote from: Snarky on Mon 13/03/2023 14:19:46Edit: Oh, I see, you couldn't find a way to add an event handler for that. It may not have an event to hook up. In that case, you do have to do it in on_mouse_click():

@Snarky, on_mouse_click is not called when you click on GUI. eMouseLeftInv/RightInv are only passed when you click on items themselves (in case "override inventory clicks in script" is true), but not on empty space in inventory window.

This is why there has to be these "hacks" with on_event, as in Khris's code.

Snarky

Fair enough, but wouldn't it still be easier to use the OnClick event of the GUI itself?

Code: ags
function gInventoryBar_OnClick(GUI *theGui, MouseButton button)
{
  if(GUIControl.GetAtScreenXY(mouse.x, mouse.y) == invCustom)
  {
    // Do stuff
  }
}

No, dammit. I see that doesn't work either: the GUI doesn't get the event when you click on the Inventory Window. OK, so Khris was right. Seems to be the only way to trigger when clicking on the empty part of an inventory window.

(Incidentally, this part of AGS click handling is insane.)

Crimson Wizard

Quote from: Snarky on Mon 13/03/2023 15:17:58Fair enough, but wouldn't it still be easier to use the OnClick event of the GUI itself?

GUI's On Click event is not triggered when you click on controls.

I don't know which "empty space" is OP referring to, but in case it's an empty space inside the InventoryWindow control, only on_event will work.

Matti

Quote from: Crimson Wizard on Mon 13/03/2023 15:08:53on_mouse_click is not called when you click on GUI. eMouseLeftInv/RightInv are only passed when you click on items themselves (in case "override inventory clicks in script" is true), but not on empty space in inventory window.

Are you sure? I always considered the inventory handling in AGS a bit confusing, but I got this in my on_mouse_click function and it works perfectly fine. If I click on an empty space the current active inventory becomes null:

EDIT: Nevermind. This code does not run, i.e. the clicks aren't registered. In my game right-clicking in general removes the current item, so it seemed to work correctly.

Code: ags
  // right click on inventory
  else if (button == eMouseRightInv)
  { 
    // put item away
    if (player.ActiveInventory != null) { player.ActiveInventory = null; mouse.Mode = eModeInteract; }
    // look at item
    else inventory[game.inv_activated].RunInteraction(eModeLookat);
  }

Crimson Wizard

#16
Quote from: Matti on Mon 13/03/2023 21:22:02
Quote from: Crimson Wizard on Mon 13/03/2023 15:08:53on_mouse_click is not called when you click on GUI. eMouseLeftInv/RightInv are only passed when you click on items themselves (in case "override inventory clicks in script" is true), but not on empty space in inventory window.

Are you sure?


Frankly, I was not fully certain, so I had to test this right now. In my test game it is called when clicking on items, but not on empty space.

In our BASS template we have a "on_event" handler for right clicking over empty inv space, similar to what Khris suggested.

Given the above, I cannot explain how your code works, if you are definite that it works on empty spaces too. Can you double check that it actually works, and you don't have anything in on_event related to eEventGUIMouseDown? or perhaps in rep-exec?


EDIT: oh, I could swear we even had a ticket opened for this, and found it:
https://github.com/adventuregamestudio/ags/issues/472

Snarky

Matti, are you sure that is the code that is making it happen? There could be an on_event somewhere, perhaps in a module. Because I'm testing it, and indeed it does not seem like on_mouse_click() is getting called except over actual inventory items.

Khris

Matti, your code should cause an error / cause unwanted behavior if you right-click on an empty part without an active inventory item. Probably an array out of bounds error since game.inv_activated should be -1(?).

The fact that you never got an error seems to support that your code doesn't run when an empty part of the inv window is clicked (which is how AGS has always behaved, afaik).

Matti

You're absolutely right, sorry for the confusion!

In my game right-clicking in general removes the current item, so it seemed to work correctly with the inventory too, but as you said, clicks on empty spaces in the inventory aren't actually registered.

SMF spam blocked by CleanTalk