From 1b3d00a36ccc20961c8c89a0e94c330f0ec8fe17 Mon Sep 17 00:00:00 2001
From: Haxxer
Date: Fri, 7 Jan 2022 16:30:36 +0000
Subject: [PATCH] Changelog, documentation, remove incompat check
---
changelog.md | 1 -
docs/api.md | 372 +++++----
scripts/api.js | 1924 +++++++++++++++++++++----------------------
scripts/module.js | 1 -
scripts/settings.js | 17 -
5 files changed, 1167 insertions(+), 1148 deletions(-)
diff --git a/changelog.md b/changelog.md
index 786bea1c..928e4eb5 100644
--- a/changelog.md
+++ b/changelog.md
@@ -4,7 +4,6 @@
- Added API endpoints:
- `ItemPiles.API.getItemPileItemTypeFilters(TokenDocument|Actor)` - Returns the item type filters for a given item pile
- `ItemPiles.API.getItemPileItems(TokenDocument|Actor, Array|Boolean)` - Returns the items the item pile contains and can transfer
-- Added warning on startup for module incompatibilities
- Updated japanese localization
- Fixed item piles not respecting item type filters
- Fixed issue with `ItemPiles.API.turnTokenIntoItemPile` not actually turning the token into an item pile
diff --git a/docs/api.md b/docs/api.md
index 8f4447ba..16babfe4 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -20,7 +20,7 @@
## Functions
-### Settings
+### Setting Methods
setActorClassType(inClassType) ⇒ Promise
@@ -39,7 +39,7 @@
Sets the filters for item types eligible for interaction within this system
-### Item Piles
+### Item Pile Methods
createItemPile(position, [items], [pileActorName]) ⇒ Promise
Creates the default item pile token at a location.
@@ -108,28 +108,28 @@
Causes all connected users to re-render a specific pile's inventory UI
-### Items & Attributes
+### Item and Attribute Methods
-transferItems(source, target, items, [itemTypeFilters]) ⇒ Promise.<object>
-Transfers items from the source to the target, subtracting a number of quantity from the source's item and adding it to the target's item, deleting items from the source if their quantity reaches 0
+addItems(target, items, [itemTypeFilters]) ⇒ Promise.<array>
+Adds item to an actor, increasing item quantities if matches were found
removeItems(target, items, [itemTypeFilters]) ⇒ Promise.<array>
Subtracts the quantity of items on an actor. If the quantity of an item reaches 0, the item is removed from the actor.
-addItems(target, items, [itemTypeFilters]) ⇒ Promise.<array>
-Adds item to an actor, increasing item quantities if matches were found
+transferItems(source, target, items, [itemTypeFilters]) ⇒ Promise.<object>
+Transfers items from the source to the target, subtracting a number of quantity from the source's item and adding it to the target's item, deleting items from the source if their quantity reaches 0
transferAllItems(source, target, [itemTypeFilters]) ⇒ Promise.<array>
Transfers all items between the source and the target.
-transferAttributes(source, target, attributes) ⇒ Promise.<object>
-Transfers a set quantity of an attribute from a source to a target, removing it or subtracting from the source and adds it the target
+addAttributes(target, attributes) ⇒ Promise.<object>
+Adds to attributes on an actor
removeAttributes(target, attributes) ⇒ Promise.<object>
Subtracts attributes on the target
-addAttributes(target, attributes) ⇒ Promise.<object>
-Adds to attributes on an actor
+transferAttributes(source, target, attributes) ⇒ Promise.<object>
+Transfers a set quantity of an attribute from a source to a target, removing it or subtracting from the source and adds it the target
transferAllAttributes(source, target) ⇒ Promise.<object>
Transfers all dynamic attributes from a source to a target, removing it or subtracting from the source and adding them to the target
@@ -138,7 +138,7 @@
Transfers all items and attributes between the source and the target.
-### Utility
+### Utility Methods
rerenderTokenHud() ⇒ Promise
Causes every user's token HUD to rerender
@@ -151,196 +151,97 @@ or not, returning the type if it is NOT allowed.
-## ItemPiles.API.ACTOR\_CLASS\_TYPE ⇒ string
+## ACTOR\_CLASS\_TYPE ⇒ string
The actor class type used for the original item pile actor in this system
-## ItemPiles.API.DYNAMIC\_ATTRIBUTES ⇒ array
+## DYNAMIC\_ATTRIBUTES ⇒ array
The attributes used to track dynamic attributes in this system
-## ItemPiles.API.ITEM\_QUANTITY\_ATTRIBUTE ⇒ string
+## ITEM\_QUANTITY\_ATTRIBUTE ⇒ string
The attribute used to track the quantity of items in this system
-## ItemPiles.API.ITEM\_TYPE\_ATTRIBUTE ⇒ string
+## ITEM\_TYPE\_ATTRIBUTE ⇒ string
The attribute used to track the item type in this system
-## ItemPiles.API.ITEM\_TYPE\_FILTERS ⇒ Array
+## ITEM\_TYPE\_FILTERS ⇒ Array
The filters for item types eligible for interaction within this system
-## ItemPiles.API.setActorClassType(inClassType) ⇒ Promise
+## setActorClassType(inClassType) ⇒ Promise
Sets the actor class type used for the original item pile actor in this system
+
| Param | Type |
| --- | --- |
| inClassType | string
|
-## ItemPiles.API.setDynamicAttributes(inAttributes) ⇒ Promise
+## setDynamicAttributes(inAttributes) ⇒ Promise
Sets the attributes used to track dynamic attributes in this system
+
| Param | Type |
| --- | --- |
| inAttributes | array
|
-## ItemPiles.API.setItemQuantityAttribute(inAttribute) ⇒ Promise
+## setItemQuantityAttribute(inAttribute) ⇒ Promise
Sets the inAttribute used to track the quantity of items in this system
+
| Param | Type |
| --- | --- |
| inAttribute | string
|
-## ItemPiles.API.setItemTypeAttribute(inAttribute) ⇒ string
+## setItemTypeAttribute(inAttribute) ⇒ string
Sets the attribute used to track the item type in this system
+
| Param | Type |
| --- | --- |
| inAttribute | string
|
-## ItemPiles.API.setItemTypeFilters(inFilters) ⇒ Promise
+## setItemTypeFilters(inFilters) ⇒ Promise
Sets the filters for item types eligible for interaction within this system
+
| Param | Type |
| --- | --- |
| inFilters | string/array
|
-## ItemPiles.API.createItemPile(position, [items], [pileActorName]) ⇒ Promise
+## createItemPile(position, [items], [pileActorName]) ⇒ Promise
Creates the default item pile token at a location.
+
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| position | object
| | The position to create the item pile at |
| [items] | array/boolean
| false
| Any items to create on the item pile |
| [pileActorName] | string/boolean
| false
| Whether to use an existing item pile actor as the basis of this new token |
-
-
-## ItemPiles.API.transferItems(source, target, items, [itemTypeFilters]) ⇒ Promise.<object>
-Transfers items from the source to the target, subtracting a number of quantity from the source's item and adding it to the target's item, deleting items from the source if their quantity reaches 0
-**Returns**: Promise.<object>
- An object containing a key value pair for each item added to the target, key being item ID, value being quantities added
-
-| Param | Type | Default | Description |
-| --- | --- | --- | --- |
-| source | Actor/Token/TokenDocument
| | The source to transfer the items from |
-| target | Actor/Token/TokenDocument
| | The target to transfer the items to |
-| items | array
| | An array of objects each containing the item id (key "_id") and the quantity to transfer (key "quantity") |
-| [itemTypeFilters] | array/boolean
| false
| Array of item types disallowed - will default to module settings if none provided |
-
-
-
-## ItemPiles.API.removeItems(target, items, [itemTypeFilters]) ⇒ Promise.<array>
-Subtracts the quantity of items on an actor. If the quantity of an item reaches 0, the item is removed from the actor.
-**Returns**: Promise.<array>
- An array containing the objects of each item that was removed, with their quantities set to the number removed
-
-| Param | Type | Default | Description |
-| --- | --- | --- | --- |
-| target | Actor/Token/TokenDocument
| | The target to remove a items from |
-| items | array
| | An array of objects each containing the item id (key "_id") and the quantity to remove (key "quantity"), or an array of IDs to remove all quantities of |
-| [itemTypeFilters] | array/boolean
| false
| Array of item types disallowed - will default to module settings if none provided |
-
-
-
-## ItemPiles.API.addItems(target, items, [itemTypeFilters]) ⇒ Promise.<array>
-Adds item to an actor, increasing item quantities if matches were found
-**Returns**: Promise.<array>
- An array containing each item added as an object, with their quantities updated to match the new amounts
-
-| Param | Type | Default | Description |
-| --- | --- | --- | --- |
-| target | Actor/TokenDocument/Token
| | The target to add an item to |
-| items | array
| | An array of item objects |
-| [itemTypeFilters] | array/boolean
| false
| Array of item types disallowed - will default to module settings if none provided |
-
-
-
-## ItemPiles.API.transferAllItems(source, target, [itemTypeFilters]) ⇒ Promise.<array>
-Transfers all items between the source and the target.
-**Returns**: Promise.<array>
- An array containing all of the items that were transferred to the target
-
-| Param | Type | Default | Description |
-| --- | --- | --- | --- |
-| source | Actor/Token/TokenDocument
| | The actor to transfer all items from |
-| target | Actor/Token/TokenDocument
| | The actor to receive all the items |
-| [itemTypeFilters] | array/boolean
| false
| Array of item types disallowed - will default to module settings if none provided |
-
-
-
-## ItemPiles.API.transferAttributes(source, target, attributes) ⇒ Promise.<object>
-Transfers a set quantity of an attribute from a source to a target, removing it or subtracting from the source and adds it the target
-**Returns**: Promise.<object>
- An object containing a key value pair of each attribute transferred, the key being the attribute path and its value being the quantity that was transferred
-
-| Param | Type | Description |
-| --- | --- | --- |
-| source | Actor/Token/TokenDocument
| The source to transfer the attribute from |
-| target | Actor/Token/TokenDocument
| The target to transfer the attribute to |
-| attributes | array/object
| This can be either an array of attributes to transfer (to transfer all of a given attribute), or an object with each key being an attribute path, and its value being the quantity to transfer |
-
-
-
-## ItemPiles.API.removeAttributes(target, attributes) ⇒ Promise.<object>
-Subtracts attributes on the target
-**Returns**: Promise.<object>
- Returns an array containing a key value pair of the attribute path and the quantity of that attribute that was removed
-
-| Param | Type | Description |
-| --- | --- | --- |
-| target | Token/TokenDocument
| The target whose attributes will be subtracted from |
-| attributes | array/object
| This can be either an array of attributes to subtract (to zero out a given attribute), or an object with each key being an attribute path, and its value being the quantity to subtract |
-
-
-
-## ItemPiles.API.addAttributes(target, attributes) ⇒ Promise.<object>
-Adds to attributes on an actor
-**Returns**: Promise.<object>
- Returns an array containing a key value pair of the attribute path and the quantity of that attribute that was removed
-
-| Param | Type | Description |
-| --- | --- | --- |
-| target | Actor/Token/TokenDocument
| The target whose attribute will have a set quantity added to it |
-| attributes | object
| An object with each key being an attribute path, and its value being the quantity to add |
-
-
-
-## ItemPiles.API.transferAllAttributes(source, target) ⇒ Promise.<object>
-Transfers all dynamic attributes from a source to a target, removing it or subtracting from the source and adding them to the target
-**Returns**: Promise.<object>
- An object containing a key value pair of each attribute transferred, the key being the attribute path and its value being the quantity that was transferred
-
-| Param | Type | Description |
-| --- | --- | --- |
-| source | Actor/Token/TokenDocument
| The source to transfer the attributes from |
-| target | Actor/Token/TokenDocument
| The target to transfer the attributes to |
-
-
-
-## ItemPiles.API.transferEverything(source, target, [itemTypeFilters]) ⇒ Promise.<object>
-Transfers all items and attributes between the source and the target.
-**Returns**: Promise.<object>
- An object containing all items and attributes transferred to the target
-
-| Param | Type | Default | Description |
-| --- | --- | --- | --- |
-| source | Actor/Token/TokenDocument
| | The actor to transfer all items and attributes from |
-| target | Actor/Token/TokenDocument
| | The actor to receive all the items and attributes |
-| [itemTypeFilters] | array/boolean
| false
| Array of item types disallowed - will default to module settings if none provided |
-
-## ItemPiles.API.turnTokenIntoItemPile(target, pileSettings, tokenSettings) ⇒ Promise.<string>
+## turnTokenIntoItemPile(target, pileSettings, tokenSettings) ⇒ Promise.<string>
Turns a token and its actor into an item pile
-**Returns**: Promise.<string>
- The uuid of the target after it was turned into an item pile
+
+**Returns**: Promise.<string>
- The uuid of the target after it was turned into an item pile
| Param | Type | Description |
| --- | --- | --- |
@@ -350,24 +251,22 @@ Turns a token and its actor into an item pile
-## ItemPiles.API.revertTokenFromItemPile(target, tokenSettings) ⇒ Promise.<string>
+## revertTokenFromItemPile(target, tokenSettings) ⇒ Promise.<string>
Reverts a token from an item pile into a normal token and actor
-**Returns**: Promise.<string>
- The uuid of the target after it was reverted from an item pile
+
+**Returns**: Promise.<string>
- The uuid of the target after it was reverted from an item pile
| Param | Type | Description |
| --- | --- | --- |
| target | Token/TokenDocument
| The target to be reverted from an item pile |
| tokenSettings | object
| Overriding settings that will update the token |
-
-
-## ItemPiles.API.rerenderTokenHud() ⇒ Promise
-Causes every user's token HUD to rerender
-## ItemPiles.API.openItemPile(target, [interactingToken]) ⇒ Promise
+## openItemPile(target, [interactingToken]) ⇒ Promise
Opens a pile if it is enabled and a container
+
| Param | Type | Default |
| --- | --- | --- |
| target | Token/TokenDocument
| |
@@ -375,9 +274,10 @@ Opens a pile if it is enabled and a container
-## ItemPiles.API.closeItemPile(target, [interactingToken]) ⇒ Promise
+## closeItemPile(target, [interactingToken]) ⇒ Promise
Closes a pile if it is enabled and a container
+
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| target | Token/TokenDocument
| | Target pile to close |
@@ -385,9 +285,10 @@ Closes a pile if it is enabled and a container
-## ItemPiles.API.toggleItemPileClosed(target, [interactingToken]) ⇒ Promise
+## toggleItemPileClosed(target, [interactingToken]) ⇒ Promise
Toggles a pile's closed state if it is enabled and a container
+
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| target | Token/TokenDocument
| | Target pile to open or close |
@@ -395,9 +296,10 @@ Toggles a pile's closed state if it is enabled and a container
-## ItemPiles.API.lockItemPile(target, [interactingToken]) ⇒ Promise
+## lockItemPile(target, [interactingToken]) ⇒ Promise
Locks a pile if it is enabled and a container
+
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| target | Token/TokenDocument
| | Target pile to lock |
@@ -405,9 +307,10 @@ Locks a pile if it is enabled and a container
-## ItemPiles.API.unlockItemPile(target, [interactingToken]) ⇒ Promise
+## unlockItemPile(target, [interactingToken]) ⇒ Promise
Unlocks a pile if it is enabled and a container
+
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| target | Token/TokenDocument
| | Target pile to unlock |
@@ -415,9 +318,10 @@ Unlocks a pile if it is enabled and a container
-## ItemPiles.API.toggleItemPileLocked(target, [interactingToken]) ⇒ Promise
+## toggleItemPileLocked(target, [interactingToken]) ⇒ Promise
Toggles a pile's locked state if it is enabled and a container
+
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| target | Token/TokenDocument
| | Target pile to lock or unlock |
@@ -425,45 +329,50 @@ Toggles a pile's locked state if it is enabled and a container
-## ItemPiles.API.rattleItemPile(target) ⇒ Promise.<boolean>
+## rattleItemPile(target) ⇒ Promise.<boolean>
Causes the item pile to play a sound as it was attempted to be opened, but was locked
+
| Param | Type |
| --- | --- |
| target | Token/TokenDocument
|
-## ItemPiles.API.isItemPileLocked(target) ⇒ boolean
+## isItemPileLocked(target) ⇒ boolean
Whether an item pile is locked. If it is not enabled or not a container, it is always false.
+
| Param | Type |
| --- | --- |
| target | Token/TokenDocument
|
-## ItemPiles.API.isItemPileClosed(target) ⇒ boolean
+## isItemPileClosed(target) ⇒ boolean
Whether an item pile is closed. If it is not enabled or not a container, it is always false.
+
| Param | Type |
| --- | --- |
| target | Token/TokenDocument
|
-## ItemPiles.API.isItemPileContainer(target) ⇒ boolean
+## isItemPileContainer(target) ⇒ boolean
Whether an item pile is a container. If it is not enabled, it is always false.
+
| Param | Type |
| --- | --- |
| target | Token/TokenDocument
|
-## ItemPiles.API.updateItemPile(target, newData, [interactingToken], [tokenSettings]) ⇒ Promise
+## updateItemPile(target, newData, [interactingToken], [tokenSettings]) ⇒ Promise
Updates a pile with new data.
+
| Param | Type | Default |
| --- | --- | --- |
| target | Token/TokenDocument
| |
@@ -473,56 +382,50 @@ Updates a pile with new data.
-## ItemPiles.API.deleteItemPile(target) ⇒ Promise
+## deleteItemPile(target) ⇒ Promise
Deletes a pile, calling the relevant hooks.
+
| Param | Type |
| --- | --- |
| target | Token/TokenDocument
|
-
-
-## ItemPiles.API.isItemTypeDisallowed(item, [itemTypeFilters]) ⇒ boolean/string
-Checks whether an item (or item data) is of a type that is not allowed. If an array whether that type is allowed
-or not, returning the type if it is NOT allowed.
-
-| Param | Type | Default |
-| --- | --- | --- |
-| item | Item/Object
| |
-| [itemTypeFilters] | array/boolean
| false
|
-
-## ItemPiles.API.isValidItemPile(document) ⇒ boolean
+## isValidItemPile(document) ⇒ boolean
Whether a given document is a valid pile or not
+
| Param | Type |
| --- | --- |
| document | TokenDocument
\| Actor
|
-## ItemPiles.API.isItemPileEmpty(target) ⇒ boolean
+## isItemPileEmpty(target) ⇒ boolean
Whether the item pile is empty
+
| Param | Type |
| --- | --- |
| target | TokenDocument
\| Actor
|
-## ItemPiles.API.getItemPileItemTypeFilters(target) ⇒ Array
+## getItemPileItemTypeFilters(target) ⇒ Array
Returns the item type filters for a given item pile
+
| Param |
| --- |
| target |
-## ItemPiles.API.getItemPileItems(target, [itemTypeFilters]) ⇒ Array
+## getItemPileItems(target, [itemTypeFilters]) ⇒ Array
Returns the items this item pile can transfer
+
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| target | TokenDocument
\| Actor
| | |
@@ -530,29 +433,164 @@ Returns the items this item pile can transfer
-## ItemPiles.API.getItemPileAttributes(target) ⇒ array
+## getItemPileAttributes(target) ⇒ array
Returns the attributes this item pile can transfer
+
| Param | Type |
| --- | --- |
| target | TokenDocument
\| Actor
|
-## ItemPiles.API.refreshItemPile(target) ⇒ Promise
+## refreshItemPile(target) ⇒ Promise
Refreshes the target image of an item pile, ensuring it remains in sync
+
| Param |
| --- |
| target |
-## ItemPiles.API.rerenderItemPileInventoryApplication(inPileUuid, [deleted]) ⇒ Promise
+## rerenderItemPileInventoryApplication(inPileUuid, [deleted]) ⇒ Promise
Causes all connected users to re-render a specific pile's inventory UI
+
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| inPileUuid | string
| | The uuid of the pile to be re-rendered |
| [deleted] | boolean
| false
| Whether the pile was deleted as a part of this re-render |
+
+
+## addItems(target, items, [itemTypeFilters]) ⇒ Promise.<array>
+Adds item to an actor, increasing item quantities if matches were found
+
+**Returns**: Promise.<array>
- An array containing each item added as an object, with their quantities updated to match the new amounts
+
+| Param | Type | Default | Description |
+| --- | --- | --- | --- |
+| target | Actor/TokenDocument/Token
| | The target to add an item to |
+| items | array
| | An array of item objects |
+| [itemTypeFilters] | array/boolean
| false
| Array of item types disallowed - will default to module settings if none provided |
+
+
+
+## removeItems(target, items, [itemTypeFilters]) ⇒ Promise.<array>
+Subtracts the quantity of items on an actor. If the quantity of an item reaches 0, the item is removed from the actor.
+
+**Returns**: Promise.<array>
- An array containing the objects of each item that was removed, with their quantities set to the number removed
+
+| Param | Type | Default | Description |
+| --- | --- | --- | --- |
+| target | Actor/Token/TokenDocument
| | The target to remove a items from |
+| items | array
| | An array of objects each containing the item id (key "_id") and the quantity to remove (key "quantity"), or an array of IDs to remove all quantities of |
+| [itemTypeFilters] | array/boolean
| false
| Array of item types disallowed - will default to module settings if none provided |
+
+
+
+## transferItems(source, target, items, [itemTypeFilters]) ⇒ Promise.<object>
+Transfers items from the source to the target, subtracting a number of quantity from the source's item and adding it to the target's item, deleting items from the source if their quantity reaches 0
+
+**Returns**: Promise.<object>
- An object containing a key value pair for each item added to the target, key being item ID, value being quantities added
+
+| Param | Type | Default | Description |
+| --- | --- | --- | --- |
+| source | Actor/Token/TokenDocument
| | The source to transfer the items from |
+| target | Actor/Token/TokenDocument
| | The target to transfer the items to |
+| items | array
| | An array of objects each containing the item id (key "_id") and the quantity to transfer (key "quantity") |
+| [itemTypeFilters] | array/boolean
| false
| Array of item types disallowed - will default to module settings if none provided |
+
+
+
+## transferAllItems(source, target, [itemTypeFilters]) ⇒ Promise.<array>
+Transfers all items between the source and the target.
+
+**Returns**: Promise.<array>
- An array containing all of the items that were transferred to the target
+
+| Param | Type | Default | Description |
+| --- | --- | --- | --- |
+| source | Actor/Token/TokenDocument
| | The actor to transfer all items from |
+| target | Actor/Token/TokenDocument
| | The actor to receive all the items |
+| [itemTypeFilters] | array/boolean
| false
| Array of item types disallowed - will default to module settings if none provided |
+
+
+
+## addAttributes(target, attributes) ⇒ Promise.<object>
+Adds to attributes on an actor
+
+**Returns**: Promise.<object>
- Returns an array containing a key value pair of the attribute path and the quantity of that attribute that was removed
+
+| Param | Type | Description |
+| --- | --- | --- |
+| target | Actor/Token/TokenDocument
| The target whose attribute will have a set quantity added to it |
+| attributes | object
| An object with each key being an attribute path, and its value being the quantity to add |
+
+
+
+## removeAttributes(target, attributes) ⇒ Promise.<object>
+Subtracts attributes on the target
+
+**Returns**: Promise.<object>
- Returns an array containing a key value pair of the attribute path and the quantity of that attribute that was removed
+
+| Param | Type | Description |
+| --- | --- | --- |
+| target | Token/TokenDocument
| The target whose attributes will be subtracted from |
+| attributes | array/object
| This can be either an array of attributes to subtract (to zero out a given attribute), or an object with each key being an attribute path, and its value being the quantity to subtract |
+
+
+
+## transferAttributes(source, target, attributes) ⇒ Promise.<object>
+Transfers a set quantity of an attribute from a source to a target, removing it or subtracting from the source and adds it the target
+
+**Returns**: Promise.<object>
- An object containing a key value pair of each attribute transferred, the key being the attribute path and its value being the quantity that was transferred
+
+| Param | Type | Description |
+| --- | --- | --- |
+| source | Actor/Token/TokenDocument
| The source to transfer the attribute from |
+| target | Actor/Token/TokenDocument
| The target to transfer the attribute to |
+| attributes | array/object
| This can be either an array of attributes to transfer (to transfer all of a given attribute), or an object with each key being an attribute path, and its value being the quantity to transfer |
+
+
+
+## transferAllAttributes(source, target) ⇒ Promise.<object>
+Transfers all dynamic attributes from a source to a target, removing it or subtracting from the source and adding them to the target
+
+**Returns**: Promise.<object>
- An object containing a key value pair of each attribute transferred, the key being the attribute path and its value being the quantity that was transferred
+
+| Param | Type | Description |
+| --- | --- | --- |
+| source | Actor/Token/TokenDocument
| The source to transfer the attributes from |
+| target | Actor/Token/TokenDocument
| The target to transfer the attributes to |
+
+
+
+## transferEverything(source, target, [itemTypeFilters]) ⇒ Promise.<object>
+Transfers all items and attributes between the source and the target.
+
+**Returns**: Promise.<object>
- An object containing all items and attributes transferred to the target
+
+| Param | Type | Default | Description |
+| --- | --- | --- | --- |
+| source | Actor/Token/TokenDocument
| | The actor to transfer all items and attributes from |
+| target | Actor/Token/TokenDocument
| | The actor to receive all the items and attributes |
+| [itemTypeFilters] | array/boolean
| false
| Array of item types disallowed - will default to module settings if none provided |
+
+
+
+## rerenderTokenHud() ⇒ Promise
+Causes every user's token HUD to rerender
+
+
+
+## isItemTypeDisallowed(item, [itemTypeFilters]) ⇒ boolean/string
+Checks whether an item (or item data) is of a type that is not allowed. If an array whether that type is allowed
+or not, returning the type if it is NOT allowed.
+
+
+| Param | Type | Default |
+| --- | --- | --- |
+| item | Item/Object
| |
+| [itemTypeFilters] | array/boolean
| false
|
+
diff --git a/scripts/api.js b/scripts/api.js
index bb6075de..3f764e53 100644
--- a/scripts/api.js
+++ b/scripts/api.js
@@ -257,720 +257,822 @@ export default class API {
}
/**
- * Transfers items from the source to the target, subtracting a number of quantity from the source's item and adding it to the target's item, deleting items from the source if their quantity reaches 0
+ * Turns a token and its actor into an item pile
*
- * @param {Actor/Token/TokenDocument} source The source to transfer the items from
- * @param {Actor/Token/TokenDocument} target The target to transfer the items to
- * @param {array} items An array of objects each containing the item id (key "_id") and the quantity to transfer (key "quantity")
- * @param {array/boolean} [itemTypeFilters=false] Array of item types disallowed - will default to module settings if none provided
+ * @param {Token/TokenDocument} target The target to be turned into an item pile
+ * @param {object} pileSettings Overriding settings to be put on the item pile's settings
+ * @param {object} tokenSettings Overriding settings that will update the token
*
- * @returns {Promise} An object containing a key value pair for each item added to the target, key being item ID, value being quantities added
+ * @return {Promise} The uuid of the target after it was turned into an item pile
*/
- static async transferItems(source, target, items, { itemTypeFilters = false } = {}) {
-
- const hookResult = Hooks.call(HOOKS.ITEM.PRE_TRANSFER, source, target, items);
+ static async turnTokenIntoItemPile(target, { pileSettings = {}, tokenSettings = {} } = {}) {
+ const hookResult = Hooks.call(HOOKS.PILE.PRE_TURN_INTO, target, pileSettings, tokenSettings);
if (hookResult === false) return;
-
- const sourceUuid = lib.getUuid(source);
- if (!sourceUuid) throw lib.custom_error(`TransferItems | Could not determine the UUID, please provide a valid source`, true)
-
- if (itemTypeFilters) {
- itemTypeFilters.forEach(filter => {
- if (typeof filter !== "string") throw lib.custom_error(`TransferItems | entries in the itemTypeFilters must be of type string`);
- })
- }
-
- const sourceActorItems = API.getItemPileItems(source);
-
- items.forEach(item => {
- const actorItem = sourceActorItems.find(actorItem => actorItem.id === item._id);
- if (!actorItem) {
- throw lib.custom_error(`TransferItems | Could not find item with id "${item._id}" on source "${sourceUuid}"`, true)
- }
- const disallowedType = API.isItemTypeDisallowed(actorItem, itemTypeFilters);
- if (disallowedType) {
- throw lib.custom_error(`TransferItems | Could not transfer item of type "${disallowedType}"`, true)
- }
- });
-
const targetUuid = lib.getUuid(target);
- if (!targetUuid) throw lib.custom_error(`TransferItems | Could not determine the UUID, please provide a valid target`, true)
-
- return itemPileSocket.executeAsGM(SOCKET_HANDLERS.TRANSFER_ITEMS, sourceUuid, targetUuid, items, { itemTypeFilters });
-
+ if (!targetUuid) throw lib.custom_error(`TurnIntoItemPile | Could not determine the UUID, please provide a valid target`, true)
+ return itemPileSocket.executeAsGM(SOCKET_HANDLERS.TURN_INTO_PILE, targetUuid, pileSettings, tokenSettings);
}
/**
* @private
*/
- static async _transferItems(sourceUuid, targetUuid, items, { itemTypeFilters = false, isEverything = false } = {}) {
-
- const itemsRemoved = await API._removeItems(sourceUuid, items, { itemTypeFilters, isTransfer: true });
-
- const itemsAdded = await API._addItems(targetUuid, itemsRemoved, { itemTypeFilters, isTransfer: true });
-
- if (!isEverything) {
+ static async _turnTokenIntoItemPile(targetUuid, pileSettings = {}, tokenSettings = {}) {
- await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.ITEM.TRANSFER, sourceUuid, targetUuid, itemsAdded);
+ const target = await fromUuid(targetUuid);
- const macroData = {
- action: "transferItems",
- source: sourceUuid,
- target: targetUuid,
- itemsAdded: itemsAdded
- };
- await API._executeItemPileMacro(sourceUuid, macroData);
- await API._executeItemPileMacro(targetUuid, macroData);
+ const existingPileSettings = foundry.utils.mergeObject(CONSTANTS.PILE_DEFAULTS, lib.getItemPileData(target));
+ const newPileSettings = foundry.utils.mergeObject(existingPileSettings, pileSettings);
+ newPileSettings.enabled = true;
- const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(sourceUuid);
- await API.rerenderItemPileInventoryApplication(sourceUuid, shouldBeDeleted);
- await API.rerenderItemPileInventoryApplication(targetUuid);
+ await API._updateItemPile(targetUuid, newPileSettings, { tokenSettings });
- if (shouldBeDeleted) {
- await API._deleteItemPile(sourceUuid);
- }
+ setTimeout(API.rerenderTokenHud, 100);
- }
+ await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.PILE.TURN_INTO, targetUuid, newPileSettings);
- return itemsAdded;
+ return targetUuid;
}
/**
- * Subtracts the quantity of items on an actor. If the quantity of an item reaches 0, the item is removed from the actor.
+ * Reverts a token from an item pile into a normal token and actor
*
- * @param {Actor/Token/TokenDocument} target The target to remove a items from
- * @param {array} items An array of objects each containing the item id (key "_id") and the quantity to remove (key "quantity"), or an array of IDs to remove all quantities of
- * @param {array/boolean} [itemTypeFilters=false] Array of item types disallowed - will default to module settings if none provided
+ * @param {Token/TokenDocument} target The target to be reverted from an item pile
+ * @param {object} tokenSettings Overriding settings that will update the token
*
- * @returns {Promise} An array containing the objects of each item that was removed, with their quantities set to the number removed
+ * @return {Promise} The uuid of the target after it was reverted from an item pile
*/
- static async removeItems(target, items, { itemTypeFilters = false } = {}) {
-
- const hookResult = Hooks.call(HOOKS.ITEM.PRE_REMOVE, target, items);
+ static async revertTokenFromItemPile(target, { tokenSettings = {} } = {}) {
+ const hookResult = Hooks.call(HOOKS.PILE.PRE_REVERT_FROM, target, tokenSettings);
if (hookResult === false) return;
-
const targetUuid = lib.getUuid(target);
- if (!targetUuid) throw lib.custom_error(`RemoveItems | Could not determine the UUID, please provide a valid target`, true);
-
- if (itemTypeFilters) {
- itemTypeFilters.forEach(filter => {
- if (typeof filter !== "string") throw lib.custom_error(`RemoveItems | entries in the itemTypeFilters must be of type string`);
- })
- }
-
- const targetActorItems = API.getItemPileItems(target);
-
- items.forEach(item => {
- const itemId = typeof item === "string" ? item : item._id;
- const actorItem = targetActorItems.find(actorItem => actorItem.id === itemId);
- if (!actorItem) {
- throw lib.custom_error(`RemoveItems | Could not find item with id "${itemId}" on target "${targetUuid}"`, true)
- }
- const disallowedType = API.isItemTypeDisallowed(actorItem, itemTypeFilters);
- if (disallowedType) {
- throw lib.custom_error(`RemoveItems | Could not transfer item of type "${disallowedType}"`, true)
- }
- });
-
- return itemPileSocket.executeAsGM(SOCKET_HANDLERS.REMOVE_ITEMS, targetUuid, items);
+ if (!targetUuid) throw lib.custom_error(`RevertFromItemPile | Could not determine the UUID, please provide a valid target`, true)
+ return itemPileSocket.executeAsGM(SOCKET_HANDLERS.REVERT_FROM_PILE, targetUuid, tokenSettings);
}
/**
* @private
*/
- static async _removeItems(targetUuid, items, { isTransfer = false } = {}) {
+ static async _revertTokenFromItemPile(targetUuid, tokenSettings) {
const target = await fromUuid(targetUuid);
- const targetActor = target instanceof TokenDocument
- ? target.actor
- : target;
-
- const itemsRemoved = [];
- const itemsToUpdate = [];
- const itemsToDelete = [];
- for (const item of items) {
- const itemId = typeof item === "string" ? item : item._id;
-
- const actorItem = targetActor.items.get(itemId);
- const removedItem = actorItem.toObject();
-
- const currentQuantity = getProperty(actorItem.data, API.ITEM_QUANTITY_ATTRIBUTE);
-
- const quantityToRemove = getProperty(item, API.ITEM_QUANTITY_ATTRIBUTE) ?? item.quantity ?? currentQuantity;
+ const pileSettings = foundry.utils.mergeObject(CONSTANTS.PILE_DEFAULTS, lib.getItemPileData(target));
- const newQuantity = Math.max(0, currentQuantity - quantityToRemove);
+ pileSettings.enabled = false;
- if (newQuantity >= 1) {
- setProperty(removedItem, API.ITEM_QUANTITY_ATTRIBUTE, quantityToRemove);
- itemsToUpdate.push({ _id: actorItem.id, [API.ITEM_QUANTITY_ATTRIBUTE]: newQuantity });
- } else {
- setProperty(removedItem, API.ITEM_QUANTITY_ATTRIBUTE, currentQuantity);
- itemsToDelete.push(actorItem.id);
- }
+ await API._updateItemPile(targetUuid, pileSettings, { tokenSettings });
- itemsRemoved.push(removedItem);
+ setTimeout(API.rerenderTokenHud, 100);
+ if (target instanceof TokenDocument) {
+ await API.rerenderItemPileInventoryApplication(targetUuid);
}
- await targetActor.updateEmbeddedDocuments("Item", itemsToUpdate);
- await targetActor.deleteEmbeddedDocuments("Item", itemsToDelete);
-
- await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.ITEM.REMOVE, targetUuid, itemsRemoved);
-
- if (!isTransfer) {
-
- const macroData = {
- action: "removeItems",
- target: targetUuid,
- items: itemsRemoved
- };
-
- await API._executeItemPileMacro(targetUuid, macroData);
-
- const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(targetUuid);
+ await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.PILE.REVERT_FROM, targetUuid);
- await API.rerenderItemPileInventoryApplication(targetUuid, shouldBeDeleted);
+ return targetUuid;
- if (shouldBeDeleted) {
- await API._deleteItemPile(targetUuid);
- }
+ }
+ /**
+ * Opens a pile if it is enabled and a container
+ *
+ * @param {Token/TokenDocument} target
+ * @param {Token/TokenDocument/boolean} [interactingToken=false]
+ *
+ * @return {Promise}
+ */
+ static async openItemPile(target, interactingToken = false) {
+ const data = lib.getItemPileData(target);
+ if (!data?.enabled || !data?.isContainer) return false;
+ const wasLocked = data.locked;
+ data.closed = false;
+ data.locked = false;
+ if (wasLocked) {
+ const hookResult = Hooks.call(HOOKS.PILE.PRE_UNLOCK, target, data, interactingToken);
+ if (hookResult === false) return;
}
-
- return itemsRemoved;
-
+ const hookResult = Hooks.call(HOOKS.PILE.PRE_OPEN, target, data, interactingToken);
+ if (hookResult === false) return;
+ if (data.openSound) {
+ AudioHelper.play({ src: data.openSound })
+ }
+ return API.updateItemPile(target, data, { interactingToken });
}
/**
- * Adds item to an actor, increasing item quantities if matches were found
+ * Closes a pile if it is enabled and a container
*
- * @param {Actor/TokenDocument/Token} target The target to add an item to
- * @param {array} items An array of item objects
- * @param {array/boolean} [itemTypeFilters=false] Array of item types disallowed - will default to module settings if none provided
+ * @param {Token/TokenDocument} target Target pile to close
+ * @param {Token/TokenDocument/boolean} [interactingToken=false]
*
- * @returns {Promise} An array containing each item added as an object, with their quantities updated to match the new amounts
+ * @return {Promise}
*/
- static async addItems(target, items, { itemTypeFilters = false } = {}) {
-
- const hookResult = Hooks.call(HOOKS.ITEM.PRE_ADD, target, items);
+ static async closeItemPile(target, interactingToken = false) {
+ const data = lib.getItemPileData(target);
+ if (!data?.enabled || !data?.isContainer) return false;
+ data.closed = true;
+ const hookResult = Hooks.call(HOOKS.PILE.PRE_CLOSE, target, data, interactingToken);
if (hookResult === false) return;
-
- const targetUuid = lib.getUuid(target);
- if (!targetUuid) throw lib.custom_error(`AddItems | Could not determine the UUID, please provide a valid target`, true)
-
- if (itemTypeFilters) {
- itemTypeFilters.forEach(filter => {
- if (typeof filter !== "string") throw lib.custom_error(`AddItem | entries in the itemTypeFilters must be of type string`);
- })
+ if (data.closeSound) {
+ AudioHelper.play({ src: data.closeSound })
}
+ return API.updateItemPile(target, data, interactingToken);
+ }
- for (const index in items) {
- const item = items[index];
- if (item instanceof Item) {
- items[index] = item.toObject();
- }
- const disallowedType = API.isItemTypeDisallowed(item, itemTypeFilters);
- if (disallowedType) {
- throw lib.custom_error(`AddItems | Could not add item of type "${disallowedType}"`, true)
- }
+ /**
+ * Toggles a pile's closed state if it is enabled and a container
+ *
+ * @param {Token/TokenDocument} target Target pile to open or close
+ * @param {Token/TokenDocument/boolean} [interactingToken=false]
+ *
+ * @return {Promise}
+ */
+ static async toggleItemPileClosed(target, interactingToken = false) {
+ const data = lib.getItemPileData(target);
+ if (!data?.enabled || !data?.isContainer) return false;
+ if (data.closed) {
+ await API.openItemPile(target, interactingToken);
+ } else {
+ await API.closeItemPile(target, interactingToken);
}
-
- return itemPileSocket.executeAsGM(SOCKET_HANDLERS.ADD_ITEMS, targetUuid, items);
+ return !data.closed;
}
/**
- * @private
+ * Locks a pile if it is enabled and a container
+ *
+ * @param {Token/TokenDocument} target Target pile to lock
+ * @param {Token/TokenDocument/boolean} [interactingToken=false]
+ *
+ * @return {Promise}
*/
- static async _addItems(targetUuid, items, { isTransfer = false } = {}) {
-
- const target = await fromUuid(targetUuid);
- const targetActor = target instanceof TokenDocument
- ? target.actor
- : target;
-
- const targetActorItems = Array.from(targetActor.items);
-
- const itemsAdded = [];
- const itemsToCreate = [];
- const itemsToUpdate = [];
- for (const itemData of items) {
-
- const item = lib.getSimilarItem(targetActorItems, { itemId: itemData._id, itemName: itemData.name, itemType: itemData.type });
-
- const incomingQuantity = getProperty(itemData, API.ITEM_QUANTITY_ATTRIBUTE) ?? 1;
-
- const itemAdded = item ? item.toObject() : foundry.utils.duplicate(itemData);
-
- if (item) {
- const currentQuantity = getProperty(item.data, API.ITEM_QUANTITY_ATTRIBUTE);
- const newQuantity = currentQuantity + incomingQuantity;
- itemsToUpdate.push({
- "_id": item.id,
- [API.ITEM_QUANTITY_ATTRIBUTE]: newQuantity
- });
-
- const itemAdded = item.toObject();
- setProperty(itemAdded, API.ITEM_QUANTITY_ATTRIBUTE, newQuantity)
- itemsAdded.push(itemAdded);
- } else {
- setProperty(itemAdded, API.ITEM_QUANTITY_ATTRIBUTE, incomingQuantity)
- itemsToCreate.push(itemData);
- }
-
+ static async lockItemPile(target, interactingToken = false) {
+ const data = lib.getItemPileData(target);
+ if (!data?.enabled || !data?.isContainer) return false;
+ const wasClosed = data.closed;
+ data.closed = true;
+ data.locked = true;
+ if (!wasClosed) {
+ const hookResult = Hooks.call(HOOKS.PILE.PRE_CLOSE, target, data, interactingToken);
+ if (hookResult === false) return;
}
+ const hookResult = Hooks.call(HOOKS.PILE.PRE_LOCK, target, data, interactingToken);
+ if (hookResult === false) return;
+ if (data.closeSound && !wasClosed) {
+ AudioHelper.play({ src: data.closeSound })
+ }
+ return API.updateItemPile(target, data, interactingToken);
+ }
- const itemsCreated = await targetActor.createEmbeddedDocuments("Item", itemsToCreate);
- await targetActor.updateEmbeddedDocuments("Item", itemsToUpdate);
-
- itemsCreated.forEach(item => itemsAdded.push(item.toObject()));
-
- await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.ITEM.ADD, targetUuid, itemsAdded);
-
- if (!isTransfer) {
-
- const macroData = {
- action: "addItems",
- target: targetUuid,
- items: itemsAdded
- };
-
- await API._executeItemPileMacro(targetUuid, macroData);
-
- await API.rerenderItemPileInventoryApplication(targetUuid);
+ /**
+ * Unlocks a pile if it is enabled and a container
+ *
+ * @param {Token/TokenDocument} target Target pile to unlock
+ * @param {Token/TokenDocument/boolean} [interactingToken=false]
+ *
+ * @return {Promise}
+ */
+ static async unlockItemPile(target, interactingToken = false) {
+ const data = lib.getItemPileData(target);
+ if (!data?.enabled || !data?.isContainer) return false;
+ data.locked = false;
+ Hooks.call(HOOKS.PILE.PRE_UNLOCK, target, data, interactingToken);
+ return API.updateItemPile(target, data, interactingToken);
+ }
+ /**
+ * Toggles a pile's locked state if it is enabled and a container
+ *
+ * @param {Token/TokenDocument} target Target pile to lock or unlock
+ * @param {Token/TokenDocument/boolean} [interactingToken=false]
+ *
+ * @return {Promise}
+ */
+ static async toggleItemPileLocked(target, interactingToken = false) {
+ const data = lib.getItemPileData(target);
+ if (!data?.enabled || !data?.isContainer) return false;
+ if (data.locked) {
+ return API.unlockItemPile(target, interactingToken);
}
+ return API.lockItemPile(target, interactingToken);
+ }
- return itemsAdded;
+ /**
+ * Causes the item pile to play a sound as it was attempted to be opened, but was locked
+ *
+ * @param {Token/TokenDocument} target
+ *
+ * @return {Promise}
+ */
+ static async rattleItemPile(target) {
+ const data = lib.getItemPileData(target);
+ if (!data?.enabled || !data?.isContainer) return false;
+ if (data.locked && data.lockedSound) {
+ AudioHelper.play({ src: data.lockedSound })
+ }
+ return true;
+ }
+ /**
+ * Whether an item pile is locked. If it is not enabled or not a container, it is always false.
+ *
+ * @param {Token/TokenDocument} target
+ *
+ * @return {boolean}
+ */
+ static isItemPileLocked(target) {
+ const data = lib.getItemPileData(target);
+ if (!data?.enabled || !data?.isContainer) return false;
+ return data.locked;
}
/**
- * Transfers all items between the source and the target.
+ * Whether an item pile is closed. If it is not enabled or not a container, it is always false.
*
- * @param {Actor/Token/TokenDocument} source The actor to transfer all items from
- * @param {Actor/Token/TokenDocument} target The actor to receive all the items
- * @param {array/boolean} [itemTypeFilters=false] Array of item types disallowed - will default to module settings if none provided
+ * @param {Token/TokenDocument} target
*
- * @returns {Promise} An array containing all of the items that were transferred to the target
+ * @return {boolean}
*/
- static async transferAllItems(source, target, { itemTypeFilters = false } = {}) {
+ static isItemPileClosed(target) {
+ const data = lib.getItemPileData(target);
+ if (!data?.enabled || !data?.isContainer) return false;
+ return data.closed;
+ }
- const hookResult = Hooks.call(HOOKS.ITEM.PRE_TRANSFER_ALL, source, target, itemTypeFilters);
- if (hookResult === false) return;
+ /**
+ * Whether an item pile is a container. If it is not enabled, it is always false.
+ *
+ * @param {Token/TokenDocument} target
+ *
+ * @return {boolean}
+ */
+ static isItemPileContainer(target) {
+ const data = lib.getItemPileData(target);
+ return data?.enabled && data?.isContainer;
+ }
- const sourceUuid = lib.getUuid(source);
- if (!sourceUuid) throw lib.custom_error(`TransferAllItems | Could not determine the UUID, please provide a valid source`, true)
+ /**
+ * Updates a pile with new data.
+ *
+ * @param {Token/TokenDocument} target
+ * @param {object} newData
+ * @param {Token/TokenDocument/boolean} [interactingToken=false]
+ * @param {object/boolean} [tokenSettings=false]
+ *
+ * @return {Promise}
+ */
+ static async updateItemPile(target, newData, { interactingToken = false, tokenSettings = false } = {}) {
const targetUuid = lib.getUuid(target);
- if (!targetUuid) throw lib.custom_error(`TransferAllItems | Could not determine the UUID, please provide a valid target`, true)
+ if (!targetUuid) throw lib.custom_error(`updateItemPile | Could not determine the UUID, please provide a valid target`, true);
- if (itemTypeFilters) {
- itemTypeFilters.forEach(filter => {
- if (typeof filter !== "string") throw lib.custom_error(`RevertFromItemPile | entries in the itemTypeFilters must be of type string`);
- })
- }
+ const interactingTokenUuid = interactingToken ? lib.getUuid(interactingToken) : false;
+ if (interactingToken && !interactingTokenUuid) throw lib.custom_error(`updateItemPile | Could not determine the UUID, please provide a valid target`, true);
- return itemPileSocket.executeAsGM(
- SOCKET_HANDLERS.TRANSFER_ALL_ITEMS,
- sourceUuid,
- targetUuid,
- {
- itemTypeFilters
- }
- );
+ const hookResult = Hooks.call(HOOKS.PILE.PRE_UPDATE, target, newData, interactingToken, tokenSettings);
+ if (hookResult === false) return;
+
+ return itemPileSocket.executeAsGM(SOCKET_HANDLERS.UPDATE_PILE, targetUuid, newData, {
+ interactingTokenUuid,
+ tokenSettings
+ })
}
/**
* @private
*/
- static async _transferAllItems(sourceUuid, targetUuid, { itemTypeFilters = false, isEverything = false } = {}) {
-
- const source = await fromUuid(sourceUuid);
- if (!source) throw lib.custom_error(`TransferAllItems | Could not find source with UUID "${sourceUuid}"`, true)
+ static async _updateItemPile(targetUuid, newData, { interactingTokenUuid = false, tokenSettings = false } = {}) {
const target = await fromUuid(targetUuid);
- if (!target) throw lib.custom_error(`TransferAllItems | Could not find target with UUID "${targetUuid}"`, true)
- if (!Array.isArray(itemTypeFilters)) {
- itemTypeFilters = API.ITEM_TYPE_FILTERS;
- } else {
- itemTypeFilters.forEach(filter => {
- if (typeof filter !== "string") throw lib.custom_error(`TransferAllItems | entries in the itemTypeFilters must be of type string`);
- })
+ const oldData = lib.getItemPileData(target);
+
+ const data = foundry.utils.mergeObject(
+ foundry.utils.duplicate(oldData),
+ foundry.utils.duplicate(newData)
+ );
+
+ const diff = foundry.utils.diffObject(oldData, data);
+
+ await lib.wait(25);
+
+ await lib.updateItemPile(target, data, tokenSettings);
+
+ if (data.isEnabled && data.isContainer) {
+ if (diff?.closed === true) {
+ await API._executeItemPileMacro(targetUuid, {
+ action: "closeItemPile",
+ source: interactingTokenUuid,
+ target: targetUuid
+ });
+ }
+ if (diff?.locked === true) {
+ await API._executeItemPileMacro(targetUuid, {
+ action: "lockItemPile",
+ source: interactingTokenUuid,
+ target: targetUuid
+ });
+ }
+ if (diff?.locked === false) {
+ await API._executeItemPileMacro(targetUuid, {
+ action: "unlockItemPile",
+ source: interactingTokenUuid,
+ target: targetUuid
+ });
+ }
+ if (diff?.closed === false) {
+ await API._executeItemPileMacro(targetUuid, {
+ action: "openItemPile",
+ source: interactingTokenUuid,
+ target: targetUuid
+ });
+ }
}
- const itemsToRemove = API.getItemPileItems(target, itemTypeFilters).map(item => item.toObject());
+ return itemPileSocket.executeForEveryone(SOCKET_HANDLERS.UPDATED_PILE, targetUuid, diff, interactingTokenUuid);
+ }
- const itemsRemoved = await API._removeItems(sourceUuid, itemsToRemove, { itemTypeFilters, isTransfer: true });
- const itemsAdded = await API._addItems(targetUuid, itemsRemoved, { itemTypeFilters, isTransfer: true });
+ /**
+ * @private
+ */
+ static async _updatedItemPile(targetUuid, diffData, interactingTokenUuid) {
- if (!isEverything) {
+ const target = await lib.getToken(targetUuid);
- await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.TRANSFER_ALL_ITEMS, HOOKS.ITEM.TRANSFER_ALL, sourceUuid, targetUuid, itemsAdded);
+ const interactingToken = interactingTokenUuid ? await fromUuid(interactingTokenUuid) : false;
- const macroData = {
- action: "transferAllItems",
- source: sourceUuid,
- target: targetUuid,
- items: itemsAdded
- };
- await API._executeItemPileMacro(sourceUuid, macroData);
- await API._executeItemPileMacro(targetUuid, macroData);
+ if (foundry.utils.isObjectEmpty(diffData)) return;
- const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(sourceUuid);
- await API.rerenderItemPileInventoryApplication(sourceUuid, shouldBeDeleted);
- await API.rerenderItemPileInventoryApplication(targetUuid);
+ const data = lib.getItemPileData(target);
- if (shouldBeDeleted) {
- await API._deleteItemPile(sourceUuid);
- }
+ Hooks.callAll(HOOKS.PILE.UPDATE, target, diffData, interactingToken)
+ if (data.isEnabled && data.isContainer) {
+ if (diffData?.closed === true) {
+ Hooks.callAll(HOOKS.PILE.CLOSE, target, interactingToken)
+ }
+ if (diffData?.locked === true) {
+ Hooks.callAll(HOOKS.PILE.LOCK, target, interactingToken)
+ }
+ if (diffData?.locked === false) {
+ Hooks.callAll(HOOKS.PILE.UNLOCK, target, interactingToken)
+ }
+ if (diffData?.closed === false) {
+ Hooks.callAll(HOOKS.PILE.OPEN, target, interactingToken)
+ }
}
-
- return itemsAdded;
}
/**
- * Transfers a set quantity of an attribute from a source to a target, removing it or subtracting from the source and adds it the target
+ * Deletes a pile, calling the relevant hooks.
*
- * @param {Actor/Token/TokenDocument} source The source to transfer the attribute from
- * @param {Actor/Token/TokenDocument} target The target to transfer the attribute to
- * @param {array/object} attributes This can be either an array of attributes to transfer (to transfer all of a given attribute), or an object with each key being an attribute path, and its value being the quantity to transfer
+ * @param {Token/TokenDocument} target
*
- * @returns {Promise} An object containing a key value pair of each attribute transferred, the key being the attribute path and its value being the quantity that was transferred
+ * @return {Promise}
*/
- static async transferAttributes(source, target, attributes) {
-
- const hookResult = Hooks.call(HOOKS.ATTRIBUTE.PRE_TRANSFER, source, target, attributes);
- if (hookResult === false) return;
-
- const sourceUuid = lib.getUuid(source);
- if (!sourceUuid) throw lib.custom_error(`TransferAttributes | Could not determine the UUID, please provide a valid source`, true)
-
+ static async deleteItemPile(target) {
+ if (!API.isValidItemPile(target)) {
+ if (!targetUuid) throw lib.custom_error(`deleteItemPile | This is not an item pile, please provide a valid target`, true);
+ }
const targetUuid = lib.getUuid(target);
- if (!targetUuid) throw lib.custom_error(`TransferAttributes | Could not determine the UUID, please provide a valid target`, true)
+ if (!targetUuid) throw lib.custom_error(`deleteItemPile | Could not determine the UUID, please provide a valid target`, true);
+ if (!targetUuid.includes("Token")) {
+ throw lib.custom_error(`deleteItemPile | Please provide a Token or TokenDocument`, true);
+ }
+ const hookResult = Hooks.call(HOOKS.PILE.PRE_DELETE, target);
+ if (hookResult === false) return;
+ return itemPileSocket.executeAsGM(SOCKET_HANDLERS.DELETE_PILE, targetUuid);
+ }
- const sourceActor = source instanceof TokenDocument
- ? source.actor
- : source;
+ static async _deleteItemPile(targetUuid) {
+ const target = await lib.getToken(targetUuid);
+ return target.delete();
+ }
+ /**
+ * Whether a given document is a valid pile or not
+ *
+ * @param {TokenDocument|Actor} document
+ * @return {boolean}
+ */
+ static isValidItemPile(document) {
+ const documentActor = document instanceof TokenDocument ? document.actor : document;
+ return document && !document.destroyed && documentActor && lib.getItemPileData(document)?.enabled;
+ }
+ /**
+ * Whether the item pile is empty
+ *
+ * @param {TokenDocument|Actor} target
+ * @returns {boolean}
+ */
+ static isItemPileEmpty(target){
const targetActor = target instanceof TokenDocument
? target.actor
: target;
- if (Array.isArray(attributes)) {
- attributes.forEach(attribute => {
- if (typeof attribute !== "string") {
- throw lib.custom_error(`TransferAttributes | Each attribute in the array must be of type string`, true)
- }
- if (!hasProperty(sourceActor.data, attribute)) {
- throw lib.custom_error(`TransferAttributes | Could not find attribute ${attribute} on source's actor with UUID "${targetUuid}"`, true)
- }
- if (!hasProperty(targetActor.data, attribute)) {
- throw lib.custom_error(`TransferAttributes | Could not find attribute ${attribute} on target's actor with UUID "${targetUuid}"`, true)
- }
- });
- } else {
- Object.entries(attributes).forEach(entry => {
- const [attribute, quantity] = entry;
- if (!hasProperty(sourceActor.data, attribute)) {
- throw lib.custom_error(`TransferAttributes | Could not find attribute ${attribute} on source's actor with UUID "${targetUuid}"`, true)
- }
- if (!hasProperty(targetActor.data, attribute)) {
- throw lib.custom_error(`TransferAttributes | Could not find attribute ${attribute} on target's actor with UUID "${targetUuid}"`, true)
- }
- if (!lib.is_real_number(quantity) && quantity > 0) {
- throw lib.custom_error(`TransferAttributes | Attribute "${attribute}" must be of type number and greater than 0`, true)
- }
- });
- }
+ if(!targetActor) return false;
- return itemPileSocket.executeAsGM(SOCKET_HANDLERS.TRANSFER_ATTRIBUTES, sourceUuid, targetUuid, attributes);
+ const hasNoItems = API.getItemPileItems(target).length === 0;
+
+ const attributes = API.getItemPileAttributes(target);
+ const hasEmptyAttributes = attributes.find(attribute => {
+ return hasProperty(targetActor.data, attribute.path) && getProperty(targetActor.data, attribute.path) === 0;
+ })
+ return hasNoItems && hasEmptyAttributes;
+ }
+ /**
+ * Returns the item type filters for a given item pile
+ *
+ * @param target
+ * @returns {Array}
+ */
+ static getItemPileItemTypeFilters(target){
+ if(!API.isValidItemPile(target)) return [];
+ const pileData = lib.getItemPileData(target);
+ return pileData.itemTypeFilters
+ ? pileData.itemTypeFilters.split(',').map(str => str.trim().toLowerCase())
+ : API.ITEM_TYPE_FILTERS;
}
/**
- * @private
+ * Returns the items this item pile can transfer
+ *
+ * @param {TokenDocument|Actor} target
+ * @param {array/boolean} [itemTypeFilters=false] Array of item types disallowed - will default to pile settings or module settings if none provided
+ * @returns {Array}
*/
- static async _transferAttributes(sourceUuid, targetUuid, attributes, { isEverything = false } = {}) {
+ static getItemPileItems(target, itemTypeFilters = false){
- const attributesRemoved = await API._removeAttributes(sourceUuid, attributes, { isTransfer: true });
+ if(!API.isValidItemPile(target)) return [];
- const attributesAdded = await API._addAttributes(targetUuid, attributesRemoved, { isTransfer: true });
+ const pileItemFilters = Array.isArray(itemTypeFilters)
+ ? new Set(itemTypeFilters)
+ : new Set(API.getItemPileItemTypeFilters(target));
- if (!isEverything) {
+ const targetActor = target instanceof TokenDocument
+ ? target.actor
+ : target;
- await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.ATTRIBUTE.TRANSFER, sourceUuid, targetUuid, attributesAdded);
+ return Array.from(targetActor.items).filter(item => {
+ const itemType = getProperty(item.data, API.ITEM_TYPE_ATTRIBUTE);
+ return !pileItemFilters.has(itemType);
+ })
- const macroData = {
- action: "transferAttributes",
- source: sourceUuid,
- target: targetUuid,
- attributes: attributesAdded
- };
- await API._executeItemPileMacro(sourceUuid, macroData);
- await API._executeItemPileMacro(targetUuid, macroData);
+ }
- const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(sourceUuid);
- await API.rerenderItemPileInventoryApplication(sourceUuid, shouldBeDeleted);
- await API.rerenderItemPileInventoryApplication(targetUuid);
+ /**
+ * Returns the attributes this item pile can transfer
+ *
+ * @param {TokenDocument|Actor} target
+ * @returns {array}
+ */
+ static getItemPileAttributes(target){
+ const pileData = lib.getItemPileData(target);
+ return pileData.overrideAttributes || API.DYNAMIC_ATTRIBUTES;
+ }
- if (shouldBeDeleted) {
- await API._deleteItemPile(sourceUuid);
- }
+ /**
+ * Refreshes the target image of an item pile, ensuring it remains in sync
+ *
+ * @param target
+ * @return {Promise}
+ */
+ static async refreshItemPile(target) {
+ if (!API.isValidItemPile(target)) return;
+ const targetUuid = lib.getUuid(target);
+ return itemPileSocket.executeAsGM(SOCKET_HANDLERS.REFRESH_PILE, targetUuid)
+ }
+
+ /**
+ * @private
+ */
+ static async _refreshItemPile(targetUuid) {
+ const targetDocument = await fromUuid(targetUuid);
+ if (!API.isValidItemPile(targetDocument)) return;
+
+ let targets = [targetDocument]
+ if (targetDocument instanceof Actor) {
+ targets = Array.from(canvas.tokens.getDocuments()).filter(token => token.actor === targetDocument);
}
- return attributesAdded
+ return Promise.allSettled(targets.map(_target => {
+ return new Promise(async (resolve) => {
+ const uuid = lib.getUuid(_target);
+ const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(uuid);
+ if (!shouldBeDeleted) {
+ await _target.update({
+ "img": API._getItemPileTokenImage(targetDocument),
+ "scale": API._getItemPileTokenScale(targetDocument),
+ })
+ }
+ resolve();
+ })
+ }));
+ }
+ /**
+ * Causes all connected users to re-render a specific pile's inventory UI
+ *
+ * @param {string} inPileUuid The uuid of the pile to be re-rendered
+ * @param {boolean} [deleted=false] Whether the pile was deleted as a part of this re-render
+ * @return {Promise}
+ */
+ static async rerenderItemPileInventoryApplication(inPileUuid, deleted = false) {
+ return itemPileSocket.executeForEveryone(SOCKET_HANDLERS.RERENDER_PILE_INVENTORY, inPileUuid, deleted);
}
/**
- * Subtracts attributes on the target
+ * @private
+ */
+ static async _rerenderItemPileInventoryApplication(inPileUuid, deleted = false) {
+ return ItemPileInventory.rerenderActiveApp(inPileUuid, deleted);
+ }
+
+ /* --- ITEM AND ATTRIBUTE METHODS --- */
+
+ /**
+ * Adds item to an actor, increasing item quantities if matches were found
*
- * @param {Token/TokenDocument} target The target whose attributes will be subtracted from
- * @param {array/object} attributes This can be either an array of attributes to subtract (to zero out a given attribute), or an object with each key being an attribute path, and its value being the quantity to subtract
+ * @param {Actor/TokenDocument/Token} target The target to add an item to
+ * @param {array} items An array of item objects
+ * @param {array/boolean} [itemTypeFilters=false] Array of item types disallowed - will default to module settings if none provided
*
- * @returns {Promise} Returns an array containing a key value pair of the attribute path and the quantity of that attribute that was removed
+ * @returns {Promise} An array containing each item added as an object, with their quantities updated to match the new amounts
*/
- static async removeAttributes(target, attributes) {
+ static async addItems(target, items, { itemTypeFilters = false } = {}) {
- const hookResult = Hooks.call(HOOKS.ATTRIBUTE.PRE_REMOVE, target, attributes);
+ const hookResult = Hooks.call(HOOKS.ITEM.PRE_ADD, target, items);
if (hookResult === false) return;
const targetUuid = lib.getUuid(target);
- if (!targetUuid) throw lib.custom_error(`RemoveAttributes | Could not determine the UUID, please provide a valid target`, true)
-
- const targetActor = target instanceof TokenDocument
- ? target.actor
- : target;
+ if (!targetUuid) throw lib.custom_error(`AddItems | Could not determine the UUID, please provide a valid target`, true)
- if (Array.isArray(attributes)) {
- attributes.forEach(attribute => {
- if (typeof attribute !== "string") {
- throw lib.custom_error(`RemoveAttributes | Each attribute in the array must be of type string`, true)
- }
- if (!hasProperty(targetActor.data, attribute)) {
- throw lib.custom_error(`RemoveAttributes | Could not find attribute ${attribute} on target's actor with UUID "${targetUuid}"`, true)
- }
- });
- } else {
- Object.entries(attributes).forEach(entry => {
- const [attribute, quantity] = entry;
- if (!hasProperty(targetActor.data, attribute)) {
- throw lib.custom_error(`RemoveAttributes | Could not find attribute ${attribute} on target's actor with UUID "${targetUuid}"`, true)
- }
- if (!lib.is_real_number(quantity) && quantity > 0) {
- throw lib.custom_error(`RemoveAttributes | Attribute "${attribute}" must be of type number and greater than 0`, true)
- }
- });
+ if (itemTypeFilters) {
+ itemTypeFilters.forEach(filter => {
+ if (typeof filter !== "string") throw lib.custom_error(`AddItem | entries in the itemTypeFilters must be of type string`);
+ })
}
- return itemPileSocket.executeAsGM(SOCKET_HANDLERS.REMOVE_ATTRIBUTES, targetUuid, attributes);
+ for (const index in items) {
+ const item = items[index];
+ if (item instanceof Item) {
+ items[index] = item.toObject();
+ }
+ const disallowedType = API.isItemTypeDisallowed(item, itemTypeFilters);
+ if (disallowedType) {
+ throw lib.custom_error(`AddItems | Could not add item of type "${disallowedType}"`, true)
+ }
+ }
+ return itemPileSocket.executeAsGM(SOCKET_HANDLERS.ADD_ITEMS, targetUuid, items);
}
/**
* @private
*/
- static async _removeAttributes(targetUuid, attributes, { isTransfer = false } = {}) {
+ static async _addItems(targetUuid, items, { isTransfer = false } = {}) {
const target = await fromUuid(targetUuid);
const targetActor = target instanceof TokenDocument
? target.actor
: target;
- const updates = {};
- const attributesRemoved = {};
+ const targetActorItems = Array.from(targetActor.items);
- if (Array.isArray(attributes)) {
- attributes = Object.fromEntries(attributes.map(attribute => {
- return [attribute, getProperty(targetActor.data, attribute)];
- }))
- }
+ const itemsAdded = [];
+ const itemsToCreate = [];
+ const itemsToUpdate = [];
+ for (const itemData of items) {
- for (const [attribute, quantityToRemove] of Object.entries(attributes)) {
+ const item = lib.getSimilarItem(targetActorItems, { itemId: itemData._id, itemName: itemData.name, itemType: itemData.type });
- const currentQuantity = getProperty(targetActor.data, attribute);
- const newQuantity = Math.max(0, currentQuantity - quantityToRemove);
+ const incomingQuantity = getProperty(itemData, API.ITEM_QUANTITY_ATTRIBUTE) ?? 1;
- updates[attribute] = newQuantity;
+ const itemAdded = item ? item.toObject() : foundry.utils.duplicate(itemData);
+
+ if (item) {
+ const currentQuantity = getProperty(item.data, API.ITEM_QUANTITY_ATTRIBUTE);
+ const newQuantity = currentQuantity + incomingQuantity;
+ itemsToUpdate.push({
+ "_id": item.id,
+ [API.ITEM_QUANTITY_ATTRIBUTE]: newQuantity
+ });
+
+ const itemAdded = item.toObject();
+ setProperty(itemAdded, API.ITEM_QUANTITY_ATTRIBUTE, newQuantity)
+ itemsAdded.push(itemAdded);
+ } else {
+ setProperty(itemAdded, API.ITEM_QUANTITY_ATTRIBUTE, incomingQuantity)
+ itemsToCreate.push(itemData);
+ }
- // if the target's quantity is above 1, we've removed the amount we expected, otherwise however many were left
- attributesRemoved[attribute] = newQuantity ? quantityToRemove : currentQuantity;
}
- await targetActor.update(updates);
+ const itemsCreated = await targetActor.createEmbeddedDocuments("Item", itemsToCreate);
+ await targetActor.updateEmbeddedDocuments("Item", itemsToUpdate);
- await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.ATTRIBUTE.REMOVE, targetUuid, attributesRemoved);
+ itemsCreated.forEach(item => itemsAdded.push(item.toObject()));
+
+ await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.ITEM.ADD, targetUuid, itemsAdded);
if (!isTransfer) {
const macroData = {
- action: "removeAttributes",
+ action: "addItems",
target: targetUuid,
- attributes: attributesRemoved
+ items: itemsAdded
};
+
await API._executeItemPileMacro(targetUuid, macroData);
- const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(targetUuid);
- await API.rerenderItemPileInventoryApplication(targetUuid, shouldBeDeleted);
+ await API.rerenderItemPileInventoryApplication(targetUuid);
- if (shouldBeDeleted) {
- await API._deleteItemPile(targetUuid);
- }
}
- return attributesRemoved;
+ return itemsAdded;
}
/**
- * Adds to attributes on an actor
- *
- * @param {Actor/Token/TokenDocument} target The target whose attribute will have a set quantity added to it
- * @param {object} attributes An object with each key being an attribute path, and its value being the quantity to add
+ * Subtracts the quantity of items on an actor. If the quantity of an item reaches 0, the item is removed from the actor.
*
- * @returns {Promise} Returns an array containing a key value pair of the attribute path and the quantity of that attribute that was removed
+ * @param {Actor/Token/TokenDocument} target The target to remove a items from
+ * @param {array} items An array of objects each containing the item id (key "_id") and the quantity to remove (key "quantity"), or an array of IDs to remove all quantities of
+ * @param {array/boolean} [itemTypeFilters=false] Array of item types disallowed - will default to module settings if none provided
*
+ * @returns {Promise} An array containing the objects of each item that was removed, with their quantities set to the number removed
*/
- static async addAttributes(target, attributes) {
+ static async removeItems(target, items, { itemTypeFilters = false } = {}) {
- const hookResult = Hooks.call(HOOKS.ATTRIBUTE.PRE_ADD, target, attributes);
+ const hookResult = Hooks.call(HOOKS.ITEM.PRE_REMOVE, target, items);
if (hookResult === false) return;
const targetUuid = lib.getUuid(target);
- if (!targetUuid) throw lib.custom_error(`AddAttributes | Could not determine the UUID, please provide a valid target`, true)
+ if (!targetUuid) throw lib.custom_error(`RemoveItems | Could not determine the UUID, please provide a valid target`, true);
- const targetActor = target instanceof TokenDocument
- ? target.actor
- : target;
+ if (itemTypeFilters) {
+ itemTypeFilters.forEach(filter => {
+ if (typeof filter !== "string") throw lib.custom_error(`RemoveItems | entries in the itemTypeFilters must be of type string`);
+ })
+ }
- Object.entries(attributes).forEach(entry => {
- const [attribute, quantity] = entry;
- if (!hasProperty(targetActor.data, attribute)) {
- throw lib.custom_error(`AddAttributes | Could not find attribute ${attribute} on target's actor with UUID "${targetUuid}"`, true)
+ const targetActorItems = API.getItemPileItems(target);
+
+ items.forEach(item => {
+ const itemId = typeof item === "string" ? item : item._id;
+ const actorItem = targetActorItems.find(actorItem => actorItem.id === itemId);
+ if (!actorItem) {
+ throw lib.custom_error(`RemoveItems | Could not find item with id "${itemId}" on target "${targetUuid}"`, true)
}
- if (!lib.is_real_number(quantity) && quantity > 0) {
- throw lib.custom_error(`AddAttributes | Attribute "${attribute}" must be of type number and greater than 0`, true)
+ const disallowedType = API.isItemTypeDisallowed(actorItem, itemTypeFilters);
+ if (disallowedType) {
+ throw lib.custom_error(`RemoveItems | Could not transfer item of type "${disallowedType}"`, true)
}
});
- return itemPileSocket.executeAsGM(SOCKET_HANDLERS.ADD_ATTRIBUTE, targetUuid, attributes);
-
+ return itemPileSocket.executeAsGM(SOCKET_HANDLERS.REMOVE_ITEMS, targetUuid, items);
}
/**
* @private
*/
- static async _addAttributes(targetUuid, attributes, { isTransfer = false } = {}) {
+ static async _removeItems(targetUuid, items, { isTransfer = false } = {}) {
const target = await fromUuid(targetUuid);
const targetActor = target instanceof TokenDocument
? target.actor
: target;
- const updates = {};
- const attributesAdded = {};
+ const itemsRemoved = [];
+ const itemsToUpdate = [];
+ const itemsToDelete = [];
+ for (const item of items) {
- for (const [attribute, quantityToAdd] of Object.entries(attributes)) {
+ const itemId = typeof item === "string" ? item : item._id;
- const currentQuantity = getProperty(targetActor.data, attribute);
+ const actorItem = targetActor.items.get(itemId);
+ const removedItem = actorItem.toObject();
- updates[attribute] = currentQuantity + quantityToAdd;
- attributesAdded[attribute] = currentQuantity + quantityToAdd;
+ const currentQuantity = getProperty(actorItem.data, API.ITEM_QUANTITY_ATTRIBUTE);
+
+ const quantityToRemove = getProperty(item, API.ITEM_QUANTITY_ATTRIBUTE) ?? item.quantity ?? currentQuantity;
+
+ const newQuantity = Math.max(0, currentQuantity - quantityToRemove);
+
+ if (newQuantity >= 1) {
+ setProperty(removedItem, API.ITEM_QUANTITY_ATTRIBUTE, quantityToRemove);
+ itemsToUpdate.push({ _id: actorItem.id, [API.ITEM_QUANTITY_ATTRIBUTE]: newQuantity });
+ } else {
+ setProperty(removedItem, API.ITEM_QUANTITY_ATTRIBUTE, currentQuantity);
+ itemsToDelete.push(actorItem.id);
+ }
+
+ itemsRemoved.push(removedItem);
}
- await targetActor.update(updates);
+ await targetActor.updateEmbeddedDocuments("Item", itemsToUpdate);
+ await targetActor.deleteEmbeddedDocuments("Item", itemsToDelete);
- await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.ATTRIBUTE.ADD, targetUuid, attributesAdded);
+ await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.ITEM.REMOVE, targetUuid, itemsRemoved);
- if (isTransfer) {
+ if (!isTransfer) {
const macroData = {
- action: "addAttributes",
+ action: "removeItems",
target: targetUuid,
- attributes: attributesAdded
+ items: itemsRemoved
};
+
await API._executeItemPileMacro(targetUuid, macroData);
- await API.rerenderItemPileInventoryApplication(targetUuid);
+ const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(targetUuid);
+
+ await API.rerenderItemPileInventoryApplication(targetUuid, shouldBeDeleted);
+
+ if (shouldBeDeleted) {
+ await API._deleteItemPile(targetUuid);
+ }
+
}
- return attributesAdded;
+ return itemsRemoved;
}
-
/**
- * Transfers all dynamic attributes from a source to a target, removing it or subtracting from the source and adding them to the target
+ * Transfers items from the source to the target, subtracting a number of quantity from the source's item and adding it to the target's item, deleting items from the source if their quantity reaches 0
*
- * @param {Actor/Token/TokenDocument} source The source to transfer the attributes from
- * @param {Actor/Token/TokenDocument} target The target to transfer the attributes to
+ * @param {Actor/Token/TokenDocument} source The source to transfer the items from
+ * @param {Actor/Token/TokenDocument} target The target to transfer the items to
+ * @param {array} items An array of objects each containing the item id (key "_id") and the quantity to transfer (key "quantity")
+ * @param {array/boolean} [itemTypeFilters=false] Array of item types disallowed - will default to module settings if none provided
*
- * @returns {Promise} An object containing a key value pair of each attribute transferred, the key being the attribute path and its value being the quantity that was transferred
+ * @returns {Promise} An object containing a key value pair for each item added to the target, key being item ID, value being quantities added
*/
- static async transferAllAttributes(source, target) {
+ static async transferItems(source, target, items, { itemTypeFilters = false } = {}) {
- const hookResult = Hooks.call(HOOKS.ATTRIBUTE.PRE_TRANSFER_ALL, source, target);
+ const hookResult = Hooks.call(HOOKS.ITEM.PRE_TRANSFER, source, target, items);
if (hookResult === false) return;
const sourceUuid = lib.getUuid(source);
- if (!sourceUuid) throw lib.custom_error(`TransferAllAttributes | Could not determine the UUID, please provide a valid source`, true);
+ if (!sourceUuid) throw lib.custom_error(`TransferItems | Could not determine the UUID, please provide a valid source`, true)
+
+ if (itemTypeFilters) {
+ itemTypeFilters.forEach(filter => {
+ if (typeof filter !== "string") throw lib.custom_error(`TransferItems | entries in the itemTypeFilters must be of type string`);
+ })
+ }
+
+ const sourceActorItems = API.getItemPileItems(source);
+
+ items.forEach(item => {
+ const actorItem = sourceActorItems.find(actorItem => actorItem.id === item._id);
+ if (!actorItem) {
+ throw lib.custom_error(`TransferItems | Could not find item with id "${item._id}" on source "${sourceUuid}"`, true)
+ }
+ const disallowedType = API.isItemTypeDisallowed(actorItem, itemTypeFilters);
+ if (disallowedType) {
+ throw lib.custom_error(`TransferItems | Could not transfer item of type "${disallowedType}"`, true)
+ }
+ });
const targetUuid = lib.getUuid(target);
- if (!targetUuid) throw lib.custom_error(`TransferAllAttributes | Could not determine the UUID, please provide a valid target`, true);
+ if (!targetUuid) throw lib.custom_error(`TransferItems | Could not determine the UUID, please provide a valid target`, true)
- return itemPileSocket.executeAsGM(SOCKET_HANDLERS.TRANSFER_ALL_ATTRIBUTES, sourceUuid, targetUuid);
+ return itemPileSocket.executeAsGM(SOCKET_HANDLERS.TRANSFER_ITEMS, sourceUuid, targetUuid, items, { itemTypeFilters });
}
/**
* @private
*/
- static async _transferAllAttributes(sourceUuid, targetUuid, { isEverything = false } = {}) {
-
- const source = await fromUuid(sourceUuid);
-
- const sourceActor = source instanceof TokenDocument
- ? source.actor
- : source;
-
- const target = await fromUuid(targetUuid);
-
- const targetActor = target instanceof TokenDocument
- ? target.actor
- : target;
-
- const sourceAttributes = API.getItemPileAttributes(sourceActor);
-
- const attributesToTransfer = sourceAttributes.filter(attribute => {
- return hasProperty(sourceActor.data, attribute.path)
- && getProperty(sourceActor.data, attribute.path) > 0
- && hasProperty(targetActor.data, attribute.path);
- }).map(attribute => attribute.path);
+ static async _transferItems(sourceUuid, targetUuid, items, { itemTypeFilters = false, isEverything = false } = {}) {
- const attributesRemoved = await API._removeAttributes(sourceUuid, attributesToTransfer, { isTransfer: true });
- const attributesAdded = await API._addAttributes(targetUuid, attributesRemoved, { isTransfer: true });
+ const itemsRemoved = await API._removeItems(sourceUuid, items, { itemTypeFilters, isTransfer: true });
- await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.ATTRIBUTE.TRANSFER_ALL, sourceUuid, targetUuid, attributesAdded);
+ const itemsAdded = await API._addItems(targetUuid, itemsRemoved, { itemTypeFilters, isTransfer: true });
if (!isEverything) {
+ await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.ITEM.TRANSFER, sourceUuid, targetUuid, itemsAdded);
+
const macroData = {
- action: "transferAllAttributes",
+ action: "transferItems",
source: sourceUuid,
target: targetUuid,
- attributes: attributesAdded
+ itemsAdded: itemsAdded
};
await API._executeItemPileMacro(sourceUuid, macroData);
await API._executeItemPileMacro(targetUuid, macroData);
const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(sourceUuid);
await API.rerenderItemPileInventoryApplication(sourceUuid, shouldBeDeleted);
+ await API.rerenderItemPileInventoryApplication(targetUuid);
if (shouldBeDeleted) {
await API._deleteItemPile(sourceUuid);
@@ -978,651 +1080,549 @@ export default class API {
}
- return attributesAdded;
+ return itemsAdded;
}
/**
- * Transfers all items and attributes between the source and the target.
+ * Transfers all items between the source and the target.
*
- * @param {Actor/Token/TokenDocument} source The actor to transfer all items and attributes from
- * @param {Actor/Token/TokenDocument} target The actor to receive all the items and attributes
+ * @param {Actor/Token/TokenDocument} source The actor to transfer all items from
+ * @param {Actor/Token/TokenDocument} target The actor to receive all the items
* @param {array/boolean} [itemTypeFilters=false] Array of item types disallowed - will default to module settings if none provided
*
- * @returns {Promise} An object containing all items and attributes transferred to the target
+ * @returns {Promise} An array containing all of the items that were transferred to the target
*/
- static async transferEverything(source, target, { itemTypeFilters = false } = {}) {
+ static async transferAllItems(source, target, { itemTypeFilters = false } = {}) {
- const hookResult = Hooks.call(HOOKS.PRE_TRANSFER_EVERYTHING, source, target, itemTypeFilters);
+ const hookResult = Hooks.call(HOOKS.ITEM.PRE_TRANSFER_ALL, source, target, itemTypeFilters);
if (hookResult === false) return;
const sourceUuid = lib.getUuid(source);
- if (!sourceUuid) throw lib.custom_error(`TransferEverything | Could not determine the UUID, please provide a valid source`, true)
+ if (!sourceUuid) throw lib.custom_error(`TransferAllItems | Could not determine the UUID, please provide a valid source`, true)
const targetUuid = lib.getUuid(target);
- if (!targetUuid) throw lib.custom_error(`TransferEverything | Could not determine the UUID, please provide a valid target`, true)
+ if (!targetUuid) throw lib.custom_error(`TransferAllItems | Could not determine the UUID, please provide a valid target`, true)
if (itemTypeFilters) {
itemTypeFilters.forEach(filter => {
- if (typeof filter !== "string") throw lib.custom_error(`TransferEverything | entries in the itemTypeFilters must be of type string`);
+ if (typeof filter !== "string") throw lib.custom_error(`RevertFromItemPile | entries in the itemTypeFilters must be of type string`);
})
}
- return itemPileSocket.executeAsGM(SOCKET_HANDLERS.TRANSFER_EVERYTHING, sourceUuid, targetUuid, { itemTypeFilters })
-
- }
-
- /**
- * @private
- */
- static async _transferEverything(sourceUuid, targetUuid, { itemTypeFilters = false } = {}) {
-
- const itemsTransferred = await API._transferAllItems(sourceUuid, targetUuid, {
- itemTypeFilters,
- isEverything: true
- });
- const attributesTransferred = await API._transferAllAttributes(sourceUuid, targetUuid, { isEverything: true });
-
- await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.TRANSFER_EVERYTHING, sourceUuid, targetUuid, itemsTransferred, attributesTransferred);
-
- const macroData = {
- action: "transferEverything",
- source: sourceUuid,
- target: targetUuid,
- items: itemsTransferred,
- attributes: attributesTransferred
- };
- await API._executeItemPileMacro(sourceUuid, macroData);
- await API._executeItemPileMacro(targetUuid, macroData);
-
- const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(sourceUuid);
- await API.rerenderItemPileInventoryApplication(sourceUuid, shouldBeDeleted);
- await API.rerenderItemPileInventoryApplication(targetUuid);
-
- if (shouldBeDeleted) {
- await API._deleteItemPile(sourceUuid);
- }
-
- return {
- itemsTransferred,
- attributesTransferred
- };
-
- }
-
- /**
- * Turns a token and its actor into an item pile
- *
- * @param {Token/TokenDocument} target The target to be turned into an item pile
- * @param {object} pileSettings Overriding settings to be put on the item pile's settings
- * @param {object} tokenSettings Overriding settings that will update the token
- *
- * @return {Promise} The uuid of the target after it was turned into an item pile
- */
- static async turnTokenIntoItemPile(target, { pileSettings = {}, tokenSettings = {} } = {}) {
- const hookResult = Hooks.call(HOOKS.PILE.PRE_TURN_INTO, target, pileSettings, tokenSettings);
- if (hookResult === false) return;
- const targetUuid = lib.getUuid(target);
- if (!targetUuid) throw lib.custom_error(`TurnIntoItemPile | Could not determine the UUID, please provide a valid target`, true)
- return itemPileSocket.executeAsGM(SOCKET_HANDLERS.TURN_INTO_PILE, targetUuid, pileSettings, tokenSettings);
- }
-
- /**
- * @private
- */
- static async _turnTokenIntoItemPile(targetUuid, pileSettings = {}, tokenSettings = {}) {
-
- const target = await fromUuid(targetUuid);
-
- const existingPileSettings = foundry.utils.mergeObject(CONSTANTS.PILE_DEFAULTS, lib.getItemPileData(target));
- const newPileSettings = foundry.utils.mergeObject(existingPileSettings, pileSettings);
- newPileSettings.enabled = true;
-
- await API._updateItemPile(targetUuid, newPileSettings, { tokenSettings });
-
- setTimeout(API.rerenderTokenHud, 100);
-
- await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.PILE.TURN_INTO, targetUuid, newPileSettings);
-
- return targetUuid;
-
- }
-
- /**
- * Reverts a token from an item pile into a normal token and actor
- *
- * @param {Token/TokenDocument} target The target to be reverted from an item pile
- * @param {object} tokenSettings Overriding settings that will update the token
- *
- * @return {Promise} The uuid of the target after it was reverted from an item pile
- */
- static async revertTokenFromItemPile(target, { tokenSettings = {} } = {}) {
- const hookResult = Hooks.call(HOOKS.PILE.PRE_REVERT_FROM, target, tokenSettings);
- if (hookResult === false) return;
- const targetUuid = lib.getUuid(target);
- if (!targetUuid) throw lib.custom_error(`RevertFromItemPile | Could not determine the UUID, please provide a valid target`, true)
- return itemPileSocket.executeAsGM(SOCKET_HANDLERS.REVERT_FROM_PILE, targetUuid, tokenSettings);
+ return itemPileSocket.executeAsGM(
+ SOCKET_HANDLERS.TRANSFER_ALL_ITEMS,
+ sourceUuid,
+ targetUuid,
+ {
+ itemTypeFilters
+ }
+ );
}
/**
* @private
*/
- static async _revertTokenFromItemPile(targetUuid, tokenSettings) {
+ static async _transferAllItems(sourceUuid, targetUuid, { itemTypeFilters = false, isEverything = false } = {}) {
+
+ const source = await fromUuid(sourceUuid);
+ if (!source) throw lib.custom_error(`TransferAllItems | Could not find source with UUID "${sourceUuid}"`, true)
const target = await fromUuid(targetUuid);
+ if (!target) throw lib.custom_error(`TransferAllItems | Could not find target with UUID "${targetUuid}"`, true)
- const pileSettings = foundry.utils.mergeObject(CONSTANTS.PILE_DEFAULTS, lib.getItemPileData(target));
+ if (!Array.isArray(itemTypeFilters)) {
+ itemTypeFilters = API.ITEM_TYPE_FILTERS;
+ } else {
+ itemTypeFilters.forEach(filter => {
+ if (typeof filter !== "string") throw lib.custom_error(`TransferAllItems | entries in the itemTypeFilters must be of type string`);
+ })
+ }
- pileSettings.enabled = false;
+ const itemsToRemove = API.getItemPileItems(target, itemTypeFilters).map(item => item.toObject());
- await API._updateItemPile(targetUuid, pileSettings, { tokenSettings });
+ const itemsRemoved = await API._removeItems(sourceUuid, itemsToRemove, { itemTypeFilters, isTransfer: true });
+ const itemsAdded = await API._addItems(targetUuid, itemsRemoved, { itemTypeFilters, isTransfer: true });
- setTimeout(API.rerenderTokenHud, 100);
+ if (!isEverything) {
- if (target instanceof TokenDocument) {
- await API.rerenderItemPileInventoryApplication(targetUuid);
- }
+ await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.TRANSFER_ALL_ITEMS, HOOKS.ITEM.TRANSFER_ALL, sourceUuid, targetUuid, itemsAdded);
- await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.PILE.REVERT_FROM, targetUuid);
+ const macroData = {
+ action: "transferAllItems",
+ source: sourceUuid,
+ target: targetUuid,
+ items: itemsAdded
+ };
+ await API._executeItemPileMacro(sourceUuid, macroData);
+ await API._executeItemPileMacro(targetUuid, macroData);
- return targetUuid;
+ const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(sourceUuid);
+ await API.rerenderItemPileInventoryApplication(sourceUuid, shouldBeDeleted);
+ await API.rerenderItemPileInventoryApplication(targetUuid);
- }
+ if (shouldBeDeleted) {
+ await API._deleteItemPile(sourceUuid);
+ }
- /**
- * Causes every user's token HUD to rerender
- *
- * @return {Promise}
- */
- static async rerenderTokenHud() {
- return itemPileSocket.executeForEveryone(SOCKET_HANDLERS.RERENDER_TOKEN_HUD);
- }
+ }
- /**
- * @private
- */
- static async _rerenderTokenHud() {
- if (!canvas.tokens.hud.rendered) return;
- await canvas.tokens.hud.render(true)
- return true;
+ return itemsAdded;
}
/**
- * Opens a pile if it is enabled and a container
- *
- * @param {Token/TokenDocument} target
- * @param {Token/TokenDocument/boolean} [interactingToken=false]
+ * Adds to attributes on an actor
*
- * @return {Promise}
- */
- static async openItemPile(target, interactingToken = false) {
- const data = lib.getItemPileData(target);
- if (!data?.enabled || !data?.isContainer) return false;
- const wasLocked = data.locked;
- data.closed = false;
- data.locked = false;
- if (wasLocked) {
- const hookResult = Hooks.call(HOOKS.PILE.PRE_UNLOCK, target, data, interactingToken);
- if (hookResult === false) return;
- }
- const hookResult = Hooks.call(HOOKS.PILE.PRE_OPEN, target, data, interactingToken);
- if (hookResult === false) return;
- if (data.openSound) {
- AudioHelper.play({ src: data.openSound })
- }
- return API.updateItemPile(target, data, { interactingToken });
- }
-
- /**
- * Closes a pile if it is enabled and a container
+ * @param {Actor/Token/TokenDocument} target The target whose attribute will have a set quantity added to it
+ * @param {object} attributes An object with each key being an attribute path, and its value being the quantity to add
*
- * @param {Token/TokenDocument} target Target pile to close
- * @param {Token/TokenDocument/boolean} [interactingToken=false]
+ * @returns {Promise} Returns an array containing a key value pair of the attribute path and the quantity of that attribute that was removed
*
- * @return {Promise}
*/
- static async closeItemPile(target, interactingToken = false) {
- const data = lib.getItemPileData(target);
- if (!data?.enabled || !data?.isContainer) return false;
- data.closed = true;
- const hookResult = Hooks.call(HOOKS.PILE.PRE_CLOSE, target, data, interactingToken);
+ static async addAttributes(target, attributes) {
+
+ const hookResult = Hooks.call(HOOKS.ATTRIBUTE.PRE_ADD, target, attributes);
if (hookResult === false) return;
- if (data.closeSound) {
- AudioHelper.play({ src: data.closeSound })
- }
- return API.updateItemPile(target, data, interactingToken);
- }
- /**
- * Toggles a pile's closed state if it is enabled and a container
- *
- * @param {Token/TokenDocument} target Target pile to open or close
- * @param {Token/TokenDocument/boolean} [interactingToken=false]
- *
- * @return {Promise}
- */
- static async toggleItemPileClosed(target, interactingToken = false) {
- const data = lib.getItemPileData(target);
- if (!data?.enabled || !data?.isContainer) return false;
- if (data.closed) {
- await API.openItemPile(target, interactingToken);
- } else {
- await API.closeItemPile(target, interactingToken);
- }
- return !data.closed;
- }
+ const targetUuid = lib.getUuid(target);
+ if (!targetUuid) throw lib.custom_error(`AddAttributes | Could not determine the UUID, please provide a valid target`, true)
- /**
- * Locks a pile if it is enabled and a container
- *
- * @param {Token/TokenDocument} target Target pile to lock
- * @param {Token/TokenDocument/boolean} [interactingToken=false]
- *
- * @return {Promise}
- */
- static async lockItemPile(target, interactingToken = false) {
- const data = lib.getItemPileData(target);
- if (!data?.enabled || !data?.isContainer) return false;
- const wasClosed = data.closed;
- data.closed = true;
- data.locked = true;
- if (!wasClosed) {
- const hookResult = Hooks.call(HOOKS.PILE.PRE_CLOSE, target, data, interactingToken);
- if (hookResult === false) return;
- }
- const hookResult = Hooks.call(HOOKS.PILE.PRE_LOCK, target, data, interactingToken);
- if (hookResult === false) return;
- if (data.closeSound && !wasClosed) {
- AudioHelper.play({ src: data.closeSound })
- }
- return API.updateItemPile(target, data, interactingToken);
- }
+ const targetActor = target instanceof TokenDocument
+ ? target.actor
+ : target;
- /**
- * Unlocks a pile if it is enabled and a container
- *
- * @param {Token/TokenDocument} target Target pile to unlock
- * @param {Token/TokenDocument/boolean} [interactingToken=false]
- *
- * @return {Promise}
- */
- static async unlockItemPile(target, interactingToken = false) {
- const data = lib.getItemPileData(target);
- if (!data?.enabled || !data?.isContainer) return false;
- data.locked = false;
- Hooks.call(HOOKS.PILE.PRE_UNLOCK, target, data, interactingToken);
- return API.updateItemPile(target, data, interactingToken);
- }
+ Object.entries(attributes).forEach(entry => {
+ const [attribute, quantity] = entry;
+ if (!hasProperty(targetActor.data, attribute)) {
+ throw lib.custom_error(`AddAttributes | Could not find attribute ${attribute} on target's actor with UUID "${targetUuid}"`, true)
+ }
+ if (!lib.is_real_number(quantity) && quantity > 0) {
+ throw lib.custom_error(`AddAttributes | Attribute "${attribute}" must be of type number and greater than 0`, true)
+ }
+ });
+
+ return itemPileSocket.executeAsGM(SOCKET_HANDLERS.ADD_ATTRIBUTE, targetUuid, attributes);
- /**
- * Toggles a pile's locked state if it is enabled and a container
- *
- * @param {Token/TokenDocument} target Target pile to lock or unlock
- * @param {Token/TokenDocument/boolean} [interactingToken=false]
- *
- * @return {Promise}
- */
- static async toggleItemPileLocked(target, interactingToken = false) {
- const data = lib.getItemPileData(target);
- if (!data?.enabled || !data?.isContainer) return false;
- if (data.locked) {
- return API.unlockItemPile(target, interactingToken);
- }
- return API.lockItemPile(target, interactingToken);
}
/**
- * Causes the item pile to play a sound as it was attempted to be opened, but was locked
- *
- * @param {Token/TokenDocument} target
- *
- * @return {Promise}
+ * @private
*/
- static async rattleItemPile(target) {
- const data = lib.getItemPileData(target);
- if (!data?.enabled || !data?.isContainer) return false;
- if (data.locked && data.lockedSound) {
- AudioHelper.play({ src: data.lockedSound })
+ static async _addAttributes(targetUuid, attributes, { isTransfer = false } = {}) {
+
+ const target = await fromUuid(targetUuid);
+ const targetActor = target instanceof TokenDocument
+ ? target.actor
+ : target;
+
+ const updates = {};
+ const attributesAdded = {};
+
+ for (const [attribute, quantityToAdd] of Object.entries(attributes)) {
+
+ const currentQuantity = getProperty(targetActor.data, attribute);
+
+ updates[attribute] = currentQuantity + quantityToAdd;
+ attributesAdded[attribute] = currentQuantity + quantityToAdd;
+
}
- return true;
- }
- /**
- * Whether an item pile is locked. If it is not enabled or not a container, it is always false.
- *
- * @param {Token/TokenDocument} target
- *
- * @return {boolean}
- */
- static isItemPileLocked(target) {
- const data = lib.getItemPileData(target);
- if (!data?.enabled || !data?.isContainer) return false;
- return data.locked;
- }
+ await targetActor.update(updates);
+
+ await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.ATTRIBUTE.ADD, targetUuid, attributesAdded);
+
+ if (isTransfer) {
+
+ const macroData = {
+ action: "addAttributes",
+ target: targetUuid,
+ attributes: attributesAdded
+ };
+ await API._executeItemPileMacro(targetUuid, macroData);
+
+ await API.rerenderItemPileInventoryApplication(targetUuid);
+ }
- /**
- * Whether an item pile is closed. If it is not enabled or not a container, it is always false.
- *
- * @param {Token/TokenDocument} target
- *
- * @return {boolean}
- */
- static isItemPileClosed(target) {
- const data = lib.getItemPileData(target);
- if (!data?.enabled || !data?.isContainer) return false;
- return data.closed;
- }
+ return attributesAdded;
- /**
- * Whether an item pile is a container. If it is not enabled, it is always false.
- *
- * @param {Token/TokenDocument} target
- *
- * @return {boolean}
- */
- static isItemPileContainer(target) {
- const data = lib.getItemPileData(target);
- return data?.enabled && data?.isContainer;
}
/**
- * Updates a pile with new data.
+ * Subtracts attributes on the target
*
- * @param {Token/TokenDocument} target
- * @param {object} newData
- * @param {Token/TokenDocument/boolean} [interactingToken=false]
- * @param {object/boolean} [tokenSettings=false]
+ * @param {Token/TokenDocument} target The target whose attributes will be subtracted from
+ * @param {array/object} attributes This can be either an array of attributes to subtract (to zero out a given attribute), or an object with each key being an attribute path, and its value being the quantity to subtract
*
- * @return {Promise}
+ * @returns {Promise} Returns an array containing a key value pair of the attribute path and the quantity of that attribute that was removed
*/
- static async updateItemPile(target, newData, { interactingToken = false, tokenSettings = false } = {}) {
+ static async removeAttributes(target, attributes) {
+
+ const hookResult = Hooks.call(HOOKS.ATTRIBUTE.PRE_REMOVE, target, attributes);
+ if (hookResult === false) return;
const targetUuid = lib.getUuid(target);
- if (!targetUuid) throw lib.custom_error(`updateItemPile | Could not determine the UUID, please provide a valid target`, true);
+ if (!targetUuid) throw lib.custom_error(`RemoveAttributes | Could not determine the UUID, please provide a valid target`, true)
- const interactingTokenUuid = interactingToken ? lib.getUuid(interactingToken) : false;
- if (interactingToken && !interactingTokenUuid) throw lib.custom_error(`updateItemPile | Could not determine the UUID, please provide a valid target`, true);
+ const targetActor = target instanceof TokenDocument
+ ? target.actor
+ : target;
- const hookResult = Hooks.call(HOOKS.PILE.PRE_UPDATE, target, newData, interactingToken, tokenSettings);
- if (hookResult === false) return;
+ if (Array.isArray(attributes)) {
+ attributes.forEach(attribute => {
+ if (typeof attribute !== "string") {
+ throw lib.custom_error(`RemoveAttributes | Each attribute in the array must be of type string`, true)
+ }
+ if (!hasProperty(targetActor.data, attribute)) {
+ throw lib.custom_error(`RemoveAttributes | Could not find attribute ${attribute} on target's actor with UUID "${targetUuid}"`, true)
+ }
+ });
+ } else {
+ Object.entries(attributes).forEach(entry => {
+ const [attribute, quantity] = entry;
+ if (!hasProperty(targetActor.data, attribute)) {
+ throw lib.custom_error(`RemoveAttributes | Could not find attribute ${attribute} on target's actor with UUID "${targetUuid}"`, true)
+ }
+ if (!lib.is_real_number(quantity) && quantity > 0) {
+ throw lib.custom_error(`RemoveAttributes | Attribute "${attribute}" must be of type number and greater than 0`, true)
+ }
+ });
+ }
+
+ return itemPileSocket.executeAsGM(SOCKET_HANDLERS.REMOVE_ATTRIBUTES, targetUuid, attributes);
- return itemPileSocket.executeAsGM(SOCKET_HANDLERS.UPDATE_PILE, targetUuid, newData, {
- interactingTokenUuid,
- tokenSettings
- })
}
/**
* @private
*/
- static async _updateItemPile(targetUuid, newData, { interactingTokenUuid = false, tokenSettings = false } = {}) {
+ static async _removeAttributes(targetUuid, attributes, { isTransfer = false } = {}) {
const target = await fromUuid(targetUuid);
+ const targetActor = target instanceof TokenDocument
+ ? target.actor
+ : target;
- const oldData = lib.getItemPileData(target);
+ const updates = {};
+ const attributesRemoved = {};
- const data = foundry.utils.mergeObject(
- foundry.utils.duplicate(oldData),
- foundry.utils.duplicate(newData)
- );
+ if (Array.isArray(attributes)) {
+ attributes = Object.fromEntries(attributes.map(attribute => {
+ return [attribute, getProperty(targetActor.data, attribute)];
+ }))
+ }
- const diff = foundry.utils.diffObject(oldData, data);
+ for (const [attribute, quantityToRemove] of Object.entries(attributes)) {
- await lib.wait(25);
+ const currentQuantity = getProperty(targetActor.data, attribute);
+ const newQuantity = Math.max(0, currentQuantity - quantityToRemove);
- await lib.updateItemPile(target, data, tokenSettings);
+ updates[attribute] = newQuantity;
- if (data.isEnabled && data.isContainer) {
- if (diff?.closed === true) {
- await API._executeItemPileMacro(targetUuid, {
- action: "closeItemPile",
- source: interactingTokenUuid,
- target: targetUuid
- });
- }
- if (diff?.locked === true) {
- await API._executeItemPileMacro(targetUuid, {
- action: "lockItemPile",
- source: interactingTokenUuid,
- target: targetUuid
- });
- }
- if (diff?.locked === false) {
- await API._executeItemPileMacro(targetUuid, {
- action: "unlockItemPile",
- source: interactingTokenUuid,
- target: targetUuid
- });
- }
- if (diff?.closed === false) {
- await API._executeItemPileMacro(targetUuid, {
- action: "openItemPile",
- source: interactingTokenUuid,
- target: targetUuid
- });
- }
+ // if the target's quantity is above 1, we've removed the amount we expected, otherwise however many were left
+ attributesRemoved[attribute] = newQuantity ? quantityToRemove : currentQuantity;
}
- return itemPileSocket.executeForEveryone(SOCKET_HANDLERS.UPDATED_PILE, targetUuid, diff, interactingTokenUuid);
- }
-
- /**
- * @private
- */
- static async _updatedItemPile(targetUuid, diffData, interactingTokenUuid) {
-
- const target = await lib.getToken(targetUuid);
+ await targetActor.update(updates);
- const interactingToken = interactingTokenUuid ? await fromUuid(interactingTokenUuid) : false;
+ await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.ATTRIBUTE.REMOVE, targetUuid, attributesRemoved);
- if (foundry.utils.isObjectEmpty(diffData)) return;
+ if (!isTransfer) {
- const data = lib.getItemPileData(target);
+ const macroData = {
+ action: "removeAttributes",
+ target: targetUuid,
+ attributes: attributesRemoved
+ };
+ await API._executeItemPileMacro(targetUuid, macroData);
- Hooks.callAll(HOOKS.PILE.UPDATE, target, diffData, interactingToken)
+ const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(targetUuid);
+ await API.rerenderItemPileInventoryApplication(targetUuid, shouldBeDeleted);
- if (data.isEnabled && data.isContainer) {
- if (diffData?.closed === true) {
- Hooks.callAll(HOOKS.PILE.CLOSE, target, interactingToken)
- }
- if (diffData?.locked === true) {
- Hooks.callAll(HOOKS.PILE.LOCK, target, interactingToken)
- }
- if (diffData?.locked === false) {
- Hooks.callAll(HOOKS.PILE.UNLOCK, target, interactingToken)
- }
- if (diffData?.closed === false) {
- Hooks.callAll(HOOKS.PILE.OPEN, target, interactingToken)
+ if (shouldBeDeleted) {
+ await API._deleteItemPile(targetUuid);
}
}
+
+ return attributesRemoved;
+
}
/**
- * Deletes a pile, calling the relevant hooks.
+ * Transfers a set quantity of an attribute from a source to a target, removing it or subtracting from the source and adds it the target
*
- * @param {Token/TokenDocument} target
+ * @param {Actor/Token/TokenDocument} source The source to transfer the attribute from
+ * @param {Actor/Token/TokenDocument} target The target to transfer the attribute to
+ * @param {array/object} attributes This can be either an array of attributes to transfer (to transfer all of a given attribute), or an object with each key being an attribute path, and its value being the quantity to transfer
*
- * @return {Promise}
+ * @returns {Promise} An object containing a key value pair of each attribute transferred, the key being the attribute path and its value being the quantity that was transferred
*/
- static async deleteItemPile(target) {
- if (!API.isValidItemPile(target)) {
- if (!targetUuid) throw lib.custom_error(`deleteItemPile | This is not an item pile, please provide a valid target`, true);
- }
+ static async transferAttributes(source, target, attributes) {
+
+ const hookResult = Hooks.call(HOOKS.ATTRIBUTE.PRE_TRANSFER, source, target, attributes);
+ if (hookResult === false) return;
+
+ const sourceUuid = lib.getUuid(source);
+ if (!sourceUuid) throw lib.custom_error(`TransferAttributes | Could not determine the UUID, please provide a valid source`, true)
+
const targetUuid = lib.getUuid(target);
- if (!targetUuid) throw lib.custom_error(`deleteItemPile | Could not determine the UUID, please provide a valid target`, true);
- if (!targetUuid.includes("Token")) {
- throw lib.custom_error(`deleteItemPile | Please provide a Token or TokenDocument`, true);
+ if (!targetUuid) throw lib.custom_error(`TransferAttributes | Could not determine the UUID, please provide a valid target`, true)
+
+ const sourceActor = source instanceof TokenDocument
+ ? source.actor
+ : source;
+
+ const targetActor = target instanceof TokenDocument
+ ? target.actor
+ : target;
+
+ if (Array.isArray(attributes)) {
+ attributes.forEach(attribute => {
+ if (typeof attribute !== "string") {
+ throw lib.custom_error(`TransferAttributes | Each attribute in the array must be of type string`, true)
+ }
+ if (!hasProperty(sourceActor.data, attribute)) {
+ throw lib.custom_error(`TransferAttributes | Could not find attribute ${attribute} on source's actor with UUID "${targetUuid}"`, true)
+ }
+ if (!hasProperty(targetActor.data, attribute)) {
+ throw lib.custom_error(`TransferAttributes | Could not find attribute ${attribute} on target's actor with UUID "${targetUuid}"`, true)
+ }
+ });
+ } else {
+ Object.entries(attributes).forEach(entry => {
+ const [attribute, quantity] = entry;
+ if (!hasProperty(sourceActor.data, attribute)) {
+ throw lib.custom_error(`TransferAttributes | Could not find attribute ${attribute} on source's actor with UUID "${targetUuid}"`, true)
+ }
+ if (!hasProperty(targetActor.data, attribute)) {
+ throw lib.custom_error(`TransferAttributes | Could not find attribute ${attribute} on target's actor with UUID "${targetUuid}"`, true)
+ }
+ if (!lib.is_real_number(quantity) && quantity > 0) {
+ throw lib.custom_error(`TransferAttributes | Attribute "${attribute}" must be of type number and greater than 0`, true)
+ }
+ });
}
- const hookResult = Hooks.call(HOOKS.PILE.PRE_DELETE, target);
- if (hookResult === false) return;
- return itemPileSocket.executeAsGM(SOCKET_HANDLERS.DELETE_PILE, targetUuid);
+
+ return itemPileSocket.executeAsGM(SOCKET_HANDLERS.TRANSFER_ATTRIBUTES, sourceUuid, targetUuid, attributes);
+
}
- static async _deleteItemPile(targetUuid) {
- const target = await lib.getToken(targetUuid);
- return target.delete();
- }
+ /**
+ * @private
+ */
+ static async _transferAttributes(sourceUuid, targetUuid, attributes, { isEverything = false } = {}) {
+
+ const attributesRemoved = await API._removeAttributes(sourceUuid, attributes, { isTransfer: true });
+
+ const attributesAdded = await API._addAttributes(targetUuid, attributesRemoved, { isTransfer: true });
+
+ if (!isEverything) {
+
+ await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.ATTRIBUTE.TRANSFER, sourceUuid, targetUuid, attributesAdded);
+
+ const macroData = {
+ action: "transferAttributes",
+ source: sourceUuid,
+ target: targetUuid,
+ attributes: attributesAdded
+ };
+ await API._executeItemPileMacro(sourceUuid, macroData);
+ await API._executeItemPileMacro(targetUuid, macroData);
+
+ const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(sourceUuid);
+ await API.rerenderItemPileInventoryApplication(sourceUuid, shouldBeDeleted);
+ await API.rerenderItemPileInventoryApplication(targetUuid);
- /* -------- UTILITY METHODS -------- */
+ if (shouldBeDeleted) {
+ await API._deleteItemPile(sourceUuid);
+ }
- /**
- * Checks whether an item (or item data) is of a type that is not allowed. If an array whether that type is allowed
- * or not, returning the type if it is NOT allowed.
- *
- * @param {Item/Object} item
- * @param {array/boolean} [itemTypeFilters=false]
- * @return {boolean/string}
- */
- static isItemTypeDisallowed(item, itemTypeFilters = false) {
- if (!API.ITEM_TYPE_ATTRIBUTE) return false;
- if (!Array.isArray(itemTypeFilters)) itemTypeFilters = API.ITEM_TYPE_FILTERS;
- const itemType = getProperty(item, API.ITEM_TYPE_ATTRIBUTE);
- if (itemTypeFilters.includes(itemType)) {
- return itemType;
}
- return false;
- }
- /**
- * Whether a given document is a valid pile or not
- *
- * @param {TokenDocument|Actor} document
- * @return {boolean}
- */
- static isValidItemPile(document) {
- const documentActor = document instanceof TokenDocument ? document.actor : document;
- return document && !document.destroyed && documentActor && lib.getItemPileData(document)?.enabled;
+ return attributesAdded
+
}
/**
- * Whether the item pile is empty
+ * Transfers all dynamic attributes from a source to a target, removing it or subtracting from the source and adding them to the target
*
- * @param {TokenDocument|Actor} target
- * @returns {boolean}
+ * @param {Actor/Token/TokenDocument} source The source to transfer the attributes from
+ * @param {Actor/Token/TokenDocument} target The target to transfer the attributes to
+ *
+ * @returns {Promise} An object containing a key value pair of each attribute transferred, the key being the attribute path and its value being the quantity that was transferred
*/
- static isItemPileEmpty(target){
- const targetActor = target instanceof TokenDocument
- ? target.actor
- : target;
+ static async transferAllAttributes(source, target) {
- if(!targetActor) return false;
+ const hookResult = Hooks.call(HOOKS.ATTRIBUTE.PRE_TRANSFER_ALL, source, target);
+ if (hookResult === false) return;
- const hasNoItems = API.getItemPileItems(target).length === 0;
+ const sourceUuid = lib.getUuid(source);
+ if (!sourceUuid) throw lib.custom_error(`TransferAllAttributes | Could not determine the UUID, please provide a valid source`, true);
- const attributes = API.getItemPileAttributes(target);
- const hasEmptyAttributes = attributes.find(attribute => {
- return hasProperty(targetActor.data, attribute.path) && getProperty(targetActor.data, attribute.path) === 0;
- })
- return hasNoItems && hasEmptyAttributes;
- }
+ const targetUuid = lib.getUuid(target);
+ if (!targetUuid) throw lib.custom_error(`TransferAllAttributes | Could not determine the UUID, please provide a valid target`, true);
+
+ return itemPileSocket.executeAsGM(SOCKET_HANDLERS.TRANSFER_ALL_ATTRIBUTES, sourceUuid, targetUuid);
- /**
- * Returns the item type filters for a given item pile
- *
- * @param target
- * @returns {Array}
- */
- static getItemPileItemTypeFilters(target){
- if(!API.isValidItemPile(target)) return [];
- const pileData = lib.getItemPileData(target);
- return pileData.itemTypeFilters
- ? pileData.itemTypeFilters.split(',').map(str => str.trim().toLowerCase())
- : API.ITEM_TYPE_FILTERS;
}
/**
- * Returns the items this item pile can transfer
- *
- * @param {TokenDocument|Actor} target
- * @param {array/boolean} [itemTypeFilters=false] Array of item types disallowed - will default to pile settings or module settings if none provided
- * @returns {Array}
+ * @private
*/
- static getItemPileItems(target, itemTypeFilters = false){
+ static async _transferAllAttributes(sourceUuid, targetUuid, { isEverything = false } = {}) {
- if(!API.isValidItemPile(target)) return [];
+ const source = await fromUuid(sourceUuid);
- const pileItemFilters = Array.isArray(itemTypeFilters)
- ? new Set(itemTypeFilters)
- : new Set(API.getItemPileItemTypeFilters(target));
+ const sourceActor = source instanceof TokenDocument
+ ? source.actor
+ : source;
+
+ const target = await fromUuid(targetUuid);
const targetActor = target instanceof TokenDocument
? target.actor
: target;
- return Array.from(targetActor.items).filter(item => {
- const itemType = getProperty(item.data, API.ITEM_TYPE_ATTRIBUTE);
- return !pileItemFilters.has(itemType);
- })
+ const sourceAttributes = API.getItemPileAttributes(sourceActor);
- }
+ const attributesToTransfer = sourceAttributes.filter(attribute => {
+ return hasProperty(sourceActor.data, attribute.path)
+ && getProperty(sourceActor.data, attribute.path) > 0
+ && hasProperty(targetActor.data, attribute.path);
+ }).map(attribute => attribute.path);
+
+ const attributesRemoved = await API._removeAttributes(sourceUuid, attributesToTransfer, { isTransfer: true });
+ const attributesAdded = await API._addAttributes(targetUuid, attributesRemoved, { isTransfer: true });
+
+ await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.ATTRIBUTE.TRANSFER_ALL, sourceUuid, targetUuid, attributesAdded);
+
+ if (!isEverything) {
+
+ const macroData = {
+ action: "transferAllAttributes",
+ source: sourceUuid,
+ target: targetUuid,
+ attributes: attributesAdded
+ };
+ await API._executeItemPileMacro(sourceUuid, macroData);
+ await API._executeItemPileMacro(targetUuid, macroData);
+
+ const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(sourceUuid);
+ await API.rerenderItemPileInventoryApplication(sourceUuid, shouldBeDeleted);
+
+ if (shouldBeDeleted) {
+ await API._deleteItemPile(sourceUuid);
+ }
+
+ }
+
+ return attributesAdded;
- /**
- * Returns the attributes this item pile can transfer
- *
- * @param {TokenDocument|Actor} target
- * @returns {array}
- */
- static getItemPileAttributes(target){
- const pileData = lib.getItemPileData(target);
- return pileData.overrideAttributes || API.DYNAMIC_ATTRIBUTES;
}
/**
- * Refreshes the target image of an item pile, ensuring it remains in sync
+ * Transfers all items and attributes between the source and the target.
*
- * @param target
- * @return {Promise}
+ * @param {Actor/Token/TokenDocument} source The actor to transfer all items and attributes from
+ * @param {Actor/Token/TokenDocument} target The actor to receive all the items and attributes
+ * @param {array/boolean} [itemTypeFilters=false] Array of item types disallowed - will default to module settings if none provided
+ *
+ * @returns {Promise} An object containing all items and attributes transferred to the target
*/
- static async refreshItemPile(target) {
- if (!API.isValidItemPile(target)) return;
+ static async transferEverything(source, target, { itemTypeFilters = false } = {}) {
+
+ const hookResult = Hooks.call(HOOKS.PRE_TRANSFER_EVERYTHING, source, target, itemTypeFilters);
+ if (hookResult === false) return;
+
+ const sourceUuid = lib.getUuid(source);
+ if (!sourceUuid) throw lib.custom_error(`TransferEverything | Could not determine the UUID, please provide a valid source`, true)
+
const targetUuid = lib.getUuid(target);
- return itemPileSocket.executeAsGM(SOCKET_HANDLERS.REFRESH_PILE, targetUuid)
+ if (!targetUuid) throw lib.custom_error(`TransferEverything | Could not determine the UUID, please provide a valid target`, true)
+
+ if (itemTypeFilters) {
+ itemTypeFilters.forEach(filter => {
+ if (typeof filter !== "string") throw lib.custom_error(`TransferEverything | entries in the itemTypeFilters must be of type string`);
+ })
+ }
+
+ return itemPileSocket.executeAsGM(SOCKET_HANDLERS.TRANSFER_EVERYTHING, sourceUuid, targetUuid, { itemTypeFilters })
+
}
/**
* @private
*/
- static async _refreshItemPile(targetUuid) {
- const targetDocument = await fromUuid(targetUuid);
+ static async _transferEverything(sourceUuid, targetUuid, { itemTypeFilters = false } = {}) {
- if (!API.isValidItemPile(targetDocument)) return;
+ const itemsTransferred = await API._transferAllItems(sourceUuid, targetUuid, {
+ itemTypeFilters,
+ isEverything: true
+ });
+ const attributesTransferred = await API._transferAllAttributes(sourceUuid, targetUuid, { isEverything: true });
- let targets = [targetDocument]
- if (targetDocument instanceof Actor) {
- targets = Array.from(canvas.tokens.getDocuments()).filter(token => token.actor === targetDocument);
+ await itemPileSocket.executeForEveryone(SOCKET_HANDLERS.CALL_HOOK, HOOKS.TRANSFER_EVERYTHING, sourceUuid, targetUuid, itemsTransferred, attributesTransferred);
+
+ const macroData = {
+ action: "transferEverything",
+ source: sourceUuid,
+ target: targetUuid,
+ items: itemsTransferred,
+ attributes: attributesTransferred
+ };
+ await API._executeItemPileMacro(sourceUuid, macroData);
+ await API._executeItemPileMacro(targetUuid, macroData);
+
+ const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(sourceUuid);
+ await API.rerenderItemPileInventoryApplication(sourceUuid, shouldBeDeleted);
+ await API.rerenderItemPileInventoryApplication(targetUuid);
+
+ if (shouldBeDeleted) {
+ await API._deleteItemPile(sourceUuid);
}
- return Promise.allSettled(targets.map(_target => {
- return new Promise(async (resolve) => {
- const uuid = lib.getUuid(_target);
- const shouldBeDeleted = await API._checkItemPileShouldBeDeleted(uuid);
- if (!shouldBeDeleted) {
- await _target.update({
- "img": API._getItemPileTokenImage(targetDocument),
- "scale": API._getItemPileTokenScale(targetDocument),
- })
- }
- resolve();
- })
- }));
+ return {
+ itemsTransferred,
+ attributesTransferred
+ };
+
}
+ /* -------- UTILITY METHODS -------- */
+
/**
- * Causes all connected users to re-render a specific pile's inventory UI
+ * Causes every user's token HUD to rerender
*
- * @param {string} inPileUuid The uuid of the pile to be re-rendered
- * @param {boolean} [deleted=false] Whether the pile was deleted as a part of this re-render
* @return {Promise}
*/
- static async rerenderItemPileInventoryApplication(inPileUuid, deleted = false) {
- return itemPileSocket.executeForEveryone(SOCKET_HANDLERS.RERENDER_PILE_INVENTORY, inPileUuid, deleted);
+ static async rerenderTokenHud() {
+ return itemPileSocket.executeForEveryone(SOCKET_HANDLERS.RERENDER_TOKEN_HUD);
}
/**
* @private
*/
- static async _rerenderItemPileInventoryApplication(inPileUuid, deleted = false) {
- return ItemPileInventory.rerenderActiveApp(inPileUuid, deleted);
+ static async _rerenderTokenHud() {
+ if (!canvas.tokens.hud.rendered) return;
+ await canvas.tokens.hud.render(true)
+ return true;
+ }
+
+ /**
+ * Checks whether an item (or item data) is of a type that is not allowed. If an array whether that type is allowed
+ * or not, returning the type if it is NOT allowed.
+ *
+ * @param {Item/Object} item
+ * @param {array/boolean} [itemTypeFilters=false]
+ * @return {boolean/string}
+ */
+ static isItemTypeDisallowed(item, itemTypeFilters = false) {
+ if (!API.ITEM_TYPE_ATTRIBUTE) return false;
+ if (!Array.isArray(itemTypeFilters)) itemTypeFilters = API.ITEM_TYPE_FILTERS;
+ const itemType = getProperty(item, API.ITEM_TYPE_ATTRIBUTE);
+ if (itemTypeFilters.includes(itemType)) {
+ return itemType;
+ }
+ return false;
}
/* -------- PRIVATE ITEM PILE METHODS -------- */
diff --git a/scripts/module.js b/scripts/module.js
index b915765d..00f93b53 100644
--- a/scripts/module.js
+++ b/scripts/module.js
@@ -58,7 +58,6 @@ Hooks.once("ready", () => {
throw lib.custom_error(`Item Piles requires the 'socketlib' module. Please ${word} it.`)
}
checkSystem();
- checkIncompatibilities();
registerHotkeys();
Hooks.callAll(HOOKS.READY);
})
diff --git a/scripts/settings.js b/scripts/settings.js
index a6f22d7c..ddc4c138 100644
--- a/scripts/settings.js
+++ b/scripts/settings.js
@@ -214,21 +214,4 @@ export async function checkSystem(){
applyDefaultSettings();
}
-}
-
-export async function checkIncompatibilities(){
-
-
- if(game.settings.get('monks-active-tiles', 'drop-item') && !game.settings.get(CONSTANTS.MODULE_NAME, 'monksActiveTilesDropItemWarning')){
- await Dialog.prompt({
- title: "Module Incompatibility",
- content: lib.dialogWarning(`The module "Monks Active Tile Triggers" has a setting called "Drop Item on Canvas", which when enabled creates a tile when an item is dropped on the canvas. This clashes with Item Piles, and it is recommended you turn this setting off.`),
- label: "OK",
- callback: () => {
- game.settings.set(CONSTANTS.MODULE_NAME, 'monksActiveTilesDropItemWarning', true)
- }
- });
- }
-
-
}
\ No newline at end of file