Items & Inventory

So I added items and inventories.

It was very difficult.

First I had to re-implement and integrate the Discworld. The initial implementation had a bunch of performance issues that have been corrected. It also exposes a nicer Lua interface.

(The GameDB stores all relationships between resources in the game. These resources could be skills, items, monsters, etc. Actions connect resources; they have inputs, outputs, and requirements. For example, a smith action may have an input of 2 bars, an output of 1 sword and some smithing XP, and a requirement of 22 smithing levels. The action can be connected to the item smithed, or the bars, both, or whatever other combination makes sense from a gameplay perspective. In turn, dependencies can be evaluated to perform the action or for goal planning, etc).

Then I had to create an authoritative “ItemBroker” that manages all item instances in the game. It holds a reference to the item instance (basically a tuple in the form { item-id, item-count, is-noted, userdata }) and the inventory the item belongs to. To transfer ownership, spawns items, or destroy/consume item, a transaction must be created. Transactions are idempotent and error handling is carefully integrated when performing the transaction. If a transaction fails, no changes are made to the ownership of items. By having all item ownership logic in a single place, it greatly reduces the scope where item dupe, cloning, or other sort of bugs can occur.

After this, I had to create the UI widgets and renderers to manage the inventory and interact with items.

For example, I can handle stacks up to the quadrillions:

(The counts are rounded down and appended with a relevant suffix. The max item count will be 2^53, or about 9 quadrillion. This is the max integer precision of a double. In actuality, I’ll limit the count to 1 quadrallion. Worse comes to worse, I’ll wrap the ItemInstance object in C++ and use a big integer library. But that can all be handled transparently in the future due to the way the item and inventory system is designed!)

Inventory management is handled by assigning keys to items. For this example, there’s keys 1-28 corresponding to the slot in the inventory. When the PlayerInventory is notified of an item transfer (during the Transaction), it assigns a proper key (the first available one, in this case). When swapping items, keys are updated. Keys are useful for other things too, such as tile positions; the GroundInventoryProvider uses (x, y, layer) as a the key for an item. A single key can point to multiple items, but a single item can only have one key.

After adding the UI for the player inventory, I had to make the “world UI” for items:

To be brief, I added some more methods/events to the Stage model. The GameView then listens for these events (dropItem and takeItem) to add or remove item tokens to or from the scene graph. There are also methods to take items at a tile; this causes the player to walk to the tile then pick up the item. (Oh, did I mention I had to implement a CommandQueue for Peeps? It’s pretty self-explanatory.)

Lastly, I added Probe and PokeMenu objects. The Probe object allows probing the game world for actions, such as loot or walk (and in the future, things like interacting with objects and NPCs). Similarly, the PokeMenu is similar to the right-click-menu in RuneScape and simply allows the player to perform an action if there’s some ambiguity. It functions almost identically.

And that’s it. Over 30 hours after I began implementing items (excluding the work on Discworld), items now work. Well—mostly. There’s still the matter of interacting with objects in the inventory… But that’s another day!