Item stacking in RPGs

Started by
11 comments, last by Kylotan 13 years, 6 months ago
I'm looking into item stacking for my RPG / roguelike game. For those not familiar with the term, it's when multiple identical (or near identical) items are reduced to a single 'stacked' item for the player to interact with. So if you're holding 1 arrow and pick up 9 more your inventory shows "Arrow (x10)", instead of "Arrow, Arrow, Arrow, Arrow, ..." This makes it easier to manipulate (eg. passing all your arrows to a ally) and reduces clutter when navigating your inventory.

As far as I see there are two obvious ways to implement this - either 1) at the GUI level, or 2) at the model level.

1. Stacking performed in the GUI
Here, if you've picked up 10 arrows then your inventory actually contains 10 'arrow' objects. This means that almost all of the gameplay code doesn't care about stacks, as it can just deal with items (or lists of items) as it needs to. Instead the relevant GUI sections (such as the inventory menu) will create stacks to show to the player.

The downside of this is a player's inventory could get very big very quickly. It's not unlikely to have hundreds of arrows for example.

2, Explicit item stacks in the gameplay representation
By this I mean that the inventory actually stores things internals as stacks. If you've picked up 10 arrows that would be represented by an ItemStack object containing a single Arrow object and a 'stackCount' of 10. This could be split into an ItemStack with a count of 9 and an ItemStack with a count of 1 when a single item needs to be passed elsewhere (ie. to use it).

The advantage of this is that the number of inventory items is much more manageable (a thousand arrows is really just an ItemStack object, an Arrow object and a count of 1000). The disadvantage is that most of the gameplay logic now needs to be aware of the concept of item stacks and becomes more complicated as a result.

Or, 3) some kind of hybrid of the two? Or any other ideas that people have?

Normally I'd go with 1 and just make it a gui thing, but I want to have money (in the form of gold, silver and bronze coins) individual objects. An inventory with 100 arrows is probably just about practical, but an inventory containing 1,000,000+ individual GoldCoin objects isn't.

Further complications:
'Cursed' objects are usually shown as identical to regular objects until they're worn/used/inspected. These need to be stacked along with items of their own type (otherwise that single arrow that refuses to stack will obviously be cursed and you can throw it away). However it might not be enough just to keep a 'stackCount' and a 'numCursed' count, as there may be two arrows with very different curses.

'Charged' objects (like Wands, or Potions) may have a 'uses' count (number of times the potion can be used before it is finished, or number of times a wand can be used before it breaks). Obviously these can't be stacked as a single Wand object with a count, as the individual charges would be lost.

This roguedev thread has a whole bunch of opinions on the subject as well.

Thanks.
Advertisement
Virtually every game I know implements stacks at the object level, since that is what makes sense -- especially if you can possibly have thousands of them. It is practically mandatory if you have multiplayer. Even if you don't have multiplayer now, it will be a major barrier if you decide to add that feature in a year from now, which you can totally avoid from the beginning.
Imagine something like Runescape where a player typically hoard ten thousand arrows, and multiply that with as few as a thousand players. Not stacking items would be an insane load on the database, both storage wise and startup time wise. It simply isn't acceptable to load a few megabytes of data for every player that logs in, just to have an inventory of mostly identical items.

Hiding cursed items can be trivially done at GUI level, using many different approaches. I'm doing this by assigning a different item ID and adding a "looks like" field, which obviously is only needed once for every item type, not every instance.
Quote:Original post by samoth
Hiding cursed items can be trivially done at GUI level, using many different approaches. I'm doing this by assigning a different item ID and adding a "looks like" field, which obviously is only needed once for every item type, not every instance.


Individually it's all "trivial", it's the knock-on effects on complexity that worry me. At the moment my ItemStack design would end up looking like:

class ItemStack{  ArrayList<InternalItemStack> internalStacks;}class InternalItemStack{  Item item;  int count;}


.. in order for an ItemStack to represent "Arrows x10" it'd internally be storing Arrow x6, Cursed Arrow x2, Blessed Arrow x2. And then everything that deals with firing arrows needs to accept an ItemStack instead of an Item, etc. etc.

Edit: The other approach could be to expand my existing Item interface so that ItemStack can actually *be* an item. However I suspect that might be more trouble than it's worth.
Quote:.. in order for an ItemStack to represent "Arrows x10" it'd internally be storing Arrow x6, Cursed Arrow x2, Blessed Arrow x2. And then everything that deals with firing arrows needs to accept an ItemStack instead of an Item, etc. etc.


I think you should reconsider this design. If the different types of arrows don't stack on each other all you have to do is have a counter for your stackable items.

Quote:This makes it easier to manipulate (eg. passing all your arrows to a ally) and reduces clutter when navigating your inventory.


This would also hold true for passing all your Cursed Arrows if it'd wouldn't stack with all types of arrows.

[Edit] Didn't notice your further complications section, which makes it more complicated indeed. Could your items not contain a state indicator, which contains information on whether the item is cursed or charged and what kind of curse it is or how many charges it has?
Quote:Original post by Mussi
[Edit] Didn't notice your further complications section, which makes it more complicated indeed. Could your items not contain a state indicator, which contains information on whether the item is cursed or charged and what kind of curse it is or how many charges it has?

Yeah, it's those that really make it hard. Lots of games get this wrong and stacking (or lack of) reveals information about the item that the user shouldn't know yet, or stacking and unstacking resets the internal counters (like the wear, or decay state) allowing cheating.

This post has some interesting ideas on 'hard' vs. 'soft' item stacking. I'm wondering if I can use both to solve this elegantly. Eg. 100 arrows become 'hard stacked' into one Arrow object with a count of 100 in the model, and Arrowx100 and CursedArrowx2 are 'soft' stacked in the GUI so the user only sees one stack.
Quote:
Eg. 100 arrows become 'hard stacked' into one Arrow object with a count of 100 in the model, and Arrowx100 and CursedArrowx2 are 'soft' stacked in the GUI so the user only sees one stack.

Well, hard stacking is more important at developing time whereas soft stacking can be added later to improve the UI handling.

With some simple rules you can easily handle hard stacking. First I would associate every item with a template which contains meta informations about the item, most important the stack size (bottle = 5, arrow = 100, armor=1 etc). With this approach you can easily define unique items like armor etc. which are just too large or too special to be stacked (you dont' want to stack 5 magic breastplates with different magical boni). Then I would define a restricted mode, in which you can't apply all stacking operations to a item stack , i.e. you can't merge unidentified potions with health potions.

This will leave you with one issue: hidden attributes. Either you define items with hidden attributes as unidentified (=restricted mode), or you should use soft stacking. But you will run into gameplay issues mixing hidden attribute items with standard items. There's nothing bad about an 'cursed', unstackable sword, but when you mix cursed potions with health potions, what potion will be consumed first ?

In my opinoin you should communicate an unidentified state to the player, so the player has the option to use it or to identified it first. Nothing is more annoying than to drink a "masked" health potion and to die from poision in a boss battle, because the player has never the chance nor the choice to react in a different way.
I'd make your generic item base classes with two attributes.

First, make a query to see if something is stackable. IsStackable(), perhaps. If true, you can display it differently in the UI.

Second, a query to see how many it is. Count(), perhaps. If it isn't stackable the count should be 1. If it is stackable, the count is >= 1.




It gives you several properties that you see in Roguelike games. You dip a stack of arrows in holy water they all become blessed; you dip them in poison they all become poisoned, etc.

The "knock-on effects" also become uniform. If the object is stackable you search for a duplicate. If there is a duplicate you just add to the count. This applies to all actions. Drop an item means you check for stackable then check for prior existence. Pick up means you check for stackable then prior existence.

Other knock-on effects can operate on count without a check for stackability. If you drop x items and you don't have that many, you can drop up to the count. The player wanted to drop 57 (unstackable) wands of digging? Sorry, you only drop one because that's the count.

Another effect, using an item, can be part of the base class. Using a stackable item would decrease the count, possibly consuming it. Using a non-stackable item may modify other counts such as charge counters, possibly consuming the object.
There are more than two options. Object + count, multiple objects, and the obvious third path of object + count + multiple objects. That is to say object + count for objects that are identical, but smart enough to use multiple objects when they are similar enough to stack but not identical. I would start with object + count then add the ability to stack item stacks.
Quote:Original post by frob
..snip..

Yeah, you've pretty much ignored the 'further complications' bit, which is where things get interesting. :)

stonemetal is thinking along the right lines (merging some items but keeping others unmerged). The only question is whether to hard stack existing stacks in the model, or whether to soft stack the existing hard stacks at a UI level.

I'm going to go with soft stacking at the UI for now, largely because that should keep the actual gameplay logic simpler.
Quote:Original post by OrangyTang
Quote:Original post by frob
..snip..

Yeah, you've pretty much ignored the 'further complications' bit, which is where things get interesting. :)

Does it really matter if you identify each particular item as cursed? If you pull an arrow from a quiver you may decrease your cursed count randomly selected by (cursed/uncursed) percent. If you have multiple cursed types, you enumerate a count of each cursed type and randomly pull from them. The stacked and count items operate unchanged.

This topic is closed to new replies.

Advertisement