Putting Active Inventory Back into Inventory Problems (SOLVED)

Started by Scavenger, Tue 19/11/2013 12:53:49

Previous topic - Next topic

Scavenger

Okay, so I'm trying to emulate the Discworld inventory system using AGS, and it's running pretty smoothly. I have double clicks, inventory items being takeable from the inventory, putting down items and picking them up again. But there's one thing, in my awful, awful code that I cannot get it to do for some reason, and it's been bugging me for the entire time I've been working on the game.

And that is, when I click on a space in the inventory occupied by the active inventory (the inventory slot while you have it active is blanked out, making it look empty) the item gets put down and immediately picked back up again, and I'm not sure why this is happening. I can't give the entire project, as it's so close to completion now, but here's the click code I'm using:

Code: AGS

int mx, my, lastclick;
int clickdelay = 15;
bool itemvisible;
bool inventoryvisible;
int clicktype;
int clickbuffer;
InventoryItem* itemclicked;
 int itemtimeout;

function left_click(bool single, ClickType type) 
{
  if (single && type == eClickField) 
  {
    // single-click on field code. not important to the example.
  }
  else if (!single && type == eClickField)
  {    
    // double-click on field code. Also not important
  }
  else if (single && type == eClickInventory && clickbuffer == 0) //Single Click on inventory.
    {
      bool newitem = false;
      InventoryItem* item = itemclicked;
      if (player.ActiveInventory != null)
          {
            if (item != player.ActiveInventory) newitem = true;
            ReturnInventory ();
            if (newitem)
                {
                  //Display ("NEWITEM");
                  player.ActiveInventory = item;
                  gItem.BackgroundGraphic = item.CursorGraphic;
                  item.Graphic = 32;
                  if (mouse.x - 16 > 0 ) gItem.X = mouse.x - 16;
                  if (mouse.y - 10 > 0 ) gItem.Y = mouse.y - 10;
                  gItem.Visible = true;
                }
            item = null;
            itemtimeout = 50; //To stop the lower conditional from being run, but doesn't work.
            return;
          }
      else if (player.ActiveInventory == null) //Should be run only when you don't have an inventory item, and have clicked on one.
          {                                        //For some reason, it's run directly after the above conditional?????
                //Display ("NO INV");
                if (itemtimeout) return; //This should stop the player from picking up the item right back up again, but it doesn't work!
                else
                    {
                      player.ActiveInventory = item;
                      gItem.BackgroundGraphic = item.CursorGraphic;
                      item.Graphic = 32;
                      if (mouse.x - 16 > 0 ) gItem.X = mouse.x - 16;
                      if (mouse.y - 10 > 0 ) gItem.Y = mouse.y - 10;
                      gItem.Visible = true;
                    }
          }    
     }
  else if (!single && type == eClickInventory && clickbuffer == 0)
    {
         if (player.ActiveInventory != null)
             {
                   if (inventory [game.inv_activated].IsInteractionAvailable(eModeUseinv))
                        {
                              inventory [game.inv_activated].RunInteraction (eModeUseinv);
                        }
         else unhandled_event (5, 3);
     }
   else 
         {
            if (inventory [game.inv_activated].IsInteractionAvailable(eModeInteract))
                  {
                    inventory [game.inv_activated].RunInteraction (eModeInteract);
                  }
            else unhandled_event (5, 1);
         }
    }
}

function repeatedly_execute() {
  if (lastclick>0 && lastclick<=clickdelay) lastclick++;
  else if (lastclick>clickdelay) 
    {
        lastclick=0;
        left_click(true, clicktype);
    }
  
  if (itemtimeout) itemtimeout --;
}


function on_mouse_click(MouseButton button) 
{
  // called when a mouse button is clicked. button is either LEFT or RIGHT
  
    if (GUI.GetAtScreenXY (mouse.x, mouse.y) != gInventory && gInventory.Visible == true) 
        {
              gInventory.Visible = false;
              inventoryvisible = false;
        }

    else if (button == eMouseLeft) 
        {
               int mxdist = AbsInt(mouse.x - mx);
               int mydist = AbsInt(mouse.y - my);
    
               if (lastclick>0 && mxdist < 3 && mydist < 3) 
                    {
                          lastclick=0;
                          left_click(false,  eClickField);  
                    }
                else 
                    {
                          lastclick=1;
                          mx=mouse.x;
                          my=mouse.y;
                          clicktype = eClickField;
                    }
        }
    else if (button == eMouseRight)
        {
              if (player.ActiveInventory != null) 
                  {
                        if (player.ActiveInventory != iWires) ReturnInventory (); //Special dispensation for game entity that isn't actually an inventory item.
                        else 
                              {
                                    player.Say ("I'll just put these back.");
                                    ReturnInventory ();
                                    player.LoseInventory (iWires);
                              }
        
                  }
              else ProcessClick (mouse.x, mouse.y, eModeLookat);
        }
    else if (button == eMouseLeftInv && itemtimeout == 0)
        {
            //Display ("Clicking Inventory");
            if (GUIControl.GetAtScreenXY (mouse.x, mouse.y) == invInventory)
                {
                    int mxdist = AbsInt(mouse.x - mx);
                    int mydist = AbsInt(mouse.y - my);
    
                    if (lastclick>0 && InventoryItem.GetAtScreenXY (mouse.x, mouse.y) == itemclicked) 
                        {
                            lastclick=0;
                            left_click(false, eClickInventory);
                            itemclicked = null;
                        }
                    else 
                        {
                            lastclick=1;
                            mx=mouse.x;
                            my=mouse.y;
                            clicktype = eClickInventory;
                            itemclicked = InventoryItem.GetAtScreenXY (mouse.x, mouse.y);
                        }
                  }
         }
    else if (button == eMouseRightInv)
         {
               InventoryItem* itemlook = InventoryItem.GetAtScreenXY (mouse.x, mouse.y);
               itemlook.RunInteraction (eModeLookat);
         }
}

function ReturnInventory ()
{
  aDrop.Play (eAudioPriorityHigh, eOnce);
  InventoryItem* item;
  item = player.ActiveInventory;
  item.Graphic = gItem.BackgroundGraphic;
  gItem.Visible = false;
  itemvisible = false;
  player.ActiveInventory = null;
}


Again, everything BUT putting items back in their own slot works fine. If you try and put the item back in it's own slot, it just pops back onto the mouse again, or it stays in the inventory randomly if you double click or quickly move the mouse away.

The behaviour I want is this: When you single click on an item when you have an active inventory item, it swaps that item with the one you're holding. If you click on an empty space OR the space where the Active Inventory actually is (and invisible), it returns your active inventory to the inventory window and leaves you with nothing.

The current behaviour is this: When you single click on an item when you have an active inventory item, it swaps that item with the one you're holding. If you click on an empty space, it returns your inventory. If you click on the space your item is in normally, it puts the item down and immediately swaps it with itself, leaving you with the exact same item in hand.

There's got to be something simple I'm just blind to.

I have no idea what I'm doing wrong. I'm like 3 days from releasing this game and this bug is being nigh impossible to crush!

Thankyou for any help at all.

Khris


Scavenger


Khris

Maybe I'm missing something, but:
In on_mouse_click / eMouseLeftInv, you're calling left_click(false, eClickInventory);
Which means inside left_click(), single is false.

Yet the code you say doesn't work is inside if (single && ...) {}, so it looks like the game will run the block starting at line 57 instead?

Scavenger

That's the double click part of the inventory interaction. Basically, the code does this:

1) Player clicks the mouse.
2) Game sets a timer, which when it ends, the single click code will run.
While the timer is going on:
3a) The player clicks the mouse again.
4a) Game sees that the timer is going on, and runs the double click action.
or
3b) Player does not click the mouse.
4b) Timer runs out and runs the single click code from repeatedly_execute.

It works in all cases but the player single clicking the Active Inventory slot.

Lupo4u2


Code: AGS

//you set:
player.ActiveInventory = item;
//...
item = null;


and afterwards you check for:

Code: AGS
if (player.ActiveInventory == null)


maybe that's the problem, because at that time ActiveInventory == null?

Scavenger

No, that can't be it, as you lose your ActiveInventory in a seperate conditional branch to the "pick item up" branch.


Code: AGS

      if (player.ActiveInventory != null)
          {
                //player's Active Inventory is removed in this branch.
          }
      else if (player.ActiveInventory == null)
         {
                //Player's active inventory is updated in this branch.
         }


Somehow, both branches are being run one after the other, on the same click. I checked it with the commented out Displays, when you click on the same inventory item that you're carrying, it sets the item down and then runs the lower branch immediately afterward. Is this just a bug in the repeatedly_execute code?

Lupo4u2

one guess what you can try is to put the else branch in { } and add the if statement inside it.
Maybe its a compiler issue with the if else, as i know that sometimes unexpected things like what you describe can happen.
(even i could not reproduce such misbehaviour with a if/else if test here)

try
Code: AGS
 if (player.ActiveInventory != null)
          {
                //player's Active Inventory is removed in this branch.
          }
      else 
          {    
            if (player.ActiveInventory == null)
             {
                //Player's active inventory is updated in this branch.
             }
          }

does it fix the problem?

Khris

I was also thinking about this and did a quick check but couldn't reproduce it. On the other hand, the first branch calls a custom function, which might screw up the if-else-handling? This would be a pretty major bug though, and I'm sure somebody would have noticed by now.

I suspect the reason is that somehow repeatedly_execute calls left_click() twice in a row, even though lastclick is reset.

Scavenger

#9
I had this same problem with my other game - where functions called in repeatedly_execute would continue to be called even though there's no reason for it.

I'm loathed to do it, but I could package up my game project files and PM you a link so you can see the code in action. You may be able to figure out whether it's just my poor coding or an actual bug. (it's most likely my poor coding).

EDIT: Okay, fixed it, it was an unrelated on_event call I hadn't checked properly. I was using it to put items down in empty slots. Everything works as planned now.

monkey0506

Just from looking at the code you'd posted, I'd figured you must be calling left_click from somewhere else. A bug that serious in rep_ex and/or conditional statements would never have survived this long.

Glad you got it sorted though! :)

SMF spam blocked by CleanTalk