Refonte complète du système Anomalies
- DataModel : renommage value→level (1-4), ajout usesRemaining (0-4), suppression scores/notes - Config : ajout ANOMALY_DEFINITIONS avec compétences applicables par type (8 anomalies) - Fiche item anomalie : header avec level/uses visuels (dots), barre de compétences applicables, 2 onglets Description + Technique/Narratif (suppression onglet Scores) - Fiche PJ onglet Domaines : bloc anomalie proéminent unique avec: - Nom + sous-type + icône - Dots niveau (●●○○) - Dots usages + bouton Utiliser + bouton Réinitialiser - Chips des domaines applicables - Actions : useAnomaly (décrémente usesRemaining), resetAnomalyUses (reset au niveau) - Contrainte : max 1 anomalie par personnage (drop + createAnomaly) - Helpers HBS : lte, gte, lt ajoutés - i18n : nouvelles clés Anomaly.* (level, usesRemaining, use, resetUses, etc.) - CSS : .anomaly-block sur fiche PJ, dots animés, .anomaly-uses-row sur fiche item Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -55,7 +55,7 @@ Hooks.once("init", () => {
|
||||
CONFIG.Actor.trackableAttributes = {
|
||||
character: {
|
||||
bar: ["blessures.lvl"],
|
||||
value: ["initiative", "anomaly.value"],
|
||||
value: ["initiative", "anomaly.level"],
|
||||
},
|
||||
npc: {
|
||||
bar: ["blessures.lvl"],
|
||||
@@ -132,6 +132,15 @@ function _registerHandlebarsHelpers() {
|
||||
// Helper : greater than
|
||||
Handlebars.registerHelper("gt", (a, b) => a > b)
|
||||
|
||||
// Helper : less than or equal
|
||||
Handlebars.registerHelper("lte", (a, b) => a <= b)
|
||||
|
||||
// Helper : greater than or equal
|
||||
Handlebars.registerHelper("gte", (a, b) => a >= b)
|
||||
|
||||
// Helper : less than
|
||||
Handlebars.registerHelper("lt", (a, b) => a < b)
|
||||
|
||||
// Helper : logical OR
|
||||
Handlebars.registerHelper("or", (...args) => args.slice(0, -1).some(Boolean))
|
||||
|
||||
|
||||
10
lang/fr.json
10
lang/fr.json
@@ -47,6 +47,15 @@
|
||||
},
|
||||
"Anomaly": {
|
||||
"type": "Type d'anomalie",
|
||||
"level": "Niveau",
|
||||
"usesRemaining": "Utilisations restantes",
|
||||
"use": "Utiliser l'anomalie",
|
||||
"resetUses": "Réinitialiser les utilisations (nouveau scénario)",
|
||||
"noAnomaly": "Aucune anomalie",
|
||||
"noUsesLeft": "Plus d'utilisations disponibles pour ce scénario",
|
||||
"maxAnomaly": "Un personnage ne peut avoir qu'une seule anomalie",
|
||||
"applicableSkills": "Domaines applicables",
|
||||
"moonDie": "Dé de lune",
|
||||
"none": "Aucune",
|
||||
"entropie": "Entropie",
|
||||
"communicationaveclesmorts": "Communication avec les morts",
|
||||
@@ -143,6 +152,7 @@
|
||||
"extreme": "Extrême"
|
||||
},
|
||||
"Item": {
|
||||
"anomaly": "Anomalie",
|
||||
"anomalies": "Anomalies",
|
||||
"aspects": "Aspects",
|
||||
"attributes": "Attributs",
|
||||
|
||||
@@ -108,6 +108,10 @@ export default class CelestopolActorSheet extends HandlebarsApplicationMixin(fou
|
||||
}
|
||||
|
||||
async _onDropItem(item) {
|
||||
if (item.type === "anomaly" && this.document.itemTypes.anomaly.length > 0) {
|
||||
ui.notifications.warn(game.i18n.localize("CELESTOPOL.Anomaly.maxAnomaly"))
|
||||
return
|
||||
}
|
||||
await this.document.createEmbeddedDocuments("Item", [item.toObject()], { renderSheet: false })
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@ export default class CelestopolCharacterSheet extends CelestopolActorSheet {
|
||||
position: { width: 920, height: 660 },
|
||||
window: { contentClasses: ["character-content"] },
|
||||
actions: {
|
||||
createAnomaly: CelestopolCharacterSheet.#onCreateAnomaly,
|
||||
createAspect: CelestopolCharacterSheet.#onCreateAspect,
|
||||
createAttribute: CelestopolCharacterSheet.#onCreateAttribute,
|
||||
createEquipment: CelestopolCharacterSheet.#onCreateEquipment,
|
||||
createAnomaly: CelestopolCharacterSheet.#onCreateAnomaly,
|
||||
createAspect: CelestopolCharacterSheet.#onCreateAspect,
|
||||
createAttribute: CelestopolCharacterSheet.#onCreateAttribute,
|
||||
createEquipment: CelestopolCharacterSheet.#onCreateEquipment,
|
||||
useAnomaly: CelestopolCharacterSheet.#onUseAnomaly,
|
||||
resetAnomalyUses: CelestopolCharacterSheet.#onResetAnomalyUses,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -64,9 +66,21 @@ export default class CelestopolCharacterSheet extends CelestopolActorSheet {
|
||||
|
||||
case "competences":
|
||||
context.tab = context.tabs.competences
|
||||
context.anomalies = doc.itemTypes.anomaly
|
||||
context.anomaly = doc.itemTypes.anomaly[0] ?? null
|
||||
context.aspects = doc.itemTypes.aspect
|
||||
context.attributes = doc.itemTypes.attribute
|
||||
if (context.anomaly) {
|
||||
const def = SYSTEM.ANOMALY_DEFINITIONS[context.anomaly.system.subtype] ?? SYSTEM.ANOMALY_DEFINITIONS.none
|
||||
context.anomalySkillLabels = def.technicalSkills.map(key => {
|
||||
if (key === "lune") return game.i18n.localize("CELESTOPOL.Anomaly.moonDie")
|
||||
for (const skills of Object.values(SYSTEM.SKILLS)) {
|
||||
if (skills[key]) return game.i18n.localize(skills[key].label)
|
||||
}
|
||||
return key
|
||||
})
|
||||
} else {
|
||||
context.anomalySkillLabels = []
|
||||
}
|
||||
break
|
||||
|
||||
case "blessures":
|
||||
@@ -91,6 +105,10 @@ export default class CelestopolCharacterSheet extends CelestopolActorSheet {
|
||||
}
|
||||
|
||||
static #onCreateAnomaly() {
|
||||
if (this.document.itemTypes.anomaly.length > 0) {
|
||||
ui.notifications.warn(game.i18n.localize("CELESTOPOL.Anomaly.maxAnomaly"))
|
||||
return
|
||||
}
|
||||
this.document.createEmbeddedDocuments("Item", [{
|
||||
name: game.i18n.localize("CELESTOPOL.Item.newAnomaly"), type: "anomaly",
|
||||
}])
|
||||
@@ -113,4 +131,23 @@ export default class CelestopolCharacterSheet extends CelestopolActorSheet {
|
||||
name: game.i18n.localize("CELESTOPOL.Item.newEquipment"), type: "equipment",
|
||||
}])
|
||||
}
|
||||
|
||||
static async #onUseAnomaly(event, target) {
|
||||
const itemId = target.dataset.itemId
|
||||
const anomaly = this.document.items.get(itemId)
|
||||
if (!anomaly) return
|
||||
const current = anomaly.system.usesRemaining
|
||||
if (current <= 0) {
|
||||
ui.notifications.warn(game.i18n.localize("CELESTOPOL.Anomaly.noUsesLeft"))
|
||||
return
|
||||
}
|
||||
await anomaly.update({ "system.usesRemaining": current - 1 })
|
||||
}
|
||||
|
||||
static async #onResetAnomalyUses(event, target) {
|
||||
const itemId = target.dataset.itemId
|
||||
const anomaly = this.document.items.get(itemId)
|
||||
if (!anomaly) return
|
||||
await anomaly.update({ "system.usesRemaining": anomaly.system.level })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { SYSTEM } from "../../config/system.mjs"
|
||||
export class CelestopolAnomalySheet extends CelestopolItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["anomaly"],
|
||||
position: { width: 620, height: 560 },
|
||||
position: { width: 560, height: 460 },
|
||||
}
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-celestopol/templates/anomaly.hbs" },
|
||||
@@ -12,7 +12,16 @@ export class CelestopolAnomalySheet extends CelestopolItemSheet {
|
||||
async _prepareContext() {
|
||||
const ctx = await super._prepareContext()
|
||||
ctx.anomalyTypes = SYSTEM.ANOMALY_TYPES
|
||||
ctx.skills = SYSTEM.SKILLS
|
||||
|
||||
const def = SYSTEM.ANOMALY_DEFINITIONS[ctx.system.subtype] ?? SYSTEM.ANOMALY_DEFINITIONS.none
|
||||
ctx.applicableSkillLabels = def.technicalSkills.map(key => {
|
||||
if (key === "lune") return game.i18n.localize("CELESTOPOL.Anomaly.moonDie")
|
||||
for (const skills of Object.values(SYSTEM.SKILLS)) {
|
||||
if (skills[key]) return game.i18n.localize(skills[key].label)
|
||||
}
|
||||
return key
|
||||
})
|
||||
|
||||
ctx.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
this.document.system.description, { async: true })
|
||||
ctx.enrichedTechnique = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
|
||||
@@ -59,6 +59,23 @@ export const ANOMALY_TYPES = {
|
||||
voyageastral: { id: "voyageastral", label: "CELESTOPOL.Anomaly.voyageastral" },
|
||||
}
|
||||
|
||||
/**
|
||||
* Définitions des anomalies : compétences applicables pour l'usage Technique.
|
||||
* "lune" est une clé spéciale désignant le dé de lune (Entropie).
|
||||
* Les autres clés correspondent aux identifiants de domaine dans SKILLS.
|
||||
*/
|
||||
export const ANOMALY_DEFINITIONS = {
|
||||
none: { technicalSkills: [] },
|
||||
entropie: { technicalSkills: ["lune"] },
|
||||
communicationaveclesmorts:{ technicalSkills: ["instruction", "mtechnologique", "raisonnement", "traitement"] },
|
||||
telekinesie: { technicalSkills: ["echauffouree", "effacement", "mobilite", "prouesse"] },
|
||||
telepathie: { technicalSkills: ["appreciation", "attraction", "echauffouree", "faveur"] },
|
||||
tarotdivinatoire: { technicalSkills: ["appreciation", "arts", "inspiration", "traque"] },
|
||||
illusion: { technicalSkills: ["coercition", "echauffouree", "effacement", "traque"] },
|
||||
suggestion: { technicalSkills: ["artifice", "attraction", "coercition", "faveur"] },
|
||||
voyageastral: { technicalSkills: ["appreciation", "mtechnologique", "traitement", "traque"] },
|
||||
}
|
||||
|
||||
/** Factions du monde de Célestopol. */
|
||||
export const FACTIONS = {
|
||||
pinkerton: { id: "pinkerton", label: "CELESTOPOL.Faction.pinkerton" },
|
||||
@@ -122,6 +139,7 @@ export const SYSTEM = {
|
||||
SKILLS,
|
||||
ALL_SKILLS,
|
||||
ANOMALY_TYPES,
|
||||
ANOMALY_DEFINITIONS,
|
||||
FACTIONS,
|
||||
WOUND_LEVELS,
|
||||
DIFFICULTY_CHOICES,
|
||||
|
||||
@@ -31,15 +31,14 @@ export class CelestopolAnomaly extends foundry.abstract.TypeDataModel {
|
||||
const fields = foundry.data.fields
|
||||
const reqInt = { required: true, nullable: false, integer: true }
|
||||
return {
|
||||
subtype: new fields.StringField({ required: true, nullable: false, initial: "none",
|
||||
choices: Object.keys(SYSTEM.ANOMALY_TYPES) }),
|
||||
value: new fields.NumberField({ ...reqInt, initial: 0, min: 0, max: 8 }),
|
||||
reference: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||
scores: skillScoresSchema(),
|
||||
description: new fields.HTMLField({ required: true, textSearch: true }),
|
||||
technique: new fields.HTMLField({ required: true, textSearch: true }),
|
||||
narratif: new fields.HTMLField({ required: true, textSearch: true }),
|
||||
notes: new fields.HTMLField({ required: true, textSearch: true }),
|
||||
subtype: new fields.StringField({ required: true, nullable: false, initial: "none",
|
||||
choices: Object.keys(SYSTEM.ANOMALY_TYPES) }),
|
||||
level: new fields.NumberField({ ...reqInt, initial: 2, min: 1, max: 4 }),
|
||||
usesRemaining: new fields.NumberField({ ...reqInt, initial: 2, min: 0, max: 4 }),
|
||||
reference: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||
description: new fields.HTMLField({ required: true, textSearch: true }),
|
||||
technique: new fields.HTMLField({ required: true, textSearch: true }),
|
||||
narratif: new fields.HTMLField({ required: true, textSearch: true }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,4 +250,187 @@
|
||||
.section-header { .cel-section-header(); }
|
||||
.enriched-html { font-size: 0.9em; line-height: 1.6; }
|
||||
}
|
||||
|
||||
// ── Bloc Anomalie sur l'onglet Domaines ──────────────────────────────────
|
||||
.anomaly-block {
|
||||
border: 1px solid rgba(196,154,26,0.5);
|
||||
border-radius: 4px;
|
||||
margin-bottom: 12px;
|
||||
overflow: hidden;
|
||||
|
||||
.anomaly-block-header {
|
||||
background: var(--cel-green);
|
||||
background-image: url("../assets/ui/fond_cadrille.jpg");
|
||||
background-blend-mode: soft-light;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 5px 10px;
|
||||
border-bottom: 2px solid var(--cel-orange);
|
||||
|
||||
.anomaly-block-title {
|
||||
font-family: var(--cel-font-title);
|
||||
font-size: 0.85em;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.07em;
|
||||
color: var(--cel-orange);
|
||||
}
|
||||
a { color: var(--cel-orange-light); &:hover { color: var(--cel-orange); } }
|
||||
}
|
||||
|
||||
.anomaly-empty {
|
||||
padding: 12px;
|
||||
text-align: center;
|
||||
color: var(--cel-border);
|
||||
font-style: italic;
|
||||
font-size: 0.85em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
i { font-size: 1.1em; }
|
||||
}
|
||||
|
||||
.anomaly-content {
|
||||
padding: 8px 10px;
|
||||
background: rgba(240,232,212,0.06);
|
||||
|
||||
.anomaly-info-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 7px;
|
||||
|
||||
.anomaly-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
object-fit: cover;
|
||||
border: 1px solid var(--cel-orange);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.anomaly-details {
|
||||
flex: 1;
|
||||
.anomaly-name {
|
||||
font-family: var(--cel-font-title);
|
||||
font-size: 1em;
|
||||
color: var(--cel-orange);
|
||||
font-weight: bold;
|
||||
}
|
||||
.anomaly-subtype {
|
||||
font-size: 0.75em;
|
||||
color: var(--cel-orange-light);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
}
|
||||
|
||||
.anomaly-controls {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
a { color: var(--cel-border); font-size: 0.9em; &:hover { color: var(--cel-orange); } }
|
||||
}
|
||||
}
|
||||
|
||||
.anomaly-level-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 6px;
|
||||
|
||||
.anomaly-level-label {
|
||||
font-size: 0.72em;
|
||||
text-transform: uppercase;
|
||||
color: var(--cel-orange-light);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.anomaly-level-dots {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
.anomaly-level-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--cel-orange);
|
||||
&.active { background: var(--cel-orange); }
|
||||
&.inactive { background: transparent; border-color: rgba(196,154,26,0.25); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.anomaly-uses-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.anomaly-uses-label {
|
||||
font-size: 0.72em;
|
||||
text-transform: uppercase;
|
||||
color: var(--cel-orange-light);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.anomaly-uses-dots {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
.anomaly-dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--cel-orange);
|
||||
&.available { background: var(--cel-orange); }
|
||||
&.spent { background: transparent; }
|
||||
&.inactive { background: transparent; border-color: rgba(196,154,26,0.25); }
|
||||
}
|
||||
}
|
||||
|
||||
.anomaly-use-btn {
|
||||
background: var(--cel-green);
|
||||
border: 1px solid var(--cel-orange);
|
||||
color: var(--cel-orange);
|
||||
font-size: 0.72em;
|
||||
padding: 2px 8px;
|
||||
cursor: pointer;
|
||||
font-family: var(--cel-font-title);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
border-radius: 2px;
|
||||
transition: background 0.15s;
|
||||
&:hover:not(:disabled) { background: var(--cel-green-light); }
|
||||
&:disabled { opacity: 0.4; cursor: default; }
|
||||
}
|
||||
|
||||
.anomaly-reset-btn {
|
||||
color: var(--cel-border);
|
||||
font-size: 0.9em;
|
||||
&:hover { color: var(--cel-orange); }
|
||||
}
|
||||
}
|
||||
|
||||
.anomaly-skills {
|
||||
margin-top: 6px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
|
||||
.anomaly-skills-label {
|
||||
font-size: 0.7em;
|
||||
color: var(--cel-border);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.anomaly-skill-chip {
|
||||
background: rgba(196,154,26,0.1);
|
||||
border: 1px solid rgba(196,154,26,0.3);
|
||||
border-radius: 3px;
|
||||
padding: 1px 5px;
|
||||
font-size: 0.7em;
|
||||
color: var(--cel-orange-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,6 +165,90 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ── Anomaly-specific styles ───────────────────────────────────────────────
|
||||
|
||||
&.anomaly {
|
||||
.anomaly-level-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
label { color: var(--cel-orange-light); font-size: 0.75em; text-transform: uppercase; }
|
||||
.level-input, .anomaly-level-value {
|
||||
width: 38px;
|
||||
background: transparent;
|
||||
border: 1px solid var(--cel-orange-light);
|
||||
color: var(--cel-orange);
|
||||
text-align: center;
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.anomaly-uses-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-top: 5px;
|
||||
padding-top: 4px;
|
||||
border-top: 1px solid rgba(196,154,26,0.2);
|
||||
|
||||
.anomaly-uses-label {
|
||||
color: var(--cel-orange-light);
|
||||
font-size: 0.7em;
|
||||
text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.anomaly-uses-dots { display: flex; gap: 4px; }
|
||||
|
||||
.uses-number-input {
|
||||
width: 34px;
|
||||
background: transparent;
|
||||
border: 1px solid rgba(196,154,26,0.4);
|
||||
color: var(--cel-orange);
|
||||
text-align: center;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
}
|
||||
|
||||
.anomaly-dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--cel-orange);
|
||||
display: inline-block;
|
||||
&.available { background: var(--cel-orange); }
|
||||
&.spent { background: transparent; }
|
||||
&.inactive { background: transparent; border-color: rgba(196,154,26,0.25); }
|
||||
}
|
||||
|
||||
.anomaly-skills-bar {
|
||||
background: rgba(0,0,0,0.18);
|
||||
border-bottom: 1px solid rgba(196,154,26,0.2);
|
||||
padding: 5px 10px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
|
||||
.anomaly-skills-label {
|
||||
color: var(--cel-orange-light);
|
||||
font-size: 0.72em;
|
||||
text-transform: uppercase;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.anomaly-skill-chip {
|
||||
background: rgba(196,154,26,0.12);
|
||||
border: 1px solid rgba(196,154,26,0.35);
|
||||
border-radius: 3px;
|
||||
padding: 1px 6px;
|
||||
font-size: 0.72em;
|
||||
color: var(--cel-orange-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Equipment-specific
|
||||
&.equipment {
|
||||
.equipment-stats {
|
||||
|
||||
@@ -11,19 +11,51 @@
|
||||
<option value="{{key}}" {{#if (eq key ../system.subtype)}}selected{{/if}}>{{localize atype.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
<div class="item-value-field">
|
||||
<label>{{localize "CELESTOPOL.Item.value"}}</label>
|
||||
<input type="number" name="system.value" value="{{system.value}}" min="0" max="8"
|
||||
{{#unless isEditable}}disabled{{/unless}}>
|
||||
<div class="anomaly-level-field">
|
||||
<label>{{localize "CELESTOPOL.Anomaly.level"}}</label>
|
||||
{{#if isEditable}}
|
||||
<input type="number" name="system.level" value="{{system.level}}" min="1" max="4" class="level-input">
|
||||
{{else}}
|
||||
<span class="anomaly-level-value">{{system.level}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{!-- Usages restants : dots visuels --}}
|
||||
<div class="anomaly-uses-row">
|
||||
<span class="anomaly-uses-label">{{localize "CELESTOPOL.Anomaly.usesRemaining"}} :</span>
|
||||
<div class="anomaly-uses-dots">
|
||||
{{#each (array 1 2 3 4) as |n|}}
|
||||
{{#if (lte n ../system.usesRemaining)}}
|
||||
<span class="anomaly-dot available"></span>
|
||||
{{else}}
|
||||
{{#if (lte n ../system.level)}}
|
||||
<span class="anomaly-dot spent"></span>
|
||||
{{else}}
|
||||
<span class="anomaly-dot inactive"></span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{#if isEditable}}
|
||||
<input type="number" name="system.usesRemaining" value="{{system.usesRemaining}}" min="0" max="4" class="uses-number-input">
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{{!-- Domaines applicables --}}
|
||||
{{#if applicableSkillLabels.length}}
|
||||
<div class="anomaly-skills-bar">
|
||||
<span class="anomaly-skills-label">{{localize "CELESTOPOL.Anomaly.applicableSkills"}} :</span>
|
||||
{{#each applicableSkillLabels as |label|}}
|
||||
<span class="anomaly-skill-chip">{{label}}</span>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<nav class="item-tabs sheet-tabs tabs" data-group="item-tabs">
|
||||
<a class="item active" data-group="item-tabs" data-tab="description">{{localize "CELESTOPOL.Tab.description"}}</a>
|
||||
<a class="item" data-group="item-tabs" data-tab="technique">{{localize "CELESTOPOL.Tab.technique"}}</a>
|
||||
<a class="item" data-group="item-tabs" data-tab="scores">{{localize "CELESTOPOL.Item.scores"}}</a>
|
||||
</nav>
|
||||
|
||||
<section class="tab active" data-group="item-tabs" data-tab="description">
|
||||
@@ -47,8 +79,4 @@
|
||||
{{editor system.narratif target="system.narratif" button=true editable=isEditable}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tab" data-group="item-tabs" data-tab="scores">
|
||||
{{> "systems/fvtt-celestopol/templates/partials/item-scores.hbs" skills=skills stats=stats system=system}}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -58,27 +58,79 @@
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
{{!-- Items : Anomalies, Aspects, Attributs --}}
|
||||
{{!-- Items : Anomalie (unique), Aspects, Attributs --}}
|
||||
<div class="items-section">
|
||||
{{!-- Anomalies --}}
|
||||
<div class="items-group">
|
||||
<div class="items-header">
|
||||
<span>{{localize "CELESTOPOL.Item.anomalies"}}</span>
|
||||
{{!-- Anomalie : bloc proéminent unique --}}
|
||||
<div class="anomaly-block">
|
||||
<div class="anomaly-block-header">
|
||||
<span class="anomaly-block-title">{{localize "CELESTOPOL.Item.anomaly"}}</span>
|
||||
{{#if isEditMode}}
|
||||
<a data-action="createAnomaly" title="{{localize 'CELESTOPOL.Item.newAnomaly'}}"><i class="fas fa-plus"></i></a>
|
||||
{{#unless anomaly}}
|
||||
<a data-action="createAnomaly" title="{{localize 'CELESTOPOL.Item.newAnomaly'}}"><i class="fas fa-plus"></i></a>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#each anomalies as |item|}}
|
||||
<div class="item-row" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true">
|
||||
<img src="{{item.img}}" class="item-icon" alt="{{item.name}}">
|
||||
<span class="item-name">{{item.name}}</span>
|
||||
<span class="item-value">{{item.system.value}}</span>
|
||||
<div class="item-controls">
|
||||
<a data-action="edit" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
|
||||
{{#if ../isEditMode}}<a data-action="delete" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>{{/if}}
|
||||
{{#if anomaly}}
|
||||
<div class="anomaly-content" data-item-id="{{anomaly.id}}" data-item-uuid="{{anomaly.uuid}}" data-drag="true">
|
||||
<div class="anomaly-info-row">
|
||||
<img src="{{anomaly.img}}" class="anomaly-icon" alt="{{anomaly.name}}">
|
||||
<div class="anomaly-details">
|
||||
<div class="anomaly-name">{{anomaly.name}}</div>
|
||||
<div class="anomaly-subtype">{{localize (lookup (lookup anomalyTypes anomaly.system.subtype) 'label')}}</div>
|
||||
</div>
|
||||
<div class="anomaly-controls">
|
||||
<a data-action="edit" data-item-uuid="{{anomaly.uuid}}"><i class="fas fa-edit"></i></a>
|
||||
{{#if isEditMode}}<a data-action="delete" data-item-uuid="{{anomaly.uuid}}"><i class="fas fa-trash"></i></a>{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="anomaly-level-row">
|
||||
<span class="anomaly-level-label">{{localize "CELESTOPOL.Anomaly.level"}} :</span>
|
||||
<div class="anomaly-level-dots">
|
||||
{{#each (array 1 2 3 4) as |n|}}
|
||||
<span class="anomaly-level-dot {{#if (lte n ../anomaly.system.level)}}active{{else}}inactive{{/if}}"></span>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="anomaly-uses-row">
|
||||
<span class="anomaly-uses-label">{{localize "CELESTOPOL.Anomaly.usesRemaining"}} :</span>
|
||||
<div class="anomaly-uses-dots">
|
||||
{{#each (array 1 2 3 4) as |n|}}
|
||||
{{#if (lte n ../anomaly.system.usesRemaining)}}
|
||||
<span class="anomaly-dot available"></span>
|
||||
{{else}}
|
||||
{{#if (lte n ../anomaly.system.level)}}
|
||||
<span class="anomaly-dot spent"></span>
|
||||
{{else}}
|
||||
<span class="anomaly-dot inactive"></span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</div>
|
||||
<button class="anomaly-use-btn" data-action="useAnomaly" data-item-id="{{anomaly.id}}"
|
||||
title="{{localize 'CELESTOPOL.Anomaly.use'}}"
|
||||
{{#unless (gt anomaly.system.usesRemaining 0)}}disabled{{/unless}}>
|
||||
<i class="fas fa-bolt"></i> {{localize "CELESTOPOL.Anomaly.use"}}
|
||||
</button>
|
||||
<a class="anomaly-reset-btn" data-action="resetAnomalyUses" data-item-id="{{anomaly.id}}"
|
||||
title="{{localize 'CELESTOPOL.Anomaly.resetUses'}}">
|
||||
<i class="fas fa-rotate-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
{{#if anomalySkillLabels.length}}
|
||||
<div class="anomaly-skills">
|
||||
<span class="anomaly-skills-label">{{localize "CELESTOPOL.Anomaly.applicableSkills"}} :</span>
|
||||
{{#each anomalySkillLabels as |label|}}
|
||||
<span class="anomaly-skill-chip">{{label}}</span>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<div class="anomaly-empty">
|
||||
<i class="fas fa-ghost"></i>
|
||||
<span>{{localize "CELESTOPOL.Anomaly.noAnomaly"}}</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{!-- Aspects --}}
|
||||
|
||||
Reference in New Issue
Block a user