The simple inventory allows Twine authors to create and manipulate array-based inventories for 'key' style items (as opposed to consumables or equipment). For a more advanced inventory plugin check the Universal Inventory System script.
📝 Note:
Simple Inventory v3 is currently in beta! Once it stabilizes, this version of the Simple Inventory will be retired and the simple inventory will no longer be part of this collection.
The simple inventory allows Twine authors to create and manipulate array-based inventories for 'key' style items (as opposed to consumables or equipment). This system provides a great deal of functionality, including sorting, displaying item lists (with drop / transfer links), and creating multiple inventories (for creating 'rooms' or other containers, or party members) and transfering items between them. All of the functionality here has both a JavaScript API and a TwineScript Macro-based API, meaning the features are easily available from within your passages and inside scripts.
⚠️ Attention:
The simple inventory has undergone some pretty major changes since it first debuted. Version 1 was mostly a bit of syntactic sugar over an array system designed to help less-experienced authors utilize standard JavaScript arrays and methods in a scripting style they were more comfortable with (that is, macros). On rewriting this system, it seemed like a good idea to push things a little farther and create something that could be useful even to more experienced authros (hopefully, anyway). The changes make simple inventory a much more robust and feature-rich system, but unfortunately, old code written for v1.x of simple inventory is not compatible with the new simple inventory system.
The options object can be found near the top of the script (in the pretty version). It looks like this:
var options = {
tryGlobal : true, // send constructor to global scope
defaultStrings : {
empty : 'The inventory is empty...',
listDrop : 'Discard',
separator : '\n'
}
};
It is recommended that you leave the tryGlobal option as true unless you know what you're doing.
Option tryGlobal
The functions, methods, and variables used by these systems all exist on the special SugarCube setup object. For ease of access to authors, everything that might be of use to them is then sent to the global scope as window.Inventory. If you don't want to send this object to the global scope, you can change this option to false.
📝 Note:
Even if this option is set to true, the script will check to make sure window.Inventory is undefined before overwriting it.
If the global Inventory object is unavailable, either because you changed this setting or because it was already in use, you can still access things: replace Inventory... with setup.Inventory... in your code, or create your own gobal reference.
Option defaultStings
This set of options represents the default strings used for certain situations:
empty: when the inventory is empty, this text is displayed instead of a list of items. You can use valid TwineScript syntax in the string, i.e. empty: "<<include 'EmptyMessagePassage'>>" would be a valid value.
listDrop: the inventory system includes a macro called <<linkedinventory>> for constructing a list of items with links that allow dropping and transfering items when clicked. These links' text should be set up in the macro, but you can set up default link text that will appear in case an invalid argument is passed; you can then pass an empty string ('') as a shortcut to display this as the link.
separator: when using the <<inventory>> macro or the <inventory>.show() method to display a list of items, you can determine how you want the items to be serparated when using those macros by supplying a string. If no string is supplied, this default separator is used instead (the default value of '\n' represents a newline in JavaScript).
Macros
<<newinventory>>
<<pickup>>
<<drop>>
<<dropall>>
<<clear>>
<<transfer>>
<<sort>>
<<inventory>>
<<linkedinventory>>
Functions and Methods
The following are the functions and methods that are included in the simple inventory. Most of these allow access to the simple inventory's features in pure JavaScript, while some of these features are only available through this JavaScript API: even if you aren't planning on interacting with this system through JavaScript, you should still read the documentation for Inventory.removeDuplicates(), <inventory>.has(), and <inventory>.hasAll(), all of which are either only available through JavaScript, or contain features that are only available for your TwineScript expressions through JavaScript.
JavaScript API
Inventory()
Inventory.is()
Inventory.log()
Inventory.removeDuplicates()
<inventory>.pickUp()
<inventory>.drop()
<inventory>.empty()
<inventory>.trasnfer()
<inventory>.has()
<inventory>.hasAll()
<inventory>.toArray()
<inventory>.count()
<inventory>.isEmpty()
<inventory>.sort()
<inventory>.show()
Tip
About chaining: Methods that don't return an explicit value will return the inventory they are called on (listed with the return value of 'this inventory' in the below documentation), meaning you can chain many of the instance method calls. For example, <inventory>.pickUp() adds items to the inventory, but doesn't need to return anything in specific, so it returns the inventory object is was called on and allows chaining. On the other hand, <inventory>.show() returns a string, so it can't be chained with other inventory methods. For example:
-> The following is valid:
<<print $inventory.pickUp('toothpick').show()>>
-> The following is not valid and will raise an error
<<run $inventory.show().pickUp('toothpick')>>
Events
The simple inventory automatically triggers one of two events as inventories are manipulated. You can use these events to perform functions and run other code in real time as the inventories are manipulated during gameplay. These events are also targetable by my <<event>> macro set.
The event object
When an event is fired, a variety of information is sent to the event handlers. That information is detailed here:
<event>.instance: A reference to the calling instance. In transfers, that's the giving inventory.
<event>.receiving: A reference to the receiving instance, if it exists (i.e. in <<transfer>> and <<linkedinventory>> calls), or null.
<event>.moved: An array of items that have been moved into or out of the calling inventory, or null if nothing was moved (for example, if items the player doesn't have were dropped, or a <<sort>> was used).
<event>.context: The context of the event: it's always one of the following strings:
'pickup': Some type of pickup action ocurred. Does not fire on items added with <<newinventory>> or similar.
'drop': Some type of drop action occured. Emptying or clearing the inventory also cause this context.
'transfer': A transfer between two inventories occured.
'initialized': A new inventory was created. If items were also added, they'll be in the <event>.moved property.
'sort': The inventory was sorted.
When defining an event handler, you can access these propertied on the event object like so:
$(document).on(':inventory-update', function (ev) {
alert('Context: ' + ev.context);
if (ev.moved && ev.moved.length) {
console.log(ev.moved.join(', '));
}
if (ev.context === 'transfer') {
console.log('a transfer happened!');
}
});
Event :inventory-init
This event is only triggered when a new inventory is defined. It's context is always 'initialized'.
Event :inventory-update
This event is triggered any time an inventory is altered, but not when it is created. In can never have the context 'initialized'.
Example Event Usage
Automatically updating inventories when to inventory link lists are on the same page:
$(document).on(':inventory-update', function (ev) {
if (ev.context !== 'transfer') {
// this event should only occur on transfer events
return;
}
// only the receiving inventory needs updated,
// but we'll update both for the sake of simplicity
$('.auto-update').each( function (i, el) {
// find the inventories marked for auto-updating
// get the macro's wrapper:
var $macro = $(el).find('.macro-linkedinventory');
// get the inventories:
var inv = State.getVar($macro.attr('data-self'));
var rec = false;
if ($macro.attr('data-rec')) {
rec = State.getVar($macro.attr('data-rec'));
}
// reconstruct the list via the `inventory#linkedList()` method
var $list = inv.linkedList(rec, $macro.attr('data-action'));
// empty the container and replace it
$(el).empty().append($list);
});
});
To use the above:
Items you're carrying:
@@.auto-update;<<linkedinventory '$player' '$room' 'Drop'>>@@
What's laying around in this room:
@@.auto-update;<<linkedinventory '$room' '$player' 'Take'>>@@
Live demo
Demo Twee code:
:: Start
<<newinventory '$playerInventory'>>\
You find a large door.
<<if $playerInventory.has('key')>>You use the old key to open the door.\
<<else>>You can't open the door without a key.<</if>>
<<pickup '$playerInventory' 'key'>>You find an old key.
<<if $playerInventory.has('key')>>You use the old key to open the door.\
<<else>>You can't open the door without a key.<</if>>