diff --git a/css/bol.css b/css/bol.css index 7b7786d..bf1ff90 100644 --- a/css/bol.css +++ b/css/bol.css @@ -524,7 +524,12 @@ ul.no-bullets { } .items-list .item-name-fixed-medium { min-width: 8rem; - width: 8rem; + width: 8rem; +} +.items-list .item-field-fixed-short { + max-width: 3rem; + min-width: 3rem; + width: 3rem; } /* ----------------------------------------- */ /* Premade colors */ @@ -1063,3 +1068,6 @@ body.system-bol img#logo { .character-summary-container { opacity: 0.95; } +.character-summary-rollable { + text-decoration: underline; +} diff --git a/lang/fr.json b/lang/fr.json index 35aa50d..2874cb5 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -172,6 +172,16 @@ "BOL.ui.boleffects": "Effets (automatiques)", "BOL.ui.modifier": "Modificateur", "BOL.ui.effects": "Effets en cours", + "BOL.ui.pcname": "PJs", + "BOL.ui.npcname": "PNJs", + "BOL.ui.pclistbutton": "Vue compacte", + "BOL.ui.noactorfound": "PNJ inconnu, le PNJ doit être présent dans le monde pour s'afficher ici.", + "BOL.ui.deletetitle": "Suppression", + "BOL.ui.confirmdelete": "Vous êtes sûr de vouloir supprimer cet item ?", + "BOL.ui.nomorealchemypoints": "Plus assez de Points de Création !", + "BOL.ui.armornoformula": "L'armure {protect.name} n'a pas de formule pour la protection !", + "BOL.ui.selectactor": "Selectionnez votre personnage pour utiliser la macro", + "BOL.ui.itemnotfound": "Impossible de trouver l'objet de cette macro", "BOL.featureCategory.origins": "Origines", "BOL.featureCategory.races": "Races", diff --git a/module/actor/actor-sheet.js b/module/actor/actor-sheet.js index b497f95..ed21d5a 100644 --- a/module/actor/actor-sheet.js +++ b/module/actor/actor-sheet.js @@ -94,8 +94,8 @@ export class BoLActorSheet extends ActorSheet { // Delete Inventory Item html.find('.item-delete').click(ev => { Dialog.confirm({ - title: "Suppression", - content: `Vous êtes sûr de vouloir supprimer cet item ?`, + title: game.i18n.localize("BOL.ui.deletetitle"), + content: game.i18n.localize("BOL.ui.confirmdelete"), yes: () => { const li = $(ev.currentTarget).parents(".item"); this.actor.deleteEmbeddedDocuments("Item", [li.data("itemId")]) diff --git a/module/actor/actor.js b/module/actor/actor.js index 51bba89..be99c2d 100644 --- a/module/actor/actor.js +++ b/module/actor/actor.js @@ -343,7 +343,7 @@ export class BoLActor extends Actor { getDamageAttributeValue(attrDamage) { let attrDamageValue = 0 if (attrDamage.includes("vigor")) { - attrDamageValue = actor.system.attributes.vigor.value + attrDamageValue = this.system.attributes.vigor.value if (attrDamage.includes("half")) { attrDamageValue = Math.floor(attrDamageValue / 2) } @@ -405,7 +405,7 @@ export class BoLActor extends Actor { newPC = alchemy.system.properties.pccurrent + pcCost await this.updateEmbeddedDocuments('Item', [{ _id: alchemy.id, 'system.properties.pccurrent': newPC }]) } else { - ui.notifications.warn("Plus assez de Points de Création !") + ui.notifications.warn( game.i18n.localize("BOL.ui.nomorealchemypoints") ) } } } @@ -638,13 +638,13 @@ export class BoLActor extends Actor { } else if (protect.system.subtype == 'armor') { if (BoLUtility.getRollArmor()) { if (!protect.system.properties.soak.formula || protect.system.properties.soak.formula == "") { - ui.notifications.warn(`L'armure ${protect.name} n'a pas de formule pour la protection !`) + ui.notifications.warn( game.i18n.localize("BOL.ui.armornoformula", protect.name) ) } else { formula += "+" + " max(" + protect.system.properties.soak.formula + ",0)" } } else { if (protect.system.properties.soak.value == undefined) { - ui.notifications.warn(`L'armure ${protect.name} n'a pas de valeur fixe pour la protection !`) + ui.notifications.warn( game.i18n.localize("BOL.ui.armornoformula", protect.name) ) } else { formula += "+ " + protect.system.properties.soak.value } diff --git a/module/bol.js b/module/bol.js index 28b8f93..0b07158 100644 --- a/module/bol.js +++ b/module/bol.js @@ -16,6 +16,7 @@ import { BoLTokenHud } from "./system/bol-action-hud.js" import { BoLHotbar } from "./system/bol-hotbar.js" import { BoLAdventureGenerator } from "./system/bol-adventure-generator.js" import { BoLCommands} from "./system/bol-commands.js" +import { BoLCharacterSummary} from "./system/bol-character-summary.js" /* -------------------------------------------- */ Hooks.once('init', async function () { @@ -117,7 +118,10 @@ function welcomeMessage() { /* -------------------------------------------- */ Hooks.once('ready', async function () { + BoLUtility.ready() + BoLCharacterSummary.ready() + registerUsageCount('bol') diff --git a/module/system/bol-character-summary.js b/module/system/bol-character-summary.js index e9548b3..78ae0e7 100644 --- a/module/system/bol-character-summary.js +++ b/module/system/bol-character-summary.js @@ -7,22 +7,28 @@ export class BoLCharacterSummary extends Application { /* -------------------------------------------- */ static displayPCSummary(){ - let pcList = new BoLCharacterSummary() - pcList.render(true) + game.bol.charSummary.render(true) } /* -------------------------------------------- */ static createSummaryPos() { return { top: 200, left: 200 }; } + + /* -------------------------------------------- */ + static ready() { + let charSummary = new BoLCharacterSummary() + game.bol.charSummary = charSummary + } /* -------------------------------------------- */ constructor() { if ( !game.user.isGM ) { // Uniquement si GM return; } - super(); + //game.settings.set("world", "character-summary-data", {npcList: [], x:0, y:0}) + this.settings = game.settings.get("world", "character-summary-data") } /* -------------------------------------------- */ @@ -31,6 +37,7 @@ export class BoLCharacterSummary extends Application { template: "systems/bol/templates/apps/character-summary-template.html", popOut: true, resizable: true, + dragDrop: [{ dragSelector: ".items-list .item", dropSelector: null }], classes: ["bol", "dialog"], width: 820, height: 'fit-content' }) } @@ -40,16 +47,62 @@ export class BoLCharacterSummary extends Application { let formData = super.getData(); formData.pcs = game.actors.filter( ac => ac.type == "character" && ac.hasPlayerOwner ) + formData.npcs = [] + let newList = [] + let toUpdate = false + for( let actorId of this.settings.npcList ) { + let actor = game.actors.get(actorId) + if (actor) { + formData.npcs.push( actor ) + newList.push(actorId) + } else { + toUpdate = true + } + } formData.config = game.bol.config + if ( toUpdate ) { + this.settings.npcList = newList + //console.log("Going to update ...", this.settings) + game.settings.set("world", "character-summary-data", this.settings) + } + return formData } + /* -------------------------------------------- */ + updateNPC() { + game.settings.set("world", "character-summary-data", game.bol.charSummary.settings) + game.bol.charSummary.close() + setTimeout( function() { game.bol.charSummary.render(true)}, 500) + } + + /* -------------------------------------------- */ + async _onDrop(event) { + //console.log("Dragged data are : ", dragData) + let data = event.dataTransfer.getData('text/plain') + let dataItem = JSON.parse( data) + let actor = fromUuidSync(dataItem.uuid) + if (actor) { + game.bol.charSummary.settings.npcList.push( actor.id ) + game.bol.charSummary.updateNPC() + + } else { + ui.notifications.warn( game.i18n.localize("BOL.ui.noactorfound") ) + } + } + /* -------------------------------------------- */ /** @override */ async activateListeners(html) { super.activateListeners(html); + html.find('.actor-open').click((event) => { + const li = $(event.currentTarget).parents(".item") + const actor = game.actors.get(li.data("actor-id")) + actor.sheet.render(true) + }) + html.find('.summary-roll').click((event) => { const li = $(event.currentTarget).parents(".item") const actor = game.actors.get(li.data("actor-id")) @@ -61,6 +114,15 @@ export class BoLCharacterSummary extends Application { BoLRoll.aptitudeCheck(actor, key, event) } }) + + html.find('.actor-delete').click(event => { + const li = $(event.currentTarget).parents(".item"); + let actorId = li.data("actor-id") + let newList = game.bol.charSummary.settings.npcList.filter(id => id != actorId) + game.bol.charSummary.settings.npcList = newList + game.bol.charSummary.updateNPC() + }) + } } \ No newline at end of file diff --git a/module/system/bol-hotbar.js b/module/system/bol-hotbar.js index 2909547..1b86d01 100644 --- a/module/system/bol-hotbar.js +++ b/module/system/bol-hotbar.js @@ -48,12 +48,12 @@ export class BoLHotbar { if (speaker.token) actor = game.actors.tokens[speaker.token] if (!actor) actor = game.actors.get(speaker.actor) if (!actor) { - return ui.notifications.warn(`Selectionnez votre personnage pour utiliser la macro`) + return ui.notifications.warn( game.i18n.localize("BOL.ui.selectactor") ) } let item = actor.items.find(it => it.name === itemName && it.type == itemType) if (!item ) { - return ui.notifications.warn(`Impossible de trouver l'objet de cette macro`) + return ui.notifications.warn( game.i18n.localize("BOL.ui.itemnotfound") ) } // Trigger the item roll if (item.system.category === "equipment" && item.system.subtype === "weapon") { diff --git a/module/system/bol-utility.js b/module/system/bol-utility.js index 5fbec48..afeb6ff 100644 --- a/module/system/bol-utility.js +++ b/module/system/bol-utility.js @@ -28,6 +28,13 @@ export class BoLUtility { type: Boolean, onChange: lang => window.location.reload() }) + game.settings.register("world", "character-summary-data", { + name: "character-summary-data", + scope: "world", + config: false, + default: { npcList : [], x: 200, y: 200}, + type: Object + }) game.settings.register("bol", "logoActorSheet", { name: "Chemin du logo des fiches de perso", hint: "Vous pouvez changer le logo BoL des fiches de perso, pour jouer dans un autre univers (idéalement 346 x 200, défaut : /systems/bol/ui/logo.webp)", @@ -69,11 +76,12 @@ export class BoLUtility { static getLogoTopLeft() { return this.logoTopLeft } - + /* -------------------------------------------- */ static async ready() { //$("#logo").attr("src", this.getLogoTopLeft() ) - $("#logo").css("content",`url(${this.getLogoTopLeft()})`) + $("#logo").css("content", `url(${this.getLogoTopLeft()})`) + } /* -------------------------------------------- */ @@ -271,7 +279,7 @@ export class BoLUtility { let attackId = event.currentTarget.attributes['data-attack-id'].value let defenseMode = event.currentTarget.attributes['data-defense-mode'].value let weaponId = (event.currentTarget.attributes['data-weapon-id']) ? event.currentTarget.attributes['data-weapon-id'].value : -1 - + // Remove message for all let msgId = BoLUtility.findChatMessageId(event.currentTarget) if (game.user.isGM) { @@ -287,7 +295,7 @@ export class BoLUtility { if (!game.user.isGM) { return } - BoLUtility.removeChatMessageId( msgId ) + BoLUtility.removeChatMessageId(msgId) console.log("Damage Handling", attackId, defenseMode, weaponId) // Only GM process this let attackDef = this.attackStore[attackId] @@ -334,10 +342,10 @@ export class BoLUtility { let defenderUser for (let user of game.users) { - if ( user.character && user.character.id == defender.id ) { + if (user.character && user.character.id == defender.id) { defenderUser = user } - } + } let damageResults = { attackId: attackDef.id, attacker: attackDef.attacker, @@ -534,31 +542,29 @@ export class BoLUtility { } /* -------------------------------------------- */ - static async confirmDelete(actorSheet, li) { - let itemId = li.data("item-id"); - let msgTxt = "
Are you sure to remove this Item ?"; - let buttons = { - delete: { - icon: '', - label: "Yes, remove it", - callback: () => { - actorSheet.actor.deleteEmbeddedDocuments("Item", [itemId]); - li.slideUp(200, () => actorSheet.render(false)); - } - }, - cancel: { - icon: '', - label: "Cancel" - } - } - msgTxt += "
"; - let d = new Dialog({ - title: "Confirm removal", - content: msgTxt, - buttons: buttons, - default: "cancel" - }); - d.render(true); + static async loadCompendiumData(compendium) { + const pack = game.packs.get(compendium); + return await pack?.getDocuments() ?? []; } + /* -------------------------------------------- */ + static async loadCompendium(compendium, filter = item => true) { + let compendiumData = await this.loadCompendiumData(compendium); + return compendiumData.filter(filter); + } + + /* -------------------------------------------- */ + static async searchItem(dataItem) { + let item + if (dataItem.pack) { + let id = dataItem.id || dataItem._id + let items = await this.loadCompendium(dataItem.pack, item => item.id == id) + item = items[0] || undefined + } else { + item = game.items.get(dataItem.id) + } + return item + } + + } diff --git a/module/system/hooks.js b/module/system/hooks.js index c50c97f..01be958 100644 --- a/module/system/hooks.js +++ b/module/system/hooks.js @@ -75,4 +75,18 @@ export default function registerHooks() { } return false; }); + + /********************************************************************************** */ + Hooks.on("renderActorDirectory", (app, html, data) => { + if (game.user.isGM) { + const button = document.createElement('button'); + button.style.width = '95%'; + button.innerHTML = game.i18n.localize("BOL.ui.pclistbutton") + button.addEventListener('click', () => { + game.bol.charSummary.render(true) + }) + html.find('.header-actions').after(button) + } + }) + } diff --git a/system.json b/system.json index 8c11302..941a684 100644 --- a/system.json +++ b/system.json @@ -14,7 +14,7 @@ ], "url": "https://www.uberwald.me/gitea/public/bol", "license": "LICENSE.txt", - "version": "10.4.3", + "version": "10.4.4", "compatibility": { "minimum": "10", "verified": "10", @@ -203,7 +203,7 @@ ], "socket": true, "manifest": "https://www.uberwald.me/gitea/public/bol/raw/v10/system.json", - "download": "https://www.uberwald.me/gitea/public/bol/archive/bol-v10.4.3.zip", + "download": "https://www.uberwald.me/gitea/public/bol/archive/bol-v10.4.4.zip", "background": "systems/images/map_lemurie.webp", "gridDistance": 1.5, "gridUnits": "m", diff --git a/templates/apps/character-summary-template.html b/templates/apps/character-summary-template.html index dd1395d..78e4c71 100644 --- a/templates/apps/character-summary-template.html +++ b/templates/apps/character-summary-template.html @@ -3,30 +3,80 @@