From cf905cdcfbd4f0e9bb63f0e7bb5663a9042a4924 Mon Sep 17 00:00:00 2001 From: LeRatierBretonnier Date: Tue, 4 Aug 2026 20:34:20 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20fiche=20PNJ=20(profil=20+=20niveaux)=20?= =?UTF-8?q?et=20passage=20du=20v=C3=A9hicule=20en=20acteur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/icons/actors/vehicle.webp | Bin 0 -> 74146 bytes lang/en.json | 11 +- lang/fr.json | 11 +- less/actor/npc.less | 159 ++++++------- less/actor/vehicle.less | 172 +++++++++++++++ less/vermine2047.less | 1 + module/applications/sheets/_module.mjs | 2 +- .../applications/sheets/base-actor-sheet.mjs | 38 ++++ .../applications/sheets/character-sheet.mjs | 2 +- module/applications/sheets/group-sheet.mjs | 8 +- module/applications/sheets/item-sheets.mjs | 28 --- module/applications/sheets/npc-sheet.mjs | 48 ++-- module/applications/sheets/vehicle-sheet.mjs | 76 +++++++ module/models/npc.mjs | 137 ++++++------ module/models/vehicle.mjs | 44 +++- module/system/config.mjs | 8 +- module/system/dialogs/npcRollDialog.mjs | 208 ++++++++++++++++++ module/system/exchange.mjs | 32 ++- module/system/roll.mjs | 15 +- module/vermine2047.mjs | 22 +- system.json | 4 +- templates/actor/appv2/character-equipment.hbs | 41 ++++ templates/actor/appv2/group-road.hbs | 25 ++- templates/actor/appv2/npc-characteristics.hbs | 116 ---------- templates/actor/appv2/npc-combat.hbs | 73 +++--- templates/actor/appv2/npc-main.hbs | 38 +++- templates/actor/appv2/npc-skills.hbs | 45 ---- templates/actor/appv2/npc-threat.hbs | 75 ------- templates/actor/appv2/npc-traits.hbs | 86 ++++++++ templates/actor/appv2/vehicle-main.hbs | 94 ++++++++ templates/actor/appv2/vehicle-specs.hbs | 83 +++++++ templates/actor/group/group-vehicles.hbs | 31 ++- templates/dialogs/npc-roll-dialog.hbs | 105 +++++++++ templates/item/chatCards/vehicle.hbs | 83 ------- templates/item/item-vehicle-sheet.hbs | 64 ------ templates/roll-message.hbs | 10 +- 36 files changed, 1288 insertions(+), 707 deletions(-) create mode 100644 assets/icons/actors/vehicle.webp create mode 100644 less/actor/vehicle.less create mode 100644 module/applications/sheets/vehicle-sheet.mjs create mode 100644 module/system/dialogs/npcRollDialog.mjs delete mode 100644 templates/actor/appv2/npc-characteristics.hbs delete mode 100644 templates/actor/appv2/npc-skills.hbs delete mode 100644 templates/actor/appv2/npc-threat.hbs create mode 100644 templates/actor/appv2/npc-traits.hbs create mode 100644 templates/actor/appv2/vehicle-main.hbs create mode 100644 templates/actor/appv2/vehicle-specs.hbs create mode 100644 templates/dialogs/npc-roll-dialog.hbs delete mode 100644 templates/item/chatCards/vehicle.hbs delete mode 100644 templates/item/item-vehicle-sheet.hbs diff --git a/assets/icons/actors/vehicle.webp b/assets/icons/actors/vehicle.webp new file mode 100644 index 0000000000000000000000000000000000000000..84a296a3f85fdf5648d0a89cbca9810c52875cad GIT binary patch literal 74146 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

v&WU^+2a@JS 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 YD)hjS++cx=v)yLIVa&r`;+}`V0Q9)GOaK4? literal 0 HcmV?d00001 diff --git a/lang/en.json b/lang/en.json index e7b2eb4..410568a 100644 --- a/lang/en.json +++ b/lang/en.json @@ -16,7 +16,7 @@ "TYPES.Item.item": "Item", "TYPES.Item.weapon": "Weapon", "TYPES.Item.defense": "Defense", - "TYPES.Item.vehicle": "Vehicle", + "TYPES.Actor.vehicle": "Vehicle", "TYPES.Item.ability": "Ability", "TYPES.Item.specialty": "Specialty", "TYPES.Item.background": "Background", @@ -145,6 +145,8 @@ }, "pool": "Reserve", "pools": "Reserves", + "dice_pool": "Dice pool", + "auto_successes": "automatic successes", "self_control": "Self-control", "effort": "Effort", "equip": "Equip", @@ -174,6 +176,7 @@ "range": "Range", "ranges": "Ranges", "mobility": "Mobility", + "vehicle": "Vehicle", "vehicle_specs": "Vehicle specifications", "kind": "Kind", "kind_vehicle": "Vehicle", @@ -183,6 +186,8 @@ "speed_duration_ph": "top speed duration (e.g. 10 min)", "effort_reserve": "Effort reserve", "maintenance": "Maintenance", + "owner": "Owner", + "no_vehicles": "No vehicles", "rarity": "Rarity", "rarity_sm": "Rar.", "reliability": "Reliability", @@ -214,6 +219,7 @@ "type_npc": "NPC", "type_creature": "Creature", "type_community": "Community", + "type_vehicle": "Vehicle", "type": "Type", "group_members": "Members", "encounters": "Encounters", @@ -394,7 +400,8 @@ "npc": "NPC", "group": "Group", "creature": "Creature", - "community": "Community" + "community": "Community", + "vehicle": "Vehicle" }, "base_values": "Base Values", "computed_values": "Computed Values", diff --git a/lang/fr.json b/lang/fr.json index 99c17b9..07e2fb6 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -8,7 +8,7 @@ "TYPES.Item.item": "Objet", "TYPES.Item.weapon": "Arme", "TYPES.Item.defense": "Protection", - "TYPES.Item.vehicle": "Véhicule", + "TYPES.Actor.vehicle": "Véhicule", "TYPES.Item.ability": "Capacité", "TYPES.Item.specialty": "Spécialité", "TYPES.Item.background": "Historique", @@ -152,6 +152,8 @@ "pool": "Réserve", "pools": "Réserves", "reserves": "Réserves", + "dice_pool": "Pool de dés", + "auto_successes": "réussites automatiques", "self_control": "Sang-Froid", "effort": "Effort", "equip": "Équiper", @@ -255,6 +257,7 @@ "range": "Portée", "ranges": "Portées", "mobility": "Mobilité", + "vehicle": "Véhicule", "vehicle_specs": "Caractéristiques du véhicule", "kind": "Type", "kind_vehicle": "Véhicule", @@ -264,6 +267,8 @@ "speed_duration_ph": "durée de pointe (ex: 10 min)", "effort_reserve": "Réserve d'Effort", "maintenance": "Entretien", + "owner": "Propriétaire", + "no_vehicles": "Aucun véhicule", "rarity": "Rareté", "rarity_sm": "Rar.", "reliability": "Fiabilité", @@ -405,6 +410,7 @@ "type_npc": "PNJ", "type_creature": "Créature", "type_community": "Communauté", + "type_vehicle": "Véhicule", "type": "Type", "group_members": "Membres", "encounters": "Rencontres", @@ -451,7 +457,8 @@ "npc": "PNJ", "group": "Groupe", "creature": "Créature", - "community": "Communauté" + "community": "Communauté", + "vehicle": "Véhicule" } }, "UI": { diff --git a/less/actor/npc.less b/less/actor/npc.less index f3d61cc..f56fcf7 100644 --- a/less/actor/npc.less +++ b/less/actor/npc.less @@ -30,77 +30,70 @@ } } - .skills-container { - display: flex; - flex-direction: column; - gap: 15px; - } - - .skill-category { - .card-style(); - padding: 10px; - - h4 { - font-family: "DistressBlack", sans-serif; - font-size: @font-size-14; - text-transform: uppercase; - margin-top: 0; - margin-bottom: 8px; - background: 50% 0% / cover no-repeat url("@{ui-path}/scotch.webp"); - } - } - - .skill-item { - display: flex; - align-items: center; - gap: 8px; - padding: 5px; - border-bottom: 1px solid @color-border-dark-3; - - &:last-child { border-bottom: none; } - - label { - flex: 1; + .npc-trait-list { + li { + display: flex; + align-items: center; + gap: 6px; + padding: 4px 0; + border-bottom: 1px solid @color-border-dark-3; font-size: @font-size-12; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + + &:last-child { border-bottom: none; } + + strong { flex: 1; } } + .trait-value { + min-width: 30px; + text-align: center; + font-weight: bold; + white-space: nowrap; + } + } + + .npc-roll-btn { + color: @color-text-light-primary; + opacity: 0.7; + transition: opacity 0.15s ease; + &:hover { - box-shadow: 0 0 10px @theme-color-highlight inset; + opacity: 1; + color: @color-text-light-1; + text-shadow: 0 0 6px @theme-color-highlight; } } - .skill-control { - display: flex; - align-items: center; - gap: 5px; + .npc-wounds { + flex-wrap: wrap; + + .wound-cat { + display: inline-flex; + align-items: center; + gap: 4px; + font-weight: bold; + } + + .wound-boxes { + display: inline-flex; + gap: 2px; + + i { + font-size: 8px; + color: @color-border-dark-2; + } + } } - .skill-value { - min-width: 25px; - text-align: center; - font-weight: bold; - } + .npc-free-skills { + margin-top: 15px; + .form-group-style(); - .rarity-badge { - display: inline-block; - padding: 1px 4px; - border-radius: 3px; - font-size: 10px; - font-weight: bold; - margin-left: 5px; - - &.rarity-0 { .rarity-badge(@rarity-0-bg, @rarity-0-text); } - &.rarity-1 { .rarity-badge(@rarity-1-bg, @rarity-1-text); } - &.rarity-2 { .rarity-badge(@rarity-2-bg, @rarity-2-text); } - &.rarity-3 { .rarity-badge(@rarity-3-bg, @rarity-3-text); } - } - - .skill-category-selector { - margin-bottom: 15px; - .card-style(); + label { + font-size: @font-size-12; + font-weight: bold; + white-space: nowrap; + } } .wounds-card { @@ -133,39 +126,6 @@ } } - .ability-section { - .card-style(); - } - - .ability-category-header { - font-family: "DistressBlack", sans-serif; - font-size: @font-size-14; - text-transform: uppercase; - margin-top: 0; - margin-bottom: 8px; - border-bottom: 1px solid @color-border-dark-3; - padding-bottom: 5px; - } - - .ability-item { - display: flex; - align-items: center; - gap: 8px; - padding: 5px 0; - - label { - flex: 1; - font-size: @font-size-12; - white-space: nowrap; - } - } - - .ability-control { - display: flex; - align-items: center; - gap: 8px; - } - .tab { padding: 10px; overflow-y: auto; @@ -213,6 +173,17 @@ padding: 3px 5px; min-width: 100px; } + + input[type="text"] { + font-size: @font-size-12; + padding: 3px 5px; + min-width: 0; + width: 100%; + } + } + + .npc-profile-grid { + grid-template-columns: repeat(4, minmax(0, 1fr)); } .editor { diff --git a/less/actor/vehicle.less b/less/actor/vehicle.less new file mode 100644 index 0000000..265c8ad --- /dev/null +++ b/less/actor/vehicle.less @@ -0,0 +1,172 @@ +@import "../variables"; +@import "../utilities"; + +.system-vermine2047 .vermine2047.actor.vehicle { + display: grid !important; + grid-template-columns: 1fr !important; + grid-template-rows: auto 1fr auto !important; + + > header.window-header { + grid-column: 1; + grid-row: 1; + } + + > section.window-content { + grid-column: 1; + grid-row: 2; + } + + > div.window-resize-handle { + grid-column: 1; + grid-row: 3; + } + + .window-content { + display: grid; + grid-template-rows: auto auto 1fr; + grid-template-columns: 1fr; + overflow: hidden; + + > .tab.main { + grid-column: 1; + grid-row: 1; + display: flex !important; + flex-direction: column; + overflow-y: auto; + padding: 8px; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + } + + > nav.tabs { + grid-column: 1; + grid-row: 2; + } + + > .tab:not(.main) { + grid-column: 1; + grid-row: 3; + display: none; + overflow-y: auto; + padding: 8px; + + &.active { + display: flex; + flex-direction: column; + } + } + } + + .sheet-header { + .background-image(url("@{ui-path}/barre_haut.webp"), no-repeat, 100% 100%, right top); + padding: 10px; + max-height: 130px; + } + + .header-fields { flex: 1; } + + .resource { + .card-style(); + } + + .resource-label { + font-weight: bold; + margin-right: 8px; + min-width: 60px; + font-size: @font-size-12; + } + + .resource-content { + display: flex; + align-items: center; + + select { + margin-right: 8px; + min-width: 100px; + } + + input[type="number"] { + width: 60px; + text-align: center; + } + } + + .charname { + margin: 0; + + input { + width: 100%; + font-size: @font-size-18; + font-weight: bold; + text-align: center; + } + } + + .vehicle-owner { + display: flex; + gap: 6px; + margin-bottom: 8px; + padding: 6px 8px; + border: 1px dashed @color-hemolymph; + background: fade(@color-hemolymph, 8%); + + .label { + font-family: "DistressBlack", sans-serif; + text-transform: uppercase; + font-size: @font-size-11; + color: @color-amber; + } + } + + .vehicle-section { + padding: 8px; + border: 1px solid @color-border-dark-4; + background: fade(@color-chitin-dark, 20%); + margin-bottom: 8px; + + h3 { + font-family: "DistressBlack", sans-serif; + text-transform: uppercase; + font-size: @font-size-13; + color: @theme-color-dark; + margin: 0 0 8px; + text-align: left; + border-bottom: none; + } + + .resource-label { + display: block; + margin: 0 0 4px; + min-width: 0; + } + + .unit { + font-size: @font-size-11; + color: @color-text-light-0; + opacity: 0.8; + } + + .maintenance { + margin-top: 8px; + + .flexrow label { + gap: 4px; + margin-right: 12px; + font-size: @font-size-12; + } + } + + .form-group { + label { + font-family: "DistressBlack", sans-serif; + text-transform: uppercase; + font-size: @font-size-11; + color: @color-amber; + } + } + } + + input[type="text"] { + width: 100%; + padding: 5px; + } +} diff --git a/less/vermine2047.less b/less/vermine2047.less index af9cea7..355e4b7 100644 --- a/less/vermine2047.less +++ b/less/vermine2047.less @@ -23,6 +23,7 @@ @import "actor/group"; @import "actor/creature"; @import "actor/community"; +@import "actor/vehicle"; // 6. Styles des items @import "items"; diff --git a/module/applications/sheets/_module.mjs b/module/applications/sheets/_module.mjs index cfe806c..ad39a94 100644 --- a/module/applications/sheets/_module.mjs +++ b/module/applications/sheets/_module.mjs @@ -5,11 +5,11 @@ export { default as VermineNpcSheetV2 } from "./npc-sheet.mjs" export { default as VermineGroupSheetV2 } from "./group-sheet.mjs" export { default as VermineCreatureSheetV2 } from "./creature-sheet.mjs" export { default as VermineCommunitySheetV2 } from "./community-sheet.mjs" +export { default as VermineVehicleSheetV2 } from "./vehicle-sheet.mjs" export { VermineItemSheetV2, VermineWeaponSheetV2, VermineDefenseSheetV2, - VermineVehicleSheetV2, VermineAbilitySheetV2, VermineSpecialtySheetV2, VermineBackgroundSheetV2, diff --git a/module/applications/sheets/base-actor-sheet.mjs b/module/applications/sheets/base-actor-sheet.mjs index a18bd4d..6a0109f 100644 --- a/module/applications/sheets/base-actor-sheet.mjs +++ b/module/applications/sheets/base-actor-sheet.mjs @@ -32,6 +32,9 @@ export default class VermineBaseActorSheet extends HandlebarsApplicationMixin(fo delete: VermineBaseActorSheet.#onItemDelete, toggleEquip: VermineBaseActorSheet.#onToggleEquip, create: VermineBaseActorSheet.#onItemCreate, + createVehicle: VermineBaseActorSheet.#onCreateVehicle, + editVehicle: VermineBaseActorSheet.#onEditVehicle, + deleteVehicle: VermineBaseActorSheet.#onDeleteVehicle, roll: VermineBaseActorSheet.#onRollItem, attack: VermineBaseActorSheet.#onAttack, clickRadio: VermineBaseActorSheet.#onClickRadioHexa, @@ -229,11 +232,46 @@ export default class VermineBaseActorSheet extends HandlebarsApplicationMixin(fo await this.document.createEmbeddedDocuments("Item", [{ name, type }]) } + // ── Véhicules (acteurs) ────────────────────────────────────────────── + + /** Crée un acteur "vehicle" rattaché à cet acteur (groupe ou personnage). */ + static async #onCreateVehicle(event, target) { + const name = game.i18n.localize("ITEMS.new_vehicle") + const vehicle = await Actor.create({ + name, + type: "vehicle", + system: { ownerId: this.document.id }, + // Le véhicule est un bien partagé : reprendre la propriété du propriétaire + ownership: foundry.utils.deepClone(this.document.ownership) + }) + vehicle?.sheet.render(true) + } + + static async #onEditVehicle(event, target) { + const id = target.closest("[data-vehicle-id]")?.dataset?.vehicleId + const vehicle = game.actors.get(id) + vehicle?.sheet.render(true) + } + + static async #onDeleteVehicle(event, target) { + const id = target.closest("[data-vehicle-id]")?.dataset?.vehicleId + const vehicle = game.actors.get(id) + await vehicle?.deleteDialog() + } + static async #onRollItem(event, target) { const id = target.closest("[data-item-id]")?.dataset?.itemId if (!id) return const item = this.document.items.get(id) if (!item) return + // Armes : PNJ → dialogue de combat (valeur d'Attaque) ; personnage → + // dialogue de compétence. Les PNJ n'ont ni caractéristiques ni compétences. + if (item.type === "weapon" && this.document.type === 'npc') { + const { default: CombatDialog } = await import("../../system/dialogs/combatDialog.mjs") + const dialog = await CombatDialog.create({ actorId: this.document.id, weapon: item }) + if (dialog) dialog.render(true) + return + } if (item.type === "weapon" && this.document.system.abilities && this.document.system.skills) { const { default: RollDialog } = await import("../../system/dialogs/rollDialog.mjs") const dialog = await RollDialog.create({ diff --git a/module/applications/sheets/character-sheet.mjs b/module/applications/sheets/character-sheet.mjs index 58e394d..106ec5f 100644 --- a/module/applications/sheets/character-sheet.mjs +++ b/module/applications/sheets/character-sheet.mjs @@ -71,7 +71,7 @@ export default class VermineCharacterSheetV2 extends VermineBaseActorSheet { context.gear = doc.itemTypes.item context.weapons = doc.itemTypes.weapon context.defenses = doc.itemTypes.defense - context.vehicles = doc.itemTypes.vehicle + context.vehicles = game.actors.filter(a => a.type === "vehicle" && a.system.ownerId === doc.id) break case "stories": context.tab = context.tabs.stories diff --git a/module/applications/sheets/group-sheet.mjs b/module/applications/sheets/group-sheet.mjs index f9a0b20..ef5e55e 100644 --- a/module/applications/sheets/group-sheet.mjs +++ b/module/applications/sheets/group-sheet.mjs @@ -80,10 +80,11 @@ export default class VermineGroupSheetV2 extends VermineBaseActorSheet { context.gear = doc.itemTypes.item context.weapons = doc.itemTypes.weapon context.defenses = doc.itemTypes.defense + context.vehicles = this.#getOwnedVehicles() break case "road": context.tab = context.tabs.road - context.vehicles = doc.itemTypes.vehicle + context.vehicles = this.#getOwnedVehicles() break case "reserve": context.tab = context.tabs.reserve @@ -92,6 +93,11 @@ export default class VermineGroupSheetV2 extends VermineBaseActorSheet { return context } + /** Véhicules (acteurs) appartenant à ce groupe via system.ownerId. */ + #getOwnedVehicles() { + return game.actors.filter(a => a.type === "vehicle" && a.system.ownerId === this.document.id) + } + // Actions : délégation aux applications AppV1 existantes pour TotemPicker/ActorPicker static async #onChooseTotem(event, target) { const { TotemPicker } = await import("../../system/applications.mjs") diff --git a/module/applications/sheets/item-sheets.mjs b/module/applications/sheets/item-sheets.mjs index 951ab61..17730a1 100644 --- a/module/applications/sheets/item-sheets.mjs +++ b/module/applications/sheets/item-sheets.mjs @@ -18,34 +18,6 @@ export class VermineDefenseSheetV2 extends VermineBaseItemSheet { static PARTS = { main: { template: "systems/vermine2047/templates/item/item-defense-sheet.hbs", scrollable: [""] } } } -// ── Véhicule ────────────────────────────────────────────────────────── -export class VermineVehicleSheetV2 extends VermineBaseItemSheet { - static DEFAULT_OPTIONS = { classes: ["vehicle"], position: { width: 520 } } - static PARTS = { main: { template: "systems/vermine2047/templates/item/item-vehicle-sheet.hbs", scrollable: [""] } } - - async _prepareContext() { - const context = await super._prepareContext() - // Compétences d'Entretien possibles (mécanique, technologie, artisanat, animalisme…) - const maintenanceKeys = ["mecanical", "technology", "crafting", "animalism", "environment", "wildlife", "flora", "repulsion", "toxics"] - const current = this.document.system.maintenance || [] - context.maintenanceSkills = maintenanceKeys.map(key => ({ - key, - label: game.i18n.localize("SKILLS." + key + ".name"), - checked: current.includes(key) - })) - return context - } - - /** @override - nettoie le tableau d'Entretien (retire les cases non cochées). */ - _prepareSubmitData(event, form, formData, updateData) { - const result = super._prepareSubmitData(event, form, formData, updateData) - if (Array.isArray(result?.system?.maintenance)) { - result.system.maintenance = result.system.maintenance.filter(v => typeof v === "string" && v.trim() !== "") - } - return result - } -} - // ── Capacité ────────────────────────────────────────────────────────── export class VermineAbilitySheetV2 extends VermineBaseItemSheet { static DEFAULT_OPTIONS = { classes: ["ability"], position: { width: 560 } } diff --git a/module/applications/sheets/npc-sheet.mjs b/module/applications/sheets/npc-sheet.mjs index baeb1f9..bc5b78f 100644 --- a/module/applications/sheets/npc-sheet.mjs +++ b/module/applications/sheets/npc-sheet.mjs @@ -2,8 +2,9 @@ import VermineBaseActorSheet from "./base-actor-sheet.mjs" export default class VermineNpcSheetV2 extends VermineBaseActorSheet { - // La fiche PNJ s'ouvre en mode édition : caractéristiques, compétences et - // niveaux se règlent dès l'ouverture (le mode jeu reste accessible via le toggle). + // La fiche PNJ s'ouvre en mode édition : profil et niveaux (Menace, + // Expérience, Rôle) se règlent dès l'ouverture (le mode jeu reste accessible + // via le toggle). _sheetMode = this.constructor.SHEET_MODES.EDIT static DEFAULT_OPTIONS = { @@ -15,22 +16,18 @@ export default class VermineNpcSheetV2 extends VermineBaseActorSheet { static PARTS = { main: { template: "systems/vermine2047/templates/actor/appv2/npc-main.hbs", scrollable: [""] }, tabs: { template: "templates/generic/tab-navigation.hbs" }, - characteristics: { template: "systems/vermine2047/templates/actor/appv2/npc-characteristics.hbs", scrollable: [""] }, - skills: { template: "systems/vermine2047/templates/actor/appv2/npc-skills.hbs", scrollable: [""] }, + traits: { template: "systems/vermine2047/templates/actor/appv2/npc-traits.hbs", scrollable: [""] }, equipment: { template: "systems/vermine2047/templates/actor/appv2/npc-equipment.hbs", scrollable: [""] }, - threat: { template: "systems/vermine2047/templates/actor/appv2/npc-threat.hbs", scrollable: [""] }, combat: { template: "systems/vermine2047/templates/actor/appv2/npc-combat.hbs", scrollable: [""] }, notes: { template: "systems/vermine2047/templates/actor/appv2/npc-notes.hbs", scrollable: [""] } } - tabGroups = { sheet: "characteristics" } + tabGroups = { sheet: "traits" } #getTabs() { const tabs = { - characteristics: { id: "characteristics", group: "sheet", icon: "fas fa-dice", label: "VERMINE.abilities" }, - skills: { id: "skills", group: "sheet", icon: "fas fa-brain", label: "VERMINE.skills" }, + traits: { id: "traits", group: "sheet", icon: "fas fa-dice", label: "VERMINE.traits" }, equipment: { id: "equipment", group: "sheet", icon: "fas fa-hammer", label: "VERMINE.tabs.equipment" }, - threat: { id: "threat", group: "sheet", icon: "fas fa-exclamation-triangle", label: "ADVERSITY.threat" }, combat: { id: "combat", group: "sheet", icon: "fas fa-sword", label: "VERMINE.combat" }, notes: { id: "notes", group: "sheet", icon: "fas fa-sticky-note", label: "IDENTITY.notes" } } @@ -57,20 +54,14 @@ export default class VermineNpcSheetV2 extends VermineBaseActorSheet { context.totemOptions = CONFIG.VERMINE.totems context.originOptions = CONFIG.VERMINE.origins break - case "characteristics": - context.tab = context.tabs.characteristics - break - case "skills": - context.tab = context.tabs.skills + case "traits": + context.tab = context.tabs.traits break case "equipment": context.tab = context.tabs.equipment context.weapons = doc.itemTypes.weapon context.defenses = doc.itemTypes.defense break - case "threat": - context.tab = context.tabs.threat - break case "combat": context.tab = context.tabs.combat context.equippedWeapons = doc.itemTypes.weapon.filter(i => i.system.equipped) @@ -84,4 +75,27 @@ export default class VermineNpcSheetV2 extends VermineBaseActorSheet { } return context } + + /** @override - Le PNJ n'a ni caractéristiques ni compétences : les jets + * rapides utilisent la valeur d'Attaque (dialogue de combat) ou les valeurs + * dérivées Action / Spécialité / Réaction (dialogue PNJ simplifié). */ + async _onRoll(event) { + event.preventDefault() + const el = event.currentTarget + const type = el.dataset.type + if (!type) return + if (type === "attack") { + const { default: CombatDialog } = await import("../../system/dialogs/combatDialog.mjs") + const dialog = await CombatDialog.create({ actorId: this.document.id }) + if (dialog) dialog.render(true) + return + } + if (["action", "specialty", "reaction"].includes(type)) { + const { default: NpcRollDialog } = await import("../../system/dialogs/npcRollDialog.mjs") + const dialog = await NpcRollDialog.create({ actorId: this.document.id, rolltype: type }) + if (dialog) dialog.render(true) + return + } + return super._onRoll(event) + } } diff --git a/module/applications/sheets/vehicle-sheet.mjs b/module/applications/sheets/vehicle-sheet.mjs new file mode 100644 index 0000000..d51f39c --- /dev/null +++ b/module/applications/sheets/vehicle-sheet.mjs @@ -0,0 +1,76 @@ +import VermineBaseActorSheet from "./base-actor-sheet.mjs" + +export default class VermineVehicleSheetV2 extends VermineBaseActorSheet { + + static DEFAULT_OPTIONS = { + classes: ["vehicle"], + position: { width: 640, height: 580 }, + window: { contentClasses: ["vehicle-content"] } + } + + static PARTS = { + main: { template: "systems/vermine2047/templates/actor/appv2/vehicle-main.hbs", scrollable: [""] }, + tabs: { template: "templates/generic/tab-navigation.hbs" }, + specs: { template: "systems/vermine2047/templates/actor/appv2/vehicle-specs.hbs", scrollable: [""] } + } + + tabGroups = { sheet: "specs" } + + #getTabs() { + const tabs = { + specs: { id: "specs", group: "sheet", icon: "fas fa-car-side", label: "VERMINE.vehicle_specs" } + } + for (const v of Object.values(tabs)) { + v.active = this.tabGroups[v.group] === v.id + v.cssClass = v.active ? "active" : "" + } + return tabs + } + + async _prepareContext() { + const context = await super._prepareContext() + context.tabs = this.#getTabs() + // Compétences d'Entretien possibles (mécanique, technologie, artisanat, animalisme…) + const maintenanceKeys = ["mecanical", "technology", "crafting", "animalism", "environment", "wildlife", "flora", "repulsion", "toxics"] + const current = this.document.system.maintenance || [] + context.maintenanceSkills = maintenanceKeys.map(key => ({ + key, + label: game.i18n.localize("SKILLS." + key + ".name"), + checked: current.includes(key) + })) + // Propriétaire (groupe ou personnage) résolu + context.resolvedOwner = null + if (this.document.system.ownerId) { + const owner = game.actors.get(this.document.system.ownerId) + if (owner) context.resolvedOwner = { id: owner.id, name: owner.name } + } + return context + } + + async _preparePartContext(partId, context) { + switch (partId) { + case "main": break + case "specs": + context.tab = context.tabs.specs + break + } + return context + } + + changeTab(tab, group, options = {}) { + super.changeTab(tab, group, options) + if (group === "sheet") { + const main = this.element?.querySelector('[data-group="sheet"][data-tab="main"]') + if (main) main.classList.add("active") + } + } + + /** @override - nettoie le tableau d'Entretien (retire les cases non cochées). */ + _prepareSubmitData(event, form, formData, updateData) { + const result = super._prepareSubmitData(event, form, formData, updateData) + if (Array.isArray(result?.system?.maintenance)) { + result.system.maintenance = result.system.maintenance.filter(v => typeof v === "string" && v.trim() !== "") + } + return result + } +} diff --git a/module/models/npc.mjs b/module/models/npc.mjs index 86a2bc6..6958ac8 100644 --- a/module/models/npc.mjs +++ b/module/models/npc.mjs @@ -2,17 +2,22 @@ * DataModel pour les acteurs de type "npc" (PNJ). * Étend foundry.abstract.TypeDataModel. * - * Note : le champ libre de compétences (texte descriptif) est nommé "freeSkills" - * pour éviter le conflit avec le SchemaField "skills" qui contient les 30 compétences. + * Conforme aux règles des PNJ (regles/regles_pnj.txt) : un PNJ n'a ni + * caractéristiques chiffrées, ni réserves détaillées, ni liste de compétences. + * Il est défini uniquement par son Profil (identité) et trois critères : + * Menace, Expérience et Rôle. Toutes les valeurs utiles en jeu sont dérivées + * des tableaux de référence (CONFIG.VERMINE.npc*Levels) et exposées dans + * "system.computed". + * + * Note : le champ libre de description des Spécialités est nommé "freeSkills" + * pour éviter le conflit avec le champ "skills" que le template.json historique + * définissait comme texte libre pour les PNJ. */ import { woundSchema, combatStatusSchema, equipmentSchema, - attributeSchema, - abilitiesSchema, - skillCategoriesSchema, - skillsSchema + attributeSchema } from "./_shared.mjs" export default class VermineNpcData extends foundry.abstract.TypeDataModel { @@ -23,8 +28,7 @@ export default class VermineNpcData extends foundry.abstract.TypeDataModel { /** * Migration des données avant traitement par le schéma. * Avant DataModel, template.json définissait "skills" comme un champ texte libre - * pour les PNJ. Le DataModel réserve "skills" pour les 30 compétences individuelles - * (SchemaField) et utilise "freeSkills" pour le texte libre. + * pour les PNJ. Le DataModel utilise "freeSkills" pour cette description. * @param {Object} source Données brutes avant validation du schéma * @returns {Object} Données migrées */ @@ -48,9 +52,10 @@ export default class VermineNpcData extends foundry.abstract.TypeDataModel { // Statut de combat (base, difficulté par défaut 9 pour PNJ) combatStatus: combatStatusSchema("9"), - // Identité + // Identité (Profil du PNJ) identity: new fields.SchemaField({ name: new fields.StringField({ required: true, nullable: false, initial: "" }), + age: new fields.StringField({ required: true, nullable: false, initial: "" }), profile: new fields.StringField({ required: true, nullable: false, initial: "" }), origin: new fields.StringField({ required: true, nullable: false, initial: "" }), totem: new fields.StringField({ required: true, nullable: false, initial: "" }), @@ -58,30 +63,29 @@ export default class VermineNpcData extends foundry.abstract.TypeDataModel { notes: new fields.HTMLField({ required: true, initial: "" }) }), - // Attributs (XP, réputation, sang-froid, effort) - attributes: new fields.SchemaField({ - xp: attributeSchema(0, 0, 10), - reputation: attributeSchema(0, 0, 10), - self_control: attributeSchema(0, 0, 5), - effort: attributeSchema(0, 0, 5) - }), - - // Niveaux PNJ (menace, expérience, rôle) + // Critères de définition du PNJ (Menace, Expérience, Rôle) threat: attributeSchema(1, 1, 4), experience: attributeSchema(1, 1, 4), role: attributeSchema(1, 1, 4), - // Compétences (les 30 compétences individuelles) - skills: skillsSchema(), - - // Description libre des compétences (champ texte PNJ) + // Description libre des Spécialités (champ texte PNJ) freeSkills: new fields.StringField({ required: true, nullable: false, initial: "" }), - // Catégories de compétences - skill_categories: skillCategoriesSchema(), - - // Caractéristiques (8) - abilities: abilitiesSchema(), + // Valeurs calculées (dérivées des niveaux de menace / expérience / rôle) + computed: new fields.SchemaField({ + attack: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 0 }), + vigor: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 0 }), + action: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 3 }), + specialties: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 4 }), + rerolls: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 0 }), + contact: new fields.StringField({ required: true, nullable: false, initial: "7" }), + reaction: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 3 }), + reactionBonus: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 0 }), + pools: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 0 }), + gear: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 9 }), + gearHindrance: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 0 }), + protection: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 1 }) + }), // Équipement equipment: equipmentSchema() @@ -92,58 +96,67 @@ export default class VermineNpcData extends foundry.abstract.TypeDataModel { prepareDerivedData() { super.prepareDerivedData() - // 1. Calculer les seuils de blessures selon le niveau de menace + // 1. Calculer les valeurs dérivées selon les niveaux de menace/expérience/rôle + this._setNpcComputedValues() + + // 2. Calculer les seuils de blessures selon le niveau de menace this._setNpcWoundThresholds() - // 2. Calculer les réserves selon le niveau de rôle - this._setNpcAttributes() - - // 3. Définir les libellés des caractéristiques - this._setAbilityLabels() - - // 4. Mettre à jour le statut de combat + // 3. Mettre à jour le statut de combat this._updateCombatStatus() } /** - * Calcule les seuils de blessures à partir du niveau de menace. - * Utilise CONFIG.VERMINE.npcThreatLevels. + * Calcule les valeurs dérivées à partir des niveaux de Menace, Expérience + * et Rôle. Utilise CONFIG.VERMINE.npcThreatLevels, .npcExperienceLevels + * et .npcRoleLevels. + */ + _setNpcComputedValues() { + const threatLevel = this.threat?.value || 1 + const expLevel = this.experience?.value || 1 + const roleLevel = this.role?.value || 1 + + const threatConfig = CONFIG.VERMINE.npcThreatLevels[threatLevel] || {} + const expConfig = CONFIG.VERMINE.npcExperienceLevels[expLevel] || {} + const roleConfig = CONFIG.VERMINE.npcRoleLevels[roleLevel] || {} + + // Menace + this.computed.attack = threatConfig.attack || 0 + this.computed.vigor = threatConfig.vigor || 0 + + // Expérience + this.computed.action = expConfig.action || 3 + this.computed.specialties = expConfig.specialties || 4 + this.computed.rerolls = expConfig.rerolls || 0 + this.computed.contact = expConfig.contact || "7" + + // Rôle + this.computed.reaction = roleConfig.reaction || 0 + this.computed.reactionBonus = roleConfig.reaction_bonus || 0 + this.computed.pools = roleConfig.pools || 0 + this.computed.gear = roleConfig.gear || 9 + this.computed.gearHindrance = roleConfig.gear_hindrance || 0 + this.computed.protection = roleConfig.protection || 1 + } + + /** + * Calcule les seuils et le nombre de boîtes de blessures à partir du + * niveau de menace (tableau "Niveau de Menace"). Utilise + * CONFIG.VERMINE.npcThreatLevels. */ _setNpcWoundThresholds() { - const health = this.abilities?.health?.value || 1 const threatLevel = this.threat?.value || 1 const threatConfig = CONFIG.VERMINE.npcThreatLevels[threatLevel] || {} - this.minorWound.threshold = health - this.majorWound.threshold = health + 3 - this.deadlyWound.threshold = Math.min(health + 7, 10) + this.minorWound.threshold = threatConfig.minorThreshold ?? 1 + this.majorWound.threshold = threatConfig.majorThreshold ?? 4 + this.deadlyWound.threshold = threatConfig.deadlyThreshold ?? 6 this.minorWound.max = threatConfig.minorWound || 1 this.majorWound.max = threatConfig.majorWound || 1 this.deadlyWound.max = threatConfig.deadlyWound || 1 } - /** - * Définit les attributs dérivés (effort, sang-froid) selon le niveau de rôle. - * Utilise CONFIG.VERMINE.npcRoleLevels. - */ - _setNpcAttributes() { - const roleLevel = this.role?.value || 1 - const roleConfig = CONFIG.VERMINE.npcRoleLevels[roleLevel] || {} - - this.attributes.effort.max = roleConfig.pools || 0 - this.attributes.self_control.max = roleConfig.reaction_bonus || 0 - } - - /** - * Définit les libellés localisés des caractéristiques. - */ - _setAbilityLabels() { - for (const [k, v] of Object.entries(this.abilities)) { - v.label = game.i18n.localize(CONFIG.VERMINE.abilities[k]) ?? k - } - } - /** * Met à jour le label du statut de combat en fonction de la difficulté. */ diff --git a/module/models/vehicle.mjs b/module/models/vehicle.mjs index 78ae47f..9cdd93c 100644 --- a/module/models/vehicle.mjs +++ b/module/models/vehicle.mjs @@ -1,43 +1,67 @@ -import { baseItemSchema } from "./_shared.mjs" - /** - * DataModel pour les items de type "vehicle" (véhicules et montures). - * Caractéristiques : Rareté, Fiabilité, Distance, Vitesse (croisière/pointe), - * Entretien (compétences) et Réserve d'Effort (montures). - * @augments {foundry.abstract.TypeDataModel} + * DataModel pour les acteurs de type "vehicle" (véhicules et montures). + * Un véhicule est désormais un acteur (et non un objet) : il possède sa propre + * fiche, peut être posé sur la scène comme un jeton et appartient à un groupe + * ou un personnage via `ownerId`. + * + * Caractéristiques (regles_vehicules.txt) : Rareté, Fiabilité (véhicules), + * Réserve d'Effort (montures), Distance, Vitesse (croisière/pointe) et Entretien. + * Pas de statistiques de combat (les règles ne définissent pas de points de vie). */ +import { raritySchema } from "./_shared.mjs" + export default class VermineVehicleData extends foundry.abstract.TypeDataModel { + /** @override */ - static LOCALIZATION_PREFIXES = ["VERMINE.item.vehicle"] + static LOCALIZATION_PREFIXES = ["VERMINE.vehicle"] /** @override */ static defineSchema() { const fields = foundry.data.fields const reqInt = { required: true, nullable: false, integer: true } return { - ...baseItemSchema(), + // Identité + identity: new fields.SchemaField({ + profile: new fields.StringField({ required: true, nullable: false, initial: "" }), + origin: new fields.StringField({ required: true, nullable: false, initial: "" }), + theme: new fields.StringField({ required: true, nullable: false, initial: "" }), + notes: new fields.HTMLField({ required: true, initial: "", textSearch: true }) + }), + + // Rareté (valeur 1-10 + handicap) + rarity: raritySchema(), + // Fiabilité étendue (1-10) pour les véhicules reliability: new fields.NumberField({ ...reqInt, initial: 5, min: 1, max: 10 }), + // Type : "vehicle" (véhicule) ou "mount" (monture) kind: new fields.StringField({ required: true, nullable: false, initial: "vehicle" }), + // Distance : km parcourus avec un "plein" distance: new fields.NumberField({ ...reqInt, initial: 0, min: 0 }), + // Vitesse : croisière / pointe (durée de la pointe) speed: new fields.SchemaField({ cruise: new fields.NumberField({ ...reqInt, initial: 0, min: 0 }), top: new fields.NumberField({ ...reqInt, initial: 0, min: 0 }), topDuration: new fields.StringField({ required: true, nullable: false, initial: "10 min" }) }), + // Entretien : compétences nécessaires (clés de CONFIG.VERMINE.skills) maintenance: new fields.ArrayField(new fields.StringField({ required: true, nullable: false, initial: "" })), + // Réserve d'Effort (montures) effortReserve: new fields.SchemaField({ value: new fields.NumberField({ ...reqInt, initial: 0, min: 0 }), min: new fields.NumberField({ ...reqInt, initial: 0, min: 0 }), max: new fields.NumberField({ ...reqInt, initial: 0, min: 0 }) }), - // Mobilité (héritée) - mobility: new fields.NumberField({ ...reqInt, initial: 3, min: 0 }) + + // Mobilité + mobility: new fields.NumberField({ ...reqInt, initial: 3, min: 0 }), + + // Propriétaire (id d'acteur : groupe ou personnage) + ownerId: new fields.StringField({ required: true, nullable: false, initial: "" }) } } } diff --git a/module/system/config.mjs b/module/system/config.mjs index 757d81d..e56b1cf 100644 --- a/module/system/config.mjs +++ b/module/system/config.mjs @@ -99,10 +99,10 @@ VERMINE.totemDomains = { * NPC Threat Levels configuration */ VERMINE.npcThreatLevels = { - 1: { "label": "THREAT_LEVELS.minor", "attack": 3, "vigor": 1, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 }, - 2: { "label": "THREAT_LEVELS.serious", "attack": 4, "vigor": 2, "minorWound": 2, "majorWound": 1, "deadlyWound": 1 }, - 3: { "label": "THREAT_LEVELS.major", "attack": 5, "vigor": 3, "minorWound": 2, "majorWound": 1, "deadlyWound": 1 }, - 4: { "label": "THREAT_LEVELS.deadly", "attack": 6, "vigor": 4, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 } + 1: { "label": "THREAT_LEVELS.minor", "attack": 3, "vigor": 1, "minorThreshold": 1, "majorThreshold": 4, "deadlyThreshold": 6, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 }, + 2: { "label": "THREAT_LEVELS.serious", "attack": 4, "vigor": 2, "minorThreshold": 2, "majorThreshold": 5, "deadlyThreshold": 8, "minorWound": 2, "majorWound": 1, "deadlyWound": 1 }, + 3: { "label": "THREAT_LEVELS.major", "attack": 5, "vigor": 3, "minorThreshold": 2, "majorThreshold": 5, "deadlyThreshold": 9, "minorWound": 2, "majorWound": 2, "deadlyWound": 1 }, + 4: { "label": "THREAT_LEVELS.deadly", "attack": 6, "vigor": 4, "minorThreshold": 3, "majorThreshold": 6, "deadlyThreshold": 9, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 } } /** diff --git a/module/system/dialogs/npcRollDialog.mjs b/module/system/dialogs/npcRollDialog.mjs new file mode 100644 index 0000000..7d7826c --- /dev/null +++ b/module/system/dialogs/npcRollDialog.mjs @@ -0,0 +1,208 @@ +import { VermineUtils } from "../roll.mjs" + +const { HandlebarsApplicationMixin } = foundry.applications.api + +/** + * Dialogue de jet simplifié pour les PNJ. + * + * Un PNJ n'a ni caractéristiques ni compétences : toutes ses actions sont + * résolues par une valeur unique dérivée de son Profil (Menace / Expérience / + * Rôle), exposée dans system.computed. Ce dialogue fixe le pool selon le type + * de jet (Action, Spécialité, Attaque ou Réaction) et n'offre que la difficulté, + * le handicap et les bonus simples. + * + * Utilisé par : + * - la fiche PNJ (boutons de jet rapide Action / Spécialité / Réaction) ; + * - la défense des PNJ dans les échanges de coups (mode verrouillé). + */ +export default class NpcRollDialog extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) { + + #actor + + get title() { + return game.i18n.localize("VERMINE.roll") + } + + static DEFAULT_OPTIONS = { + classes: ["vermine-roll"], + tag: "form", + window: { + icon: "fas fa-dice-d10", + resizable: false + }, + position: { + width: 520, + height: 600 + }, + actions: { + roll: NpcRollDialog.#onRoll, + cancel: NpcRollDialog.#onCancel + } + } + + static PARTS = { + main: { template: "systems/vermine2047/templates/dialogs/npc-roll-dialog.hbs" } + } + + static async create(data = {}) { + const actor = data.actor instanceof Actor ? data.actor : await game.actors.get(data.actorId) + if (!actor) { + ui.notifications.warn(game.i18n.localize("VERMINE.error_no_actor_selected")) + return null + } + return new NpcRollDialog({ + actor, + rolltype: data.rolltype ?? "action", + locks: data.locks ?? null, + defense: data.defense ?? null + }) + } + + constructor(options = {}) { + super(options) + this.#actor = options.actor + this.rolltype = options.rolltype ?? "action" + this.locks = options.locks ?? null + this.defense = options.defense ?? null + } + + // ── Getters ────────────────────────────────────────────────────────── + + get computed() { return this.#actor.system?.computed || {} } + + /** Pool de dés selon le type de jet. */ + get pool() { + const c = this.computed + switch (this.rolltype) { + case "specialty": return c.specialties || 0 + case "attack": return c.attack || 0 + case "reaction": return c.reaction || 0 + default: return c.action || 3 + } + } + + /** Réussites automatiques (bonus de Réaction du rôle). */ + get freeSuccesses() { + return this.rolltype === "reaction" ? (this.computed.reactionBonus || 0) : 0 + } + + /** Relances : utilisables uniquement sur les attaques ou les Spécialités. */ + get rerolls() { + if (this.rolltype !== "specialty" && this.rolltype !== "attack") return 0 + return this.computed.rerolls || 0 + } + + get label() { + const keys = { + action: "ADVERSITY.action", + specialty: "ADVERSITY.specialties", + attack: "ADVERSITY.attack", + reaction: "ADVERSITY.reaction" + } + return game.i18n.localize(keys[this.rolltype] || "VERMINE.roll") + } + + // ── Rendu ──────────────────────────────────────────────────────────── + + async _prepareContext() { + const difficultyOptions = [] + for (let d = 3; d <= 10; d++) { + difficultyOptions.push({ difficulty: d, label: String(d) }) + } + let lockedDifficulty = null + let defaultDifficulty = 7 + if (this.locks?.difficulty !== undefined && this.locks?.difficulty !== null) { + lockedDifficulty = parseInt(this.locks.difficulty, 10) + defaultDifficulty = lockedDifficulty + } + return { + actor: this.#actor, + system: this.#actor.system, + config: CONFIG.VERMINE, + rollLabel: this.label, + rolltype: this.rolltype, + pool: this.pool, + freeSuccesses: this.freeSuccesses, + rerolls: this.rerolls, + isDefense: Boolean(this.defense), + lockedDifficulty, + difficultyOptions, + defaultDifficulty, + speakerId: this.#actor.id, + availableItems: this.#actor.items.filter(i => i.type === "item") + } + } + + async _onRender(context, options) { + this.element.dataset.actorId = this.#actor.id + for (const inp of this.element.querySelectorAll("[data-roll]")) { + inp.addEventListener("change", this.#onInputChange.bind(this)) + } + this.element.querySelector("#handicap")?.addEventListener("change", () => this.#updateUI()) + this.#updateUI() + } + + get #el() { return this.element } + + #getHandicap() { + const sel = this.#el.querySelector("#handicap") + return Math.max(0, (parseInt(sel?.value, 10) || 1) - 1) + } + + #getDifficulty() { + const sel = this.#el.querySelector("#difficulty") + return parseInt(sel?.value, 10) || 7 + } + + #getHelped() { return this.#el.querySelector("#helped")?.checked ? 1 : 0 } + + #getGroup() { return parseInt(this.#el.querySelector("#group")?.value, 10) || 0 } + + getPoolBreakdown() { + const help = this.#getHelped() + const group = this.#getGroup() + return { pool: this.pool, help, group, total: this.pool + help + group } + } + + #updateUI() { + const b = this.getPoolBreakdown() + const totalEl = this.#el.querySelector("#dice-pool-total") + if (totalEl) totalEl.textContent = `${b.total}D` + const bonusEl = this.#el.querySelector("#total-bonus") + if (bonusEl) bonusEl.textContent = b.help + b.group + const freeEl = this.#el.querySelector("#free-successes") + if (freeEl) freeEl.textContent = String(this.freeSuccesses) + } + + #onInputChange() { + this.#updateUI() + } + + // ── Actions ────────────────────────────────────────────────────────── + + static async #onCancel(event, target) { + this.close() + } + + static async #onRoll(event, target) { + const label = this.defense + ? (this.defense.type === "parade" + ? game.i18n.localize("VERMINE.defense_parade") + : game.i18n.localize("VERMINE.defense_esquive")) + : this.label + + await VermineUtils.roll({ + actor: this.#actor, + NoD: this.getPoolBreakdown().total, + Reroll: this.rerolls, + difficulty: this.#getDifficulty(), + handicap: this.#getHandicap(), + rollLabel: label, + bonusSuccesses: this.freeSuccesses, + poolBreakdown: this.getPoolBreakdown(), + messageFlags: this.defense ? { "vermine-defense": this.defense } : null + }) + + this.close() + } +} diff --git a/module/system/exchange.mjs b/module/system/exchange.mjs index 17b94c8..00f514c 100644 --- a/module/system/exchange.mjs +++ b/module/system/exchange.mjs @@ -359,6 +359,28 @@ export class VermineExchange { ui.notifications.warn(game.i18n.localize('VERMINE.error_creature_no_defense')) return } + const defense = { + exchangeId: exchange.id, + type, + actorId: actor.id, + actorUuid: actor.uuid, + actorName: actor.name, + difficulty: exchange.difficulty, + parryLevel: type === 'parade' ? this.#parryLevel(actor) : null + } + // PNJ : pas de caractéristiques/compétences — la défense utilise la valeur + // d'Action (Expérience), difficulté verrouillée. + if (actor.type === 'npc') { + const { default: NpcRollDialog } = await import('./dialogs/npcRollDialog.mjs') + const dialog = await NpcRollDialog.create({ + actor, + rolltype: 'action', + locks: { difficulty: exchange.difficulty }, + defense + }) + if (dialog) dialog.render(true) + return + } const { default: RollDialog } = await import('./dialogs/rollDialog.mjs') const locks = this.#defenseLocks(actor, exchange, type) const dialog = await RollDialog.create({ @@ -366,15 +388,7 @@ export class VermineExchange { rolltype: 'skill', label: locks.skill, locks, - defense: { - exchangeId: exchange.id, - type, - actorId: actor.id, - actorUuid: actor.uuid, - actorName: actor.name, - difficulty: exchange.difficulty, - parryLevel: type === 'parade' ? this.#parryLevel(actor) : null - } + defense }) if (dialog) dialog.render(true) } diff --git a/module/system/roll.mjs b/module/system/roll.mjs index 4c1532b..95a51b8 100644 --- a/module/system/roll.mjs +++ b/module/system/roll.mjs @@ -30,6 +30,7 @@ export class VermineUtils { skillLevel = null, hasSpecialty = false, handicap = 0, + bonusSuccesses = 0, poolBreakdown = null, specialtyName = null, weapon = null, @@ -147,9 +148,9 @@ export class VermineUtils { totemBonuses: { ...totemBonus }, baseNoD: NoD, rerolls: Reroll, - selfControl: self_control + selfControl: self_control, + bonusSuccesses: bonusSuccesses }; - // Evaluate the roll await roll.evaluate(); @@ -171,6 +172,7 @@ export class VermineUtils { skillLevel, hasSpecialty, handicap, + bonusSuccesses, poolBreakdown, specialtyName, weapon, @@ -321,6 +323,9 @@ export class VermineUtils { const isTotem = die.classList.contains('human') || die.classList.contains('adapted'); total += isTotem ? 2 : 1; }); + // Réussites automatiques (ex. bonus de Réaction) : ajoutées au total. + const freeSuccesses = parseInt(rollMessage.dataset?.freeSuccesses ?? '0', 10) || 0; + total += freeSuccesses; totalEl.innerText = total; } @@ -488,11 +493,13 @@ export class VermineUtils { } // Verdict const required = 1 + (param.handicap ?? 0); - const total = roll._total ?? 0; + const bonusSuccesses = param.bonusSuccesses ?? 0; + const total = (roll._total ?? 0) + bonusSuccesses; const verdict = { success: total >= required, total, - required + required, + bonusSuccesses }; const content = await foundry.applications.handlebars.renderTemplate("systems/vermine2047/templates/roll-message.hbs", { roll, param, diceStats, verdict }); diff --git a/module/vermine2047.mjs b/module/vermine2047.mjs index 09d24e9..66f764c 100644 --- a/module/vermine2047.mjs +++ b/module/vermine2047.mjs @@ -38,18 +38,20 @@ Hooks.once('init', async function () { CONFIG.Actor.dataModels.group = models.VermineGroupData; CONFIG.Actor.dataModels.creature = models.VermineCreatureData; CONFIG.Actor.dataModels.community = models.VermineCommunityData; + CONFIG.Actor.dataModels.vehicle = models.VermineVehicleData; - // Libellé du type "community" (TYPES.Actor.* du core ne le connaît pas) + // Libellés des types "community"/"vehicle" (TYPES.Actor.* du core ne les connaît pas) CONFIG.Actor.typeLabels ??= {}; CONFIG.Actor.typeLabels.community = "VERMINE.type_community"; + CONFIG.Actor.typeLabels.vehicle = "VERMINE.type_vehicle"; Hooks.once('i18nInit', () => { CONFIG.Actor.typeLabels.community = "VERMINE.type_community"; + CONFIG.Actor.typeLabels.vehicle = "VERMINE.type_vehicle"; }); CONFIG.Item.dataModels.item = models.VermineItemData; CONFIG.Item.dataModels.weapon = models.VermineWeaponData; CONFIG.Item.dataModels.defense = models.VermineDefenseData; - CONFIG.Item.dataModels.vehicle = models.VermineVehicleData; CONFIG.Item.dataModels.ability = models.VermineAbilityData; CONFIG.Item.dataModels.specialty = models.VermineSpecialtyData; CONFIG.Item.dataModels.background = models.VermineBackgroundData; @@ -80,7 +82,7 @@ Hooks.once('init', async function () { // Register sheet application classes (ApplicationV2) // Unregister core sheets foundry.documents.collections.Actors.unregisterSheet("core", foundry.applications.sheets.ActorSheetV2, { - types: ["character", "npc", "group", "creature"] + types: ["character", "npc", "group", "creature", "community", "vehicle"] }) foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1?.sheets?.ItemSheet) @@ -100,6 +102,9 @@ Hooks.once('init', async function () { foundry.documents.collections.Actors.registerSheet("vermine2047", sheets.VermineCommunitySheetV2, { types: ["community"], makeDefault: true, label: "VERMINE.Sheet.community" }) + foundry.documents.collections.Actors.registerSheet("vermine2047", sheets.VermineVehicleSheetV2, { + types: ["vehicle"], makeDefault: true, label: "VERMINE.Sheet.vehicle" + }) // Item sheets — un par type foundry.documents.collections.Items.registerSheet("vermine2047", sheets.VermineItemSheetV2, { @@ -111,9 +116,6 @@ Hooks.once('init', async function () { foundry.documents.collections.Items.registerSheet("vermine2047", sheets.VermineDefenseSheetV2, { types: ["defense"], makeDefault: true }) - foundry.documents.collections.Items.registerSheet("vermine2047", sheets.VermineVehicleSheetV2, { - types: ["vehicle"], makeDefault: true - }) foundry.documents.collections.Items.registerSheet("vermine2047", sheets.VermineAbilitySheetV2, { types: ["ability"], makeDefault: true }) @@ -189,10 +191,8 @@ Hooks.once('init', async function () { "systems/vermine2047/templates/actor/appv2/character-stories.hbs", "systems/vermine2047/templates/actor/appv2/character-combat.hbs", "systems/vermine2047/templates/actor/appv2/npc-main.hbs", - "systems/vermine2047/templates/actor/appv2/npc-characteristics.hbs", - "systems/vermine2047/templates/actor/appv2/npc-skills.hbs", + "systems/vermine2047/templates/actor/appv2/npc-traits.hbs", "systems/vermine2047/templates/actor/appv2/npc-equipment.hbs", - "systems/vermine2047/templates/actor/appv2/npc-threat.hbs", "systems/vermine2047/templates/actor/appv2/npc-combat.hbs", "systems/vermine2047/templates/actor/appv2/npc-notes.hbs", "systems/vermine2047/templates/actor/appv2/group-main.hbs", @@ -208,7 +208,9 @@ Hooks.once('init', async function () { "systems/vermine2047/templates/actor/appv2/community-main.hbs", "systems/vermine2047/templates/actor/appv2/community-identity.hbs", "systems/vermine2047/templates/actor/appv2/community-domains.hbs", - "systems/vermine2047/templates/actor/appv2/community-resources.hbs" + "systems/vermine2047/templates/actor/appv2/community-resources.hbs", + "systems/vermine2047/templates/actor/appv2/vehicle-main.hbs", + "systems/vermine2047/templates/actor/appv2/vehicle-specs.hbs" ]); }); diff --git a/system.json b/system.json index 9d2548c..d7333bd 100644 --- a/system.json +++ b/system.json @@ -35,13 +35,13 @@ "npc": { "htmlFields": ["equipment.description", "identity.notes"] }, "group": { "htmlFields": ["equipment.description", "identity.notes"] }, "creature": { "htmlFields": ["equipment.description", "identity.notes", "identity.biography"] }, - "community": { "htmlFields": ["identity.notes", "location.landmarks", "location.territory", "history.events", "history.relations"] } + "community": { "htmlFields": ["identity.notes", "location.landmarks", "location.territory", "history.events", "history.relations"] }, + "vehicle": { "htmlFields": ["identity.notes"] } }, "Item": { "item": { "htmlFields": ["description"] }, "weapon": { "htmlFields": ["description"] }, "defense": { "htmlFields": ["description"] }, - "vehicle": { "htmlFields": ["description"] }, "ability": { "htmlFields": ["description"] }, "specialty": {}, "background": { "htmlFields": ["description"] }, diff --git a/templates/actor/appv2/character-equipment.hbs b/templates/actor/appv2/character-equipment.hbs index 30ed020..33335ad 100644 --- a/templates/actor/appv2/character-equipment.hbs +++ b/templates/actor/appv2/character-equipment.hbs @@ -86,6 +86,47 @@ {{/each}} +

{{ localize 'IDENTITY.notes'}}

{{formInput systemFields.equipment.fields.description enriched=enrichedEquipmentNotes value=system.equipment.description name="system.equipment.description" toggled=true}} diff --git a/templates/actor/appv2/group-road.hbs b/templates/actor/appv2/group-road.hbs index 068f394..5cf24f5 100644 --- a/templates/actor/appv2/group-road.hbs +++ b/templates/actor/appv2/group-road.hbs @@ -7,31 +7,34 @@
{{ localize 'VERMINE.reliability'}}
{{#if isEditMode}} - + {{/if}}
- {{#each vehicles as |item id|}} -
  • + {{#each vehicles as |vehicle|}} +
  • - - - + + +
    {{#if @root.isEditMode}} - {{/if}}
  • + {{else}} +
  • + {{ localize 'VERMINE.no_vehicles' }} +
  • {{/each}}
    diff --git a/templates/actor/appv2/npc-characteristics.hbs b/templates/actor/appv2/npc-characteristics.hbs deleted file mode 100644 index cb3caa3..0000000 --- a/templates/actor/appv2/npc-characteristics.hbs +++ /dev/null @@ -1,116 +0,0 @@ -
    -

    {{ localize 'VERMINE.abilities' }}

    - - {{!-- Caracteristiques physiques --}} -
    -

    {{ localize 'VERMINE.ability_category.physical' }}

    -
    -
    - -
    - {{#if isEditMode}} - - {{/if}} - {{system.abilities.vigor.value}}D -
    -
    -
    - -
    - {{#if isEditMode}} - - {{/if}} - {{system.abilities.health.value}}D -
    -
    -
    -
    - - {{!-- Caracteristiques manuelles --}} -
    -

    {{ localize 'VERMINE.ability_category.manual' }}

    -
    -
    - -
    - {{#if isEditMode}} - - {{/if}} - {{system.abilities.precision.value}}D -
    -
    -
    - -
    - {{#if isEditMode}} - - {{/if}} - {{system.abilities.reflexes.value}}D -
    -
    -
    -
    - - {{!-- Caracteristiques mentales --}} -
    -

    {{ localize 'VERMINE.ability_category.mental' }}

    -
    -
    - -
    - {{#if isEditMode}} - - {{/if}} - {{system.abilities.knowledge.value}}D -
    -
    -
    - -
    - {{#if isEditMode}} - - {{/if}} - {{system.abilities.perception.value}}D -
    -
    -
    -
    - - {{!-- Caracteristiques sociales --}} -
    -

    {{ localize 'VERMINE.ability_category.social' }}

    -
    -
    - -
    - {{#if isEditMode}} - - {{/if}} - {{system.abilities.will.value}}D -
    -
    -
    - -
    - {{#if isEditMode}} - - {{/if}} - {{system.abilities.empathy.value}}D -
    -
    -
    -
    - - {{!-- Reserves --}} -
    -

    {{ localize 'VERMINE.reserves' }}

    -
    -
    - {{ localize 'VERMINE.effort' }} : {{system.attributes.effort.value}}/{{system.attributes.effort.max}}D -
    -
    - {{ localize 'VERMINE.self_control' }} : {{system.attributes.self_control.value}}/{{system.attributes.self_control.max}}D -
    -
    -
    -
    diff --git a/templates/actor/appv2/npc-combat.hbs b/templates/actor/appv2/npc-combat.hbs index 1240d82..68f57a5 100644 --- a/templates/actor/appv2/npc-combat.hbs +++ b/templates/actor/appv2/npc-combat.hbs @@ -1,56 +1,43 @@
    -
    -
    -

    {{ localize "VERMINE.self_control"}}

    -

    - {{#if isEditMode}} - - {{/if}} - {{ system.attributes.self_control.value }} / {{ - system.attributes.self_control.max }} -

    -
    -
    -

    {{ localize "VERMINE.effort"}}

    -

    - {{#if isEditMode}} - - {{/if}} - {{ system.attributes.effort.value }} / {{ - system.attributes.effort.max }} -

    -
    -
    {{> "systems/vermine2047/templates/actor/parts/actor-equipped-gear.hbs"}} -

    {{ localize - "VERMINE.wounds.name"}}

    +

    {{ localize "VERMINE.wounds.name"}}

    • {{ localize 'VERMINE.wounds.light'}} ({{ system.minorWound.threshold }}) - {{#repeat system.minorWound.max }} - - {{/repeat}}
    • +
      + {{#repeat system.minorWound.max 1 "minorwoundmax"}} +
      + +
      + {{/repeat}} +
      +
    • {{ localize 'VERMINE.wounds.heavy'}} ({{ system.majorWound.threshold }}) - {{#repeat system.majorWound.max }} - - {{/repeat}} +
      + {{#repeat system.majorWound.max 1 "majorwoundmax"}} +
      + +
      + {{/repeat}} +
    • {{ localize 'VERMINE.wounds.deadly'}} ({{ system.deadlyWound.threshold }}) - {{#repeat system.deadlyWound.max }} - - {{/repeat}} +
      + {{#repeat system.deadlyWound.max 1 "deadlywoundmax"}} +
      + +
      + {{/repeat}} +

    {{ localize "UI.effects.name"}}

    diff --git a/templates/actor/appv2/npc-main.hbs b/templates/actor/appv2/npc-main.hbs index 0f7ecc3..7216dee 100644 --- a/templates/actor/appv2/npc-main.hbs +++ b/templates/actor/appv2/npc-main.hbs @@ -20,7 +20,7 @@ {{/if}} - {{!-- Niveaux de Menace, Experience, Role --}} + {{!-- Critères : Menace, Expérience, Rôle --}}
    @@ -29,12 +29,12 @@ {{else}} - {{system.threat.value}} + {{ system.threat.value }} {{/if}}
    @@ -46,12 +46,12 @@ {{else}} - {{system.experience.value}} + {{ system.experience.value }} {{/if}}
    @@ -63,19 +63,39 @@ {{else}} - {{system.role.value}} + {{ system.role.value }} {{/if}} - {{!-- Totem et Origine --}} -
    + {{!-- Profil : âge, activité, totem, origine --}} +
    +
    + +
    + {{#if isEditMode}} + + {{else}} + {{system.identity.age}} + {{/if}} +
    +
    +
    + +
    + {{#if isEditMode}} + + {{else}} + {{system.identity.profile}} + {{/if}} +
    +
    diff --git a/templates/actor/appv2/npc-skills.hbs b/templates/actor/appv2/npc-skills.hbs deleted file mode 100644 index bc57b65..0000000 --- a/templates/actor/appv2/npc-skills.hbs +++ /dev/null @@ -1,45 +0,0 @@ -
    -

    {{ localize 'VERMINE.skills' }}

    - - {{!-- Category Selector --}} -
    - - {{#if isEditMode}} - - {{else}} - {{system.skill_categories.preferred}} - {{/if}} -
    - - {{!-- Skills Grid by Category --}} -
    - {{#each config.skillCategories as |category key|}} - {{#ife key "preferred"}}{{else}} - {{> "systems/vermine2047/templates/actor/parts/npc-skill-category.hbs" - categoryKey=key - categoryLabel=(concat "VERMINE.skill_category." key) - skills=@root.system.skills - }} - {{/ife}} - {{/each}} -
    - - {{!-- Free Skills text field --}} -
    - - {{#if isEditMode}} - - {{else}} - {{system.freeSkills}} - {{/if}} -
    -
    diff --git a/templates/actor/appv2/npc-threat.hbs b/templates/actor/appv2/npc-threat.hbs deleted file mode 100644 index 0925240..0000000 --- a/templates/actor/appv2/npc-threat.hbs +++ /dev/null @@ -1,75 +0,0 @@ -
    -

    {{ localize 'ADVERSITY.threat_details' }}

    -
    - {{!-- Menace --}} -
    -

    {{ localize 'ADVERSITY.threat' }}

    -
      -
    • - {{ localize 'ADVERSITY.attack' }}: - {{ npcThreatLevel "attack" system.threat.value }} -
    • -
    • - {{ localize 'ADVERSITY.vigor' }}: - {{ npcThreatLevel "vigor" system.threat.value }} -
    • -
    • - {{ localize 'ADVERSITY.wounds' }}: - {{ npcThreatLevel "minorWound" system.threat.value }} / - {{ npcThreatLevel "majorWound" system.threat.value }} / - {{ npcThreatLevel "deadlyWound" system.threat.value }} -
    • -
    -
    - - {{!-- Experience --}} -
    -

    {{ localize 'ADVERSITY.experience' }}

    -
      -
    • - {{ localize 'ADVERSITY.action' }}: - {{ npcExperienceLevel "action" system.experience.value }}D -
    • -
    • - {{ localize 'ADVERSITY.specialties' }}: - {{ npcExperienceLevel "specialties" system.experience.value }} -
    • -
    • - {{ localize 'ADVERSITY.rerolls' }}: - {{ npcExperienceLevel "rerolls" system.experience.value }}D -
    • -
    • - {{ localize 'ADVERSITY.contact' }}: - {{ npcExperienceLevel "contact" system.experience.value }} -
    • -
    -
    - - {{!-- Role --}} -
    -

    {{ localize 'ADVERSITY.role' }}

    -
      -
    • - {{ localize 'ADVERSITY.reaction' }}: - {{ npcRoleLevel "reaction" system.role.value }} + {{ npcRoleLevel "reaction_bonus" system.role.value }} -
    • -
    • - {{ localize 'ADVERSITY.pools' }}: - {{ npcRoleLevel "pools" system.role.value }}D -
    • -
    • - {{ localize 'ADVERSITY.gear' }}: - {{ npcRoleLevel "gear" system.role.value }} -
    • -
    • - {{ localize 'ADVERSITY.gear_hindrance' }}: - {{ npcRoleLevel "gear_hindrance" system.role.value }} -
    • -
    • - {{ localize 'ADVERSITY.protection' }}: - {{ npcRoleLevel "protection" system.role.value }} -
    • -
    -
    -
    -
    diff --git a/templates/actor/appv2/npc-traits.hbs b/templates/actor/appv2/npc-traits.hbs new file mode 100644 index 0000000..f850fe1 --- /dev/null +++ b/templates/actor/appv2/npc-traits.hbs @@ -0,0 +1,86 @@ +
    +

    {{ localize 'VERMINE.traits' }}

    +
    + + {{!-- Menace --}} +
    +

    {{ localize 'ADVERSITY.threat' }}

    +
      +
    • + {{ localize 'ADVERSITY.attack' }}: + {{ system.computed.attack }}D + +
    • +
    • + {{ localize 'ADVERSITY.vigor' }}: + {{ system.computed.vigor }}D +
    • +
    • + {{ localize 'ADVERSITY.wounds' }}: + {{#repeat system.minorWound.max}}{{/repeat}} {{ system.minorWound.threshold }} + {{#repeat system.majorWound.max}}{{/repeat}} {{ system.majorWound.threshold }} + {{#repeat system.deadlyWound.max}}{{/repeat}} {{ system.deadlyWound.threshold }} +
    • +
    +
    + + {{!-- Expérience --}} +
    +

    {{ localize 'ADVERSITY.experience' }}

    +
      +
    • + {{ localize 'ADVERSITY.action' }}: + {{ system.computed.action }}D + +
    • +
    • + {{ localize 'ADVERSITY.specialties' }}: + {{ system.computed.specialties }}D + +
    • +
    • + {{ localize 'ADVERSITY.rerolls' }}: + {{ system.computed.rerolls }}D +
    • +
    • + {{ localize 'ADVERSITY.contact' }}: + {{ system.computed.contact }} +
    • +
    +
    + + {{!-- Rôle --}} +
    +

    {{ localize 'ADVERSITY.role' }}

    +
      +
    • + {{ localize 'ADVERSITY.reaction' }}: + {{ system.computed.reaction }}D{{#if system.computed.reactionBonus}} +{{ system.computed.reactionBonus }}{{/if}} + +
    • +
    • + {{ localize 'ADVERSITY.pools' }}: + {{ system.computed.pools }}D +
    • +
    • + {{ localize 'ADVERSITY.gear' }}: + {{ system.computed.gear }}{{#if system.computed.gearHindrance}} ({{ system.computed.gearHindrance }}){{/if}} +
    • +
    • + {{ localize 'ADVERSITY.protection' }}: + {{ system.computed.protection }} +
    • +
    +
    +
    + + {{!-- Spécialités (description libre) --}} +
    + + {{#if isEditMode}} + + {{else}} + {{system.freeSkills}} + {{/if}} +
    +
    diff --git a/templates/actor/appv2/vehicle-main.hbs b/templates/actor/appv2/vehicle-main.hbs new file mode 100644 index 0000000..ea95aa0 --- /dev/null +++ b/templates/actor/appv2/vehicle-main.hbs @@ -0,0 +1,94 @@ +
    + {{!-- Toggle Edit/Play --}} +
    + {{#if isEditMode}} + + {{else}} + + {{/if}} +
    + + {{!-- HEADER --}} +
    + +
    +
    +

    + {{#if isEditMode}} + + {{else}} + {{actor.name}} + {{/if}} +

    +
    + +
    + {{#if isEditMode}} + + {{else}} + {{#ife system.kind "mount"}}{{ localize "VERMINE.kind_mount" }}{{else}}{{ localize "VERMINE.kind_vehicle" }}{{/ife}} + {{/if}} +
    +
    +
    + +
    + {{#if isEditMode}} + + {{else}} + {{system.reliability}} + {{/if}} +
    +
    +
    +
    +
    + +
    + {{#if isEditMode}} + + {{else}} + {{system.rarity.value}} + {{/if}} +
    +
    +
    + +
    + {{#if isEditMode}} + + {{else}} + {{system.mobility}} + {{/if}} +
    +
    +
    + +
    + {{#if isEditMode}} + + {{else}} + {{system.distance}} + {{/if}} + km +
    +
    +
    +
    +
    + + {{#if resolvedOwner}} +
    + {{ localize 'VERMINE.owner' }}: + {{ resolvedOwner.name }} +
    + {{/if}} +
    diff --git a/templates/actor/appv2/vehicle-specs.hbs b/templates/actor/appv2/vehicle-specs.hbs new file mode 100644 index 0000000..aee9653 --- /dev/null +++ b/templates/actor/appv2/vehicle-specs.hbs @@ -0,0 +1,83 @@ +
    +
    +

    {{ localize 'VERMINE.vehicle_specs' }}

    +
    +
    + +
    +
    + km +
    +
    +
    + +
    +
    + / +
    +
    + +
    +
    +
    +
    + +
    +
    + / +
    +
    +
    +
    + +
    +
    +
    +
    + +
    + {{#each maintenanceSkills}} + + {{/each}} +
    +
    +
    + +
    +

    {{ localize 'IDENTITY.profile' }}

    +
    +
    + + {{#if isEditMode}} + + {{else}} + {{system.identity.profile}} + {{/if}} +
    +
    + + {{#if isEditMode}} + + {{else}} + {{system.identity.origin}} + {{/if}} +
    +
    + + {{#if isEditMode}} + + {{else}} + {{system.identity.theme}} + {{/if}} +
    +
    +
    + + {{formInput systemFields.identity.fields.notes enriched=enrichedNotes value=system.identity.notes name="system.identity.notes" toggled=true}} +
    +
    +
    diff --git a/templates/actor/group/group-vehicles.hbs b/templates/actor/group/group-vehicles.hbs index e3db0e6..180ad2f 100644 --- a/templates/actor/group/group-vehicles.hbs +++ b/templates/actor/group/group-vehicles.hbs @@ -5,27 +5,34 @@
    {{ localize 'VERMINE.rarity'}}
    {{ localize 'VERMINE.reliability'}}
    - + {{#if @root.isEditMode}} + + {{/if}}
    - {{#each vehicles as |item id|}} -
  • + {{#each vehicles as |vehicle|}} +
  • - - - + + +
    - + {{/if}}
  • + {{else}} +
  • + {{ localize 'VERMINE.no_vehicles' }} +
  • {{/each}} - \ No newline at end of file + diff --git a/templates/dialogs/npc-roll-dialog.hbs b/templates/dialogs/npc-roll-dialog.hbs new file mode 100644 index 0000000..8475475 --- /dev/null +++ b/templates/dialogs/npc-roll-dialog.hbs @@ -0,0 +1,105 @@ +
    + + + +

    {{ rollLabel }}

    + +
    + {{localize 'VERMINE.dice_pool'}}: + {{ pool }}D + {{#if freeSuccesses}} + +{{ freeSuccesses }} {{localize 'VERMINE.auto_successes'}} + {{/if}} + {{#if rerolls}} + {{localize 'ADVERSITY.rerolls'}}: {{ rerolls }}D + {{/if}} +
    + +
    + + +
    + + +
    + + +
    + + +
    + + +
    + + {{localize 'VERMINE.bonuses'}} + +0D + +
    + +
    + + +
    + +
    + + + D +
    + +
    +
    + + +
    + + 0D + {{#if freeSuccesses}} + + (+{{ freeSuccesses }} {{localize 'VERMINE.auto_successes'}}) + + {{/if}} +
    + +
    + +
    + + +
    +
    diff --git a/templates/item/chatCards/vehicle.hbs b/templates/item/chatCards/vehicle.hbs deleted file mode 100644 index 9e98df0..0000000 --- a/templates/item/chatCards/vehicle.hbs +++ /dev/null @@ -1,83 +0,0 @@ -
    - {{> "systems/vermine2047/templates/item/chatCards/parts/base.hbs"}} - - {{!-- Vehicle specific content --}} -
    - {{#if item.system.mobility}} -
    - {{ localize 'VERMINE.mobility' }}: - {{item.system.mobility}} -
    - {{/if}} - - {{#if item.system.quantity}} -
    - {{ localize 'VERMINE.qty' }}: - {{item.system.quantity}} -
    - {{/if}} - - {{#if item.system.weight}} -
    - {{ localize 'VERMINE.weight' }}: - {{item.system.weight}} -
    - {{/if}} - - {{#if item.system.rarity.value}} -
    - {{ localize 'VERMINE.rarity' }}: - - {{#repeat item.system.rarity.value 1 "i"}} - {{romanNumber i}} - {{/repeat}} - {{#ifgt item.system.rarity.handicap 0}} - ({{romanNumber item.system.rarity.handicap}}) - {{/ifgt}} - -
    - {{/if}} - - {{#if item.system.damages.value}} -
    - {{ localize 'VERMINE.damages' }}: - - {{getDamagesData item.system.damages "state"}} - {{#ifgt item.system.damages.value 1}} - ({{item.system.damages.value}}) - {{/ifgt}} - -
    - {{/if}} - - {{#if item.system.reliability}} -
    - {{ localize 'VERMINE.reliability' }}: - {{item.system.reliability}} -
    - {{/if}} - - {{#if item.system.traits}} -
    - {{ localize 'VERMINE.traits' }}: -
      - {{#each item.system.traits as |trait key|}} - {{#if trait}} -
    • - {{localize (lookup (lookup ../config.traits key) "name")}}: - {{localize (lookup (lookup ../config.traits key) "description")}} -
    • - {{/if}} - {{/each}} -
    -
    - {{/if}} - - {{#if item.system.description}} -
    -

    {{{item.system.description}}}

    -
    - {{/if}} -
    - -
    diff --git a/templates/item/item-vehicle-sheet.hbs b/templates/item/item-vehicle-sheet.hbs deleted file mode 100644 index e28fa38..0000000 --- a/templates/item/item-vehicle-sheet.hbs +++ /dev/null @@ -1,64 +0,0 @@ -
    - {{> "systems/vermine2047/templates/item/partials/header.hbs"}} - -
    - {{> "systems/vermine2047/templates/item/partials/traits.hbs"}} - -
    -

    {{ localize "VERMINE.vehicle_specs" }}

    - -
    -
    - - -
    -
    - -
    - km -
    -
    - -
    - - / - -
    - -
    -
    - -
    -
    - -
    -
    - / -
    -
    -
    -
    - -
    -
    -
    - -
    - -
    - {{#each maintenanceSkills}} - - {{/each}} -
    -
    -
    - - {{> "systems/vermine2047/templates/item/partials/physicalItems.hbs"}} -
    -
    diff --git a/templates/roll-message.hbs b/templates/roll-message.hbs index b0d0913..353fb03 100644 --- a/templates/roll-message.hbs +++ b/templates/roll-message.hbs @@ -1,4 +1,4 @@ -
    +
    {{!-- Verdict --}}
    {{#if verdict.success}} @@ -75,6 +75,12 @@ +{{param.handicap}}
    {{/if}} + {{#if verdict.bonusSuccesses}} +
    + {{localize "VERMINE.auto_successes"}} + +{{verdict.bonusSuccesses}} +
    + {{/if}} {{#if param.specialtyName}}
    {{localize "VERMINE.specialty"}} @@ -208,7 +214,7 @@

    {{localize "VERMINE.success_count"}}:

    - {{roll._total}} + {{verdict.total}}

    {{localize "VERMINE.success_required"}}: