From 5a8b151451696afd4f9d0469675836b055954e90 Mon Sep 17 00:00:00 2001 From: LeRatierBretonnier Date: Sun, 29 Mar 2026 17:03:23 +0200 Subject: [PATCH] Nouveaux items Arme et Armure (DataModel + feuille + CSS) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Items: - CelestopolWeapon : degats (0/1/2/X), portee (contact/courte/longue), description - CelestopolArmure : protection (1-2), malus (0-2), description Config: - WEAPON_DAMAGE_TYPES et WEAPON_RANGE_TYPES ajoutés dans system.mjs - Enregistrement des DataModels, sheets et templates dans fvtt-celestopol.mjs - system.json : types weapon et armure avec htmlFields UI: - weapon.hbs : badge de dégâts avec hint, sélecteurs portée/dégâts - armure.hbs : blocs protection + malus art-déco - items.less : styles .weapon et .armure i18n: clés Weapon.*, Armure.*, Sheet.weapon, Sheet.armure Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- fvtt-celestopol.mjs | 18 ++++++ lang/fr.json | 31 +++++++++- module/applications/_module.mjs | 2 +- module/applications/sheets/item-sheets.mjs | 34 +++++++++++ module/config/system.mjs | 17 ++++++ module/models/_module.mjs | 2 +- module/models/items.mjs | 26 +++++++++ styles/items.less | 57 ++++++++++++++++++ system.json | 67 ++++++++++++++++++---- templates/armure.hbs | 39 +++++++++++++ templates/weapon.hbs | 42 ++++++++++++++ 11 files changed, 321 insertions(+), 14 deletions(-) create mode 100644 templates/armure.hbs create mode 100644 templates/weapon.hbs diff --git a/fvtt-celestopol.mjs b/fvtt-celestopol.mjs index bcf9d5e..4a187a2 100644 --- a/fvtt-celestopol.mjs +++ b/fvtt-celestopol.mjs @@ -10,6 +10,8 @@ import { CelestopolAnomaly, CelestopolAspect, CelestopolEquipment, + CelestopolWeapon, + CelestopolArmure, } from "./module/models/_module.mjs" import { CelestopolActor, @@ -23,6 +25,8 @@ import { CelestopolAnomalySheet, CelestopolAspectSheet, CelestopolEquipmentSheet, + CelestopolWeaponSheet, + CelestopolArmureSheet, } from "./module/applications/_module.mjs" /* ─── Init hook ──────────────────────────────────────────────────────────── */ @@ -41,6 +45,8 @@ Hooks.once("init", () => { CONFIG.Item.dataModels.anomaly = CelestopolAnomaly CONFIG.Item.dataModels.aspect = CelestopolAspect CONFIG.Item.dataModels.equipment = CelestopolEquipment + CONFIG.Item.dataModels.weapon = CelestopolWeapon + CONFIG.Item.dataModels.armure = CelestopolArmure // ── Document classes ──────────────────────────────────────────────────── CONFIG.Actor.documentClass = CelestopolActor @@ -90,6 +96,16 @@ Hooks.once("init", () => { makeDefault: true, label: "CELESTOPOL.Sheet.equipment", }) + foundry.documents.collections.Items.registerSheet(SYSTEM_ID, CelestopolWeaponSheet, { + types: ["weapon"], + makeDefault: true, + label: "CELESTOPOL.Sheet.weapon", + }) + foundry.documents.collections.Items.registerSheet(SYSTEM_ID, CelestopolArmureSheet, { + types: ["armure"], + makeDefault: true, + label: "CELESTOPOL.Sheet.armure", + }) // ── Handlebars helpers ─────────────────────────────────────────────────── _registerHandlebarsHelpers() @@ -197,6 +213,8 @@ function _preloadTemplates() { `${base}/anomaly.hbs`, `${base}/aspect.hbs`, `${base}/equipment.hbs`, + `${base}/weapon.hbs`, + `${base}/armure.hbs`, `${base}/roll-dialog.hbs`, `${base}/chat-message.hbs`, `${base}/partials/item-scores.hbs`, diff --git a/lang/fr.json b/lang/fr.json index ef7393c..bfddd7b 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -184,7 +184,11 @@ "protection": "Protection", "speed": "Vitesse", "crew": "Équipage", - "weight": "Poids" + "weight": "Poids", + "weapons": "Armes", + "armures": "Armures", + "newWeapon": "Nouvelle arme", + "newArmure": "Nouvelle armure" }, "Equipment": { "autre": "Autre", @@ -195,7 +199,9 @@ }, "Sheet": { "editMode": "Mode édition", - "playMode": "Mode jeu" + "playMode": "Mode jeu", + "weapon": "Fiche Arme", + "armure": "Fiche Armure" }, "Setting": { "autoWounds": { @@ -213,6 +219,27 @@ }, "ChatCard": { "rollFor": "Jet de {skill} ({stat})" + }, + "Weapon": { + "degats": "Dégâts", + "degats0": "Dégâts 0", + "degats0Hint": "Mains nues, arme improvisée, matraque, rasoir, arc, couteau", + "degats1": "Dégâts 1", + "degats1Hint": "Arbalète, épée, hachette, masse, rapière, fléau, hache, hallebarde", + "degats2": "Dégâts 2", + "degats2Hint": "Armes à feu", + "degatsX": "Dégâts X", + "degatsXHint": "Explosifs, sélénium, etc. (à l'appréciation du narrateur)", + "portee": "Portée", + "rangeContact": "Contact", + "rangeCourte": "Courte portée", + "rangeLongue": "Longue portée" + }, + "Armure": { + "protection": "Protection", + "protectionHint": "Réduit les blessures subies de ce montant", + "malus": "Malus", + "malusHint": "Malus aux tests de Mobilité et Discrétion (ou Domaine Corps pour PNJ)" } } } \ No newline at end of file diff --git a/module/applications/_module.mjs b/module/applications/_module.mjs index fd3219e..78acc48 100644 --- a/module/applications/_module.mjs +++ b/module/applications/_module.mjs @@ -1,3 +1,3 @@ export { default as CelestopolCharacterSheet } from "./sheets/character-sheet.mjs" export { default as CelestopolNPCSheet } from "./sheets/npc-sheet.mjs" -export { CelestopolAnomalySheet, CelestopolAspectSheet, CelestopolEquipmentSheet } from "./sheets/item-sheets.mjs" +export { CelestopolAnomalySheet, CelestopolAspectSheet, CelestopolEquipmentSheet, CelestopolWeaponSheet, CelestopolArmureSheet } from "./sheets/item-sheets.mjs" diff --git a/module/applications/sheets/item-sheets.mjs b/module/applications/sheets/item-sheets.mjs index 70e969a..05ebf84 100644 --- a/module/applications/sheets/item-sheets.mjs +++ b/module/applications/sheets/item-sheets.mjs @@ -69,3 +69,37 @@ export class CelestopolEquipmentSheet extends CelestopolItemSheet { return ctx } } + +export class CelestopolWeaponSheet extends CelestopolItemSheet { + static DEFAULT_OPTIONS = { + classes: ["weapon"], + position: { width: 480, height: 460 }, + } + static PARTS = { + main: { template: "systems/fvtt-celestopol/templates/weapon.hbs" }, + } + async _prepareContext() { + const ctx = await super._prepareContext() + ctx.damageTypes = SYSTEM.WEAPON_DAMAGE_TYPES + ctx.rangeTypes = SYSTEM.WEAPON_RANGE_TYPES + ctx.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML( + this.document.system.description, { async: true }) + return ctx + } +} + +export class CelestopolArmureSheet extends CelestopolItemSheet { + static DEFAULT_OPTIONS = { + classes: ["armure"], + position: { width: 440, height: 380 }, + } + static PARTS = { + main: { template: "systems/fvtt-celestopol/templates/armure.hbs" }, + } + async _prepareContext() { + const ctx = await super._prepareContext() + ctx.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML( + this.document.system.description, { async: true }) + return ctx + } +} diff --git a/module/config/system.mjs b/module/config/system.mjs index bf29cc2..839537d 100644 --- a/module/config/system.mjs +++ b/module/config/system.mjs @@ -140,6 +140,21 @@ export const EQUIPMENT_TYPES = { vehicule: { id: "vehicule", label: "CELESTOPOL.Equipment.vehicule" }, } +/** Niveaux de dégâts des armes (règles p. ?). */ +export const WEAPON_DAMAGE_TYPES = { + "0": { id: "0", label: "CELESTOPOL.Weapon.degats0", hint: "CELESTOPOL.Weapon.degats0Hint" }, + "1": { id: "1", label: "CELESTOPOL.Weapon.degats1", hint: "CELESTOPOL.Weapon.degats1Hint" }, + "2": { id: "2", label: "CELESTOPOL.Weapon.degats2", hint: "CELESTOPOL.Weapon.degats2Hint" }, + "X": { id: "X", label: "CELESTOPOL.Weapon.degatsX", hint: "CELESTOPOL.Weapon.degatsXHint" }, +} + +/** Portées des armes. */ +export const WEAPON_RANGE_TYPES = { + contact: { id: "contact", label: "CELESTOPOL.Weapon.rangeContact" }, + courte: { id: "courte", label: "CELESTOPOL.Weapon.rangeCourte" }, + longue: { id: "longue", label: "CELESTOPOL.Weapon.rangeLongue" }, +} + export const SYSTEM = { id: SYSTEM_ID, ASCII, @@ -154,4 +169,6 @@ export const SYSTEM = { MOON_DIE_FACES, MOON_RESULT_TYPES, EQUIPMENT_TYPES, + WEAPON_DAMAGE_TYPES, + WEAPON_RANGE_TYPES, } diff --git a/module/models/_module.mjs b/module/models/_module.mjs index 380cd65..d01eccb 100644 --- a/module/models/_module.mjs +++ b/module/models/_module.mjs @@ -1,3 +1,3 @@ export { default as CelestopolCharacter } from "./character.mjs" export { default as CelestopolNPC } from "./npc.mjs" -export { CelestopolAnomaly, CelestopolAspect, CelestopolEquipment } from "./items.mjs" +export { CelestopolAnomaly, CelestopolAspect, CelestopolEquipment, CelestopolWeapon, CelestopolArmure } from "./items.mjs" diff --git a/module/models/items.mjs b/module/models/items.mjs index e9db670..7510f61 100644 --- a/module/models/items.mjs +++ b/module/models/items.mjs @@ -76,3 +76,29 @@ export class CelestopolEquipment extends foundry.abstract.TypeDataModel { } } } + +export class CelestopolWeapon extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields + const reqInt = { required: true, nullable: false, integer: true } + return { + degats: new fields.StringField({ required: true, nullable: false, initial: "0", + choices: Object.keys(SYSTEM.WEAPON_DAMAGE_TYPES) }), + portee: new fields.StringField({ required: true, nullable: false, initial: "contact", + choices: Object.keys(SYSTEM.WEAPON_RANGE_TYPES) }), + description: new fields.HTMLField({ required: true, textSearch: true }), + } + } +} + +export class CelestopolArmure extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields + const reqInt = { required: true, nullable: false, integer: true } + return { + protection: new fields.NumberField({ ...reqInt, initial: 1, min: 1, max: 2 }), + malus: new fields.NumberField({ ...reqInt, initial: 0, min: 0, max: 2 }), + description: new fields.HTMLField({ required: true, textSearch: true }), + } + } +} diff --git a/styles/items.less b/styles/items.less index 9f5475b..9fdfebb 100644 --- a/styles/items.less +++ b/styles/items.less @@ -333,4 +333,61 @@ margin-bottom: 8px; } } + + // Weapon-specific + &.weapon { + .weapon-meta { + display: flex; + gap: 10px; + flex-wrap: wrap; + .form-group { + display: flex; + align-items: center; + gap: 4px; + label { font-size: 0.75em; color: var(--cel-orange-light); white-space: nowrap; } + select { background: rgba(0,0,0,0.3); border: 1px solid var(--cel-orange); color: var(--cel-orange); font-family: var(--cel-font-title); border-radius: 3px; padding: 2px 4px; font-size: 0.85em; } + } + } + .weapon-damage-badge { + display: flex; + align-items: center; + gap: 10px; + background: var(--cel-green-dark); + border: 1px solid var(--cel-orange); + border-radius: 6px; + padding: 6px 12px; + margin: 8px 0; + .damage-label { font-size: 0.72em; text-transform: uppercase; color: var(--cel-orange-light); letter-spacing: 0.05em; } + .damage-value { font-family: var(--cel-font-title); font-size: 1.6em; font-weight: bold; color: var(--cel-orange); min-width: 28px; text-align: center; } + .damage-hint { font-size: 0.78em; color: var(--cel-cream); font-style: italic; } + } + } + + // Armure-specific + &.armure { + .armure-stats { + display: flex; + gap: 14px; + justify-content: center; + margin: 12px 0; + } + .armure-stat-box { + display: flex; + flex-direction: column; + align-items: center; + background: var(--cel-green-dark); + border: 1px solid var(--cel-orange); + border-radius: 6px; + padding: 8px 20px; + min-width: 110px; + label { font-size: 0.72em; text-transform: uppercase; color: var(--cel-orange-light); letter-spacing: 0.05em; } + .armure-stat-value { + input, span { + font-family: var(--cel-font-title); font-size: 1.8em; font-weight: bold; color: var(--cel-orange); + text-align: center; background: transparent; border: none; width: 40px; + } + } + .armure-stat-hint { font-size: 0.7em; color: var(--cel-cream); font-style: italic; text-align: center; margin-top: 4px; } + } + } } diff --git a/system.json b/system.json index 6391324..b4fa914 100644 --- a/system.json +++ b/system.json @@ -15,16 +15,29 @@ ], "flags": { "hotReload": { - "extensions": ["css", "html", "hbs", "json"], - "paths": ["css/", "templates/", "lang/fr.json"] + "extensions": [ + "css", + "html", + "hbs", + "json" + ], + "paths": [ + "css/", + "templates/", + "lang/fr.json" + ] } }, "compatibility": { "minimum": "13", "verified": "13" }, - "esmodules": ["fvtt-celestopol.mjs"], - "styles": ["css/fvtt-celestopol.css?v=1774698726"], + "esmodules": [ + "fvtt-celestopol.mjs" + ], + "styles": [ + "css/fvtt-celestopol.css?v=1774698726" + ], "languages": [ { "lang": "fr", @@ -35,16 +48,50 @@ "documentTypes": { "Actor": { "character": { - "htmlFields": ["description", "notes"] + "htmlFields": [ + "description", + "notes" + ] }, "npc": { - "htmlFields": ["description", "notes"] + "htmlFields": [ + "description", + "notes" + ] } }, "Item": { - "anomaly": { "htmlFields": ["technique", "narratif", "exemples"] }, - "aspect": { "htmlFields": ["description", "technique", "narratif", "notes"] }, - "equipment": { "htmlFields": ["description", "notes"] } + "anomaly": { + "htmlFields": [ + "technique", + "narratif", + "exemples" + ] + }, + "aspect": { + "htmlFields": [ + "description", + "technique", + "narratif", + "notes" + ] + }, + "equipment": { + "htmlFields": [ + "description", + "notes" + ] + }, + "weapon": { + "htmlFields": [ + "description" + ] + }, + "armure": { + "htmlFields": [ + "description" + ] + } } }, "packs": [ @@ -70,4 +117,4 @@ "primaryTokenAttribute": "resource", "socket": true, "background": "systems/fvtt-celestopol/assets/ui/celestopol_background.webp" -} +} \ No newline at end of file diff --git a/templates/armure.hbs b/templates/armure.hbs new file mode 100644 index 0000000..69a63a2 --- /dev/null +++ b/templates/armure.hbs @@ -0,0 +1,39 @@ +
+
+
+ {{item.name}} +
+
+ +
+
+ +
+
+ +
+ {{#if isEditable}} + + {{else}} + {{system.protection}} + {{/if}} +
+
{{localize "CELESTOPOL.Armure.protectionHint"}}
+
+
+ +
+ {{#if isEditable}} + + {{else}} + {{system.malus}} + {{/if}} +
+
{{localize "CELESTOPOL.Armure.malusHint"}}
+
+
+ +
+ {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}} +
+
diff --git a/templates/weapon.hbs b/templates/weapon.hbs new file mode 100644 index 0000000..1a96ae0 --- /dev/null +++ b/templates/weapon.hbs @@ -0,0 +1,42 @@ +
+
+
+ {{item.name}} +
+
+ +
+
+ + +
+
+ + +
+
+
+
+ +
+ {{localize "CELESTOPOL.Weapon.degats"}} + {{system.degats}} + {{localize (lookup (lookup damageTypes system.degats) "hint")}} +
+ +
+ {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}} +
+