Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a152ad11ba | |||
| befb8e97c2 | |||
| 6f3996d216 | |||
| 48660c9430 | |||
| 0b88e53d77 | |||
| 2c73108f63 | |||
| 8718cfff05 |
+52
-2
@@ -104,7 +104,6 @@
|
||||
"DNC.Dialog.InitiativeIntro": "<strong>{actorName}</strong> lance l'initiative.",
|
||||
"DNC.Dialog.InitiativeCurrent": "DEX actuelle : <strong>{dex}</strong>, bonus de fiche : <strong>{initiativeBonus}</strong>",
|
||||
"DNC.Dialog.CharacteristicUsed": "Caracteristique utilisee",
|
||||
"DNC.Dialog.ActorDamageBonus": "Bonus de degats de l'acteur",
|
||||
"DNC.Dialog.DamageCappedByDv": "Le DV martial actuel ({dv}) plafonne cette arme : {base} devient {damage}.",
|
||||
"DNC.Dialog.SpellAutoDisadvantage": "Le cout depasse le rang du lanceur : le jet se fera automatiquement avec desavantage.",
|
||||
"DNC.Dialog.UseUsageDie": "Utiliser <strong>{itemName}</strong> et lancer son de d'usage actuel.",
|
||||
@@ -205,5 +204,56 @@
|
||||
"DNC.Chat.DamageUsageStable": "L'arme tient bon, ses degats restent inchanges.",
|
||||
"DNC.Chat.DamageUsageExhausted": "L'arme est epuisee, elle ne peut plus causer de degats.",
|
||||
"DNC.UI.DamageExhausted": "Epuise",
|
||||
"DNC.Warn.DamageExhausted": "Cette arme est epuisee et ne peut plus causer de degats."
|
||||
"DNC.Warn.DamageExhausted": "Cette arme est epuisee et ne peut plus causer de degats.",
|
||||
|
||||
"DNC.Dialog.EmployeesTitle": "Employés",
|
||||
|
||||
"DNC.Dialog.EmployeesTabEmployes": "Employés",
|
||||
"DNC.Dialog.EmployeesTabCombat": "Combat",
|
||||
"DNC.Dialog.EmployeesTabCharacteristics": "Caractéristiques",
|
||||
"DNC.Dialog.EmployeesTabMagie": "Magie",
|
||||
"DNC.Dialog.EmployeesTabClients": "Clients",
|
||||
|
||||
"DNC.Empty.NoEmployees": "Aucun employé trouvé.",
|
||||
|
||||
"DNC.UI.Weapons": "Armes",
|
||||
"DNC.UI.Armors": "Armures",
|
||||
"DNC.UI.Spells": "Sortilèges",
|
||||
"DNC.UI.Capacities": "Capacités",
|
||||
|
||||
"DNC.UI.Employee": "Employé",
|
||||
"DNC.UI.Dv": "DV",
|
||||
"DNC.UI.MeleeAttacks": "Attaques CàC",
|
||||
"DNC.UI.RangedAttacks": "Attaques Dist.",
|
||||
|
||||
"DNC.UI.Damage": "Dégâts",
|
||||
"DNC.UI.Range": "Portée",
|
||||
"DNC.UI.Ammunition": "Munitions",
|
||||
"DNC.UI.ProtectionDie": "Protection Δ",
|
||||
"DNC.UI.Encumbrance": "Encombrement",
|
||||
"DNC.UI.RemainingProtection": "Protection restante",
|
||||
"DNC.UI.Notes": "Notes",
|
||||
"DNC.UI.Description": "Description",
|
||||
|
||||
"DNC.UI.Rank": "Rang",
|
||||
"DNC.UI.Focus": "Focus",
|
||||
"DNC.UI.Chaos": "Chaos",
|
||||
|
||||
"DNC.WeaponCategory.Melee": "Corps à corps",
|
||||
"DNC.WeaponCategory.Ranged": "Distance",
|
||||
"DNC.WeaponHands.Label": "Mains",
|
||||
"DNC.WeaponHands.One": "1 main",
|
||||
"DNC.WeaponHands.Two": "2 mains",
|
||||
"DNC.WeaponRange.Contact": "Contact",
|
||||
"DNC.Ammunition.Exhausted": "Épuisées",
|
||||
|
||||
"DNC.Empty.NoWeapons": "Aucune arme répertoriée.",
|
||||
"DNC.Empty.NoArmors": "Aucune armure répertoriée.",
|
||||
"DNC.Empty.NoSpells": "Aucun sortilège répertorié.",
|
||||
"DNC.Empty.NoCapacities": "Aucune capacité répertoriée.",
|
||||
"DNC.Empty.NoClients": "Aucun client répertorié.",
|
||||
|
||||
"DNC.Client.Species": "Espèce",
|
||||
"DNC.Client.Category": "Catégorie",
|
||||
"DNC.Client.Role": "Rôle"
|
||||
}
|
||||
|
||||
@@ -21,6 +21,16 @@
|
||||
gap: @spacing-md;
|
||||
}
|
||||
|
||||
// Réduction de la taille des champs PV
|
||||
.dnc-actor-sheet .hp-field .counter-field input[type="number"] {
|
||||
max-width: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dnc-actor-sheet .hp-field .counter-field {
|
||||
gap: @spacing-xs;
|
||||
}
|
||||
|
||||
.dnc-actor-sheet .profile-card-wide {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
+32
-5
@@ -44,7 +44,7 @@
|
||||
}
|
||||
|
||||
.chat-card-kicker {
|
||||
margin: 0 0 0.25rem;
|
||||
margin: 0 0 @spacing-xs;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.16em;
|
||||
@@ -189,7 +189,7 @@
|
||||
}
|
||||
|
||||
.chat-details li + li {
|
||||
margin-top: 0.25rem;
|
||||
margin-top: @spacing-xs;
|
||||
}
|
||||
|
||||
.chat-actions {
|
||||
@@ -225,9 +225,36 @@
|
||||
.chat-targeting {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
display: flex;
|
||||
gap: @spacing-sm;
|
||||
margin-top: @spacing-sm;
|
||||
flex-wrap: wrap;
|
||||
align-items: end;
|
||||
|
||||
.chat-action-button {
|
||||
padding: 0.35rem 0.65rem;
|
||||
min-height: 1.75rem;
|
||||
font-size: 0.82rem;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
// Boutons Appliquer et Avec Armure sur une seule ligne
|
||||
.dnc-chat-card-damage .chat-actions-inline {
|
||||
flex-wrap: nowrap;
|
||||
gap: @spacing-xs;
|
||||
}
|
||||
|
||||
.dnc-chat-card-damage .chat-actions-inline .chat-action-button {
|
||||
padding: 0.3rem 0.55rem;
|
||||
min-height: 1.65rem;
|
||||
font-size: 0.78rem;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.dnc-chat-card-damage .chat-actions-inline .chat-action-button i {
|
||||
font-size: 0.85rem;
|
||||
margin-right: 0.2rem;
|
||||
}
|
||||
|
||||
.chat-control {
|
||||
@@ -255,7 +282,7 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 2rem;
|
||||
padding: 0.25rem 0.7rem;
|
||||
padding: @spacing-xs 0.7rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid fade(@color-border, 38%);
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
@@ -417,7 +444,7 @@
|
||||
}
|
||||
|
||||
.chat-chaos-result-title {
|
||||
margin: 0 0 0.25rem;
|
||||
margin: 0 0 @spacing-xs;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
@import "item-sheet";
|
||||
@import "dialogs";
|
||||
@import "chat";
|
||||
@import "employes-dialog";
|
||||
|
||||
@@ -0,0 +1,394 @@
|
||||
// ============================================
|
||||
// Dialog Employés - Styles
|
||||
// Structure 2 niveaux : Employés/Clients → sous-onglets par PC/client
|
||||
// ============================================
|
||||
|
||||
// Conteneur principal
|
||||
.dnc-employes-dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: @spacing-md;
|
||||
padding: @spacing-lg;
|
||||
min-width: 640px;
|
||||
max-width: 90vw;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
|
||||
.sheet-header {
|
||||
display: block;
|
||||
grid-template-columns: none;
|
||||
gap: normal;
|
||||
|
||||
h1 {
|
||||
font-family: @font-display;
|
||||
font-size: 1.4rem;
|
||||
color: @color-accent;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper pour DialogV2
|
||||
.dnc-employes-dialog-wrapper {
|
||||
.dialog-content,
|
||||
.window-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// Cacher le footer (bouton requis par l'API mais inutile visuellement)
|
||||
.dialog-footer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Onglets racine (niveau 1)
|
||||
// ============================================
|
||||
.dnc-root-tabs {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: @spacing-md;
|
||||
border-bottom: 2px solid @color-border;
|
||||
padding-bottom: @spacing-sm;
|
||||
}
|
||||
|
||||
.dnc-root-tab {
|
||||
border: 1px solid fade(@color-border, 55%);
|
||||
border-radius: @radius-md @radius-md 0 0;
|
||||
background: @color-panel-strong;
|
||||
color: @color-ink;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 700;
|
||||
padding: @spacing-sm @spacing-lg;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: @spacing-xs;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
i { font-size: 0.9rem; }
|
||||
|
||||
&.active {
|
||||
background: @color-accent;
|
||||
border-color: darken(@color-accent, 12%);
|
||||
color: #fff;
|
||||
box-shadow: 0 -3px 8px fade(@color-shadow, 20%);
|
||||
position: relative;
|
||||
bottom: -2px;
|
||||
}
|
||||
|
||||
&:hover:not(.active) {
|
||||
background: fade(@color-panel-strong, 120%);
|
||||
border-color: fade(@color-border, 75%);
|
||||
}
|
||||
}
|
||||
|
||||
// Panneaux racine
|
||||
.dnc-root-panels {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dnc-root-panel {
|
||||
display: none;
|
||||
|
||||
&.active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Sous-onglets (niveau 2 — par PC ou client)
|
||||
// ============================================
|
||||
.dnc-pc-tabs {
|
||||
display: flex;
|
||||
gap: @spacing-xs;
|
||||
flex-wrap: wrap;
|
||||
padding: @spacing-sm 0;
|
||||
border-bottom: 1px solid fade(@color-border, 40%);
|
||||
margin-bottom: @spacing-md;
|
||||
}
|
||||
|
||||
.dnc-pc-tab {
|
||||
border: 1px solid fade(@color-border, 45%);
|
||||
border-radius: @radius-sm;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
color: @color-muted;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
padding: @spacing-xs @spacing-md;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
white-space: nowrap;
|
||||
|
||||
&.active {
|
||||
background: @color-accent;
|
||||
border-color: darken(@color-accent, 10%);
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
&:hover:not(.active) {
|
||||
background: fade(@color-panel-strong, 110%);
|
||||
color: @color-ink;
|
||||
}
|
||||
}
|
||||
|
||||
// Panneaux par PC / client
|
||||
.dnc-pc-panels {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dnc-pc-panel,
|
||||
.dnc-client-panel {
|
||||
display: none;
|
||||
|
||||
&.active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Fiche compacte par employé (3 sections)
|
||||
// ============================================
|
||||
.dnc-compact-section {
|
||||
padding: @spacing-md;
|
||||
margin-bottom: @spacing-sm;
|
||||
border: 1px solid fade(@color-border, 40%);
|
||||
border-radius: @radius-md;
|
||||
background: @color-panel;
|
||||
|
||||
& + .dnc-compact-section {
|
||||
margin-top: @spacing-sm;
|
||||
}
|
||||
}
|
||||
|
||||
.dnc-compact-section-title {
|
||||
font-family: @font-display;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 700;
|
||||
color: @color-accent;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
margin: 0 0 @spacing-sm;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: @spacing-xs;
|
||||
border-bottom: 1px solid fade(@color-border, 35%);
|
||||
padding-bottom: @spacing-xs;
|
||||
|
||||
i { font-size: 0.85rem; }
|
||||
}
|
||||
|
||||
.dnc-compact-concept {
|
||||
font-size: 0.8rem;
|
||||
color: @color-muted;
|
||||
font-style: italic;
|
||||
margin: @spacing-xs 0 0;
|
||||
}
|
||||
|
||||
// Grille de caractéristiques compacte
|
||||
.dnc-compact-carac-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: @spacing-sm;
|
||||
}
|
||||
|
||||
.dnc-carac-stat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
min-width: 48px;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border: 1px solid fade(@color-border, 40%);
|
||||
border-radius: @radius-sm;
|
||||
padding: @spacing-xs @spacing-sm;
|
||||
}
|
||||
|
||||
.dnc-carac-label {
|
||||
font-size: 0.68rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
color: @color-muted;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.dnc-carac-value {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: @color-ink;
|
||||
|
||||
&.warning {
|
||||
color: @color-failure;
|
||||
}
|
||||
}
|
||||
|
||||
// Combat stats badges
|
||||
.dnc-compact-combat-stats {
|
||||
display: flex;
|
||||
gap: @spacing-sm;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: @spacing-sm;
|
||||
}
|
||||
|
||||
.dnc-combat-badge {
|
||||
font-size: 0.82rem;
|
||||
padding: @spacing-xs @spacing-sm;
|
||||
background: @color-panel-strong;
|
||||
border: 1px solid fade(@color-border, 40%);
|
||||
border-radius: @radius-sm;
|
||||
color: @color-ink;
|
||||
}
|
||||
|
||||
// Listes d'items compactes
|
||||
.dnc-compact-item-list {
|
||||
margin-top: @spacing-sm;
|
||||
}
|
||||
|
||||
.dnc-compact-subhead {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
color: @color-muted;
|
||||
margin: 0 0 @spacing-xs;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: @spacing-xs;
|
||||
|
||||
i { color: @color-accent; }
|
||||
}
|
||||
|
||||
.dnc-compact-item {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: @spacing-xs;
|
||||
padding: @spacing-xs 0;
|
||||
border-top: 1px dashed fade(@color-border, 35%);
|
||||
font-size: 0.85rem;
|
||||
|
||||
&:first-of-type {
|
||||
border-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dnc-compact-item-name {
|
||||
font-weight: 600;
|
||||
color: @color-ink;
|
||||
}
|
||||
|
||||
.dnc-compact-item-detail {
|
||||
font-size: 0.78rem;
|
||||
color: @color-muted;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border-radius: @radius-sm;
|
||||
padding: 0.05rem 0.3rem;
|
||||
}
|
||||
|
||||
// Stats magie compactes
|
||||
.dnc-compact-magic-stats {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: @spacing-sm;
|
||||
margin-bottom: @spacing-sm;
|
||||
}
|
||||
|
||||
// Réutilisation de .item-meta pour les badges de sortilège/capacité
|
||||
.item-meta {
|
||||
border-radius: 999px;
|
||||
background: @color-panel-strong;
|
||||
color: @color-ink;
|
||||
font-size: 0.75rem;
|
||||
padding: 0.1rem 0.5rem;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Fiche client dans sous-panneau
|
||||
// ============================================
|
||||
.client-summary {
|
||||
margin: @spacing-sm 0 0;
|
||||
color: @color-ink;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.client-description {
|
||||
margin-top: @spacing-md;
|
||||
padding-top: @spacing-md;
|
||||
border-top: 1px solid fade(@color-border, 45%);
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
color: @color-muted;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ============================================
|
||||
// Roll buttons dans vue clients
|
||||
// ============================================
|
||||
.dnc-roll-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
padding: 0.1rem 0.5rem;
|
||||
font-size: 0.78rem;
|
||||
font-family: @font-body;
|
||||
color: @color-ink;
|
||||
background: @color-panel-strong;
|
||||
border: 1px solid fade(@color-border, 60%);
|
||||
border-radius: @radius-sm;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
|
||||
i { font-size: 0.7rem; color: @color-accent; }
|
||||
|
||||
&:hover {
|
||||
background: @color-accent;
|
||||
color: #fff;
|
||||
border-color: @color-accent;
|
||||
i { color: #fff; }
|
||||
}
|
||||
}
|
||||
|
||||
.dnc-carac-rollable {
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
border-radius: @radius-sm;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background: fade(@color-accent, 18%);
|
||||
.dnc-carac-label { color: @color-accent; }
|
||||
}
|
||||
}
|
||||
|
||||
// Bouton ouvrir fiche dans les titres de section
|
||||
.dnc-compact-section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
|
||||
.dnc-open-sheet-btn {
|
||||
margin-left: auto;
|
||||
background: none;
|
||||
border: 1px solid fade(@color-border, 50%);
|
||||
border-radius: @radius-sm;
|
||||
color: @color-muted;
|
||||
cursor: pointer;
|
||||
font-size: 0.7rem;
|
||||
padding: 0.1rem 0.35rem;
|
||||
line-height: 1;
|
||||
transition: color 0.15s, border-color 0.15s;
|
||||
|
||||
&:hover {
|
||||
color: @color-accent;
|
||||
border-color: @color-accent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
@color-failure: #842c2c;
|
||||
@color-shadow: rgba(0, 0, 0, 0.22);
|
||||
|
||||
@spacing-xs: 0.25rem;
|
||||
@spacing-sm: 0.4rem;
|
||||
@spacing-md: 0.75rem;
|
||||
@spacing-lg: 1rem;
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,363 @@
|
||||
/**
|
||||
* Donjon & Cie - Systeme FoundryVTT
|
||||
*
|
||||
* Fenêtre de dialogue pour afficher les employés (PJ)
|
||||
* Structure : 2 onglets racine (Employés / Clients),
|
||||
* avec sous-onglets par PC ou par client.
|
||||
*
|
||||
* @author LeRatierBretonnien
|
||||
* @copyright 2025–2026 LeRatierBretonnien
|
||||
* @license CC BY-NC-SA 4.0
|
||||
*/
|
||||
|
||||
import { DonjonEtCieUtility } from "../donjon-et-cie-utility.mjs";
|
||||
import { DONJON_ET_CIE } from "../donjon-et-cie-config.mjs";
|
||||
|
||||
export class DonjonEtCieEmployesDialog {
|
||||
/**
|
||||
* Ouvre la fenêtre des employés
|
||||
*/
|
||||
static async open() {
|
||||
const pcs = this.#getPlayerCharacters();
|
||||
const clientTokens = this.#getClients();
|
||||
const characteristicKeys = this.#getCharacteristicKeys();
|
||||
|
||||
const pcsData = await Promise.all(
|
||||
pcs.map(async (pc) => this.#preparePcData(pc, characteristicKeys))
|
||||
);
|
||||
|
||||
const templateContext = {
|
||||
pcs: pcsData,
|
||||
clients: clientTokens.map(t => this.#prepareClientData(t)),
|
||||
characteristicKeys
|
||||
};
|
||||
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/fvtt-donjon-et-cie/templates/dialogs/employes-dialog.hbs",
|
||||
templateContext
|
||||
);
|
||||
|
||||
return foundry.applications.api.DialogV2.wait({
|
||||
window: {
|
||||
title: "Employés",
|
||||
icon: "fa-solid fa-hard-hat"
|
||||
},
|
||||
classes: ["fvtt-donjon-et-cie", "dnc-employes-dialog-wrapper"],
|
||||
content,
|
||||
modal: false,
|
||||
buttons: [
|
||||
{
|
||||
action: "close",
|
||||
label: "Fermer",
|
||||
icon: "fa-solid fa-xmark",
|
||||
callback: () => true
|
||||
}
|
||||
],
|
||||
rejectClose: false,
|
||||
render: (event, dialog) => this.#setupTabs(dialog)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère les personnages joueurs (employés)
|
||||
*/
|
||||
static #getPlayerCharacters() {
|
||||
return game.actors.filter(a => a.type === "character" || a.hasPlayerOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère les PNJ clients de la scène courante (retourne les TokenDocuments)
|
||||
*/
|
||||
static #getClients() {
|
||||
const scene = canvas?.scene ?? game.scenes?.current;
|
||||
if (!scene) return [];
|
||||
|
||||
return scene.tokens.filter(token => {
|
||||
const actor = token.actor;
|
||||
return actor &&
|
||||
!actor.hasPlayerOwner &&
|
||||
actor.type === "pnj" &&
|
||||
actor.system.categorie === "Client";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère les clés des caractéristiques
|
||||
*/
|
||||
static #getCharacteristicKeys() {
|
||||
return Object.entries(DONJON_ET_CIE.characteristics).map(([key, metadata]) => ({
|
||||
key,
|
||||
label: metadata.label,
|
||||
short: metadata.short
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prépare les données d'un PJ pour l'affichage
|
||||
*/
|
||||
static async #preparePcData(pc, characteristicKeys) {
|
||||
const sys = pc.system || {};
|
||||
const items = pc.items?.contents || [];
|
||||
|
||||
const pvValue = sys.sante?.pv?.value ?? 0;
|
||||
const pvMax = sys.sante?.pv?.max ?? 0;
|
||||
const dv = sys.sante?.dv ?? "1d6";
|
||||
const meleeAttacks = sys.combat?.attaquesCorpsACorps ?? 1;
|
||||
const rangedAttacks = sys.combat?.attaquesDistance ?? 1;
|
||||
|
||||
const magicResources = DonjonEtCieUtility.getMagicResourceContext(pc);
|
||||
|
||||
const weapons = [];
|
||||
const armors = [];
|
||||
const spells = [];
|
||||
const capacities = [];
|
||||
|
||||
for (const item of items) {
|
||||
const itemSys = item.system || {};
|
||||
|
||||
if (item.type === "arme") {
|
||||
const categoryLabel = itemSys.categorie === "distance" ? "Distance" : "Corps à corps";
|
||||
const handsLabel = (itemSys.mains ?? 1) > 1 ? "2 mains" : "1 main";
|
||||
|
||||
weapons.push({
|
||||
name: item.name,
|
||||
categoryLabel,
|
||||
handsLabel,
|
||||
damage: itemSys.degatsEstUsageDe
|
||||
? `${itemSys.degats}(Δ)`
|
||||
: (itemSys.degats || "—"),
|
||||
range: itemSys.portee || "Contact",
|
||||
ammunition: itemSys.munitionsDelta != null
|
||||
? (itemSys.munitionsDelta === 0 ? "Épuisées" : `Δ${itemSys.munitionsDelta}`)
|
||||
: ""
|
||||
});
|
||||
}
|
||||
|
||||
if (item.type === "armure") {
|
||||
armors.push({
|
||||
name: item.name,
|
||||
protectionDie: `Δ${itemSys.delta || 0}`,
|
||||
encumbrance: itemSys.encombrement || "—",
|
||||
remainingProtection: itemSys.resultatProtection || "—"
|
||||
});
|
||||
}
|
||||
|
||||
if (item.type === "sortilege") {
|
||||
spells.push({
|
||||
name: item.name,
|
||||
usageLabel: itemSys.delta > 0 ? DonjonEtCieUtility.formatUsageDie(itemSys.delta) : null
|
||||
});
|
||||
}
|
||||
|
||||
if (item.type === "capacite") {
|
||||
capacities.push({
|
||||
name: item.name,
|
||||
usageLabel: itemSys.delta > 0 ? DonjonEtCieUtility.formatUsageDie(itemSys.delta) : null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Spread des valeurs de caractéristiques directement sur l'objet pc
|
||||
const characteristics = {};
|
||||
characteristicKeys.forEach(({ key }) => {
|
||||
characteristics[key] = sys.caracteristiques?.[key]?.value ?? 0;
|
||||
});
|
||||
|
||||
return {
|
||||
actorId: pc.id,
|
||||
name: pc.name,
|
||||
concept: pc.system.concept || "",
|
||||
pvValue,
|
||||
pvMax,
|
||||
dv,
|
||||
meleeAttacks,
|
||||
rangedAttacks,
|
||||
weapons,
|
||||
armors,
|
||||
spells,
|
||||
capacities,
|
||||
magicRank: magicResources.rank,
|
||||
focusDisplay: magicResources.focusDisplay,
|
||||
chaosDisplay: magicResources.chaosLabel,
|
||||
...characteristics
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Prépare les données d'un client (PNJ) depuis son TokenDocument
|
||||
*/
|
||||
static #prepareClientData(token) {
|
||||
const client = token.actor;
|
||||
const sys = client.system || {};
|
||||
const items = client.items?.contents || [];
|
||||
|
||||
// Attaques système du modèle PNJ
|
||||
const attaques = (sys.attaques || []).filter(a => a.nom || a.degats);
|
||||
|
||||
// Items du PNJ
|
||||
const weapons = [];
|
||||
const spells = [];
|
||||
const capacities = [];
|
||||
|
||||
for (const item of items) {
|
||||
const itemSys = item.system || {};
|
||||
if (item.type === "arme") {
|
||||
weapons.push({
|
||||
name: item.name,
|
||||
damage: itemSys.degatsEstUsageDe
|
||||
? `${itemSys.degats}(Δ)`
|
||||
: (itemSys.degats || "—"),
|
||||
categoryLabel: itemSys.categorie === "distance" ? "Distance" : "Corps à corps"
|
||||
});
|
||||
}
|
||||
if (item.type === "sortilege") {
|
||||
spells.push({
|
||||
name: item.name,
|
||||
usageLabel: itemSys.delta > 0 ? DonjonEtCieUtility.formatUsageDie(itemSys.delta) : null
|
||||
});
|
||||
}
|
||||
if (item.type === "capacite") {
|
||||
capacities.push({
|
||||
name: item.name,
|
||||
usageLabel: itemSys.delta > 0 ? DonjonEtCieUtility.formatUsageDie(itemSys.delta) : null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: client.id,
|
||||
tokenUuid: token.uuid,
|
||||
name: client.name,
|
||||
species: sys.espece || "",
|
||||
category: sys.categorie || "",
|
||||
role: sys.role || "",
|
||||
summary: sys.resume || "",
|
||||
pvValue: sys.sante?.pv?.value ?? 0,
|
||||
pvMax: sys.sante?.pv?.max ?? 0,
|
||||
dv: sys.sante?.dv || "1d8",
|
||||
armureDelta: sys.defense?.armure?.delta ?? 0,
|
||||
armureProtection: sys.defense?.armure?.resultatProtection ?? 0,
|
||||
courageDelta: sys.defense?.courage?.delta ?? 0,
|
||||
attaques,
|
||||
weapons,
|
||||
spells,
|
||||
capacities,
|
||||
pouvoirsSpeciaux: sys.pouvoirsSpeciaux || "",
|
||||
hasMagie: spells.length > 0 || capacities.length > 0 || !!(sys.pouvoirsSpeciaux || "").trim()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration des onglets à 2 niveaux
|
||||
* Niveau 1 : Employés / Clients (root tabs)
|
||||
* Niveau 2 : un onglet par PC ou par client (sub-tabs)
|
||||
*/
|
||||
static #setupTabs(dialog) {
|
||||
const root = dialog.element;
|
||||
|
||||
// ---- Onglets racine ----
|
||||
const rootTabs = root.querySelectorAll('.dnc-root-tab');
|
||||
const rootPanels = root.querySelectorAll('.dnc-root-panel');
|
||||
|
||||
const activateRoot = (tabName) => {
|
||||
rootTabs.forEach(btn => btn.classList.toggle('active', btn.dataset.rootTab === tabName));
|
||||
rootPanels.forEach(panel => panel.classList.toggle('active', panel.dataset.rootPanel === tabName));
|
||||
};
|
||||
|
||||
rootTabs.forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
activateRoot(btn.dataset.rootTab);
|
||||
});
|
||||
});
|
||||
|
||||
// Activer premier onglet racine par défaut
|
||||
if (rootTabs.length > 0) activateRoot(rootTabs[0].dataset.rootTab);
|
||||
|
||||
// ---- Sous-onglets PC ----
|
||||
const pcTabs = root.querySelectorAll('.dnc-pc-tab[data-pc-tab]');
|
||||
const pcPanels = root.querySelectorAll('.dnc-pc-panel[data-pc-panel]');
|
||||
|
||||
const activatePc = (actorId) => {
|
||||
pcTabs.forEach(btn => btn.classList.toggle('active', btn.dataset.pcTab === actorId));
|
||||
pcPanels.forEach(panel => panel.classList.toggle('active', panel.dataset.pcPanel === actorId));
|
||||
};
|
||||
|
||||
pcTabs.forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
activatePc(btn.dataset.pcTab);
|
||||
});
|
||||
});
|
||||
|
||||
if (pcTabs.length > 0) activatePc(pcTabs[0].dataset.pcTab);
|
||||
|
||||
// ---- Sous-onglets Clients ----
|
||||
const clientTabs = root.querySelectorAll('.dnc-pc-tab[data-client-tab]');
|
||||
const clientPanels = root.querySelectorAll('.dnc-client-panel[data-client-panel]');
|
||||
|
||||
const activateClient = (clientId) => {
|
||||
clientTabs.forEach(btn => btn.classList.toggle('active', btn.dataset.clientTab === clientId));
|
||||
clientPanels.forEach(panel => panel.classList.toggle('active', panel.dataset.clientPanel === clientId));
|
||||
};
|
||||
|
||||
clientTabs.forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
activateClient(btn.dataset.clientTab);
|
||||
});
|
||||
});
|
||||
|
||||
if (clientTabs.length > 0) activateClient(clientTabs[0].dataset.clientTab);
|
||||
|
||||
// ---- Ouverture des fiches ----
|
||||
root.addEventListener('click', (e) => {
|
||||
const btn = e.target.closest('.dnc-open-sheet-btn');
|
||||
if (!btn) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const type = btn.dataset.openSheet;
|
||||
if (type === "pc") {
|
||||
const actor = game.actors.get(btn.dataset.actorId);
|
||||
actor?.sheet.render(true);
|
||||
} else if (type === "client") {
|
||||
const tokenDoc = fromUuidSync(btn.dataset.tokenUuid);
|
||||
const actor = tokenDoc?.actor ?? game.actors.get(btn.dataset.actorId);
|
||||
actor?.sheet.render(true);
|
||||
}
|
||||
});
|
||||
|
||||
// ---- Jets de dés depuis la vue clients (même dialogs que la fiche PNJ) ----
|
||||
root.addEventListener('click', async (e) => {
|
||||
const btn = e.target.closest('.dnc-roll-btn, .dnc-carac-rollable');
|
||||
if (!btn) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
// Résolution de l'actor : token UUID pour gérer les tokens non-liés
|
||||
const tokenUuid = btn.dataset.tokenUuid;
|
||||
const actorId = btn.dataset.actorId;
|
||||
let actor = null;
|
||||
if (tokenUuid) {
|
||||
const tokenDoc = fromUuidSync(tokenUuid);
|
||||
actor = tokenDoc?.actor ?? null;
|
||||
}
|
||||
if (!actor && actorId) {
|
||||
actor = game.actors.get(actorId);
|
||||
}
|
||||
if (!actor) return;
|
||||
|
||||
const action = btn.dataset.pnjAction;
|
||||
switch (action) {
|
||||
case "rollArmure": return actor.rollPnjArmor();
|
||||
case "rollCourage": return actor.rollPnjCourage();
|
||||
case "rollAttaque": return actor.rollPnjAttackDamage(btn.dataset.attackIndex ?? 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,16 +202,18 @@ export class DonjonEtCieRollDialog {
|
||||
|
||||
static async createDamage(actor, item) {
|
||||
const damageContext = DonjonEtCieUtility.getMartialDamageContext(actor, item);
|
||||
const isMeleeTwoHanded = item.type === "arme" && item.system?.categorie === "melee" && Number(item.system?.mains ?? 1) > 1;
|
||||
const defaultMode = isMeleeTwoHanded ? "avantage" : "normal";
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/fvtt-donjon-et-cie/templates/dialogs/damage-roll.hbs",
|
||||
{
|
||||
actorName: actor?.name ?? item.actor?.name ?? "",
|
||||
item,
|
||||
actorBonus: actor?.system?.combat?.degatsBonus ?? 0,
|
||||
damageFormula: damageContext.effectiveFormula || item.system.degats,
|
||||
damageBase: damageContext.baseFormula || item.system.degats,
|
||||
damageCapped: damageContext.capped,
|
||||
martialDvLabel: damageContext.martialDvSides ? `d${damageContext.martialDvSides}` : damageContext.martialDvFormula
|
||||
martialDvLabel: damageContext.martialDvSides ? `d${damageContext.martialDvSides}` : damageContext.martialDvFormula,
|
||||
defaultMode
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import { DonjonEtCieItem } from "./donjon-et-cie-item.mjs";
|
||||
import * as models from "./models/index.mjs";
|
||||
import * as sheets from "./applications/sheets/_module.mjs";
|
||||
import { DonjonEtCieRollDialog } from "./applications/donjon-et-cie-roll-dialog.mjs";
|
||||
import { DonjonEtCieEmployesDialog } from "./applications/donjon-et-cie-employes-dialog.mjs";
|
||||
import { DonjonEtCieRolls } from "./donjon-et-cie-rolls.mjs";
|
||||
import { DonjonEtCieMacros } from "./donjon-et-cie-macros.mjs";
|
||||
|
||||
@@ -43,6 +44,18 @@ function injectActorDirectoryMissionPackButton(app, element) {
|
||||
void game.system.donjonEtCie.macros.openMissionPackDialog();
|
||||
});
|
||||
headerActions.append(button);
|
||||
|
||||
// Bouton "Employés / Clients"
|
||||
const empButton = document.createElement("button");
|
||||
empButton.type = "button";
|
||||
empButton.className = "dnc-employes-button";
|
||||
empButton.title = game.i18n.localize("DNC.Dialog.EmployeesTitle");
|
||||
empButton.setAttribute("aria-label", game.i18n.localize("DNC.Dialog.EmployeesTitle"));
|
||||
empButton.innerHTML = `<i class="fa-solid fa-hard-hat" inert></i><span>${game.i18n.localize("DNC.Dialog.EmployeesTitle")}</span>`;
|
||||
empButton.addEventListener("click", () => {
|
||||
void DonjonEtCieEmployesDialog.open();
|
||||
});
|
||||
headerActions.append(empButton);
|
||||
}
|
||||
|
||||
function onChatActionClick(event) {
|
||||
@@ -233,10 +246,62 @@ Hooks.once("init", async () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Gestion de la commande /employes
|
||||
// Enregistrement officiel via ChatLogV2.CHAT_COMMANDS (comme mgt2-compendium-amiral-denisov)
|
||||
function registerEmployesCommand() {
|
||||
const ChatLogV2 = foundry.applications.sidebar.tabs.ChatLog;
|
||||
|
||||
if (ChatLogV2?.CHAT_COMMANDS) {
|
||||
ChatLogV2.CHAT_COMMANDS.employes = {
|
||||
rgx: /^\/employes(?:\s+(.*))?$/i,
|
||||
fn: () => {
|
||||
DonjonEtCieEmployesDialog.open();
|
||||
return false;
|
||||
},
|
||||
};
|
||||
console.log("DNC | Commande /employes enregistrée via ChatLog.CHAT_COMMANDS");
|
||||
} else {
|
||||
console.warn("DNC | ChatLog.CHAT_COMMANDS indisponible, utilisation des hooks de fallback");
|
||||
}
|
||||
}
|
||||
|
||||
Hooks.once("init", () => {
|
||||
registerEmployesCommand();
|
||||
});
|
||||
|
||||
Hooks.once("ready", () => {
|
||||
DonjonEtCieMacros.registerSocketListeners();
|
||||
document.addEventListener("click", onChatActionClick);
|
||||
void maybeCreateWelcomeMessage();
|
||||
|
||||
// Hooks de fallback pour compatibilité
|
||||
Hooks.on("preCreateChatMessage", (message, data, options, userId) => {
|
||||
const content = data.content?.trim()?.toLowerCase();
|
||||
if (content === "/employes" || content?.startsWith("/employes ")) {
|
||||
DonjonEtCieEmployesDialog.open();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
Hooks.on("chatMessage", (...args) => {
|
||||
// Gestion compatibilité v13/v14
|
||||
let message;
|
||||
if (args[0]?.content !== undefined) {
|
||||
message = args[0].content; // v14
|
||||
} else if (typeof args[1] === "string") {
|
||||
message = args[1]; // v13
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
const trimmed = message?.trim()?.toLowerCase();
|
||||
if (trimmed === "/employes" || trimmed?.startsWith("/employes ")) {
|
||||
DonjonEtCieEmployesDialog.open();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
Hooks.on("renderActorDirectory", (app, element) => {
|
||||
|
||||
@@ -372,11 +372,15 @@ export class DonjonEtCieRolls {
|
||||
}
|
||||
if (!isUsageDie && !item.system.degats) return null;
|
||||
|
||||
// Arme à 2 mains de corps à corps : avantage automatique
|
||||
const isMeleeTwoHanded = item.type === "arme" && item.system?.categorie === "melee" && Number(item.system?.mains ?? 1) > 1;
|
||||
if (isMeleeTwoHanded && mode === "normal") {
|
||||
mode = "avantage";
|
||||
}
|
||||
|
||||
const damageContext = DonjonEtCieUtility.getMartialDamageContext(actor, item);
|
||||
const actorBonus = Number(actor?.system?.combat?.degatsBonus ?? 0);
|
||||
const totalBonus = actorBonus;
|
||||
const effectiveDamage = damageContext.effectiveFormula || (isUsageDie ? `1d${degatsDelta}` : item.system.degats);
|
||||
const formula = totalBonus ? `${effectiveDamage} + ${totalBonus}` : effectiveDamage;
|
||||
const formula = effectiveDamage;
|
||||
const result = await this.#resolveFormulaRoll(formula, {}, { mode, favorable: "high" });
|
||||
const targets = DonjonEtCieUtility.getSceneDamageTargets();
|
||||
const rollDieLabels = result.rolls.map((roll) => {
|
||||
@@ -396,7 +400,6 @@ export class DonjonEtCieRolls {
|
||||
keptDieLabel,
|
||||
values: result.values,
|
||||
total: result.kept,
|
||||
bonus: totalBonus,
|
||||
baseDamage: baseDamageDisplay,
|
||||
effectiveDamage,
|
||||
damageCapped: damageContext.capped,
|
||||
@@ -414,7 +417,6 @@ export class DonjonEtCieRolls {
|
||||
baseDamage: baseDamageDisplay,
|
||||
effectiveDamage,
|
||||
damageCapped: damageContext.capped,
|
||||
bonus: totalBonus,
|
||||
values: result.values,
|
||||
mode: result.mode
|
||||
};
|
||||
@@ -427,6 +429,12 @@ export class DonjonEtCieRolls {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Arme à 2 mains de corps à corps : avantage automatique
|
||||
const isMeleeTwoHanded = item.type === "arme" && item.system?.categorie === "melee" && Number(item.system?.mains ?? 1) > 1;
|
||||
if (isMeleeTwoHanded && mode === "normal") {
|
||||
mode = "avantage";
|
||||
}
|
||||
|
||||
const resolved = await this.#resolveFormulaRoll(`1d${before}`, {}, { mode, favorable: "high" });
|
||||
const result = resolved.kept;
|
||||
const degraded = result <= 3;
|
||||
|
||||
@@ -36,6 +36,7 @@ export class DonjonEtCieUtility {
|
||||
"systems/fvtt-donjon-et-cie/templates/dialogs/usage-roll.hbs",
|
||||
"systems/fvtt-donjon-et-cie/templates/dialogs/mission-pack-dialog.hbs",
|
||||
"systems/fvtt-donjon-et-cie/templates/dialogs/mission-pack-campaign-dialog.hbs",
|
||||
"systems/fvtt-donjon-et-cie/templates/dialogs/employes-dialog.hbs",
|
||||
"systems/fvtt-donjon-et-cie/templates/chat/roll-card.hbs",
|
||||
"systems/fvtt-donjon-et-cie/templates/chat/spell-card.hbs",
|
||||
"systems/fvtt-donjon-et-cie/templates/chat/chaos-card.hbs",
|
||||
@@ -75,6 +76,9 @@ export class DonjonEtCieUtility {
|
||||
static getSceneDamageTargets() {
|
||||
const scene = canvas?.scene ?? game.scenes?.current;
|
||||
const tokens = scene?.tokens?.contents ?? [];
|
||||
|
||||
const targetedTokens = game.user?.targets ?? new Set();
|
||||
const targetedTokenUuid = targetedTokens?.first()?.document.uuid ?? null;
|
||||
|
||||
return tokens
|
||||
.map((token) => {
|
||||
@@ -89,7 +93,8 @@ export class DonjonEtCieUtility {
|
||||
tokenId: token.id,
|
||||
tokenUuid: token.uuid,
|
||||
actorUuid: actor.uuid,
|
||||
label
|
||||
label,
|
||||
isSelected: token.uuid === targetedTokenUuid
|
||||
};
|
||||
})
|
||||
.filter(Boolean)
|
||||
|
||||
@@ -50,7 +50,6 @@ export default class EmployeDataModel extends foundry.abstract.TypeDataModel {
|
||||
}),
|
||||
combat: new fields.SchemaField({
|
||||
initiativeBonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
degatsBonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
attaquesCorpsACorps: new fields.NumberField({ initial: 1, integer: true }),
|
||||
attaquesDistance: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
|
||||
@@ -1 +1 @@
|
||||
MANIFEST-000085
|
||||
MANIFEST-000189
|
||||
|
||||
+7
-7
@@ -1,7 +1,7 @@
|
||||
2026/05/22-09:28:26.005874 7fb57dfee6c0 Recovering log #83
|
||||
2026/05/22-09:28:26.015537 7fb57dfee6c0 Delete type=3 #81
|
||||
2026/05/22-09:28:26.015651 7fb57dfee6c0 Delete type=0 #83
|
||||
2026/05/22-09:49:57.296086 7fb567fff6c0 Level-0 table #88: started
|
||||
2026/05/22-09:49:57.296112 7fb567fff6c0 Level-0 table #88: 0 bytes OK
|
||||
2026/05/22-09:49:57.302010 7fb567fff6c0 Delete type=0 #86
|
||||
2026/05/22-09:49:57.319148 7fb567fff6c0 Manual compaction at level-0 from '!folders!K9aiFu0dE6UYiXBd' @ 72057594037927935 : 1 .. '!items!zyqLzmpbHxK3jt5q' @ 0 : 0; will stop at (end)
|
||||
2026/06/03-20:02:36.286349 7f589d3fe6c0 Recovering log #187
|
||||
2026/06/03-20:02:36.295607 7f589d3fe6c0 Delete type=3 #185
|
||||
2026/06/03-20:02:36.295653 7f589d3fe6c0 Delete type=0 #187
|
||||
2026/06/03-20:14:21.989739 7f584f7fe6c0 Level-0 table #192: started
|
||||
2026/06/03-20:14:21.989753 7f584f7fe6c0 Level-0 table #192: 0 bytes OK
|
||||
2026/06/03-20:14:21.995792 7f584f7fe6c0 Delete type=0 #190
|
||||
2026/06/03-20:14:22.012809 7f584f7fe6c0 Manual compaction at level-0 from '!folders!K9aiFu0dE6UYiXBd' @ 72057594037927935 : 1 .. '!items!zyqLzmpbHxK3jt5q' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
2026/05/09-23:56:26.228807 7fe7211fe6c0 Recovering log #79
|
||||
2026/05/09-23:56:26.239813 7fe7211fe6c0 Delete type=3 #77
|
||||
2026/05/09-23:56:26.239859 7fe7211fe6c0 Delete type=0 #79
|
||||
2026/05/09-23:58:32.093072 7fe6d37fe6c0 Level-0 table #84: started
|
||||
2026/05/09-23:58:32.093102 7fe6d37fe6c0 Level-0 table #84: 0 bytes OK
|
||||
2026/05/09-23:58:32.100189 7fe6d37fe6c0 Delete type=0 #82
|
||||
2026/05/09-23:58:32.106644 7fe6d37fe6c0 Manual compaction at level-0 from '!folders!K9aiFu0dE6UYiXBd' @ 72057594037927935 : 1 .. '!items!zyqLzmpbHxK3jt5q' @ 0 : 0; will stop at (end)
|
||||
2026/06/03-17:24:13.769178 7f589dbff6c0 Recovering log #183
|
||||
2026/06/03-17:24:13.812146 7f589dbff6c0 Delete type=3 #181
|
||||
2026/06/03-17:24:13.812199 7f589dbff6c0 Delete type=0 #183
|
||||
2026/06/03-19:19:52.344655 7f584f7fe6c0 Level-0 table #188: started
|
||||
2026/06/03-19:19:52.344671 7f584f7fe6c0 Level-0 table #188: 0 bytes OK
|
||||
2026/06/03-19:19:52.350896 7f584f7fe6c0 Delete type=0 #186
|
||||
2026/06/03-19:19:52.367561 7f584f7fe6c0 Manual compaction at level-0 from '!folders!K9aiFu0dE6UYiXBd' @ 72057594037927935 : 1 .. '!items!zyqLzmpbHxK3jt5q' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000072
|
||||
MANIFEST-000176
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
2026/05/22-09:28:26.020644 7fb57d7ed6c0 Recovering log #70
|
||||
2026/05/22-09:28:26.031504 7fb57d7ed6c0 Delete type=3 #68
|
||||
2026/05/22-09:28:26.031624 7fb57d7ed6c0 Delete type=0 #70
|
||||
2026/05/22-09:49:57.312571 7fb567fff6c0 Level-0 table #75: started
|
||||
2026/05/22-09:49:57.312612 7fb567fff6c0 Level-0 table #75: 0 bytes OK
|
||||
2026/05/22-09:49:57.318950 7fb567fff6c0 Delete type=0 #73
|
||||
2026/05/22-09:49:57.319188 7fb567fff6c0 Manual compaction at level-0 from '!tables!PPsxQgHwLCQ2gjSW' @ 72057594037927935 : 1 .. '!tables.results!wJZXUo4q5b5vE3Dy.zFTPLMc9zOl5hISV' @ 0 : 0; will stop at (end)
|
||||
2026/06/03-20:02:36.298130 7f584ffff6c0 Recovering log #174
|
||||
2026/06/03-20:02:36.307600 7f584ffff6c0 Delete type=3 #172
|
||||
2026/06/03-20:02:36.307643 7f584ffff6c0 Delete type=0 #174
|
||||
2026/06/03-20:14:22.006386 7f584f7fe6c0 Level-0 table #179: started
|
||||
2026/06/03-20:14:22.006405 7f584f7fe6c0 Level-0 table #179: 0 bytes OK
|
||||
2026/06/03-20:14:22.012715 7f584f7fe6c0 Delete type=0 #177
|
||||
2026/06/03-20:14:22.012822 7f584f7fe6c0 Manual compaction at level-0 from '!tables!PPsxQgHwLCQ2gjSW' @ 72057594037927935 : 1 .. '!tables.results!wJZXUo4q5b5vE3Dy.zFTPLMc9zOl5hISV' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
2026/05/09-23:56:26.242643 7fe7219ff6c0 Recovering log #66
|
||||
2026/05/09-23:56:26.252924 7fe7219ff6c0 Delete type=3 #64
|
||||
2026/05/09-23:56:26.252971 7fe7219ff6c0 Delete type=0 #66
|
||||
2026/05/09-23:58:32.087004 7fe6d37fe6c0 Level-0 table #71: started
|
||||
2026/05/09-23:58:32.087037 7fe6d37fe6c0 Level-0 table #71: 0 bytes OK
|
||||
2026/05/09-23:58:32.092951 7fe6d37fe6c0 Delete type=0 #69
|
||||
2026/05/09-23:58:32.106635 7fe6d37fe6c0 Manual compaction at level-0 from '!tables!PPsxQgHwLCQ2gjSW' @ 72057594037927935 : 1 .. '!tables.results!wJZXUo4q5b5vE3Dy.zFTPLMc9zOl5hISV' @ 0 : 0; will stop at (end)
|
||||
2026/06/03-17:24:13.815984 7f589cbfd6c0 Recovering log #170
|
||||
2026/06/03-17:24:13.870566 7f589cbfd6c0 Delete type=3 #168
|
||||
2026/06/03-17:24:13.870643 7f589cbfd6c0 Delete type=0 #170
|
||||
2026/06/03-19:19:52.350980 7f584f7fe6c0 Level-0 table #175: started
|
||||
2026/06/03-19:19:52.351000 7f584f7fe6c0 Level-0 table #175: 0 bytes OK
|
||||
2026/06/03-19:19:52.357007 7f584f7fe6c0 Delete type=0 #173
|
||||
2026/06/03-19:19:52.367567 7f584f7fe6c0 Manual compaction at level-0 from '!tables!PPsxQgHwLCQ2gjSW' @ 72057594037927935 : 1 .. '!tables.results!wJZXUo4q5b5vE3Dy.zFTPLMc9zOl5hISV' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000006
|
||||
MANIFEST-000002
|
||||
|
||||
+5
-15
@@ -1,15 +1,5 @@
|
||||
2026/05/22-09:28:26.037049 7fb57dfee6c0 Recovering log #4
|
||||
2026/05/22-09:28:26.047411 7fb57dfee6c0 Delete type=3 #2
|
||||
2026/05/22-09:28:26.047498 7fb57dfee6c0 Delete type=0 #4
|
||||
2026/05/22-09:49:57.302133 7fb567fff6c0 Level-0 table #9: started
|
||||
2026/05/22-09:49:57.305585 7fb567fff6c0 Level-0 table #9: 3183 bytes OK
|
||||
2026/05/22-09:49:57.312423 7fb567fff6c0 Delete type=0 #7
|
||||
2026/05/22-09:49:57.319164 7fb567fff6c0 Manual compaction at level-0 from '!journal!69Da9YvF9BfOV7oK' @ 72057594037927935 : 1 .. '!journal.pages!69Da9YvF9BfOV7oK.XM0eLkgKXPyskV65' @ 0 : 0; will stop at (end)
|
||||
2026/05/22-09:49:57.319233 7fb567fff6c0 Manual compaction at level-1 from '!journal!69Da9YvF9BfOV7oK' @ 72057594037927935 : 1 .. '!journal.pages!69Da9YvF9BfOV7oK.XM0eLkgKXPyskV65' @ 0 : 0; will stop at '!journal.pages!69Da9YvF9BfOV7oK.XM0eLkgKXPyskV65' @ 3 : 1
|
||||
2026/05/22-09:49:57.319246 7fb567fff6c0 Compacting 1@1 + 1@2 files
|
||||
2026/05/22-09:49:57.322612 7fb567fff6c0 Generated table #10@1: 2 keys, 3183 bytes
|
||||
2026/05/22-09:49:57.322655 7fb567fff6c0 Compacted 1@1 + 1@2 files => 3183 bytes
|
||||
2026/05/22-09:49:57.328541 7fb567fff6c0 compacted to: files[ 0 0 1 0 0 0 0 ]
|
||||
2026/05/22-09:49:57.328673 7fb567fff6c0 Delete type=2 #5
|
||||
2026/05/22-09:49:57.328793 7fb567fff6c0 Delete type=2 #9
|
||||
2026/05/22-09:49:57.351951 7fb567fff6c0 Manual compaction at level-1 from '!journal.pages!69Da9YvF9BfOV7oK.XM0eLkgKXPyskV65' @ 3 : 1 .. '!journal.pages!69Da9YvF9BfOV7oK.XM0eLkgKXPyskV65' @ 0 : 0; will stop at (end)
|
||||
2026/06/03-20:12:45.450958 7f07bbfff6c0 Delete type=3 #1
|
||||
2026/06/03-20:12:45.455909 7f07baffd6c0 Level-0 table #5: started
|
||||
2026/06/03-20:12:45.474772 7f07baffd6c0 Level-0 table #5: 3056 bytes OK
|
||||
2026/06/03-20:12:45.523202 7f07baffd6c0 Delete type=0 #3
|
||||
2026/06/03-20:12:45.523559 7f07baffd6c0 Manual compaction at level-0 from '!journal!69Da9YvF9BfOV7oK' @ 72057594037927935 : 1 .. '!journal.pages!69Da9YvF9BfOV7oK.XM0eLkgKXPyskV65' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
2026/05/22-08:07:40.563282 7f63427ef6c0 Delete type=3 #1
|
||||
2026/05/22-08:07:40.567990 7f6323fff6c0 Level-0 table #5: started
|
||||
2026/05/22-08:07:40.571414 7f6323fff6c0 Level-0 table #5: 3056 bytes OK
|
||||
2026/05/22-08:07:40.577623 7f6323fff6c0 Delete type=0 #3
|
||||
2026/05/22-08:07:40.577857 7f6323fff6c0 Manual compaction at level-0 from '!journal!69Da9YvF9BfOV7oK' @ 72057594037927935 : 1 .. '!journal.pages!69Da9YvF9BfOV7oK.XM0eLkgKXPyskV65' @ 0 : 0; will stop at (end)
|
||||
Binary file not shown.
+353
-1
@@ -271,6 +271,13 @@
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
.dnc-actor-sheet .hp-field .counter-field input[type="number"] {
|
||||
max-width: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
.dnc-actor-sheet .hp-field .counter-field {
|
||||
gap: 0.25rem;
|
||||
}
|
||||
.dnc-actor-sheet .profile-card-wide {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -879,9 +886,31 @@
|
||||
.chat-targeting {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
margin-top: 0.4rem;
|
||||
flex-wrap: wrap;
|
||||
align-items: end;
|
||||
}
|
||||
.chat-targeting .chat-action-button {
|
||||
padding: 0.35rem 0.65rem;
|
||||
min-height: 1.75rem;
|
||||
font-size: 0.82rem;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.dnc-chat-card-damage .chat-actions-inline {
|
||||
flex-wrap: nowrap;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
.dnc-chat-card-damage .chat-actions-inline .chat-action-button {
|
||||
padding: 0.3rem 0.55rem;
|
||||
min-height: 1.65rem;
|
||||
font-size: 0.78rem;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.dnc-chat-card-damage .chat-actions-inline .chat-action-button i {
|
||||
font-size: 0.85rem;
|
||||
margin-right: 0.2rem;
|
||||
}
|
||||
.chat-control {
|
||||
display: grid;
|
||||
@@ -1083,5 +1112,328 @@
|
||||
.initiative-sync p {
|
||||
margin: 0.4rem 0 0;
|
||||
}
|
||||
.dnc-employes-dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem;
|
||||
min-width: 640px;
|
||||
max-width: 90vw;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.dnc-employes-dialog .sheet-header {
|
||||
display: block;
|
||||
grid-template-columns: none;
|
||||
gap: normal;
|
||||
}
|
||||
.dnc-employes-dialog .sheet-header h1 {
|
||||
font-family: "IM Fell English SC", "Palatino Linotype", "Book Antiqua", Palatino, serif;
|
||||
font-size: 1.4rem;
|
||||
color: #8b2e17;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.dnc-employes-dialog-wrapper .dialog-content,
|
||||
.dnc-employes-dialog-wrapper .window-content {
|
||||
padding: 0;
|
||||
}
|
||||
.dnc-employes-dialog-wrapper .dialog-footer {
|
||||
display: none;
|
||||
}
|
||||
.dnc-root-tabs {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 0.75rem;
|
||||
border-bottom: 2px solid #5b4634;
|
||||
padding-bottom: 0.4rem;
|
||||
}
|
||||
.dnc-root-tab {
|
||||
border: 1px solid rgba(91, 70, 52, 0.55);
|
||||
border-radius: 10px 10px 0 0;
|
||||
background: #e2d0b1;
|
||||
color: #221b18;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 700;
|
||||
padding: 0.4rem 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.dnc-root-tab i {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.dnc-root-tab.active {
|
||||
background: #8b2e17;
|
||||
border-color: #561d0e;
|
||||
color: #fff;
|
||||
box-shadow: 0 -3px 8px rgba(0, 0, 0, 0.2);
|
||||
position: relative;
|
||||
bottom: -2px;
|
||||
}
|
||||
.dnc-root-tab:hover:not(.active) {
|
||||
background: #e2d0b1;
|
||||
border-color: rgba(91, 70, 52, 0.75);
|
||||
}
|
||||
.dnc-root-panels {
|
||||
position: relative;
|
||||
}
|
||||
.dnc-root-panel {
|
||||
display: none;
|
||||
}
|
||||
.dnc-root-panel.active {
|
||||
display: block;
|
||||
}
|
||||
.dnc-pc-tabs {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
flex-wrap: wrap;
|
||||
padding: 0.4rem 0;
|
||||
border-bottom: 1px solid rgba(91, 70, 52, 0.4);
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
.dnc-pc-tab {
|
||||
border: 1px solid rgba(91, 70, 52, 0.45);
|
||||
border-radius: 6px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
color: #6d5a4f;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
padding: 0.25rem 0.75rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.dnc-pc-tab.active {
|
||||
background: #8b2e17;
|
||||
border-color: #5f2010;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
}
|
||||
.dnc-pc-tab:hover:not(.active) {
|
||||
background: #e2d0b1;
|
||||
color: #221b18;
|
||||
}
|
||||
.dnc-pc-panels {
|
||||
position: relative;
|
||||
}
|
||||
.dnc-pc-panel,
|
||||
.dnc-client-panel {
|
||||
display: none;
|
||||
}
|
||||
.dnc-pc-panel.active,
|
||||
.dnc-client-panel.active {
|
||||
display: block;
|
||||
}
|
||||
.dnc-compact-section {
|
||||
padding: 0.75rem;
|
||||
margin-bottom: 0.4rem;
|
||||
border: 1px solid rgba(91, 70, 52, 0.4);
|
||||
border-radius: 10px;
|
||||
background: #f1e5d0;
|
||||
}
|
||||
.dnc-compact-section + .dnc-compact-section {
|
||||
margin-top: 0.4rem;
|
||||
}
|
||||
.dnc-compact-section-title {
|
||||
font-family: "IM Fell English SC", "Palatino Linotype", "Book Antiqua", Palatino, serif;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 700;
|
||||
color: #8b2e17;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
margin: 0 0 0.4rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
border-bottom: 1px solid rgba(91, 70, 52, 0.35);
|
||||
padding-bottom: 0.25rem;
|
||||
}
|
||||
.dnc-compact-section-title i {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.dnc-compact-concept {
|
||||
font-size: 0.8rem;
|
||||
color: #6d5a4f;
|
||||
font-style: italic;
|
||||
margin: 0.25rem 0 0;
|
||||
}
|
||||
.dnc-compact-carac-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
.dnc-carac-stat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
min-width: 48px;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border: 1px solid rgba(91, 70, 52, 0.4);
|
||||
border-radius: 6px;
|
||||
padding: 0.25rem 0.4rem;
|
||||
}
|
||||
.dnc-carac-label {
|
||||
font-size: 0.68rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
color: #6d5a4f;
|
||||
font-weight: 700;
|
||||
}
|
||||
.dnc-carac-value {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: #221b18;
|
||||
}
|
||||
.dnc-carac-value.warning {
|
||||
color: #842c2c;
|
||||
}
|
||||
.dnc-compact-combat-stats {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
.dnc-combat-badge {
|
||||
font-size: 0.82rem;
|
||||
padding: 0.25rem 0.4rem;
|
||||
background: #e2d0b1;
|
||||
border: 1px solid rgba(91, 70, 52, 0.4);
|
||||
border-radius: 6px;
|
||||
color: #221b18;
|
||||
}
|
||||
.dnc-compact-item-list {
|
||||
margin-top: 0.4rem;
|
||||
}
|
||||
.dnc-compact-subhead {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
color: #6d5a4f;
|
||||
margin: 0 0 0.25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
.dnc-compact-subhead i {
|
||||
color: #8b2e17;
|
||||
}
|
||||
.dnc-compact-item {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
padding: 0.25rem 0;
|
||||
border-top: 1px dashed rgba(91, 70, 52, 0.35);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.dnc-compact-item:first-of-type {
|
||||
border-top: 0;
|
||||
}
|
||||
.dnc-compact-item-name {
|
||||
font-weight: 600;
|
||||
color: #221b18;
|
||||
}
|
||||
.dnc-compact-item-detail {
|
||||
font-size: 0.78rem;
|
||||
color: #6d5a4f;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border-radius: 6px;
|
||||
padding: 0.05rem 0.3rem;
|
||||
}
|
||||
.dnc-compact-magic-stats {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
.item-meta {
|
||||
border-radius: 999px;
|
||||
background: #e2d0b1;
|
||||
color: #221b18;
|
||||
font-size: 0.75rem;
|
||||
padding: 0.1rem 0.5rem;
|
||||
}
|
||||
.client-summary {
|
||||
margin: 0.4rem 0 0;
|
||||
color: #221b18;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.45;
|
||||
}
|
||||
.client-description {
|
||||
margin-top: 0.75rem;
|
||||
padding-top: 0.75rem;
|
||||
border-top: 1px solid rgba(91, 70, 52, 0.45);
|
||||
}
|
||||
.client-description p {
|
||||
margin: 0;
|
||||
color: #6d5a4f;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.dnc-roll-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
padding: 0.1rem 0.5rem;
|
||||
font-size: 0.78rem;
|
||||
font-family: "Signika", sans-serif;
|
||||
color: #221b18;
|
||||
background: #e2d0b1;
|
||||
border: 1px solid rgba(91, 70, 52, 0.6);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.dnc-roll-btn i {
|
||||
font-size: 0.7rem;
|
||||
color: #8b2e17;
|
||||
}
|
||||
.dnc-roll-btn:hover {
|
||||
background: #8b2e17;
|
||||
color: #fff;
|
||||
border-color: #8b2e17;
|
||||
}
|
||||
.dnc-roll-btn:hover i {
|
||||
color: #fff;
|
||||
}
|
||||
.dnc-carac-rollable {
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
border-radius: 6px;
|
||||
position: relative;
|
||||
}
|
||||
.dnc-carac-rollable:hover {
|
||||
background: rgba(139, 46, 23, 0.18);
|
||||
}
|
||||
.dnc-carac-rollable:hover .dnc-carac-label {
|
||||
color: #8b2e17;
|
||||
}
|
||||
.dnc-compact-section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
.dnc-compact-section-title .dnc-open-sheet-btn {
|
||||
margin-left: auto;
|
||||
background: none;
|
||||
border: 1px solid rgba(91, 70, 52, 0.5);
|
||||
border-radius: 6px;
|
||||
color: #6d5a4f;
|
||||
cursor: pointer;
|
||||
font-size: 0.7rem;
|
||||
padding: 0.1rem 0.35rem;
|
||||
line-height: 1;
|
||||
transition: color 0.15s, border-color 0.15s;
|
||||
}
|
||||
.dnc-compact-section-title .dnc-open-sheet-btn:hover {
|
||||
color: #8b2e17;
|
||||
border-color: #8b2e17;
|
||||
}
|
||||
/*# sourceMappingURL=donjon-et-cie.css.map */
|
||||
/*# sourceMappingURL=donjon-et-cie.css.map */
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -46,10 +46,6 @@
|
||||
<span>Attaques distance</span>
|
||||
<input type="number" name="system.combat.attaquesDistance" value="{{system.combat.attaquesDistance}}">
|
||||
</label>
|
||||
<label>
|
||||
<span>Bonus degats</span>
|
||||
<input type="number" name="system.combat.degatsBonus" value="{{system.combat.degatsBonus}}">
|
||||
</label>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
{{#if modeLabel}}<span class="chat-pill">{{modeLabel}}</span>{{/if}}
|
||||
<span class="chat-pill success">Dé {{keptDieLabel}}</span>
|
||||
{{#if damageCapped}}<span class="chat-pill">{{localize "DNC.Chat.DamageCapped" damage=effectiveDamage dv=martialDvLabel}}</span>{{/if}}
|
||||
{{#if bonus}}<span class="chat-pill">Bonus +{{bonus}}</span>{{/if}}
|
||||
</div>
|
||||
<p class="chat-formula">{{formula}}</p>
|
||||
{{#if rollDieLabels.[1]}}
|
||||
@@ -23,14 +22,14 @@
|
||||
<p class="roll-values">{{#each rollDieLabels}}<span>{{this}}</span>{{/each}}</p>
|
||||
</div>
|
||||
{{/if}}
|
||||
<p class="chat-note"><strong>Base</strong> : {{baseDamage}}{{#if damageCapped}} · <strong>{{localize "DNC.Chat.MartialDv"}}</strong> : {{martialDvLabel}} · <strong>{{localize "DNC.Chat.EffectiveDamage"}}</strong> : {{effectiveDamage}}{{/if}}{{#if bonus}} · <strong>Bonus</strong> : +{{bonus}}{{/if}}</p>
|
||||
<p class="chat-note"><strong>Base</strong> : {{baseDamage}}{{#if damageCapped}} · <strong>{{localize "DNC.Chat.MartialDv"}}</strong> : {{martialDvLabel}} · <strong>{{localize "DNC.Chat.EffectiveDamage"}}</strong> : {{effectiveDamage}}{{/if}}</p>
|
||||
<div class="chat-targeting">
|
||||
<label class="chat-control">
|
||||
<span class="chat-keyline-label">Cible</span>
|
||||
<select class="chat-select" data-role="damage-target" {{#unless hasTargets}}disabled{{/unless}}>
|
||||
{{#if hasTargets}}
|
||||
{{#each targets}}
|
||||
<option value="{{this.tokenUuid}}">{{this.label}}</option>
|
||||
<option value="{{this.tokenUuid}}"{{#if this.isSelected}} selected{{/if}}>{{this.label}}</option>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<option value="">Aucune cible sur la scène</option>
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
{{#if damageCapped}}
|
||||
<p>{{localize "DNC.Dialog.DamageCappedByDv" dv=martialDvLabel damage=damageFormula base=damageBase}}</p>
|
||||
{{/if}}
|
||||
<p>{{localize "DNC.Dialog.ActorDamageBonus"}} : <strong>{{actorBonus}}</strong></p>
|
||||
<label>
|
||||
<span>{{localize "DNC.UI.Mode"}}</span>
|
||||
<select name="mode">
|
||||
<option value="normal">{{localize "DNC.UI.ModeNormal"}}</option>
|
||||
<option value="avantage">{{localize "DNC.UI.ModeAdvantage"}}</option>
|
||||
<option value="desavantage">{{localize "DNC.UI.ModeDisadvantage"}}</option>
|
||||
<option value="normal" {{#if (eq defaultMode "normal")}}selected{{/if}}>{{localize "DNC.UI.ModeNormal"}}</option>
|
||||
<option value="avantage" {{#if (eq defaultMode "avantage")}}selected{{/if}}>{{localize "DNC.UI.ModeAdvantage"}}</option>
|
||||
<option value="desavantage" {{#if (eq defaultMode "desavantage")}}selected{{/if}}>{{localize "DNC.UI.ModeDisadvantage"}}</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,366 @@
|
||||
<div class="dnc-employes-dialog" role="region" aria-labelledby="employes-title">
|
||||
<header class="sheet-header">
|
||||
<h1 id="employes-title">{{localize "DNC.Dialog.EmployeesTitle"}}</h1>
|
||||
</header>
|
||||
|
||||
<!-- ===== ONGLETS RACINE ===== -->
|
||||
<nav class="dnc-root-tabs" role="tablist" aria-label="{{localize 'DNC.Dialog.EmployeesTitle'}}">
|
||||
<button type="button"
|
||||
class="dnc-root-tab active"
|
||||
data-root-tab="employes"
|
||||
role="tab"
|
||||
aria-selected="true"
|
||||
aria-controls="root-panel-employes"
|
||||
id="root-tab-employes"
|
||||
>
|
||||
<i class="fa-solid fa-hard-hat" aria-hidden="true"></i> {{localize "DNC.Dialog.EmployeesTabEmployes"}}
|
||||
</button>
|
||||
<button type="button"
|
||||
class="dnc-root-tab"
|
||||
data-root-tab="clients"
|
||||
role="tab"
|
||||
aria-selected="false"
|
||||
aria-controls="root-panel-clients"
|
||||
id="root-tab-clients"
|
||||
>
|
||||
<i class="fa-solid fa-users" aria-hidden="true"></i> {{localize "DNC.Dialog.EmployeesTabClients"}}
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div class="dnc-root-panels">
|
||||
|
||||
<!-- ===== ROOT PANEL : EMPLOYÉS ===== -->
|
||||
<div class="dnc-root-panel active"
|
||||
data-root-panel="employes"
|
||||
role="tabpanel"
|
||||
aria-labelledby="root-tab-employes"
|
||||
id="root-panel-employes"
|
||||
>
|
||||
{{#if pcs.length}}
|
||||
<!-- Sous-onglets par employé -->
|
||||
<nav class="dnc-pc-tabs" role="tablist" aria-label="{{localize 'DNC.Dialog.EmployeesTabEmployes'}}">
|
||||
{{#each pcs}}
|
||||
<button type="button"
|
||||
class="dnc-pc-tab{{#if @first}} active{{/if}}"
|
||||
data-pc-tab="{{this.actorId}}"
|
||||
role="tab"
|
||||
aria-selected="{{#if @first}}true{{else}}false{{/if}}"
|
||||
aria-controls="pc-panel-{{this.actorId}}"
|
||||
id="pc-tab-{{this.actorId}}"
|
||||
>
|
||||
{{this.name}}
|
||||
</button>
|
||||
{{/each}}
|
||||
</nav>
|
||||
|
||||
<!-- Sous-panneaux par employé -->
|
||||
<div class="dnc-pc-panels">
|
||||
{{#each pcs}}
|
||||
<div class="dnc-pc-panel{{#if @first}} active{{/if}}"
|
||||
data-pc-panel="{{this.actorId}}"
|
||||
role="tabpanel"
|
||||
aria-labelledby="pc-tab-{{this.actorId}}"
|
||||
id="pc-panel-{{this.actorId}}"
|
||||
>
|
||||
<!-- SECTION : CARACTÉRISTIQUES -->
|
||||
<section class="dnc-compact-section dnc-compact-carac">
|
||||
<h3 class="dnc-compact-section-title">
|
||||
<i class="fa-solid fa-chart-line" aria-hidden="true"></i>
|
||||
{{localize "DNC.Dialog.EmployeesTabCharacteristics"}}
|
||||
<button type="button" class="dnc-open-sheet-btn" data-open-sheet="pc" data-actor-id="{{this.actorId}}" title="Ouvrir la fiche">
|
||||
<i class="fa-solid fa-external-link-alt"></i>
|
||||
</button>
|
||||
</h3>
|
||||
<div class="dnc-compact-carac-grid">
|
||||
<div class="dnc-carac-stat">
|
||||
<span class="dnc-carac-label">{{localize "DNC.UI.Pv"}}</span>
|
||||
<span class="dnc-carac-value{{#if (lt this.pvValue 3)}} warning{{/if}}">{{this.pvValue}}/{{this.pvMax}}</span>
|
||||
</div>
|
||||
<div class="dnc-carac-stat">
|
||||
<span class="dnc-carac-label">{{localize "DNC.UI.Dv"}}</span>
|
||||
<span class="dnc-carac-value">{{this.dv}}</span>
|
||||
</div>
|
||||
{{#each ../characteristicKeys}}
|
||||
<div class="dnc-carac-stat">
|
||||
<span class="dnc-carac-label">{{this.short}}</span>
|
||||
<span class="dnc-carac-value">{{lookup .. this.key}}</span>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{#if this.concept}}
|
||||
<p class="dnc-compact-concept">{{this.concept}}</p>
|
||||
{{/if}}
|
||||
</section>
|
||||
|
||||
<!-- SECTION : COMBAT -->
|
||||
<section class="dnc-compact-section dnc-compact-combat">
|
||||
<h3 class="dnc-compact-section-title">
|
||||
<i class="fa-solid fa-sword" aria-hidden="true"></i>
|
||||
{{localize "DNC.Dialog.EmployeesTabCombat"}}
|
||||
</h3>
|
||||
<div class="dnc-compact-combat-stats">
|
||||
<span class="dnc-combat-badge">⚔️ ×{{this.meleeAttacks}} {{localize "DNC.UI.MeleeAttacks"}}</span>
|
||||
<span class="dnc-combat-badge">🏹 ×{{this.rangedAttacks}} {{localize "DNC.UI.RangedAttacks"}}</span>
|
||||
</div>
|
||||
|
||||
{{#if this.weapons.length}}
|
||||
<div class="dnc-compact-item-list">
|
||||
<h4 class="dnc-compact-subhead"><i class="fa-solid fa-sword"></i> {{localize "DNC.UI.Weapons"}}</h4>
|
||||
{{#each this.weapons}}
|
||||
<div class="dnc-compact-item">
|
||||
<span class="dnc-compact-item-name">{{this.name}}</span>
|
||||
<span class="item-meta">{{this.categoryLabel}}</span>
|
||||
<span class="item-meta">{{this.handsLabel}}</span>
|
||||
<span class="dnc-compact-item-detail">{{localize "DNC.UI.Damage"}} {{this.damage}}</span>
|
||||
{{#if this.ammunition}}<span class="dnc-compact-item-detail">{{localize "DNC.UI.Ammunition"}} {{this.ammunition}}</span>{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.armors.length}}
|
||||
<div class="dnc-compact-item-list">
|
||||
<h4 class="dnc-compact-subhead"><i class="fa-solid fa-shield-halved"></i> {{localize "DNC.UI.Armors"}}</h4>
|
||||
{{#each this.armors}}
|
||||
<div class="dnc-compact-item">
|
||||
<span class="dnc-compact-item-name">{{this.name}}</span>
|
||||
<span class="dnc-compact-item-detail">{{this.protectionDie}}</span>
|
||||
{{#if this.remainingProtection}}<span class="dnc-compact-item-detail">ARM {{this.remainingProtection}}</span>{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
|
||||
<!-- SECTION : MAGIE -->
|
||||
<section class="dnc-compact-section dnc-compact-magie">
|
||||
<h3 class="dnc-compact-section-title">
|
||||
<i class="fa-solid fa-book-sparkles" aria-hidden="true"></i>
|
||||
{{localize "DNC.Dialog.EmployeesTabMagie"}}
|
||||
</h3>
|
||||
<div class="dnc-compact-magic-stats">
|
||||
<div class="dnc-carac-stat">
|
||||
<span class="dnc-carac-label">{{localize "DNC.UI.Rank"}}</span>
|
||||
<span class="dnc-carac-value">{{this.magicRank}}</span>
|
||||
</div>
|
||||
<div class="dnc-carac-stat">
|
||||
<span class="dnc-carac-label">{{localize "DNC.UI.Focus"}}</span>
|
||||
<span class="dnc-carac-value">{{this.focusDisplay}}</span>
|
||||
</div>
|
||||
<div class="dnc-carac-stat">
|
||||
<span class="dnc-carac-label">{{localize "DNC.UI.Chaos"}}</span>
|
||||
<span class="dnc-carac-value">{{this.chaosDisplay}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if this.spells.length}}
|
||||
<div class="dnc-compact-item-list">
|
||||
<h4 class="dnc-compact-subhead"><i class="fa-solid fa-book-sparkles"></i> Sortilèges</h4>
|
||||
{{#each this.spells}}
|
||||
<div class="dnc-compact-item">
|
||||
<span class="dnc-compact-item-name">{{this.name}}</span>
|
||||
{{#if this.usageLabel}}<span class="item-meta">{{this.usageLabel}}</span>{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.capacities.length}}
|
||||
<div class="dnc-compact-item-list">
|
||||
<h4 class="dnc-compact-subhead"><i class="fa-solid fa-brain"></i> Capacités</h4>
|
||||
{{#each this.capacities}}
|
||||
<div class="dnc-compact-item">
|
||||
<span class="dnc-compact-item-name">{{this.name}}</span>
|
||||
{{#if this.usageLabel}}<span class="item-meta">{{this.usageLabel}}</span>{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
{{else}}
|
||||
<p class="empty-state">{{localize "DNC.Empty.NoEmployees"}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<!-- ===== ROOT PANEL : CLIENTS ===== -->
|
||||
<div class="dnc-root-panel"
|
||||
data-root-panel="clients"
|
||||
role="tabpanel"
|
||||
aria-labelledby="root-tab-clients"
|
||||
id="root-panel-clients"
|
||||
>
|
||||
{{#if clients.length}}
|
||||
<!-- Sous-onglets par client -->
|
||||
<nav class="dnc-pc-tabs dnc-client-tabs" role="tablist" aria-label="{{localize 'DNC.Dialog.EmployeesTabClients'}}">
|
||||
{{#each clients}}
|
||||
<button type="button"
|
||||
class="dnc-pc-tab{{#if @first}} active{{/if}}"
|
||||
data-client-tab="{{this.id}}"
|
||||
role="tab"
|
||||
aria-selected="{{#if @first}}true{{else}}false{{/if}}"
|
||||
aria-controls="client-panel-{{this.id}}"
|
||||
id="client-tab-{{this.id}}"
|
||||
>
|
||||
{{this.name}}
|
||||
</button>
|
||||
{{/each}}
|
||||
</nav>
|
||||
|
||||
<!-- Sous-panneaux par client -->
|
||||
<div class="dnc-pc-panels">
|
||||
{{#each clients}}
|
||||
<div class="dnc-client-panel{{#if @first}} active{{/if}}"
|
||||
data-client-panel="{{this.id}}"
|
||||
role="tabpanel"
|
||||
aria-labelledby="client-tab-{{this.id}}"
|
||||
id="client-panel-{{this.id}}"
|
||||
>
|
||||
<!-- SECTION : IDENTITÉ + SANTÉ -->
|
||||
<section class="dnc-compact-section">
|
||||
<h3 class="dnc-compact-section-title">
|
||||
<i class="fa-solid fa-id-card" aria-hidden="true"></i>
|
||||
{{this.name}}
|
||||
<button type="button" class="dnc-open-sheet-btn" data-open-sheet="client" data-token-uuid="{{this.tokenUuid}}" data-actor-id="{{this.id}}" title="Ouvrir la fiche">
|
||||
<i class="fa-solid fa-external-link-alt"></i>
|
||||
</button>
|
||||
</h3>
|
||||
<div class="dnc-compact-carac-grid">
|
||||
{{#if this.species}}<div class="dnc-carac-stat"><span class="dnc-carac-label">Espèce</span><span class="dnc-carac-value">{{this.species}}</span></div>{{/if}}
|
||||
{{#if this.category}}<div class="dnc-carac-stat"><span class="dnc-carac-label">Catégorie</span><span class="dnc-carac-value">{{this.category}}</span></div>{{/if}}
|
||||
{{#if this.role}}<div class="dnc-carac-stat"><span class="dnc-carac-label">Rôle</span><span class="dnc-carac-value">{{this.role}}</span></div>{{/if}}
|
||||
<div class="dnc-carac-stat">
|
||||
<span class="dnc-carac-label">{{localize "DNC.UI.Pv"}}</span>
|
||||
<span class="dnc-carac-value{{#if (lt this.pvValue 3)}} warning{{/if}}">{{this.pvValue}}/{{this.pvMax}}</span>
|
||||
</div>
|
||||
<div class="dnc-carac-stat">
|
||||
<span class="dnc-carac-label">{{localize "DNC.UI.Dv"}}</span>
|
||||
<span class="dnc-carac-value">{{this.dv}}</span>
|
||||
</div>
|
||||
{{#if this.armureDelta}}
|
||||
<div class="dnc-carac-stat dnc-carac-rollable"
|
||||
data-pnj-action="rollArmure"
|
||||
data-token-uuid="{{this.tokenUuid}}"
|
||||
data-actor-id="{{this.id}}"
|
||||
title="Lancer armure Δ{{this.armureDelta}}"
|
||||
>
|
||||
<span class="dnc-carac-label">Armure <i class="fa-solid fa-dice" style="font-size:0.6rem"></i></span>
|
||||
<span class="dnc-carac-value">Δ{{this.armureDelta}}</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if this.courageDelta}}
|
||||
<div class="dnc-carac-stat dnc-carac-rollable"
|
||||
data-pnj-action="rollCourage"
|
||||
data-token-uuid="{{this.tokenUuid}}"
|
||||
data-actor-id="{{this.id}}"
|
||||
title="Lancer courage Δ{{this.courageDelta}}"
|
||||
>
|
||||
<span class="dnc-carac-label">Courage <i class="fa-solid fa-dice" style="font-size:0.6rem"></i></span>
|
||||
<span class="dnc-carac-value">Δ{{this.courageDelta}}</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if this.summary}}<p class="client-summary">{{this.summary}}</p>{{/if}}
|
||||
</section>
|
||||
|
||||
<!-- SECTION : ATTAQUES -->
|
||||
{{#if this.attaques.length}}
|
||||
<section class="dnc-compact-section dnc-compact-combat">
|
||||
<h3 class="dnc-compact-section-title">
|
||||
<i class="fa-solid fa-sword" aria-hidden="true"></i>
|
||||
{{localize "DNC.Dialog.EmployeesTabCombat"}}
|
||||
</h3>
|
||||
<div class="dnc-compact-item-list">
|
||||
{{#each this.attaques}}
|
||||
<div class="dnc-compact-item">
|
||||
<span class="dnc-compact-item-name">{{this.nom}}</span>
|
||||
<button type="button"
|
||||
class="dnc-roll-btn"
|
||||
data-pnj-action="rollAttaque"
|
||||
data-attack-index="{{@index}}"
|
||||
data-token-uuid="{{../tokenUuid}}"
|
||||
data-actor-id="{{../id}}"
|
||||
><i class="fa-solid fa-dice"></i> {{this.degats}}</button>
|
||||
{{#if this.notes}}<span class="dnc-compact-item-detail">{{this.notes}}</span>{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{#if this.weapons.length}}
|
||||
<div class="dnc-compact-item-list" style="margin-top:0.5rem">
|
||||
<h4 class="dnc-compact-subhead"><i class="fa-solid fa-sword"></i> {{localize "DNC.UI.Weapons"}}</h4>
|
||||
{{#each this.weapons}}
|
||||
<div class="dnc-compact-item">
|
||||
<span class="dnc-compact-item-name">{{this.name}}</span>
|
||||
<span class="item-meta">{{this.categoryLabel}}</span>
|
||||
<span class="dnc-compact-item-detail">{{this.damage}}</span>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
{{else if this.weapons.length}}
|
||||
<section class="dnc-compact-section dnc-compact-combat">
|
||||
<h3 class="dnc-compact-section-title">
|
||||
<i class="fa-solid fa-sword" aria-hidden="true"></i>
|
||||
{{localize "DNC.Dialog.EmployeesTabCombat"}}
|
||||
</h3>
|
||||
<div class="dnc-compact-item-list">
|
||||
{{#each this.weapons}}
|
||||
<div class="dnc-compact-item">
|
||||
<span class="dnc-compact-item-name">{{this.name}}</span>
|
||||
<span class="item-meta">{{this.categoryLabel}}</span>
|
||||
<span class="dnc-compact-item-detail">{{this.damage}}</span>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
{{/if}}
|
||||
|
||||
<!-- SECTION : MAGIE / CAPACITÉS -->
|
||||
{{#if this.hasMagie}}
|
||||
<section class="dnc-compact-section dnc-compact-magie">
|
||||
<h3 class="dnc-compact-section-title">
|
||||
<i class="fa-solid fa-book-sparkles" aria-hidden="true"></i>
|
||||
{{localize "DNC.Dialog.EmployeesTabMagie"}}
|
||||
</h3>
|
||||
{{#if this.spells.length}}
|
||||
<div class="dnc-compact-item-list">
|
||||
<h4 class="dnc-compact-subhead"><i class="fa-solid fa-book-sparkles"></i> Sortilèges</h4>
|
||||
{{#each this.spells}}
|
||||
<div class="dnc-compact-item">
|
||||
<span class="dnc-compact-item-name">{{this.name}}</span>
|
||||
{{#if this.usageLabel}}<span class="item-meta">{{this.usageLabel}}</span>{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if this.capacities.length}}
|
||||
<div class="dnc-compact-item-list">
|
||||
<h4 class="dnc-compact-subhead"><i class="fa-solid fa-brain"></i> Capacités</h4>
|
||||
{{#each this.capacities}}
|
||||
<div class="dnc-compact-item">
|
||||
<span class="dnc-compact-item-name">{{this.name}}</span>
|
||||
{{#if this.usageLabel}}<span class="item-meta">{{this.usageLabel}}</span>{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if this.pouvoirsSpeciaux}}
|
||||
<div class="client-description">{{{this.pouvoirsSpeciaux}}}</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
{{else}}
|
||||
<p class="empty-state">{{localize "DNC.Empty.NoClients"}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user