diff --git a/docs/api.md b/docs/api.md index 27115e7a..dc251beb 100644 --- a/docs/api.md +++ b/docs/api.md @@ -46,6 +46,7 @@ * [isItemPileVault](#isItemPileVault) * [isItemPileMerchant](#isItemPileMerchant) * [isItemPileAuctioneer](#isItemPileAuctioneer) + * [isItemPileBanker](#isItemPileBanker) * [isItemPileEmpty](#isItemPileEmpty) * [updateItemPile](#updateItemPile) * [deleteItemPile](#deleteItemPile) @@ -633,6 +634,19 @@ Whether an item pile is a auctioneer. If it is not enabled, it is always false. --- +### isItemPileBanker + +`game.itempiles.API.isItemPileBanker(target)` ⇒ `boolean` + +Whether an item pile is a banker. If it is not enabled, it is always false. + +| Param | Type | Default | Description | +|--------------------|-------------------------------|---------|-------------------------------| +| target | `Token/TokenDocument` | | Target token to check | +| [data] | `Object/boolean` | `false` | Existing data flags to use | + +--- + ### isItemPileEmpty `game.itempiles.API.isItemPileEmpty(target)` ⇒ `boolean` @@ -766,11 +780,12 @@ Refreshes the merchant's inventory, potentially removing existing items and popu **Returns**: `Promise>` - An array of object containing the item data and their quantity -| Param | Type | Default | Description | -|------------------------------------|------------------------------------|---------|--------------------------------------------------------------------------------| -| target | `Actor/TokenDocument/Token/String` | | The merchant actor to refresh the inventory of | -| options | `object` | | Options to pass to the function | -| [options.removeExistingActorItems] | `boolean` | `true` | Whether to clear the merchant's existing inventory before adding the new items | +| Param | Type | Default | Description | +|-------------------------------------|------------------------------------|---------|--------------------------------------------------------------------------------| +| target | `Actor/TokenDocument/Token/String` | | The merchant actor to refresh the inventory of | +| options | `object` | | Options to pass to the function | +| [options.removeExistingActorItems] | `boolean` | `true` | Whether to clear the merchant's existing inventory before adding the new items | +| [options.ignoreCheckItemPilesType] | `boolean` | `false` | Populate this target with the same roll tables set on the merchant settings, but on a actor/token with item piles disabled. This is useful for as a alternative for populate NPC on the canvas | --- diff --git a/languages/en.json b/languages/en.json index c852bb00..de16111e 100644 --- a/languages/en.json +++ b/languages/en.json @@ -37,7 +37,9 @@ "DropNoToken": "You don't have a token on this scene, so you can't drop any items here.", "NoVaultAccess": "You don't have permission to view this vault.", "NoVaultAccessActor": "{actor_name} doesn't have permission to view this vault.", - "ItemNoQuantity": "{item_name} has 0 quantity, so you can't transfer this item!" + "ItemNoQuantity": "{item_name} has 0 quantity, so you can't transfer this item!", + "NoRollTableAndNoActorIsPresent": "No actor or any tables is present", + "NoRollTableIsPresent": "No tables is been set on the actor {actorName}" }, "Warnings": { "NoGMsConnected": "WARNING - No GMs connected - Item Piles requires a GM to be connected for players to be able to utilize most of the module's features.", @@ -555,6 +557,10 @@ "DeleteWhenEmptyDefault": "Default module setting", "DeleteWhenEmptyYes": "Yes, delete when empty", "DeleteWhenEmptyNo": "No, don't delete when empty", + "OnCreateTokenRollTable": "Refresh the inventory on the token when created", + "OnCreateTokenRollTableExplanation": "With this setting, when the actor token is created on the canvas it will refresh the inventory on the token based on some rollTable. NOTE: You must set at least have one roll table set , and if the actor is set to be a merchant by default all the old items are removed so be aware...", + "OnCreateTokenRollTableNoMerchant": "Refresh the inventory on the token when created even if is not a enabled items piles", + "OnCreateTokenRollTableExplanationNoMerchant": "With this setting, the effect of the setting 'Refresh the inventory on the token when created' is been applied even if this is not a item piles.", "CanStackItems": "Can Stack Items", "CanStackItemsExplanation": "With this setting, items added to the item pile will stack with similar items. This can also be controlled per-item in their configuration. Note: This is dependent on the system as well, since some items do not have quantity so they can never be stacked.", "CanStackItemsYes": "Yes, stack items (unless item says otherwise)", diff --git a/package-lock.json b/package-lock.json index 44c8b459..94717f47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,6 @@ "dependencies": { "@typhonjs-fvtt/runtime": "^0.0.23", "@typhonjs-fvtt/svelte-standard": "^0.0.23", - "svelecte": "^3.17.2", "svelte": "^3.57.0", "svelte-select": "^5.7.0" }, @@ -6483,14 +6482,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/svelecte": { - "version": "3.17.2", - "resolved": "https://registry.npmjs.org/svelecte/-/svelecte-3.17.2.tgz", - "integrity": "sha512-dKm50Em11f4DNP3UMI+6oGUBHSrPWDOVsuG44T+2f/Vh/RVJYWjdTGJy87BfetDRTHKmuGMiwaGmMBh58tHmGg==", - "dependencies": { - "svelte-tiny-virtual-list": "^2.0.0" - } - }, "node_modules/svelte": { "version": "3.59.2", "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz", @@ -6609,11 +6600,6 @@ "svelte-floating-ui": "1.2.8" } }, - "node_modules/svelte-tiny-virtual-list": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/svelte-tiny-virtual-list/-/svelte-tiny-virtual-list-2.0.5.tgz", - "integrity": "sha512-xg9ckb8UeeIme4/5qlwCrl2QNmUZ8SCQYZn3Ji83cUsoASqRNy3KWjpmNmzYvPDqCHSZjruBBsoB7t5hwuzw5g==" - }, "node_modules/svgo": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", @@ -11748,14 +11734,6 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, - "svelecte": { - "version": "3.17.2", - "resolved": "https://registry.npmjs.org/svelecte/-/svelecte-3.17.2.tgz", - "integrity": "sha512-dKm50Em11f4DNP3UMI+6oGUBHSrPWDOVsuG44T+2f/Vh/RVJYWjdTGJy87BfetDRTHKmuGMiwaGmMBh58tHmGg==", - "requires": { - "svelte-tiny-virtual-list": "^2.0.0" - } - }, "svelte": { "version": "3.59.2", "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz", @@ -11814,11 +11792,6 @@ "svelte-floating-ui": "1.2.8" } }, - "svelte-tiny-virtual-list": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/svelte-tiny-virtual-list/-/svelte-tiny-virtual-list-2.0.5.tgz", - "integrity": "sha512-xg9ckb8UeeIme4/5qlwCrl2QNmUZ8SCQYZn3Ji83cUsoASqRNy3KWjpmNmzYvPDqCHSZjruBBsoB7t5hwuzw5g==" - }, "svgo": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", diff --git a/src/API/api.js b/src/API/api.js index 3a1d469b..568e3cbf 100644 --- a/src/API/api.js +++ b/src/API/api.js @@ -1081,7 +1081,7 @@ class API { } /** - * Whether an item pile is a merchant. If it is not enabled, it is always false. + * Whether an item pile is a auctioneer. If it is not enabled, it is always false. * * @param {Token/TokenDocument} target * @param {Object/boolean} [data=false] data existing flags data to use @@ -1097,6 +1097,23 @@ class API { return PileUtilities.isItemPileAuctioneer(target, data); } + /** + * Whether an item pile is a banker. If it is not enabled, it is always false. + * + * @param {Token/TokenDocument} target + * @param {Object/boolean} [data=false] data existing flags data to use + * @return {boolean} + */ + static isItemPileBanker(target, data = false) { + if(!game.modules.get("item_piles_bankers")?.active) { + let word = "install and activate"; + if (game.modules.get('item_piles_bankers')) word = "activate"; + Helpers.custom_warning(`This api method from Item Piles requires the 'item_piles_bankers' module. Please ${word} it.`, true); + return false; + } + return PileUtilities.isItemPileBanker(target, data); + } + /** * Whether an item pile is empty pile. If it is not enabled, it is always false. * @@ -2257,9 +2274,10 @@ class API { * @param {Actor/Token/TokenDocument} target The merchant actor to refresh the inventory of * @param {object} options Options to pass to the function * @param {boolean} [options.removeExistingActorItems=true] Whether to clear the merchant's existing inventory before adding the new items + * @param {boolean} [options.ignoreCheckItemPilesType=false] Populate this target with the same roll tables set on the merchant settings, but on a actor/token with item piles disabled. This is useful for as a alternative for populate NPC on the canvas * @returns {Promise} */ - static async refreshMerchantInventory(target, { removeExistingActorItems = true } = {}) { + static async refreshMerchantInventory(target, { removeExistingActorItems = true, ignoreCheckItemPilesType = false } = {}) { if (target) { target = Utilities.getActor(target); @@ -2270,7 +2288,7 @@ class API { const targetUuid = Utilities.getUuid(target); - if (!PileUtilities.isItemPileMerchant(target)) { + if (!ignoreCheckItemPilesType && !PileUtilities.isItemPileMerchant(target)) { throw Helpers.custom_error(`refreshMerchantInventory | target of uuid ${targetUuid} is not a merchant`); } @@ -2280,6 +2298,7 @@ class API { const items = await ItemPileSocket.executeAsGM(ItemPileSocket.HANDLERS.REFRESH_MERCHANT_INVENTORY, targetUuid, { removeExistingActorItems, + ignoreCheckItemPilesType, userId: game.user.id }); diff --git a/src/API/private-api.js b/src/API/private-api.js index 29797584..5bb19ff2 100644 --- a/src/API/private-api.js +++ b/src/API/private-api.js @@ -162,6 +162,7 @@ export default class PrivateAPI { * @private */ static _onCreateToken(doc) { + this._refreshInventoryOnCreate(doc); if (!PileUtilities.isValidItemPile(doc)) return; const itemPileConfig = PileUtilities.getActorFlagData(doc.actor) Helpers.hooks.callAll(CONSTANTS.HOOKS.PILE.CREATE, doc, itemPileConfig); @@ -1062,6 +1063,8 @@ export default class PrivateAPI { pileDataDefaults.showItemName = true; pileDataDefaults.overrideSingleItemScale = true; pileDataDefaults.singleItemScale = 0.75; + pileDataDefaults.onCreateTokenRollTable = false; + pileDataDefaults.onCreateTokenRollTableNoMerchant = false; } pileDataDefaults = foundry.utils.mergeObject(pileDataDefaults, itemPileFlags); @@ -1114,6 +1117,8 @@ export default class PrivateAPI { pileDataDefaults.showItemName = true; pileDataDefaults.overrideSingleItemScale = true; pileDataDefaults.singleItemScale = 0.75; + pileDataDefaults.onCreateTokenRollTable = false; + pileDataDefaults.onCreateTokenRollTableNoMerchant = false; } pileDataDefaults = foundry.utils.mergeObject(pileDataDefaults, itemPileFlags); @@ -1479,6 +1484,91 @@ export default class PrivateAPI { })(targetUuid); } + /** + * Pre-loads all images and sounds related to a given token document on the client-side. + * + * @param {TokenDocument} tokenDocument + * @return {Promise} + */ + static async _refreshInventoryOnCreate(tokenDocument) { + + const pileData = PileUtilities.getActorFlagData(tokenDocument.actor, false, true); + + const rollTableOnDrop = pileData.onCreateTokenRollTable; + const rollTableOnDropNoMerchant = pileData.onCreateTokenRollTableNoMerchant; + const betterRollTablesActive = game.modules.get('better-rolltables')?.active; + const isValid = PileUtilities.isValidItemPile(tokenDocument,pileData); + + if(isValid && !PileUtilities.isItemPileMerchant(tokenDocument, pileData)) { + Helpers.debug(`Cannot roll tables on create token on item pile with uuid ${tokenDocument.uuid} with 'Roll Table on Drop' the type is not supported only Merchant is supported`); + return false; + } + + if(rollTableOnDrop) { + if(isValid) { + // Make sure to not destroy anything important on the original actor... + await tokenDocument.update({ actorLink: false }); + + await this._refreshMerchantInventory(tokenDocument.uuid, { + removeExistingActorItems: true, + ignoreCheckItemPilesType: false + }); + + Helpers.debug(`Roll tables on create token on item pile with uuid ${tokenDocument.uuid} with 'Roll Table on Drop' for merchant`); + + } else if(rollTableOnDropNoMerchant) { + + if(betterRollTablesActive) { + const options = { + brtTypes: ['none','better','loot'] // TODO not sure how manage this the right way wait for community feed back + } + const merchant = Utilities.getActor(tokenDocument.uuid); + const brtActorList = await game.modules.get('better-rolltables').api.retrieveActorList(merchant, options); + const rollTablesToRoll = []; + for(const rollTableData of brtActorList.rollTableList) { + rollTablesToRoll.push(rollTableData.rollTable); + } + + const items = await PileUtilities.rollMerchantTables({ + tableData: rollTablesToRoll, + actor: merchant, + ignoreCheckItemPilesType:true }); + + const itemsToAdd = items.map((item) => { + const actualItem = item.item.toObject(); + return Utilities.setItemQuantity(actualItem, item.quantity); + }); + + await PrivateAPI._addItems(tokenDocument.uuid, itemsToAdd, null, { removeExistingActorItems:true }); + Helpers.debug(`Roll tables on create token on item pile with uuid ${tokenDocument.uuid} with 'Roll Table on Drop' for NO merchant with BRT`); + } else { + // TODO Explained here https://github.com/fantasycalendar/FoundryVTT-ItemPiles/pull/562 + // The issue 482 is more complicated because the mechanism for choosing tables is only on + // the merchant sheet panel O.O, i avoided on the code level with a "trick". The "trick" is to use + // the current rolltables flags through the merchant sheet and then disable the item piles + // and drop as a standard npc, the is the optioon to use the new actor list from BRT as alternative + /* + // Make sure to not destroy anything important on the original actor... + await tokenDocument.update({ actorLink: false }); + + await this._refreshMerchantInventory(tokenDocument.uuid, { + removeExistingActorItems: true, + ignoreCheckItemPilesType: true + }); + + Helpers.debug(`Roll tables on create token on item pile with uuid ${tokenDocument.uuid} with 'Roll Table on Drop' for NO merchant with ITEM PILES`); + */ + Helpers.custom_error(`Cannot Roll tables on create token on item pile with uuid ${tokenDocument.uuid} with 'Roll Table on Drop' for NO merchant with ITEM PILES`); + } + } else { + Helpers.debug(`Cannot roll tables on create token on item pile with uuid ${tokenDocument.uuid} because is a valid item pile`); + } + } else { + Helpers.debug(`Cannot Initialized item pile with uuid ${tokenDocument.uuid} because is not a container`); + } + return false; + } + /** * Pre-loads all images and sounds related to a given token document on the client-side. * @@ -2359,14 +2449,24 @@ export default class PrivateAPI { } + /** + * + * @param {string} merchantUuid + * @param {Object} options + * @param {boolean} [options.removeExistingActorItems=false] + * @param {boolean} [options.ignoreCheckItemPilesType=false] + * @param {string|boolean} [options.userId=false] + * @returns + */ static async _refreshMerchantInventory(merchantUuid, { removeExistingActorItems = false, + ignoreCheckItemPilesType = false, userId = false } = {}) { const merchant = Utilities.getActor(merchantUuid); - const items = await PileUtilities.rollMerchantTables({ actor: merchant }); + const items = await PileUtilities.rollMerchantTables({ actor: merchant, ignoreCheckItemPilesType:ignoreCheckItemPilesType }); const itemsToAdd = items.map((item) => { const actualItem = item.item.toObject(); diff --git a/src/applications/item-pile-config/item-pile-config.svelte b/src/applications/item-pile-config/item-pile-config.svelte index b86acb92..70e07995 100644 --- a/src/applications/item-pile-config/item-pile-config.svelte +++ b/src/applications/item-pile-config/item-pile-config.svelte @@ -34,6 +34,14 @@ pileData.deleteWhenEmpty = !!pileData?.deleteWhenEmpty; } + if (typeof pileData?.onCreateTokenRollTable === "boolean") { + pileData.onCreateTokenRollTable = !!pileData?.onCreateTokenRollTable; + } + + if (typeof pileData?.onCreateTokenRollTableNoMerchant === "boolean") { + pileData.onCreateTokenRollTableNoMerchant = !!pileData?.onCreateTokenRollTableNoMerchant; + } + let pileEnabled = writable(pileData.enabled); $: pileData.enabled = $pileEnabled; diff --git a/src/applications/item-pile-config/settings/main.svelte b/src/applications/item-pile-config/settings/main.svelte index 0f8f9118..d9590318 100644 --- a/src/applications/item-pile-config/settings/main.svelte +++ b/src/applications/item-pile-config/settings/main.svelte @@ -158,6 +158,22 @@ +
+ + +
+ +
+ + +
+