Adventure Game Studio

AGS Support => Beginners' Technical Questions => Topic started by: ManicMatt on Tue 09/03/2021 18:59:17

Title: Making the only visible inventory item active
Post by: ManicMatt on Tue 09/03/2021 18:59:17
Hello (again),

My other hurdle is hurting my brain, I've been searching through forum results with no luck.

So my game doesn't support the mouse, keys only. I have a small inventory GUI that is constantly onscreen, and only displays one item. You press the tab key or the Q key to flick between different inventory items. But I cannot find any code that would make the currently visible item become the active inventory item. Does such a piece of code exist?
Title: Re: Making the only visible inventory item active
Post by: eri0o on Tue 09/03/2021 19:03:15
Not sure how your inventory works, but you can assign any item to player.ActiveInventory

https://adventuregamestudio.github.io/ags-manual/Character.html#characteractiveinventory
Title: Re: Making the only visible inventory item active
Post by: Crimson Wizard on Tue 09/03/2021 19:23:48
That said, "active inventory item" is just a convention. You may make your own InventoryItem* variable (or an integer refering to item's ID) and assign it,  then use it to handle using items in game.
Title: Re: Making the only visible inventory item active
Post by: ManicMatt on Tue 09/03/2021 19:55:44
Thank you but I do not believe either are what I am after.

Let's say there's 5 inventory items held by the player. Pressing a key will replace the current visible inventory item displayed in a GUI inventory box with the next one, and so on. So in my code it is just:

Code (ags) Select
else if (keycode == eKeyTab)
  {
   InventoryWindow1.ScrollDown();
}


So this isn't going to identify which item appears next, so I can't just code in that iKey (For example) will be active upon pressing a key without being able to detect what item is currently visible. That's why I was hoping there's a way for AGS to detect which inventory item is shown and automatically make that the active item, so when the player presses the enter key it will use the active item on a region/hotspot.
Title: Re: Making the only visible inventory item active
Post by: Matti on Tue 09/03/2021 20:31:54
I don't really have time right now but I think you should be able to keep track of the index (or the shown row of the inventory window which should be equal to the item index) and use the ItemAtIndex property to retrieve the currently shown item. Another way would be to check InventoryItem.GetAtScreenXY(int x, int y).
Title: Re: Making the only visible inventory item active
Post by: Crimson Wizard on Tue 09/03/2021 21:07:34
InventoryWindow has TopItem property to know first visible items, InvWindow.ItemsPerRow to know number of items visible per row and InvWindow.RowCount to know number of visible rows.
Using these together lets you may find out which items are visible at the moment. If you need only first visible, that would be TopItem.

You may retrieve actual inventory item using InvWindow.ItemAtIndex[], where you pass the item index.

Title: Re: Making the only visible inventory item active
Post by: Khris on Wed 10/03/2021 00:59:05
I'd probably do this:

Code (ags) Select
function activateNextInvItem() {
  for (int i = 0; i < invMain.ItemCount; i++) {
    if (invMain.ItemAtIndex[i] == player.ActiveInventory) {
      // move to next item, including wrapping around
      player.ActiveInventory = invMain.ItemAtIndex[(i + 1) % invMain.ItemCount];
      break;
    }
  }
  // actually show sprite (instead of visible inv window)
  if (player.ActiveInventory) {
    btnInvItem.Graphic = player.ActiveInventory.Graphic;
    guiInv.Visible = true;
  }
  else guiInv.Visible = false; // hide active item GUI if player loses active item / has none
}


That way I avoid having to rely on GetInvItemAt and other such commands; it'll always just work. The InventoryWindow is just used for its array, which also conveniently keeps the order in which items were picked up.
Also, since I'm using a button to display the active item, I have full control over what's shown on screen.
Title: Re: Making the only visible inventory item active
Post by: ManicMatt on Wed 10/03/2021 11:25:33
Thanks everyone! I tried Khris' code out but I don't think I know what I'm doing, it's too complicated for me. I get the game to run but nothing seems to happen.

The closest I have with Crimson and Matti's suggestions is

Code (ags) Select
  else if (keycode == eKeyTab)
  {
    InventoryWindow1.ScrollDown();
  player.ActiveInventory = InventoryWindow1.ItemAtIndex[1];
  }
  else if (keycode == eKeyQ)
  {
   InventoryWindow1.ScrollUp();
   
    player.ActiveInventory = InventoryWindow1.ItemAtIndex[0];

  }


But this doesn't actually seem to go up and down, as the third item in my inventory doesn't appear as an active item. I just seem to be activating inventory items 1 and 2. You said about keeping track of the index, but I have no idea how to implement that. Help!
Title: Re: Making the only visible inventory item active
Post by: Khris on Wed 10/03/2021 11:32:49
I posted just the function, you need to also call it:

Code (ags) Select
  else if (keyCode == eKeyTab) activateNextInvItem();

My code also relies on a GUI (guiInv) created to show the active item on a button (btnInvItem).

As for "keeping track of the index", this translates to "global int variable" that is used in place of a hard-coded 0 and 1.
Title: Re: Making the only visible inventory item active
Post by: ManicMatt on Wed 10/03/2021 11:54:55
Okay, I'll give it another go!

The problems I am now having:

invMain is an undefined symbol, should I be renaming this to the name of my inventory GUI?

If I do that, I then get

"GlobalScript.asc(28): Error (line 28): property 'Button::Graphic' is read-only"

The manual states this is a read only command too? Do I change it to "btnInvItem.NormalGraphic;"?

Making this change also means the game runs but there's no inventory on screen. I think that's what happened when I first tried your code, I'm clearly doing something wrong here. Please advise!
Title: Re: Making the only visible inventory item active
Post by: Matti on Wed 10/03/2021 12:13:21
You need to use Button.NormalGraphic instead of Button.Graphic.
Title: Re: Making the only visible inventory item active
Post by: ManicMatt on Wed 10/03/2021 12:23:52
Okay so what happens now is, I see the graphic, I press tab, and then the inventory image dissapears, but at no point are items active because before, the mouse cursor would appear with the active inventory item. (Something else I need to work on)

I'm wondering if my GUI set up is wrong. Is guiInv supposed to contain InventoryWindow1, and btnInvItem inside it?

The code currently looks like this:

Code (ags) Select

    function activateNextInvItem() {
      for (int i = 0; i < InventoryWindow1.ItemCount; i++) {
        if (InventoryWindow1.ItemAtIndex[i] == player.ActiveInventory) {
          // move to next item, including wrapping around
          player.ActiveInventory = InventoryWindow1.ItemAtIndex[(i + 1) % InventoryWindow1.ItemCount];
          break;
        }
      }
      // actually show sprite (instead of visible inv window)
      if (player.ActiveInventory) {
        btnInvItem.NormalGraphic = player.ActiveInventory.Graphic;
        guiInv.Visible = true;
      }
      else guiInv.Visible = false; // hide active item GUI if player loses active item / has none
    }
Title: Re: Making the only visible inventory item active
Post by: Khris on Wed 10/03/2021 15:06:37
Sorry for that, it was primarily example code, not really meant to be used as-is without further adjustments.

The inventory window is only used for internal inventory management; it stores the items in the order in which the player receives them. It has to exist, but is not used "visually" in my code.

Here's a revised version:
Code (ags) Select
function activateNextInvItem() {

  InvWindow *iw = InventoryWindow1; // assigned to player, does not have to be visible(?)

  if (player.ActiveInventory == null) {
    // if no item is active, make first item active
    if (InventoryWindow1.ItemCount > 0) player.ActiveInventory = InventoryWindow1.ItemAtIndex(0);
  }
  else {
    // move to item after current one
    for (int i = 0; i < iw.ItemCount; i++) {
      if (iw.ItemAtIndex[i] == player.ActiveInventory) {
        player.ActiveInventory = iw.ItemAtIndex[(i + 1) % iw.ItemCount];
        break;
      }
    }
  }
}


Now we need to display the active item:
Code (ags) Select
function repeatedly_execute_always() {

  GUI *ig = guiInv;                 // used to display item
  BUtton *ib = btnInvItem;          // ditto

  // actually show sprite (instead of visible inv window)
  if (player.ActiveInventory) {
    // set graphic, do not react to hovering or clicks
    ib.NormalGraphic = player.ActiveInventory.Graphic;
    ib.MouseOverGraphic = player.ActiveInventory.Graphic;
    ib.PushedGraphic = player.ActiveInventory.Graphic;
    ig.Visible = true;
  }
  else ig.Visible = false; // hide active item GUI if player loses active item / has none
}


You should probably also add this (make item active after receiving it):
Code (ags) Select
function on_event(EventType event, int data) {
  if (event == eEventAddInventory) player.ActiveInventory = inventory[data]; // set received item as active
}
Title: Re: Making the only visible inventory item active
Post by: ManicMatt on Wed 10/03/2021 16:55:30
Thanks Khris, you're awesome as always!

However the code as is didn't work for me, I had to change it to this and now it works, although it doesn't show any inventory items until I press the Tab key first but given the character won't start with any inventory items it might not be a problem. This is how it looks now, also note you had accidently used () instead of [] for ItemAtIndex which is easily done. Just pointing this out just in case anyone in the future is looking at this thread for advice.

Code (ags) Select
    function activateNextInvItem() {
     
      InvWindow *iw = InventoryWindow1; // assigned to player, does not have to be visible(?)
     
      if (player.ActiveInventory == null && InventoryWindow1.ItemCount > 1)
    // if no item is active, make first item active
   
    player.ActiveInventory = InventoryWindow1.ItemAtIndex[0];
      else {
      // move to item after current one
      for (int i = 0; i < iw.ItemCount; i++) {
      if (iw.ItemAtIndex[i] == player.ActiveInventory) {
      player.ActiveInventory = iw.ItemAtIndex[(i + 1) % iw.ItemCount];
      break;
      }
}
}
}


I also had to change "BUtton" in the second piece of code to "Button", just a typo. Easily spotted for me, and I risk sounding like an arse, but again just pointing it out for anyone intending to use your code.  :smiley:

So unless you can see some error in my changes, I think this case is closed?

Thanks again!  :cheesy:
Title: Re: Making the only visible inventory item active
Post by: Khris on Thu 11/03/2021 10:51:14
Great, glad you got it to work :)
When I find the time I'll put my code in an actual game and test it properly, then fix my code in the previous post. Fingers crossed :-D

Also, if the character starts out with one or more inventory items, try putting
Code (ags) Select
  player.ActiveInventory = iWallet;
in room_Load or game_start and it should appear.