zischenstand

This commit is contained in:
centron\schwoerer
2025-11-14 14:52:43 +01:00
parent 30aa03c6db
commit f054a31b20
8733 changed files with 900639 additions and 0 deletions

View File

@@ -0,0 +1,239 @@
.loot-sheet-npc .gm-section {
/* height: 48px; */
color: #000;
/* font-weight: 700; */
font-size: 20px;
margin-top: 0.5rem;
text-align: center;
border-top: 1px solid #CCC;
border-bottom: 1px solid #CCC;
font-family: "Nodesto", "Signika", "Palatino Linotype", serif;
font-size: 20px;
color: #4b4a44;
font-size: 18px;
}
.loot-sheet-npc .gm-header {
margin-top: 0.5rem;
}
.loot-sheet-npc .gm-settings .permissions-list,
.loot-sheet-npc .gm-settings .coin-list {
margin: 0;
padding: 0;
list-style: none;
}
.loot-sheet-npc .warn {
color: red;
}
.loot-sheet-npc .gm-settings .sheet-types,
.loot-sheet-npc .gm-settings .merchant-settings {
margin-right: 10px;
}
.loot-sheet-npc .gm-settings .merchant-settings .flexrow {
border-bottom: 1px solid #CCC;
margin-bottom: 5px;
}
.loot-sheet-npc .gm-settings .merchant-settings .flexrow h4 {
margin: 2px 0 0 0;
}
.loot-sheet-npc .gm-settings .merchant-settings {
margin-left: 24px;
}
.loot-sheet-npc .gm-settings .coins-list {
padding-left: 24px;
}
.loot-sheet-npc .gm-settings h4.sheet-name {
flex: 1;
margin: 0 0 0 24px;
line-height: 22px;
}
.loot-sheet-npc .gm-settings .permission,
.loot-sheet-npc .gm-settings .denomination {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
height: 21px;
line-height: 21px;
border-bottom: 1px solid #CCC;
font-size: 13px;
}
.loot-sheet-npc .gm-settings .sheet-type-info,
.loot-sheet-npc .gm-settings .permission-info,
.loot-sheet-npc .gm-settings .merchant-settings-info {
color: #7a7971;
margin: 6px 6px 6px 24px;
display: none;
}
.loot-sheet-npc .gm-settings .help {
color: #7a7971;
font-size: 13px;
}
.loot-sheet-npc .gm-settings .permission,
.loot-sheet-npc .gm-settings .denomination>* {
flex: 1;
flex-wrap: inherit;
height: auto;
}
.loot-sheet-npc .gm-settings .permission .permission-name {
margin: 0;
}
.loot-sheet-npc .gm-settings .permission .permission-proficiency {
text-align: center;
flex: 0 0 24px;
}
.loot-sheet-npc .gm-settings .permission .permission-proficiency i.fa-circle {
font-size: 10px;
}
.loot-sheet-npc .gm-settings .split-coins {
width: 95%;
}
.loot-sheet-npc .gm-settings .update-inventory {
width: 95%;
}
.loot-sheet-npc img.sheet-profile {
border: none;
max-width: 220px;
max-height: 220px;
}
.loot-sheet-npc img.sheet-profile-small {
border: none;
max-width: 120px;
max-height: 120px;
}
section.sheet-sidebar.sidebar {
flex: 0 0 250px;
border-bottom: 2px groove #eeede0;
border-right: 2px groove #eeede0;
}
.sheet-profile-img {
text-align: center;
}
section.sheet-content.content {
border-bottom: 2px groove #eeede0;
}
.loot-sheet-npc.sheet.actor .inventory-list .item .item-price,
.loot-sheet-npc.sheet.actor .inventory-list .item .adjusted-price,
.loot-sheet-npc.sheet.actor .inventory-list .item .item-quantity {
flex: 0 0 100px;
color: #666;
font-size: 10px;
}
.loot-sheet-npc.sheet.actor .inventory-list .item-controls {
flex: 0 0 120px !important;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
justify-content: flex-end;
}
.loot-sheet-npc.sheet .sheet-header .charbutton {
flex: 0 0 200px;
margin: auto;
text-align: right;
}
button.price-modifier, button.convert-loot {
width: auto;
padding: 1px 10px;
margin-right: 5px;
}
.loot-sheet-npc.sheet .sheet-navigation {
margin-bottom: 15px;
}
input#price-modifier-percent-display {
background: none;
border: 1px solid transparent;
width: 50px;
}
input#quantity {
background: none;
border: 1px solid #111;
}
input#price-modifier-percent-display:hover,
input#price-modifier-percent-display:focus,
input#quantity:hover,
input#quantity:focus {
border: 1px solid #111;
box-shadow: 0 0 8px red;
}
.loot-sheet-npc .sheet-profile-img {
padding: 10px;
}
.loot-sheet-npc.sheet.actor .editor {
height: 600px;
}
.loot-sheet-npc.sheet .sheet-header h1 input {
margin: 0px;
}
.loot-sheet-npc .currency-controls a {
flex: 0 0 16px;
font-size: 10px;
text-align: center;
color: #666;
}
.loot-sheet-npc .totals {
margin-left: 20px;
padding: 10px 0 2px 0;
}
.loot-sheet-npc .features {
height: 530px;
overflow-y: scroll;
}
.loot-sheet-npc .batch-update {
padding: 5px;
}
.loot-sheet-npc .batch-update a {
margin-left: 10px;
}
.loot-sheet-npc .fa-eye-slash {
color: darkred;
}
.loot-sheet-npc .fa-infinity {
padding: 0 2px
}
.loot-sheet-npc .enabled .fa-infinity {
color: darkred;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 722 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 856 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

View File

@@ -0,0 +1,142 @@
{
"SETTINGS.lsPurchaseChatMessageTitle": "Display chat message for purchases?",
"SETTINGS.lsPurchaseChatMessageHint": "If enabled, a chat message will display purchases of items from the loot sheet.",
"SETTINGS.lsClearInventoryTitle": "Clear inventory?",
"SETTINGS.lsClearInventoryHint": "If enabled, all existing items will be removed from the Loot Sheet before adding new items from the rollable table. If disabled, existing items will remain.",
"SETTINGS.lsChangeIconForSpellScrollsTitle": "Change icon for Spell Scrolls?",
"SETTINGS.lsChangeIconForSpellScrollsHint": "Changes the icon for spell scrolls to a scroll icon. If left unchecked, retains the spell's icon.",
"SETTINGS.lsRemoveEmptyStackTitle": "Delete empty stacks",
"SETTINGS.lsRemoveEmptyStackHint": "Deletes items that have quantity set to 0. If disabled, the items will remain with quantity of 0.",
"ERROR.lsItemInvalidQuantity": "Item quantity invalid.",
"ERROR.lsChangingSettingsFor": "Error changing settings for \"{name}\".",
"ERROR.lsNoRollableTableFound": "No Rollable Table found with name \"{name}\".",
"ERROR.lsNoItemFound": "No item found \"{item}\".",
"ERROR.lsNoActiveGM": "No active GM on your scene, he must be online and on the same scene.",
"ERROR.lsPurchaseFromToken": "You must purchase items from a token.",
"ERROR.lsNoActiveCharacter": "No active character for user.",
"ERROR.lsLootFromToken": "You must loot items from a token.",
"ERROR.lsNotEnougFunds": "Not enough funds to purchase item.",
"ERROR.lsLootAttempt": "Player attempted to loot an item on a different scene.",
"ERROR.lsPurchaseAttempt": "Player attempted to purchase an item on a different scene.",
"ERROR.lsChooseTable": "Please choose a table.",
"ERROR.lsCurrencyConversionFailed": "Currency conversion failed. That must be a bug!",
"ERROR.lsNotAutorizedToAdd": "You're not autorized to add items that you don't own!",
"ERROR.lsInvalidType": "You cannot add this type of element to the loot sheet!",
"ERROR.lsInvalidDrop": "Only GMs can drop items from compendiums!",
"ERROR.lsNotAutorizedToGive": "You're not autorized to give items that you don't own!",
"ERROR.lsWhyGivingToYourself": "Why would you give that item to yourself??",
"ERROR.lsGiveInvalidType": "You cannot give this type of element!",
"ERROR.lsInvalidParentPermission": "Doesn't work properly if default permission is not 'None'. Please fix the actor's permissions!",
"ERROR.lsInvalidMove": "The actor {actor} tried to sell or drop an item from an unlinked token!",
"ls.quantity": "Quantity",
"ls.price": "Price (in gp)",
"ls.accept": "Accept",
"ls.cancel": "Cancel",
"ls.update": "Update",
"ls.purchase": "Purchase",
"ls.give": "Give",
"ls.split": "Split",
"ls.loot": "Loot",
"ls.weapons": "Weapons",
"ls.equipment": "Equipment",
"ls.consumables": "Consumables",
"ls.lootType": "Loot",
"ls.containerType": "Containers",
"ls.percentage": "Percentage",
"ls.scrollof": "Scroll of {name}",
"ls.chatLoot": "{buyer} looted {quantity} x {name}.",
"ls.chatLootCoins": "{buyer} looted {quantity} {currency}.",
"ls.chatPurchase": "{buyer} purchased {quantity} x {name} for {cost} gp.",
"ls.chatSell": "{seller} sold {quantity} x {item} for {price} gp. to {container}",
"ls.chatDrop": "{seller} dropped {quantity} x {item} into {container}",
"ls.chatGive": "{quantity} x {item} given/moved from {giver} to {receiver}.",
"ls.permissionNoaccess": "None (cannot access sheet)",
"ls.permissionLimited": "Limited (access to sheet but cannot do any action)",
"ls.permissionObserver": "Observer (can loot/buy items and coins)",
"ls.batchUpdate": "All players",
"ls.priceModifierTitle": "Price Modifier",
"ls.priceModifierTooltip": "This uses a percentage factor where 100% is the current price, 0% is 0, and 200% is double the price.",
"ls.priceModifierText": "Use this slider to increase or decrease the price of all items in this inventory.",
"ls.convertLootTitle": "Convert to coins",
"ls.convertLootMessage": "Are you sure you want to convert all items into coins? Items will be sold for {saleValue}% of their price (except TradeGoods). Unidentified items will be sold based on unidentified cost.",
"ls.lootName": "Merchant/Loot Name",
"ls.noAccesToSheet": "You don't have access to that Loot/Merchant sheet!",
"ls.inventory": "Inventory",
"ls.biography": "Biography",
"ls.currency": "Currency",
"ls.add": "Add",
"ls.createItem": "Create Item",
"ls.lootItem": "Loot Item",
"ls.lootCoins": "Loot Coins",
"ls.buyItem": "Buy Item",
"ls.editItem": "Edit Item",
"ls.deleteItem": "Delete Item",
"ls.gmSettings": "GM Settings",
"ls.type": "Type",
"ls.typeInfo": "Loot: allows for distribution of coins across players. Merchant: allows players to purchase items directly from the sheet.",
"ls.typeOfSheet": "Type of sheet",
"ls.typeLoot": "Loot",
"ls.typeMerchant": "Merchant",
"ls.permissions": "Permissions",
"ls.permissionsInfo": "Ensure players have selected a character via the Player Configuration (right-click player in bottom left) menu.",
"ls.coinDistribution": "Coin Distribution",
"ls.each": "each",
"ls.splitBy": "Split into",
"ls.merchantSettings": "Merchant Settings",
"ls.merchantInfo": "Replace this merchant's inventory with a random number of items from a Rollable Table. Specify the Rollable Table's name, along with how a formula for how many different items to add (Shop Qty Formula), and a formula for determining how many of each item to add (Item Qty Formula).",
"ls.rollableTable": "Rollable Table",
"ls.chooseTable": "-- Choose table --",
"ls.shopQtyFormula": "Shop Qty Formula",
"ls.itemQtyFormula": "Item Qty Formula",
"ls.updateShopInventory": "Update Shop Inventory",
"ls.splitcoins": " {quantity} {currency}",
"ls.receives": "{actor} receives:",
"ls.lsOptions": "Options",
"ls.enableDragging": "Enable dragging",
"ls.enableDraggingTooltip": "A player can drag an item from the loot. Be careful because the item will not be removed from the loot and no message will be displayed in the chat log. When disabled, players are forced to use the loot action to take something.",
"ls.maxCapacity": "Max capacity",
"ls.maxCapacityTooltip": "Maximum number of items in the loot (empty or 0 means unlimited)",
"ls.maxLoad": "Max load",
"ls.maxLoadTooltip": "Max weight that can be put in the loot (empty or 0 means unlimited)",
"ls.saleValue": "Sale Value",
"ls.saleValueTooltip": "The percentage of value that non trade goods will be sold for (empty means 50%)",
"ls.displaySaleValue": "Display Sale Value",
"ls.displaySaleValueTooltip": "If enabled, displays the adjusted sale value to the user.",
"ls.pp": "pp",
"ls.gp": "gp",
"ls.sp": "sp",
"ls.cp": "cp",
"ls.wl_pp": "pp (weightless)",
"ls.wl_gp": "gp (weightless)",
"ls.wl_sp": "sp (weightless)",
"ls.wl_cp": "cp (weightless)",
"ls.totalItems": "Items (count)",
"ls.totalPrice": "Total value",
"ls.totalWeight": "Total weight",
"ls.adjustedPrice": "Sale value",
"ls.giveTitleSplit": "Split quantity",
"ls.giveTitle": "Give {item} to {actor}",
"ls.giveContent": "How many?",
"ls.giveContentSingle": "Are you sure you want to give <em>{item}</em> to <b>{actor}</b>?",
"ls.lootTitle": "Loot {item}",
"ls.lootContent": "Are you sure you want to loot <em>{item}</em>?",
"ls.buyTitle": "Buy {item}",
"ls.buyContent": "Are you sure you want to buy <em>{item}</em>?",
"ls.convertToLoot": "Convert to loot",
"ls.convertToLootUnlinked": "Convert defeated (tokens) to loot"
}

View File

@@ -0,0 +1,141 @@
{
"SETTINGS.lsPurchaseChatMessageTitle": "Afficher les messages de transaction?",
"SETTINGS.lsPurchaseChatMessageHint": "Si activé, un message sera affiché dans la conversation pour les objets achetés d'un marchand ou récupérés de la feuille de butin.",
"SETTINGS.lsClearInventoryTitle": "Supprimer l'inventaire?",
"SETTINGS.lsClearInventoryHint": "Si activé, les objets seront retirés de la feuille de butin avant d'en ajouter d'autres à partir de la table aléatoire. Sinon, les objets seront conservés.",
"SETTINGS.lsChangeIconForSpellScrollsTitle": "Changer l'icône des parchemins?",
"SETTINGS.lsChangeIconForSpellScrollsHint": "Si activé, l'icône du sort sera remplacée par celle d'un parchemin. Sinon, l'icône du sort sera préservée.",
"SETTINGS.lsRemoveEmptyStackTitle": "Supprimer les piles vides",
"SETTINGS.lsRemoveEmptyStackHint": "Supprimer les objets lorsque la quantité est 0. Si désactivé, conserve les objets avec une quantité de 0.",
"ERROR.lsItemInvalidQuantity": "Quantité invalide.",
"ERROR.lsChangingSettingsFor": "Erreur lors du changement de configuration \"{name}\".",
"ERROR.lsNoRollableTableFound": "Aucune table aléatoire trouvée avec le nom \"{name}\".",
"ERROR.lsNoItemFound": "Aucun objet \"{item}\" trouvé.",
"ERROR.lsNoActiveGM": "Aucun MJ sur la scène. Celui-ci doit être en ligne et se trouver sur la même scène.",
"ERROR.lsPurchaseFromToken": "Les achats doivent se faire à partir du token sur la carte.",
"ERROR.lsNoActiveCharacter": "Aucun personnage actif pour l'utilisateur.",
"ERROR.lsLootFromToken": "L'action doit se faire à partir du token sur la carte.",
"ERROR.lsNotEnougFunds": "Pas assez d'argent pour acheter l'objet.",
"ERROR.lsLootAttempt": "Un joueur a tenté de s'approprier un objet dans une scène différente.",
"ERROR.lsPurchaseAttempt": "Un joueur a tenté d'acheter un objet dans une scène différente.",
"ERROR.lsChooseTable": "Veuillez choisir une table.",
"ERROR.lsCurrencyConversionFailed": "Échec de conversion de monnaie. Ça doit être un bogue!",
"ERROR.lsNotAutorizedToAdd": "Vous n'êtes pas autorisé à ajouter des objets dont vous n'êtes pas le propriétaire!",
"ERROR.lsInvalidType": "La feuille de butin n'accepte pas ce type d'élément!",
"ERROR.lsInvalidDrop": "Seuls les MJ peuvent déposer des objets depuis les compendiums!",
"ERROR.lsNotAutorizedToGive": "Vous n'êtes pas autorisé à donner des objets dont vous n'êtes pas le propriétaire!",
"ERROR.lsWhyGivingToYourself": "Pourquoi voudriez-vous donner cet objet à vous-même??",
"ERROR.lsGiveInvalidType": "Vous ne pouvez pas donner ce type d'élément!",
"ERROR.lsInvalidParentPermission": "Ne fonctionne pas si les permissions par défaut ne sont pas 'None'. Veuillez corriger les permissions de l'acteur!",
"ERROR.lsInvalidMove": "L'acteur {actor} a tenté de vendre ou déposer un objet depuis un token non-relié!",
"ls.quantity": "Quantité",
"ls.price": "Prix (en po)",
"ls.accept": "Accepter",
"ls.cancel": "Annuler",
"ls.update": "Mettre à jour",
"ls.purchase": "Acheter",
"ls.give": "Donner",
"ls.split": "Diviser",
"ls.loot": "S'approprier",
"ls.weapons": "Armes",
"ls.equipment": "Armures/bouclier",
"ls.consumables": "Consommables",
"ls.lootType": "Autres butins",
"ls.containerType": "Contenants",
"ls.percentage": "Pourcentage",
"ls.scrollof": "Parchemin de {name}",
"ls.chatLoot": "{buyer} s'est approprié(e) {quantity} x {name}.",
"ls.chatLootCoins": "{buyer} s'est approprié(e) {quantity} {currency}.",
"ls.chatPurchase": "{buyer} a acheté {quantity} x {name} pour {cost} po.",
"ls.chatSell": "{seller} a vendu {quantity} x {item} pour {price} po. à {container}",
"ls.chatDrop": "{seller} a déposé {quantity} x {item} dans {container}",
"ls.chatGive": "{quantity} x {item} donné/transféré de {giver} à {receiver}.",
"ls.permissionNoaccess": "Aucun (ne peut accéder au butin)",
"ls.permissionLimited": "Limité (peut accéder à la feuille mais ne peut faire aucune action)",
"ls.permissionObserver": "Observateur (peut accéder acheter/s'approprier des objets et des pièces)",
"ls.batchUpdate": "Tous les joueurs",
"ls.priceModifierTitle": "Modificateur de prix",
"ls.priceModifierTooltip": "Utilisation d'un facteur de prix, 100% set le prix normal, 0% est 0, et 200% signifie un prix doublé.",
"ls.priceModifierText": "Utiliser le curseur pour augmenter ou réduire le prix de tous les objets de l'inventaire.",
"ls.convertLootTitle": "Convertir en pièces",
"ls.convertLootMessage": "Êtes-vous sûr de vouloir convertir tous les objets en pièces d'or? Les objets seront vendus pour {saleValue}% de leur valeur (sauf les objets d'échange). Les objets non-identifiés seront vendus à leur prix non-identifié (si disponible).",
"ls.lootName": "Nom du Marchant/Butin",
"ls.noAccesToSheet": "Vous n'avez pas accès à cette feuille de marchant/butin!",
"ls.inventory": "Inventaire",
"ls.biography": "Biographie",
"ls.currency": "Richesses",
"ls.add": "Ajouter",
"ls.createItem": "Créer un objet",
"ls.lootItem": "S'approprier l'objet",
"ls.buyItem": "Acheter l'objet",
"ls.editItem": "Modifier l'objet",
"ls.deleteItem": "Supprimer l'objet",
"ls.gmSettings": "Propriétés du MJ",
"ls.type": "Type",
"ls.typeInfo": "Butin: permet la distribution parmis les joueurs. Marchant: permet aux joueurs d'acheter des objets directement depuis la feuille.",
"ls.typeOfSheet": "Type de feuille",
"ls.typeLoot": "Butin",
"ls.typeMerchant": "Marchand",
"ls.permissions": "Permissions",
"ls.permissionsInfo": "Assurez-vous que les joueurs ont sélectionné un personnage via la configuration (clic droit sur le nom du joueur en bas à gauche).",
"ls.coinDistribution": "Distribution pièces",
"ls.each": "chacun",
"ls.splitBy": "Séparer en",
"ls.merchantSettings": "Propriétés du marchand",
"ls.merchantInfo": "Remplacer l'inventaire par un nombre d'objets tirés au hasard dans la table aléatoire. Spécifier le nom de la table aléatoire, la formule pour déterminer le nombre d'objets différents (Formule nbr. différents) et la formule pour déterminer la quantité pour chacun (Formule quantité).",
"ls.rollableTable": "Table aléatoire",
"ls.chooseTable": "-- Choisir table --",
"ls.shopQtyFormula": "Nombre (obj)",
"ls.itemQtyFormula": "Quantité (chq)",
"ls.updateShopInventory": "Mettre à jour l'inventaire",
"ls.splitcoins": " {quantity} {currency}",
"ls.receives": "{actor} reçoit:",
"ls.lsOptions": "Options",
"ls.enableDragging": "Activer dragging",
"ls.enableDraggingTooltip": "Un joueur peut cliquer et glisser un élément depuis le loot directement dans son inventaire. Soyez conscient que l'objet sera alors dupliqué, ne sera pas retiré du butin et aucun message ne sera affiché dans la conversation. Désactivé, les joueurs seront forcés d'utiliser l'action 'S'approprier'.",
"ls.maxCapacity": "Capacité max",
"ls.maxCapacityTooltip": "Nombre d'objets maximum dans le butin (vide ou 0 signifie aucune limite)",
"ls.maxLoad": "Charge max",
"ls.maxLoadTooltip": "Poids maximal qui peut être déposé dans le butin (vide ou 0 signifie aucune limite)",
"ls.saleValue": "Valeur de vente",
"ls.saleValueTooltip": "Le pourcentage de la valeur pour laquelle les biens non commerciaux seront vendus (vide signifie 50 %)",
"ls.displaySaleValue": "Afficher la valeur de vente",
"ls.displaySaleValueTooltip": "Si activé, affiche la valeur de vente ajustée à l'utilisateur.",
"ls.pp": "pp",
"ls.gp": "po",
"ls.sp": "pa",
"ls.cp": "pc",
"ls.wl_pp": "pp (sans poids)",
"ls.wl_gp": "po (sans poids)",
"ls.wl_sp": "pa (sans poids)",
"ls.wl_cp": "pc (sans poids)",
"ls.totalItems": "Nbr. éléments",
"ls.totalPrice": "Valeur totale",
"ls.totalWeight": "Poids total",
"ls.adjustedPrice": "Valeur de vente",
"ls.giveTitleSplit": "Diviser la quantité",
"ls.giveTitle": "Donner {item} à {actor}",
"ls.giveContent": "Donner combien?",
"ls.giveContentSingle": "Êtes-vous sûr de vouloir donner <em>{item}</em> à <b>{actor}</b>?",
"ls.lootTitle": "S'approprier {item}",
"ls.lootContent": "Êtes-vous sûr de vouloir vous approprier <em>{item}</em>?",
"ls.buyTitle": "Achter {item}",
"ls.buyContent": "Êtes-vous sûr de vouloir acheter <em>{item}</em>?",
"ls.convertToLoot": "Convertir en butin",
"ls.convertToLootUnlinked": "Convertir hors-combat (jetons) en butin"
}

View File

@@ -0,0 +1,142 @@
{
"SETTINGS.lsPurchaseChatMessageTitle": "Mostra messaggio di chat per gli acquisti?",
"SETTINGS.lsPurchaseChatMessageHint": "Se abilitato, un messaggio di chat mostrerà gli acquisti di oggetti dalla scheda.",
"SETTINGS.lsClearInventoryTitle": "Cancella Inventario?",
"SETTINGS.lsClearInventoryHint": "Se abilitato, tutti gli oggetti esistenti verranno rimossi dalla scheda prima di aggiungere nuovi oggetti dalla tabella dinamica. Se disabilitato, gli elementi esistenti rimarranno.",
"SETTINGS.lsChangeIconForSpellScrollsTitle": "Cambia icona per le Pergamene di Incantesimi?",
"SETTINGS.lsChangeIconForSpellScrollsHint": "Cambia l'icona per le pergamene di incantesimi in un'icona di pergamena. Se lasciato deselezionato, mantiene l'icona dell'incantesimo.",
"SETTINGS.lsRemoveEmptyStackTitle": "Elimina se vuoti",
"SETTINGS.lsRemoveEmptyStackHint": "Elimina gli oggetti la cui quantità è impostata su 0. Se disabilitato, gli articoli rimarranno con quantità pari a 0.",
"ERROR.lsItemInvalidQuantity": "Quantità oggetto non valida.",
"ERROR.lsChangingSettingsFor": "Errore modificando impostazioni per \"{name}\".",
"ERROR.lsNoRollableTableFound": "Nessuna tabella dinamica trovata con il nome \"{name}\".",
"ERROR.lsNoItemFound": "Trovato nessun oggetto \"{item}\".",
"ERROR.lsNoActiveGM": "Nessun GM attivo sulla tua scena, deve essere online e sulla stessa scena.",
"ERROR.lsPurchaseFromToken": "Devi comprare oggetti da un token.",
"ERROR.lsNoActiveCharacter": "Nessun personaggio attivo per l'utente.",
"ERROR.lsLootFromToken": "Devi raccogliere oggetti da un token.",
"ERROR.lsNotEnougFunds": "Fondi insufficienti per acquistare l'oggetto.",
"ERROR.lsLootAttempt": "Il giocatore ha tentato di raccogliere un oggetto da una differente scena.",
"ERROR.lsPurchaseAttempt": "Il giocatore ha tentato di acquistare un oggetto da una differente scena.",
"ERROR.lsChooseTable": "Prego scegliere una tabella.",
"ERROR.lsCurrencyConversionFailed": "Conversione della valuta fallita. Deve esserci un bug!",
"ERROR.lsNotAutorizedToAdd": "Non sei autorizzato ad aggiungere elementi che non possiedi!",
"ERROR.lsInvalidType": "Non puoi aggiungere questo tipo di elemento alla scheda!",
"ERROR.lsInvalidDrop": "Solo i GM possono rilasciare oggetti dai compendi!",
"ERROR.lsNotAutorizedToGive": "Non sei autorizzato a dare oggetti che non possiedi!",
"ERROR.lsWhyGivingToYourself": "Perché dovresti dare quell'oggetto a te stesso???",
"ERROR.lsGiveInvalidType": "Non puoi dare questo tipo di elemento!",
"ERROR.lsInvalidParentPermission": "Non funziona correttamente se l'autorizzazione predefinita non è 'Nessuno'. Si prega di correggere i permessi dell'attore!",
"ERROR.lsInvalidMove": "L'attore {actor} ha provato a vendere o rilasciare un oggetto da un token non collegato!",
"ls.quantity": "Quantità",
"ls.price": "Prezzo (in mo)",
"ls.accept": "Accetta",
"ls.cancel": "Cancella",
"ls.update": "Aggiorna",
"ls.purchase": "Acquista",
"ls.give": "Dona",
"ls.split": "Dividi",
"ls.loot": "Raccogli",
"ls.weapons": "Armi",
"ls.equipment": "Equipaggiamento",
"ls.consumables": "Consumabili",
"ls.lootType": "Bottino",
"ls.containerType": "Contenitori",
"ls.percentage": "Percentuale",
"ls.scrollof": "Pergamena di {name}",
"ls.chatLoot": "{buyer} ha raccolto {quantity} x {name}.",
"ls.chatLootCoins": "{buyer} ha raccolto {quantity} {currency}.",
"ls.chatPurchase": "{buyer} ha acquistato {quantity} x {name} per {cost} mo.",
"ls.chatSell": "{seller} ha venduto {quantity} x {item} per {price} mo. a {container}",
"ls.chatDrop": "{seller} ha rilasciato {quantity} x {item} in {container}",
"ls.chatGive": "{quantity} x {item} dati/spostati da {giver} a {receiver}.",
"ls.permissionNoaccess": "Nessuno (non si può accedere alla scheda)",
"ls.permissionLimited": "Limitato (si può accedere alla scheda senza poter fare azioni)",
"ls.permissionObserver": "Osservatore (si possono raccogliere/comprare oggetti e monete)",
"ls.batchUpdate": "Tutti i giocatori",
"ls.priceModifierTitle": "Modificatore Prezzo",
"ls.priceModifierTooltip": "Usa un fattore percentuale dove 100% è il prezzo corrente, 0% è 0, e 200% è il doppio del prezzo.",
"ls.priceModifierText": "Usa questo cursore per aumentare o diminuire il prezzo di tutti gli articoli in questo inventario.",
"ls.convertLootTitle": "Converti in Monete",
"ls.convertLootMessage": "Sei sicuro di voler convertire tutti gli oggetti in monete? Gli articoli saranno venduti al {saleValue}% del loro prezzo (eccetto la merce di scambio). Gli articoli non identificati verranno venduti in base al costo da non identificato.",
"ls.lootName": "Nome Mercante/Bottino",
"ls.noAccesToSheet": "Non hai accesso alla scheda di quel Bottino/Mercante!",
"ls.inventory": "Inventario",
"ls.biography": "Biografia",
"ls.currency": "Monete",
"ls.add": "Aggiungi",
"ls.createItem": "Crea oggetto",
"ls.lootItem": "Raccogli oggetto",
"ls.lootCoins": "Raccogli monete",
"ls.buyItem": "Compra oggetto",
"ls.editItem": "Modifica oggetto",
"ls.deleteItem": "Elimina oggetto",
"ls.gmSettings": "Impostazioni GM",
"ls.type": "Tipo",
"ls.typeInfo": "Boot: consente la distribuzione di monete tra i giocatori. Mercante: consente ai giocatori di acquistare oggetti direttamente dalla scheda.",
"ls.typeOfSheet": "Tipo di scheda",
"ls.typeLoot": "Bottino",
"ls.typeMerchant": "Mercante",
"ls.permissions": "Permessi",
"ls.permissionsInfo": "Assicurati che i giocatori abbiano selezionato un personaggio tramite il menu Configurazione giocatore (click tasto destro in basso a sinistra).",
"ls.coinDistribution": "Distribuzione Monete",
"ls.each": "ogni",
"ls.splitBy": "Dividi in",
"ls.merchantSettings": "Impostazioni Mercante",
"ls.merchantInfo": "Sostituisci l'inventario di questo mercante con un numero casuale di articoli da una tabella dinamica. Specificare il nome della tabella dinamica, insieme a una formula per il numero di articoli diversi da aggiungere (formula qtà negozio) e una formula per determinare la quantità di ciascun articolo da aggiungere (formula qtà articolo).",
"ls.rollableTable": "Tabella Dinamica",
"ls.chooseTable": "-- Scegli tabella --",
"ls.shopQtyFormula": "Formula qtà negozio",
"ls.itemQtyFormula": "Formula qtà articolo",
"ls.updateShopInventory": "Aggiorna inventario negozio",
"ls.splitcoins": " {quantity} {currency}",
"ls.receives": "{actor} riceve:",
"ls.lsOptions": "Opzioni",
"ls.enableDragging": "Abilita trascinamento",
"ls.enableDraggingTooltip": "Un giocatore può trascinare un oggetto dalla scheda. Fai attenzione perché l'oggetto non verrà rimosso dalla scheda e nessun messaggio verrà visualizzato in chat. Se disabilitato, i giocatori sono costretti a usare l'azione Raccogli per prendere qualcosa.",
"ls.maxCapacity": "Capacità Massima",
"ls.maxCapacityTooltip": "Massimo numero di oggetti nel bottino (vuoto o 0 = illimitato)",
"ls.maxLoad": "Carico Massimo",
"ls.maxLoadTooltip": "Massimo peso supportato dal bottino (vuoto o 0 = illimitato)",
"ls.saleValue": "Valore di vendita",
"ls.saleValueTooltip": "La percentuale di valore per cui verranno venduti i beni non commerciali (vuoto significa 50%)",
"ls.displaySaleValue": "Mostra il valore di vendita",
"ls.displaySaleValueTooltip": "Se abilitato, mostra all'utente il valore di vendita rettificato.",
"ls.pp": "mp",
"ls.gp": "mo",
"ls.sp": "ma",
"ls.cp": "mr",
"ls.wl_pp": "mp (senza peso)",
"ls.wl_gp": "mo (senza peso)",
"ls.wl_sp": "ma (senza peso)",
"ls.wl_cp": "mr (senza peso)",
"ls.totalItems": "Nr. Oggetti",
"ls.totalPrice": "Valore Totale",
"ls.totalWeight": "Peso Totale",
"ls.adjustedPrice": "Valore di vendita",
"ls.giveTitleSplit": "Dividi quantità",
"ls.giveTitle": "Dai {item} a {actor}",
"ls.giveContent": "Quanti?",
"ls.giveContentSingle": "Sei sicuro di voler dare <em>{item}</em> a <b>{actor}</b>?",
"ls.lootTitle": "Raccogli {item}",
"ls.lootContent": "Sei sicuro di voler raccogliere <em>{item}</em>?",
"ls.buyTitle": "Compra {item}",
"ls.buyContent": "Sei sicuro di voler comprare <em>{item}</em>?",
"ls.convertToLoot": "Converti in bottino",
"ls.convertToLootUnlinked": "Converti token sconfitti in bottino"
}

View File

@@ -0,0 +1,282 @@
/**
* Adapted for PF1 system from original module: https://github.com/jopeek/fvtt-loot-sheet-npc-5e
*/
import { LootSheetActions } from "./modules/actions.js";
import { LootSheetConstants } from "./modules/constants.js";
import { QuantityDialog } from "./modules/quantity-dialog.js";
// Module's entry point
Hooks.on("ready", async () => {
LootSheetConstants.LootSheetPf1NPC = (await import("./modules/lootsheet-npc.js")).LootSheetPf1NPC;
//Register the loot sheet
Actors.registerSheet("PF1", LootSheetConstants.LootSheetPf1NPC, {
types: ["npc"],
makeDefault: false
});
});
/**
* Register a hook
*/
Hooks.on('preCreateOwnedItem', (actor, item, data) => {
if (!actor) throw new Error(`Parent Actor ${actor._id} not found`);
// If the target actor is using the LootSheetPf1NPC then check in the item
if (actor.sheet instanceof LootSheetConstants.LootSheetPf1NPC) {
// validate the type of item to be "moved" or "added"
if(!["weapon","equipment","consumable","loot","container"].includes(item.type)) {
ui.notifications.error(game.i18n.localize("ERROR.lsInvalidType"));
return false;
}
}
});
/**
* Register drop action on actor
*/
Hooks.on('renderActorDirectory', (app, html, data) => {
function giveItemTo(actorDestId, event) {
event.preventDefault();
// try to extract the data
let data;
let extraData = {};
try {
data = JSON.parse(event.dataTransfer.getData('text/plain'));
if (data.type !== "Item") return;
} catch (err) {
return false;
}
const giver = game.actors.get(data.actorId)
const receiver = game.actors.get(actorDestId)
const item = giver.getEmbeddedDocument("Item", data.data._id);
if(!item) return;
// validate the type of item to be "moved" or "added"
if(!["weapon","equipment","consumable","loot"].includes(item.type)) {
ui.notifications.error(game.i18n.localize("ERROR.lsGiveInvalidType"));
return false;
}
let targetGm = null;
game.users.forEach((u) => {
if (u.isGM && u.active && u.viewedScene === game.user.viewedScene) {
targetGm = u;
}
});
if(!targetGm) return;
//if (data.actorId === actorDestId) {
// ui.notifications.error(game.i18n.localize("ERROR.lsWhyGivingToYourself"));
// console.log("Loot Sheet | Ignoring giving something to same person")
// return false;
//}
let options = {}
if (data.actorId === actorDestId) {
if(item.data.quantity == 1) {
ui.notifications.error(game.i18n.localize("ERROR.lsWhyGivingToYourself"));
console.log("Loot Sheet | Ignoring giving something to same person")
return false;
}
options['title'] = game.i18n.localize("ls.giveTitleSplit");
options['acceptLabel'] = game.i18n.localize("ls.split");
} else if(item.data.quantity == 1) {
options['title'] = game.i18n.localize("ls.give");
options['label'] = game.i18n.format("ls.giveContentSingle", {item: item.name, actor: receiver.name });
options['quantity'] = 1
options['acceptLabel'] = game.i18n.localize("ls.give");
} else {
options['title'] = game.i18n.format("ls.giveTitle", {item: item.name, actor: receiver.name });
options['label'] = game.i18n.localize("ls.giveContent");
options['acceptLabel'] = game.i18n.localize("ls.give");
}
// constants required to pass ad
const gmId = targetGm._id
const dta = data
let d = new QuantityDialog((quantity) => {
if( game.user.isGM ) {
LootSheetActions.giveItem(game.user, dta.actorId, actorDestId, dta.data._id, quantity)
} else {
const packet = {
type: "give",
userId: game.user._id,
actorId: dta.actorId,
itemId: dta.data._id,
targetActorId: actorDestId,
processorId: gmId,
quantity: quantity
};
console.log(`Loot Sheet | Sending packet to ${actorDestId}`)
game.socket.emit(LootSheetConstants.SOCKET, packet);
}
}, options);
d.render(true);
}
html.find('li.actor').each((i, li) => {
li.addEventListener("drop", giveItemTo.bind(this, li.getAttribute("data-entity-id")));
});
});
Hooks.once("init", () => {
loadTemplates([
"modules/lootsheetnpcpf1/template/npc-sheet-gmpart.html",
"modules/lootsheetnpcpf1/template/dialog-price-modifier.html"]);
Handlebars.registerHelper('ifeq', function(a, b, options) {
if (a == b) {
return options.fn(this);
}
return options.inverse(this);
});
game.settings.register(LootSheetConstants.MODULENAME, "changeScrollIcon", {
name: game.i18n.localize("SETTINGS.lsChangeIconForSpellScrollsTitle"),
hint: game.i18n.localize("SETTINGS.lsChangeIconForSpellScrollsHint"),
scope: "world",
config: true,
default: true,
type: Boolean
});
game.settings.register(LootSheetConstants.MODULENAME, "buyChat", {
name: game.i18n.localize("SETTINGS.lsPurchaseChatMessageTitle"),
hint: game.i18n.localize("SETTINGS.lsPurchaseChatMessageHint"),
scope: "world",
config: true,
default: true,
type: Boolean
});
game.settings.register(LootSheetConstants.MODULENAME, "clearInventory", {
name: game.i18n.localize("SETTINGS.lsClearInventoryTitle"),
hint: game.i18n.localize("SETTINGS.lsClearInventoryHint"),
scope: "world",
config: true,
default: false,
type: Boolean
});
game.settings.register(LootSheetConstants.MODULENAME, "removeEmptyStacks", {
name: game.i18n.localize("SETTINGS.lsRemoveEmptyStackTitle"),
hint: game.i18n.localize("SETTINGS.lsRemoveEmptyStackHint"),
scope: "world",
config: true,
default: true,
type: Boolean
});
/*******************************************
* SOCKET HANDLING!
*******************************************/
game.socket.on(LootSheetConstants.SOCKET, data => {
console.log("Loot Sheet | Socket Message: ", data);
if (game.user.isGM && data.processorId === game.user.id) {
let user = game.users.get(data.userId);
let sourceActor = game.actors.get(data.actorId);
let targetActor = data.tokenId ? canvas.tokens.get(data.tokenId).actor : game.actors.get(data.targetActorId);
if (data.type === "buy") {
if (sourceActor && targetActor) {
LootSheetActions.transaction(user, targetActor, sourceActor, data.itemId, data.quantity);
} else if (!targetActor) {
LootSheetActions.errorMessageToActor(sourceActor, game.i18n.localize("ERROR.lsNoActiveGM"))
ui.notifications.error(game.i18n.localize("ERROR.lsPurchaseAttempt"));
}
}
else if (data.type === "loot") {
if (sourceActor && targetActor) {
LootSheetActions.lootItem(user, targetActor, sourceActor, data.itemId, data.quantity);
} else if (!targetActor) {
LootSheetActions.errorMessageToActor(sourceActor, game.i18n.localize("ERROR.lsNoActiveGM"))
ui.notifications.error(game.i18n.localize("ERROR.lsLootAttempt"));
}
}
else if (data.type === "drop") {
if(sourceActor && targetActor) {
LootSheetActions.dropOrSellItem(user, targetActor, sourceActor, data.itemId)
}
}
else if (data.type === "give") {
LootSheetActions.giveItem(user, data.actorId, data.targetActorId, data.itemId, data.quantity);
}
}
if (data.type === "error" && data.targetId === game.user.actorId) {
console.log("Loot Sheet | Transaction Error: ", data.message);
return ui.notifications.error(data.message);
}
});
});
Hooks.on("getActorDirectoryEntryContext", (html, options) => {
options.push({
name: game.i18n.localize("ls.convertToLoot"),
icon: '<i class="fas fa-skull-crossbones"></i>',
callback: async function(li) {
const actor = game.actors.get(li.data("entityId"))
if(actor) {
await actor.setFlag("core", "sheetClass", "PF1.LootSheetPf1NPC");
let permissions = duplicate(actor.data.permission)
game.users.forEach((u) => {
if (!u.isGM) { permissions[u.id] = 2 }
});
await actor.update( { permission: permissions }, {diff: false});
}
},
condition: li => {
const actor = game.actors.get(li.data("entityId"))
return game.user.isGM && actor && actor.data.type === "npc" && !(actor.sheet instanceof LootSheetConstants.LootSheetPf1NPC) && actor.data.token.actorLink;
},
});
// Special case: actor is not linked => convert all defeated tokens!
options.push({
name: game.i18n.localize("ls.convertToLootUnlinked"),
icon: '<i class="fas fa-skull-crossbones"></i>',
callback: async function(li) {
const actor = game.actors.get(li.data("entityId"))
if(actor) {
let tokens = game.scenes.active.data.tokens.filter(o => o.actorId == actor.id)
tokens.forEach( async function(t) {
const effects = getProperty( t.actorData, "effects" )
// to be considered dead, a token must have the "dead" overlay effect (either from combat tracker or directly)
if( effects && effects.filter( e => [CONFIG.Combat.defeatedStatusId, "combat-utility-belt.dead"].indexOf(getProperty(e, "flags.core.statusId")) >= 0 ).length > 0) {
let actor = canvas.tokens.get(t._id).actor
if( !(actor.sheet instanceof LootSheetConstants.LootSheetPf1NPC) ) {
await actor.setFlag("core", "sheetClass", "PF1.LootSheetPf1NPC");
let permissions = duplicate(actor.data.permission)
game.users.forEach((u) => {
if (!u.isGM) { permissions[u.id] = 2 }
});
await actor.update( { permission: permissions }, {diff: false});
}
}
});
}
},
condition: li => {
const actor = game.actors.get(li.data("entityId"))
return game.user.isGM && actor && actor.data.type === "npc" && !(actor.sheet instanceof LootSheetConstants.LootSheetPf1NPC) && !actor.data.token.actorLink;
},
});
});

View File

@@ -0,0 +1,49 @@
{
"title": "Loot Sheet NPC Pathfinder1",
"description": "This module adds an additional NPC sheet which can be used for loot containers such as chests or shopkeepers.",
"version": "3.2.3",
"esmodules": [
"lootsheetnpcpf1.js"
],
"styles": [
"/css/lootsheetnpcpf1.css"
],
"languages": [
{
"lang": "en",
"name": "English",
"path": "lang/en.json",
"flags": {}
},
{
"lang": "fr",
"name": "French",
"path": "lang/fr.json",
"flags": {}
},
{
"lang": "it",
"name": "Italian",
"path": "lang/it.json",
"flags": {}
}
],
"socket": true,
"url": "https://github.com/Almightygir/fvtt-loot-sheet-npc-pf1",
"manifest": "https://github.com/Almightygir/fvtt-loot-sheet-npc-pf1/releases/latest/download/module.json",
"download": "https://github.com/Almightygir/fvtt-loot-sheet-npc-pf1/releases/download/v3.2.3/module.zip",
"id": "lootsheetnpcpf1",
"relationships": {
"systems": [
{
"id": "pf1",
"type": "system",
"compatibility": {}
}
]
},
"compatibility": {
"minimum": "9",
"verified": "9"
}
}

View File

@@ -0,0 +1,443 @@
/*************************
* Global static actions
*************************
*/
export class LootSheetActions {
/**
* Displays a message into the chat log
*/
static chatMessage(speaker, owner, message, item) {
if (game.settings.get("lootsheetnpcpf1", "buyChat")) {
if (item) {
message = `<div class="pf1 chat-card item-card" data-actor-id="${owner._id}" data-item-id="${item._id}">
<header class="card-header flexrow">
<img src="${item.img}" title="${item.showName}" width="36" height="36">
<h3 class="item-name">${item.showName}</h3>
</header>
<div class="card-content"><p>${message}</p></div></div>`;
} else {
message = `<div class="pf1 chat-card item-card" data-actor-id="${owner._id}">
<div class="card-content"><p>${message}</p></div></div>`;
}
ChatMessage.create({
user: game.user._id,
speaker: {
actor: speaker,
alias: speaker.name
},
content: message
});
}
}
/**
* Sends a error message to the target user
*/
static errorMessageToActor(target, message) {
game.socket.emit("module.lootsheetnpcpf1", {
type: "error",
targetId: target.id,
message: message
});
}
/**
* Moves an item from a source actor to a destination actor
*/
static moveItem(source, destination, itemId, quantity) {
//console.log("Loot Sheet | moveItem")
let item = source.getEmbeddedDocument("Item", itemId);
if(!item) {
ui.notifications.warn(game.i18n.format("ERROR.lsInvalidMove", { actor: source.name }));
console.log(source, destination, itemId)
return null;
}
item = item.data // migration to 0.8.x
if(!quantity) {
quantity = item.data.quantity
}
// Move all items if we select more than the quantity.
if (item.data.quantity < quantity) {
quantity = item.data.quantity;
}
let newItem = duplicate(item);
// remove unecessary flags
if(newItem.flags.lootsheetnpcpf1) {
delete(newItem.flags.lootsheetnpcpf1)
}
// decrease the quantity (unless infinite)
if(!item.flags.lootsheetnpcpf1 || !item.flags.lootsheetnpcpf1.infinite) {
const update = {
_id: itemId,
"data.quantity": item.data.quantity - quantity
};
let removeEmptyStacks = game.settings.get("lootsheetnpcpf1", "removeEmptyStacks");
if (update["data.quantity"] === 0 && removeEmptyStacks) {
source.deleteEmbeddedDocuments("Item", [itemId]);
} else {
source.updateEmbeddedDocuments("Item", [update]);
}
}
newItem.data.quantity = quantity;
destination.createEmbeddedDocuments("Item", [newItem]);
newItem.showName = LootSheetActions.getItemName(newItem)
newItem.showCost = LootSheetActions.getItemCost(newItem)
return {
item: newItem,
quantity: quantity
};
}
static spreadFunds(totalGP, funds) {
const gpBare = Math.floor(totalGP),
spLeftOver = (totalGP - gpBare) * 10,
spBare = Math.floor(spLeftOver),
cpLeftOver = (spLeftOver - spBare) * 10,
cpBare = Math.floor(cpLeftOver);
funds.gp += gpBare;
funds.sp += spBare;
funds.cp += cpBare;
return funds;
}
/**
* Moves coins from a source actor to a destination actor
*/
static moveCoins(source, destination, itemId, quantity) {
//console.log("Loot Sheet | moveCoins")
if(itemId.startsWith("wl_")) {
itemId = itemId.substring(3)
// Move all items if we select more than the quantity.
let coins = source.data.data.altCurrency[itemId]
if (coins < quantity) {
quantity = coins;
}
if (quantity == 0) return null;
const srcUpdate = { data: { altCurrency: { } } };
srcUpdate.data.altCurrency[itemId] = source.data.data.altCurrency[itemId] - quantity;
source.update(srcUpdate)
const dstUpdate = { data: { altCurrency: { } } };
dstUpdate.data.altCurrency[itemId] = destination.data.data.altCurrency[itemId] + quantity;
destination.update(dstUpdate)
}
else {
// Move all items if we select more than the quantity.
let coins = source.data.data.currency[itemId]
if (coins < quantity) {
quantity = coins;
}
if (quantity == 0) return null;
const srcUpdate = { data: { currency: { } } };
srcUpdate.data.currency[itemId] = source.data.data.currency[itemId] - quantity;
source.update(srcUpdate)
const dstUpdate = { data: { currency: { } } };
dstUpdate.data.currency[itemId] = destination.data.data.currency[itemId] + quantity;
destination.update(dstUpdate)
}
return {
quantity: quantity
};
}
/**
* A looter (target actor) takes an item from a container (source actor)
*/
static lootItem(speaker, container, looter, itemId, quantity) {
console.log("Loot Sheet | LootSheetActions.lootItem")
if (itemId.length == 2 || itemId.startsWith("wl_")) {
let moved = LootSheetActions.moveCoins(container, looter, itemId, quantity);
if (moved) {
LootSheetActions.chatMessage(
speaker, looter,
game.i18n.format("ls.chatLootCoins", { buyer: looter.name, quantity: moved.quantity, currency: game.i18n.localize("ls." + itemId) }));
}
}
else {
let moved = LootSheetActions.moveItem(container, looter, itemId, quantity);
if(!moved) return;
LootSheetActions.chatMessage(
speaker, looter,
game.i18n.format("ls.chatLoot", { buyer: looter.name, quantity: moved.quantity, name: moved.item.showName }),
moved.item);
}
}
/**
* A giver (source actor) drops or sells a item to a container (target actor)
*/
static async dropOrSellItem(speaker, container, giver, itemId) {
//console.log("Loot Sheet | Drop or sell item")
let moved = LootSheetActions.moveItem(giver, container, itemId);
if(!moved) return;
let messageKey = ""
let cost = moved.item.showCost;
if(container.getFlag("lootsheetnpcpf1", "lootsheettype") === "Merchant") {
messageKey = "ls.chatSell"
let sellerFunds = duplicate(giver.data.data.currency)
if(sellerFunds && moved.item.showCost > 0) {
if( moved.item.data.subType !== "tradeGoods" )
cost = cost / 2;
const totalGP = cost * moved.quantity;
sellerFunds = LootSheetActions.spreadFunds(totalGP, sellerFunds);
await giver.update({ "data.currency": sellerFunds });
}
} else {
messageKey = "ls.chatDrop"
}
LootSheetActions.chatMessage(
speaker, giver,
game.i18n.format(messageKey, { seller: giver.name, quantity: moved.quantity, price: cost * moved.quantity, item: moved.item.showName, container: container.name }),
moved.item);
}
/**
* Quick function to do a trasaction between a seller (source) and a buyer (target)
*/
static async transaction(speaker, seller, buyer, itemId, quantity) {
console.log("Loot Sheet | Transaction")
let sellItem = seller.getEmbeddedDocument("Item", itemId);
// If the buyer attempts to buy more then what's in stock, buy all the stock.
if (sellItem.data.quantity < quantity) {
quantity = sellItem.data.quantity;
}
let sellerModifier = seller.getFlag("lootsheetnpcpf1", "priceModifier");
if (!sellerModifier) sellerModifier = 1.0;
let itemCost = LootSheetActions.getItemCost(sellItem.data)
itemCost = itemCost * sellerModifier;
itemCost *= quantity;
let buyerFunds = duplicate(buyer.data.data.currency);
let buyerFundsAlt = duplicate(buyer.data.data.altCurrency);
const conversionRate = {
"pp": 10,
"gp": 1,
"sp": 0.1,
"cp": 0.01
};
let buyerFundsAsGold = 0;
let buyerFundsAsGoldAlt = 0;
for (let currency in buyerFunds) {
buyerFundsAsGold += Math.floor(buyerFunds[currency] * conversionRate[currency]);
}
for (let currency in buyerFundsAlt) {
buyerFundsAsGoldAlt += Math.floor(buyerFundsAlt[currency] * conversionRate[currency]);
}
if (itemCost > buyerFundsAsGold + buyerFundsAsGoldAlt) {
LootSheetActions.errorMessageToActor(buyer, game.i18n.localize("ERROR.lsNotEnougFunds"));
return;
}
const originalCost = itemCost;
// Update buyer's gold
// make sure that coins is a number (not a float)
while(!Number.isInteger(itemCost)) {
itemCost *= 10;
for (const key in conversionRate) {
conversionRate[key] *= 10
}
}
// cost can be paid with funds
if (itemCost <= buyerFundsAsGold) {
buyerFunds = LootSheetActions.removeCostFromFunds(buyer, itemCost, buyerFunds, conversionRate);
await buyer.update({ "data.currency": buyerFunds });
}
// cost must also be paid with weightless funds
else {
buyerFunds = LootSheetActions.removeCostFromFunds(buyer, buyerFundsAsGold, buyerFunds, conversionRate);
buyerFundsAlt = LootSheetActions.removeCostFromFunds(buyer, itemCost - buyerFundsAsGold, buyerFundsAlt, conversionRate);
await buyer.update({ "data.currency": buyerFunds, "data.altCurrency": buyerFundsAlt });
}
let moved = LootSheetActions.moveItem(seller, buyer, itemId, quantity);
if(moved) {
LootSheetActions.chatMessage(
speaker, buyer,
game.i18n.format("ls.chatPurchase", { buyer: buyer.name, quantity: quantity, name: moved.item.showName, cost: originalCost }),
moved.item);
}
}
/**
* Remove cost from actor's funds using provided conversionRate
*/
static removeCostFromFunds(buyer, cost, funds, conversionRate, DEBUG = false) {
if (DEBUG) console.log("Loot Sheet | Conversion rates: ");
if (DEBUG) console.log(conversionRate);
// remove funds from lowest currency to highest
let remainingFond = 0
for (const currency of Object.keys(conversionRate).reverse()) {
//console.log("Rate: " + conversionRate[currency])
if(conversionRate[currency] < 1) {
const ratio = 1/conversionRate[currency]
const value = Math.min(cost, Math.floor(funds[currency] / ratio))
if (DEBUG) console.log("Loot Sheet | BuyerFunds " + currency + ": " + funds[currency])
if (DEBUG) console.log("Loot Sheet | Ratio: " + ratio)
if (DEBUG) console.log("Loot Sheet | Value: " + value)
cost -= value
funds[currency] -= value * ratio
} else {
const value = Math.min(cost, Math.floor(funds[currency] * conversionRate[currency]))
cost -= value
const lost = Math.ceil( value / conversionRate[currency] )
funds[currency] -= lost
remainingFond += lost * conversionRate[currency] - value
if (DEBUG) console.log("Loot Sheet | Value+: " + value)
if (DEBUG) console.log("Loot Sheet | Lost+: " + lost)
if (DEBUG) console.log("Loot Sheet | RemainingFond+: " + remainingFond)
}
}
if(cost > 0) {
LootSheetActions.errorMessageToActor(buyer, game.i18n.localize("ERROR.lsCurrencyConversionFailed"));
ui.notifications.error(game.i18n.localize("ERROR.lsCurrencyConversionFailed"));
throw "Couldn't remove from funds"
}
//console.log("RemainingFond: " + remainingFond)
if(remainingFond > 0) {
for (const currency of Object.keys(conversionRate)) {
if (conversionRate[currency] <= remainingFond) {
funds[currency] += Math.floor(remainingFond / conversionRate[currency]);
remainingFond = remainingFond % conversionRate[currency];
if (DEBUG) console.log("Loot Sheet | funds " + currency + ": " + funds[currency]);
if (DEBUG) console.log("Loot Sheet | remainingFond: " + remainingFond);
}
}
}
if(remainingFond > 0) {
LootSheetActions.errorMessageToActor(buyer, game.i18n.localize("ERROR.lsCurrencyConversionFailed"));
return ui.notifications.error(game.i18n.localize("ERROR.lsCurrencyConversionFailed"));
throw "Couldn't remove from funds"
}
if (DEBUG) console.log(funds)
return funds;
}
/**
* Actor gives something to another actor
*/
static giveItem(speaker, giverId, receiverId, itemId, quantity) {
quantity = Number(quantity) // convert to number (just in case)
let giver = game.actors.get(giverId);
let receiver = game.actors.get(receiverId);
let giverUser = null;
game.users.forEach((u) => {
if (u.character && u.character._id === giverId) {
giverUser = u;
}
});
if(quantity <= 0) {
return;
}
if (giver && receiver) {
let moved = LootSheetActions.moveItem(giver, receiver, itemId, quantity);
if(moved) {
LootSheetActions.chatMessage(
speaker, receiver,
game.i18n.format("ls.chatGive", {giver: giver.data.name, receiver: receiver.data.name, quantity: quantity, item: moved.item.showName}),
moved.item);
}
} else {
console.log("Loot Sheet | Give operation failed because actors (giver or receiver) couldn't be found!");
}
}
/**
* Returns the unidentified name (if unidentified and specified) or the name
*/
static getItemName(item) {
if(!item) return ""
else return item.data.identified || !item.data.unidentified || !item.data.unidentified.name || item.data.unidentified.name.length == 0 ? item.name : item.data.unidentified.name
}
/**
* Returns the unidentified cost (if unidentified and specified) or the cost
*/
static getItemCost(item)
{
if(!item)
{
return 0
}
else
{
return Number(item.data.identified || item.data.unidentified == null ? item.data.price : item.data.unidentified.price)
}
}
/**
* Returns the sale value of an item
*/
static getItemSaleValue(item, saleValue)
{
if(!item)
{
return 0;
}
if(item.type == "container")
{
let total = LootSheetActions.getItemCost(item) * saleValue;
if(item.data.inventoryItems)
{
item.data.inventoryItems.forEach(i => total += LootSheetActions.getItemSaleValue(i, saleValue));
}
return total;
}
else if (["weapon", "equipment", "consumable", "tool", "loot"].indexOf(item.type) >= 0)
{
if( item.data.subType !== "tradeGoods" )
{
return LootSheetActions.getItemCost(item) * saleValue;
}
return LootSheetActions.getItemCost(item);
}
return 0;
}
}

View File

@@ -0,0 +1,9 @@
export class LootSheetConstants {
static MODULENAME = "lootsheetnpcpf1"
static SOCKET = "module.lootsheetnpcpf1";
static LootSheetPf1NPC;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
export class QuantityDialog extends Dialog {
constructor(callback, options) {
if (typeof(options) !== "object") {
options = {};
}
let applyChanges = false;
const chooseQuantity = 'quantity' in options ? "" : '<input type=number min="1" id="quantity" name="quantity" value="1">'
super({
title: 'title' in options ? options['title'] : game.i18n.localize("ls.quantity"),
content: `
<form>
<div class="form-group">
<label>${'label' in options ? options['label'] : game.i18n.localize("ls.quantity")}</label>
${chooseQuantity}
</div>
</form>`,
buttons: {
yes: {
icon: "<i class='fas fa-check'></i>",
label: options.acceptLabel ? options.acceptLabel : game.i18n.localize("ls.accept"),
callback: () => applyChanges = true
},
no: {
icon: "<i class='fas fa-times'></i>",
label: game.i18n.localize("ls.cancel")
},
},
default: "yes",
close: () => {
if (applyChanges) {
var quantity = Number('quantity' in options ? options['quantity'] : document.getElementById('quantity').value)
if (isNaN(quantity)) {
console.log("Loot Sheet | Item quantity invalid");
return ui.notifications.error(game.i18n.localize("ERROR.lsItemInvalidQuantity"));
}
callback(quantity);
}
}
});
}
}

View File

@@ -0,0 +1,17 @@
<p>
{{localize "ls.priceModifierText"}}
<i class='fa fa-question-circle' title='{{localize "ls.priceModifierTooltip"}}'></i>
</p>
<p>
<input name="price-modifier-percent" id="price-modifier-percent" type="range" min="0" max="200" value="{{priceModifier}}" class="slider">
</p>
<p>
<label>{{localize "ls.percentage"}}:</label> <input type=number min="0" max="200" value="{{priceModifier}}" id="price-modifier-percent-display">
</p>
<script>
var pmSlider = document.getElementById("price-modifier-percent");
var pmDisplay = document.getElementById("price-modifier-percent-display");
pmDisplay.value = pmSlider.value;
pmSlider.oninput = function() { pmDisplay.value = this.value; };
pmDisplay.oninput = function() { pmSlider.value = this.value; };
</script>

View File

@@ -0,0 +1,105 @@
<h3 class="gm-section">{{localize "ls.gmSettings"}}</h3>
<!-- GM SETTINGS -->
<div class="gm-settings" data-group="sidebar" data-tab="gm-settings">
<h3 class="gm-header"><i class="fas fa-id-card"></i> {{localize "ls.type"}} <i class="fas fa-info-circle help" onclick="$('.sheet-type-info').toggle();"></i></h3>
<div class="sheet-type-info">{{localize "ls.typeInfo"}}</div>
<div class="sheet-types">
<div class="flexrow">
<div class="flexcol"><h4 class="sheet-name">{{localize "ls.typeOfSheet"}}:</h4></div>
<div class="flexcol">
<select class="sheet-type" name="flags.lootsheetnpcpf1.lootsheettype">
{{#select flags.lootsheetnpcpf1.lootsheettype}}
<option value="Loot">{{localize "ls.typeLoot"}}</option>
<option value="Merchant">{{localize "ls.typeMerchant"}}</option>
{{/select}}
</select>
</div>
</div>
</div>
<h3 class="gm-header"><i class="fas fa-users"></i> {{localize "ls.permissions"}} <i class="fas fa-info-circle help" onclick="$('.permission-info').toggle();"></i></h3>
<div class="permission-info">{{localize "ls.permissionsInfo"}}</div>
{{#if flags.loot.warning}}
<div class="warning">{{localize "ERROR.lsInvalidParentPermission"}}</div>
{{/if}}
{{#unless flags.loot.warning}}
<ol class="permissions-list">
{{#each flags.loot.players as |player p|}}
<li class="permission">
<input type="hidden" name="{{player.playerId}}" value="{{player.lootPermission}}" data-dtype="Number" actor="{{player.actorId}}"/>
<a class="permission-proficiency" title="{{player.lootPermissionDescription}}">{{{player.icon}}}</a>
<h4 class="permission-name">{{player.actor}} ({{player.name}})</h4>
</li>
{{/each}}
<div class="batch-update">{{localize "ls.batchUpdate"}}
<a class="permission-batch" title="{{localize "ls.permissionNoaccess"}}" data-perm="0"><i class="far fa-circle"></i></a>
<a class="permission-batch" title="{{localize "ls.permissionLimited"}}" data-perm="1"><i class="fas fa-eye"></i></a>
<a class="permission-batch" title="{{localize "ls.permissionObserver"}}" data-perm="2"><i class="fas fa-check"></i></a>
</div>
</ol>
{{/unless}}
{{#ifeq lootsheettype "Loot"}}
<h3 class="gm-header"><i class="fas fa-tools"></i> {{localize "ls.lsOptions"}}</h3>
<div class="flexrow">
<div class="flexcol"><h4>{{localize "ls.enableDragging"}} <i class="fas fa-info-circle help" title="{{localize "ls.enableDraggingTooltip"}}"></i></h4></div>
<div class="flexcol"><input name="data.flags.lootsheetnpcpf1.dragEnabled" type="checkbox" value="{{flags.lootsheetnpcpf1.dragEnabled}}" {{#if flags.lootsheetnpcpf1.dragEnabled}}checked{{/if}} /></div>
</div>
<div class="flexrow">
<div class="flexcol"><h4>{{localize "ls.maxCapacity"}} <i class="fas fa-info-circle help" title="{{localize "ls.maxCapacityTooltip"}}"></i></h4></div>
<div class="flexcol"><input name="data.flags.lootsheetnpcpf1.maxCapacity" type="text" data-dtype="Number" placeholder="e.g. 10" value="{{flags.lootsheetnpcpf1.maxCapacity}}"/></div>
</div>
<div class="flexrow">
<div class="flexcol"><h4>{{localize "ls.maxLoad"}} <i class="fas fa-info-circle help" title="{{localize "ls.maxLoadTooltip"}}"></i></h4></div>
<div class="flexcol"><input name="data.flags.lootsheetnpcpf1.maxLoad" type="text" data-dtype="Number" placeholder="e.g. 200" value="{{flags.lootsheetnpcpf1.maxLoad}}"/></div>
</div>
<div class="flexrow">
<div class="flexcol"><h4>{{localize "ls.saleValue"}}<i class="fas fa-info-circle help" title="{{localize "ls.saleValueTooltip"}}"></i></h4></div>
<div class="flexcol"><input name="data.flags.lootsheetnpcpf1.saleValue" type="text" data-dtype="Number" placeholder="e.g. 50" value="{{flags.lootsheetnpcpf1.saleValue}}"/></div>
</div>
<div class="flexrow">
<div class="flexcol"><h4>{{localize "ls.displaySaleValue"}} <i class="fas fa-info-circle help" title="{{localize "ls.displaySaleValueTooltip"}}"></i></h4></div>
<div class="flexcol"><input name="data.flags.lootsheetnpcpf1.displaySaleValueEnabled" type="checkbox" value="{{flags.lootsheetnpcpf1.displaySaleValueEnabled}}" {{#if flags.lootsheetnpcpf1.displaySaleValueEnabled}}checked{{/if}} /></div>
</div>
<h3 class="gm-header"><i class="fas fa-coins"></i> {{localize "ls.coinDistribution"}}</h3>
<ol class="coins-list">
{{#each flags.loot.currency as |c i|}}
<li class="denomination {{i}}">
<label>{{ lookup ../config.currencies i }}:</label>
<h4 class="denomination-value">{{c}} {{localize "ls.each"}}</h4>
</li>
{{/each}}
</ol>
<button class= "split-coins" type="split-coins" name="split-coins" value="1"><i class="fa fa-coins"></i> {{localize "ls.splitBy"}} {{flags.loot.ownerCount}}</button>
{{/ifeq}}
{{#ifeq lootsheettype "Merchant"}}
<h3 class="gm-header"><i class="fas fa-balance-scale"></i> {{localize "ls.merchantSettings"}} <i class="fas fa-info-circle help" onclick="$('.merchant-settings-info').toggle();"></i></h3>
<div class="merchant-settings-info">{{localize "ls.merchantInfo"}}</div>
<div class="merchant-settings">
<div class="flexrow">
<div class="flexcol"><h4>{{localize "ls.rollableTable"}}: </h4></div>
<div class="flexcol">
<select class="sheet-rolltable" name="flags.lootsheetnpcpf1.rolltable">
<option value="">{{localize "ls.chooseTable"}}</option>
{{#select flags.lootsheetnpcpf1.rolltable}}
{{#each rolltables as |table i|}}
<option value="{{table.name}}">{{table.name}}</option>
{{/each}}
{{/select}}
</select>
</div>
</div>
<div class="flexrow">
<div class="flexcol"><h4>{{localize "ls.shopQtyFormula"}}: </h4></div>
<div class="flexcol"><input name="flags.lootsheetnpcpf1.shopQty" type="text" data-dtype="String" placeholder="e.g. 1d20" value="{{flags.lootsheetnpcpf1.shopQty}}"/></div>
</div>
<div class="flexrow">
<div class="flexcol"><h4>{{localize "ls.itemQtyFormula"}}: </h4></div>
<div class="flexcol"><input name="flags.lootsheetnpcpf1.itemQty" type="text" data-dtype="String" placeholder="e.g. 1d4" value="{{flags.lootsheetnpcpf1.itemQty}}"/></div>
</div>
</div>
<button class="update-inventory" type="update-inventory" name="update-inventory" value="1"><i class="fas fa-balance-scale"></i> {{localize "ls.updateShopInventory"}} </button>
{{/ifeq}}
</div>

View File

@@ -0,0 +1,194 @@
<form class="pf1 {{cssClass}}" autocomplete="off">
<!-- HEADER -->
<header class="sheet-header flexrow">
<h1 class="charname">
<input name="name" type="text" value="{{actor.name}}" placeholder="{{localize "ls.lootName"}}" />
</h1>
{{#if isGM}}
{{#ifeq lootsheettype "Merchant"}}
<div class="charbutton">
<button class="price-modifier" type="price-modifier" name="price-modifier" value=""><i class="fa fa-balance-scale"></i> {{localize "ls.priceModifierTitle"}}</button>
</div>
{{/ifeq}}
{{#ifeq lootsheettype "Loot"}}
<div class="charbutton">
<button class="convert-loot" type="convert-loot" name="convert-loot" value=""><i class="fa fa-coins"></i> {{localize "ls.convertLootTitle"}}</button>
</div>
{{/ifeq}}
{{/if}}
</header>
<section class="sheet-lower flexrow">
<!-- SIDEBAR -->
<section class="sheet-sidebar sidebar">
<div class="sheet-profile-img">
{{#if isGM}}<img class="sheet-profile-small" src="{{actor.img}}" title="{{actor.name}}" data-edit="img" />{{/if}}
{{#unless isGM}}<img class="sheet-profile" src="{{actor.img}}" title="{{actor.name}}" data-edit="img" />{{/unless}}
</div>
{{#if isGM}} {{> "modules/lootsheetnpcpf1/template/npc-sheet-gmpart.html"}} {{/if}}
</section>
<!-- BODY -->
<section class="sheet-content content">
{{#unless actor.visible}}
<span class="warning">{{localize "ls.noAccesToSheet"}}</span>
{{/unless}}
{{#if actor.visible}}
<div class="flexcol active">
<nav class="sheet-navigation tabs" data-group="primary">
<a class="item active" data-tab="inventory">{{localize "ls.inventory"}}</a>
<a class="item" data-tab="biography">{{localize "ls.biography"}}</a>
</nav>
<section class="primary-body">
<div class="tab biography" data-tab="biography" data-group="primary">
{{editor content=data.details.biography.value target="data.details.biography.value" button=true owner=owner editable=editable}}
</div>
<div class="tab inventory active" data-tab="inventory" data-group="primary">
<!-- FEATURES -->
<div class="features" data-group="primary" data-tab="features">
{{#ifeq lootsheettype "Loot"}}
<div class="inventory-filters">
<ol class="currency flexrow">
<h3>
{{localize "PF1.Currency"}}
</h3>
{{#each data.currency as |v k|}}
<label class="denomination {{k}}">{{ lookup ../config.currencies k }}</label>
<input type="text" name="data.currency.{{k}}" value="{{v}}" data-dtype="Number"/>
<label class="item currency-controls" data-item-id="{{k}}">
{{#if ../canAct}}
{{#unless ../../isGM}}
<a class="currency-controls item-control item-loot" title="{{localize "ls.lootCoins"}}"><i class="fas fa-gem"></i></a>
{{/unless}}
{{/if}}
</label>
{{/each}}
</ol>
<ol class="currency flexrow">
<h3>
{{localize "PF1.WeightlessCurrency"}}
</h3>
{{#each data.altCurrency as |v k|}}
<label class="denomination {{k}}">{{ lookup ../config.currencies k }}</label>
<input type="text" name="data.altCurrency.{{k}}" value="{{v}}" data-dtype="Number"/>
<label class="item currency-controls" data-item-id="wl_{{k}}">
{{#if ../canAct}}
{{#unless ../../isGM}}
<a class="currency-controls item-control item-loot" title="{{localize "ls.lootCoins"}}"><i class="fas fa-gem"></i></a>
{{/unless}}
{{/if}}
</label>
{{/each}}
</ol>
</div>
{{/ifeq}}
<ul class="inventory-list">
{{#each actor.features as |section sid|}}
<li class="inventory-header flexrow">
<h3 class="item-name flexrow">{{section.label}}</h3>
{{#if ../isGM}}
<div class="item-detail item-identified"><i class="icon icon-quill-ink large" title="{{localize "PF1.Identified"}}"></i></div>
{{/if}}
<div class="item-detail item-weight"><i class="icon icon-weight large" src="systems/pf1/icons/actions/weight.svg" title="{{localize "PF1.Weight"}}"></i></div>
<div class="item-detail item-weight"><i class="fas fa-coins large" title="{{localize "ls.price"}}"></i></div>
<div class="item-controls">
{{#if ../isGM}}
<a class="item-control item-create" title="{{localize "ls.createItem"}}" data-type="{{section.type}}">
<i class="fas fa-plus"></i> {{localize "ls.add"}}
</a>
{{/if}}
</div>
</li>
<ol class="item-list">
{{#each section.items as |item iid|}}
<li class="item flexrow" data-item-id="{{item._id}}" data-item-quantity="{{item.data.quantity}}">
<div class="item-name flexrow rollable">
<div class="item-image" style="background-image: url({{item.img}})"></div>
<h4 class="rollable{{#if item.empty}} strikethrough-text{{/if}}">{{ lootsheetname item.name item.data.quantity item.flags.lootsheetnpcpf1.infinite}}</h4>
</div>
{{#if ../../isGM}}
<div class="item-detail item-identified">
<a class="item-control item-identify"><span>{{{item.labels.identified}}}</span></a>
</div>
{{/if}}
<div class="item-detail item-weight"><span>{{ lootsheetweight item.data.quantity item.data.weightConverted }} {{ ../../weightUnit }}</span></div>
<div class="item-detail item-weight"><span>{{ lootsheetprice item.showPrice ../../priceModifier }}<span></div>
<div class="item-controls">
{{#ifeq ../../lootsheettype "Loot"}}
{{#if ../../canAct}}
{{#unless ../../isGM}}
{{#if data.quantity}}
<a class="item-control item-loot" title="{{localize "ls.lootItem"}}"><i class="fas fa-gem"></i></a>
{{/if}}
{{/unless}}
{{/if}}
{{/ifeq}}
{{#ifeq ../../lootsheettype "Merchant"}}
{{#if ../../canAct}}
{{#unless ../../isGM}}
{{#if data.quantity}}
<a class="item-control item-buy" title="{{localize "ls.buyItem"}}"><i class="fas fa-dollar-sign"></i></a>
{{/if}}
{{/unless}}
{{/if}}
{{/ifeq}}
{{#if ../../isGM}}
<a class="item-control item-visibility" title="{{localize "ls.itemToggleVisibility"}}">
{{#if item.flags.lootsheetnpcpf1.secret}}<i class="fas fa-eye-slash"></i>{{/if}}
{{#unless item.flags.lootsheetnpcpf1.secret}}<i class="fas fa-eye"></i>{{/unless}}
</a>
{{#unless item.flags.lootsheetnpcpf1.infinite}}
<a class="item-control item-quantity-add"><i class="fas fa-plus"></i></a>
<a class="item-control item-quantity-subtract"><i class="fas fa-minus"></i></a>
<a class="item-control item-quantity-infinite"><i class="fas fa-infinity"></i></a>
{{/unless}}
{{#if item.flags.lootsheetnpcpf1.infinite}}
<a class="item-control item-quantity-infinite enabled"><i class="fas fa-infinity"></i></a>
{{/if}}
<a class="item-control item-edit" title="{{localize "ls.editItem"}}"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="{{localize "ls.deleteItem"}}"><i class="fas fa-trash"></i></a>
{{/if}}
</div>
</li>
{{/each}}
</ol>
{{/each}}
</ul>
</div>
{{#ifeq lootsheettype "Loot"}}
<div class="form-group totals">
<div class="item-count {{itemsWarning}}">
<i class="fas fa-box"> {{localize "ls.totalItems"}}:</i> {{totalItems}} {{maxItems}}
</div>
<div class="item-weight {{weightWarning}}">
<i class="fas fa-weight-hanging"> {{localize "ls.totalWeight"}}:</i> {{totalWeight}} {{maxWeight}} {{weightUnit}}
</div>
<div class="item-price">
<i class="fas fa-coins"> {{localize "ls.totalPrice"}}:</i> {{totalPrice}}
</div>
{{#if data.flags.lootsheetnpcpf1.displaySaleValueEnabled}}
<div class="adjusted-price">
<i class="fas fa-coins"> {{localize "ls.adjustedPrice"}}:</i> {{adjustedPrice}}
</div>
{{/if}}
</div>
{{/ifeq}}
</div>
</section>
</div>
{{/if}}
</section>
</section>
</form>