{ "name": "Clients", "type": "script", "command": "// =========================================================\n// 1. RECUPERATION DES CLIENTS\n// =========================================================\nconst clients = canvas.scene.tokens.filter(token =>\n token.actor.hasPlayerOwner === false &&\n token.actor.type === \"pnj\" &&\n token.actor.system.categorie === \"Client\"\n);\n\nif (clients.length === 0) {\n ui.notifications.warn(\"Aucun Client trouvé.\");\n return;\n}\n\n// =========================================================\n// 2. CONSTRUCTION DU CODE HTML (avec onglets et panel)\n// =========================================================\nlet tabsHtml = `
`;\nlet panelsHtml = ``;\n\n// =========================================================\n// 3. POUR CHAQUE CLIENT\n// =========================================================\nclients.forEach((client, index) => {\n const sys = client.actor.system || {};\n \n // ---------------------------\n // Bouton d'onglet\n // ---------------------------\n tabsHtml += `\n \n `;\n // ---------------------------\n // PERSONNAGE\n // ---------------------------\n const espece = sys.espece ?? \"humain\";\n const role = sys.role ?? \"\";\n const resume = sys.resume ?? \"\";\n const courage = sys.defense.courage.delta ?? \"\";\n \n // ---------------------------\n // SANTE\n // ---------------------------\n const pvVal = sys.sante?.pv?.value ?? 0;\n const pvMax = sys.sante?.pv?.max ?? 0;\n const dv = sys.sante?.dv ?? \"1d6\";\n\n // ---------------------------\n // ATTAQUES\n // ---------------------------\n const armureDelta = sys.defense.armure.delta;\n const armureProtectionStockee = sys.defense.armure.resultatProtection;\n const attaques = sys.attaques;\n let attaquesHtml = null;\n if(attaques.length > 0) {\n attaquesHtml = `\n
\n

Attaques

\n `;\n attaques.forEach(attaque => {\n attaquesHtml += `\n
\n
\n Arme\n

${attaque.nom}

\n
\n
\n Dégats\n

${attaque.degats}

\n
\n
\n `;\n });\n attaquesHtml += `
`;\n }\n \n // ---------------------------\n // SORTS\n // ---------------------------\n const sorts = client.actor.items?.filter(item => item.type === \"sortilege\")\n let sortsHtml = \"\";\n if(sorts.length > 0) {\n sortsHtml = `\n
\n

SORTILEGES

\n `;\n \n sorts.forEach(sort => {\n sortsHtml += `\n
\n
\n Nom\n

${sort.name}

\n
\n
\n Effet\n

${sort.system.effet}

\n
\n
\n `;\n });\n sortsHtml += `
`;\n } \n\n // ---------------------------\n // CAPACITES\n // ---------------------------\n const capacites = client.actor.items?.filter(item => item.type === \"capacite\")\n let capacitesHtml = \"\";\n if(capacites.length > 0) {\n capacitesHtml = `\n
\n

CAPACITES

\n `;\n \n capacites.forEach(capacite => {\n capacitesHtml += `\n
\n
\n Nom\n

${capacite.name}

\n
\n
\n Cout\n

${capacite.system.cout}

\n
\n
\n Effet\n

${capacite.system.effet}

\n
\n
\n `;\n });\n capacitesHtml += `
`;\n }\n\n \n // ---------------------------\n // CONSTITUER LE HTML COMPLET\n // ---------------------------\n panelsHtml += `\n
\n
\n
\n Espèce\n

${espece}

\n
\n
\n Rôle\n

${role}

\n
\n
\n DV\n

${dv}

\n
\n
\n PV\n

${pvVal} / ${pvMax}

\n
\n
\n Courage\n

Δ${courage}

\n
\n
\n
\n
\n resume\n

${resume}

\n
\n
\n\n ${attaquesHtml}\n\n
\n

Protection

\n
\n
\n Armure\n

${armureDelta}

\n
\n
\n Protection stockée\n

${armureProtectionStockee}

\n
\n
\n
\n \n ${sortsHtml}\n \n ${capacitesHtml}\n \n
`;\n});\n\ntabsHtml += `
`;\n\nlet content = `\n
\n
\n

Les Clients

\n ${tabsHtml}\n
\n ${panelsHtml}\n
\n
\n
\n`;\n\n// =========================================================\n// 4. AFFICHE DE LA BOITE DE DIALOGUE\n// =========================================================\nconst dialog = await foundry.applications.api.DialogV2.wait({\n window: {\n title: \"Les Clients\",\n icon: \"fa-solid fa-shield-halved\"\n },\n content: content,\n classes: [\"fvtt-donjon-et-cie\"],\n buttons: [\n {\n action: \"close\",\n label: \"Fermer\",\n icon: \"fas fa-xmark\",\n callback: () => ({action: \"Fermer\"})\n } \n ],\n rejectClose: false,\n render: (event, dialog) => {\n const root = dialog.element;\n \n const triggers = root.querySelectorAll('.custom-tab-trigger');\n const panels = root.querySelectorAll('.custom-pc-panel');\n \n const setActiveTab = (activeId) => {\n triggers.forEach(btn => {\n const pcId = btn.getAttribute('data-pc-id');\n if (pcId === activeId) {\n btn.style.setProperty('background', '#8b2e17', 'important');\n btn.style.setProperty('color', '#ffffff', 'important');\n btn.style.setProperty('border-color', '#561d0e', 'important');\n } else {\n btn.style.setProperty('background', 'rgba(226, 208, 177, 0.6)', 'important');\n btn.style.setProperty('color', '#221b18', 'important');\n btn.style.setProperty('border-color', '#561d0e', 'important');\n }\n });\n \n panels.forEach(panel => {\n const panelId = panel.getAttribute('id');\n if (panelId === `panel-pc-${activeId}`) {\n panel.style.setProperty('display', 'block', 'important');\n } else {\n panel.style.setProperty('display', 'none', 'important');\n }\n });\n };\n \n if (triggers.length > 0) {\n const firstId = triggers[0].getAttribute('data-pc-id');\n setActiveTab(firstId);\n }\n \n triggers.forEach(btn => {\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n const pcId = btn.getAttribute('data-pc-id');\n setActiveTab(pcId);\n });\n });\n }, \n submit: (result) => {}\n});", "img": "icons/environment/people/cleric-grey.webp", "author": "eibNkxM8PO50SgGM", "scope": "global", "folder": null, "flags": {}, "_stats": { "compendiumSource": null, "duplicateSource": null, "exportSource": { "worldId": "donjon-et-cie", "uuid": "Macro.JHKPpJNz2LP5YDUd", "coreVersion": "13.351", "systemId": "fvtt-donjon-et-cie", "systemVersion": "14.0.14" }, "coreVersion": "13.351", "systemId": "fvtt-donjon-et-cie", "systemVersion": "14.0.14", "createdTime": 1780430930887, "modifiedTime": 1780468322761, "lastModifiedBy": "eibNkxM8PO50SgGM" }, "ownership": { "default": 0 } }