Your browser lacks required capabilities. Please upgrade it or switch to another to continue.
Loading…
,,,,<div style="text-align: center"><h2>Universal Inventory System Help File</h2>for <<=UInv.Version()>></div> <div style="text-align: center">''Please note that this help file is still a work in progress. More details and examples will be added as the code is finalized.''</div> This is the help file for the Universal Inventory System (or "UInv" for short) which is made for use in <a href="http://twinery.org/">Twine&nbsp;2</a> with the <a href="http://www.motoslave.net/sugarcube/2/">SugarCube&nbsp;2</a> story format. <<Title "General UInv Topics">> [[Introduction to UInv Concepts]] [[Getting Started]] [[Basic UInv Functions]] [[Function Cheat Sheet]] [[Glossary of Terms]] (not written yet) [[Efficient UInv Coding]] [[Primitive Variables vs Object Variables]] (incomplete) [[Arrays vs Generic Objects]] [[Error Handling]] [[Item Collision]] (not written yet) [[The UInv Data Structure]] [[UInv Safe Save Code]] [[Changelog]] <<Title "Builders">> [[Bag Builder]] (not yet implemented) [[Item Builder]] [[Table Builder]] [[Radial Menu Builder]] (not yet implemented) <<Title "Functions">> <<nobr>> <div class="accordion"> <h3>[[Bag Functions]]: (49 functions)</h3> <div><ul> <li>[[AddBag]]</li> <li>[[AddToBagPropertyValue]]</li> <li>[[BagExists]]</li> <li>[[BagHasAllProperties]]</li> <li>[[BagHasProperty]]</li> <li>[[BagMatchesDefault]]</li> <li>[[BagPropertyCount]]</li> <li>[[CopyAllItemsToBag]]</li> <li>[[CopyBag]]</li> <li>[[CopyBagProperty]]</li> <li>[[CreateBag]]</li> <li>[[DeleteBag]]</li> <li>[[DeleteBagProperty]]</li> <li>[[EmptyBag]]</li> <li>[[GetBagByProperty]]</li> <li>[[GetBagCount]]</li> <li>[[GetBagCountByDefaultType]]</li> <li>[[GetBagObject]]</li> <li>[[GetBagPropertyArray]]</li> <li>[[GetBagPropertyObject]]</li> <li>[[GetBagPropertyValue]]</li> <li>[[GetBagWherePropertyEquals]]</li> <li>[[GetBagWherePropertyGreaterThan]]</li> <li>[[GetBagWherePropertyLessThan]]</li> <li>[[GetBagWithHighestPropertyValue]]</li> <li>[[GetBagWithLowestPropertyValue]]</li> <li>[[GetBagsArray]]</li> <li>[[GetBagsArrayByProperty]]</li> <li>[[GetBagsArrayWherePropertyEquals]]</li> <li>[[GetBagsArrayWherePropertyGreaterThan]]</li> <li>[[GetBagsArrayWherePropertyLessThan]]</li> <li>[[GetBagsArrayWithAllProperties]]</li> <li>[[GetBagsArrayWithItem]]</li> <li>[[GetBagsDefaultType]]</li> <li>[[GetCurrentBagName]]</li> <li>[[GetDefaultBagObject]]</li> <li>[[GetTotalBagPropertyValue]]</li> <li>[[GetUniqueBagName]]</li> <li>[[MergeBags]]</li> <li>[[MoveAllItemsToBag]]</li> <li>[[MoveBagPropertyValueToBag]]</li> <li>[[MoveItemPropertyValueToBag]]</li> <li>[[RenameBag]]</li> <li>[[SetBagPropertyValue]]</li> <li>[[SetBagTouched]]</li> <li>[[SetBagUntouched]]</li> <li>[[SetBagsDefaultType]]</li> <li>[[SetCurrentBagName]]</li> <li>[[WasTouched]]</li> </ul></div> <h3>[[Pocket/Container Functions]]: (24 functions)</h3> <div><ul> <li>[[AddExistingBagAsPocket]]</li> <li>[[AddPocket]]</li> <li>[[BagHasSpecificItem]]</li> <li>[[BagIsPocket]]</li> <li>[[ContainerHasItem]]</li> <li>[[ContainerHasPocketBag]]</li> <li>[[CreatePocket]]</li> <li>[[DeletePocket]]</li> <li>[[GetAllBagPockets]]</li> <li>[[GetAllContainerPockets]]</li> <li>[[GetContainerIndex]]</li> <li>[[GetItemPocketBagArray]]</li> <li>[[GetItemPocketBagName]]</li> <li>[[GetItemPocketNameArray]]</li> <li>[[GetItemPocketObject]]</li> <li>[[GetPocketBagContainerArray]]</li> <li>[[GetPocketBagsPocketName]]</li> <li>[[GetPocketDepth]]</li> <li>[[ItemHasPocket]]</li> <li>[[MoveItemFromPocket]]</li> <li>[[MoveItemToPocket]]</li> <li>[[MovePocket]]</li> <li>[[UnlinkPocketBagFromContainer]]</li> <li>[[UnlinkPocketFromContainer]]</li> </ul></div> <h3>[[Item Functions]]: (85 functions, 2 left to complete)</h3> <div><ul> <li>[[AddItem]]</li> <li>AddItemCapped</li> <li>[[AddItems]]</li> <li>[[AddToAllItemsPropertyValue]]</li> <li>[[AddToItemPropertyValue]]</li> <li>[[BagHasAllItems]]</li> <li>[[BagHasAnyItem]]</li> <li>[[BagHasItem]]</li> <li>[[CopyItem]]</li> <li>[[CopyItemsByProperty]]</li> <li>[[CreateItem]]</li> <li>[[DeleteItem]]</li> <li>[[DeleteItemProperty]]</li> <li>[[DeleteItemsByProperty]]</li> <li>[[GetAllPropertyValues]]</li> <li>[[GetBagItemArrayWhereItemPropertyEquals]]</li> <li>[[GetCurrentItemName]]</li> <li>[[GetDefaultItemObject]]</li> <li>[[GetDefaultItemPropertyValue]]</li> <li>[[GetItemByProperty]]</li> <li>[[GetItemByType]]</li> <li>[[GetItemCount]]</li> <li>[[GetItemCountByDefaultType]]</li> <li>[[GetItemCountByFunction]]</li> <li>[[GetItemCountFull]]</li> <li>[[GetItemCountFullByDefaultType]]</li> <li>[[GetItemCountWherePropertyEquals]]</li> <li>[[GetItemCountWherePropertyGreaterThan]]</li> <li>[[GetItemCountWherePropertyLessThan]]</li> <li>[[GetItemObject]]</li> <li>[[GetItemPropertiesArray]]</li> <li>[[GetItemPropertyCount]]</li> <li>[[GetItemPropertyValue]]</li> <li>[[GetItemPropertyValueObject]]</li> <li>[[GetItemWherePropertyEquals]]</li> <li>[[GetItemWherePropertyGreaterThan]]</li> <li>[[GetItemWherePropertyLessThan]]</li> <li>[[GetItemWithHighestPropertyValue]]</li> <li>[[GetItemWithLowestPropertyValue]]</li> <li>[[GetItemsAndQuantitiesObject]]</li> <li>[[GetItemsArray]]</li> <li>[[GetItemsArrayByFunction]]</li> <li>[[GetItemsArrayByProperty]]</li> <li>[[GetItemsArrayByType]]</li> <li>[[GetItemsArraySortedByFunction]]</li> <li>[[GetItemsArraySortedByProperty]]</li> <li>[[GetItemsArrayWhereItemNameContains]]</li> <li>[[GetItemsArrayWherePropertyEquals]]</li> <li>[[GetItemsArrayWherePropertyGreaterThan]]</li> <li>[[GetItemsArrayWherePropertyLessThan]]</li> <li>[[GetItemsArrayWherePropertyValueContains]]</li> <li>[[GetItemsArrayWithAllProperties]]</li> <li>[[GetItemsArrayWithoutProperties]]</li> <li>[[GetItemsDefaultType]]</li> <li>[[GetMatchingItemsArray]]</li> <li>[[GetObjectOfItemPropertyValues]]</li> <li>[[GetRandomItem]]</li> <li>[[GetRandomItemPropertyValue]]</li> <li>[[GetRandomItemValue]]</li> <li>[[GetTotalItemPropertyValue]]</li> <li>[[GetUniqueItemName]]</li> <li>[[GetUniqueItemPropertyValuesArray]]</li> <li>[[ItemExists]]</li> <li>[[ItemHasAllProperties]]</li> <li>[[ItemHasAnyProperties]]</li> <li>[[ItemHasProperty]]</li> <li>[[ItemPropertyHasValue]]</li> <li>[[ItemsMatch]]</li> <li>[[MoveItem]]</li> <li>MoveItems</li> <li>[[MoveBagPropertyValueToItem]]</li> <li>[[MoveItemPropertyValueToItem]]</li> <li>[[MoveItemsByProperty]]</li> <li>[[RenameItem]]</li> <li>[[RenameItemProperty]]</li> <li>[[ResetItemProperties]]</li> <li>[[RestackItems]]</li> <li>[[SetCurrentItemName]]</li> <li>[[SetItemPropertyValue]]</li> <li>[[SetItemPropertyValues]]</li> <li>[[SetItemQuantity]]</li> <li>[[SetItemsDefaultType]]</li> <li>[[SetItemsPropertyValue]]</li> <li>[[SwapItems]]</li> <li>[[SwapItemsProperties]]</li> </ul></div> <h3>[[Tag Functions]]: (49 functions)</h3> <div><ul> <li>[[AddBagTag]]</li> <li>[[AddItemTag]]</li> <li>[[ArrayHasAllItemTags]]</li> <li>[[BagHasAllBagTags]]</li> <li>[[BagHasAllItemTags]]</li> <li>[[BagHasAnyBagTag]]</li> <li>[[BagHasAnyItemTag]]</li> <li>[[BagHasItemByBagTag]]</li> <li>[[BagHasAllItemsByBagTag]]</li> <li>[[BagHasAnyItemByBagTag]]</li> <li>[[BagHasItemByItemTag]]</li> <li>[[BagHasItemWithAllItemTags]]</li> <li>[[BagHasItemWithAnyItemTag]]</li> <li>[[BagHasItemWithoutAllItemTags]]</li> <li>[[BagHasItemWithoutAnyItemTags]]</li> <li>[[BagHasTag]]</li> <li>[[CopyItemsByItemTag]]</li> <li>[[DeleteBagTag]]</li> <li>[[DeleteItemsByItemTag]]</li> <li>[[DeleteItemTag]]</li> <li>[[GetAllUniqueItemTagsArray]]</li> <li>[[GetBagsArrayByBagTag]]</li> <li>[[GetBagsArrayWithBothBagTags]]</li> <li>[[GetBagsArrayWithItemByBagTag]]</li> <li>[[GetBagTagQuantityObject]]</li> <li>[[GetFullItemCountByAllItemTags]]</li> <li>[[GetFullItemCountByAnyItemTag]]</li> <li>[[GetItemsArrayByAllItemTags]]</li> <li>[[GetItemsArrayByAnyItemTag]]</li> <li>[[GetItemsArrayByItemTag]]</li> <li>[[GetItemsArrayWithAllItemTags]]</li> <li>[[GetItemsArrayWithBothItemTags]]</li> <li>[[GetItemsArrayWithMostItemTags]]</li> <li>[[GetItemsArrayWithoutAllItemTags]]</li> <li>[[GetItemsArrayWithoutAnyItemTags]]</li> <li>[[GetItemTagCount]]</li> <li>[[GetItemTagQuantityObject]]</li> <li>[[GetMissingBagTagsArray]]</li> <li>[[GetMissingItemTagsArray]]</li> <li>[[GetRandomBagTagFromRange]]</li> <li>[[GetRandomItemTagFromRange]]</li> <li>[[GetUniqueBagTagsArray]]</li> <li>[[GetUniqueItemTagsArray]]</li> <li>[[MoveItemsByItemTag]]</li> <li>[[ItemHasAllTags]]</li> <li>[[ItemHasAnyTag]]</li> <li>[[ItemHasTag]]</li> <li>[[SetBagTag]]</li> <li>[[SetItemTag]]</li> </ul></div> <h3>[[Display Functions]]: (16 functions + 2 display elements, 1 function to complete)</h3> <div><ul> <li>[[AddEventHandler]]</li> <li>[[CallEventHandler]]</li> <li>[[CallEventHandlerEx]]</li> <li>[[DecrementUpdateLock]]</li> <li>[[DeleteEventHandler]]</li> <li>[[DisplayArray]]</li> <li>[[DisplayItemList]]</li> <li>[[DisplayRadialMenu]]</li> <li>[[FixTableCells]]</li> <li>GetElementVisibility</li> <li>[[GetEventHandlerByID]]</li> <li>[[GetMatchingEventHandlersArray]]</li> <li>[[GetUpdateLocks]]</li> <li>[[IncrementUpdateLock]]</li> <li>[[UpdateDisplay]]</li> <li>[[UpdatesAreLocked]]</li> <li>Table Element</li> <li>Radial Menu Element</li> <li>(total will probably be around 16-20 functions + 1 macro + 8 display elements)</li> </ul></div> <h3>[[Other UInv Functions and Macros]]: (7 functions + 2 macros)</h3> <div><ul> <li>[[ClearErrors]]</li> <li>[[GetLastError]]</li> <li>[[GetUserAlerts]]</li> <li>[[Initialize]]</li> <li>[[SetUserAlerts]]</li> <li>[[SetMergeItemMethod]]</li> <li>[[Version]]</li> <li>[[UInvSet Macro]]</li> <li>[[UInvTry Macro]]</li> </ul></div> <h3>[[UInv Utility Functions]]: (63 functions, 1 left to complete)</h3> <div><ul> <li>[[addArticle]]</li> <li>[[arrayObjectIncludes]]</li> <li>[[arraysAreEqual]]</li> <li>[[arrayHasAllTags]]</li> <li>[[arrayHasAnyTag]]</li> <li>[[arrayHasTag]]</li> <li>[[cacheImages]]</li> <li>[[combineGenericObjects]]</li> <li>[[docHasCSSElement]]</li> <li>[[flushAllCachedImages]]</li> <li>[[flushCachedImages]]</li> <li>[[getArrayReverseSortedByOtherArray]]</li> <li>[[getArraySortedByOtherArray]]</li> <li>[[getCachedImageObject]]</li> <li>[[getObjectProperties]]</li> <li>[[getRandomHexString]]</li> <li>[[getUniqueArray]]</li> <li>[[integerToOrdinal]]</li> <li>[[isArray]]</li> <li>[[isArrayOfArrays]]</li> <li>[[isArrayOfBooleans]]</li> <li>[[isArrayOfDates]]</li> <li>[[isArrayOfGenericObjects]]</li> <li>[[isArrayOfIntegers]]</li> <li>[[isArrayOfMaps]]</li> <li>[[isArrayOfNumbers]]</li> <li>[[isArrayOfObjects]]</li> <li>[[isArrayOfSets]]</li> <li>[[isArrayOfStrings]]</li> <li>[[isArrayOfType]]</li> <li>[[isBoolean]]</li> <li>[[isDate]]</li> <li>[[isFunction]]</li> <li>[[isGenericObject]]</li> <li>[[isInteger]]</li> <li>[[isMap]]</li> <li>[[isNumber]]</li> <li>[[isObject]]</li> <li>[[isProperty]]</li> <li>[[isRegExp]]</li> <li>[[isSet]]</li> <li>[[isString]]</li> <li>[[isUndefined]]</li> <li>[[mapsAreEqual]]</li> <li>[[numberToAPString]]</li> <li>[[objectsAreEqual]]</li> <li>sanitizeString</li> <li>[[setsAreEqual]]</li> <li>[[setsMatch]]</li> <li>[[spread]]</li> <li>[[valuesAreEqual]]</li> <li>[[Engine Detection]] (12 functions)</li> </ul></div> </div> <</nobr>> ''AddToBagPropertyValue(BagName, BagPropertyName, Amount)'' Add an amount to a property's value (returns true), create that property if it doesn't exist (returns false), or return {{{undefined}}} on error. ''GetBagCount()'' Returns the number of bags. ''BagExists(BagName/Array)'' = t/f Returns {{{true}}} if bag exists/all bags in array exist, otherwise returns {{{false}}}, or {{{undefined}}} on error. Unlike [[ItemExists]], this function does NOT check [[GetDefaultBagObject]] to see if a default bag by that name exists. ''BagHasProperty(BagName, BagPropertyName/Array)'' = t/f Returns true if bag's property exists, otherwise returns false, or {{{undefined}}} on error.''BagPropertyCount(BagName)'' = number of BagName's properties, or {{{undefined}}} on error. Returns the number of BagName's properties, or {{{undefined}}} on error. <center><h2>Bag Functions</h2></center> - [[AddBag]](BagName, [DefaultBagType]) - [[AddToBagPropertyValue]](BagName, BagPropertyName, Amount) - [[BagExists]](BagName/Array) - [[BagHasAllProperties]](BagName, BagPropertyNameArray) - [[BagHasProperty]](BagName, BagPropertyName/Array) - [[BagMatchesDefault]](BagName) - [[BagPropertyCount]](BagName) - [[CopyAllItemsToBag]](SourceBagName, DestinationBagName) - [[CopyBag]](ExistingBagName, NewBagName) - [[CopyBagProperty]](SourceBagName, DestinationBagName, BagPropertyName/Array) - [[CreateBag]](BagName) - [[DeleteBag]](BagName) - [[DeleteBagProperty]](BagName, BagPropertyName) - [[EmptyBag]](BagName) - [[GetBagByProperty]](BagPropertyName) - [[GetBagCount]]() - [[GetBagCountByDefaultType]]() - [[GetBagObject]](BagName) - [[GetBagPropertyArray]](BagName) - [[GetBagPropertyObject]](BagName) - [[GetBagPropertyValue]](BagName, BagPropertyName) - [[GetBagsArrayByProperty]](BagPropertyName, [BagNameArray]) - [[GetBagsArray]]() - [[GetBagsArrayWherePropertyEquals]](BagPropertyName, Value) - [[GetBagsArrayWherePropertyGreaterThan]](BagPropertyName, Value) - [[GetBagsArrayWherePropertyLessThan]](BagPropertyName, Value) - [[GetBagsArrayWithAllProperties]](BagPropertyNameArray) - [[GetBagsArrayWithItem]](ItemName, [BagArray]) - [[GetBagsDefaultType]](BagName) - [[GetBagWherePropertyEquals]](BagPropertyName, Value) - [[GetBagWherePropertyGreaterThan]](BagPropertyName, Value) - [[GetBagWherePropertyLessThan]](BagPropertyName, Value) - [[GetBagWithHighestPropertyValue]](BagPropertyName, [BagNameArray]) - [[GetBagWithLowestPropertyValue]](BagPropertyName, [BagNameArray]) - [[GetCurrentBagName]]() - [[GetDefaultBagObject]](DefaultBagType) - [[GetTotalBagPropertyValue]](BagPropertyName, [BagNameArray]) - [[GetUniqueBagName]]() - [[MergeBags]](SourceBagName, DestinationBagName) - [[MoveAllItemsToBag]](SourceBagName, DestinationBagName) - [[MoveBagPropertyValueToBag]](SourceBagName, SourceBagPropertyName, DestinationBagName, [DestinationBagPropertyName], [Amount], [MinimumValue], [MaximumValue], [DeletionValue], [DeletionType]) - [[MoveItemPropertyValueToBag]](SourceBagName, SourceItemName, SourceItemPropertyName, DestinationBagName, [DestinationBagPropertyName], [Amount], [MinimumValue], [MaximumValue], [DeletionValue], [DeletionType]) - [[RenameBag]](CurrentBagName, NewBagName) - [[SetCurrentBagName]](BagName) - [[SetBagPropertyValue]](BagName/Array, BagPropertyName, Value) - [[SetBagsDefaultType]](BagName, DefaultBagType) - [[SetBagTouched]](BagName/Array) - [[SetBagUntouched]](BagName/Array) - [[WasTouched]](BagName)''CopyAllItemsToBag(SourceBagName, DestinationBagName)'' Copies all items from source to destination. Copies all items from source to destination and returns an array of all of the new item names, or {{{undefined}}} on error. The UInvMergeItemMethod setting determines what happens on item collision. See [[SetMergeItemMethod]] for details. ''CopyBag(ExistingBagName, NewBagName)'' Creates a new bag named NewBagName if that bag doesn't exist already, and copies ExistingBagName into it. If the existing bag was a pocket, the copy will ''NOT'' be a pocket. Returns true if it succeeded, or {{{undefined}}} on error. The copied bag will be marked as "untouched", even if the bag it was copied from was marked as "touched". See [[WasTouched]] for details. See also: [[AddBag]] and [[CreateBag]] ''CopyBagProperty(SourceBagName, DestinationBagName, BagPropertyName/Array)'' overwrites existing properties Copies a bag property from one bag to another, overwriting the destination if that property is already there. Returns {{{true}}} on success or {{{undefined}}} on error. <center><h2>CreateBag</h2></center>__Format:__ ''CreateBag(''<<hovertip "''BagName'' must be a string, and cannot be \"\" (an empty string), \"-\" (a dash), or the name of an existing bag.">>''BagName''<</hovertip>>'')'' __Short Description:__ Creates a new bag with no properties or items. __Returns:__ {{{true}}} on success.<span style="float: right;">__Added:__ ''UInv v1.0.0''</span> __Sets:__ ''CurrentBag'' = ''BagName'', ''UInvTouched'' on ''BagName'' = {{{false}}} __See Also:__ [[AddBag]], [[CopyBag]], [[GetDefaultBagObject]], and [[DeleteBag]]. <<Title "Details">> ''CreateBag'' creates a bag named ''BagName'' as long as a bag with that name doesn't exist already. Returns {{{true}}} on success or {{{undefined}}} on error. Sets ''UInvTouched'' on that bag to {{{false}}} (see [[WasTouched]] for details). This function is used to create generic bags which do not have a pre-defined type. If you want to create a bag which has predefined properties and/or items, use the [[AddBag]] function instead. ''BagName'' must be a string, and it cannot be "-" (a dash) or "" (an empty string). There cannot already be a bag with that name. If either of these conditions are not met, the function will fail, triggering an error and returning {{{undefined}}}. <<Title "Sample Code">> The sample code below assumes you've added default bag types named "''inventory''" and "''backpack''" to the UInv [[BagData]] code. {{{ /* Create a bag named "inventory" with no default type. */ <<run UInv.CreateBag("inventory")>> }}} {{{ /* Attempt to create a bag named "backpack" and verify that it worked. */ <<set _BagName = "backpack">> <<if UInv.CreateBag(_BagName)>> Successfully created a bag named "_BagName"! <<else>> /* CreateBag failed, so show the error message explaining why. */ $UInvLastErrorMessage <</if>> }}} <<Title "Error Cases">> ''CreateBag(BagName)'' will throw an error if: * a bag named ''BagName'' already exists * ''BagName'' is ''not'' a string * ''BagName'' is {{{""}}} (an empty string) or {{{"-"}}} (a dash) ''DeleteBag(BagName/Array)'' Deletes bag or all bags in array entirely, including all items in the bag(s). Returns {{{true}}} if successful or {{{undefined}}} on error. ''DeleteBagProperty(BagName, BagPropertyName)'' Deletes bag property BagPropertyName. Returns true if successful or {{{undefined}}} on error. If the property to be deleted is a default property, then the bag's default type will change to "-", unless "UInvVariableType" is also one of its properties. (You can use [[SetBagPropertyValue]] if you want to add a "UInvVariableType" property to the bag.) ''NOTE:'' Deleting the "UInvVariableType" property may lead to bag properties having variable values each time you check them if you have defined them to have variable values in the [[BagData]] function. It's recommended that you ''DO NOT'' delete this property if it exists. See [[GetDefaultBagObject]] for details. ''EmptyBag(BagName)'' Deletes all items from bag. Returns {{{true}}} if successful or {{{undefined}}} on error. ''GetBagByProperty(BagPropertyName)'' = get a random BagName that has property BagPropertyName Returns a random BagName that has property BagPropertyName or {{{undefined}}} on error. ''GetBagPropertyValue(BagName, BagPropertyName)'' (alias: GetBagProp) Return a bag's property value or {{{undefined}}} on error. ''GetBagPropertyArray(BagName)'' = array of all properties a bag has. Return an array of all bag's property names or {{{undefined}}} on error. ''GetBagsArrayByProperty(BagPropertyName, [BagNameArray])'' = array of BagNames that have property BagPropertyName (within the set of BagNameArray if parameter is included) Returns an array of BagNames that have property BagPropertyName or {{{undefined}}} on error. ''GetBagsArray()'' = an array of all bag names (alias: BagArray) Returns an array of all bag names. ''NOTE:'' UInv stores the bags as an object, which means that the order that the bags are returned may possibly vary. If you require that the bags in the array are in the same order each time (assuming no bags are added or removed) you can do something like this: {{{<<set _Arr = UInv.GetBagsArray().sort()>>}}} That will set the _Arr temporary variable equal to the list of bag names, with the names sorted by the JavaScript array "sort()" function. ''GetBagsArrayWherePropertyEquals(BagPropertyName, Value)'' = array of BagNames where BagPropertyName value == Value Returns an array of all BagNames where BagPropertyName's value === Value, returns [] if none found, or {{{undefined}}} on error. ''GetBagsArrayWherePropertyGreaterThan(BagPropertyName, Value)'' = array of BagNames where BagPropertyName value > Value Returns an array of all BagNames where BagPropertyName > Value, returns [] if none found, or {{{undefined}}} on error. ''GetBagsArrayWherePropertyLessThan(BagPropertyName, Value)'' = array of BagNames where BagPropertyName value < Value Returns an array of all BagNames where BagPropertyName < Value, returns [] if none found, or {{{undefined}}} on error. ''GetBagsArrayWithItem(ItemName, [BagArray])'' = array of BagNames that have item (limited to items in BagArray bags if BagArray is passed to function) Returns an array of BagNames that have item (limited to items in BagArray bags if BagArray is passed to function), or {{{undefined}}} on error. ''GetBagWherePropertyEquals(BagPropertyName, Value)'' = BagName (get a random BagName where BagPropertyName == Value) Returns a random BagName where BagPropertyName === Value, returns "" if not found, or {{{undefined}}} on error. Sets that bag as the current bag. ''GetBagWherePropertyGreaterThan(BagPropertyName, Value)'' = BagName (get a random BagName where BagPropertyName > Value) Returns a random BagName where BagPropertyName > Value, returns "" if not found, or {{{undefined}}} on error. Sets that bag as the current bag. ''GetBagWherePropertyLessThan(BagPropertyName, Value)'' = BagName (get a random BagName where BagPropertyName < Value) Returns a random BagName where BagPropertyName < Value, returns "" if not found, or {{{undefined}}} on error. Sets that bag as the current bag. ''GetBagWithHighestPropertyValue(BagPropertyName, [BagNameArray])'' = BagName (bags without BagPropertyName are ignored); randomly pick one of the highest if multiple bags are tied for highest Returns the BagName with the highest value on BagPropertyName (bags without BagPropertyName are ignored), randomly picks one of the highest if multiple bags are tied for highest, "" if none found, or {{{undefined}}} on error. ''GetBagWithLowestPropertyValue(BagPropertyName, [BagNameArray])'' = BagName (bags without BagPropertyName are ignored); randomly pick one of the lowest if multiple bags are tied for lowest Returns the BagName with the lowest value on BagPropertyName (bags without BagPropertyName are ignored), randomly picks one of the lowest if multiple bags are tied for lowest, "" if none found, or {{{undefined}}} on error. ''GetUniqueBagName()'' returns a name not used by any bag currently ("bag0ffd39" 0-255 in hex * 3) Generates and returns an unused bag name ("bagXXHEXX"). ''MergeBags(SourceBagName, DestinationBagName)'' Moves all items from source to destination and deletes source. Moves all items from source to destination and deletes source. Returns {{{undefined}}} on error. The UInvMergeItemMethod setting determines what happens on item collision. See [[SetMergeItemMethod]] for details. ''MoveAllItemsToBag(SourceBagName, DestinationBagName)'' Moves all items from source to destination. Moves all items from source to destination. Returns {{{undefined}}} on error. The UInvMergeItemMethod setting determines what happens on item collision. See [[SetMergeItemMethod]] for details. ''RenameBag(CurrentBagName, NewBagName)'' Renames CurrentBagName to NewBagName if that bag doesn't exist already. Returns true if it succeeded or {{{undefined}}} on error. ''SetCurrentBagName(BagName)'' Sets the UInvCurrentBagName to BagName for use as the default BagName parameter in UInv functions. Returns true on success or {{{undefined}}} on error. ''SetBagPropertyValue(BagName/Array, BagPropertyName, Value)'' sets bag property value, adds property if it doesn't exist (alias: SetBagValue) Add or change a bag property and set it to Value. Returns true if it succeeds or {{{undefined}}} on error. If you use this to add a "UInvVariableType" property, then this will allow you to delete a default property from the bag without changing the bag's default type (which would normally change to "-" in that case). See [[DeleteBagProperty]] and [[GetDefaultBagObject]] for details. ''SetBagTouched(BagName/Array)'' sets bag(s) as touched. Sets bag(s) to touched and returns true, or returns {{{undefined}}} on error. See also: [[WasTouched]] and [[SetBagUntouched]] ''SetBagUntouched(BagName/Array)'' sets bag(s) as untouched. Sets bag(s) to untouched and returns true, or {{{undefined}}} on error. See also: [[WasTouched]] and [[SetBagTouched]] ''WasTouched(BagName)'' = Whether items in bag have changed since creation or since Untouched was last set. Returns whether the number of items in the bag have changed since creation or since the bag was last marked as untouched using [[SetBagUntouched]], otherwise it returns {{{undefined}}} on error. This function can be used to determine if the bag has changed since it was created or since the last time [[SetBagUntouched]] was used to mark it as "untouched". See also: [[SetBagTouched]] and [[SetBagUntouched]] <center><h2>Item Functions</h2></center> - [[AddItem]](BagName, ItemType, [Quantity], [NewItemName]) - [[AddItems]](BagName, ItemArray) - [[AddToAllItemsPropertyValue]](BagName, ItemPropertyName, Amount) - [[AddToItemPropertyValue]](BagName, ItemName, ItemPropertyName, Amount) - [[BagHasAllItems]](BagName/Array, ItemNameArray) - [[BagHasAnyItem]](BagName/Array, ItemNameArray) - [[BagHasItem]](BagName/Array, ItemName) - [[CopyItem]](SourceBagName, DestinationBagName, ItemName, [Quantity], [NewItemName]) - [[CopyItemsByProperty]](SourceBagName, DestinationBagName, ItemProperty, [Value]) - [[CreateItem]](BagName, ItemName, [Quantity]) - [[DeleteItem]](BagName, ItemName/Array, [Quantity]) - [[DeleteItemProperty]](BagName/Array, ItemName, [ItemPropertyName]) - [[DeleteItemsByProperty]](BagName, ItemProperty, [Value]) - [[GetAllPropertyValues]](BagName, ItemPropertyName) - [[GetBagItemArrayWhereItemPropertyEquals]](BagNameArray, ItemPropertyName, Value) - [[GetCurrentItemName]]() - [[GetDefaultItemObject]](ItemName) - [[GetDefaultItemPropertyValue]](ItemName, ItemPropertyName) - [[GetItemByProperty]](BagName, ItemPropertyName) - [[GetItemByType]](BagName, ItemType) - [[GetItemCount]](BagName/Array) - [[GetItemCountByDefaultType]](BagName/Array) - [[GetItemCountByFunction]](BagName/Array, CountFunction) - [[GetItemCountFull]](BagName/Array) - [[GetItemCountFullByDefaultType]](BagName/Array, DefaultItemType) - [[GetItemCountWherePropertyEquals]](BagName/Array, ItemPropertyName, Value) - [[GetItemCountWherePropertyGreaterThan]](BagName/Array, ItemPropertyName, Value) - [[GetItemCountWherePropertyLessThan]](BagName/Array, ItemPropertyName, Value) - [[GetItemObject]](BagName, ItemName) - [[GetItemPropertiesArray]](BagName, ItemName) - [[GetItemPropertyCount]](BagName, ItemName) - [[GetItemPropertyValue]](BagName, ItemName, ItemPropertyName) - [[GetItemPropertyValueObject]](BagName, ItemPropertyName) - [[GetItemsAndQuantitiesObject]](BagName) - [[GetItemsArray]](BagName) - [[GetItemsArrayByFunction]](BagName, SelectionFunction) - [[GetItemsArrayByProperty]](BagName, ItemPropertyName) - [[GetItemsArrayByType]](BagName, ItemType) - [[GetItemsArraySortedByFunction]](BagName, SortFunction) - [[GetItemsArraySortedByProperty]](BagName, [ItemPropertyName]) - [[GetItemsArrayWhereItemNameContains]](BagName, SubString) - [[GetItemsArrayWherePropertyEquals]](BagName, ItemPropertyName, Value) - [[GetItemsArrayWherePropertyGreaterThan]](BagName, ItemPropertyName, Amount) - [[GetItemsArrayWherePropertyLessThan]](BagName, ItemPropertyName, Amount) - [[GetItemsArrayWherePropertyValueContains]](BagName, ItemPropertyName, SubString, [CaseSensitive]) - [[GetItemsArrayWithAllProperties]](BagName, ItemPropertyName/Array) - [[GetItemsArrayWithoutProperties]](BagName, ItemPropertyName/Array) - [[GetItemsDefaultType]](BagName, ItemName) - [[GetItemWherePropertyEquals]](BagName, ItemPropertyName, Value) - [[GetItemWherePropertyGreaterThan]](BagName, ItemPropertyName, Amount) - [[GetItemWherePropertyLessThan]](BagName, ItemPropertyName, Amount) - [[GetItemWithHighestPropertyValue]](BagName, ItemPropertyName) - [[GetItemWithLowestPropertyValue]](BagName, ItemPropertyName) - [[GetMatchingItemsArray]](BagName, ItemName, SearchBag, [PropertyExceptionArray]) - [[GetObjectOfItemPropertyValues]](BagName, ItemPropertyName) - [[GetRandomItem]](BagName) - [[GetRandomItemPropertyValue]](BagName, ItemPropertyName) - [[GetRandomItemValue]](BagName, ItemPropertyName) - [[GetTotalItemPropertyValue]](BagName, ItemPropertyName) - [[GetUniqueItemName]]() - [[GetUniqueItemPropertyValuesArray]](BagName/Array, ItemPropertyName) - [[ItemExists]](ItemName) - [[ItemHasAllProperties]](BagName, ItemName, ItemPropertyNameArray) - [[ItemHasAnyProperties]](BagName, ItemName, ItemPropertyNameArray) - [[ItemHasProperty]](BagName, ItemName, ItemPropertyName) - [[ItemPropertyHasValue]](BagName, ItemName, ItemPropertyName, Value) - [[ItemsMatch]](BagName1, ItemName1, BagName2, ItemName2, [PropertyExceptionArray]) - [[MoveItem]](SourceBagName, DestinationBagName, ItemName, [Quantity], [NewItemName]) - [[MoveBagPropertyValueToItem]](SourceBagName, SourceBagPropertyName, DestinationBagName, DestinationItemName, [DestinationItemPropertyName], [Amount], [MinimumValue], [MaximumValue], [DeletionValue], [DeletionType]) - [[MoveItemPropertyValueToItem]](SourceBagName, SourceItemName, SourceItemPropertyName, DestinationBagName, DestinationItemName, [DestinationItemPropertyName], [Amount], [MinimumValue], [MaximumValue], [DeletionValue], [DeletionType]) - [[MoveItemsByProperty]](SourceBagName, DestinationBagName, ItemProperty, [Value]) - [[RenameItem]](BagName, CurrentItemName, NewItemName, [Quantity]) - [[RenameItemProperty]](BagName, ItemName, CurrentItemPropertyName, NewItemPropertyName) - [[ResetItemProperties]](BagName/Array, ItemName, [DefaultItemName]) - [[RestackItems]](BagName) - [[SetCurrentItemName]](ItemName) - [[SetItemPropertyValue]](BagName, ItemName, ItemPropertyName, Value) - [[SetItemPropertyValues]](BagName, ItemName, ValueObject) - [[SetItemQuantity]](BagName, ItemName, Quantity) - [[SetItemsDefaultType]](BagName, ItemName, DefaultItemType) - [[SetItemsPropertyValue]](BagName, ItemPropertyName, Value) - [[SwapItems]](BagName1, ItemName1, BagName2, ItemName2, [ExceptItemPropertyName/array]) - [[SwapItemsProperties]](BagName1, ItemName1, BagName2, ItemName2, ItemPropertyName/array) ''AddItem(BagName, ItemType, [Quantity], [NewItemName])'' adds an item using [[GetDefaultItemObject]], default Quantity = 1 Adds a predefined item to bag. Returns the new item's name if it succeeds, or {{{undefined}}} on error. You pre-define the default properties for your item types in the UInv [[ItemData]] code. For more information on default bag types see [[GetDefaultItemObject]]. For help creating default bags, see the [[Item Builder]]. If a matching item (see [[ItemsMatch]]) in the bag already exists, this function will increment the quantity of that item, unless one or both items have pockets, in which case it will randomly choose a new item name (see [[GetUniqueItemName]]), add the item as that new name, and then return that new name. If you want to create an item from scratch you should use the [[CreateItem]] function instead. Items are defined in the [[ItemData]] function. See [[GetDefaultItemObject]] for details. To create an item from scratch, use the [[CreateItem]] function instead. {{{Quantity}}} is an optional parameter, which defaults to {{{1}}}. If included, the {{{Quantity}}} parameter must be a positive integer. If you want to reduce the number of items, use [[DeleteItem]]. If you want to set the number of items, use [[SetItemQuantity]] instead. If you want to modify the number of items, and delete the item if the number remaining is less than one, then use [[AddToItemPropertyValue]] on the item's {{{UInvQuantity}}} property. If {{{NewItemName}}} is ''not'' set, then {{{ItemType}}} will also be the item's name. If {{{NewItemName}}} ''is'' set, then the item gets {{{NewItemName}}} as its name, but it uses the default item type of {{{ItemType}}}. The name of the new item cannot be "UInvTouched", "UInvProperties", "UInvDefaultBagType", "UInvContainer", "-" (the minus sign), or "" (an empty string). If you plan on refering to item property names using dot notation (i.e. {{{$variable.property}}}), then the names should only be made up of A - Z, a - z, _, and $, and also cannot start with a number. The UInvMergeItemMethod setting determines what happens on item collision. See [[SetMergeItemMethod]] for details. ''NOTE:'' Changing the quantity of any item in a bag will cause that bag to be marked as "touched" until you call [[SetBagUntouched]]. This way you can determine if the number of any items in a bag have changed since the last time it was marked as "untouched". See [[WasTouched]] for details. ''AddItems(BagName, ItemArray)'' Adds an array of items to bag (Quantity = 1 for each). If you want to add more than one of an item, use [[AddItem]] instead. Returns {{{undefined}}} if illegal property values were passed to ''AddItems'', returns {{{false}}} if any items failed to be added, otherwise it returns an array of all of the new item names. The UInvMergeItemMethod setting determines what happens on item collision. See [[SetMergeItemMethod]] for details. ''NOTE:'' Changing the quantity of any item in a bag will cause that bag to be marked as "touched" until you call [[SetBagUntouched]]. This way you can determine if the number of any items in a bag have changed since the last time it was marked as "untouched". See [[WasTouched]] for details. ''AddToItemPropertyValue(BagName, ItemName, ItemPropertyName, Amount)'' adds amount to property's value Add an amount to a property's value (returns true), create that property if it doesn't exist (returns false), or return {{{undefined}}} on error. Does not touch bag unless UInvQuantity changed. Deletes item if UInvQuantity would become <= 0. __If you're using pockets:__ The ''UInvQuantity'' property cannot be set above one for items that have pockets. ''BagHasAllItems(BagName/Array, ItemNameArray)'' = t/f if bag/s has/have all of the items in ItemNameArray Returns t/f based on whether the bag has all of the items in the bag, or {{{undefined}}} on error. ''BagHasAnyItem(BagName/Array, ItemNameArray)'' = t/f if bag/s has/have any of the items in ItemNameArray Returns t/f based on whether the bag has any of the items in the bag, or {{{undefined}}} on error. ''BagHasItem(BagName/Array, ItemName)'' = Quantity [alias: GetItemQuantity, HasItem, ItemQuantity] Returns the number of ItemName items in BagName, or {{{undefined}}} on error. ''CopyItem(SourceBagName, DestinationBagName, ItemName, [Quantity], [NewItemName])'' Quantity = amount to add, default to same quantity, NewItemName must be used if source and destination bags are the same Copy item from source to destination (not including the ''UInvCell'' property), changing the ''UInvQuantity'' property if the ''Quantity'' parameter is used. Returns the new item's name if it succeeds, or {{{undefined}}} on error. If {{{NewItemName}}} is ''not'' set, then {{{ItemName}}} will also be the item's name. If {{{NewItemName}}} ''is'' set, then the item gets {{{NewItemName}}} as its name, but otherwise it will be identical to the default {{{ItemName}}} object. The name of the new item cannot be "UInvTouched", "UInvProperties", "UInvDefaultBagType", "UInvContainer", "-" (the minus sign), or "" (an empty string). If you plan on refering to item property names using dot notation (i.e. {{{$variable.property}}}), then the names should only be made up of A - Z, a - z, _, and $, and also cannot start with a number. The UInvMergeItemMethod setting determines what happens on item collision. See [[SetMergeItemMethod]] for details. ''NOTE:'' If this is a variable item (i.e. it has a "UInvVariableType" property) then the item copied will try to merge with other identical items of the same type, and failing that will merge using the UInv.MERGE_RENAME_SOURCE_ITEMNAME method. See [[GetDefaultItemObject]] for more information on variable items. ''NOTE:'' Changing the quantity of any item in a bag will cause that bag to be marked as "touched" until you call [[SetBagUntouched]]. This way you can determine if the number of any items in a bag have changed since the last time it was marked as "untouched". See [[WasTouched]] for details. ''CreateItem(BagName, ItemName, [Quantity])'' create new item instead of pulling from GetDefaultItemObject function Creates an item from scratch (does not link to a {{{DefaultItemObject}}} type). {{{Quantity}}} defaults to 1. Returns (the potentially modified) ''ItemName'' on success or {{{undefined}}} on error. The ''ItemName'' may be changed if the original name wasn't in lowercase. To add a predefined item, use the [[AddItem]] function instead. ''NOTE:'' Changing the quantity of any item in a bag will cause that bag to be marked as "touched" until you call [[SetBagUntouched]]. This way you can determine if the number of any items in a bag have changed since the last time it was marked as "untouched". See [[WasTouched]] for details. ''DeleteItem(BagName, ItemName/Array, [Quantity])'' if no Quantity then remove all. Deletes "Quantity" items from bag, returns {{{true}}} if successful or {{{undefined}}} on error. Quantity is an integer, defaults to deleting all items, has a floor of 0, and a max of the item's UInvQuantity. DeleteItem does not throw an error if ItemName doesn't exist, since that item is basically already deleted. ''NOTE:'' Changing the quantity of any item in a bag will cause that bag to be marked as "touched" until you call [[SetBagUntouched]]. This way you can determine if the number of any items in a bag have changed since the last time it was marked as "untouched". See [[WasTouched]] for details. ''DeleteItemProperty(BagName/Array, ItemName, [ItemPropertyName])'' cannot delete ItemPropertyName "UInvQuantity", "UInvDefaultItemType", or "UInvPocket", also deleting a property of a default item will return that property to its default value Deletes the item property ItemPropertyName. If ItemPropertyName is not passed, then it deletes all properties on ItemName, except UInvQuantity, UInvPocket, and sets the UInvDefaultItemType to "-". If you delete a default item property, then the default item type of the item will change to "-", unless the item has a "UInvVariableType" property. (You can use [[SetItemPropertyValue]] to add a "UInvVariableType" property.) DeleteItemProperty cannot delete UInvQuantity or UInvDefaultItemType. Returns true if successful or {{{undefined}}} on error. ''NOTE:'' Deleting the "UInvVariableType" property may lead to item properties having variable values each time you check them if you have defined them to have variable values in the [[ItemData]] function. It's recommended that you ''DO NOT'' delete this property if it exists. See [[GetDefaultItemObject]] for details. ''GetAllPropertyValues(BagName, ItemPropertyName)'' = [ array of all unique values that property has ] Returns an array of all unique values of the items' ItemPropertyName in a bag or {{{undefined}}} on error. ''GetDefaultItemObject(DefaultItemType)'' = item object Returns the item object which matches ''DefaultItemType'', {{{null}}} for unknown item types, or {{{undefined}}} on error. (Both {{{null}}} and {{{undefined}}} have "falsey" values.) If the returned item would normally have pockets then instead the {{{UInvPocket}}} property will be an object containing {{{PocketName : BagType}}} pairs (the {{{BagType}}} will be {{{-}}} if it's a generic bag without a default type). Normally you won't call this function yourself, but UInv uses it in [[AddItem]] and [[AddItems]] to add that item to a bag, and in other functions to check the default properties of the items you added. You set the default item properties in UInv's [[ItemData]] function, near the bottom of the UInv code. ''__IMPORTANT!:__'' * Items with consistent default property values are "static items". * Items with property values that may vary are "variable items". * Item names must be unique strings in all lowercase. * Item names cannot be "uinvtouched", "uinvproperties", "uinvdefaultbagtype", "uinvcontainer", "-" (the minus sign), or "" (an empty string), they're reserved for use by UInv. * Property names can be upper and/or lowercase strings. * Property names with spaces in them must be inside quotes. * Property names are case sensitive, so a property named "XYZ" is different from properties named "Xyz" or "xyz". * Item and property names cannot start with a number. * An item cannot have more than one property with the same name. * An item cannot have a property named "UInvQuantity" or "UInvDefaultItemType", they're reserved for use by UInv. * Property values can be strings, numbers, booleans, or arrays. * Objects and functions are unsupported property value types. * Quote marks inside strings need to have a backslash before them. (e.g. "Bob said, \"Hello.\"") * Backslashes will also need a backslash before them. Static items should be added in the following format to the "static items" section: {{{ Items.itemname = { property-name-string1 : property-value1, property-name-string2 : property-value2, ... }; }}} If the item name contains a space, then it should be in this format: {{{ Items['item name'] = { property-name-string1 : property-value1, property-name-string2 : property-value2, ... }; }}} For example: {{{ Items.shortsword = { singular : "a short sword", plural : "short swords", type : ["weapon", "slashing", "1-handed"], size : 4, magic: false, image : "SSword.jpg", thumb : "SSword_sm.jpg", description : "A shortsword." }; }}} If an item's properties are variable, then they should be set in the "variable items" section instead as follows: {{{ case "itemname": // Other code may go here. Item = { property-name-string1 : property-value1, property-name-string2 : property-value2, ... }; break; }}} ''NOTE:'' For variable items the property "UInvVariableType" has to be set to something (it doesn't matter what) in the item's properties. For example: {{{ case "rainbow potion": var color = ["red", "orange", "yellow", "green", "blue", "purple"].random(); // Randomly picks a color. var article = color === "orange" ? "an " : "a "; // Because this item's property values can vary, the "UInvVariableType" property has to be set to something. Item = { UInvVariableType : color, type : ["potion"], singular : article + color + " potion", plural : color + " potions", size : 1, image : color + "Potion.jpg", thumb : color + "Potion.jpg", description : "A " + color + " potion." }; break; }}} It's recommended (though not required) that you list your items in those two sections alphabetically both to help avoid duplicating names and to make them easier to find if you need to modify them later. If an item with the same name exists in both sections, the variable item will be preferred. If you need help creating static items, you can use the [[Item Builder]] to make sure everything is formatted correctly. Optionally, you can also put a list of default item names in the ''ItemList'' array at the bottom of the UInv code. ''GetDefaultItemPropertyValue(DefaultItemName, ItemPropertyName)'' = default value for item's property Returns the default value for item's property, {{{null}}} if property or item isn't found, or {{{undefined}}} if there is an error. ''NOTE:'' Values may vary if the property is defined to be a random value. ''GetItemWithHighestPropertyValue(BagName, ItemPropertyName)'' = ItemName (items without ItemPropertyName are ignored) Returns the ItemName with the highest value of ItemPropertyName in BagName (items without ItemPropertyName are ignored), randomly picks one of the highest if multiple items are tied for highest, "" if none found, or {{{undefined}}} on error. ''GetItemByProperty(BagName, ItemPropertyName)'' = get a random ItemName that has property ItemPropertyName Returns a random item from a bag that has property ItemPropertyName and sets that item as the current item, or returns {{{undefined}}} on error. ''GetItemCount(BagName/Array)'' = the number of unique items in each bag (ignores Quantity) Returns the number of unique items in a bag (not including UInvTouched and UInvProperties) or {{{undefined}}} on error. ''GetItemCountByFunction(BagName/Array, CountFunction)'' = returns the sum of the values returned by function (function is passed BagName) or {{{undefined}}} on error. (not written yet) ''GetItemCountFull(BagName/Array)'' = the total number of items in bag(s) (Quantity included) Returns the total number of items in a bag, adding up the UInvQuantity value of each item (not including UInvTouched and UInvProperties), or returns {{{undefined}}} on error. ''GetItemCountWherePropertyEquals(BagName/Array, ItemPropertyName, Value)'' Returns the numer of items in a bag which have a particular property value or {{{undefined}}} on error. ''GetItemCountWherePropertyGreaterThan(BagName/Array, ItemPropertyName, Value)'' Returns the numer of items in a bag which have a particular property value greater than Value or {{{undefined}}} on error. ''GetItemCountWherePropertyLessThan(BagName/Array, ItemPropertyName, Value)'' Returns the numer of items in a bag which have a particular property value less than Value or {{{undefined}}} on error. ''GetItemObject(BagName, ItemName)'' = item object Returns an item object from BagName that matches ItemName, or {{{undefined}}} on error. UInvQuantity will try to be the first property on the object. ''GetItemPropertyValueObject(BagName, ItemPropertyName)'' = { ItemName : ItemPropertyName's value, ... } (items that don't have ItemPropertyName are ignored) Returns an object in the format { ItemName : ItemPropertyName's value, ... } for each item in BagName that has the property ItemPropertyName. Items that don't have ItemPropertyName are ignored. Returns {{{undefined}}} on error. ''GetItemPropertiesArray(BagName, ItemName)'' = Array of all properties on item in bag Returns an array of ItemName's item property names from BagName, or {{{undefined}}} on error. UInvQuantity will be item 0 in array. ''NOTE:'' UInv stores the properties as an object, which means that the order that the properties are returned may possibly vary. If you require that the properties in the array are in the same order each time (assuming no items are added or removed) you can do something like this: {{{<<set _Arr = UInv.GetItemPropertiesArray(BagName, ItemName).sort()>>}}} That will set the _Arr temporary variable equal to the list of property names for that item, with the names sorted by the JavaScript array "sort()" function. ''GetItemPropertyCount(BagName, ItemName)'' = number of ItemPropertyNames ItemName has (inc. quantity) Returns the number of ItemName's item properties from BagName (including UInvQuantity and UInvDefaultItemType), or {{{undefined}}} on error. ''GetItemPropertyValue(BagName, ItemName, ItemPropertyName)'' = Value, {{{undefined}}} if PropertyName doesn't exist Returns the value of ItemPropertyName if it exists, otherwise return {{{undefined}}} on error. ''GetItemsArray(BagName)'' = array of item objects' names Returns an array of item names in BagName (not including UInvTouched and UInvProperties), or {{{undefined}}} on error. ''NOTE:'' UInv stores the items as an object, which means that the order that the items are returned may possibly vary. If you require that the items in the array are in the same order each time (assuming no items are added or removed) you can do something like this: {{{<<set _Arr = UInv.GetItemsArray(BagName).sort()>>}}} That will set the _Arr temporary variable equal to the list of item names for that bag, with the names sorted by the JavaScript array "sort()" function. ''GetItemsArrayByFunction(BagName, SelectionFunction)'' = array of items where function is true (function is passed BagName and ItemName strings) or {{{undefined}}} on error. (not written yet) ''GetItemsArrayByProperty(BagName, ItemPropertyName)'' = array of ItemNames that have property ItemPropertyName Returns an array of all ItemNames in a bag that have property ItemPropertyName or {{{undefined}}} on error. ''GetItemsArraySortedByProperty(BagName, [ItemPropertyName])'' returns an array of ItemNames sorted by the items' names unless ItemPropertyName parameter is used, in which case it's sorted by that property's value (if the property exists; only sorting by numbers and strings are supported for that) Returns an array of item names in BagName, sorted by the value in ItemPropertyName (subsorted by ItemName), or by ItemName if ItemPropertyName isn't set. The array is sorted by number or boolean if all item property values are of that type, otherwise it converts non-strings to strings and does a lowercase comparison. Items that don't have ItemPropertyName are ignored. Returns {{{undefined}}} on error. ''GetItemsArraySortedByFunction(BagName, SortFunction)'' returns an array of ItemNames sorted by the function. Returns an array of ItemNames sorted by the SortFunction function, or {{{undefined}}} on error. The SortFunction will be passed the parameters (BagName, ItemName1, ItemName2), and if the function returns a "truthy" value, then those two items will be swapped in the array. ''GetItemsArrayWhereItemNameContains(BagName, SubString)'' = array of ItemNames where item's name contains the substring; use RegExp matching? Returns an array of ItemNames where item's name contains the substring or {{{undefined}}} on error. ''GetItemsArrayWherePropertyValueContains(BagName, ItemPropertyName, SubString, [CaseSensitive])'' = array of ItemNames where property contains the substring; CaseSensitive defaults to false; use RegExp matching? Returns an array of ItemNames where item's ItemPropertyName contains the substring or {{{undefined}}} on error. ''GetItemsArrayWherePropertyEquals(BagName, ItemPropertyName, Value)'' = array of ItemNames where property = Value Returns an array of all items in a bag where ItemPropertyName = Value, or {{{undefined}}} on error. ''GetItemsArrayWherePropertyGreaterThan(BagName, ItemPropertyName, Amount)'' = array of ItemNames where property value > Amount Returns an array of all items in a bag where ItemPropertyName > Value, or {{{undefined}}} on error. ''GetItemsArrayWherePropertyLessThan(BagName, ItemPropertyName, Amount)'' = array of ItemNames where property value < Amount Returns an array of all items in a bag where ItemPropertyName > Value, {{{undefined}}} on error. ''GetItemWherePropertyEquals(BagName, ItemPropertyName, Value)'' = get a random ItemName where property = Value, if ItemPropertyName points to an array, see if Value is in that array, returns "" if none found, or {{{undefined}}} on error. Returns a random ItemName from a bag where ItemPropertyName = Value. Sets that item as the current item. ''GetItemWherePropertyGreaterThan(BagName, ItemPropertyName, Amount)'' = random ItemName where property value > Amount Returns a random ItemName from a bag where ItemPropertyName = Value. Sets that item as the current item. Returns {{{undefined}}} on error. ''GetItemWherePropertyLessThan(BagName, ItemPropertyName, Amount)'' = random ItemName where property value < Amount Returns a random ItemName from a bag where ItemPropertyName = Value. Sets that item as the current item. Returns {{{undefined}}} on error. ''GetItemWithLowestPropertyValue(BagName, ItemPropertyName)'' = ItemName (items without ItemPropertyName are ignored) Returns the ItemName with the lowest value of ItemPropertyName in BagName (items without ItemPropertyName are ignored), randomly picks one of the lowest if multiple items are tied for lowest, "" if none found, or {{{undefined}}} on error. ''GetObjectOfItemPropertyValues(BagName, ItemPropertyName)'' return { ItemName : ItemPropertyName's value, ... } Returns an object in the format { ItemName : Value, ... } for each item in bag that has a property of ItemPropertyName, or {{{undefined}}} on error. ''GetRandomItem(BagName)'' = random ItemName in BagName Returns a random ItemName from the bag. Sets that item as the current item. Returns {{{undefined}}} on error. ''GetRandomItemPropertyValue(BagName, ItemPropertyName)'' = value of the ItemProperty for a random item in BagName Returns the value of ItemPropertyName for a random item in BagName (items without ItemPropertyName are ignored), "" if none found, or {{{undefined}}} on error. ''GetTotalItemPropertyValue(BagName, ItemPropertyName)'' = total of all items' ItemPropertyName values (multiplied by UInvQuantity) added together (all values must be numbers; items without ItemPropertyName are treated as having a value of zero) Returns the total of all items' ItemPropertyName values (multiplied by UInvQuantity) added together (all values must be numbers; items without ItemPropertyName are treated as having a value of zero), or {{{undefined}}} on error. ''GetUniqueItemName()'' returns a name not used by any item currently ("item0ffd39" 0-255 in hex * 3) Generates and returns an unused item name ("itemXXHEXX"). ''ItemExists(ItemName)'' = t/f, checks GetDefaultItemObject function and all bags for ItemName This function returns {{{true}}} if ItemName is included in [[ItemData]] or any bags, otherwise returns false, or {{{undefined}}} on error. ''ItemHasProperty(BagName, ItemName, ItemPropertyName)'' = t/f Returns whether ItemName in BagName has ItemPropertyName, or {{{undefined}}} on error. ''ItemsMatch(BagName1, ItemName1, BagName2, ItemName2, [PropertyExceptionArray])'' = t/f if all properties exist and match, except UInvQuantity, UInvDefaultItemType, and UInvCell, plus any properties in PropertyExceptionArray if included Returns whether all properties on those two items exist and match, not including the UInvQuantity, UInvDefaultItemType, and UInvCell properties, and any property names included in the optional ''PropertyExceptionArray''. Returns {{{undefined}}} on error. ''ItemPropertyHasValue(BagName, ItemName, ItemPropertyName, Value)'' = t/f if item's property =/contains Value Returns true if item's property =/contains Value, false if it doesn't, otherwise return {{{undefined}}} on error. ''MoveItem(SourceBagName, DestinationBagName, ItemName, [Quantity], [NewItemName])'' if no Quantity parameter then move all Moves {{{Quantity}}} items from source to destination (moves all items if {{{Quantity}}} is undefined, equal to, or larger than the number of source items), changing the source item's UInvQuantity if any remain. Returns the destination item's name on success, or {{{undefined}}} on error. Returns {{{undefined}}} if illegal property values were passed to ''MoveItem'', returns {{{false}}} if any items failed to move, otherwise it returns the moved item's name. The UInvMergeItemMethod setting determines what happens on item collision. See [[SetMergeItemMethod]] for details. ''RenameItem(BagName, CurrentItemName, NewItemName, [Quantity])'' Quantity for partial stacks of items, copy in default item properties Renames an item. Optional Quantity parameter if you want to rename partial stacks, defaults to all items. Returns the new item's name if it succeeds, or {{{undefined}}} on error. The name of the new item cannot be "UInvTouched", "UInvProperties", "UInvDefaultBagType", "UInvContainer", "-" (the minus sign), or "" (an empty string). The UInvMergeItemMethod setting determines what happens on item collision. See [[SetMergeItemMethod]] for details. ''RenameItemProperty(BagName, ItemName, CurrentItemPropertyName, NewItemPropertyName)'' Renames item property. Returns {{{true}}} if it succeeds or {{{undefined}}} on error. Bag is not marked "touched". ''ResetItemProperties(BagName/Array, ItemName, [DefaultItemType])'' removes all properties then loads default Resets all properties of an item to default (except UInvQuantity and UInvPocket). If DefaultItemType is passed then it loads the default properties of that item type onto the item. Any pockets that were on the item will remain there untouched, no new pockets will be added this way. Returns {{{true}}} on success or {{{undefined}}} on error. ''SetCurrentItemName(ItemName)'' Sets the UInvCurrentItemName to ItemName for use as the default ItemName parameter in UInv functions. Returns true on success or {{{undefined}}} on error. ''SetItemPropertyValue(BagName, ItemName, ItemPropertyName, Value)'' Sets the value of an existing property on an object (returns true), or adds that property and value if it doesn't already exist (returns false), or it returns {{{undefined}}} on error. Does not mark bag as "touched" unless UInvQuantity was changed. (See [[WasTouched]] for details.) If you use this to add a "UInvVariableType" property, then this will allow you to delete default properties from the item without changing the item's default type (which would normally change to "-" in that case). See [[DeleteItemProperty]] and [[GetDefaultItemObject]] for details. __If you're using pockets:__ You cannot use this function to change a ''UInvPocket'' property. [[Pocket/Container functions|Pocket/Container Functions]] should be used instead. Also, the ''UInvQuantity'' property can only be {{{1}}} (one) for items with pockets. ''SetItemQuantity(BagName, ItemName, Quantity)'' Quantity must be a positive integer Sets an item's quantity, returns true if successful or {{{undefined}}} on error. Quantity must be a positive integer. __If you're using pockets:__ The quantity cannot be set above one for items with pockets, so since ''Quantity'' cannot go //below// one either, this function will not do anything to items with pockets. ''SetItemsPropertyValue(BagName, ItemPropertyName, Value)'' sets the value of ItemPropertyName on all items in bag (Note: The function's name should be read as "Set Item's Property Values", but you can't have apostrophes in function names.) Set the value of ItemPropertyName to Value for all items in BagName. Returns {{{true}}} on success or {{{undefined}}} on error. ''SetMergeItemMethod(MergeMethod)'' call this to set how items will be merged if source and destination items do not match (other than UInvQuantity) Sets the """$UInvMergeItemMethod""" variable, which controls how UInv handles cases where functions attempt to merge two non-identical items. ''NOTE:'' If this is a variable item (i.e. it has a "UInvVariableType" property) then the item will try to merge with other identical items, and failing that it will merge using the UInv.MERGE_RENAME_SOURCE_ITEMNAME method, regardless of the merge method that is set. See [[GetDefaultItemObject]] for more information on variable items. ''NOTE:'' This does ''not'' affect bags. Here are the possible MergeMethod values: - ''UInv.MERGE_USE_ONLY_DESTINATION_PROPERTIES'' = 1 Ignore source properties, just increment destination's quantity. (default) (...add example results...) - ''UInv.MERGE_USE_ONLY_SOURCE_PROPERTIES'' = 2 Delete the destination's properties, replace with the source's properties and values, and increment the quantity. - ''UInv.MERGE_PREFER_DESTINATION_PROPERTIES'' = 3 Keep the properties and values in the destination, add any properties and values the source had but the destination didn't, and increment the quantity. - ''UInv.MERGE_PREFER_SOURCE_PROPERTIES'' = 4 Keep the properties and values in the source, add any properties and values the destination had but source the didn't, and increment the quantity. - ''UInv.MERGE_RENAME_SOURCE_ITEMNAME'' = 5 Rename the source's unique identifier so that it's stored separately in the destination bag. This causes the function to return the new item name instead of {{{true}}}. - ''UInv.MERGE_FAIL_WITH_ERROR'' = 6 Fail with an error on item collision. Functions which can potentially cause item collision: [[CopyAllItemsToBag]], [[MoveAllItemsToBag]], [[MergeBags]], [[AddItem]], [[AddItems]], [[CopyItem]], [[MoveItem]], [[RenameItem]] <center><h2>Introduction to UInv Concepts</h2></center>The way UInv works is that there are two basic objects: "''bags''" and "''items''". "''Bags''" are containers which have their own properties that you can customize. Bags can also contain "''items''", which are collections of properties that you can pre-define in the code, and then easily create, move from bag to bag, delete, etc... So, for example, you could have one "''bag''" which represents the player's backpack, another "''bag''" which represents what they're holding in their hands, and a bunch of other "''bags''" which represent the various rooms the player will travel to. You could then populate those room "''bags''" with items. Then, when the player travels to that room they could see all of the items that are there, and the items' properties could be used by the code to determine how the player can interact with those items. You could even make the player's description a "''bag''" and have the "''items''" in it represent the player's various stats, skills, and physical descriptions. ''Bags'' are identified by their unique ''BagName''. For more information see the [[Bag Functions]]. Anything with a collection of properties that will be attached to something else in some way can be an "''item''", and you define ''items'' in UInv's [[ItemData]] function, at the bottom of the UInv code. Some example ''items'' might look like this: {{{ case "pants": Item = { type : ["clothing"], singular : "a pair of pants", plural : "pairs of pants", place : "hips1", size : 4, image : "Pants.jpg", thumb : "Pants_sm.jpg", description : "A pair of pants."}; break; case "dagger": Item = { type : ["weapon", "stabbing", "1-handed"], singular : "a dagger", plural : "daggers", size : 2, image : "Dagger.jpg", thumb : "Dagger_sm.jpg", description : "A small dagger." }; break; }}} The code handles quantities by default, so you don't need to include that there. The name next to the "''case''" acts as a unique ID, indicating the name of the item's "''default type''". Properties of an item in a bag are only stored in memory/history if they've changed from the default values, but UInv functions will still show you those default values. Specific items are identified by using both the ''BagName'' of the bag that the item is in, and the ''ItemName'', which will be unique within that bag. This allows you to have two different stacks of items with the same ''ItemName'' if they're in different bags. ''ItemNames'' must be a lowercase string and they cannot be {{{""}}} (an empty string), {{{"-"}}} (a dash). There are four general types of items (though it's possible for an item to be of more than one of these types at the same time): * ''generic items'' - These are usually items created with [[CreateItem]], thus lack a default type and the memory/history saving ability of ''items with a default type''. * ''items with a default type'' - These are usually items created with [[AddItem]] or [[AddBag]], which have default properties (as shown above) which are automatically added upon creation. * ''variable type items'' - These are items where their default properties may vary. They will automatically try to stack themselves with matching items, so //they may get renamed when copied or moved//, in order to stack properly. * ''items with pockets'' - These are items which can contain other items. //Items with pockets cannot stack// (similar to Shulker Boxes in Minecraft). Since they cannot stack, //they may also rename themselves when being moved or copied// when there is already an item of the same name in the destination bag. For more information see the [[GetDefaultItemObject]] function and the other [[Item Functions]]. Use the [[Item Builder]] if you need help building your list of items. Similarly, bags can also be set up with default properties and items in UInv's [[BagData]] function, at the bottom of the UInv code. For more details see the [[GetDefaultBagObject]] function and the [[Bag Builder]]. As described above, bags and items can have their own properties. If the value of a property is an //array//, such as the "type" property in the examples above, then the values in the array are called "''tags''" (also refered to as the "elements" of an array). This allows you to, for example, get a list of all items in a bag with the "Type" property that have a "weapon" tag. For more information see the [[Tag Functions]]. Once you have your bags and items all set up, and you want to display the items or allow the user to directly interact with the inventory, you can either do that yourself or use the [[Display Functions]] to make that a lot easier. (more to come here...) Finally, if you're looking for functions that do what you want, it will most likely be made up of certain common words. ''Modification:'' Add / Create / Delete / Copy / Move / Merge / Rename / Empty / Set / Reset ''Informational:'' Get / Match / Sort / Exists ''Conditionals:'' Where / Has / Highest / Lowest / Are / With / Without / By / Unique ''Modifiers:'' Equal(s) / GreaterThan / LessThan / Contains / All / Any / None / Full ''Data Categories:'' Bag(s) / Propert(y/ies) / Item(s) / ItemQuantit(y/ies) ''Data Types:'' Name(s) / Value(s) / Tag(s) / Array / Object / Count ''Display:'' Display / Fill / List So, for example, if you were looking for a function which would get you the name of the item with the highest "Cost" property value in a bag, you could look for [[GetItemWithHighestPropertyValue]]. Knowing this vocabulary of UInv terms should help you find the function that you're looking for. <center><h2>Getting Started</h2></center>To add UInv to your Twine project, first open ''UniversalInventorySystem.js'' in a text editor (like Notepad, Notepad++, Visual Studio Code, etc.), select all of the text (CTRL+A), and copy it to the clipboard (CTRL+C). You may then close that file. Next, open your story in Twine. If you haven't done it yet, set your story's format to the latest version of SugarCube 2 (from the bottom pop-up menu, in "Change Story Format"). Then go down to the bottom left corner, click the story name or the upward pointing triangle next to it to bring up the bottom pop-up menu, and click "Edit Story JavaScript". <img @src='setup.Path + "images/EditStoryJavaScript.gif"' style='color: lawngreen; max-width: 99%;' alt='(PLEASE WAIT: If the image does not load within a few seconds, please edit the setup.Path variable at the top of the JavaScript section to point to the correct directory.)'> Now paste (CTRL+V) the text you copied into the bottom of that passage, below any functions you may already have there. Next, go to the [[ItemData]] function, near the bottom of the code, and add any items there that you will use in your story. Use the [[Item Builder]] if you need help with this. If you need default bags, you may also edit the bags in the [[BagData]] function, located just above [[ItemData]]. Use the [[Bag Builder]] if you need help with this. (You can delete the example items and bags if you want.) Optionally, you can add the names of your default bags to the ''BagList'' array and/or the names of your default items to the ''ItemList'' array, both of which are near the very bottom of the UInv code. (You can delete the examples in those arrays if you want.) UInv normally tries to silently handle errors, returning a value that indicates an error occurred and setting {{{$UInvLastErrorMessage}}} to a string that explains what the error was. If you want it to throw an error insted you can either go to the bottom of the JavaScript and change "''UInv.Initialize(UInv.ERROR_NONE);''" to "''UInv.Initialize(UInv.ERROR_THROW_ERROR);''", or you can have your code do "''{{{<<set UInv.SetUserAlerts(UInv.ERROR_THROW_ERROR)>>}}}''". See [[Initialize]] and [[SetUserAlerts]] for details and other settings. That's it! You're now ready to use UInv in your Twine story! Next I'd recommend either taking a look at the [[Basic UInv Functions]] section or just opening up the "<a target="_blank" @href="setup.Path+'Universal_Inventory_System.html'">Universal_Inventory_System.html</a>" file in Twine and taking a look at the example code in there so you can see how you can use UInv in //your// Twine project. <center><h2>Tag Functions</h2></center> - [[AddBagTag]](BagName/Array, BagPropertyName, BagTag/Array) - [[AddItemTag]](BagName/Array, ItemName, ItemPropertyName, ItemTag/Array) - [[ArrayHasAllItemTags]](BagName, ItemName, ItemPropertyName, ItemTagArray) - [[BagHasAllBagTags]](BagName, BagPropertyName, BagTagArray) - [[BagHasAllItemTags]](BagName, ItemPropertyName, ItemTagArray) - [[BagHasAnyBagTag]](BagName, BagPropertyName, BagTagArray) - [[BagHasAnyItemTag]](BagName, ItemPropertyName, ItemTagArray) - [[BagHasItemByBagTag]](BagPropertyName, BagTag, ItemName) - [[BagHasAllItemsByBagTag]](BagPropertyName, BagTag, ItemNameArray) - [[BagHasAnyItemByBagTag]](BagPropertyName, BagTag, ItemNameArray) - [[BagHasItemByItemTag]](BagName, ItemPropertyName, ItemTag) - [[BagHasItemWithAllItemTags]](BagName, ItemPropertyName, ItemTag/Array) - [[BagHasItemWithAnyItemTag]](BagName, ItemPropertyName, ItemTag/Array) - [[BagHasItemWithoutAllItemTags]](BagName, ItemPropertyName, ItemTag/Array) - [[BagHasItemWithoutAnyItemTags]](BagName, ItemPropertyName, ItemTag/Array) - [[BagHasTag]](BagName, BagPropertyName, BagTag) - [[CopyItemsByItemTag]](SourceBagName, DestinationBagName, ItemPropertyName, ItemTag) - [[DeleteBagTag]](BagName/Array, BagPropertyName, BagTag/Array) - [[DeleteItemsByItemTag]](BagName, ItemPropertyName, ItemTag) - [[DeleteItemTag]](BagName/Array, ItemName, ItemPropertyName, ItemTag/Array) - [[GetAllUniqueItemTagsArray]](BagName, ItemPropertyName) - [[GetBagsArrayByBagTag]](BagPropertyName, BagTag) - [[GetBagsArrayWithBothBagTags]](BagPropertyName1, BagTag1, BagPropertyName2, BagTag2) - [[GetBagsArrayWithItemByBagTag]](BagPropertyName, BagTag, ItemName) - [[GetBagTagQuantityObject]](BagName, BagPropertyName) - [[GetFullItemCountByAllItemTags]](BagName, ItemPropertyName, TagArray) - [[GetFullItemCountByAnyItemTag]](BagName, ItemPropertyName, TagArray) - [[GetItemsArrayByAllItemTags]](BagName, ItemPropertyName, ItemTagArray) - [[GetItemsArrayByAnyItemTag]](BagName, ItemPropertyName, ItemTagArray) - [[GetItemsArrayByItemTag]](BagName, ItemPropertyName, ItemTag) - [[GetItemsArrayWithAllItemTags]](BagName, ItemPropertyName, ItemTagArray) - [[GetItemsArrayWithBothItemTags]](BagName, ItemPropertyName1, ItemTag1, ItemPropertyName2, ItemTag2) - [[GetItemsArrayWithMostItemTags]](BagName, ItemPropertyName, ItemTagArray) - [[GetItemsArrayWithoutAllItemTags]](BagName, ItemPropertyName, ItemTagArray) - [[GetItemsArrayWithoutAnyItemTags]](BagName, ItemPropertyName, ItemTagArray) - [[GetItemTagCount]](BagName, ItemName, ItemPropertyName, Tag) - [[GetItemTagQuantityObject]](BagName, ItemName, ItemPropertyName) - [[GetMissingBagTagsArray]](BagName, BagPropertyName, BagTagArray) - [[GetMissingItemTagsArray]](BagName, ItemName, ItemPropertyName, ItemTagArray) - [[GetRandomBagTagFromRange]](BagName, BagPropertyName, HighIndex, [LowIndex]) - [[GetRandomItemTagFromRange]](BagName, ItemName, ItemPropertyName, HighIndex, [LowIndex]) - [[GetUniqueBagTagsArray]](BagPropertyName, [BagName/Array]) - [[GetUniqueItemTagsArray]](ItemPropertyName, [BagName/Array]) - [[ItemHasAllTags]](BagName, ItemName, ItemPropertyName, ItemTagArray) - [[ItemHasAnyTag]](BagName, ItemName, ItemPropertyName, ItemTagArray) - [[ItemHasTag]](BagName, ItemName, ItemPropertyName, ItemTag) - [[MoveItemsByItemTag]](SourceBagName, DestinationBagName, ItemPropertyName, ItemTag) - [[SetBagTag]](BagName/Array, BagPropertyName, BagTag/Array, Enabled) - [[SetItemTag]](BagName/Array, ItemName, ItemPropertyName, ItemTag/Array, Enabled)''AddBagTag(BagName/Array, BagPropertyName, BagTag/Array)'' Add or change a bag property to include BagTag. If property exists, then the value gets put in an array if it isn't already. Returns true if it succeeds or {{{undefined}}} on error. ''AddItemTag(BagName/Array, ItemName, ItemPropertyName, ItemTag/Array)'' Add or change a item property to include ItemTag. If property exists, then the value gets put in an array if it isn't already. Returns true if it succeeds or {{{undefined}}} on error. ''BagHasAllBagTags(BagName, BagPropertyName, BagTagArray)'' = t/f Returns {{{true}}} if the bag's property's value (which must be an array) has an equal or greater number of all tags in BagTagArray. ({{{true}}} if BagTagArray is empty) Returns {{{undefined}}} on error. ''BagHasAnyBagTag(BagName, BagPropertyName, BagTagArray)'' = t/f Returns {{{true}}} if the bag's property's value (which must be an array) has any of the tags in BagTagArray. ({{{false}}} if BagTagArray is empty) Returns {{{undefined}}} on error. ''BagHasItemByBagTag(BagPropertyName, BagTag, ItemName)'' = true if any bags with BagPropertyName/BagTag have item Returns true if any bags with BagPropertyName/BagTag have item, false if none do, or {{{undefined}}} on error. ''BagHasAllItemsByBagTag(BagPropertyName, BagTag, ItemNameArray)'' = t/f if any bag with BagPropertyName/BagTag has all of the items in ItemNameArray Returns true if any bag with BagPropertyName/BagTag has all of the items in ItemNameArray, false if none do, or {{{undefined}}} on error. ''BagHasAnyItemByBagTag(BagPropertyName, BagTag, ItemNameArray)'' = t/f if any bag with BagPropertyName/BagTag has any of the items in ItemNameArray Returns true if any bag with BagPropertyName/BagTag has any of the items in ItemName/Array, false if none do, or {{{undefined}}} on error. ''BagHasItemByItemTag(BagName, ItemPropertyName, ItemTag)'' = t/f Returns true if any item in bag has tag ItemTag, false if none do, or {{{undefined}}} on error. ''BagHasItemWithAllItemTags(BagName, ItemPropertyName, ItemTag/Array)'' = t/f Returns true if any items in bag have all tags in ItemTagArray, false if none do, or {{{undefined}}} on error. ''BagHasItemWithAnyItemTag(BagName, ItemPropertyName, ItemTag/Array)'' = t/f Returns true if any items in bag have any tags in ItemTagArray, false if none do, or {{{undefined}}} on error. ''BagHasItemWithoutAllItemTags(BagName, ItemPropertyName, ItemTag/Array)'' = t/f Returns true if any items in bag do not have all tags in ItemTagArray, false if none do, or {{{undefined}}} on error. ''BagHasItemWithoutAnyItemTags(BagName, ItemPropertyName, ItemTag/Array)'' = t/f Returns true if any items in bag do not have any tags in ItemTagArray, false if none do, or {{{undefined}}} on error. ''BagHasTag(BagName, BagPropertyName, BagTag)'' = t/f Returns true if bag's property contains the tag, false if it doesn't, or {{{undefined}}} on error. ''DeleteBagTag(BagName/Array, BagPropertyName, BagTag/Array)'' Delete one instance of BagTag from bag property. Returns true if it succeeds or {{{undefined}}} on error. ''DeleteItemTag(BagName/Array, ItemName, ItemPropertyName, ItemTag/Array)'' Delete one instance of ItemTag from item property. Returns {{{true}}} if it succeeds or {{{undefined}}} on error. If the value of the property is an array, and all items are deleted, the property will be equal to "[]". If you want to actually delete the property, use [[DeleteItemProperty]] instead. However, if the value of the property property is ''not'' an array, the property will be removed from the item entirely. ''GetBagsArrayByBagTag(BagPropertyName, BagTag)'' = array of bag names that have BagTag in BagPropertyName Returns an array of bag names for all bags that have BagTag in their BagPropertyName property, or {{{undefined}}} on error. ''GetBagsArrayWithBothBagTags(BagPropertyName1, BagTag1, BagPropertyName2, BagTag2)'' = array of bag names Returns array of bag names with both tags on their respective bag properties, {{{undefined}}} on error. ''GetBagsArrayWithItemByBagTag(BagPropertyName, BagTag, ItemName)'' = array of bag names from bags with tag and item Returns array of bag names from bags with bag tag and item, or {{{undefined}}} on error. ''GetBagTagQuantityObject(BagName, BagPropertyName)'' = { "UniqueBagTag1" : QuantityOfBagTag1, ... } Returns an object with "TagName : TagQuantity" pairs, like {{{ { UniqueBagTag1 : 2, ... } }}}, or {{{undefined}}} on error. ''GetFullItemCountByAllItemTags(BagName, ItemPropertyName, TagArray)'' = full number of items with all tags in that property Returns full number of items with all item property tags, or {{{undefined}}} on error. ''GetFullItemCountByAnyItemTag(BagName, ItemPropertyName, TagArray)'' = full number of items with any of those tags in that property Returns full number of items with any item property tags, or {{{undefined}}} on error. ''GetItemsArrayByAllItemTags(BagName, ItemPropertyName, ItemTagArray)'' = array of item names with all tags Returns an array of item names with all of the tags in ItemTagArray, {{{undefined}}} on error. For example, if we assume the following: {{{ "ItemA" = { [ItemPropertyName]: ["X", "Y", "Z"] } "ItemB" = { [ItemPropertyName]: ["X"] } ItemTagArray = ["X", "Y"] }}} Then "ItemA" ''//will//'' be included in the array returned by this function, because all tags in ItemTagArray are also in "ItemA". However, "ItemB" will ''NOT'' be included, because it's missing tag "Y". If you want to get an array of all items where all of their item tags are included in ItemTagArray you need to use [[GetItemsArrayWithAllItemTags]] instead. ''GetItemsArrayByAnyItemTag(BagName, ItemPropertyName, ItemTagArray)'' = array of item names with any tags Returns array of item names in bag with any tags, or {{{undefined}}} on error. ''GetItemsArrayByItemTag(BagName, ItemPropertyName, ItemTag)'' = array of item names that have tag Returns array of item names in bag which have that tag, or {{{undefined}}} on error. ''GetItemsArrayWithBothItemTags(BagName, ItemPropertyName1, ItemTag1, ItemPropertyName2, ItemTag2)'' = array of item names Returns array of all item names in BagName which have both ItemTag1 on ItemPropertyName1, and also ItemTag2 on ItemPropertyName2. Returns {{{undefined}}} on error. ''GetItemsArrayWithoutAllItemTags(BagName, ItemPropertyName, ItemTagArray)'' = array of item names without all of these tags Returns array of item names in bag without any of the tags, or {{{undefined}}} on error. ''GetItemsArrayWithoutAnyItemTags(BagName, ItemPropertyName, ItemTagArray)'' = array of item names without any of these tags Returns array of item names in bag without any of the tags, or {{{undefined}}} on error. ''GetItemTagQuantityObject(BagName, ItemName, ItemPropertyName)'' = { "UniqueItemTag1" : QuantityOfItemTag1, ... } Returns an object with TagName : TagQuantity pairs, like {{{ { "UniqueItemTag1" : QuantityOfItemTag1, ... } }}}, or {{{undefined}}} on error. ''GetUniqueBagTagsArray(BagPropertyName, [BagName/Array])'' = [ "UniqueTag1", ... ] Returns an array of unique bag tags (no duplicates) for this bag property. Checks all bags if ''BagName'' is undefined. Returns {{{undefined}}} on error. ''GetUniqueItemTagsArray(ItemPropertyName, [BagName/Array])'' = [ "UniqueTag1", ... ] Returns an array unique item tags (no duplicates) for this item property. Uses all bags if BagName is undefined. Returns {{{undefined}}} on error. ''ItemHasAllTags(BagName, ItemName, ItemPropertyName, ItemTagArray)'' = t/f Returns {{{true}}} if item's property contains the tag, {{{false}}} if it doesn't, or {{{undefined}}} on error. ''ItemHasAnyTag(BagName, ItemName, ItemPropertyName, ItemTagArray)'' = t/f Returns {{{true}}} if item's property contains the tag, {{{false}}} if it doesn't, or {{{undefined}}} on error. ''ItemHasTag(BagName, ItemName, ItemPropertyName, ItemTag)'' = t/f Returns {{{true}}} if item's property contains the tag, {{{false}}} if it doesn't, or {{{undefined}}} on error. ''SetBagTag(BagName/Array, BagPropertyName, BagTag/Array, Enabled)'' adds or removes all tags based on Enabled Makes sure it has one of or removes all of tag BagTag based on whether Enabled is true or false, respectively. Returns true on success or {{{undefined}}} on error. ''SetItemTag(BagName/Array, ItemName, ItemPropertyName, ItemTag/Array, Enabled)'' adds or removes all tags based on Enabled Makes sure it has one of or removes all of tag ItemTag based on whether Enabled is true or false, respectively. Returns true on success or {{{undefined}}} on error. <center><h2>Display Functions</h2></center> - [[AddEventHandler]](Group, Event, Handler, [Options]) - [[CallEventHandler]](Group, Event, Values) - [[CallEventHandlerEx]](Group, Event, Values) - [[DecrementUpdateLock]]() - [[DeleteEventHandler]](Group, Event, Handler/HandlerID, [Options]) - [[DisplayArray]](YourArray, [EmptyString], [SeparatorString], [ConjunctionString], [UseAPNumbers]) - [[DisplayItemList]](BagName, [PluralItemPropertyName], [EmptyString], [SeparatorString], [ConjunctionString], [SingleItemPropertyName]) - [[DisplayRadialMenu]](WedgeItems, Position, [Handler], [Options]) - [[FixTableCells]](BagName) - [[GetEventHandlerByID]](Group, Event, HandlerID) - [[GetMatchingEventHandlersArray]](Group, Event, [Options], [Handler]) - [[GetUpdateLocks]]() - [[IncrementUpdateLock]]() - [[UpdateDisplay]]([Container]) - [[UpdatesAreLocked]]() - (more to be added...) ''DisplayItemList(BagName, [PluralItemPropertyName], [EmptyString], [SeparatorString], [ConjunctionString], [SingleItemPropertyName])'' Returns all of the items in a bag as a single string, or the ''EmptyString'' value if the bag is empty, or {{{undefined}}} on error. All of the properties other than ''BagName'' are optional. ''PluralItemPropertyName'' should be set to the property name on the item which describes it in plural form (e.g. "pairs of pants" or "geese"). This defaults to the item's name if it's not set. Setting it to "" (an empty string) will also cause it to use the item's name. ''EmptyString'' is the text to display if there are no items in the bag. This defaults to "nothing". ''SeparatorString'' is the string which separates items. It will be followed by a single space. This defaults to ",". ''ConjunctionString'' is the string which will show just before the last item in the bag if there is more than one item. This defaults to "and". ''SingleItemPropertyName'' should be set to the property name on the item which describes it in singular form (e.g. "a pair of pants" or "a goose"). This defaults to the item's name if it's not set. Setting it to "" (an empty string) will also cause it to use the item's name. Also, numbers will be displayed per the AP writing style guide. See the [[numberToAPString]] function for details. For example, the following Twine/SugarCube code: {{{Your backpack contains <<= UInv.DisplayItemList("Backpack", "plural", "nothing", ",", "and", "singular")>>.}}} might display as something like this: Your backpack contains a dagger, two pairs of pants, and 20 gold coins. ''See also:'' [[DisplayArray]] <center><h2>Other UInv Functions and Macros</h2></center> - [[ClearErrors]]() - [[GetLastError]]([Clear]) - [[GetUserAlerts]]() - [[Initialize]]([DisplayErrors]) - [[SetUserAlerts]](ErrorSetting, [ErrorStringAddendum]) - [[SetMergeItemMethod]](MergeMethod) - [[Version]]() - [[UInvSet Macro]] {{{<<UInvSet>><</UInvSet>>}}} - [[UInvTry Macro]] {{{<<UInvTry CodeString>><<Fail>><</UInvTry>>}}} <center><h2>Non-UInv General Functions</h2></center> - [[addArticle]](WordIn, [Caps], [Acronyms]) - [[arrayObjectIncludes]](ArrayOfGenericObjects, ObjProperty, Value) - [[arraysAreEqual]](Array1, Array2) - [[arrayHasAllTags]](Array, TagArray) - [[arrayHasAnyTag]](Array, TagArray) - [[arrayHasTag]](Array, Tag) - [[cacheImages]](Path, ImageName/array, [Handler]) - [[combineGenericObjects]](Obj1, Obj2) - [[docHasCSSElement]](CSSElement) - [[flushAllCachedImages]]([MaxCache]) - [[flushCachedImages]](Path, ImageName/array) - [[getArrayReverseSortedByOtherArray]](UnsortedArray, ArrayToSortBy, [RemoveDuplicates]) - [[getArraySortedByOtherArray]](UnsortedArray, ArrayToSortBy, [RemoveDuplicates]) - [[getCachedImageObject]](Path, ImageName) - [[getObjectProperties]](Object, [Ext]) - [[getRandomHexString]]() - [[getUniqueArray]](Array) - [[integerToOrdinal]](Value, [Options]) - [[isArray]](Value) - [[isArrayOfArrays]](Value) - [[isArrayOfBooleans]](Value) - [[isArrayOfDates]](Value) - [[isArrayOfGenericObjects]](Value) - [[isArrayOfIntegers]](Value) - [[isArrayOfMaps]](Value) - [[isArrayOfNumbers]](Value) - [[isArrayOfObjects]](Value) - [[isArrayOfSets]](Value) - [[isArrayOfStrings]](Value) - [[isArrayOfType]](Array, Type) - [[isBoolean]](Value) - [[isDate]](Value) - [[isFunction]](Value) - [[isGenericObject]](Value) - [[isInteger]](Value) - [[isMap]](Value) - [[isNumber]](Value) - [[isObject]](Value) - [[isProperty]](Obj, Prop) - [[isRegExp]](Value) - [[isSet]](Value) - [[isString]](Value) - [[isUndefined]](Value) - [[mapsAreEqual]](Map1, Map2) - [[numberToAPString]](Value) - [[objectsAreEqual]](Object1, Object2, [ArrayOfObjectsToIgnore]) - sanitizeString(String) - [[setsAreEqual]](Set1, Set2) - [[setsMatch]](Set1, Set2) - [[spread]](Value, Funct) - [[valuesAreEqual]](Var1, Var2) + [[Engine Detection]] (12 functions)''ClearErrors()'' Clears error message string. Clears out any error messages in {{{$UInvLastErrorMessage}}} by setting it to {{{""}}} (an empty string). ''SetUserAlerts(ErrorSetting, [ErrorStringAddendum])'' This function allows you to control the type of error messages returned by UInv. It returns a value which indicates the current alert settings. The setting can be used for debugging and/or to let users know how to report any errors. The ''ErrorSetting'' parameter should be either {{{UInv.ERROR_NONE}}} (for no error messages) or any combination of the following values: {{{UInv.ERROR_SHOW_ALERT}}} (Displays a modal dialog box for each error message and pauses execution.) {{{UInv.ERROR_THROW_ERROR}}} (Throws traditional Twine/SugarCube error messages, instead of silently returning a value which indicates that a UInv error occurred.) {{{UInv.ERROR_TO_CONSOLE}}} (Silently displays errors in the console window. Hit {{{F12}}}, or your brower's equivalent, to see the console window.) {{{UInv.ERROR_SHOW_PASSAGE_NAME}}} (Displays the current passage name in any error messages.) The combinations of those four settings are represented by the values 1 through 15. {{{UInv.ERROR_SHOW_PASSAGE_NAME}}} = 1 {{{UInv.ERROR_SHOW_ALERT}}} = 2 {{{UInv.ERROR_THROW_ERROR}}} = 4 {{{UInv.ERROR_TO_CONSOLE}}} = 8 So, instead of doing: {{{ <<set UInv.SetUserAlerts(UInv.ERROR_TO_CONSOLE + UInv.ERROR_SHOW_PASSAGE_NAME)>> }}} you could do: {{{ <<set UInv.SetUserAlerts(9)>> }}} which would produce the same result. If you pass any other "<<hovertip '"Truthy" values include any values other than {{{false}}}, {{{undefined}}}, {{{null}}}, {{{NaN}}} (which stands for "Not a Number"), {{{0}}} (the number zero), and {{{""}}} (an empty string).'>>truthy<</hovertip>>" value through the ''ErrorSetting'' parameter, then it will default to {{{UInv.ERROR_THROW_ERROR + UInv.ERROR_SHOW_PASSAGE_NAME}}}. (''Note:'' It's recommended you avoid using numbers above 15 though, in case more options are added later.) Otherwise any "<<hovertip 'All of the possible "falsy" values are: {{{false}}}, {{{undefined}}}, {{{null}}}, {{{NaN}}} (which stands for "Not a Number"), {{{0}}} (the number zero), and {{{""}}} (an empty string)'>>falsy<</hovertip>>" value for that parameter will act as {{{UInv.ERROR_NONE}}}. If nothing is passed for the ''ErrorStringAddendum'' parameter, then any value you set through it previously will remain unchanged. If a value is passed for ''ErrorStringAddendum'', then that value will be appended to any error messages. You could use this if, for example, you wanted to show the version number of your code or include a message to your users on how and where to report the error. For example: {{{ <<set UInv.SetUserAlerts(UInv.ERROR_THROW_ERROR + UInv.ERROR_SHOW_PASSAGE_NAME, "Apologies for the error. \nPlease click the ► toggle and copy this entire error message to the developer.")>> <<set UInv.DeleteBag("Nonexistent Bag")>> }}} would show: <<UInvSet>> _tmp = GetUserAlerts() SetUserAlerts(UInv.ERROR_THROW_ERROR + UInv.ERROR_SHOW_PASSAGE_NAME, "Apologies for the error. \nPlease click the ► toggle and copy this entire error message to the developer.") DeleteBag("Nonexistent Bag") SetUserAlerts(_tmp, "") <</UInvSet>> If you want each of those pieces of information in the error message to be on their own line, then add this to your Stylesheet section: {{{ span.error { white-space: pre-wrap; } }}} Your error messages would then look like this: <span id="spreadErrorMsg"><<UInvSet>> _tmp = GetUserAlerts() SetUserAlerts(UInv.ERROR_THROW_ERROR + UInv.ERROR_SHOW_PASSAGE_NAME, "Apologies for the error. \nPlease click the ► toggle and copy this entire error message to the developer.") DeleteBag("Nonexistent Bag") SetUserAlerts(_tmp, "") <</UInvSet>></span> (Note that, with that CSS, the {{{\n}}} used above in the ''ErrorStringAddendum'' parameter now causes the second sentence to appear on a new line.) If the value of ''ErrorStringAddendum'' is {{{""}}} (an empty string) then nothing will be appended to any error messages. Use this to clear out any extra error message text you set previously. ''NOTE:'' When testing your code it's recommended that you set this to {{{UInv.ERROR_SHOW_ALERT}}} and/or {{{UInv.ERROR_THROW_ERROR}}} at the end of the UInv JavaScript code or put something like {{{<<set UInv.SetUserAlerts(UInv.ERROR_SHOW_ALERT)>>}}} in your StoryInit passage so that you can see when UInv errors occur. See also: [[GetUserAlerts]], [[Initialize]] ''GetLastError([Clear])'' = last error message, also clears error messages if ''Clear'' is set to true, returns an empty string if there has been no errors since last cleared Returns the last error string, or {{{""}}} (an empty string) if there have been no errors since UInv was initialized or since errors were last cleared. Also clears the error messages if ''Clear'' is set to true. Essentially, this is the same as checking the value of {{{$UInvLastErrorMessage}}}. ''Initialize([ErrorSetting])'' creates and set global variables. Set up variables. Returns "false" if any were already set, otherwise it returns "true". This function is called automatically at the end of the UInv JavaScript. You should not need to call it yourself unless you want to reset everything. If you want error messages displayed by default you can edit the ''ErrorSetting'' parameter at the bottom of the UInv JavaScript. ''ErrorSetting'' should be either ''UInv.ERROR_NONE'' (for no error messages) or any combination of the following values: ''UInv.ERROR_SHOW_ALERT'' (Displays a modal dialog box for each error message and pauses execution.) ''UInv.ERROR_THROW_ERROR'' (Throws traditional Twine/SugarCube error messages, instead of silently returning a value which indicates that a UInv error occurred.) ''UInv.ERROR_TO_CONSOLE'' (Silently displays errors in the console window. Hit {{{F12}}}, or your brower's equivalent, to see the console window.) ''UInv.ERROR_SHOW_PASSAGE_NAME'' (Displays the current passage name in any error messages.) The combinations of those four settings are represented by the values 1 through 15. If you pass some other "truthy" value then it will default to ''UInv.ERROR_THROW_ERROR + UInv.ERROR_SHOW_PASSAGE_NAME''. Otherwise any "falsy" value will act as ''UInv.ERROR_NONE''. ''NOTE:'' When testing your code it's recommended that you either set this to ''UInv.ERROR_SHOW_ALERT'' and/or ''UInv.ERROR_THROW_ERROR'' at the end of the UInv JavaScript code or put something like {{{<<set UInv.SetUserAlerts(UInv.ERROR_SHOW_ALERT)>>}}} in your StoryInit passage so that you can see when UInv errors occur. See also: [[SetUserAlerts]] ''Version()'' = version info Returns a string showing the version of UInv. That output currently is: <<=UInv.Version()>> ''arraysAreEqual(Array1, Array2)'' = t/f Check two arrays to see if they're identical. Returns {{{undefined}}} on error. ''arrayHasAllTags(Array, TagArray)'' = t/f (if a tag in TagArray is repeated, Array must have that many or more of that tag in it to count) Returns true if Array1 has an equal or greater number of all tags in TagArray, or {{{undefined}}} on error. ''arrayHasAnyTag(Array, TagArray)'' = t/f (if a tag in TagArray is repeated, Array must have that many or more of that tag in it to count) Returns true if Array1 has at least one of the tags in TagArray, or {{{undefined}}} on error. ''arrayHasTag(Array, Tag)'' = number of Tag tags found in array, or {{{undefined}}} on error. Returns the number of tags found in array, or {{{undefined}}} on error. ''getArraySortedByOtherArray(UnsortedArray, ArrayToSortBy, [RemoveDuplicates = false])'' = UnsortedArray sorted based on ArrayToSortBy and subsorted by UnsortedArray value, if RemoveDuplicates is true, remove any with the same values across both arrays Returns UnsortedArray sorted based on ArrayToSortBy and subsorted by UnsortedArray value. This is a case insensitive sort. Returns {{{undefined}}} on error. If RemoveDuplicates is true, it also removes any elements where its pair is duplicated in both arrays. See also: [[getArrayReverseSortedByOtherArray]] ''isArray(Value)'' = t/f Returns if a value is an array. ''isArrayOfBooleans(Value)'' = t/f Test an array to see if all the values are booleans. Returns {{{undefined}}} if ''Value'' is not an array. ''isArrayOfNumbers(Value)'' = t/f Test an array to see if all the values are numbers. Returns {{{undefined}}} if ''Value'' is not an array. ''isArrayOfStrings(Value)'' = t/f Test an array to see if all the values are strings. Returns {{{undefined}}} if ''Value'' is not an array. ''isBoolean(Value)'' = t/f Returns if a value is a boolean. ''isNumber(Value)'' = t/f Returns if a value is a number. ''isObject(Value)'' = t/f Returns if a value is an object. ''Note:'' Arrays are a type of object. If you don't want to include other objects, such as arrays, use [[isGenericObject]] instead. ''isString(Value)'' = t/f Returns if a value is a string. ''isUndefined(Value)'' = t/f Returns if a value is {{{undefined}}}. ''numberToAPString(Value)'' = returns the number as an AP style formatted string Converts a number to a string that conforms to basic AP writing style guidelines. For example, a number "2" will get changed to "two", "10000" will get changed to either "10,000" or "10.000" (depending on which is preferred by the user based on their region settings; see the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString">JavaScript toLocaleString() function</a> for details), and "12557631" will get changed to "12.56 million". Any decimals will be rounded to two places. Integers "0" up to and including "9" will get changed to their equivalent word. Numbers "10" up to, but ''not'' including, 1 million will be shown in number form, with appropriate thousands and decimal place indicators if needed. Numbers at or above 1 million will be divided by the nearest "1 quadrillion", "1 trillion", "1 billion", or "1 million", and rounded to two decimal places. (''Note:'' This ends at "quadrillions" because {{{Number.MAX_SAFE_INTEGER}}} is just a bit over 9 quadrillion, so it's not recommended that you exceed that number.) For exceptions and details see: [[https://writingexplained.org/ap-style/ap-style-numbers]] and [[https://writingexplained.org/ap-style/ap-style-millions-billions-trillions]] See also: [[integerToOrdinal]] for changing integers like 1 or 101 into "first" or "101st", respectively. ''objectsAreEqual(Object1, Object2)'' = t/f Check two objects to see if they're identical. Returns {{{false}}} if either parameter passed is not an object. ''valuesAreEqual(Var1, Var2)'' = t/f Check two variables to see if they're identical. This function only supports comparing strings, numbers, booleans, {{{undefined}}}, {{{null}}}, arrays, dates, and/or generic objects. ''GetItemsDefaultType(BagName, ItemName)'' (Note: The function's name should be read as "Get Item's Default Type", but you can't have apostrophes in function names.) Returns item's default item type if it has one, {{{"-"}}} (a dash; meaning that it's a custom object) if it doesn't, or {{{undefined}}} on error. An item's default type is usually the same as the ItemName, however some functions ([[AddItem]], [[CopyItem]], and [[RenameItem]]) allow you to change or create an item with an item type that doesn't match its item name. ''SetItemsDefaultType(BagName, ItemName, DefaultItemType)'' (Note: The function's name should be read as "Set Item's Default Type", but you can't have apostrophes in function names.) Changes an item's default item type. Returns true on success or {{{undefined}}} on error. If ''DefaultItemType'' is set to {{{"-"}}} (a string with a dash in it) then it will remove the item's default type. You will likely never need to use this function. However, you may want to use it if you edit an item's type to the point where it more closely resembles another item's type. In this case, switching its type to that other item type will reduce the amount of data Twine has to save in your story's history. ''isProperty(Obj, Prop)'' Returns if Prop is a property of the object Obj. The Prop parameter should be passed in the form of a string. Returns {{{false}}} if ''Obj'' is not an object. ''GetBagPropertyObject(BagName)'' = object of all properties/values a bag has. Returns object of all properties/values a bag has or {{{undefined}}} on error. ''GetBagsDefaultType(BagName)'' Returns bag's default bag type if it has one, "-" if it doesn't, or {{{undefined}}} on error. ''GetDefaultBagObject(DefaultBagType, [PropertiesOnly])'' returns a bag object, or if ''PropertiesOnly'' is true then it returns the default properties object for that bag. Returns the bag object which matches ''DefaultBagType'', or if ''PropertiesOnly'' = true it returns the default properties object for DefaultBagType, or {{{null}}} for unknown bag types, or {{{undefined}}} on error. (Both {{{null}}} and {{{undefined}}} have "falsey" values.) Normally you won't call this function yourself, but UInv uses it in [[AddBag]] to add that bag with its default properties and items, and in other functions to check the default properties of the items you added. You set the default bag properties and items in UInv's [[BagData]] function, at the bottom of the UInv code. ''__IMPORTANT!:__'' * Bag types must be unique strings in all lowercase. * Bag types cannot be "-" (the minus sign) or "" (an empty string). * Property names can be upper and/or lowercase strings. * Property names with spaces in them must be inside quotes. * Property names are case sensitive, so a property named "XYZ" is different from properties named "Xyz" or "xyz". * Bag and property names cannot start with a number. * A bag cannot have more than one property with the same name. * Property values can be strings, numbers, booleans, or arrays. * Objects and functions are unsupported property value types. * Multiple successive case lines with no "break;" between them will be treated as different items with the same properties. * Quote marks inside strings need to have a backslash before them. (e.g. "Bob said, \"Hello.\"") * Backslashes will also need a backslash before them. New bags should be added in the following format: {{{ case "unique-lowercase-bag-name-string": BagProperties = { unique-property-name1-string : property-value1, unique-property-name2-string : property-value2, ... }; BagItems = [ // String Method = 1 item of that type "item-name-string1", // Quantity Method = Quantity items of that type { item-name-string2 : Quantity }, // Quantity must be an integer // Type Method = UInvQuantity items of type UInvDefaultItemType { item-name-string3 : { UInvDefaultItemType: "item-type", UInvQuantity: Quantity } }, // Creation Method = UInvQuantity items of type UInvDefaultItemType { item-name-string4 : { UInvQuantity: Quantity, property-name1: value1, ... } }, ... ]; break; }}} The BagProperties and BagItems lines are optional. You can leave either of them out if you don't need to set the bag's properties or items, respectively. ''NOTE:'' If any of a bag's __properties__ are variable, then in BagProperties the property "UInvVariableType" has to be set to something (it doesn't matter what). However, you do ''not'' need to add the "UInvVariableType" property if any of the __items__ that may be in the bag can vary. For a bag's items, you can add them a couple of ways. Use the ''String Method'' (as shown above) for single items of a default type, the ''Quantity Method'' for multiple items of a default type, the ''Type Method'' for items whose type doesn't match the item name (UInvQuantity defaults to 1 if not included), or the ''Creation Method'' to create items without a default type. If you combine the ''Type Method'' and ''Creation Method'' by having "UInvDefaultItemType" plus other properties, then it will use the default type and have the other properties override that type's default properties. Here's an example showing all of the different methods of adding items: {{{ case "clothing": BagProperties = { description: "A pile of clothing." }; BagItems = [ // This adds 1 "shoes" (of type "shoes") "shoes", // This adds 4 "pants" (of type "pants") { "pants" : 4 }, // This adds 2 "black belt" (of type "belt") { "black belt" : { UInvDefaultItemType : "belt", UInvQuantity : 2, // override default belt "description" property description : "A black belt." } }, // This creates 3 "shirt" as described { "shirt" : { UInvQuantity : 3, type : ["clothing"], singular : "a shirt", plural : "shirts", place : ["torso2"], size : 3, image : "icon_cloth_shirt1.png", description : "An ordinary white shirt." } } ]; break; }}} Generally it's recommended that you create a default item instead of using the ''Creation Method'' for adding default items to bags since it will save memory/history space. That said, this method can be useful for creating items with no properties, or when used in combination with the ''Type Method''. It's also recommended (though not required) that you list your bags alphabetically both to help avoid duplicating names and to make them easier to find if you need to modify them later. If {{{BagProperties}}} is not set, then "{}" (an empty object) will be returned for the types properties. If {{{BagItems}}} is not set, then "[]" (an empty array) will be returned for the item list. If you need help creating bags, you can use the [[Bag Builder]] to make sure everything is formatted correctly. Optionally, you can also put a list of default bag names in the ''BagList'' array at the bottom of the UInv code. ''SetBagsDefaultType(BagName, DefaultBagType)'' (Note: The function's name should be read as "Set Bag's Default Type", but you can't have apostrophes in function names.) Attempts to change a bag's default bag type. Returns {{{true}}} on success, {{{false}}} on failure, or {{{undefined}}} on error. You will likely never need to use this function. However, you may want to use it if you edit an bag's type to the point where its properties more closely resembles another bag's type. In this case, switching its type to that other bag type will reduce the amount of data Twine has to save in your story's history. This function will not change anything if changing the default type would add properties to the bag (so this will always work when changing to a variable type bag, but may not work on some static type bags), and will return {{{false}}} in that case. <center><h2>AddBag</h2></center>__Format:__ ''AddBag(''<<hovertip "''BagName'' must be a string, and cannot be \"\" (an empty string), \"-\" (a dash), or the name of an existing bag. If ''DefaultBagType'' is not set, then this must be the name of a default type of bag you've defined in UInv's ''[[BagData]]'' function." 330>>''BagName''<</hovertip>>'', [''<<hovertip "__Optional:__ If included, ''DefaultBagType'' must be the name of a default type of bag you've defined in UInv's ''[[BagData]]'' function.<br>__Default Value:__ ''BagName''">>''DefaultBagType''<</hovertip>>''])'' __Short Description:__ Creates a new bag with properties and/or items from [[GetDefaultBagObject]]. __Returns:__ {{{true}}} on success.<span style="float: right;">__Added:__ ''UInv v1.0.0''</span> __Sets:__ ''CurrentBag'' = ''BagName'', ''UInvTouched'' on ''BagName'' = {{{false}}} __See Also:__ [[CreateBag]], [[CopyBag]], [[GetDefaultBagObject]], and [[DeleteBag]]. <<Title "Details">> ''AddBag'' creates a bag of type ''BagName'' (or of type ''DefaultBagType'' if that parameter is used), and adds any default properties and/or items to that bag. Returns {{{true}}} on success or {{{undefined}}} on error. You pre-define the default properties and/or items for your bag types in the UInv [[BagData]] code. For more information on default bag types see [[GetDefaultBagObject]]. For help creating default bags, see the [[Bag Builder]]. ''BagName'' must be a string, and it cannot be "-" (a dash) or "" (an empty string). There cannot already be a bag with that name. Also, the bag type must exist in [[BagData]]. If any of these conditions are not met, the function will fail, triggering an error and returning {{{undefined}}}. If you want to create a new bag //without// a default type, use [[CreateBag]] instead. ''Note when using pockets:'' Default items will ''not'' be added to a bag's default items' sub-sub-sub-pockets (if there are any), where the depth of those pockets equals ''UInv.MaximumPocketDepth'' (which defaults to ''<<= UInv.MaximumPocketDepth>>''). This is to prevent potential infinite loops of items or potential exponential explosions of items. You can still add items to those pockets directly. <<Title "Sample Code">> The sample code below assumes you've added default bag types named "''inventory''" and "''backpack''" to the UInv [[BagData]] code. {{{ /* Create a bag named "inventory" of bag type "inventory". */ <<run UInv.AddBag("inventory")>> }}} {{{ /* Create a bag named "PCBackpack" of bag type "backpack". */ <<run UInv.AddBag("PCBackpack", "backpack")>> }}} {{{ /* Attempt to create a bag named "backpack" of bag type "backpack" and verify that it worked. */ <<set _BagName = "backpack">> <<if UInv.AddBag(_BagName)>> Successfully created a bag named "_BagName"! <<else>> /* AddBag failed, so show the error message explaining why. */ $UInvLastErrorMessage <</if>> }}} <<Title "Error Cases">> ''AddBag(BagName, [DefaultBagType])'' will throw an error if: * a bag named ''BagName'' already exists * ''BagName'' and/or ''DefaultBagType'' are ''not'' strings * ''BagName'' is {{{""}}} (an empty string) or {{{"-"}}} (a dash) * (if included) ''DefaultBagType'' is ''not'' a valid default bag type * (if ''DefaultBagType'' is ''not'' included) ''BagName'' is ''not'' a valid default bag type ''CopyItemsByProperty(SourceBagName, DestinationBagName, ItemProperty, [Value])'' copy all items in bag that have the ItemProperty, or ItemProperty = Value if Value is passed Copy all items from SourceBagName to DestinationBagName that have the ItemPropertyName, or ItemPropertyName = Value if Value is passed. Returns {{{undefined}}} if illegal property values were passed to ''CopyItemsByProperty'', returns {{{false}}} if any items failed to copy, otherwise it returns an array of all of the new item names. ''DeleteItemsByProperty(BagName, ItemProperty, [Value])'' delete all items in bag that have the ItemProperty, or ItemProperty = Value if Value is passed Delete all items from BagName that have the ItemProperty, or ItemProperty = Value if Value is passed. Returns {{{true}}} on success or {{{undefined}}} on error. ''GetItemsAndQuantitiesObject(BagName)'' = { item1: quantity1, item2: quantity2, etc... } in a bag Returns an object of items and quantities in a bag in the format { item1: quantity1, item2: quantity2, etc... } or {{{undefined}}} on error. ''MoveItemsByProperty(SourceBagName, DestinationBagName, ItemProperty, [Value])'' move all items in bag that have the ItemProperty, or ItemProperty = Value if Value is passed Move all items from SourceBagName to DestinationBagName that have the ItemPropertyName, or ItemPropertyName = Value if Value is passed. Returns an array of all item names that were moved to the destination bag, or {{{undefined}}} on error. ''BagHasAllItemTags(BagName, ItemPropertyName, ItemTagArray)'' = t/f Returns whether bag's items have all ItemTagArray tags in the ItemPropertyName property among its items or {{{undefined}}} on error. ''BagHasAnyItemTag(BagName, ItemPropertyName, ItemTagArray)'' = t/f Returns whether any of bag's items have ItemTagArray tag in their ItemPropertyName property or {{{undefined}}} on error. ''CopyItemsByItemTag(SourceBagName, DestinationBagName, ItemPropertyName, ItemTag)'' copy all items in bag that have the ItemTag Copy all items from SourceBagName to DestinationBagName which have ItemTag in the items' ItemPropertyName. Returns {{{true}}} on success or {{{undefined}}} on error. ''DeleteItemsByItemTag(BagName, ItemPropertyName, ItemTag)'' delete all items in bag that have the ItemTag Delete all items from BagName which have ItemTag in the items' ItemPropertyName. Returns {{{true}}} on success or {{{undefined}}} on error. ''GetAllUniqueItemTagsArray(BagName, ItemPropertyName)'' = array of all unique item tags in the ItemPropertName property for all items in bag Returns an array of all unique item tags in the ItemPropertName property for all items in bag, or {{{undefined}}} on error. ''MoveItemsByItemTag(SourceBagName, DestinationBagName, ItemPropertyName, ItemTag)'' move all items in bag that have the ItemTag Move all items from SourceBagName to DestinationBagName which have ItemTag in the items' ItemPropertyName. Returns an array of all moved item names on success, or {{{undefined}}} on error. ''GetItemsArrayWithMostItemTags(BagName, ItemPropertyName, ItemTagArray)'' = array of all items that are tied for the most ItemTags in ItemPropertyName Returns an array of all items in BagName that are tied for the most tags from ItemTagArray in ItemPropertyName, or {{{undefined}}} on error. <center><h2>UInv Item Builder</h2></center><table><col width="141px"><col><col width="187px"><col width="161px"><tr><th>Item Name:</th><td><<textbox "$ItemName" "sword">></td><th align="right">Copy From Selection:</th><td>@@#CopyItm;<<button "Copy Item">><<run CopyItem()>><</button>>@@</td></tr> <tr><th>Property Name:</th><td><<textbox "$PropertyName" "type">></td><th align="right">Property Value Type:</th><td><select id="Types" name="Types"> <option value="string">String</option> <option value="number">Number</option> <option value="boolean">Boolean</option> <option value="image">Image</option> </select></td></tr> <tr><th>Property Value:</th><td><span id="PropVal"><<textbox "$PropertyValue" "weapon">></span><span id="PropValBool" class="hidden">True: <<radiobutton "$PropertyValueBool" "true" checked>> / False: <<radiobutton "$PropertyValueBool" "false">></span></td><th title="Mark this checkbox to give multiple values (tags) to the current property." align="right">Add as tags: <<checkbox "$UseTags" false true>> </th><td>@@#AddEditProp;<<button "Add/Edit Property">><<run AddProperty()>><</button>>@@</td></tr></table><table width="100%" id="ImgTbl" class="hidden"><col width="102px"><col><col width="64px"><col><tr><th>Browse:</th><td><input id="Img" name="Img" type="file" accept=".jpg, .jpeg, .png, .svg, .gif, .ico, .webp" class="link-internal macro-button" style="width: calc(100% - 20px);"></td><th>Select:</th><td><select id="Images"></select></td></tr> <tr><th>Temp Path:</th><td><<textbox "$ImgPath" $ImgPath>></td><th>Image:</th><td><img id="ImageBox" src="" title="Click to see image full size." class="modalIcon" style="max-height: 36px; border: 1px solid white; padding: 1px; vertical-align: middle; float: left; margin-right: 8px;">(Click image to view full size)</td></tr></table><table width="100%"><col width="25%"><col width="25%"><col width="25%"><col width="25%"><tr><th>Items:</th><th>Properties:</th><th><span id="ValTitle">Value:</span><span id="TagTitle" class="hidden">Tags: <span id="TagSrt" title="Sort tags"><<button "S">><<run SortTags()>><</button>></span> <span id="TagUp" title="Move tag up"><<button "▲">><<run MoveTag("up")>><</button>></span> <span id="TagDn" title="Move tag down"><<button "▼">><<run MoveTag("down")>><</button>></span></span></th><th><span id="Opts">Value Options:</span></th></tr> <tr><td><select size="5" id="Items" onchange="UpdateList(this.options[this.selectedIndex].text); this.focus();"></select></td><td><select size="5" id="Properties" onchange="UpdateList(undefined, this.options[this.selectedIndex].text); this.focus();"></select></td><td><select size="5" id="Values" onchange="UpdateList(undefined, undefined, this.options[this.selectedIndex].text); this.focus();"></select></td><td style="vertical-align: top;"><select size="5" id="Tags" onchange="ReadyTagsButton(); this.focus();" multiple></select></td></tr> <tr><td>@@#RmItemBtn;<<button "Remove Item">><<run RemoveItem()>><</button>>@@</td><td>@@#RmPropBtn;<<button "Remove Property">><<run RemoveProperty()>><</button>>@@</td><td>@@#RmTagBtn;<<button "Remove Tag">><<run RemoveTag()>><</button>>@@</td><td>@@#UseTags;<<button "Use Selected Tags">><<run SetTags()>><</button>>@@</td></tr></table>''ItemData code:'' Copy and paste the code below into the "static items" section of the [[ItemData]] function (near the bottom of the UInv JavaScript code). <<textarea "_ItemData" "">> Please note that the ''UInv Item Builder'' can only handle strings, numbers, and booleans, and also arrays of those three types (image filenames are stored as strings). Anything else will require manual editing of the resulting code. See [[GetDefaultItemObject]] for details. If you want to have your current items import here automatically, simply paste the item data from your story into the [[ItemData]] function of the JavaScript in this Twine story, then add your items to the bag named "Items" in the {{{StoryInit}}} passage. They will then be listed here when you enter the UInv Item Builder. Also, you can use the "SAVES" button on the left panel to save or load work you've done in the Item Builder.''GetMissingBagTagsArray(BagName, BagPropertyName, BagTagArray)'' returns an array of all tags in BagTagArray which were not found on the BagPropertyName for that bag Returns an array of all tags in BagTagArray which were not found on the BagPropertyName for that bag, or {{{undefined}}} on error. ''GetMissingItemTagsArray(BagName, ItemName, ItemPropertyName, ItemTagArray)'' returns an array of all tags in ItemTagArray which were not found on the items' ItemPropertyName in that bag Returns an array of all tags in ItemTagArray which were not found on the items' ItemPropertyName in that bag, or {{{undefined}}} on error. Code under construction. ''GetBagObject(BagName)'' = the full bag object (including UInvDefaultBagType) Returns the full bag object (including UInvDefaultBagType) or {{{undefined}}} on error. ''BagMatchesDefault(BagName)'' = t/f depending on whether it's an exact match for its default bag type Returns whether bag exactly matches its default version, or {{{undefined}}} on error. Returns false if the bag does not have a default object. ''GetUniqueItemPropertyValuesArray(BagName/Array, ItemPropertyName)'' returns an array of unique values for all items with ItemPropertyName in all bags in BagName/Array, or {{{undefined}}} on error. Returns an array of unique (string, number, and boolean) values for all items with ItemPropertyName in all bags in BagName/Array, or {{{undefined}}} on error. (use GetUniqueItemTagsArray instead for properties which have array values) ''isDate(Value)'' = t/f Returns if a value is a date. ''isFunction(Value)'' = t/f Returns if a value is a function. ''isRegExp(Value)'' = t/f Returns if a value is a RegExp. <center>[[UInv Help Main]] - Functions: [[Bag|Bag Functions]] - [[Pocket|Pocket/Container Functions]] - [[Item|Item Functions]] - [[Tag|Tag Functions]] - [[Display|Display Functions]] - [[Other|Other UInv Functions and Macros]] - [[Utility|UInv Utility Functions]]<br> Builders: <<Disabled "Bag">> - [[Item|Item Builder]] - [[Table|Table Builder]] - <<Disabled "Radial Menu">> - Link to this passage: <a @href="encodeURI(decodeURI(document.location.href.match(/(^[^#]*)/)[0])+'#'+passage())" title="Link to this passage.">#</a></center> <div id="modalWindow"> /* Set up modalWinow */ <span id="modalClose"> &times; </span> <div id="modalBlock"> <span><img id="modalImage"></span><br> <span id="modalCaption"></span> </div> </div><br>''GetUserAlerts()'' Returns a value which indicates the current alert settings. If user alerts are disabled then the value will be ''false'' (''UInv.ERROR_NONE''). You can test other values by doing a bitwise comparison with these values: ''UInv.ERROR_SHOW_PASSAGE_NAME'' (Displays the current passage name in any error messages.) ''UInv.ERROR_SHOW_ALERT'' (Displays a modal dialog box for each error message and pauses execution.) ''UInv.ERROR_THROW_ERROR'' (Throws traditional Twine/SugarCube error messages, instead of silently returning a value which indicates that a UInv error occurred.) ''UInv.ERROR_TO_CONSOLE'' (Outputs any error messages to the console.) For example, this code would display a messages if alert messages are enabled: {{{ <<if (UInv.GetUserAlerts() & UInv.ERROR_SHOW_ALERT)>> Alerts are enabled. <</if>> }}} See also: [[SetUserAlerts]] ''GetCurrentItemName()'' Gets the current item name if there is one, otherwise returns "". Gets the current item name if there is one, otherwise returns "". ''GetCurrentBagName()'' Gets the current bag name if there is one, otherwise returns "". Gets the current bag name if there is one, otherwise returns "". ''SwapItems(BagName1, ItemName1, BagName2, ItemName2, [ExceptItemPropertyName/array])'' swaps two items, optionally keeps certain item properties un-swapped Swaps two items, optionally keeps certain item properties un-swapped. Returns true on success or {{{undefined}}} on error. ''isInteger(Value)'' = t/f Returns if a value is an integer. ''GetRandomBagTagFromRange(BagName, BagPropertyName, HighIndex, [LowIndex = 0])'' Returns a random tag from LowIndex to HighIndex (inclusive) Returns a random tag from LowIndex to HighIndex (inclusive), returns {{{undefined}}} on error. ''GetRandomItemTagFromRange(BagName, ItemName, ItemPropertyName, HighIndex, [LowIndex = 0])'' Returns a random tag from LowIndex to HighIndex (inclusive) Returns a random tag from LowIndex to HighIndex (inclusive), returns {{{undefined}}} on error. <<set _SnapTo = [], $(".SnapTo").each(function(index) { State.temporary.SnapTo.push( '"' + $(this).attr("id") + '"' ) })>><<if _SnapTo.length > 0>><div class="TOCFix">''Table of Contents:'' * <a href="javascript:window.scrollTo(0, 0)"><<= passage()>></a> <<capture _i>><<for _i = 0; _i < _SnapTo.length; _i++>>* <<set _title = $("#" + _SnapTo[_i].slice(1, -1)).text().slice(0, -1).replace(/</g, "&lt;").replace(/>/g, "&gt;")>><a @href="'javascript:document.getElementById('+_SnapTo[_i]+').scrollIntoView(true)'">_title</a><</for>><</capture>></div><</if>><input type="text" id="SearchTxt" style="width: calc(100% - 50px); min-width: auto; float: left;"><span id="Search" alt="Search" title="Search" style="float: left;"><<button " ">><<run DoSearch()>><</button>></span><br> <span style="display: table; line-height: 2;">Include ''all'' search terms: <<checkbox "$SearchAll" false true checked>></span><span style="display: table; line-height: 1;"> Results (by relevancy):</span><select id="Results" size=10 style="width: 100%; margin-top: 6px;" onchange="GoToPassage(this.options[this.selectedIndex].value);"> </select><input type="checkbox" id="fullscreen"><label for="fullscreen" class="gofullscreen"><img src='data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m82 324v87c0 11 8 19 19 19h88c15 0 22-17 11-29l-27-28 83-83 83 83-27 28c-11 11-4 29 11 29h88c11 0 19-8 19-19v-87c0-15-17-23-29-12l-28 27-83-83 83-83 28 27c11 11 29 3 29-12v-87c0-11-8-19-19-19h-88c-15 0-22 17-11 29l27 28-83 83-83-83 27-28c11-11 4-29-11-29h-88c-11 0-19 8-19 19v87c0 15 17 23 29 12l28-27 83 83-83 83-28-27c-12-11-29-4-29 12zm374 188h-400c-30 0-56-26-56-56v-400c0-30 26-56 56-56h400c30 0 56 26 56 56v400c0 30-27 56-56 56zm-5-471h-390c-14 0-20 10-20 20v390c0 19 15 20 20 20h390c12 0 20-7 20-20v-390c0-17-11-20-20-20z" fill="white" /></svg>' alt="Go full screen" title="Go full screen" class="fullscreenImg"></label><label for="fullscreen" class="exitfullscreen"><img src='data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m65 99 83 83-27 28c-11 11-4 29 11 29h88c11 0 19-8 19-19v-87c0-15-17-23-29-12l-28 27-83-83zm117 265 28 27c11 11 29 3 29-12v-87c0-11-8-19-19-19h-88c-15 0-22 17-11 29l27 28-83 83 34 34zm265 49-83-83 27-28c11-11 4-29-11-29h-88c-11 0-19 8-19 19v87c0 15 17 23 29 12l28-27 83 83zm-117-265-28-27c-12-11-29-4-29 12v87c0 11 8 19 19 19h88c15 0 22-17 11-29l-27-28 83-83-34-34zm126 364h-400c-30 0-56-26-56-56v-400c0-30 26-56 56-56h400c30 0 56 26 56 56v400c0 30-27 56-56 56zm-5-471h-390c-17 0-20 10-20 20v390c0 16 10 20 20 20h390c8 0 20-4 20-20v-390c0-18-12-20-20-20z" fill="white" /></svg>' alt="Exit full screen" title="Exit full screen" class="fullscreenImg"></label><img src='data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m456 512h-400c-30 0-56-26-56-56v-400c0-30 26-56 56-56h400c30 0 56 26 56 56v400c0 30-27 56-56 56zm-5-471h-390c-14 0-20 10-20 20v390c0 19 15 20 20 20h390c12 0 20-7 20-20v-390c0-17-11-20-20-20z" fill="white" /><path d="m163 79v163h10c15 0 30-2 37-5 18-9 22-19 25-33h8v97h-8c-3-15-14-27-25-32-12-5-20-5-37-5h-10v123c0 20 1 33 3 39 2 5 5 9 11 14 5 4 12 6 19 6h9v11h-133v-11h8c8 0 14-2 18-6 3-2 6-7 8-14 2-5 2-18 2-38v-264c0-20-1-33-2-39-3-13-15-19-26-19h-8c-1 0 0-11 0-11h220v116h-8c-2-27-6-47-14-60s-17-22-32-27c-8-4-25-5-48-5z" fill="white" /><path d="m271 155v129h8c12 0 24-2 30-4 14-7 18-15 20-26h6v78h-6c-2-12-11-22-20-26-10-4-16-4-30-4h-8v99c0 16 1 26 2 31 2 4 4 7 9 11 4 3 10 5 15 5h7v9h-106v-9h6c6 0 11-2 14-5 2-2 5-6 6-11 2-4 2-14 2-30v-211c0-16-1-26-2-31-2-10-12-15-21-15h-6c-1 0 0-9 0-9h176v93h-6c-2-22-5-38-11-48s-14-18-26-22c-6-3-20-4-38-4z" opacity="0.75" fill="white" /><path d="m361 217v102h6c10 0 19-1 23-3 11-6 14-12 16-21h5v62h-5c-2-10-9-17-16-20-8-3-13-3-23-3h-6v78c0 13 1 21 2 25 1 3 3 6 7 9 3 3 8 4 12 4h6v7h-84v-7h5c5 0 9-1 11-4 2-1 4-4 5-9 1-3 1-11 1-24v-168c0-13-1-21-1-25-2-8-10-12-17-12h-5c-1 0 0-7 0-7h140v74h-5c-1-17-4-30-9-38s-11-14-20-17c-5-3-16-3-30-3z" opacity="0.5" fill="white" /></svg>' alt="Larger font" title="Larger font" class="fullscreenImg" style="top: 70px;" onclick="fontSize(1)"><img src='data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m456 512h-400c-30 0-56-26-56-56v-400c0-30 26-56 56-56h400c30 0 56 26 56 56v400c0 30-27 56-56 56zm-5-471h-390c-14 0-20 10-20 20v390c0 19 15 20 20 20h390c12 0 20-7 20-20v-390c0-17-11-20-20-20z" fill="white" /><path d="m163 79v163h10c15 0 30-2 37-5 18-9 22-19 25-33h8v97h-8c-3-15-14-27-25-32-12-5-20-5-37-5h-10v123c0 20 1 33 3 39 2 5 5 9 11 14 5 4 12 6 19 6h9v11h-133v-11h8c8 0 14-2 18-6 3-2 6-7 8-14 2-5 2-18 2-38v-264c0-20-1-33-2-39-3-13-15-19-26-19h-8c-1 0 0-11 0-11h220v116h-8c-2-27-6-47-14-60s-17-22-32-27c-8-4-25-5-48-5z" opacity="0.5" fill="white" /><path d="m271 155v129h8c12 0 24-2 30-4 14-7 18-15 20-26h6v78h-6c-2-12-11-22-20-26-10-4-16-4-30-4h-8v99c0 16 1 26 2 31 2 4 4 7 9 11 4 3 10 5 15 5h7v9h-106v-9h6c6 0 11-2 14-5 2-2 5-6 6-11 2-4 2-14 2-30v-211c0-16-1-26-2-31-2-10-12-15-21-15h-6c-1 0 0-9 0-9h176v93h-6c-2-22-5-38-11-48s-14-18-26-22c-6-3-20-4-38-4z" opacity="0.75" fill="white" /><path d="m361 217v102h6c10 0 19-1 23-3 11-6 14-12 16-21h5v62h-5c-2-10-9-17-16-20-8-3-13-3-23-3h-6v78c0 13 1 21 2 25 1 3 3 6 7 9 3 3 8 4 12 4h6v7h-84v-7h5c5 0 9-1 11-4 2-1 4-4 5-9 1-3 1-11 1-24v-168c0-13-1-21-1-25-2-8-10-12-17-12h-5c-1 0 0-7 0-7h140v74h-5c-1-17-4-30-9-38s-11-14-20-17c-5-3-16-3-30-3z" fill="white" /></svg>' alt="Smaller font" title="Smaller font" class="fullscreenImg" style="top: 100px;" onclick="fontSize(-1)"> <<script>> $("#Search button").addClass("fas fa-search").css({ "line-height": "1.5em" }); var prepWait = 0; function PrepSearch () { if (setup.JSLoaded != 2) { return false; } clearInterval(prepWait); var SearchTxt = $("#SearchTxt"); SearchTxt.autocomplete({ source: PassageList, minLength: 2, select: function( event, ui ) { DoSearch(); } }); SearchTxt.keyup( function(event) { if (event.keyCode === 13) { // Number 13 is the "Enter" key on the keyboard $("#Search button").trigger("click"); this.focus(); } }); SearchTxt.val(State.variables.SearchTx); if (UInv.isUndefined(State.variables.ResultLst)) { State.variables.ResultLst = []; } var Results = $("#Results"); if (State.variables.ResultLst.length > 0) { for (var i = 0; i < State.variables.ResultLst.length; i++) { Results.append($("<option></option>").attr("value", State.variables.ResultLst[i]).text(State.variables.ResultLst[i])); } if (State.variables.ResultIdx >= 0) { Results.prop('selectedIndex', State.variables.ResultIdx); } } SearchTxt.focus(); var SearchAll = $("#checkbox-searchall"); SearchAll.on("change", function(event) { // On "Include ALL search terms" checkbox changed. $("#Search button").trigger("click"); }); return true; } if (setup.JSLoaded == 2) { PrepSearch(); } else { prepWait = setInterval(PrepSearch, 100); } <</script>><<set $SearchTx = "">> <<set $ResultLst = []>> <<set $ResultIdx = -1>> <<set $ImgPath = setup.Path + "images/">> <<if !UInv.BagExists("Items")>> <<run UInv.CreateBag("Items")>> <<run UInv.AddItem("Items", "belt")>> <<run UInv.AddItem("Items", "dagger")>> <<run UInv.AddItem("Items", "gold coin")>> <<run UInv.AddItem("Items", "heavy mace")>> <<run UInv.AddItem("Items", "pants")>> <<run UInv.AddItem("Items", "shoes")>> <<run UInv.AddItem("Items", "shortsword")>> <<run UInv.AddItem("Items", "suit")>> <</if>> <<LoadImages>>''getArrayReverseSortedByOtherArray(UnsortedArray, ArrayToSortBy, [RemoveDuplicates = false])'' = UnsortedArray reverse sorted based on ArrayToSortBy and subsorted by UnsortedArray value, if RemoveDuplicates is true, remove any with the same values across both arrays Returns UnsortedArray reverse sorted based on ArrayToSortBy and (''NOT'' reverse) subsorted by UnsortedArray value. This is a case insensitive sort. Returns {{{undefined}}} on error. If RemoveDuplicates is true, it also removes any elements where its pair is duplicated in both arrays. See also: [[getArraySortedByOtherArray]] ''GetBagCountByDefaultType()'' = the number of unique bag types, bags with no default bag type count as unique bag types Returns the number of unique bag types, bags with no default bag type count as unique bag types. ''GetItemCountByDefaultType(BagName/Array)'' = the number of unique item types in each bag (ignores Quantity), items with a default item type of "-" are each counted as separate unique item types Returns the number of unique item types in each bag (ignores Quantity), items with a default item type of "-" are each counted as separate unique item types. Returns {{{undefined}}} on error. ''GetItemCountFullByDefaultType(BagName/Array, DefaultItemType)'' = the total number of items in bag(s) (Quantity included) of that DefaultItemType Returns the total number of items in bag(s) (Quantity included) of that DefaultItemType. Returns {{{undefined}}} on error. ''GetItemsArrayWithAllItemTags(BagName, ItemPropertyName, ItemTagArray)'' = array of all items which have all of their tags in ItemTagArray Returns an array of all items which have all of their tags in ItemTagArray (per the [[ArrayHasAllItemTags]] function), [] if ItemTagArray or the bag is empty, or {{{undefined}}} on error. For example, if we assume the following: {{{ "ItemA" = { [ItemPropertyName]: ["X", "Y", "Z"] } "ItemB" = { [ItemPropertyName]: ["X"] } ItemTagArray = ["X", "Y"] }}} Then "ItemA" will ''NOT'' be included in the array returned by this function, due to having tag "Z", which is not in ItemTagArray. However, "ItemB" ''//will//'' be included, because all of "ItemB"'s tags are found inside ItemTagArray. If you want to get an array of item names with all of the tags in ItemTagArray you need to use [[GetItemsArrayByAllItemTags]] instead. ''GetBagsArrayWithAllProperties(BagPropertyNameArray)'' = array of all bags which have all of the properties in BagPropertyNameArray (per the BagHasAllProperties function) Returns an array of all bags which have all of the properties in BagPropertyNameArray (per the [[BagHasAllProperties]] function), not including bags with no properties, or {{{undefined}}} on error. ''BagHasAllProperties(BagName, BagPropertyNameArray)'' = t/f if all of the bag's properties are listed in BagPropertyNameArray Reurns whether all of the bag's properties are listed in BagPropertyNameArray, false if the bag has no properties, or {{{undefined}}} on error. ''ItemHasAllProperties(BagName, ItemName, ItemPropertyNameArray)'' = t/f if all of the item's properties are listed in ItemPropertyNameArray Returns whether all of the item's properties are listed in ItemPropertyNameArray, false if the item has no properties, or {{{undefined}}} on error. ''GetItemsArrayWithAllProperties(BagName, ItemPropertyNameArray)'' = array of all items which have all of the properties in ItemPropertyNameArray (per the [[ItemHasAllProperties]] function) Returns an array of all items which have all of the properties in ItemPropertyNameArray (per the [[ItemHasAllProperties]] function), or {{{undefined}}} on error. Items which have no properties will not be included. ''GetMatchingItemsArray(BagName, ItemName, SearchBag, [PropertyExceptionArray])'' = array of all items in SearchBag that match ItemName (per the ItemsMatch function), not including excluded property names Returns an array of all items in SearchBag that match ItemName (per the [[ItemsMatch]] function), not including excluded property names, or {{{undefined}}} on error. ''ArrayHasAllItemTags(BagName, ItemName, ItemPropertyName, ItemTagArray)'' = t/f if all of the item's tags exist in ItemTagArray Returns whether all of the item's tags exist in ItemTagArray, or {{{undefined}}} on error. ''GetItemTagCount(BagName, ItemName, ItemPropertyName, Tag)'' = the number of times Tag is found in that tag array Returns the number of times an exact match for Tag is found in an item's tag array, or {{{undefined}}} on error. SugarCube includes [[normalize.css|https://necolas.github.io/normalize.css/]], which tries to make HTML elements work the same in all browsers, but in the cases where they don't, or if you need to work around problems with JavaScript that doesn't work in certain browsers, you can use the following UInv functions to easily detect what browser you're in. ''UInv.isAndroid()'' = true when running on Android ''UInv.isBlackBerry()'' = true when running on BlackBerry ''UInv.isBlink()'' = true when running on a Blink-based browser (Chrome, Opera 15+, etc.) ''UInv.isChrome()'' = true when running on Chrome ''UInv.isEdge()'' = true when running on Edge 20+ ''UInv.isFirefox()'' = true when running on Firefox ''UInv.isIE()'' = true when running on Internet Explorer 6-11 ''UInv.isiOS()'' = true when running on iOS ''UInv.isMobile()'' = true when running on mobile engines (Android, iOS, BlackBerry, and Windows mobile) ''UInv.isOpera()'' = true when running on Opera 8+ ''UInv.isSafari()'' = true when running on Safari 3+ ''UInv.isTwine()'' = true when running in Twine You could also use these functions, along with {{{Browser.userAgent}}}, to add useful information in your error messages, so that those error messages will tell you what browser is being used. ''NOTE:'' It's strongly recommended that these functions should only be used in cases where feature detection cannot be used, since feature detection is generally less likely to cause errors than depending on engine detection. For information on what feature dection is and how to use it, see <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection">MDN: Implementing feature detection</a> for details. <center><h2>UInv Safe Save Code</h2></center>Want to make it so that your users can change their inventory, save immediately (without first going to another passage), and then the inventory will be the same when they reload later? Then you'll want to use the "Safe Save" code below. Normally, if you or the person playing your game change the value of a Twine/SugarCube <<hovertip "A variable which starts with a {{{$}}}.">>story variable<</hovertip>> after the current passage was initially displayed (such as might happen on an inventory screen), and then they save the game (without going to another passage first), any such changes to those variables will ''not'' be saved. The save will instead reflect the values that those variables had when they first entered the passage. If you want to make sure any changes made to UInv values after a particular passage is displayed are stored when saving, first add the code below to your JavaScript section. Then add a {{{SafeSave}}} tag to any passages where the user might want to change UInv values within the passage and then save (before going to another passage), such as might happen in an "inventory" passage or an "equipment shop" passage. <<Title "Usage Notes">> ''**IMPORTANT**'' The {{{SafeSave}}} tag should ''only'' be used on passages which do ''NOT'' modify a UInv object's existing values simply by entering the passage, and also do ''NOT'' use any UInv values upon entering the passage which may change within that passage. Doing the first of those two things will cause those modifications to happen again upon reloading a save in that passage. So, for example, if the old man gives you the fantastically valuable sword when you go to the passage "GetSword", then you would ''NOT'' want to add the {{{SafeSave}}} tag to that passage, otherwise reloading their save in the "GetSword" passage would give the player a second sword. Doing the second will cause the passage to react differently if it's reopened from a saved game. To give an example, say you have a "shop" passage set up so that it checks how much money you have when you enter it, and then the shopkeep greets you differently depending on how much money you have. If you incorrectly add the {{{SafeSave}}} tag to that passage, the shopkeep could greet you warmly due to all the money you have initially. Then, if you spend all of your money, save while still in that passage, and then reload, he could tell you to get out for not having any money instead of greeting you warmly like he did initially. That would happen because you spent all your money at his shop, and that initial money check will now see the saved ending total, instead of the amount the player had initially when they first entered the "shop" passage. Thus, adding the {{{SafeSave}}} tag to a passage should be done with care. Also note that this function does ''NOT'' store the values of any other variables which may also be changed after the passage is opened. See the section at the bottom if you want to add that feature. <<Title "JavaScript Code">> To add this feature, copy this to your JavaScript section: {{{ Config.saves.onSave = function (save) { function UpdateVar(VarName) { if (UInv.isProperty(State.variables, VarName)) { save.state.history[save.state.index].variables[VarName] = State.variables[VarName]; } else if (UInv.isProperty(save.state.history[save.state.index].variables, VarName)) { delete save.state.history[save.state.index].variables[VarName]; } } if (tags().includes("SafeSave")) { // Makes sure that the current state is saved only if the passage has a "SafeSave" tag. UpdateVar("UInvBags"); UpdateVar("UInvCurrentBagName"); UpdateVar("UInvCurrentItemName"); UpdateVar("UInvShowAlerts"); UpdateVar("UInvLastErrorMessage"); UpdateVar("UInvErrorStringAddendum"); UpdateVar("UInvMergeItemMethod"); UpdateVar("UInvUpdatesAreLocked"); UpdateVar("UInvEventHandlers"); } }; }}} If the current passage has a {{{SafeSave}}} tag, that function will get triggered whenever the user tries to save their game in that passage. When it gets triggered it will update the save history to match the current UInv state. <<Title "Modifying the Function">> If you have any other non-UInv story variables which you also want to save if they've been updated after the passage is loaded, you will need to add them to that code as well. To do that you would just add the name of the story variable, without the {{{$}}} in the front, to the list of {{{UpdateVar()}}} calls above. So if you wanted to keep track of {{{$Money}}} as well, you would add a line like this: {{{ UpdateVar("Money"); }}} with the other {{{UpdateVar()}}} lines (the order doesn't matter, it just has to be before the "}" line). ''Note:'' The function ''CANNOT'' be used to store <<hovertip "A variable which starts with an {{{_}}}.">>temporary variables<</hovertip>>, it can only store story variables. <center><h2>Efficient UInv Coding</h2></center>OK, you've got the basics of UInv down, and now you're ready to start programming. However, if you've looked through some of the UInv functions, you can see that some of the function names are quite long. Also, there's a lot of redundant typing to do. Fortunately, UInv has three tricks you can use to make this more efficient. <<Title "Aliases">> Aliases are ways to make shorter/faster/easier to use versions of existing functions. They exist in the section of the UInv code you can edit, just after the {{{// UInv Aliases:}}} line. Several example aliases are already there. When should you create an alias? Well, let's start with an example. Let's say you had to use this line of code repeatedly throughout your code: {{{ <<set _Items = UInv.GetItemsArrayByItemTag("inventory", "type", _itemType)>> }}} Instead of typing the above every time, you could create a simplified alias by adding a JavaScript function like this one to UInv's "Aliases" section: {{{ GetType : function (ItemType) { return UInv.GetItemsArrayByItemTag("inventory", "type", ItemType); }, }}} This creates a new UInv function named "GetType", which itself calls the UInv [[GetItemsArrayByAnyItemTag]] function. Once you've done that, the code you need to write has gone from this: {{{ <<set _Items = UInv.GetItemsArrayByItemTag("inventory", "type", _itemType)>> }}} to just this: {{{ <<set _Items = UInv.GetType(_itemType)>> }}} It's so much shorter now because you've built the bag name ("inventory") and property name ("type") into the "GetType" alias, and only the remaining piece (the "Value" parameter) is being passed as a parameter through your new "GetType" function. If you know a little JavaScript, you can make much more complicated custom UInv functions in the "Aliases" section as well. <<Title "Last Bag/Item Memory">> Most UInv functions will track the last bag and or item name used, marking them as the "current" bag and item names. The current bag and item names will then be the default bag and item names used by subsequent functions when {{{""}}} (an empty string) is passed to the function, in place of where a bag or item name would normally be. If you want to see the current ''BagName'' you can check the value of {{{$UInvCurrentBagName}}} or use the [[GetCurrentBagName]] function. If you want to see the current ''ItemName'' you can check the value of {{{$UInvCurrentItemName}}} or use the [[GetCurrentItemName]] function. You can also set the values of {{{$UInvCurrentBagName}}} and {{{$UInvCurrentItemName}}} directly if you want them to have a certain bag or item name, respectively. Here's an example of how this works in practice. This code: {{{ <<set UInv.AddBag("backpack")>> <<set UInv.AddItem("backpack", "pants")>> <<set UInv.SetItemQuantity("backpack", "pants", 5)>> }}} could be rewritten using this trick as this: {{{ <<set UInv.AddBag("backpack")>> <<set UInv.AddItem("", "pants")>> <<set UInv.SetItemQuantity("", "", 5)>> }}} The [[AddBag]] function will create a "backpack" bag, and set {{{$UInvCurrentBagName}}} to "backpack", making "backpack" the current bag name. Then the [[AddItem]] function adds a "pants" item to the "backpack" bag. The first parameter expects a bag name, so the {{{""}}} there means it will use the current bag name. {{{AddItem}}} also sets {{{$UInvCurrentItemName}}} to "pants", making "pants" the current item name. If the bag name parameter had been "satchel", then the current bag name would have changed to "satchel" as well. Finally, the [[SetItemQuantity]] function sets the number of pairs of pants in the backpack to 5, using the current bag and item names for the first two parameters, respectively. If you've passed an array of bag names or item names to a function, then usually the last thing in that array will become the "current" version. Exceptions to this are when those things no longer exist, such as when deleting bags or items. ''NOTE:'' You should use caution when using the current bag or item names, as some functions may not set them in the way you expect. See the help file for each function to see what the current bag and/or item gets set to by each function. (Sub-Note: *** This information is not actually in help file yet. *** ) <<Title "The {{{<<UInvSet>>}}} Macro">> You may have noticed that all UInv functions need to have {{{UInv.}}} in front of them by now. To help cut down on that redundancy, you can skip that part inside of a {{{<<UInvSet>>}}} macro. This macro wraps each line in {{{<<set (line)>>}}}, and adds {{{UInv.}}} in front of any UInv function calls (including custom aliases). So instead of typing this: {{{ <<set UInv.AddBag("backpack")>> <<set UInv.AddItem("", "pants")>> <<set UInv.SetItemQuantity("", "", 5 + UInv.BagHasItem("", ""))>> <<set _Items = UInv.GetType(_itemType)>> }}} you could just type this: {{{ <<UInvSet>> AddBag("backpack") AddItem("", "pants") SetItemQuantity("", "", 5 + BagHasItem("", "")) _Items = GetType(_itemType) <</UInvSet>> }}} and it would act exactly the same. UInv function names within this macro will have {{{UInv.}}} put in front of them only if ''all'' of the following conditions are met: # they're a valid UInv function name (including aliases) # they're preceded by a new line, a space, a tab, {{{,}}}, {{{+}}}, {{{-}}}, {{{/}}}, {{{*}}}, {{{%}}}, {{{=}}}, {{{<}}}, {{{>}}}, {{{!}}}, {{{&}}}, {{{|}}}, {{{?}}}, {{{(}}}, {{{[}}}, {{{{}}}, or {{{:}}} # they're immediately followed by {{{(}}} (the left parenthesis) # they're not within a string (within a pair of single or double-quotes) ''NOTE:'' When using the {{{<<UInvSet>>}}} macro you should make sure you aren't using any other functions which have the same name as UInv functions, or those functions won't work since they will have {{{UInv.}}} stuck in front of them by this macro. You can work around this by putting a space between the function name and the left parenthesis (e.g. {{{someFunction (parameters)}}}). <center><h2>Arrays vs Generic Objects</h2></center>If you're new to programmimg, you may not be familiar with //arrays// or //generic objects//, so this section should help get you started. Both //arrays// and //generic objects// are useful for storing all sorts of data, but they work differently in how you access that data. Thus choosing the right one for the job is important. <<Title "Creating Arrays and Generic Objects">> The basic way to initialize variables as //arrays// is like this: {{{ <<set _tempVar = []>> /* an empty array */ <<set $storyVar = [ "value" ]>> /* an array with one element */ }}} The basic way to initialize variables as //generic objects// is like this: {{{ <<set _tempVar = {}>> /* an empty generic object */ <<set $storyVar = { parameter: "value" }>> /* a generic object with one property-value pair */ }}} As you can see above, "[...]" basically means "an array" (which is a specific kind of object) and "{...}" means "a generic object". <<Title "Arrays">> //Arrays// use ''numeric indexes'', which start at zero, to uniquely identify each element in an //array//. So: {{{ <<set $numbers = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]>> }}} makes the //story variable// {{{$numbers}}} equal to a ten element array, with indexes numbered 0 - 9. You could access the elements in that //array// like this: {{{ <<print $numbers[3]>> }}} which prints "three". You can determine the length of an //array// by checking its {{{.length}}} property, like this: {{{ <<set $numbers = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]>> <<for _i = 0; _i < $numbers.length; _i++>> <<print $numbers[_i]>> <</for>> }}} That would print out all of the elements in the {{{$numbers}}} //array//. Inside the {{{<<for>>}}} macro above: * {{{_i = 0}}} sets the starting value of {{{_i}}} to 0 * {{{_i < $numbers.length}}} tells it to keep looping if it hasn't reached the end of the {{{$numbers}}} //array// * and {{{_i++}}} means "add one to {{{_i}}} after each loop". The values of each element of an //array// can be of any data type, such as //numbers//, //strings//, //booleans//, or even //arrays// and //generic objects//. Array elements can be of different types within the same //array//. Here are some (but not all) ways to ''add'' items to //arrays//: * {{{<<set $someArray.push(_someVariable)>>}}} which will add the value of {{{_someVariable}}} to the ''end'' of the list of values in the //array//. (See <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push">here for details</a>.) * {{{<<set $someArray.pushUnique(_someVariable)>>}}} which will add the value of {{{_someVariable}}} to the ''end'' of the list of values in the //array// if that value is not already in the list. (See <a href="http://www.motoslave.net/sugarcube/2/docs/#methods-array-prototype-method-pushunique">here for details</a>.) * {{{<<set $someArray.unshift(_someVariable)>>}}} which will add the value of {{{_someVariable}}} to the ''beginning'' of the list of values in the //array//. (See <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift">here for details</a>.) * {{{<<set $someArray.unshiftUnique(_someVariable)>>}}} which will add the value of {{{_someVariable}}} to the ''beginning'' of the list of values in the //array// if that value is not already in the list. (See <a href="http://www.motoslave.net/sugarcube/2/docs/#methods-array-prototype-method-unshiftunique">here for details</a>.) * {{{<<set $someArray.splice(_position, 0, _someVariable)>>}}} which will insert the value of {{{_someVariable}}} before the element at {{{_position}}} in the list of values in the //array//. (See <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice">here for details</a>.) Here are some (but not all) ways to ''remove'' items from //arrays//: * {{{<<set _someVariable = $someArray.pop()>>}}} which will remove the ''last'' value from the list of values in the //array// and returns that removed value. (See <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop">here for details</a>.) * {{{<<set _someVariable = $someArray.shift()>>}}} which will remove the ''first'' value from the list of values in the //array// and returns that removed value. (See <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift">here for details</a>.) * {{{<<set $someArray.delete(_elementValue)>>}}} which will remove ''all'' of the elements from the given //array// which match that element value. (See <a href="http://www.motoslave.net/sugarcube/2/docs/#methods-array-prototype-method-delete">here for details</a>.) * {{{<<set _someVariable = $someArray.deleteAt(_index)>>}}} which will remove the elements at each index given from the list of values in the //array// and returns those removed values as an //array//. (See <a href="http://www.motoslave.net/sugarcube/2/docs/#methods-array-prototype-method-deleteat">here for details</a>.) * {{{<<set _someVariable = $someArray.pluck()>>}}} which will remove a random element from the list of values in the //array// and returns that removed value. (See <a href="http://www.motoslave.net/sugarcube/2/docs/#methods-array-prototype-method-deleteat">here for details</a>.) For more information see <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">the MDN entry on "Array"</a> and <a href="http://www.motoslave.net/sugarcube/2/docs/#methods-array">the SugarCube Array Methods section</a>. <<Title "Generic Objects">> On the other hand, //generic objects// use ''named indexes'' to uniquely identify each property (also known as a "key"). So: {{{ <<set $inventory = { coins : 20, daggers : 1, shirts : 3 }>> }}} makes a //story variable// named {{{$inventory}}} which has three properties, with those three names, and each property has its own value. You could access them like this: {{{ You have <<print $inventory.coins>> coins. }}} which would display "You have 20 coins." As seen above, you can set a //generic object's// data in the format of {{{ { propertyName: value, propertyName: value, ... } }}}, where each ''propertyName'' is a unique string. If a ''propertyName'' starts with a number or includes any non-<<hovertip 'Alphanumeric characters include "a" to "z", "A" to "Z", and "0" to "9".'>>alphanumeric character<</hovertip>> other than {{{_}}} or {{{$}}}, then that ''propertyName'' must be inside quotes. If you want to use the value of a variable for a ''propertyName'', then the variable name must be inside square brackets (e.g. {{{<<set $someObject = { [ _someVariable ] : "value" }>>}}}). The value of each property can be of any data type, such as //numbers//, //strings//, //booleans//, or even //arrays// and //generic objects//. Different properties can have values of different data types. Typically you would ''add'' property-value pairs to //generic objects// like this: * {{{<<set $someGenericObject.propertyName = _someValue>>}}} which adds a property named "''propertyName''" to the object (if necessary) and set that property's value to the same value that "''_someValue''" has. And to ''remove'' a property-value pair you would do this: * {{{<<set delete $someGenericObject.propertyName>>}}} which deletes the property named "''propertyName''" from the object. (See <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete">here for details</a>.) You can get a list of all properties on a //generic object// like this: * {{{<<set _propertyNamesArray = Object.keys($someGenericObject)>>}}} which returns an //array// of //strings// consisting of all property names on the object. (See <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys">here for details</a>.) ** ''Note:'' Unlike //arrays//, //generic objects// are ''unordered lists'', which means that the order that you receive property names from functions like {{{Object.keys()}}} may not always be the same. And you can check to see if a //generic object// has a specific property like this: * {{{<<if UInv.isProperty($someGenericObject, "propertyName")>>}}} where ''propertyName'' is a string that is/contains the name of the property you're trying to verify. (See [[isProperty]] for details.) For more information see <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object">the MDN entry on "Object"</a>. <<Title "Advanced Notes">> ''FEEL FREE TO IGNORE THIS IF YOU'RE FEELING OVERWHELMED:'' As long as we're in the deep end with //story variables// and //objects//... Unlike most variables, //objects// (including //arrays//) are stored by reference, instead of by value. Bascally, instead of the variable holding a value, the variable actually points to ("references") a chunk of data in the computer's memory. So, if you do {{{<<set $ObjectA = $ObjectB>>}}} then within that passage both variables will be pointing to the same chunk of data. So if you change the value of one, the other will change the same way, because they're sharing that data. However, SugarCube "<a href="http://www.motoslave.net/sugarcube/2/docs/#functions-function-clone">clones</a>" //objects// when you load a passage, so after that they'll be pointing to two different chunks of data, with the same values in both chunks. This means that if you do this: {{{ <<set $ObjectA = $ObjectB>> <<set $ObjectB.X = 10>> }}} in one passage, then ''$ObjectA.X'' will //also// get set to ''10''. However, if you change passages and //then// set the value of ''$ObjectB.X'' again, it will no longer affect the value of ''$ObjectA.X''. This is because cloning makes it so that they're no longer two variables referencing the same //object//, but instead are referencing two different //objects//, one of which was copied from the other. Basically, this means that you can't easily compare two //objects// to each other to see if their data is the same. Unless they have the same reference, they will ''not'' be treated as being equal, even if the values inside of those //objects// are the same. To deal with this problem, you can use the UInv [[valuesAreEqual]] function to determine if two //generic objects// or two //arrays// contain all of the same values. <center><h2>Item Collision</h2></center>Explain "item collision"./* Title : Shows the title of a section and allows the Table of Contents to snap to it. */ /* EXAMPLE: <<Title "Sample Code">> */ <<widget "Title">> <<if ndef _SnapToCount>> <<set _SnapToCount = 1>> <<else>> <<set _SnapToCount++>> <</if>> <span @id="'snapto'+_SnapToCount" class="SnapTo">__''<<=$args[0]>>:''__</span> <</widget>> <<widget "Slider">> <<set _Min = $args[4]>> <<if UInv.isUndefined(_Min)>> <<set _Min = 1>> <</if>> <<set _Lbl = $args[5]>> <<if UInv.isUndefined(_Lbl)>> <<set _Lbl = "">> <</if>> <<set _Slider = '<th>' + $args[1] + '</th><td><input data-uinv="slider" type="range" id="' + $args[0] + '" min="' + _Min + '" max="' + $args[3] + '" step="1" value="' + $args[2] + '" class="slider" /></td><td><label id="' + $args[0] + '-value" data-uinv="value"></label>_Lbl</td>'>> <</widget>> <<widget "Disabled">> <span class="disabled" alt="Not yet implemented." title="Not yet implemented." tabindex="0">$args[0]</span> <</widget>> <<widget "ToggleTheme">> Toggle Theme: <div class="toggle-wrapper" id="ToggleTheme"> <div class="rect_2"></div> <div class="rect_1"> <div class="rect_1_inset"></div> </div> <div class="rect_3"></div> <div class="toggle_handler"> <div class="toggle_ellipse"></div> </div> </div> <</widget>> /* HoverTxt : Show notepad icon shows some wikified text in a window of width X pixels above an icon when it's hovered over. */ /* EXAMPLE: <<HoverTxt 200 "text">> */ /* EXAMPLE: <<HoverTxt 300 `someFunction()`>> */ <<widget "HoverTxt">> <<if !Number.isInteger($args[0])>> <<set _width = 330>> /* Default to a width of 330 if an invalid width is passed. */ <<else>> <<set _width = $args[0]>> <</if>> <<set _left = Math.trunc(_width / 2) - 11>> <<if ndef _HoverTxtCount>> <<set _HoverTxtCount = 1>> <<else>> <<set _HoverTxtCount += 1>> <</if>> <a class="hoverTxt" style="text-decoration: none;"><img id="hoverIco" @src="setup.ImagePath+'NoteIcon.png'"> <span @id="'hoverTxt' + _HoverTxtCount" class="hoverBox" @style="'left: -' + _left + 'px; width: ' + _width + 'px;'"> <<print $args[1]>> </span> </a> <</widget>> <<widget "LoadImages">> <<run UInv.AddEventHandler("cacheImages", "Idle", "ImagesLoaded")>> <<if UInv.BagExists("Items")>> <<set _TmpImages = UInv.GetItemsArrayByProperty("Items", "image")>> <<for _i = 0; _i < _TmpImages.length; _i++>> <<set _TmpImages[_i] = UInv.GetItemPropertyValue("Items", _TmpImages[_i], "image")>> <</for>> <<run UInv.cacheImages(setup.ImagePath, _TmpImages)>> <</if>> <</widget>> <<widget "ImagesLoaded">> <<if UInv.BagExists("Items")>> <<set _TmpImages = UInv.GetItemsArrayByProperty("Items", "image")>> <<for _i = 0; _i < _TmpImages.length; _i++>> <<set _img = UInv.GetItemPropertyValue("Items", _TmpImages[_i], "image")>> <<set _imgObj = UInv.getCachedImageObject(setup.ImagePath, _img)>> <<set UInv.AddBagTag("Items", "Images", _img)>> <<set UInv.AddBagTag("Items", "Dimensions", _imgObj.naturalWidth + "x" + _imgObj.naturalHeight)>> <</for>> <<set UInv.SetBagPropertyValue("Items", "DefaultPath", setup.ImagePath)>> <</if>> <</widget>><<if UInv.isFirefox()>><<set _ColorStyle = 'padding: 7px 5px; width: 47px; height: 25px; background-image: url("' + setup.Path + 'images/InsetColorButton.png");'>><<else>><<set _ColorStyle = 'padding: 3px; width: 41px; height: 19px; background-image: url("' + setup.Path + 'images/InsetColorButton.png");'>><</if>><center><h2>__UInv Table Builder__</h2></center><div class="inventory-table" id="inventory" data-uinv="table"></div> <span id="TableDim">(Width: 0px - Height: 0px)</span> -- (save/load themes here) <<nobr>> <div class="accordion"> <h3>__Table:__</h3> <div><table><col width="40%"><col width="32%"><col width="28%"><tr><th>Background Color: <input type="color" value="#ce8126" id="TableBkgColor" @style="_ColorStyle" data-uinv="color"></th><th>Border Color: <input type="color" value="#111111" id="TableBdrColor" @style="_ColorStyle" data-uinv="color"></th><th>Smooth Edges: <input id="smoothedges" type="checkbox" class="macro-checkbox" data-uinv="checkbox" checked></th></tr></table><table><col width="240px"><col width="420px"><col><tr><<Slider "TableOpacity" "Background Opacity:" "100" "100" "0" "%">>_Slider</tr><tr><th>Image Background: <input id="TableImgBkg" type="checkbox" class="macro-checkbox" data-uinv="checkbox" checked></th><td><input id="TableImg" type="file" accept=".jpg, .jpeg, .png, .svg, .gif, .ico" class="link-internal macro-button" style="width: 100%; background-color: #111;" data-uinv="file"></td></tr> <tr><<Slider "table-border" "Border Width:" "1" "50" "0" "px">>_Slider</tr> <tr><<Slider "table-radius" "Corner Radius:" "10" "50" "0" "px">>_Slider</tr> <tr><th>Box-Shadow: <input id="boxshadow" type="checkbox" class="macro-checkbox" data-uinv="checkbox"></th><th>Shadow Color: <input type="color" value="#18f400" id="ShadowColor" @style="_ColorStyle" data-uinv="color"></th></tr> <tr><<Slider "shdoffset-x" "Shadow Offset-X:" "0" "50" "-50" "px">>_Slider</tr> <tr><<Slider "shdoffset-y" "Shadow Offset-Y:" "0" "50" "-50" "px">>_Slider</tr> <tr><<Slider "shdblurradius" "Shadow Blur Radius:" "13" "50" "0" "px">>_Slider</tr> <tr><<Slider "shdspreadradius" "Shadow Spread Radius:" "3" "50" "0" "px">>_Slider</tr> <tr><<Slider "row-count" "Rows:" "3" "50">>_Slider</tr> <tr><<Slider "column-count" "Columns:" "3" "50">>_Slider</tr></table></div> <h3>__Cells:__</h3> <div><table><col width="36%"><col width="30%"><col width="34%"><tr><th>Background Color: <input type="color" value="#ce8126" id="CellBkgColor" @style="_ColorStyle" data-uinv="color"></th><th>Border Color: <input type="color" value="#ae6c30" id="CellBdrColor" @style="_ColorStyle" data-uinv="color"></th><th>Smooth Background: <input id="CellSmoothing" type="checkbox" class="macro-checkbox" data-uinv="checkbox" checked></th></tr></table><table><col width="240px"><col width="420px"><col><tr><<Slider "CellOpacity" "Background Opacity:" "5" "100" "0" "%">>_Slider</tr> <tr><th>Image Background: <input id="CellImgBkg" type="checkbox" class="macro-checkbox" data-uinv="checkbox"></th><td><input id="CellImg" type="file" accept=".jpg, .jpeg, .png, .svg, .gif, .ico" class="link-internal macro-button" style="width: 100%; background-color: #111;" data-uinv="file"></td></tr> <tr><<Slider "cell-border" "Border Width:" "1" "50" "0" "px">>_Slider</tr> <tr><<Slider "border-margin" "Border Margin:" "4" "100" "0" "px">>_Slider</tr> <tr><<Slider "cell-margin" "Margin:" "5" "100" "0" "px">>_Slider</tr> <tr><<Slider "cell-radius" "Corner Radius:" "10" "50" "0" "%">>_Slider</tr> <tr><<Slider "cell-width" "Width:" "50" "250" "1" "px">>_Slider</tr> <tr><<Slider "cell-height" "Height:" "50" "250" "1" "px">>_Slider</tr> <tr><th>Box-Shadow: <input id="cellshadow" type="checkbox" class="macro-checkbox" data-uinv="checkbox" checked></th><th>Shadow Color: <input type="color" value="#ffffff" id="CellShadowColor" @style="_ColorStyle" data-uinv="color"></th></tr> <tr><<Slider "Cellshdoffset-x" "Shadow Offset-X:" "1" "50" "-50" "px">>_Slider</tr> <tr><<Slider "Cellshdoffset-y" "Shadow Offset-Y:" "1" "50" "-50" "px">>_Slider</tr> <tr><<Slider "Cellshdblurradius" "Shadow Blur Radius:" "5" "50" "0" "px">>_Slider</tr> <tr><<Slider "Cellshdspreadradius" "Shadow Spread Radius:" "0" "50" "0" "px">>_Slider</tr></table></div> <h3>__Quantity Text:__</h3> <div><table><col width="30%"><col width="43%"><col width="27%"><tr><th>Text Color: <input type="color" value="#ffffff" id="TextColor" @style="_ColorStyle" data-uinv="color"></th><th>Background Color: <input type="color" value="#000000" id="TextBkgColor" @style="_ColorStyle" data-uinv="color"></th><th>Text Outline: <input id="TextOutline" type="checkbox" class="macro-checkbox" data-uinv="checkbox" checked></th></tr></table>&#8198;''Font:'' <select id="FontName" data-uinv="dropdown"> /* Intentionally left out "Comic Sans" and "Impact". */ <optgroup label="Sans-Serif Fonts (recommended)"> <option style="font-family:Arial" value="Arial" selected="selected">Arial</option> <option style="font-family:'Arial Black'" value="'Arial Black'">Arial Black</option> <option style="font-family:Helvetica" value="Helvetica">Helvetica</option> <option style="font-family:'Lucida Sans Unicode'" value="'Lucida Sans Unicode'">Lucida Sans Unicode</option> <option style="font-family:Tahoma" value="Tahoma">Tahoma</option> <option style="font-family:'Trebuchet MS'" value="'Trebuchet MS'">Trebuchet MS</option> <option style="font-family:Verdana" value="Verdana">Verdana</option> </optgroup> <optgroup label="Serif Fonts"> <option style="font-family:Bookman" value="Bookman">Bookman</option> <option style="font-family:Garamond" value="Garamond">Garamond</option> <option style="font-family:Georgia" value="Georgia">Georgia</option> <option style="font-family:Palatino" value="Palatino">Palatino</option> <option style="font-family:'Palatino Linotype'" value="'Palatino Linotype'">Palatino Linotype</option> <option style="font-family:Times" value="Times">Times</option> <option style="font-family:'Times New Roman'" value="'Times New Roman'">Times New Roman</option> </optgroup> <optgroup label="Monospace Fonts"> <option style="font-family:Courier" value="Courier">Courier</option> <option style="font-family:'Courier New'" value="'Courier New'">Courier New</option> <option style="font-family:'Lucida Console'" value="'Lucida Console'">Lucida Console</option> </optgroup> </select><span id="SampleTxt" style="padding: 0 5px; margin: 0 15px;">Sample Text. ILL1 / ill1</span><h5>(''Note:'' Only <a href='https://www.cssfontstack.com/'>the most widely installed</a> "<a href='https://www.w3schools.com/cssref/css_websafe_fonts.asp'>web-safe</a>" fonts are included in the font list. If you want to use other fonts, such as from <a href='https://fonts.google.com/'>Google Fonts</a>, you will need to add them manually.)</h5><table><col width="205px"><col><col width="60px"><tr><<Slider "FontSiz" "Font Size:" "16" "32" "4" "px">>_Slider</tr></table> <table><col width="23%"><col width="10%"><col width="20%"><col width="25%"><col width="22%"><tr><th>Bold: <input id="BoldFont" type="checkbox" class="macro-checkbox" data-uinv="checkbox"></th><th>Top-</th><th>Left: <input id="FontTL" value=1 name="TxtPos" type="radio" data-uinv="radiobutton"></th><th>Center: <input id="FontTC" value=2 name="TxtPos" type="radio" data-uinv="radiobutton"></th><th>Right: <input id="FontTR" value=3 name="TxtPos" type="radio" data-uinv="radiobutton"></th></tr> <tr><th>Italic: <input id="ItalicFont" type="checkbox" class="macro-checkbox" data-uinv="checkbox"></th><th>Bottom-</th><th>Left: <input id="FontBL" value=11 name="TxtPos" type="radio" data-uinv="radiobutton"></th><th>Center: <input id="FontBC" value=12 name="TxtPos" type="radio" data-uinv="radiobutton"></th><th>Right: <input id="FontBR" value=13 name="TxtPos" type="radio" data-uinv="radiobutton" checked></th></tr></table><table><col width="205px"><col><col width="60px"><tr><<Slider "FontOpacity" "Font Opacity:" "100" "100" "0" "%">>_Slider</tr><tr><<Slider "TxtBkgOpacity" "Background Opacity:" "50" "100" "0" "%">>_Slider</tr> <tr><<Slider "TxtTBOffset" "T+B Offset:" "-3" "50" "-50" "px">>_Slider</tr> <tr><<Slider "TxtLROffset" "L+R Offset:" "3" "50" "-50" "px">>_Slider</tr> <tr><<Slider "TxtTBPadding" "T+B Padding:" "3" "20" "0" "px">>_Slider</tr> <tr><<Slider "TxtLRPadding" "L+R Padding:" "3" "20" "0" "px">>_Slider</tr> <tr><<Slider "TxtRadius" "Background Corner Radius:" "10" "50" "0" "px">>_Slider</tr></table></div> </div> <</nobr>> ''Bag Name:'' <input type="text" id="BagName" style="width: calc(100% - 150px); min-width: unset;" value="inventory"> ''ItemTable style:'' Copy and paste this into your story's "Stylesheet" section. <<textarea "_ItemTable" "">> ''ItemTable code:'' Copy and paste this code into the passage(s) in your story where you want the table to appear. <<textarea "_TableCode" "">> <<timed 50ms>><<run $("#FontName").val("Arial")>><</timed>> ''SwapItemsProperties(BagName1, ItemName1, BagName2, ItemName2, ItemPropertyName/array)'' Swaps the given properties of two items. Returns true on success or {{{undefined}}} on error. You cannot swap the ''UInvDefaultItemType'' or ''UInvVariableType'' properties using this function. Additionally, items with pockets cannot swap the ''UInvQuantity'' property, as you cannot have stacks of items with pockets. ''FixTableCells(BagName, UInvTable)'' Makes sure each item is assigned a unique cell by setting the "UInvCell" property on each item. Tries to make sure items will display in table UInvTable if that parameter is used, assuming there is enough room. Returns {{{true}}} on success or {{{undefined}}} on error. The value of the "UInvCell" property determines the placement of the item on a table. The top-left cell is 0, then each cell after that (left-to-right on each row) will be one number higher. To get a table to update you will need to do: {{{ <<run UInv.UpdateDisplay()>> }}} Calling FixTableCells is only needed if you are working with tables and want to set the item order prior to displaying the table. The value of ''UInvTable'' should come from a jQuery reference to a UInv table element, like this: {{{ UInv.FixTableCells("Backpack", $("#Backpack")); }}} The bag name and table ID must match, as shown above. See also: [[UpdateDisplay]] ''UpdateDisplay([Container])'' Updates the display of any UInv HTML elements, such as tables. The Container parameter is optional, and will equal "document" if it's not set. If you are calling this from within a {{{$(document).on(':passagerender', function (ev) { /* code here */ } );}}} function, then the Container parameter should be "ev.content" (without the quotes). This function will call the [[FixTableCells]] function to guarantee that no items share the same cell. This function is called automatically any time a bag is "touched" (the quantity of items in the bag changes) and also whenever [[DecrementUpdateLock]] reduces the "lock count" to zero. You only need to call this function manually if any changes you make to items (such as changing the "UInvCell" property) do not trigger a "touched" event on a bag and you aren't using [[DecrementUpdateLock]]. To prevent automatic display updates you should use a pair of [[IncrementUpdateLock]] and [[DecrementUpdateLock]] function calls around the code which updates bags and items. Those locks, however, will not prevent manual calls to the {{{UpdateDisplay}}} function from working. See also: [[FixTableCells]] and [[WasTouched]] ''isGenericObject(Value)'' = t/f Returns if a value is a generic object. Passing non-generic objects, such as arrays, will cause this function to return false. If you want to include other objects, use [[isObject]] instead. ''getObjectProperties(Object, [Ext])'' Returns all of the properties and values of an object as a string. Non-objects get returned unchanged. You can use this if you want to take a look at all of the values and properties of an object. The {{{Ext}}} parameter is optional, and lets you include the name of the object in the output. Example: {{{ <<= UInv.getObjectProperties($SomeObject, "$SomeObject")>> }}} ''Note:'' This goes through all of the objects, sub-objects, arrays, etc., so make sure there are no circular object references in the object passed to this function, because that would cause it to lock up in an infinite loop. ''GetUpdateLocks()'' Returns the "lock count" on display updates. To lock display updates you should use a pair of [[IncrementUpdateLock]] and [[DecrementUpdateLock]] function calls around the code which updates bags and items. See also: [[UpdateDisplay]] and [[WasTouched]] ''UpdatesAreLocked()'' Returns whether automatic display updates are locked or not. See also: [[UpdateDisplay]] ''GetItemByType(BagName, ItemType)'' Returns a random ItemName that is of type ItemType. If there are none it returns "", otherwise it returns {{{undefined}}} on error. ''GetItemsArrayByType(BagName, ItemType)'' Returns an array of ItemNames that are of type ItemType. If there are none it returns an empty array. Returns {{{undefined}}} on error. ''cacheImages(Path, ImageName/array, [Handler])'' Allows you to preload images. You can use the handler to receive notifications about load or error events. Returns {{{undefined}}} when passed invalid parameters. The {{{Handler}}} is optional. You only need it if you want to be notified when images load or fail to load into the cache. If included, the {{{Handler}}} should be a //string// which refers to either a {{{setup}}} function or a {{{<<widget>>}}}. See below for examples and [[AddEventHandler]] and [[CallEventHandlerEx]] for additional details. ''NOTE:'' The cache gets flushed whenever the game is reloaded or restarted. Also, once the maximum number of cached images (default = 100) is exceeded, the oldest images will be flushed out until it's down to the maximum number. Do ''NOT'' depend on files to exist in the cache. You can get information about a cached images using [[getCachedImageObject]]. A copy of the image in the cache is also passed to the {{{Handler}}} function, if you include one when calling {{{cacheImages}}}. So, if you passed the //string// ''"MyHandler"'' as the {{{Handler}}} parameter, then for a JavaScript handler you would do something like this in your JavaScript section: {{{ setup.MyHandler = function (Value) { (Your JavaScript code goes here.) }; }}} And for a {{{<<widget>>}}} handler you would do something like this: {{{ <<widget "MyHandler">> <<set _Value = _UInvEvent>> (Your Twine code goes here.) <<set _UInvReturn = _ReturnValue>> /* only needed if the handler expects a return value */ <</widget>> }}} (As with all widgets, the above widget code must be in a passage with a "widget" tag. See the <a href="http://www.motoslave.net/sugarcube/2/docs/#macros-macro-widget">SugarCube widget documentation</a> for details.) The properties on the {{{Image}}} returned through either of those two functions are: * {{{Image.path}}} = The {{{Path}}} passed to {{{cacheImages}}} for this image. * {{{Image.filename}}} = The {{{ImageName}}} passed to {{{cacheImages}}} for this image. * {{{Image.URL}}} = The {{{Path}}} + {{{ImageName}}} passed to {{{cacheImages}}} for this image. * {{{Image.src}}} = This will be the same as URL unless the image is waiting to load, in which case it will be an empty string (""). * {{{Image.naturalWidth}}} = Once the image is loaded, this will be the image's actual width. * {{{Image.naturalHeight}}} = Once the image is loaded, this will be the image's actual height. * {{{Image.handler}}} = The {{{Handler}}} passed to {{{cacheImages}}} for this image, or "null" if no handler was passed. * {{{Image.status}}} = This will either be "Waiting...", "Loading...", "Loaded", or "Error", depending on the image's status. ''DO NOT'' modify any of those values or the cache may not function properly. If you want to be notified when the cache is done trying to load ''all'' images, you can add an "Idle" handler for "cacheImages" events like this: {{{ <<run UInv.AddEventHandler("cacheImages", "Idle", "MyHandler")>> }}} See [[AddEventHandler]] for details. You can find the status of the whole cache by looking at the following properties on {{{setup.UInvImageCache}}}: * {{{loading}}} = The total number of images currently downloading. Should never be higher than {{{maxConcurrent}}}. * {{{complete}}} = The total number of images that have either successfully loaded or failed to load. * {{{loaded}}} = The total number of images that have successfully loaded. * {{{errors}}} = The total number of images that have failed to load. * {{{waiting}}} = The total number of images waiting to load. * {{{total}}} = The total number of images in all possible loading states ("Waiting...", "Loading...", "Loaded", and "Error"). Should never be higher than {{{maxCache}}}. * {{{maxConcurrent}}} = The maximum number of concurrent downloads. Defaults to 5. * {{{maxCache}}} = The maximum number of cached images. Defaults to 100. ''DO NOT'' modify any of those values or the cache may not function properly. You can get rid of cached images using [[flushCachedImages]] or [[flushAllCachedImages]]. You can also use {{{flushAllCachedImages}}} to set the maxConcurrent (default = 5) and maxCache (default = 100) values. Changing those values should normally be done with {{{flushAllCachedImages}}} in the {{{StoryInit}}} passage, so that you don't have to flush the existing cache. To best use this you would put this in the passage where you want the images to start loading, which will typically be a passage or two before they're displayed: (change the {{{path}}} and {{{images}}} to your path and your image names) {{{ <<script>> $(document).one(':passageend', function (ev) { var path = "images/"; var images = ["Image1.gif", "Image2.png", "Image3.jpg"]; var CacheWait = setInterval(function () { if ($("#init-screen").css("display") == "none") { clearInterval(CacheWait); UInv.cacheImages(path, images, CacheEvent); } }, 300); }); function CacheEvent(Image) { /* Your JavaScript event handler code goes here. */ } <</script>> }}} That triggers the {{{cacheImages()}}} function only after the passage is loaded and displayed. See [[getCachedImageObject]] to see how to get access to specific images in the cache. ''flushAllCachedImages([MaxConcurrent], [MaxCache])'' Clears out all cached images. Also lets you set the maximum number of concurrent images to download (defaults to 5) and the maximum images to cache (defaults to 100). Returns true on success and {{{undefined}}} on error. See: [[cacheImages]] ''flushCachedImages(Path, ImageName/array)'' Allows you to manually unload previously cached images. Returns {{{true}}} on success or {{{undefined}}} on error. See: [[cacheImages]] ''getCachedImageObject(Path, ImageName)'' Returns a reference to the cached image object. This function returns {{{null}}} if the image is not in the cache, or {{{undefined}}} on error. ''Note:'' You should ''not'' depend on images to exist in the cache, since if the player reloads the game, then the cache will likely be empty. The object which is returned by this function is an Image object, with some extra properties. The properties you'll likely need are: * {{{.status}}} = This will either be "Waiting...", "Loading...", "Loaded", or "Error", depending on the image's status. * {{{.path}}} = The path passed to {{{cacheImages}}} for this image. * {{{.filename}}} = The filename passed to {{{cacheImages}}} for this image. * {{{.URL}}} = The path + filename passed to {{{cacheImages}}} for this image. * {{{.src}}} = This will be the same as URL unless the image is waiting to load, in which case it will be an empty string (""). * {{{.naturalWidth}}} = Once the image is loaded, this will be the image's actual width. * {{{.naturalHeight}}} = Once the image is loaded, this will be the image's actual height. * {{{.handler}}} = The handler passed to {{{cacheImages}}} for this image, or "null" if no handler was passed. ''DO NOT'' modify any of those values or the cache may not function properly. See: [[cacheImages]] ''SetItemPropertyValues(BagName, ItemName, ValuesObject)'' Updates and/or adds values to multiple properties on an item. Returns "true" if all items get added successfully, "false" if some items fail, or {{{undefined}}} on error. ''ValuesObject'' must be a generic object in the format of {{{ { propertyName: value, propertyName: value, ... } }}}, where each ''propertyName'' is a unique string. If a ''propertyName'' starts with a number or includes any alphanumeric character ("a" to "z", "A" to "Z", or "0" to "9") other than {{{_}}} or {{{$}}}, then that ''propertyName'' must be inside quotes. If you want to use the value of a variable for a ''propertyName'', then the variable name must be inside square brackets ({{{[ ]}}}). ''docHasCSSElement(CSSElement)'' If document has CSS element "CSSElement" (e.g. ".xyz:hover"), returns the element's <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration">CSSStyleDeclaration object</a>, otherwise returns "false". ''isArrayOfArrays(Value)'' = t/f Test an array to see if all the values are arrays. Returns {{{undefined}}} if ''Value'' is not an array. ''isArrayOfGenericObjects(Value)'' = t/f Test an array to see if all the values are generic objects. Returns {{{undefined}}} if ''Value'' is not an array. ''isArrayOfIntegers(Value)'' = t/f Test an array to see if all the values are integers. Returns {{{undefined}}} if ''Value'' is not an array. ''isArrayOfObjects(Value)'' = t/f Test an array to see if all the values are objects. Returns {{{undefined}}} if ''Value'' is not an array. ''Note:'' "Objects" includes not just generic objects, but also arrays, Date objects, Map objects, Set objects, and basically anything else declared using the "new ObjectName()" format. If you want to test for an array of //generic// objects, use [[isArrayOfGenericObjects]] instead. See also: [[isArrayOfArrays]], [[isArrayOfDates]], [[isArrayOfMaps]], [[isArrayOfSets]] ''IncrementUpdateLock()'' Increases the "lock count" by one. Functions which would trigger display updates will not do so while the lock count is greater than zero. The lock status can be tested using [[UpdatesAreLocked]]. [[UpdateDisplay]] can still be triggered directly though. See also: [[DecrementUpdateLock]] ''DecrementUpdateLock()'' Reduces the "lock count" by one, to a minimum of zero. Functions which would trigger display updates will not do so while the lock count is greater than zero. [[UpdateDisplay]] will be called when the lock count is reduced to zero. The function returns the value of the lock count after it was decremented. The lock status can be tested using [[UpdatesAreLocked]]. [[UpdateDisplay]] can still be triggered directly though. See also: [[IncrementUpdateLock]] ''AddEventHandler(Group, Event, Handler, [Options])'' Adds an event handler. If that exact handler already exists then it returns the existing {{{HandleID}}}, otherwise returns a new {{{HandleID}}} on success, or {{{undefined}}} on error. (A {{{HandleID}}} is a unique identifier for a {{{Group}}} + {{{Event}}} handler.) See below for the list of {{{Groups}}} and {{{Events}}} you can build handlers for. The {{{Handler}}} is a string which refers to either a {{{setup}}} function or a {{{<<widget>>}}}. See [[CallEventHandlerEx]] for details. The optional {{{Options}}} parameter can be used trigger the handler only if all event properties match the {{{Options}}} properties. If an event will trigger one or more event handlers based on matching {{{Options}}}, then any other more general event handlers, which only match the {{{Group}}} and {{{Event}}}, will not be triggered. ''{{{general}}} events:'' * {{{MouseDown}}} * {{{MouseUp}}} ''{{{bag}}} events:'' * {{{Touched}}} ''{{{table}}} events:'' * {{{Accept}}} * {{{DragStart}}} * {{{Drop}}} * {{{DragStop}}} ''{{{radialMenu}}} events:'' * {{{Open}}} * {{{WedgeClick}}} * {{{DisabledWedgeClick}}} * {{{Cancel}}} ''{{{cacheImages}}} events:'' * {{{Loaded}}} * {{{Error}}} * {{{Idle}}} {{{ All events: ----------- + Event .eventGroup = this event's Group type .eventType = this event's Event type .handlerID = HandlerID which is triggering this event "general" events: ----------------- - MouseDown (sends MouseDown event) > See: https://developer.mozilla.org/en-US/docs/Web/Events/mousedown https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent + Event (no additional properties besides .eventGroup, .eventType, and .handlerID) + Return = { stopPropagation: true } (prevents event from further propagating) > See: https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation - MouseUp (sends MouseUp event) > See: https://developer.mozilla.org/en-US/docs/Web/Events/mouseup https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent + Event (no additional properties besides .eventGroup, .eventType, and .handlerID) + Return = { stopPropagation: true } (prevents event from further propagating) > See: https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation "bag" events: ------------- - Touched (sends generic object) [handle multi-touch Start and Stop events?] + Event .bagName = name of bag which is being marked as touched .lockCount = the current display update "lock count" + Return = { ignoreTouch: true } (prevents bag from being marked as Touched) "table" events: --------------- IMPORTANT: Table drag-drop events require the inclusion of jQuery UI. See the UInv sample code which demonstrates how to do this. - Accept (sends element to be dropped) NOTE: The table Accept event gets called many times during drag-and-drop actions. It gets called once for each droppable element after DragStart and before DragStop, plus once on each DragOver and DragOut event. Any event handlers for this event should finish as quickly as possible. + Event .srcBag = name of the bag the item was dragged from .draggedItem = name of the dragged item .destBag = name of the bag it's being dropped into .droppedOnItem = if it's being dropped on another item it's the item's name, otherwise it's "" (an empty string) .newCellNo = the UInvCell number in destBag that item is being dropped on .acceptVal = the current choice of whether to accept or reject the drop + Return = { acceptVal: true/false } (prevents allows/prevents drop action) - DragStart (sends DragStart event) + Event .srcBag = name of the bag the item was dragged from .draggedItem = name of the dragged item .ui = the DragStart event's UI object + Return (none) - DragStop (sends DragStop event) + Event .srcBag = name of the bag the item was dragged from .draggedItem = name of the dragged item .ui = the DragStop event's UI object + Return (none) - Drop (sends Drop event) + Event .srcBag = name of the bag the item was dragged from .draggedItem = name of the dragged item .oldCellNo = the UInvCell number in srcBag that the item was dragged from .destBag = name of the bag it's being dropped into .droppedOnItem = if it's being dropped on another item it's the item's name, otherwise it's "" (an empty string) .newCellNo = the UInvCell number in destBag that item is being dropped on .pos = { x: mouseLeft, y: mouseTop } .ui = the Drop event's UI object + Return = { overrideDefaultAction: true } (prevents default drop action) = { openRadialMenu: true } (opens the radial menu, overrides the default drop action; requires .radialMenuWedgeItems and .radialMenuHandler) = { radialMenuWedgeItems: UInvRadialWedgeItems } (see DisplayRadialMenu) = { radialMenuHandler: Handler } (see DisplayRadialMenu) = { radialMenuOptions: UInvRadialOptions } (see DisplayRadialMenu) ToDo: add ItemClick and ItemDoubleClick events "radialMenu" events: -------------------- - Open (sends radial menu div element) + Event .radialMenuWedgeItems = WedgeItems; .radialMenuHandler = Handler; .radialMenuOptions = Options; + Return = { radialMenuWedgeItems: UInvRadialWedgeItems } (see DisplayRadialMenu) = { radialMenuHandler: Handler } (see DisplayRadialMenu) = { radialMenuOptions: UInvRadialOptions } (see DisplayRadialMenu) - WedgeClick (sends MouseUp event) + Event .wedgeID = The wedge's ID number (0 = center, 1 = top, 2... rotate clockwise) .wedgeData = The wedge's data string .wedgeDisabled = false .srcBag = name of the bag the item was dragged from .draggedItem = name of the dragged item .oldCellNo = the UInvCell number in srcBag that the item was dragged from .destBag = name of the bag it's being dropped into .droppedOnItem = if it's being dropped on another item it's the item's name, otherwise it's "" (an empty string) .newCellNo = the UInvCell number in destBag that item is being dropped on .radialMenuWedgeItems = current radialMenuWedgeItems values .pos = { x: radial menu center X position, y: radial menu center y position } .radialMenuHandler = current radialMenuHandler value .radialMenuOptions = current radialMenuOptions values + Return = { keepOpen: true } (don't close radial menu) = { overrideDefaultAction: true } (prevents default click action) = { radialMenuWedgeItems: UInvRadialWedgeItems } (see DisplayRadialMenu) = { radialMenuHandler: Handler } (see DisplayRadialMenu) = { radialMenuOptions: UInvRadialOptions } (see DisplayRadialMenu) - DisabledWedgeClick (sends MouseUp event) + Event .wedgeID = The wedge's ID number (0 = center, 1 = top, 2... rotate clockwise) .wedgeData = The wedge's data string .wedgeDisabled = true .srcBag = name of the bag the item was dragged from .draggedItem = name of the dragged item .oldCellNo = the UInvCell number in srcBag that the item was dragged from .destBag = name of the bag it's being dropped into .droppedOnItem = if it's being dropped on another item it's the item's name, otherwise it's "" (an empty string) .newCellNo = the UInvCell number in destBag that item is being dropped on + Return = { keepOpen: false } (close radial menu) = { radialMenuWedgeItems: UInvRadialWedgeItems } (see DisplayRadialMenu) = { radialMenuHandler: Handler } (see DisplayRadialMenu) = { radialMenuOptions: UInvRadialOptions } (see DisplayRadialMenu) - Cancel (sends :passagerender event for "NewPassage", otherwise sends MouseDown/Up event) + Event .cancelType = "NewPassage", "MouseDown", or "MouseUp" > See: http://www.motoslave.net/sugarcube/2/docs/#navigation-event-passagerender http://www.motoslave.net/sugarcube/2/docs/#passage-api https://developer.mozilla.org/en-US/docs/Web/Events/mousedown https://developer.mozilla.org/en-US/docs/Web/Events/mouseup https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent + Return = { keepOpen: true } (don't close radial menu) "cacheImages" events: --------------------- - Loaded (triggered on "load" events) > See: https://developer.mozilla.org/en-US/docs/Web/Events/load https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onload + Event .path = image's path .filename = image's filename .URL = image's URL (= .path + .filename) .tries = the number of times the image has tried to load .src = image's source URL .imageGroup = (optional) if the handler was set using UInv.cacheImages, this is a unique group ID + Return (none) - Error (triggered on "error" and "abort" events) > See: https://developer.mozilla.org/en-US/docs/Web/Events/error https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onabort + Event .path = image's path .filename = image's filename .URL = image's URL (= .path + .filename) .tries = the number of times the image has tried to load .src = image's source URL .imageGroup = (optional) if the handler was set using UInv.cacheImages, this is a unique group ID + Return = { retryLoad: true } (retry loading this image) - Idle (triggered after the last image in the cache has been processed) + Event .complete = The total number of images that have either successfully loaded or failed to load. .loaded = The total number of images that have successfully loaded. .errors = The total number of images that have failed to load. + Return (none) }}}''DeleteEventHandler(Group, Event, Handler/HandlerID, [Options])'' Deletes any matching event handlers. Returns the number of deleted handlers, or {{{undefined}}} on error. See also: [[AddEventHandler]] ''CallEventHandlerEx(Group, Event, Values)'' Triggers any matching event handlers and passes the {{{Values}}} object to them. Returns an array of returned objects from all triggered handlers (returns will all either be generic objects or undefined), or returns {{{undefined}}} on error. The length of that array can be used to determine how many handlers were triggered. Use [[CallEventHandler]] to get all of the returns combined into a single generic object. If the handler is a function on the {{{setup}}} object, then it will be called as {{{setup.Handler(Values)}}}. If the handler is a {{{<<widget>>}}}, then it will be called as {{{<<Handler _UInvEvent>>}}}. Values can be returned from the widget by setting {{{_UInvReturn}}}. Both the {{{_UInvEvent}}} and {{{_UInvReturn}}} variables will be wiped immediately after the widget finishes using them. Some events can use certain return values, which should be passed as a generic object. See the specific {{{Group}}}/{{{Event}}} for details {{{ *** (TBD) *** }}}. See [[AddEventHandler]] for a list of {{{Group}}} and {{{Event}}} values. ''DisplayRadialMenu(WedgeItems, Position, [Handler], [Options])'' {{{ *** TBD *** }}} ''GetEventHandlerByID(Group, Event, HandlerID)'' Returns a {{{UInvEventHandler}}} object if one exists, or {{{null}}} if none exist, or {{{undefined}}} on error. See also: [[AddEventHandler]] ''GetMatchingEventHandlersArray(Group, Event, [Options], [Handler])'' Returns an array of the {{{HandleID}}} of all handlers which match the parameters passed in ({{{Handler}}} and/or {{{Options}}} are optional), or it returns {{{undefined}}} on error. See also: [[AddEventHandler]] Code under construction. ''CallEventHandler(Group, Event, Values)'' Triggers any matching event handlers and passes the {{{Values}}} object to them. Returns a generic object from all of the combined returned objects from all triggered handlers, or returns {{{undefined}}} on error. Use [[CallEventHandlerEx]] to get an array of all returned objects from all triggered handlers instead. If the handler is a function on the {{{setup}}} object, then it will be called as {{{setup.Handler(Values)}}}. If the handler is a {{{<<widget>>}}}, then it will be called as {{{<<Handler _UInvEvent>>}}}. Values can be returned from the widget by setting {{{_UInvReturn}}}. Both the {{{_UInvEvent}}} and {{{_UInvReturn}}} variables will be wiped immediately after the widget finishes using them. Some events can use certain return values, which should be passed as a generic object. See the specific {{{Group}}}/{{{Event}}} for details {{{ *** (TBD) *** }}}. See [[AddEventHandler]] for a list of {{{Group}}} and {{{Event}}} values. ''combineGenericObjects(Obj1, Obj2)'' Returns a new object that has the combined properties of Obj1 and Obj2, with Obj2's properties preferred when both objects have matching property names. Returns {{{undefined}}} on error. ''getRandomHexString()'' Returns a random hexidecimal (0-9 and a-f) string of 6 characters. This can be useful if you need to generate a random ID. ''BagData(DefaultBagType, [PropertiesOnly])'' This function is the one that stores the descriptions of your custom bags, which you can design using the [[Bag Builder]]. You should ''not'' call this function directly. Use [[GetDefaultBagObject]] if you want to access that information. To find the place where you should add your default bags to the UInv JavaScript code, search for this text: {{{ YOUR DEFAULT BAGS GO BELOW THIS LINE. }}} See [[GetDefaultBagObject]] for details on how to add your data there. ''ItemData'' This function is the one that stores your custom items that you can design using the [[Item Builder]], and is called by [[GetDefaultItemObject]] to get that information. You should not call this function directly. See [[GetDefaultItemObject]] for details on how to add your data there. ''arrayObjectIncludes(ArrayOfGenericObjects, ObjProperty, Value)'' Returns whether the array has any objects with the property ObjProperty that has a matching value, or {{{undefined}}} on error. Searches an array for generic objects with a property of ObjProperty that == Value. Returns {{{true}}} if it finds any matches, {{{false}}} when unable to find any matches, and {{{undefined}}} on error. <center><h2>Pocket/Container Functions</h2></center>For reference, "pockets" are bags connected to "containers", and "containers" are items that have "pockets". - [[AddExistingBagAsPocket]](BagName, ItemName, PocketName, PocketBagName) - [[AddPocket]](BagName, ItemName, PocketName, [DefaultBagType]) - [[BagHasSpecificItem]](MainBagName, ItemBagName, ItemName) - [[BagIsPocket]](BagName) - [[ContainerHasItem]](ContainerBagName, ContainerName, ItemName) - [[ContainerHasPocketBag]](ContainerBagName, ContainerName, BagName) - [[CreatePocket]](BagName, ItemName, PocketName) - [[DeletePocket]](BagName, ItemName, PocketName) - [[GetAllBagPockets]](BagName/Array, [NoSourceBag]) - [[GetAllContainerPockets]](ContainerBagName, ContainerName) - [[GetContainerIndex]](BagName, PocketName) - [[GetItemPocketBagArray]](BagName, ItemName) - [[GetItemPocketBagName]](BagName, ItemName, [PocketName]) - [[GetItemPocketNameArray]](BagName, ItemName) - [[GetItemPocketObject]](BagName, ItemName) - [[GetPocketBagContainerArray]](PocketBagName) - [[GetPocketBagsPocketName]](BagName, ItemName, PocketBagName) - [[GetPocketDepth]](BagName) - [[ItemHasPocket]](BagName, ItemName, [PocketName]) - [[MoveItemFromPocket]](ContainerBagName, ContainerItemName, PocketName, ItemName, DestinationBagName, [Quantity]) - [[MoveItemToPocket]](SourceBagName, SourceItemName, DestinationBagName, DestinationItemName, DestinationPocketName, [Quantity]) - [[MovePocket]](SourceBagName, SourceItemName, SourcePocketName, DestinationBagName, DestinationItemName, [DestinationPocketName]) - [[UnlinkPocketBagFromContainer]](ContainerBagName, ContainerName, PocketBagName) - [[UnlinkPocketFromContainer]](ContainerBagName, ContainerName, [PocketName]) <center><h2>The UInv Data Structure</h2></center>While it's generally not advisable to interact with the UInv data structure directly, there may be some cases where it's necessary. This section details what variables UInv uses, how they're structured, and what they mean. ''Always available variables:'' {{{$UInvBags}}} = This is a generic object which stores the UInv bag and item data. (See details below.) {{{$UInvMergeItemMethod}}} = This holds the method for handling item collision in some functions. (See [[SetMergeItemMethod]] and [[Item Collision]] for details.) {{{$UInvEventHandlers}}} = This stores various event handlers for the [[Display Functions]]. (See [[AddEventHandler]] for details.) {{{$UInvLastErrorMessage}}} = This is a string variable which holds the last error message, or "" if there have been no errors. You can use the [[ClearErrors]] function to clear this value, or use the [[GetLastError]] function to read this value and optionally clear it as well. ''Sometimes available variables:'' {{{$UInvShowAlerts}}} = If this variable exists then it will either equal {{{false}}} or the sum of the various {{{UInv.ERROR_*}}} values. If it does not exist then it's equivalent to being set to {{{false}}}. (See the [[SetUserAlerts]] function for details.) {{{$UInvErrorStringAddendum}}} = If it exists, this variable is the string of text that gets added to the end of error messages. (See the [[SetUserAlerts]] function for details.) {{{$UInvUpdatesAreLocked}}} = A positive integer indicating the number of locks when automatic display updates are locked. If it does not exist then updates aren't locked. (See the [[UpdateDisplay]] function for details.) {{{setup.UInvImageCache}}} = This uses the SugarCube {{{setup}}} object to store the state of the image cache as a generic object in the following form (with the default values): {{{ { waiting: 0, /* Total images waiting to start downloading */ loading: 0, /* Total images currently downloading */ loaded: 0, /* Total images loaded succesfully */ errors: 0, /* Total images that failed to load */ complete: 0, /* Total images loaded + errors */ total: 0, /* Total images in any state in the cache */ maxConcurrent: 5, /* Maximum images to download simultaneously */ maxCache: 100, /* Maximum images to store in the image cache */ images: [] /* An array of the Image objects, sorted newest to oldest, use the "getCachedImageObject" function to access these directly */ } }}} {{{$UInvCurrentBagName}}} = The last BagName used. {{{$UInvCurrentItemName}}} = The last ItemName used. The value of those two variables will act as the default value if you call a UInv function and put {{{""}}} where those parameters go in that function call. This allows you to make multiple function calls more easily. For example: {{{ <<set UInv.AddBag("backpack")>> <<set UInv.AddItem("", "pants")>> /* "" = "backpack" */ <<set UInv.SetItemQuantity("", "", 5)>> /* "", "" = "backpack", "pants" */ }}} That will create a "backpack" bag, add a "pants" item to the "backpack" bag, and then set the number of pairs of pants to 5. That's because the [[AddBag]] function sets {{{$UInvCurrentBagName}}} to "backpack", so when the [[AddItem]] function is called, passing {{{""}}} as the BagName parameter will cause it to use the last BagName used. ''The {{{$UInvBags}}} data structure:'' It's strongly advised that you do not use the {{{$UInvBags}}} variable directly, even just reading it directly, because UInv uses some tricks to reduce the size of the game history and save files. The information below is strictly for advanced usage only. {{{ $UInvBags { BagName : { [ UInvTouched : true/false, ] (unless it's true) UInvProperties : { [ UInvVariableType : "", ] (if a bag's DefaultBagType is variable) property object for bag ... (done in "BagPropertyName : value" format) }, [ UInvDefaultBagType : "DefaultBagTypeString", ] (only if the type and bag name are not the same, or "-" if the bag has no bag type) [ UInvContainer : [ { BagName : "name", ItemName : "name", PocketName : "name" }, ... ], ] (only if it's a pocket) ItemName : { [ UInvQuantity : positive integer, ] (unless the quantity == 1) [ UInvDefaultItemType : "DefaultItemTypeString", ] (only if it's based on a default type) [ UInvVariableType : "", ] (if an item's DefaultItemType is variable) [ UInvPocket : { "PocketName" : "BagName", ... } ] (only if it has pockets) [ UInvCell : positive integer, ] (only if it's in a table) property object for item ... (done in "ItemPropertyName : value" format) }, next item in bag ... (ItemName format) }, next bag ... (BagName format) } }}} Properties within brackets may not exist; the reasons why will be in parentheses to the right (exception: the UInvContainer value is an array). Also, item and bag properties will not exist if the item/bag is of a default type, unless the item/bag is also a variable type of item/bag, or if the property's value is not the same as the item's/bag's default value for that property. Basically, properties only exist in {{{$UInvBags}}} when they are needed and not the default value. This should reduce the size of your game's history, thus helping reduce the amount of slowdown during passage transitions for games with large and/or complex inventories. ''RestackItems(BagName)'' RestackItems attempts to restack any items in a bag which may be stacked incorrectly. Returns true if any were restacked, false for no changes, and {{{undefined}}} on error. In most cases items should automatically stack properly, so you won't normally need to call this function. However, if you modify one item in a bag so that it becomes identical to another in that same bag, it won't normally automatically restack. This function allows you to force that to happen. ''AddExistingBagAsPocket(BagName, ItemName, PocketName, PocketBagName)'' Adds an existing bag as pocket to an existing item. If the items are stacked, one of the items will get renamed and has a pocket added. Returns the item's name on success (in case it had to be changed when unstacking occurred), or {{{undefined}}} on error. ''AddPocket(BagName, ItemName, PocketName, [DefaultBagType])'' adds a pocket named PocketName of a particular bag type to an item Adds a pocket to an existing item. If the items are stacked, one of the items will get renamed and have a pocket added. Returns the item's name on success, or {{{undefined}}} on error. ''BagHasSpecificItem(MainBagName, ItemBagName, ItemName)'' Returns whether MainBagName contains ItemBagName+ItemName, or {{{undefined}}} on error. (Only needed if you're using pockets.) Returns whether MainBagName (or any pockets on items within MainBagName) contain ItemBagName+ItemName, or {{{undefined}}} on error. This function should ''not'' be used to determine if an item exists, rather, it should be used to determine if an item you know exists can be found anywhere inside the main bag or the pockets of any items within the main bag. This is generally used before moving an item to make sure you don't put an item inside of itself, either directly or indirectly. BagIsPocket(BagName) = number of items it's a pocket for (uses GetPocketContainerArray) Returns how many items the bag is a pocket for, or 0 if none, or {{{undefined}}} on error. ''ContainerHasItem(ContainerBagName, ContainerName, ItemName)'' = number of items named ItemName in all of container's pockets (does not include the container itself in that count) Returns the total number of items named ItemName in all of container's pockets (does not include the container itself in that count), or {{{undefined}}} on error. ''CreatePocket(BagName, ItemName, PocketName)'' creates an empty pocket named PocketName attached to an item Creates a generic pocket on an existing item. If the items are stacked, one of the items will get renamed and have a pocket added. Returns the item's name on success, or {{{undefined}}} on error. ''DeletePocket(BagName, ItemName, PocketName)'' deletes the pocket named PocketName on an item Deletes the bag associated with the item's pocket name. Returns true on success or {{{undefined}}} on error. ''GetAllBagPockets(BagName/Array, [NoSourceBag])'' = array of all pockets' and sub-pockets's BagNames, plus BagName (unless NoSourceBag == true), or {{{undefined}}} on error. (all BagNames returned in the array will be unique within that array) Returns an array of all pockets' and sub-pockets's BagNames, plus BagName (unless NoSourceBag == true), or {{{undefined}}} on error. All BagNames returned in the array will be unique within that array. ''GetAllContainerPockets(ContainerBagName, ContainerName)'' = array of all pockets' and sub-pockets's BagNames, or {{{undefined}}} on error. (all BagNames returned in the array will be unique within that array) Returns an array of all pockets' and sub-pockets's BagNames, or {{{undefined}}} on error. (All BagNames returned in the array will be unique within that array.) ''GetContainerIndex(BagName, PocketName)'' = Index of container in a bag's UInvContainer array, -1 if not found, or {{{undefined}}} on error. Returns index of container in a bag's UInvContainer array which has the pocket name of PocketName, -1 if not found, or {{{undefined}}} on error. ''GetItemPocketBagName(BagName, ItemName, [PocketName])'' = bag name of PocketName in an item, or a random pocket bag name if PocketName isn't specified Returns the bag name which matches the item's pocket name, or a random pocket bag name if PocketName isn't passed. Returns false if pocket not found or {{{undefined}}} on error. ''GetItemPocketBagArray(BagName, ItemName)'' = an array of bag names which the item has as pockets, returns [] if it has none, or {{{undefined}}} on error. Gets an array of bag names which the item has as pockets, returns [] if it has none, or {{{undefined}}} on error. ''GetItemPocketNameArray(BagName, ItemName)'' = an array of pocket names which the item has as pockets, returns [] if it has none, or {{{undefined}}} on error. Gets an array of pocket names which the item has as pockets, returns [] if it has none, or {{{undefined}}} on error. ''GetPocketBagContainerArray(PocketBagName)'' = array of { BagName : "name", ItemName : "name", PocketName : "name" } -or- [] if it's not a pocket Returns the array of all items that directly contain this pocket, or [] if none do, or {{{undefined}}} on error. The array will be in the format of: [ { ContainerBagName : "name", ContainerName : "name", PocketName : "name" }, ... ] ''GetPocketBagsPocketName(BagName, ItemName, PocketBagName)'' = PocketName Returns the first PocketName which matches a pocket/bag (PocketBagName) on a particular item, or false if no match is found, or {{{undefined}}} on error. GetPocketDepth(BagName) = 0 if it's a bag, 1 if it's a pocket, 2 if it's a pocket within a pocket, etc... or {{{undefined}}} on error. Returns 0 if it's a bag, 1 if it's a pocket, 2 if it's a pocket within a pocket, etc... or {{{undefined}}} on error. ''ItemHasPocket(BagName, ItemName, [PocketName])'' = number of pockets (uses GetItemPocketBagArray) -or- if item has a pocket named PocketName (if the PocketName parameter is set) Returns how many pockets the item has, or 0 if none, or {{{undefined}}} on error. If PocketName is passed, returns whether the item has a pocket with that name or not. ''MovePocket(SourceBagName, SourceItemName, SourcePocketName, DestinationBagName, DestinationItemName, [DestinationPocketName])'' Move a pocket from one container to another. If the destination item was stacked, one of the items will get renamed and have a pocket added. Returns the item's name on success (in case it had to be changed when unstacking occurred), or {{{undefined}}} on error. ''UnlinkPocketBagFromContainer(ContainerBagName, ContainerName, PocketBagName)'' Unlinks a bag from the given container item. Unlinks a pocket from its container item (and vice versa). Returns true on success or {{{undefined}}} on error. ''UnlinkPocketFromContainer(ContainerBagName, ContainerName, [PocketName])'' Unlinks a pocket from its container item, or all pockets if PocketName isn't set. Unlinks a pocket from its container item (and vice versa). Returns true on success or {{{undefined}}} on error. ''integerToOrdinal(Value, [Options])'' = an ordinal string (e.g. "first", "11th", "1,000th", etc...), or same value if Value isn't an integer. Options = "NoOrdinalText", "UseSuperscript", "Capitalize" Converts an integer to an ordinal string (e.g. "first", "20th", "1,001st" etc...). The number portion of the string (if there is one) will be processed using the JavaScript <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString">Number.toLocaleString()</a> method, which will add commas or whatever else is needed based on the browser's locale setting. If the ''Value'' parameter isn't an integer, then the function will return ''Value'' unchanged instead. The ''Options'' parameter is optional. If used it changes the default behavior of the function (see below). A single option may be passed as a string, multiple options may be passed as an array of strings. The option names are ''not'' case sensitive. ''Options:'' * "''NoOrdinalText''" = If ''Value'' is from ''1'' to ''9'', then it will normally get converted to text (e.g. a value of ''1'' becomes "''first''"), per the AP style guide. Instead, if the "''NoOrdinalText''" option is used, the result will be returned as a number followed by the ordinal suffix (e.g. instead of the value of ''1'' returning "''first''", it will return "''1st''"). This option effectively overrides the "''Capitalize''" option. * "''Capitalize''" = If ''Value'' is from ''1'' to ''9'', and the "''NoOrdinalText''" option is ''not'' used, then this option will capitalize the first letter of the result (e.g. instead of ''1'' returning "''first''", it will return "''First''"). * "''UseSuperscript''" = This displays the suffix as a superscript, instead of as normal text (e.g. instead of returning a value of ''11'' as "''11th''", it will return it as "''11<sup>th</sup>''" {{{11<sup>th</sup>}}}). This option will not affect ordinal text (i.e. "first" will remain "first", etc...). <center><h2>Universal Inventory System Changelog</h2>for <<=UInv.Version()>></center> ''v0.9.7.2'' - September 9, 2019 - (preview release 12) * 4 new functions written * added some missing date, map, and set support * added missing documentation for new utility functions to help file ''v0.9.7.1'' (bugfix) - September 7, 2019 - (preview release 11) * 7 new functions written + 5 new functions planned * added support for Set and Map objects; UInv now supports all of SugarCube's supported types * added an "Idle" event to the "cacheImages" events. * fixed a problem the image cache had with some browsers * fixed a couple of bugs in the event handler code ** note: this required some minor changes to the CSS generated for tables ** Table Builder updated to accomodate CSS changes * added another bit of sample code to the UInv_Sample_Code.html file * another update to the "UInv Safe Save Code" in the UInv help file * numerous help file updates and fixes ''v0.9.7'' - December 29, 2018 - (preview release 10) * 40 new functions written (including 2 macros) + 38 new functions planned * added Pocket/Container functions; items can now contain other items * updated existing functions to work with pockets properly * updated more functions to support bag name arrays * added a {{{<<UInvSet>>}}} macro to shorten calls to multiple UInv functions * added a {{{<<UInvTry>>}}} macro to simplify error handling in TwineScript * added more ways to add default items to default bags * default return value on error was standardized to "undefined" * enforced stricter verification of values for item names (must be lowercase, etc...) * removed LockUpdates function; use IncrementUpdateLock and DecrementUpdateLock instead * removed capitalizeFirstLetter function; use SugarCube's .toUpperFirst() instead * discovered a function I wrote and apparently forgot to document anywhere (LOL) * renamed the following functions to conform to consistent naming style (aliases added): ** ArrayHasAllBagProperties to BagHasAllProperties ** ArrayHasAllItemProperties to ItemHasAllProperties ** GetBagArrayWithAllProperties to GetBagsArrayWithAllProperties (added an "s") ** GetHighestBagPropertyValue to GetBagWithHighestPropertyValue ** GetHighestItemPropertyValue to GetItemWithHighestPropertyValue ** GetLowestBagPropertyValue to GetBagWithLowestPropertyValue ** GetLowestItemPropertyValue to GetItemWithLowestPropertyValue ** SetItemsPropertyValues to SetItemsPropertyValue (removed an "s") ** UpdateItemProperties to SetItemPropertyValues * fixes/improvements to valuesAreEqual, arraysAreEqual, and objectsAreEqual * corrected two minor inefficiencies in memory/history usage * fixed a few incorrect function names in error messages * fixed a problem with items changed to variable type still using default properties * fixed a problem where variable type items might not merge when they should * fixed GetBagWithHighestPropertyValue and GetBagWithLowestPropertyValue functions * fixed a bug in BagHasAllProperties * preliminary work on unit/regression testing tool (37 functions fully tested) * property values may now be set to "undefined" * new/updated general help file sections: ** [[Changelog]] ** [[Function Cheat Sheet]] ** [[Basic UInv Functions]] (incomplete) ** [[Error Handling]] (incomplete) ** [[Efficient UInv Coding]] ** [[Arrays vs Generic Objects]] (major improvements; incomplete) ** [[The UInv Data Structure]] * worked on how help file entries should look for UInv functions (see "AddBag") * modified UInv structure to support internal-use-only functions and variables ** this means you'll need to insert your bag, item, and alias definitions this update * Over 10,000 non-blank lines of code and comments! Yay for arbitrary milestones! ''v0.9.6'' - September 25, 2018 - (preview release 9) * 31 new functions written + 27 new functions planned * major bugfix in SwapItems and many "Tag" functions * all utility function names now start lowercase * added the ability to cache images for online usage * the [[UInv Safe Save Code]] has been updated * added option for sending UInv errors to console * typing "xyzzy" now toggles console (F12) error log * began implementation of display elements ** table ** radialMenu * began implementation of event handlers ** "general" events: *** MouseDown *** MouseUp ** "bag" events: *** Touched ** "table" events: *** Accept *** DragStart *** Drop *** DragStop ** "radialMenu" events: *** Open *** WedgeClick *** DisabledWedgeClick *** Cancel ** "cacheImages" events: *** Loaded *** Error * added Font Awesome support: https://fontawesome.com/free Just add the following line to the top of your Stylesheet/CSS section: {{{@import url('https://use.fontawesome.com/releases/v5.3.1/css/all.css');}}} See the "FA_Icons.html" file for the list of icons * jQuery UI is now required to support display elements: https://api.jqueryui.com/category/all/ Just include and load the jquery-ui.css and jquery-ui.js files, along with the "images/ui-*.png" images from the "images" folder ''v0.9.5'' - July 23, 2018 - (preview release 8) * 12 new functions written + 12 new functions planned * revamped error handling to add thrown errors * added utility functions for engine detection * saved a bit more memory/history size * major restructuring of item data * added handling of variable items and variable bags ''v0.9.4'' - July 8, 2018 - (preview release 7) * 22 new functions written + 19 new functions planned * some functions renamed to conform to consistent naming style * centralized more functions for display utilities * saved a bit more memory/history size * handled a potential problem with non-static default properties * improved compatibility with other browsers * moved utility functions inside UInv namespace ''v0.9.2'' - May 23, 2018 - (preview release 6) * 10 new functions written + 8 new functions planned * renamed BagCount to GetBagCount for more consistent naming style * moved data sections to bottom to make updating UInv easier * some bugs fixed * Item Builder added to UInv help file ''v0.9.1'' - May 10, 2018 - (preview release 5) * 18 new functions written + 11 new functions planned * added default bags * major rework of engine to allow deletion of default properties * some bugs fixed ''v0.8.6'' - April 24, 2018 - (preview release 4) * 25 new functions written + 13 new functions planned * some functions renamed to conform to consistent naming style * work on help file started (very preliminary) ''v0.7.7'' - April 18, 2018 - (preview release 3) * 32 new functions written + 27 new functions planned * some functions renamed to conform to consistent naming style * most previously incomplete functions are now complete * lots of debugging and additional error checking done ''v0.6.9'' - April 6, 2018 - (preview release 2) * 28 new functions written + 23 new functions planned * some functions renamed to conform to consistent naming style ''v0.5.7'' - March 29, 2018 - (preview release 1) * 62 functions written out of 108 planned functions ''GetBagItemArrayWhereItemPropertyEquals(BagNameArray, ItemPropertyName, Value)'' = array of [[BagName, ItemName], ...] where the item's ItemPropertyName property == Value Returns an array of [[BagName, ItemName], ...] where the item's ItemPropertyName property == Value (all entries are unique), or {{{undefined}}} on error. ''getUniqueArray(Array)'' = an array so that all elements of the original array are now unique, or {{{undefined}}} on error. Returns an array so that all elements of the original array are now unique, or {{{undefined}}} on error. <center><h2>Basic UInv Functions</h2></center>If you're new to UInv, you're probably looking at all of the UInv functions and feeling a bit overwhelmed. Well, don't panic. Here are the few functions you'll need for most operations. <<Title Basic Bag Functions>> Here are the UInv bag functions you're most likely to need: * [[CreateBag]](BagName) - Use this to create a bag from scratch. * [[AddBag]](BagName, [DefaultBagType]) - Use this to create a pre-defined ("default") type of bag. ("DefaultBagType" is in brackets because it's an optional parameter.) * [[GetBagsArray]]() - This will get you an array of all existing bags. * [[BagExists]](BagName/Array) - Use this to determine if a bag or bags with certain names exist. * [[DeleteBag]](BagName/Array) - Use this to delete a particular bag or bags and all items in those bags. For the {{{AddBag}}} function, you'll need to edit those default bag types into the [[BagData]] part of the UInv JavaScript code. You can generate the code for the bag types using the [[Bag Builder]]. See [[GetDefaultBagObject]] for details. Here's some simple sample code using those basic bag functions: {{{ <<set UInv.CreateBag("inventory")>> <<if UInv.BagExists("inventory")>> It worked! Inventory exists! <<else>> Something went wrong... <<print UInv.GetLastError(true)>> <</if>> Existing bags: <<print UInv.GetBagsArray()>> <<set UInv.DeleteBag("inventory")>> <<if UInv.BagExists("inventory")>> Something went wrong... <<print UInv.GetLastError(true)>> <<else>> It worked! Inventory was deleted. <</if>> }}} If that's the only UInv code in your project then that code should work fine. However, if you have a lot of code, here are reasons why those functions could fail: * {{{CreateBag}}} will fail if a bag of that name already exists, or if the name passed to it is "" (an empty string), "-" (a dash), or is not a string. * {{{AddBag}}} will fail for the same reasons as {{{CreateBag}}}, plus it will also fail if neither the BagName parameter nor the (optional) DefaultBagType parameter are default bag types you've defined. * {{{GetBagsArray}}} should always work. * {{{BagExists}}} will fail if it's not handed a string or an array of strings. * {{{DeleteBag}}} will fail for the same reasons as {{{BagExists}}} or if the bag name or any name in the bag name array doesn't exist. In short, the most common cause of failure would be not handing a function a valid string or that string not being a valid bag name. <<Title Basic Item Functions>> Here are the UInv item functions you're most likely to need: (not written yet) ''MoveItemToPocket(SourceBagName, SourceItemName, DestinationBagName, DestinationItemName, DestinationPocketName, [Quantity])'' Works the same as [[MoveItem]]. Moves {{{Quantity}}} items from source bag to destination pocket (moves all items if {{{Quantity}}} is undefined, equal to, or larger than the number of source items), changing the source item's UInvQuantity if any remain. Returns the destination item's name on success, or {{{undefined}}} on error. Returns {{{undefined}}} if illegal property values were passed to ''MoveItem'', returns {{{false}}} if any items failed to move, otherwise it returns the moved item's name. The UInvMergeItemMethod setting determines what happens on item collision. See [[SetMergeItemMethod]] for details. If you want to access a pocket directly, instead of using this function, just use the [[GetItemPocketBagName]] function to translate the pocket name into a bag name. ''MoveItemFromPocket(ContainerBagName, ContainerItemName, PocketName, ItemName, DestinationBagName, [Quantity])'' Works the same as [[MoveItem]]. Moves {{{Quantity}}} items from source pocket to destination bag (moves all items if {{{Quantity}}} is undefined, equal to, or larger than the number of source items), changing the source item's UInvQuantity if any remain. Returns the destination item's name on success, or {{{undefined}}} on error. Returns {{{undefined}}} if illegal property values were passed to ''MoveItem'', returns {{{false}}} if any items failed to move, otherwise it returns the moved item's name. The UInvMergeItemMethod setting determines what happens on item collision. See [[SetMergeItemMethod]] for details. If you want to access a pocket directly, instead of using this function, just use the [[GetItemPocketBagName]] function to translate the pocket name into a bag name. <center><h2>UInv Function Cheat Sheet</h2></center><<nobr>> <div class="accordion"> <h3>Bag Functions:</h3> <div><ul> <li>[[AddBag]](BagName, [DefaultBagType])</li> <li>[[AddToBagPropertyValue]](BagName, BagPropertyName, Amount)</li> <li>[[BagExists]](BagName/Array)</li> <li>[[BagHasAllProperties]](BagName, BagPropertyNameArray)</li> <li>[[BagHasProperty]](BagName, BagPropertyName/Array)</li> <li>[[BagMatchesDefault]](BagName)</li> <li>[[BagPropertyCount]](BagName)</li> <li>[[CopyAllItemsToBag]](SourceBagName, DestinationBagName)</li> <li>[[CopyBag]](ExistingBagName, NewBagName)</li> <li>[[CopyBagProperty]](SourceBagName, DestinationBagName, BagPropertyName/Array)</li> <li>[[CreateBag]](BagName)</li> <li>[[DeleteBag]](BagName)</li> <li>[[DeleteBagProperty]](BagName, BagPropertyName)</li> <li>[[EmptyBag]](BagName)</li> <li>[[GetBagByProperty]](BagPropertyName)</li> <li>[[GetBagCount]]()</li> <li>[[GetBagCountByDefaultType]]()</li> <li>[[GetBagObject]](BagName)</li> <li>[[GetBagPropertyArray]](BagName)</li> <li>[[GetBagPropertyObject]](BagName)</li> <li>[[GetBagPropertyValue]](BagName, BagPropertyName)</li> <li>[[GetBagsArray]]()</li> <li>[[GetBagsArrayByProperty]](BagPropertyName, [BagNameArray])</li> <li>[[GetBagsArrayWherePropertyEquals]](BagPropertyName, Value)</li> <li>[[GetBagsArrayWherePropertyGreaterThan]](BagPropertyName, Value)</li> <li>[[GetBagsArrayWherePropertyLessThan]](BagPropertyName, Value)</li> <li>[[GetBagsArrayWithAllProperties]](BagPropertyNameArray)</li> <li>[[GetBagsArrayWithItem]](ItemName, [BagArray])</li> <li>[[GetBagsDefaultType]](BagName)</li> <li>[[GetBagWherePropertyEquals]](BagPropertyName, Value)</li> <li>[[GetBagWherePropertyGreaterThan]](BagPropertyName, Value)</li> <li>[[GetBagWherePropertyLessThan]](BagPropertyName, Value)</li> <li>[[GetBagWithHighestPropertyValue]](BagPropertyName, [BagNameArray])</li> <li>[[GetBagWithLowestPropertyValue]](BagPropertyName, [BagNameArray])</li> <li>[[GetCurrentBagName]]()</li> <li>[[GetDefaultBagObject]](DefaultBagType)</li> <li>[[GetTotalBagPropertyValue]](BagPropertyName, [BagNameArray])</li> <li>[[GetUniqueBagName]]()</li> <li>[[MergeBags]](SourceBagName, DestinationBagName)</li> <li>[[MoveAllItemsToBag]](SourceBagName, DestinationBagName)</li> <li>[[MoveBagPropertyValueToBag]](SourceBagName, SourceBagPropertyName, DestinationBagName, [DestinationBagPropertyName], [Amount], [MinimumValue], [MaximumValue], [DeletionValue], [DeletionType])</li> <li>[[MoveItemPropertyValueToBag]](SourceBagName, SourceItemName, SourceItemPropertyName, DestinationBagName, [DestinationBagPropertyName], [Amount], [MinimumValue], [MaximumValue], [DeletionValue], [DeletionType])</li> <li>[[RenameBag]](CurrentBagName, NewBagName)</li> <li>[[SetCurrentBagName]](BagName)</li> <li>[[SetBagPropertyValue]](BagName/Array, BagPropertyName, Value)</li> <li>[[SetBagsDefaultType]](BagName, DefaultBagType)</li> <li>[[SetBagTouched]](BagName/Array)</li> <li>[[SetBagUntouched]](BagName/Array)</li> <li>[[WasTouched]](BagName)</li> </ul></div> <h3>Pocket/Container Functions:</h3> <div><ul> <li>[[AddExistingBagAsPocket]](BagName, ItemName, PocketName, PocketBagName)</li> <li>[[AddPocket]](BagName, ItemName, PocketName, [DefaultBagType])</li> <li>[[BagHasSpecificItem]](MainBagName, ItemBagName, ItemName)</li> <li>[[BagIsPocket]](BagName)</li> <li>[[ContainerHasItem]](ContainerBagName, ContainerName, ItemName)</li> <li>[[ContainerHasPocketBag]](ContainerBagName, ContainerName, BagName)</li> <li>[[CreatePocket]](BagName, ItemName, PocketName)</li> <li>[[DeletePocket]](BagName, ItemName, PocketName)</li> <li>[[GetAllBagPockets]](BagName/Array, [NoSourceBag])</li> <li>[[GetAllContainerPockets]](ContainerBagName, ContainerName)</li> <li>[[GetContainerIndex]](BagName, PocketName)</li> <li>[[GetItemPocketBagArray]](BagName, ItemName)</li> <li>[[GetItemPocketBagName]](BagName, ItemName, [PocketName])</li> <li>[[GetItemPocketNameArray]](BagName, ItemName)</li> <li>[[GetItemPocketObject]](BagName, ItemName)</li> <li>[[GetPocketBagContainerArray]](PocketBagName)</li> <li>[[GetPocketBagsPocketName]](BagName, ItemName, PocketBagName)</li> <li>[[GetPocketDepth]](BagName)</li> <li>[[ItemHasPocket]](BagName, ItemName, [PocketName])</li> <li>[[MoveItemFromPocket]](ContainerBagName, ContainerItemName, PocketName, ItemName, DestinationBagName, [Quantity])</li> <li>[[MoveItemToPocket]](SourceBagName, SourceItemName, DestinationBagName, DestinationItemName, DestinationPocketName, [Quantity])</li> <li>[[MovePocket]](SourceBagName, SourceItemName, SourcePocketName, DestinationBagName, DestinationItemName, [DestinationPocketName])</li> <li>[[UnlinkPocketBagFromContainer]](ContainerBagName, ContainerName, PocketBagName)</li> <li>[[UnlinkPocketFromContainer]](ContainerBagName, ContainerName, [PocketName])</li> </ul></div> <h3>Item Functions:</h3> <div><ul> <li>[[AddItem]](BagName, ItemType, [Quantity], [NewItemName])</li> <li>[[AddItems]](BagName, ItemArray)</li> <li>[[AddToAllItemsPropertyValue]](BagName, ItemPropertyName, Amount)</li> <li>[[AddToItemPropertyValue]](BagName, ItemName, ItemPropertyName, Amount)</li> <li>[[BagHasAllItems]](BagName/Array, ItemNameArray)</li> <li>[[BagHasAnyItem]](BagName/Array, ItemNameArray)</li> <li>[[BagHasItem]](BagName/Array, ItemName)</li> <li>[[CopyItem]](SourceBagName, DestinationBagName, ItemName, [Quantity], [NewItemName])</li> <li>[[CopyItemsByProperty]](SourceBagName, DestinationBagName, ItemProperty, [Value])</li> <li>[[CreateItem]](BagName, ItemName, [Quantity])</li> <li>[[DeleteItem]](BagName, ItemName/Array, [Quantity])</li> <li>[[DeleteItemProperty]](BagName/Array, ItemName, [ItemPropertyName])</li> <li>[[DeleteItemsByProperty]](BagName, ItemProperty, [Value])</li> <li>[[GetAllPropertyValues]](BagName, ItemPropertyName)</li> <li>[[GetBagItemArrayWhereItemPropertyEquals]](BagNameArray, ItemPropertyName, Value)</li> <li>[[GetCurrentItemName]]()</li> <li>[[GetDefaultItemObject]](ItemName)</li> <li>[[GetDefaultItemPropertyValue]](ItemName, ItemPropertyName)</li> <li>[[GetItemByProperty]](BagName, ItemPropertyName)</li> <li>[[GetItemByType]](BagName, ItemType)</li> <li>[[GetItemCount]](BagName/Array)</li> <li>[[GetItemCountByDefaultType]](BagName/Array)</li> <li>[[GetItemCountByFunction]](BagName/Array, CountFunction)</li> <li>[[GetItemCountFull]](BagName/Array)</li> <li>[[GetItemCountFullByDefaultType]](BagName/Array, DefaultItemType)</li> <li>[[GetItemCountWherePropertyEquals]](BagName, ItemPropertyName, Value)</li> <li>[[GetItemCountWherePropertyGreaterThan]](BagName, ItemPropertyName, Value)</li> <li>[[GetItemCountWherePropertyLessThan]](BagName, ItemPropertyName, Value)</li> <li>[[GetItemObject]](BagName, ItemName)</li> <li>[[GetItemPropertiesArray]](BagName, ItemName)</li> <li>[[GetItemPropertyCount]](BagName, ItemName)</li> <li>[[GetItemPropertyValue]](BagName, ItemName, ItemPropertyName)</li> <li>[[GetItemPropertyValueObject]](BagName, ItemPropertyName)</li> <li>[[GetItemsAndQuantitiesObject]](BagName)</li> <li>[[GetItemsArray]](BagName)</li> <li>[[GetItemsArrayByFunction]](BagName, SelectionFunction)</li> <li>[[GetItemsArrayByProperty]](BagName, ItemPropertyName)</li> <li>[[GetItemsArrayByType]](BagName, ItemType)</li> <li>[[GetItemsArraySortedByFunction]](BagName, SortFunction)</li> <li>[[GetItemsArraySortedByProperty]](BagName, [ItemPropertyName])</li> <li>[[GetItemsArrayWhereItemNameContains]](BagName, SubString)</li> <li>[[GetItemsArrayWherePropertyEquals]](BagName, ItemPropertyName, Value)</li> <li>[[GetItemsArrayWherePropertyGreaterThan]](BagName, ItemPropertyName, Amount)</li> <li>[[GetItemsArrayWherePropertyLessThan]](BagName, ItemPropertyName, Amount)</li> <li>[[GetItemsArrayWherePropertyValueContains]](BagName, ItemPropertyName, SubString, [CaseSensitive])</li> <li>[[GetItemsArrayWithAllProperties]](BagName, ItemPropertyNameArray)</li> <li>[[GetItemsArrayWithoutProperties]](BagName, ItemPropertyName/Array)</li> <li>[[GetItemsDefaultType]](BagName, ItemName)</li> <li>[[GetItemWherePropertyEquals]](BagName/Array, ItemPropertyName, Value)</li> <li>[[GetItemWherePropertyGreaterThan]](BagName/Array, ItemPropertyName, Amount)</li> <li>[[GetItemWherePropertyLessThan]](BagName/Array, ItemPropertyName, Amount)</li> <li>[[GetItemWithHighestPropertyValue]](BagName, ItemPropertyName)</li> <li>[[GetItemWithLowestPropertyValue]](BagName, ItemPropertyName)</li> <li>[[GetMatchingItemsArray]](BagName, ItemName, SearchBag, [PropertyExceptionArray])</li> <li>[[GetObjectOfItemPropertyValues]](BagName, ItemPropertyName)</li> <li>[[GetRandomItem]](BagName)</li> <li>[[GetRandomItemPropertyValue]](BagName, ItemPropertyName)</li> <li>[[GetRandomItemValue]](BagName, ItemPropertyName)</li> <li>[[GetTotalItemPropertyValue]](BagName, ItemPropertyName)</li> <li>[[GetUniqueItemName]]()</li> <li>[[GetUniqueItemPropertyValuesArray]](BagName/Array, ItemPropertyName)</li> <li>[[ItemExists]](ItemName)</li> <li>[[ItemHasAllProperties]](BagName, ItemName, ItemPropertyNameArray)</li> <li>[[ItemHasAnyProperties]](BagName, ItemName, ItemPropertyNameArray)</li> <li>[[ItemHasProperty]](BagName, ItemName, ItemPropertyName)</li> <li>[[ItemPropertyHasValue]](BagName, ItemName, ItemPropertyName, Value)</li> <li>[[ItemsMatch]](BagName1, ItemName1, BagName2, ItemName2, [PropertyExceptionArray])</li> <li>[[MoveItem]](SourceBagName, DestinationBagName, ItemName, [Quantity], [NewItemName])</li> <li>[[MoveBagPropertyValueToItem]](SourceBagName, SourceBagPropertyName, DestinationBagName, DestinationItemName, [DestinationItemPropertyName], [Amount], [MinimumValue], [MaximumValue], [DeletionValue], [DeletionType])</li> <li>[[MoveItemPropertyValueToItem]](SourceBagName, SourceItemName, SourceItemPropertyName, DestinationBagName, DestinationItemName, [DestinationItemPropertyName], [Amount], [MinimumValue], [MaximumValue], [DeletionValue], [DeletionType])</li> <li>[[MoveItemsByProperty]](SourceBagName, DestinationBagName, ItemProperty, [Value])</li> <li>[[RenameItem]](BagName, CurrentItemName, NewItemName, [Quantity])</li> <li>[[RenameItemProperty]](BagName, ItemName, CurrentItemPropertyName, NewItemPropertyName)</li> <li>[[ResetItemProperties]](BagName/Array, ItemName, [DefaultItemName])</li> <li>[[RestackItems]](BagName)</li> <li>[[SetCurrentItemName]](ItemName)</li> <li>[[SetItemPropertyValue]](BagName, ItemName, ItemPropertyName, Value)</li> <li>[[SetItemPropertyValues]](BagName, ItemName, GenericObject)</li> <li>[[SetItemQuantity]](BagName, ItemName, Quantity)</li> <li>[[SetItemsDefaultType]](BagName, ItemName, DefaultItemType)</li> <li>[[SetItemsPropertyValue]](BagName, ItemPropertyName, Value)</li> <li>[[SwapItems]](BagName1, ItemName1, BagName2, ItemName2, [ExceptItemPropertyName/array])</li> <li>[[SwapItemsProperties]](BagName1, ItemName1, BagName2, ItemName2, ItemPropertyName/array)</li> </ul></div> <h3>Tag Functions:</h3> <div><ul> <li>[[AddBagTag]](BagName/Array, BagPropertyName, BagTag/Array)</li> <li>[[AddItemTag]](BagName/Array, ItemName, ItemPropertyName, ItemTag/Array)</li> <li>[[ArrayHasAllItemTags]](BagName, ItemName, ItemPropertyName, ItemTagArray)</li> <li>[[BagHasAllBagTags]](BagName, BagPropertyName, BagTagArray)</li> <li>[[BagHasAllItemTags]](BagName, ItemPropertyName, ItemTagArray)</li> <li>[[BagHasAnyBagTag]](BagName, BagPropertyName, BagTagArray)</li> <li>[[BagHasAnyItemTag]](BagName, ItemPropertyName, ItemTagArray)</li> <li>[[BagHasItemByBagTag]](BagPropertyName, BagTag, ItemName)</li> <li>[[BagHasAllItemsByBagTag]](BagPropertyName, BagTag, ItemNameArray)</li> <li>[[BagHasAnyItemByBagTag]](BagPropertyName, BagTag, ItemNameArray)</li> <li>[[BagHasItemByItemTag]](BagName, ItemPropertyName, ItemTag)</li> <li>[[BagHasItemWithAllItemTags]](BagName, ItemPropertyName, ItemTag/Array)</li> <li>[[BagHasItemWithAnyItemTag]](BagName, ItemPropertyName, ItemTag/Array)</li> <li>[[BagHasItemWithoutAllItemTags]](BagName, ItemPropertyName, ItemTag/Array)</li> <li>[[BagHasItemWithoutAnyItemTags]](BagName, ItemPropertyName, ItemTag/Array)</li> <li>[[BagHasTag]](BagName, BagPropertyName, BagTag)</li> <li>[[CopyItemsByItemTag]](SourceBagName, DestinationBagName, ItemPropertyName, ItemTag)</li> <li>[[DeleteBagTag]](BagName/Array, BagPropertyName, BagTag/Array)</li> <li>[[DeleteItemsByItemTag]](BagName, ItemPropertyName, ItemTag)</li> <li>[[DeleteItemTag]](BagName/Array, ItemName, ItemPropertyName, ItemTag/Array)</li> <li>[[GetAllUniqueItemTagsArray]](BagName, ItemPropertyName)</li> <li>[[GetBagsArrayByBagTag]](BagPropertyName, BagTag)</li> <li>[[GetBagsArrayWithBothBagTags]](BagPropertyName1, BagTag1, BagPropertyName2, BagTag2)</li> <li>[[GetBagsArrayWithItemByBagTag]](BagPropertyName, BagTag, ItemName)</li> <li>[[GetBagTagQuantityObject]](BagName, BagPropertyName)</li> <li>[[GetFullItemCountByAllItemTags]](BagName, ItemPropertyName, TagArray)</li> <li>[[GetFullItemCountByAnyItemTag]](BagName, ItemPropertyName, TagArray)</li> <li>[[GetItemsArrayByAllItemTags]](BagName, ItemPropertyName, ItemTagArray)</li> <li>[[GetItemsArrayByAnyItemTag]](BagName, ItemPropertyName, ItemTagArray)</li> <li>[[GetItemsArrayByItemTag]](BagName, ItemPropertyName, ItemTag)</li> <li>[[GetItemsArrayWithAllItemTags]](BagName, ItemPropertyName, ItemTagArray)</li> <li>[[GetItemsArrayWithBothItemTags]](BagName, ItemPropertyName1, ItemTag1, ItemPropertyName2, ItemTag2)</li> <li>[[GetItemsArrayWithMostItemTags]](BagName, ItemPropertyName, ItemTagArray)</li> <li>[[GetItemsArrayWithoutAllItemTags]](BagName, ItemPropertyName, ItemTagArray)</li> <li>[[GetItemsArrayWithoutAnyItemTags]](BagName, ItemPropertyName, ItemTagArray)</li> <li>[[GetItemTagCount]](BagName, ItemName, ItemPropertyName, Tag)</li> <li>[[GetItemTagQuantityObject]](BagName, ItemName, ItemPropertyName)</li> <li>[[GetMissingBagTagsArray]](BagName, BagPropertyName, BagTagArray)</li> <li>[[GetMissingItemTagsArray]](BagName, ItemName, ItemPropertyName, ItemTagArray)</li> <li>[[GetRandomBagTagFromRange]](BagName, BagPropertyName, HighIndex, [LowIndex])</li> <li>[[GetRandomItemTagFromRange]](BagName, ItemName, ItemPropertyName, HighIndex, [LowIndex])</li> <li>[[GetUniqueBagTagsArray]](BagPropertyName, [BagName/Array])</li> <li>[[GetUniqueItemTagsArray]](ItemPropertyName, [BagName/Array])</li> <li>[[ItemHasAllTags]](BagName, ItemName, ItemPropertyName, ItemTagArray)</li> <li>[[ItemHasAnyTag]](BagName, ItemName, ItemPropertyName, ItemTagArray)</li> <li>[[ItemHasTag]](BagName, ItemName, ItemPropertyName, ItemTag)</li> <li>[[MoveItemsByItemTag]](SourceBagName, DestinationBagName, ItemPropertyName, ItemTag)</li> <li>[[SetBagTag]](BagName/Array, BagPropertyName, BagTag/Array, Enabled)</li> <li>[[SetItemTag]](BagName/Array, ItemName, ItemPropertyName, ItemTag/Array, Enabled)</li> </ul></div> <h3>Display Functions:</h3> <div><ul> <li>[[AddEventHandler]](Group, Event, Handler, [Options])</li> <li>[[CallEventHandler]](Group, Event, Values)</li> <li>[[CallEventHandlerEx]](Group, Event, Values)</li> <li>[[DecrementUpdateLock]]()</li> <li>[[DeleteEventHandler]](Group, Event, Handler/HandlerID, [Options])</li> <li>[[DisplayArray]](YourArray, [EmptyString], [SeparatorString], [ConjunctionString], [UseAPNumbers])</li> <li>[[DisplayItemList]](BagName, [PluralItemPropertyName], [EmptyString], [SeparatorString], [ConjunctionString], [SingleItemPropertyName]) </li> <li>[[DisplayRadialMenu]](WedgeItems, Position, [Handler], [Options])</li> <li>[[FixTableCells]](BagName)</li> <li>[[GetEventHandlerByID]](Group, Event, HandlerID)</li> <li>[[GetMatchingEventHandlersArray]](Group, Event, [Options], [Handler])</li> <li>[[GetUpdateLocks]]()</li> <li>[[IncrementUpdateLock]]()</li> <li>[[UpdateDisplay]]([Container])</li> <li>[[UpdatesAreLocked]]()</li> <li>(more to be added...)</li> </ul></div> <h3>Other UInv Functions and Macros:</h3> <div><ul> <li>[[ClearErrors]]()</li> <li>[[GetLastError]]([Clear])</li> <li>[[GetUserAlerts]]()</li> <li>[[Initialize]]([DisplayErrors])</li> <li>[[SetUserAlerts]](ErrorSetting, [ErrorStringAddendum])</li> <li>[[SetMergeItemMethod]](MergeMethod)</li> <li>[[Version]]()</li> <li>[[UInvSet Macro]]</li> {{{<<UInvSet>><</UInvSet>>}}} <li>[[UInvTry Macro]]</li> {{{<<UInvTry CodeString>><<Fail>><</UInvTry>>}}} </ul></div> <h3>UInv Utility Functions:</h3> <div><ul> <li>[[addArticle]](WordIn, [Caps], [Acronyms])</li> <li>[[arrayObjectIncludes]](ArrayOfGenericObjects, ObjProperty, Value)</li> <li>[[arraysAreEqual]](Array1, Array2)</li> <li>[[arrayHasAllTags]](Array, TagArray)</li> <li>[[arrayHasAnyTag]](Array, TagArray)</li> <li>[[arrayHasTag]](Array, Tag)</li> <li>[[cacheImages]](Path, ImageName/array, [Handler])</li> <li>[[combineGenericObjects]](Obj1, Obj2)</li> <li>[[docHasCSSElement]](CSSElement)</li> <li>[[flushAllCachedImages]]([MaxCache])</li> <li>[[flushCachedImages]](Path, ImageName/array)</li> <li>[[getArrayReverseSortedByOtherArray]](UnsortedArray, ArrayToSortBy, [RemoveDuplicates])</li> <li>[[getArraySortedByOtherArray]](UnsortedArray, ArrayToSortBy, [RemoveDuplicates])</li> <li>[[getCachedImageObject]](Path, ImageName)</li> <li>[[getObjectProperties]](Object, [Ext])</li> <li>[[getRandomHexString]]()</li> <li>[[getUniqueArray]](Array)</li> <li>[[integerToOrdinal]](Value, [Options])</li> <li>[[isArray]](Value)</li> <li>[[isArrayOfArrays]](Value)</li> <li>[[isArrayOfBooleans]](Value)</li> <li>[[isArrayOfDates]](Value)</li> <li>[[isArrayOfGenericObjects]](Value)</li> <li>[[isArrayOfIntegers]](Value)</li> <li>[[isArrayOfMaps]](Value)</li> <li>[[isArrayOfNumbers]](Value)</li> <li>[[isArrayOfObjects]](Value)</li> <li>[[isArrayOfSets]](Value)</li> <li>[[isArrayOfStrings]](Value)</li> <li>[[isArrayOfType]](Value, Type)</li> <li>[[isBoolean]](Value)</li> <li>[[isDate]](Value)</li> <li>[[isFunction]](Value)</li> <li>[[isGenericObject]](Value)</li> <li>[[isInteger]](Value)</li> <li>[[isMap]](Value)</li> <li>[[isNumber]](Value)</li> <li>[[isObject]](Value)</li> <li>[[isProperty]](Obj, Prop)</li> <li>[[isRegExp]](Value)</li> <li>[[isSet]](Value)</li> <li>[[isString]](Value)</li> <li>[[isUndefined]](Value)</li> <li>[[mapsAreEqual]](Map1, Map2)</li> <li>[[numberToAPString]](Value)</li> <li>[[objectsAreEqual]](Object1, Object2, [ArrayOfObjectsToIgnore])</li> <li>sanitizeString(String)</li> <li>[[setsAreEqual]](Set1, Set2)</li> <li>[[setsMatch]](Set1, Set2)</li> <li>[[spread]](Value, Funct)</li> <li>[[valuesAreEqual]](Var1, Var2)</li> <li>+ [[Engine Detection]] (12 functions)</li> </ul></div> </div> <</nobr>> ''ContainerHasPocketBag(ContainerBagName, ContainerName, BagName)'' = returns whether BagName exists anywhere within the container, or {{{undefined}}} on error. Returns whether BagName exists anywhere within the container, or {{{undefined}}} on error. ''AddToAllItemsPropertyValue(BagName, ItemPropertyName, Amount)'' adds amount to property's value for all items that have ItemPropertyName Adds an amount to a property's value for all of a bag's items which have the property (returns true), or {{{undefined}}} on error. Does not touch bag unless UInvQuantity changed. Deletes item if UInvQuantity would become <= 0. ''ItemHasAnyProperties(BagName, ItemName, ItemPropertyNameArray)'' = t/f if any of the item's properties are listed in ItemPropertyNameArray Returns whether any of the item's properties are listed in ItemPropertyNameArray, false if the item has no properties, or {{{undefined}}} on error. ''GetItemsArrayWithoutProperties(BagName, ItemPropertyName/Array)'' = an array of ItemNames in BagName that do not have any ItemPropertyName/Array as any of their properties Returns an array of ItemNames in BagName that do not have any ItemPropertyName/Array as any of their properties, or {{{undefined}}} on error. <center><h2>Error Handling</h2></center>(Explain error handling.) UInv functions will return {{{undefined}}} if an error occurs, so you can test that using the TwineScript {{{def}}} and {{{ndef}}} operators to detect errors. For example: {{{ <<if def UInv.CreateBag("test")>> Success! <<else>> <<=UInv.GetLastError()>> <</if>> }}} or: {{{ <<if ndef UInv.CreateBag("test")>> <<=UInv.GetLastError()>> <</if>> }}} You can also use UInv's [[isUndefined]] function: {{{ <<if UInv.isUndefined(UInv.CreateBag("test"))>> <<=UInv.GetLastError()>> <</if>> }}} However, as you can see, it's much easier to use {{{def}}} and {{{ndef}}} when working with SugarCube code. JavaScript, however, does not have the {{{def}}} and {{{ndef}}} operators, so you can use these instead: {{{ if (UInv.CreateBag("test") === undefined) { alert(UInv.GetLastError()); } }}} or: {{{ if (typeof UInv.CreateBag("test") === "undefined") { alert(UInv.GetLastError()); } }}} ... If a value is "falsy" that means that an {{{<<if>>}}} macro will treat that value as though it's untrue, though the value may not necessarly be {{{false}}} itself. "Falsy" values include {{{false}}}, {{{undefined}}}, {{{null}}}, {{{NaN}}} (which stands for "Not a Number"), {{{0}}} (the number zero), and {{{""}}} (an empty string). All other values are "truthy" values (meaning that they'll be treated as though they're true instead). <<Title "{{{<<UInvTry>>}}} Macro">> __Format:__ {{{<<UInvTry CodeString>><<Fail>><</UInvTry>>}}} The {{{<<UInvTry>>}}} macro attempts to run the equivalent of the content of a SugarCube {{{<<set>>}}} macro, and then runs one set of code if it succeeds, or another set of code after a {{{<<Fail>>}}} marker if it causes an error. There must be a {{{<</UInvTry>>}}} at the end. The ''CodeString'' should should be a string without the {{{<<set >>}}} part, and any UInv functions inside the string will automatically have "UInv." added to the front if it's not already there. Note that {{{_UInvResult}}} will also receive the return value from ''CodeString''. UInv function names within ''CodeString'' will have {{{UInv.}}} put in front of them only if ''all'' of the following conditions are met: # they're a valid UInv function name (including aliases) # they're preceded by a new line, a space, a tab, {{{,}}}, {{{+}}}, {{{-}}}, {{{/}}}, {{{*}}}, {{{%}}}, {{{=}}}, {{{<}}}, {{{>}}}, {{{!}}}, {{{&}}}, {{{|}}}, {{{?}}}, {{{(}}}, {{{[}}}, {{{{}}}, or {{{:}}} # they're immediately followed by {{{(}}} (the left parenthesis) # they're not within a string (within a pair of single or double-quotes) ''Example Code:'' {{{ <<UInvTry "AddBag('backpack')">>\ Success! <<Fail>>\ Failure: $UInvLastErrorMessage <</UInvTry>>\ }}} That will try to run the UInv [[AddBag]] function. If it succeeds, then it will display the "Success!" message. If it fails, such as would happen if a bag named "backpack" already exists, then it will display a "Failure: " message, followed by the reason for the failure. {{{ <<set _room = "Room">>\ <<set _test = "_items = GetItemsArray(_room)">>\ <<UInvTry _test>>\ Items: _items <<Fail>>\ <<set UInv.CreateBag(_room)>>\ Items: (none) <</UInvTry>>\ }}} That will try to set {{{_items}}} to an array of all of the items in "Room" using [[GetItemsArray]]. If the "Room" bag exists, then it will show a list of items in that bag. If the "Room" bag //doesn't// exist (which is the most likely reason why ''GetItemsArray'' would fail), then it will create that bag using [[CreateBag]] and indicate that there are no items there. This can be quite useful if you want your code to be able to handle error messages which may be expected in certain situations, such as trying to delete an item that may or may not exist. ''NOTE:'' When using the {{{<<UInvTry>>}}} macro you should make sure you aren't using any other functions in the ''CodeString'' parameter which have the same name as UInv functions, or those functions won't work since they will have {{{UInv.}}} stuck in front of them by this macro. You can work around this by putting a space between the function name and the left parenthesis (e.g. {{{someFunction (parameters)}}}). ''GetRandomItemValue(BagName, ItemPropertyName)'' = a random value of an item's ItemPropertyName in a bag if it has that property. Sets that item as the current item Returns a random value of an item's ItemPropertyName in a bag if it has that property. Sets that item as the current item. ''The {{{<<UInvSet>>}}} Macro'' You may have noticed that all UInv functions need to have {{{UInv.}}} in front of them by now. To help cut down on that redundancy, you can skip that part inside of a {{{<<UInvSet>>}}} macro. This macro wraps each line in {{{<<set (line)>>}}}, and adds {{{UInv.}}} in front of any UInv function calls (including custom aliases). So instead of typing this: {{{ <<set UInv.AddBag("backpack")>> <<set UInv.AddItem("", "pants")>> <<set UInv.SetItemQuantity("", "", 5 + UInv.BagHasItem("", ""))>> <<set _Items = UInv.GetType(_itemType)>> }}} you could just type this: {{{ <<UInvSet>> AddBag("backpack") AddItem("", "pants") SetItemQuantity("", "", 5 + BagHasItem("", "")) _Items = GetType(_itemType) <</UInvSet>> }}} and it would act exactly the same. UInv function names within this macro will have {{{UInv.}}} put in front of them only if ''all'' of the following conditions are met: # they're a valid UInv function name (including aliases) # they're preceded by a new line, a space, a tab, {{{,}}}, {{{+}}}, {{{-}}}, {{{/}}}, {{{*}}}, {{{%}}}, {{{=}}}, {{{<}}}, {{{>}}}, {{{!}}}, {{{&}}}, {{{|}}}, {{{?}}}, {{{(}}}, {{{[}}}, {{{{}}}, or {{{:}}} # they're immediately followed by {{{(}}} (the left parenthesis) # they're not within a string (within a pair of single or double-quotes) ''NOTE:'' When using the {{{<<UInvSet>>}}} macro you should make sure you aren't using any other functions which have the same name as UInv functions, or those functions won't work since they will have {{{UInv.}}} stuck in front of them by this macro. You can work around this by putting a space between the function name and the left parenthesis (e.g. {{{someFunction (parameters)}}}). ''{{{<<UInvTry>>}}} Macro:'' {{{<<UInvTry CodeString>><<Fail>><</UInvTry>>}}} The {{{<<UInvTry>>}}} macro attempts to run the equivalent of the content of a SugarCube {{{<<set>>}}} macro, and then runs one set of code if it succeeds, or another set of code after a {{{<<Fail>>}}} marker if it causes an error. There must be a {{{<</UInvTry>>}}} at the end. The ''CodeString'' should should be a string without the {{{<<set >>}}} part, and any UInv functions inside the string will automatically have "UInv." added to the front if it's not already there. Note that {{{_UInvResult}}} will also receive the return value from ''CodeString''. UInv function names within ''CodeString'' will have {{{UInv.}}} put in front of them only if ''all'' of the following conditions are met: # they're a valid UInv function name (including aliases) # they're preceded by a new line, a space, a tab, {{{,}}}, {{{+}}}, {{{-}}}, {{{/}}}, {{{*}}}, {{{%}}}, {{{=}}}, {{{<}}}, {{{>}}}, {{{!}}}, {{{&}}}, {{{|}}}, {{{?}}}, {{{(}}}, {{{[}}}, {{{{}}}, or {{{:}}} # they're immediately followed by {{{(}}} (the left parenthesis) # they're not within a string (within a pair of single or double-quotes) ''Example Code:'' {{{ <<UInvTry "AddBag('backpack')">>\ Success! <<Fail>>\ Failure: $UInvLastErrorMessage <</UInvTry>>\ }}} That will try to run the UInv [[AddBag]] function. If it succeeds, then it will display the "Success!" message. If it fails, such as would happen if a bag named "backpack" already exists, then it will display a "Failure: " message, followed by the reason for the failure. Here's another example: {{{ <<set _room = "Room">>\ <<set _test = "_items = GetItemsArray(_room)">>\ <<UInvTry _test>>\ Items: _items <<Fail>>\ <<set UInv.CreateBag(_room)>>\ Items: (none) <</UInvTry>>\ }}} That will try to set {{{_items}}} to an array of all of the items in "Room" using [[GetItemsArray]]. If the "Room" bag exists, then it will show a list of items in that bag. If the "Room" bag //doesn't// exist (which is the most likely reason why ''GetItemsArray'' would fail), then it will create that bag using [[CreateBag]] and indicate that there are no items there. This can be quite useful if you want your code to be able to handle error messages which may be expected in certain situations, such as trying to delete an item that may or may not exist. ''NOTE:'' When using the {{{<<UInvTry>>}}} macro you should make sure you aren't using any other functions in the ''CodeString'' parameter which have the same name as UInv functions, or those functions won't work since they will have {{{UInv.}}} stuck in front of them by this macro. You can work around this by putting a space between the function name and the left parenthesis (e.g. {{{someFunction (parameters)}}}). ''DisplayArray(YourArray, [EmptyString], [SeparatorString], [ConjunctionString], [UseAPNumbers])'' Returns all of the elements in an array as a single string, or the ''EmptyString'' value if the array is empty. All of the properties other than ''YourArray'' are optional. ''EmptyString'' is the text to display if there are no items in the bag. This defaults to "nothing". ''SeparatorString'' is the string which separates items. It will be followed by a single space. This defaults to ",". ''ConjunctionString'' is the string which will show just before the last item in the bag if there is more than one item. This defaults to "and". ''UseAPNumbers'' determines whether numbers will be displayed per the [[numberToAPString]] function or not. This defaults to {{{false}}}. For example, the following Twine/SugarCube code: {{{Items: <<= UInv.DisplayArray(["apple", "banana", "carrot"])>>}}} Would display like this: Items: apple, banana, and carrot ''See also:'' [[DisplayItemList]] ''GetItemPocketObject(BagName, ItemName)'' = an object of { "PocketName": "BagName", ... } from item Gets an object containing the PocketName-PocketBagName key-value pairs on the item, returns {} if it has none, or undefined on error. ''GetTotalBagPropertyValue(BagPropertyName, [BagNameArray])'' gets the total value of BagPropertyName across all bags, or across all bags in BagNameArray Returns the total value of BagPropertyName across all bags, or across all bags in BagNameArray, or undefined on error. ''MoveBagPropertyValueToBag(SourceBagName, SourceBagPropertyName, DestinationBagName, [DestinationBagPropertyName], [Amount], [MinimumValue], [MaximumValue], [DeletionValue], [DeletionType])'' Moves moves the value of a property from one bag to another ''-or-'' if ''Amount'' is used, moves an amount of a number from one bag's property to another bag's property, limited by the minimum and maximum values. Deletes the bag, item, or property (depending on ''DeletionType'') if the property's value gets set to ''DeletionValue''. Returns the destination property's new value or undefined on error. If the ''DestinationBagPropertyName'' is not included then it uses the ''SourceBagPropertyName'' for both. If ''Amount'' is included, then it must be a number. If the ''Amount'' is ''not'' included, then it will move the entire value, overwriting the destination value. All parameters after ''Amount'' are ignored if there is no ''Amount'' parameter. If used, valid values for ''DeletionType'' are: * {{{"bag"}}} - Deletes the bag if its value equals ''DeletionValue'', does nothing to items. * {{{"item"}}} - Deletes the item if its value equals ''DeletionValue'', does nothing to bags. * {{{"object"}}} - Deletes the item or bag if its value equals ''DeletionValue''. * {{{"property"}}} - ''DEFAULT'' - Deletes the property if its value equals ''DeletionValue''. If you set a deletion value or if you set this to none of the above vlaues, then it will use this method. See also: [[MoveItemPropertyValueToBag]], [[MoveBagPropertyValueToItem]], [[MoveItemPropertyValueToItem]] ''MoveItemPropertyValueToBag(SourceBagName, SourceItemName, SourceItemPropertyName, DestinationBagName, [DestinationBagPropertyName], [Amount], [MinimumValue], [MaximumValue], [DeletionValue], [DeletionType])'' Moves moves the value of a property from an item to a bag to another ''-or-'' if ''Amount'' is used, moves an amount of a number from an item's property to a bag's property, limited by the minimum and maximum values. Deletes the bag, item, or property (depending on ''DeletionType'') if the property's value gets set to ''DeletionValue''. Returns the destination property's new value or undefined on error. If the ''DestinationBagPropertyName'' is not included then it uses the ''SourceItemPropertyName'' for both. ''SourceItemPropertyName'' cannot be {{{"UInvDefaultItemType"}}} or {{{"UInvPocket"}}}. If ''Amount'' is included, then it must be a number, or an integer if ''SourceItemPropertyName'' is {{{"UInvQuantity"}}}. If the ''Amount'' is ''not'' included, then it will move the entire value, overwriting the destination value. All parameters after ''Amount'' are ignored if there is no ''Amount'' parameter. If used, valid values for ''DeletionType'' are: * {{{"bag"}}} - Deletes the bag if its value equals ''DeletionValue'', does nothing to items. * {{{"item"}}} - Deletes the item if its value equals ''DeletionValue'', does nothing to bags. * {{{"object"}}} - Deletes the item or bag if its value equals ''DeletionValue''. * {{{"property"}}} - ''DEFAULT'' - Deletes the property if its value equals ''DeletionValue''. If you set a deletion value or if you set this to none of the above vlaues, then it will use this method. See also: [[MoveBagPropertyValueToBag]], [[MoveBagPropertyValueToItem]], [[MoveItemPropertyValueToItem]] ''MoveBagPropertyValueToItem(SourceBagName, SourceBagPropertyName, DestinationBagName, DestinationItemName, [DestinationItemPropertyName], [Amount], [MinimumValue], [MaximumValue], [DeletionValue], [DeletionType])'' Moves moves the value of a property from an item to a bag to another ''-or-'' if ''Amount'' is used, moves an amount of a number from a bag's property to an item's property, limited by the minimum and maximum values. Deletes the bag, item, or property (depending on ''DeletionType'') if the property's value gets set to ''DeletionValue''. Returns the destination property's new value or undefined on error. If the ''DestinationItemPropertyName'' is not included then it uses the ''SourceBagPropertyName'' for both. ''DestinationItemPropertyName'' cannot be {{{"UInvDefaultItemType"}}} or {{{"UInvPocket"}}}. If ''Amount'' is included, then it must be a number, or an integer if ''DestinationItemPropertyName'' is {{{"UInvQuantity"}}}. If the ''Amount'' is ''not'' included, then it will move the entire value, overwriting the destination value. All parameters after ''Amount'' are ignored if there is no ''Amount'' parameter. If used, valid values for ''DeletionType'' are: * {{{"bag"}}} - Deletes the bag if its value equals ''DeletionValue'', does nothing to items. * {{{"item"}}} - Deletes the item if its value equals ''DeletionValue'', does nothing to bags. * {{{"object"}}} - Deletes the item or bag if its value equals ''DeletionValue''. * {{{"property"}}} - ''DEFAULT'' - Deletes the property if its value equals ''DeletionValue''. If you set a deletion value or if you set this to none of the above vlaues, then it will use this method. See also: [[MoveItemPropertyValueToItem]], [[MoveBagPropertyValueToBag]], [[MoveItemPropertyValueToBag]] ''MoveItemPropertyValueToItem(SourceBagName, SourceItemName, SourceItemPropertyName, DestinationBagName, DestinationItemName, [DestinationItemPropertyName], [Amount], [MinimumValue], [MaximumValue], [DeletionValue], [DeletionType])'' Moves moves the value of a property from an item to a bag to another ''-or-'' if ''Amount'' is used, moves an amount of a number from one item's property to another item's property, limited by the minimum and maximum values. Deletes the bag, item, or property (depending on ''DeletionType'') if the property's value gets set to ''DeletionValue''. Returns the destination property's new value or undefined on error. If the ''DestinationItemPropertyName'' is not included then it uses the ''SourceItemPropertyName'' for both. ''SourceItemPropertyName'' and ''DestinationItemPropertyName'' cannot be {{{"UInvDefaultItemType"}}} or {{{"UInvPocket"}}}. If ''Amount'' is included, then it must be a number, or an integer if either property name is {{{"UInvQuantity"}}}. If the ''Amount'' is ''not'' included, then it will move the entire value, overwriting the destination value. All parameters after ''Amount'' are ignored if there is no ''Amount'' parameter. If used, valid values for ''DeletionType'' are: * {{{"bag"}}} - Deletes the bag if its value equals ''DeletionValue'', does nothing to items. * {{{"item"}}} - Deletes the item if its value equals ''DeletionValue'', does nothing to bags. * {{{"object"}}} - Deletes the item or bag if its value equals ''DeletionValue''. * {{{"property"}}} - ''DEFAULT'' - Deletes the property if its value equals ''DeletionValue''. If you set a deletion value or if you set this to none of the above vlaues, then it will use this method. See also: [[MoveBagPropertyValueToItem]], [[MoveBagPropertyValueToBag]], [[MoveItemPropertyValueToBag]] <center><h2>addArticle</h2></center>__Format:__ ''addArticle(''<<hovertip "''WordIn'' must be a string in quotes or a string variable. This parameter is the word or phrase which needs an indefinite article (\"a\" or \"an\") in front of it. No indefinite article will be put in front of the string if it already starts with an article or a possessive pronoun that the function recognizes.">>''WordIn''<</hovertip>>'', [''<<hovertip "__Optional:__ Determines the capitalization rule. If used it should be either {{{true}}} (to capitalize the article), {{{false}}} (to ''not'' capitalize the article), or {{{undefined}}} (to capitalize the article only if {{{WordIn}}} is capitalized, in which case also change the first character of {{{WordIn}}} to lowercase).<br>__Default Value:__ {{{undefined}}}">>''Caps''<</hovertip>>''], [''<<hovertip "__Optional:__ A special capitalization rule for words which are all uppercase acronyms (such as in \"NASA scientist\"), not merely an initialism (such as in \"FBI agent\"). If used it should be either {{{true}}} or {{{false}}}.<br>__Default Value:__ {{{false}}}">>''Acronym''<</hovertip>>''])'' __Short Description:__ Puts an indefinite article ("a" or "an") in front of a singular noun. __Returns:__ "a " or "an " followed by the string passed in.<span style="float: right;">__Added:__ ''UInv v1.0.0''</span> __Sets:__ (nothing) __See Also:__ <<Title "Details">> The {{{addArticle()}}} function tries to add the correct indefinite article (i.e. "a" or "an") in front of the string you pass in as the {{{WordIn}}} parameter. That string should begin with a singular noun. The function will throw an error if the first parameter isn't a string. The function will not put an indefinite article in front of the string if it already begins with an article or a possessive pronoun which it recognizes. The function will try to automatically capitalize the article correctly based on the capitalization of the string passed in through the first parameter. So {{{UInv.addArticle("Hour")}}} will return {{{An hour}}}, where the capitalization of "Hour" is moved to the "An". (''Note:'' If the string doesn't start with a letter, then the capitalization will remain unchanged.) The function can't automatically recognize proper nouns (like "Tuesday") or tell acronyms (like "FUBAR") apart from initialisms (like "FBI"), so you have to use the 2nd and 3rd parameters in those cases if you want everything to display properly (see the examples underneath the failure cases in the table below). If the first word starts with more than one capital letter it will be treated as an initialism (e.g. "FBI agent" returns "an FBI agent"). The {{{Caps}}} parameter is optional, and should be set when dealing with proper nouns or when dealing with initials, initialisms, or acronyms where you need the article in front of the string to be capitalized. This parameter defaults to {{{undefined}}}, in which case it will "steal" any capitalization from the first word (e.g. "Hour" returns "An hour"). If {{{Caps}}} is set to {{{true}}} then "a"/"an" will be capitalized and {{{WordIn}}} will be returned unchanged (e.g. "Tuesday" returns "A Tuesday"). If {{{Caps}}} is set to {{{false}}} then "a"/"an" will be lowercase and {{{WordIn}}} will be returned unchanged (e.g. "Friday" returns "a Friday"). Setting the {{{Acronym}}} parameter to {{{true}}} tells the function to treat words in all caps as acronyms, instead of as initialisms (e.g. "FUBAR situation" returns "a FUBAR situation"). If you don't set this parameter then it defaults to {{{false}}} and treats words in all caps as initialisms. <<Title "TL;DR Explanation">> ''Use Cases:'' {{{UInv.addArticle(WordIn, [Caps], [Acronym])}}} * If you're ''not'' dealing with proper nouns you can can probably ignore the {{{Caps}}} and {{{Acronym}}} parameters except for the case where the {{{WordIn}}} string is used at the beginning of a sentence. In that case you can either capitalize the first word in the {{{WordIn}}} parameter or you can set {{{Caps}}} to {{{true}}}, and that will capitalize the returned string, and change the first character of {{{WordIn}}} to lowercase. * If you ''are'' dealing with proper nouns (e.g. "Bob" or "Paris") you should set {{{Caps}}} to {{{true}}} when the string is at the beginning of a sentence, or {{{false}}} when not at the beginning of a sentence. * You only need to set {{{Acronym}}} to {{{true}}} when dealing with an all uppercase acronym, otherwise you can ignore this parameter. The function assumes by default that words which are all uppercase are initialisms, not acronyms. This parameter is just for the rare situation where the all uppercase word is an acronym, not an initialization. <<Title "Sample Code">> You could use the function like this: {{{ You find <<print UInv.addArticle(_itemName, false)>> in the chest. }}} And if {{{_itemName}}} was set to "sword", then the output from that would be: {{{ You find a sword in the chest. }}} <<Title "Try the {{{addArticle()}}} function out">> ''Enter a word or phrase starting with a singular noun:'' <input id="txt" type="test" oninput="updateAA()" onfocus="updateAA(); this.select();" autofocus value="Hour" style="position: relative; left: 1.5em;"> ''Default output:'' {{{UInv.addArticle("word")}}} * <span id="output"></span> ''Output for proper nouns:'' {{{UInv.addArticle("word", true/false)}}} * 2nd parameter is {{{true}}}: <span id="toutput"></span> * 2nd parameter is {{{false}}}: <span id="foutput"></span> ''Output for all uppercase acronyms only:'' {{{UInv.addArticle("word", undefined, true)}}} * <span id="aoutput"></span> <<Title "Function Examples">> <span class="wrong">Red items</span> = failure cases. The cases which follow them show how to deal with the problem. <span class="forced">Yellow items</span> = forced failure. Cases caused by bad string parameter values.<table class="tstyle"><tr><th>Parameters:</th><th>Output:</th></tr> <tr><td>"test"</td><td><<print UInv.addArticle("test")>></td></tr> <tr><td>"Test"</td><td><<print UInv.addArticle("Test")>></td></tr> <tr><td>"apple"</td><td><<print UInv.addArticle("apple")>></td></tr> <tr><td>"Apple"</td><td><<print UInv.addArticle("Apple")>></td></tr> <tr><td>"an apple"</td><td><<print UInv.addArticle("an apple")>></td></tr> <tr><td>"a apple"</td><td class="forced"><<print UInv.addArticle("a apple")>></td></tr> <tr><td>"the apple"</td><td><<print UInv.addArticle("the apple")>></td></tr> <tr><td>"my apple"</td><td><<print UInv.addArticle("my apple")>></td></tr> <tr><td>"an banana"</td><td class="forced"><<print UInv.addArticle("an banana")>></td></tr> <tr><td>"one-time deal"</td><td><<print UInv.addArticle("one-time deal")>></td></tr> <tr><td>"hour long ride"</td><td><<print UInv.addArticle("hour long ride")>></td></tr> <tr><td>"3-hour tour"</td><td><<print UInv.addArticle("3-hour tour")>></td></tr> <tr><td>"88 MPH sign"</td><td><<print UInv.addArticle("88 MPH sign")>></td></tr> <tr><td>"house", true</td><td><<print UInv.addArticle("house", true)>></td></tr> <tr><td>"house", false</td><td><<print UInv.addArticle("house", false)>></td></tr> <tr><td>"Tuesday"</td><td class="wrong"><<print UInv.addArticle("Tuesday")>></td></tr> <tr><td>"Tuesday", true</td><td><<print UInv.addArticle("Tuesday", true)>></td></tr> <tr><td>"Tuesday", false</td><td><<print UInv.addArticle("Tuesday", false)>></td></tr> <tr><td>"<nowiki>//Rift//</nowiki>"</td><td class="forced"><<print UInv.addArticle("//Rift//")>></td></tr> <tr><td>"<nowiki>//rift//</nowiki>", true</td><td><<print UInv.addArticle("//rift//", true)>></td></tr> <tr><td>"<nowiki>//People// magazine</nowiki>"</td><td class="wrong"><<print UInv.addArticle("//People// magazine")>></td></tr> <tr><td>"<nowiki>//People// magazine</nowiki>", false</td><td><<print UInv.addArticle("//People// magazine", false)>></td></tr> <tr><td>"F Scott Fitzgerald book"</td><td><<print UInv.addArticle("F Scott Fitzgerald book")>></td></tr> <tr><td>"F. Scott Fitzgerald book"</td><td><<print UInv.addArticle("F. Scott Fitzgerald book")>></td></tr> <tr><td>"CIA agent"</td><td><<print UInv.addArticle("CIA agent")>></td></tr> <tr><td>"CIA agent", true</td><td><<print UInv.addArticle("CIA agent", true)>></td></tr> <tr><td>"FBI agent"</td><td><<print UInv.addArticle("FBI agent")>></td></tr> <tr><td>"EPA test", true</td><td><<print UInv.addArticle("EPA test", true)>></td></tr> <tr><td>"UFO"</td><td><<print UInv.addArticle("UFO")>></td></tr> <tr><td>"SNAFU"</td><td class="wrong"><<print UInv.addArticle("SNAFU")>></td></tr> <tr><td>"SNAFU", undefined, true</td><td><<print UInv.addArticle("SNAFU", undefined, true)>></td></tr></table> <<Title '"Why/When would I use it?"'>> Most commonly you would use this function if your game has a list of items, and you didn't want to have to build the appropriate article into the code for each item when it's used in singular form. Instead, you could use the {{{addArticle()}}} function to automatically display the item names with the appropriate article for normal English speech. For example, if you had an {{{$inventory}}} array in which each element was an item name, like this: {{{ <<set $inventory = ["map", "hourglass", "lamp", "the Sword of Legends"]>> }}} then you could print it out like this: {{{ You're carrying \ <<for _i = 0; _i < $inventory.length; _i++>>\ <<print UInv.addArticle($inventory[_i])>><<if ($inventory.length > 2) && (_i < $inventory.length - 1)>>, <</if>>\ <<if ($inventory.length > 1) && (_i == $inventory.length - 2)>>and <</if>>\ <</for>>. }}} which would produce the following output: <<set $inventory = ["map", "hourglass", "lamp", "the Sword of Legends"]>> You're carrying \ <<for _i = 0; _i < $inventory.length; _i++>>\ <<print UInv.addArticle($inventory[_i])>><<if ($inventory.length > 2) && (_i < $inventory.length - 1)>>, <</if>>\ <<if ($inventory.length > 1) && (_i == $inventory.length - 2)>>and <</if>>\ <</for>>. So you can see that the appropriate article is automatically put in front of each item name by the function. <<Title '"Word \'X\' doesn\'t work right. How do I fix it?"'>> If you run into a word that doesn't work properly, just add it to the appropriate array in the JavaScript code. * If it's a word that's showing "an" when it should show "a", then add it to the {{{acon}}} array. * If it's a word that's showing "a" when it should show "an", then add it to the {{{anvwl}}} array. * If it's a word that you don't want an article added in front of, then add it to the {{{aanskip}}} array. <<Title "Error Cases">> ''addArticle(WordIn, [Caps], [Acronym])'' will throw an error if: * ''WordIn'' is ''not'' a string <<script>> $(document).one(":passagedisplay", function (ev) { setTimeout(function () { $("#txt").focus(); window.scrollTo(0, 0); }, 200); }); if (!UInv.isProperty(window, "updateAA")) { window.updateAA = function () { if ($("#output")) { $("#output").empty().wiki(UInv.addArticle($("#txt").val())); $("#toutput").empty().wiki(UInv.addArticle($("#txt").val(), true)); $("#foutput").empty().wiki(UInv.addArticle($("#txt").val(), false)); $("#aoutput").empty().wiki(UInv.addArticle($("#txt").val(), undefined, true)); } }; } <</script>><div style="text-align: center"><h2>Glossary of Terms</h2></div> ''Terms:'' Twine Passage Special Passage Link Tag / Tagged Story Map Story History Proofing Format Story Format SugarCube Story Variable Temporary Variable Scope Object The {{{setup}}} Object Parameter / Key Array Array Index Array Element HTML Element Attribute Class ID Selector Style CSS HTML JavaScript jQuery Inspector Console Window Absolute File Path Relative File Path UI Bar Dialog Box Select Box / Dropdown Box <center><h2>Primitive Variables vs Object Variables</h2></center>There are two basic variable types: //primitives// and //objects// Primitive variables you're likely to use are //<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">Boolean</a>// (true / false), //<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null">null</a>//, //<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined">undefined</a>//, //<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number">Number</a>//, and //<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String">String</a>//. (There are also //<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt">BigInt</a>// and //<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol">Symbol</a>// primitives, but <a href="http://www.motoslave.net/sugarcube/2/docs/#twinescript-supported-types">they aren't supported in SugarCube</a> or some browsers.) Object variables, on the other hand, are structures for holding multiple primitive variables and/or other objects. Most commonly you'll use an //<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a>// or a generic //<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a>//, but //<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date">Date</a>//, //<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map">Map</a>//, and //<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set">Set</a>// objects are also supported. Which one to use when handling your data really comes down to how many pieces of data you're planning on tracking and how you need to access that data. Generally, if it's only a couple of values you're working with, it's easier to just use a variable with a primitive data type (a string, boolean, number, etc.) than an object variable. However, if you're working with a lot of variables, especially if they're easily organized into groups, then an object (either a generic object or an array; see also [[Arrays vs Generic Objects]]) is probably better. So, let's say that instead of one NPC, you could have any number of NPCs. Then you might want to use a generic object like {{{$npc.Anne}}}, {{{$npc.Bob}}}, {{{$npc.Charlie}}}, etc..., where each of those NPCs have {{{name}}}, {{{skill}}}, and {{{weapon}}} properties like this: {{{ <<set $npc = {}>> /* Initializes $npc as a generic object. */ <<set $npc.Anne = { name: "Anne Smith", skill: "magic", weapon: "a wand" }>> <<set $npc.Bob = { name: "Bob Jones", skill: "fighting", weapon: "a sword" }>> <<set $npc.Charlie = { name: "Charlie Tran", skill: "stealth", weapon: "throwing knives" }>> }}} Now, you could access that data by using "bracket notation" (instead of "dot notation" like above) like this: {{{ <<set _NPCID = "Anne">> <<set _NPCName = $npc[_NPCID].name>> }}} That would set {{{_NPCName}}} to "{{{Anne Smith}}}" in this example. This gives you an easy way to access the information about each NPC by using their unique ID like that. Also, just to be clear, in the above example, {{{$npc}}} is an object, as is {{{$npc.Anne}}}. On the other hand, {{{$npc.Anne.name}}} is a string, because it's set to "{{{Anne Smith}}}". The {{{.name}}} part is a property (also sometimes called a "key") of the {{{$npc.Anne}}} object, and {{{.Anne}}} is a property of the {{{$npc}}} object. As for bracket notation giving you an easy way to access the information, what I mean is that you can write the code to work for all NPCs, and then you just plug in an NPC's unique ID to have the code work on that particular NPC. For a simple example using the earlier code, you could list info about each NPC like this: {{{ <<set _i = 0>> <<for _NPCID, _NPC range $npc>> <<print ++_i>>. $npc[_NPCID].name - Skill: _NPC.skill - Weapon: _NPC.weapon <</for>> }}} (In that example {{{$npc[_NPCID]}}} and {{{_NPC}}} both represent the same object, I did it both ways just for an example of the ways you can do that. See the <a href="http://www.motoslave.net/sugarcube/2/docs/#macros-macro-for">''{{{<<for>>}}}'' macro</a> for details.) That code would allow you display a list of all NPCs, regardless of how many NPCs you have. There isn't an easy way to do that if you have different variables for each NPC. That's what I meant about having an "easy way" to access information, compared to how difficult some things would be to do with individual variables. One other major difference between variables holding primitive values and variables which hold objects, is that primitives are stored "by value" (meaning that referring to the variable refers directly to the value) while objects are stored "by reference" (meaning that the variable is actually a pointer to some data, rather than just the data itself). This means that if you do this: {{{ <<set $A = "test">> <<set $B = "test">> <<print ($A == $B)>> }}} it will print {{{true}}} because the primitive values in those variables are the same. However, if you do: {{{ <<set $A = { data: "test" }>> <<set $B = { data: "test" }>> <<print ($A == $B)>> }}} that will print out {{{false}}} because those two variables are pointing to different objects, even though those two objects contain identical information. On the other hand, if you do this: {{{ <<set $A = { data: "test" }>> <<set $B = $A>> <<print ($A == $B)>> }}} then that will print out {{{true}}} because currently both {{{$A}}} and {{{$B}}} point to the same object. Normally that would remain the case, however SugarCube <a href="http://www.motoslave.net/sugarcube/2/docs/#functions-function-clone">clones</a> objects during passage transitions. This means that, for example, after the user clicks on a link that loads a passage, then those two variables will get cloned, turning them into separate copies of that object, so they will no longer be equal. However, if you did this all within the same passage: {{{ <<set $A = { data: "test" }>> <<set $B = $A>> <<set $B.data = "result">> <<print $A>> }}} That would print {{{result}}}, because at that point both {{{$A}}} and {{{$B}}} refer to the same object data, so modifying data on one variable affects both of them (at least, that's how things will work until the next passage transition). Remembering this difference between variables with primitive values vs object values can be important when you're passing an object to a function, <a href="http://www.motoslave.net/sugarcube/2/docs/#macros-macro-widget">widget</a>, or <a href="http://www.motoslave.net/sugarcube/2/docs/#macro-api">macro</a>, because an object passed to them can be modified by them, while a primitive value passed to them cannot be. This can be useful if you //''do''// want them to modify an object's values, or a potential problem to watch out for if you //''don't''// want them to modify an object's values. Hopefully you can see now how primitives and objects have different uses. Primitives are easier to compare and are safe to pass to functions, while objects are easier to use for collections of data and allow you to have functions which modify directly that data. {{{ IMPORTANT: Table drag-drop events require the inclusion of jQuery UI. See the UInv sample code which demonstrates how to do this. }}} Double-click this passage to edit it.''isArrayOfMaps(Value)'' = t/f Test an array to see if all the values are maps. Returns {{{undefined}}} if ''Value'' is not an array. ''isSet(Value)'' = t/f Returns if a value is a set. ''isMap(Value)'' = t/f Returns if a value is a map. ''isArrayOfSets(Value)'' = t/f Test an array to see if all the values are sets. Returns {{{undefined}}} if ''Value'' is not an array. ''mapsAreEqual(Map1, Map2)'' = t/f Check two maps to see if they're identical. Returns {{{false}}} if either parameter passed is not a map. ''setsAreEqual(Set1, Set2)'' = t/f Check two sets to see if they're identical, including the order. Returns {{{false}}} if either parameter passed is not a set. See also: [[setsMatch]] for unordered matches of sets ''setsMatch(Set1, Set2)'' Returns if two sets contain matches for all values in any order. See also: [[setsAreEqual]] for ordered matches of sets ''isArrayOfType(Value, Type)'' = t/f Test an array to see if all the values are of that type. Returns {{{undefined}}} if ''Value'' is not an array or if ''Type'' is not a valid type. Valid ''Type'' values are: * "Array" * "Boolean" * "Date" * "Generic Object" * "Integer" * "Map" * "Number" * "Object" * "Set" * "String" The ''Type'' parameter should be a string and is ''not'' case sensitive (i.e. "Array", "array", and "ARRAY" are all valid ''Type'' values). Double-click this passage to edit it.''spread(Value, [Value2/Funct])'' Returns a Map, Set, or String converted to an array. If the optional second parameter is an Array, Map, Set, or String, then the two objects are spread and returned as a single array. If a function is passed as the second parameter, this calls the function with the spread array as parameters and returns that function's value. ''isArrayOfDates(Value)'' = t/f Test an array to see if all the values are dates. Returns {{{undefined}}} if ''Value'' is not an array.