Saturday, 27 October 2007

A stack of problems

It has been said that Angband is a game of inventory management. If so, then then the mastering the Angband item stacking algorithm is like playing invisible Tetris: possible, but you have to know the rules and what order the pieces arrive in.

The Angband inventory has 23 slots, in which each slot up to 99 items can be placed. In addition, each item has a weight, which the character's strength determines the maximum total weight that can be carried. The slot function is the most important, however, as a set of hidden rules cover how many different types of items can be carried in each slot, and these rules are known as stacking rules.

At a high level, a set of tests in object2.c in the object_similar() code test if two stacks of 1 or more objects are similar, and if so, the two stacks are combined using the object_absorb() code. I'll endeavor to describe a high level version of the algorithm:

  1. Artifacts (unique magical objects) never stack.
  2. Objects may not stack if their kinds are different. An object kind could be 'a set of leather gloves' or 'a wand of fire bolts'.
  3. Objects may not stack if their ego_types are different. Some objects qualify for ego types, such as armours 'of resist fire' or weapons 'of acid brand'. Others, such as wands, do not have ego types.
  4. An object may not stack if its to-hit, to-damage or to-ac bonuses don't match, if it has any of these properties. Other numeric values also prevent this (such as different weights) - except -
  5. An object may be forced to stack if it only has a different 'discount percentage' if the stack_discounts option is selected.
  6. Wands, staves and rods with differing charges and/or timeouts may be allowed to stack together, but the charges and/or timeouts may mysteriously disappear, or be 'averaged out' on the stack. The exact method used for this depends on the Angband variant.
  7. An object may be prevented from stacking if the player has identified its characteristics from another identical object that the player has not identified the characteristics of, some characteristics of which the player will never actually be told about.
  8. An object will not stack if the player has 'inscribed' it with a note, with an item not so inscribed, unless the stack_notes option is selected.
  9. Some variants implement a quiver system, which has 10 additional slots, which can be used in exchange for 1 inventory slot for every 99 items total in the quiver (regardless of the number of quiver slots occupied by these 99 items). However, only certain equipment is allowed in the quiver.
  10. Hengband allows you to collect all the different types of wands in a separate inventory screeen.
  11. Unangband allows you to have magical bags which occupy a single inventory slot: each of which has 23 further slots, which can hold up to 99 items per slot. However, the kind of item (see point 2) for each slot is fixed for each magical bag type.
Simple!

The inventory slot mechanism is a great game mechanic, because it forces the player into trade offs: roughly speaking each inventory slot corresponds to one in-game function, be it healing, or attacking with arrows, or magical fire, or causing monsters to fall asleep, and so on. However, the stacking mechanic leaves a lot to be desired from a comprehensibility point of view. Which is why, I am considering simplify the mechanic in the next version of Unangband to the following three rules:
  1. Artifacts (unique magical objects) never stack.
  2. Objects may not stack if their kinds are different. An object kind could be 'a set of leather gloves' or 'a wand of fire bolts'.
  3. Objects may not stack if their ego_types are different. Some objects qualify for ego types, such as armours 'of resist fire' or weapons 'of acid brand'. Others, such as wands, do not have ego types.
This will require amending the current inventory slot system to include a linked list of objects for each slot. The top of each linked list will be displayed in the inventory as follows:

a) 6 of 19 daggers (+1, +1)
b) 3 of 7 wands of magic missiles (10 charges)
etc.

where the 'of 9' indicates the total number of items in the linked list (each list element can hold up to 99 items as before). The top item will be shown as the 'best' identified item, and a sub-list will be shown when the slot is selected e.g.

a) 6 daggers (+1,+1)
b) 5 daggers (+1,+0)
c) 4 daggers (+0,+0)
d) 2 daggers {magical}
e) 2 daggers {cursed}

I'm also considering implementing a special inscription '=t' that will allow objects to be stacked by tval, which corresponds to 'swords' or 'wands' or 'potions' instead. This may tip the balance the wrong way too far, but it should considerably simplify the code and the number of exceptions made to the existing Unangband stacking implementation.

2 comments:

Mikolaj said...

Wow. It may be that this will not remove the good trade-offs, because they are usually between objects of different kinds. This will also subsume the quiver (except artifacts in the quiver recharge), so it sounds good. I wonder...

ben.citak said...

I really like the idea. I think it goes too far to stack all items of the same tval though.