Inventory item stacks

Started by The creature, Sat 22/09/2018 03:07:20

Previous topic - Next topic

The creature

Hi

I've been looking around for a while now for a solution (not wanting to really post) but I've struggled to find any information on how to do this.

Is there a way to stack items in an inventory? I know in the general settings you can set it to allow duplicates, but a stacking option would be amazing. I did find this post: Forum Post on Stacking but it doesn's sound very robust - e.i if you take a stacked item do you take the whole stack or just one from it, ect).

I was wondering if there were any modules or plugins that I've missed that achieve this? Something like this would probably help me in a number of projects, and I can't be alone :)

Currently I have an Inventory GUI and a Font for the stack number display - the GUI inventory doesn't need to scroll as shifiting stack numbers up and down with the items would be complicated - I imagine.

Any help would be really fantastic on such a matter

Kind Regards.
C

Khris

#1
One way is to create an Array of DynamicSprites, one for each inventory item. That way the image can be changed arbitrarily at any time. When the player gains or loses an item, the image is redrawn: first, a copy of the original sprite is created, then the number is drawn on top.

Edit:
Here's a first version: download

1. In General Settings -> Inventory, make sure "Display multiple icons for multiple items" is set to FALSE.

2. Example usage (in game_start / first room_Load):
Code: ags
  StackingInv.Setup(invCustomInv, eFontWestwoodOutline, 15, true);

This will grab inventory item dimensions from invCustomInv, use the stated font, use white (color #15) as font color, and show a "1" for a single item (as opposed to only showing values >= 2)

Disclaimer: Since this version 0.1 of the module simply replaces the inventory item's graphic, the graphic used for eModeUseinv has to be manually changed to the original item graphic when an inventory item is selected, otherwise the quantity number is part of the cursor image. This is hard-coded using late_repeatedly_execute_always so might interfere with other things.

The creature

That's fantastic Khris

I'll have a look at the script and give it a good play. Much thanks to you! Stacking would be such a handy option for how AGS handles it's inventory. So this is great.

Kind Regards
C

The creature

Just a quick question with the script.

I added the script to my game start and as a test gave the player a number of items but it seems to add an additional item.

Code: ags
 
  player.AddInventory(iKey);
  player.AddInventory(iKey);
  player.AddInventory(iKey);
  player.AddInventory(iBlueCup);
  
  StackingInv.Setup(invCustomInv, eFontPixelFont, 19680, true);


So with this code presented above, it says I have a stack of 4 keys rather than 3, and 2 blue cups rather than one. I Set the general settings to not display multiple items. I'm sure I'm just doing something silly.

For my mouse control I'm doing it a little differently from the built in system, with one mouse button doing everything and the right as a cancel/deselect.

Code: ags

function on_mouse_click(MouseButton button) {
    int lt = GetLocationType(mouse.x, mouse.y);
  InventoryItem*ai = player.ActiveInventory, ia = inventory[game.inv_activated];
 
  if (button == eMouseLeft) {
    if (lt == eLocationNothing) Room.ProcessClick(mouse.x, mouse.y, eModeWalkto);
    else if (ai) Room.ProcessClick(mouse.x, mouse.y, eModeUseinv);
    else Room.ProcessClick(mouse.x, mouse.y, eModeInteract);
  }
  else if (button == eMouseRight) {
    if (ai) player.ActiveInventory = null;
    else Room.ProcessClick(mouse.x, mouse.y, eModeLookat);
  }
  else if (button == eMouseLeftInv) {
    if (ai) ia.RunInteraction(eModeUseinv);
    else player.ActiveInventory = ia;
  }
  else if (button == eMouseRightInv) {
    if (ai) player.ActiveInventory = null;
    else ia.RunInteraction(eModeLookat);
  }
  
  if (button == eMouseRight)
  {
    player.ActiveInventory=null;
  }
}



I;ve not had a proper test as I'm still working on UI stuff but adding
Code: ags
  if (button == eMouseRight)
  {
    player.ActiveInventory=null;
  }
should do the trick.

This is exactly what I need though. So Thank you so much.

Kind Regards
C

Cassiebsg

When you created your inventory items, did you change the setting "Player starts with item" to false? It's set to true by default...
There are those who believe that life here began out there...

Slasher

#5
Nice module Khris (nod)

Definitely very handy (nod)

Added it to my weaponry ;)

The creature

Yes I'm an idiot Cassiebsg... Player does start with these items...

Kind Regards
C

The creature

Have you tried using the stacking on multiple inventories?

I'm using 2 inventories, one for the player and one for crafting items. In the game_start I've set both:
StackingInv.Setup(invCustomInv, eFontStackFont, 15, false); //player
StackingInv.Setup(invCustomInv2, eFontStackFont, 15, false); //crafting

Something odd is happening though, the items are getting added to the inventories but for some reason they're not being displayed. They are there though, just invisible because if I mouse over the empty inventory spaces it display the names of the items (I'm using a label that displays what's under the mouse). It's really odd.

**General settings**
Display multiple duplicate items is = false.
Override built-in inv win click handling = true.

It's not a problem if this isn't something that can be solved - I'm just wondering if I'm just doing something stupid.

Kind Regards
CC

Khris

Yeah, it won't work for multiple inventories. Like I said, the module replaces the inventory item's image. It's also hardcoded to only look at the player's inventory.
And calling StackingInv.Setup a second time will just overwrite the first call. The invWindow parameter is only used to get ItemWidth and ItemHeight.

What you are looking for is much more complicated since it requires another way to show the numbers. And the only way to do that is to show a non-clickable GUI or Button on top of the inventory. This requires manually creating a suitable GUI element and much more code.

The creature

Dont worry about it then Kris

Still a fantastic script and it shall be used!

King Regards
CC

The creature

Good afternoon

I have started a project that I finally would like to use this wonderful stacking script in but I'm hitting a compile error:

StackingInv (1).asc(18): Error (line 18): Local variable cannot have the same name as an import

It seems to be a problem with the latest 3.4.1 build as there is no compile issues with 3.4.0. I was curious if anyone else has been using this script in  3.4.1?

The C.

Crimson Wizard

Quote from: The creature on Thu 23/05/2019 15:29:49
I have started a project that I finally would like to use this wonderful stacking script in but I'm hitting a compile error:

StackingInv (1).asc(18): Error (line 18): Local variable cannot have the same name as an import

It seems to be a problem with the latest 3.4.1 build as there is no compile issues with 3.4.0. I was curious if anyone else has been using this script in  3.4.1?

This is either new bug in 3.4.1 or 3.4.0 allowed something wrong.
Could you post module code or give download link?

The creature

Sure here is a link to the original script:

https://drive.google.com/open?id=1Ea5OD1j-xTMuNuXmOW8mYxrYXM_mof-p

But the Code is as follows:

Code: ags
// new module script

DynamicSprite* _is[];
int _os[];

FontType _iFont;
int _fontColor;
bool _ShowOne = false;
int _iw, _ih;

static void StackingInv::Setup(InvWindow* invWindow, FontType font, int color, bool showOne) {
  _iFont = font;
  _fontColor = color;
  _ShowOne = showOne;
  _iw = invWindow.ItemWidth;
  _ih = invWindow.ItemHeight;
}

static int StackingInv::GetItemSlot(InventoryItem* item) {
  if (item == null) return 0;
  return _os[item.ID];
}

void _update(int iid) {
  _is[iid] = DynamicSprite.Create(_iw, _ih, true);
  int iq = player.InventoryQuantity[iid];
  if (iq == 0 || iq == 1 && !_ShowOne) return;
  String q = String.Format("%d", iq);
  int w = GetTextWidth(q, _iFont);
  int h = GetTextHeight(q, _iFont, w + 10);
  DrawingSurface *ds = _is[iid].GetDrawingSurface();
  //ds.DrawImage((_iw - Game.SpriteWidth[_os[iid]]) / 2, (_ih - Game.SpriteHeight[_os[iid]]) / 2, _os[iid]);
  ds.DrawImage(0, 0, _os[iid]);
  ds.DrawingColor = _fontColor;
  ds.DrawString(_iw - w - 2, _ih - h - 2, _iFont, q);
  ds.Release();
  inventory[iid].Graphic = _is[iid].Graphic;
}

void game_start() {
  _is = new DynamicSprite[Game.InventoryItemCount+1];
  _os = new int[Game.InventoryItemCount+1];
  for (int i = 1; i <= Game.InventoryItemCount; i++) {
    _os[i] = inventory[i].Graphic;
    _update(i);
    inventory[i].Graphic = _is[i].Graphic;
  }
}

void on_event(EventType event, int data) {
  if (event == eEventAddInventory || event == eEventLoseInventory) {
    _update(data);
  }
}

bool _wasEMUI;

void late_repeatedly_execute_always() {
  bool _isEMUI = mouse.Mode == eModeUseinv;
  if (_isEMUI && !_wasEMUI) {
    int slot = _os[player.ActiveInventory.ID];
    mouse.ChangeModeGraphic(eModeUseinv, slot);
    mouse.ChangeModeHotspot(eModeUseinv, Game.SpriteWidth[slot]/2, Game.SpriteHeight[slot]/2);
  }
  _wasEMUI = _isEMUI;
}



Thank you!

The creature

#13
Is this too complex to fix with the latest version of the AGS Engine?

I'm just wondering because if it is, I will start transferring everything over to the previous 3.4.0 - as I know the script works fine in that version (even if it shouldn't).


SCRATCH THIS.
I managed to fix it.

SMF spam blocked by CleanTalk