Skip to content

Commit

Permalink
3.1.6
Browse files Browse the repository at this point in the history
  • Loading branch information
Haxxer committed Oct 6, 2024
1 parent 80b636b commit 2b91fb3
Show file tree
Hide file tree
Showing 12 changed files with 91 additions and 155 deletions.
8 changes: 8 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Item Piles Changelog

## Version 3.1.6

- Improved D&D5e support for merchants by allowing them to buy and sell both containers and the items they contain
- This does not prevent players from selling containers and their contents, and the sell price only takes the container's price into consideration
- Updated Italian, Polish, and Portuguese localization (thank you, Gregory Warn, Lioheart, and Eduadro on weblate!)
- Fixed property lookup with item filters and required item properties not handling arrays well
- Fixed editing unlinked item pile actors would not transfer the configuration to the prototype token of the item pile

## Version 3.1.5

- Added missing localization for "Give To Character" item right click menu in D&D5e
Expand Down
4 changes: 2 additions & 2 deletions src/API/chat-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ export default class ChatAPI {
.map(user => user.id);
chatData.whisper.push(userId);
chatData.whisper.push(targetUserId);
if (CONSTANTS.IS_V12) {
if (!CONSTANTS.IS_V12) {
chatData.type = CHAT_MESSAGE_STYLES.WHISPER;
}
}
Expand Down Expand Up @@ -652,7 +652,7 @@ export default class ChatAPI {
if (mode === 2) {
chatData.whisper.push(userId);
}
if (CONSTANTS.IS_V12) {
if (!CONSTANTS.IS_V12) {
chatData.type = CHAT_MESSAGE_STYLES.WHISPER;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@
}}/>
{:else}
<small>
{localize(...paymentData.reason)}
{#each paymentData.reason ?? [] as reason}
<p style="margin:0;">{localize(...reason)}</p>
{/each}
</small>
{/if}
</div>
Expand Down
5 changes: 1 addition & 4 deletions src/applications/merchant-app/MerchantItemTab.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,10 @@
export let noItemsLabel = "ITEM-PILES.Merchant.NoItemsForSale";
export let services = false;
const pileData = store.pileData;
const searchStore = store.search;
const visibleItemsStore = store.visibleItems;
const itemsStore = store.items;
const itemsPerCategoryStore = store.itemsPerCategory;
const categoryStore = store.categories;
const priceModifiersPerType = store.priceModifiersPerType;
const itemCategoriesStore = store.itemCategories;
const typeFilterStore = store.typeFilter;
const sortTypesStore = store.sortTypes;
Expand All @@ -26,7 +23,7 @@
$: categoryDropDown = $itemCategoriesStore.filter(category => category.service === services);
$: categories = $categoryStore.filter(category => category.service === services);
$: items = $itemsStore.filter(item => Boolean(get(item.itemFlagData)?.isService) === services)
$: items = $visibleItemsStore.filter(item => Boolean(get(item.itemFlagData)?.isService) === services)
$: visibleItems = $visibleItemsStore.filter(item => Boolean(get(item.itemFlagData)?.isService) === services)
let columns = [];
Expand Down
8 changes: 0 additions & 8 deletions src/constants/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ const SETTINGS = {
TOKEN_FLAG_DEFAULTS: "tokenFlagDefaults",

// Hidden settings
DEFAULT_ITEM_PILE_JOURNAL_ID: "defaultItemPileJournalID",
DEFAULT_ITEM_PILE_ACTOR_ID: "defaultItemPileActorID",
SYSTEM_FOUND: "systemFound",
SYSTEM_NOT_FOUND_WARNING_SHOWN: "systemNotFoundWarningShown",
Expand Down Expand Up @@ -317,13 +316,6 @@ const SETTINGS = {
type: String
},

[SETTINGS.DEFAULT_ITEM_PILE_JOURNAL_ID]: {
scope: "world",
config: false,
default: "",
type: String
},

[SETTINGS.SYSTEM_FOUND]: {
scope: "world",
config: false,
Expand Down
100 changes: 64 additions & 36 deletions src/helpers/pile-utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -460,12 +460,21 @@ export function cleanItemFilters(itemFilters) {
}
return str;
});
filter.filters = new Set(filter.filters)
return filter;
})
: [];
}

function doesPropertyMatch(propertyValue, filterValue) {
if (Array.isArray(propertyValue)) {
return propertyValue.some(value => doesPropertyMatch(value, filterValue));
}
if (Utilities.isRealNumber(propertyValue) && Utilities.isRealNumber(Number(filterValue))) {
return Math.abs(propertyValue - Number(filterValue)) < Number.EPSILON;
}
return propertyValue === filterValue;
}

export function isItemInvalid(targetActor, item, itemFilters = false) {
const pileItemFilters = itemFilters
? itemFilters
Expand All @@ -475,10 +484,10 @@ export function isItemInvalid(targetActor, item, itemFilters = false) {
: item;
for (const filter of pileItemFilters) {
if (!foundry.utils.hasProperty(itemData, filter.path)) continue;
const attributeValue = foundry.utils.getProperty(itemData, filter.path);
if (filter.filters.has(attributeValue)) {
return attributeValue;
}
const propertyValue = foundry.utils.getProperty(itemData, filter.path);
const filterValues = Array.isArray(filter.filters) ? filter.filters : Array.from(filter.filters);
const foundFilterValue = filterValues.find(filterValue => doesPropertyMatch(propertyValue, filterValue));
if (foundFilterValue) return foundFilterValue;
}
return false;
}
Expand All @@ -490,8 +499,12 @@ export function isItemValidBasedOnProperties(targetActor, item) {
: item;
for (const filter of pileItemRequiredProperties) {
if (!foundry.utils.hasProperty(itemData, filter.path)) return false;
const attributeValue = foundry.utils.getProperty(itemData, filter.path);
if (!filter.filters.has(attributeValue)) return false;

const propertyValue = foundry.utils.getProperty(itemData, filter.path);
const filterValues = Array.isArray(filter.filters) ? filter.filters : Array.from(filter.filters);

const matchFound = filterValues.some(filterValue => doesPropertyMatch(propertyValue, filterValue));
if (!matchFound) return false;
}
return true;

Expand Down Expand Up @@ -761,7 +774,11 @@ export async function updateItemPileData(target, newFlags, tokenData) {
if (documentActor) {
await documentActor.update({
[CONSTANTS.FLAGS.PILE]: cleanedFlagData,
[CONSTANTS.FLAGS.VERSION]: Helpers.getModuleVersion()
[CONSTANTS.FLAGS.VERSION]: Helpers.getModuleVersion(),
prototypeToken: {
[CONSTANTS.FLAGS.PILE]: cleanedFlagData,
[CONSTANTS.FLAGS.VERSION]: Helpers.getModuleVersion(),
}
});
}

Expand Down Expand Up @@ -1534,16 +1551,18 @@ export function getPaymentData({
quantity: data.quantity || 1
})[data.paymentIndex || 0];
return {
...prices, item: data.item
...prices,
item: data.item
};
})
.reduce((priceData, priceGroup) => {

priceData.reasons = [];

if (!priceGroup.maxQuantity && (buyer || seller)) {
priceData.canBuy = false;
priceData.reason = ["ITEM-PILES.Applications.TradeMerchantItem." + (buyer === merchant
? "TheyCantAfford"
: "YouCantAfford")];
const reason = (buyer === merchant ? "TheyCantAfford" : "YouCantAfford");
priceData.reason.push([`ITEM-PILES.Applications.TradeMerchantItem.${reason}`]);
return priceData;
}

Expand Down Expand Up @@ -1578,39 +1597,48 @@ export function getPaymentData({

if (existingPrice.buyerQuantity < 0) {
priceData.canBuy = false;
priceData.reason = ["ITEM-PILES.Applications.TradeMerchantItem." + (buyer === merchant
? "TheyCantAfford"
: "YouCantAfford")];
const reason = (buyer === merchant ? "TheyCantAfford" : "YouCantAfford");
priceData.reasons.push([`ITEM-PILES.Applications.TradeMerchantItem.${reason}`]);
}
}
}

if (priceGroup.item) {

const itemQuantity = Utilities.getItemQuantity(priceGroup.item);
let items = [{ item: priceGroup.item, contained: false }];
const itemTypeHandler = Utilities.getItemTypeHandler(CONSTANTS.ITEM_TYPE_METHODS.TRANSFER, priceGroup.item.type);
if (itemTypeHandler) {
const containedItems = [];
itemTypeHandler({ item: priceGroup.item, items: containedItems, raw: true })
items = items.concat(containedItems.map(item => ({ item, contained: true })))
}

const quantityPerPrice = game.itempiles.API.QUANTITY_FOR_PRICE_ATTRIBUTE
? foundry.utils.getProperty(priceGroup.item, game.itempiles.API.QUANTITY_FOR_PRICE_ATTRIBUTE) ?? 1
: 1;
for (const itemData of items) {

const requiredQuantity = Math.floor(priceGroup.quantity * quantityPerPrice);
const itemQuantity = Utilities.getItemQuantity(itemData.item);

if (requiredQuantity > itemQuantity && requiredQuantity > (priceGroup.maxQuantity * quantityPerPrice)) {
priceData.canBuy = false;
priceData.reason = [`ITEM-PILES.Applications.TradeMerchantItem.${buyer === merchant
? "You"
: "They"}LackQuantity`, {
quantity: itemQuantity, requiredQuantity
}];
}
const quantityPerPrice = foundry.utils.getProperty(itemData.item, game.itempiles.API.QUANTITY_FOR_PRICE_ATTRIBUTE) ?? 1;

priceData.buyerReceive.push({
type: "item",
name: priceGroup.item.name,
img: priceGroup.item.img,
quantity: requiredQuantity,
item: priceGroup.item,
});
const requiredQuantity = Math.floor(priceGroup.quantity * quantityPerPrice);

if (requiredQuantity > itemQuantity && requiredQuantity > (priceGroup.maxQuantity * quantityPerPrice)) {
priceData.canBuy = false;
const reason = buyer === merchant ? "You" : "They";
priceData.reasons.push([`ITEM-PILES.Applications.TradeMerchantItem.${reason}LackQuantity`, {
quantity: itemQuantity,
requiredQuantity
}]);
}

priceData.buyerReceive.push({
type: "item",
name: itemData.item.name,
img: itemData.item.img,
quantity: requiredQuantity,
item: itemData.item,
contained: itemData.contained
});
}
}

return priceData;
Expand Down Expand Up @@ -1845,7 +1873,7 @@ export function isMerchantClosed(merchant, { pileData = false } = {}) {

}

export async function updateMerchantLog(itemPile, activityData = {}) {
export async function updateMerchantLog(itemPile, activityData) {

const vaultLog = getActorLog(itemPile);

Expand Down
7 changes: 2 additions & 5 deletions src/helpers/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import ItemPileSocket from "../socket.js";
import PrivateAPI from "../API/private-api.js";
import { SYSTEMS } from "../systems.js";
import CONSTANTS from "../constants/constants.js";
import container from "../applications/item-pile-config/settings/container.svelte";

export default class Transaction {

Expand All @@ -30,10 +29,6 @@ export default class Transaction {
set = false, remove = false, type = "item", keepIfZero = false
} = {}) {

if (!remove) {
items = Utilities.ensureValidIds(this.document, items);
}

for (let data of items) {

let item = data.item ?? data;
Expand Down Expand Up @@ -221,6 +216,8 @@ export default class Transaction {
return item;
});

this.itemsToCreate = Utilities.ensureValidIds(this.document, this.itemsToCreate);

this.itemsToDelete = this.itemsToUpdate.filter(item => {
return Utilities.getItemQuantity(item) <= 0 && this.itemTypeMap.get(item._id) !== "currency";
}).map(item => item._id).concat(Array.from(this.itemsToForceDelete));
Expand Down
4 changes: 4 additions & 0 deletions src/helpers/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -506,3 +506,7 @@ export function ensureValidIds(actor, itemsToCreate) {
});

}

export function isRealNumber(inNumber) {
return !isNaN(inNumber) && typeof inNumber === "number" && isFinite(inNumber);
}
2 changes: 2 additions & 0 deletions src/stores/merchant-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,9 @@ export default class MerchantStore extends ItemPileStore {

visibleItemFilterFunction(entry, actorIsMerchant, pileData, recipientPileData) {
const itemIsFree = !!get(entry.prices).find(price => price.free);
const itemIsContained = get(entry.containerID);
return super.visibleItemFilterFunction(entry, actorIsMerchant, pileData, recipientPileData)
&& !itemIsContained
&& (
actorIsMerchant
? !(pileData?.hideItemsWithZeroCost && itemIsFree)
Expand Down
4 changes: 2 additions & 2 deletions src/systems/dnd5e.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ export default {
[CONSTANTS.ITEM_TYPE_METHODS.CONTENTS]: ({ item }) => {
return item.system.contents.contents;
},
[CONSTANTS.ITEM_TYPE_METHODS.TRANSFER]: ({ item, items }) => {
[CONSTANTS.ITEM_TYPE_METHODS.TRANSFER]: ({ item, items, raw = false } = {}) => {
for (const containedItem of item.system.contents.contents) {
items.push(containedItem.toObject());
items.push(raw ? containedItem : containedItem.toObject());
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion templates/chat/merchant-traded.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
</div>

<ul>
{{#each priceInformation as |bought basePriceString|}}
{{#each priceInformation as |bought|}}
{{#each bought.buyerReceive as |item id|}}
<li>
<img src="{{item.img}}" data-fast-tooltip="{{item.name}}" height="16"/>
<label>{{item.name}} <small>(x{{item.quantity}})</small></label>
{{#unless item.contained}}
<label class="item-piles-chat-price">{{bought.basePriceString}}</label>
{{/unless}}
</li>
{{/each}}
{{/each}}
Expand Down
Loading

0 comments on commit 2b91fb3

Please sign in to comment.