diff --git a/src/systems/_index.js b/src/systems/_index.js index cce656ff..8fa0bbf0 100644 --- a/src/systems/_index.js +++ b/src/systems/_index.js @@ -40,6 +40,7 @@ import starwarsffg from "./starwarsffg.js"; import demonlord from "./demonlord.js"; import dnd5e241 from "./dnd5e-2.4.1.js"; import dragonbane from "./dragonbane.js"; +import vaarfeu from "./vaarfeu.js"; // ↑ IMPORT SYSTEMS HERE ↑ /** @@ -162,6 +163,9 @@ export default { }, "dragonbane": { "latest": dragonbane - } + }, + "vaarfeu": { + "latest": vaarfeu + } // ↑ ADD SYSTEMS HERE ↑ } diff --git a/src/systems/vaarfeu.js b/src/systems/vaarfeu.js new file mode 100644 index 00000000..1871a67b --- /dev/null +++ b/src/systems/vaarfeu.js @@ -0,0 +1,223 @@ +import GiveItems from "../applications/dialogs/give-items-dialog/give-items-dialog.js"; +import PrivateAPI from "../API/private-api.js"; +import CONSTANTS from "../constants/constants.js"; + +export default { + +"VERSION": "1.0.0", + // The actor class type is the type of actor that will be used for the default item pile actor that is created on first item drop. + "ACTOR_CLASS_TYPE": "character", + // The item class type is the type of item that will be used for the default loot item + "ITEM_CLASS_LOOT_TYPE": "loot", + // The item class type is the type of item that will be used for the default weapon item + "ITEM_CLASS_WEAPON_TYPE": "weapon", + // The item class type is the type of item that will be used for the default equipment item + "ITEM_CLASS_EQUIPMENT_TYPE": "equipment", + // The item quantity attribute is the path to the attribute on items that denote how many of that item that exists + "ITEM_QUANTITY_ATTRIBUTE": "system.quantity", + // The item price attribute is the path to the attribute on each item that determine how much it costs + "ITEM_PRICE_ATTRIBUTE": "system.price.value", + // Item filters actively remove items from the item pile inventory UI that users cannot loot, such as spells, feats, and classes + "ITEM_FILTERS": [ + { + "path": "type", + "filters": "spell,feat,class,subclass,background" + }, + { + "path": "system.type.value", + "filters": "natural" + } + ], + // This function is an optional system handler that specifically transforms an item's price into a more unified numeric format + "ITEM_COST_TRANSFORMER": (item, currencies) => { + const overallCost = Number(foundry.utils.getProperty(item, "system.price.value")) ?? 0; + const priceDenomination = foundry.utils.getProperty(item, "system.price.denomination"); + if (priceDenomination) { + const currencyDenomination = currencies.filter((currency) => currency.type === "attribute").find((currency) => { + return currency.data.path.toLowerCase().endsWith(priceDenomination); + }); + if (currencyDenomination) { + return overallCost * currencyDenomination.exchangeRate; + } + } + return overallCost ?? 0; + }, + "PRICE_MODIFIER_TRANSFORMER": ({ + buyPriceModifier, + sellPriceModifier, + actor = false, + actorPriceModifiers = [] + } = {}) => { + const modifiers = { + buyPriceModifier, + sellPriceModifier + }; + if (!actor) + return modifiers; + const groupModifiers = actorPriceModifiers.map((data2) => ({ ...data2, actor: fromUuidSync(data2.actorUuid) })).filter((data2) => { + return data2.actor && data2.actor.type === "group" && data2.actor.system.members.some((member) => member === actor); + }); + modifiers.buyPriceModifier = groupModifiers.reduce((acc, data2) => { + return data2.override ? data2.buyPriceModifier ?? acc : acc * data2.buyPriceModifier; + }, buyPriceModifier); + modifiers.sellPriceModifier = groupModifiers.reduce((acc, data2) => { + return data2.override ? data2.sellPriceModifier ?? acc : acc * data2.sellPriceModifier; + }, sellPriceModifier); + return modifiers; + }, + + "PILE_DEFAULTS": { + merchantColumns: [{ + label: "", + path: "system.equipped", + formatting: "{#}", + buying: false, + selling: true, + mapping: { + "true": "✔", + "false": "" + } + }, { + label: "Rarity", + path: "system.rarity", + formatting: "{#}", + buying: true, + selling: true, + mapping: { + "common": "VAARFEU.ItemRarityCommon", + "uncommon": "VAARFEU.ItemRarityUncommon", + "rare": "VAARFEU.ItemRarityRare", + "veryRare": "VAARFEU.ItemRarityVeryRare", + "legendary": "VAARFEU.ItemRarityLegendary", + "artifact": "VAARFEU.ItemRarityArtifact" + } + }] + }, + + // Item similarities determines how item piles detect similarities and differences in the system + "ITEM_SIMILARITIES": ["name", "type", "system.container"], + + // Currencies in item piles is a versatile system that can accept actor attributes (a number field on the actor's sheet) or items (actual items in their inventory) + // In the case of attributes, the path is relative to the "actor.system" + // In the case of items, it is recommended you export the item with `.toObject()` and strip out any module data + "CURRENCIES": [ + { + type: "attribute", + name: "VAARFEU.CurrencyPP", + img: "icons/commodities/currency/coin-inset-snail-silver.webp", + abbreviation: "{#}PP", + data: { + path: "system.currency.pp" + }, + primary: false, + exchangeRate: 10 + }, + { + type: "attribute", + name: "VAARFEU.CurrencyGP", + img: "icons/commodities/currency/coin-embossed-crown-gold.webp", + abbreviation: "{#}GP", + data: { + path: "system.currency.gp" + }, + primary: true, + exchangeRate: 1 + }, + { + type: "attribute", + name: "VAARFEU.CurrencyEP", + img: "icons/commodities/currency/coin-inset-copper-axe.webp", + abbreviation: "{#}EP", + data: { + path: "system.currency.ep" + }, + primary: false, + exchangeRate: 0.5 + }, + { + type: "attribute", + name: "VAARFEU.CurrencySP", + img: "icons/commodities/currency/coin-engraved-moon-silver.webp", + abbreviation: "{#}SP", + data: { + path: "system.currency.sp" + }, + primary: false, + exchangeRate: 0.1 + }, + { + type: "attribute", + name: "VAARFEU.CurrencyCP", + img: "icons/commodities/currency/coin-engraved-waves-copper.webp", + abbreviation: "{#}CP", + data: { + path: "system.currency.cp" + }, + primary: false, + exchangeRate: 0.01 + } + ], + + "VAULT_STYLES": [ + { + path: "system.rarity", + value: "artifact", + styling: { + "box-shadow": "inset 0px 0px 7px 0px rgba(255,191,0,1)" + } + }, + { + path: "system.rarity", + value: "legendary", + styling: { + "box-shadow": "inset 0px 0px 7px 0px rgba(255,119,0,1)" + } + }, + { + path: "system.rarity", + value: "veryRare", + styling: { + "box-shadow": "inset 0px 0px 7px 0px rgba(255,0,247,1)" + } + }, + { + path: "system.rarity", + value: "rare", + styling: { + "box-shadow": "inset 0px 0px 7px 0px rgba(0,136,255,1)" + } + }, + { + path: "system.rarity", + value: "uncommon", + styling: { + "box-shadow": "inset 0px 0px 7px 0px rgba(0,255,9,1)" + } + } + ], + + "SYSTEM_HOOKS": () => { + + Hooks.on("vaarfeu.getItemContextOptions", (item, options) => { + options.push({ + name: "Give to character", + icon: "", + callback: async () => { + const result = await GiveItems.show(item); + if (!result) return; + PrivateAPI._giveItem({ + itemData: { + item: item.toObject(), + quantity: result.quantity + }, + source: item.parent.uuid, + target: result.target, + secret: result.secret, + }, { skipQuantityDialog: true }) + }, + condition: !game.itempiles.API.isItemInvalid(item) + }) + }); + + } +}