[Another small issue] Custom interactions menu not working with inventory items

Started by Lord Vetinari, Wed 29/11/2017 13:46:48

Previous topic - Next topic

Lord Vetinari

My game uses a custom interaction menu that you guys helped me code a while ago (thanks!)
It works perfectly fine for everything during normal gameplay, but it seems that there's something that prevents it to work or appear when used to interact with the inventory items. So far I handled the inventory via custom buttons in the inventory window itself, now I really want to consolidate the ways the player interacts with anything, plus I wanted to add some custom interactions to a couple of items, so I thought I could easily expand the interction menu's function to work with inventory items too just like I expanded it to work with objects and characters. Apparently I was wrong :P

This is the code for the interaction menu:

Code: ags

function on_mouse_click(MouseButton button)
{
  // called when a mouse button is clicked. button is either LEFT or RIGH
  
  if (IsGamePaused() == 1) {
    // Game is paused, so do nothing (ie. don't allow mouse click)
  }
  else if (button == eMouseLeft)  {
    //reset everything before a fresh start on a new interactive element
    gInteractionsMenu.Visible = false;
    ListInteractions.Clear();
    gInteractionsMenu.Height = 40;
    ListInteractions.Height = 0;
    
    if (Room.GetProperty("InteractionMenu_Available") == true) {
      //set the required variables
      int AreThereInteractions = 0;
      MouseActionX = mouse.x;
      MouseActionY = mouse.y;
      String CurrentOption;

      //these are pointers I properly created outside this function because I use them for a couple other stuff too
      activeHotspot = Hotspot.GetAtScreenXY(mouse.x, mouse.y);
      activeObject = Object.GetAtScreenXY(mouse.x, mouse.y);
      activeCharacter = Character.GetAtScreenXY (mouse.x, mouse.y);
      activeItem = InventoryItem.GetAtScreenXY (mouse.x, mouse.y);
      
      //Handling Inventory items
      if(activeItem != null) { //safety check: pointers can be "null", and if so you can't call methods on them
        ActionNumber = activeItem.GetProperty("Interaction_Number"); //Get the number of custom interactions thisobject/item/hotspot/character has
        int ActionCounter = 1;
        while (ActionNumber > 0) 
        {
          CurrentOption = String.Format("Action_%d", ActionCounter);
          ListInteractions.AddItem (String.Format("%s", activeItem.GetTextProperty(String.Format("%s", CurrentOption))));  
          gInteractionsMenu.Height += 26;
          ListInteractions.Height += 26;
          ActionNumber -=1;
          AreThereInteractions += 1;
          ActionCounter +=1;
        }
        if (AreThereInteractions > 0) {
          gInteractionsMenu.X = mouse.x;
          gInteractionsMenu.Y = mouse.y;
          ListInteractions.SelectedIndex = -1;
          lbMenuTitle.Text = String.Format("%s", activeItem.Name);
          gInteractionsMenu.Visible = true;
        }
      }

      // Repeat the same code with appropriate pointers for objects, characters and hotspots
      // They have an additional else clause at the end to handle character movement when you're not clicking on something interactable


As I said, it works perfectly during regular room browsing, but nothing happens when the inventory GUI is open.
I checked the z-order of the guis, in case it was drawn under the inventory screen. Nope, gInteractionMenu is set to appear on top of everything else.
I also made it so that the inventory menu didn't pause the game even though it leads to some undesirable behaviour if you click outside the GUI (By the way, any suggestion on how to handle that in case I have to keep it this way?), and of course I also made sure that the inventory item I was clicking on had the proper custom properties correctly set. Still nothing.

Help, please?

Khris

AGS only calls on_mouse_click(eMouseLeft) when you left-click the room; if you want do manually handle clicks on inventory items, you have to
a) turn on the respective option in General Settings / Inventory (Override built-in ...)
b) add code for (button == eMouseLeftInv)

Lord Vetinari

#2
Oh thank God, I feared I had some major rewrite to do.

Thank you, now it works perfectly!

EDIT: actually, I was a bit too hasty, there's a tiny annoying bug. If you select an option and therefore process an interaction, the menu disappears correctly. If you instead click somewhere else that is not another item (say, the arrow buttons to scroll the inventory up and down), the menu stays visible despite the gInteractionsMenu.Visible = false; that I put right after the button check to be sure that it hides any currently existing menu. Any idea why?
The code now looks like this:

Code: ags

function on_mouse_click(MouseButton button)
{
  if (button == eMouseLeftInv) {
    // reset everything to start from scratch
    gInteractionsMenu.Visible = false;
    ListInteractions.Clear();
    gInteractionsMenu.Height = 40;
    ListInteractions.Height = 0;
    
    // set the required variables
    int AreThereInteractions = 0;
    vIntMouseActionX = mouse.x;
    vIntMouseActionY = mouse.y;
    String CurrentOption;
    activeItem = InventoryItem.GetAtScreenXY (mouse.x,  mouse.y);
    if(activeItem != null) { //safety check: pointers can be "null", and if so you can't call methods on them
        ActionNumber = activeItem.GetProperty("Interaction_Number"); //Get the number of custom interactions thisobject/item/hotspot/character has
        int ActionCounter = 1;
        while (ActionNumber > 0) 
        {
          CurrentOption = String.Format("Action_%d", ActionCounter);
          ListInteractions.AddItem (String.Format("%s", activeItem.GetTextProperty(String.Format("%s", CurrentOption))));  
          gInteractionsMenu.Height += 26;
          ListInteractions.Height += 26;
          ActionNumber -=1;
          AreThereInteractions += 1;
          ActionCounter +=1;
        }
        if (AreThereInteractions > 0) {
          gInteractionsMenu.X = mouse.x;
          gInteractionsMenu.Y = mouse.y;
          ListInteractions.SelectedIndex = -1;
          lbMenuTitle.Text = String.Format("%s", activeItem.Name);
          gInteractionsMenu.Visible = true;
        }
     }
  }
  
  else if (IsGamePaused() == 1) {
    // Game is paused, so do nothing (ie. don't allow mouse click)
    // This check goes after the inventory one because otherwise the inventory (which pauses the game) will prevent the item check to fire.
  }
  
  else if (button == eMouseLeft)  {
    // the old code for interacting with stuff in rooms
  ]


EDIT bonus question2: how do I use mouse mode Usermode1 on an inventory item? I would've guessed it was with the Other Click On Inventory Item event, but it doesn't seem to work.
To add more info on how this system works with regular rooms interactions, the player's selection from the interaction menu listbox is then handled in a function that I updated this way for handling inventory items too:

Code: ags

function ListInteractions_OnSelectionCh(GUIControl *control)
{
  if (ListInteractions.SelectedIndex == 0) {
    MenuAction_1 = true;
    gInteractionsMenu.Visible = false;
    if (GUI.GetAtScreenXY(MouseActionX, MouseActionY) != null) {
      GUI.ProcessClick (MouseActionX, MouseActionY, eModeUsermode1);
    }
    else {
      Room.ProcessClick (MouseActionX, MouseActionY, eModeUsermode1);
    }
    MouseActionX = 0;
    MouseActionY = 0;
    mouse.Mode = 1;
  }
  else if (ListInteractions.SelectedIndex == 1) {
    MenuAction_2 = true;
    gInteractionsMenu.Visible = false;
    if (GUI.GetAtScreenXY (MouseActionX, MouseActionY) != null) {
      GUI.ProcessClick (MouseActionX, MouseActionY, eModeUsermode1);
    }
    else {
      Room.ProcessClick (MouseActionX, MouseActionY, eModeUsermode1);
    }
    MouseActionX = 0;
    MouseActionY = 0;
    mouse.Mode = 1;
  }
  //and so on...
}


and finally, the object/character/hotspot events handles what happens based on the MenuAction_x variables.
I thought I could do the same with inventory objects simply by updating the function with GUI.ProcessClick on top of Room.ProcessClick, but evidently that's not the case.

Lord Vetinari

Sorry to bump this up, but I only have the next two weekends and a couple of wordays evening to finish fizing this stuff before a meeting on the 21st of Dicember during which I can probably start to turn this into something and team up with a proper coder, I'm pretty sure I can't figure out in such a short amount of time what's wrong all by myself. Please?

Khris

The first issue can probably be solved with on_event:

Code: ags
// add to GlobalScript.asc
function on_event(EventType event, int data) {
  GUI* gui = GUI.GetAtScreenXY(mouse.x, mouse.y);
  if (event == eEventGUIMouseUp) {
    // inv item interaction menu
    if (gInteractionsMenu.Visible && gui != gInteractionsMenu) gInteractionsMenu.Visible = false;
  }
}


As for simulating clicks on Inventory items, use
Code: ags
  inventory[game.inv_activated].RunInteraction(mouse.Mode);

(game.inv_activated contains the ID of the InvItem that was clicked when for instance on_mouse_click(eMouseLeftInv) is called)

Lord Vetinari

It works perfectly, thank you!

Even if I'm hopefully leaving the coding side of things soon, I don't want to be a code monkey and I'd still like to understand what was going on. Why does Gui.Processclick does not work? Isn't it supposed to simulate a click of that type in the position I tell it to?

SMF spam blocked by CleanTalk