feat: équipement, échanges de coups et améliorations des fiches

- équipement des armes et protections (champ equipped, liste des équipés, toggle)
- échanges de coups automatisés (attaque/défense/résolution/blessures dans le chat)
- dialogue d'attaque par type (personnage/PNJ/créature), portées et difficultés
- conservation du scroll des fiches lors des modifs (option scrollable + classe active)
- verrouillage des compétences PNJ en mode jeu
- corrections review combat (défenseur, difficulté >10, multi-cibles, permissions)
This commit is contained in:
2026-08-04 14:14:03 +02:00
parent 31f2f4530c
commit f2c8cfe246
45 changed files with 2105 additions and 78 deletions
@@ -30,8 +30,10 @@ export default class VermineBaseActorSheet extends HandlebarsApplicationMixin(fo
toggleSheet: VermineBaseActorSheet.#onToggleSheet,
edit: VermineBaseActorSheet.#onItemEdit,
delete: VermineBaseActorSheet.#onItemDelete,
toggleEquip: VermineBaseActorSheet.#onToggleEquip,
create: VermineBaseActorSheet.#onItemCreate,
roll: VermineBaseActorSheet.#onRollItem,
attack: VermineBaseActorSheet.#onAttack,
clickRadio: VermineBaseActorSheet.#onClickRadioHexa,
effectControl: VermineBaseActorSheet.#onEffectControl,
chooseTotem: VermineBaseActorSheet.#onChooseTotem
@@ -237,7 +239,8 @@ export default class VermineBaseActorSheet extends HandlebarsApplicationMixin(fo
const dialog = await RollDialog.create({
actorId: this.document.id,
rolltype: "skill",
label: item.system.skill
label: item.system.skill,
weapon: item
})
if (dialog) dialog.render(true)
return
@@ -245,6 +248,24 @@ export default class VermineBaseActorSheet extends HandlebarsApplicationMixin(fo
item?.roll()
}
static async #onAttack(event, target) {
const id = target.closest("[data-item-id]")?.dataset?.itemId
if (!id) return
const item = this.document.items.get(id)
if (!item) return
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)
}
static async #onToggleEquip(event, target) {
const id = target.closest("[data-item-id]")?.dataset?.itemId
if (!id) return
const item = this.document.items.get(id)
if (!item) return
await item.update({ "system.equipped": !item.system.equipped })
}
static #onClickRadioHexa(event, target) {
event.preventDefault()
event.stopPropagation()
+9 -19
View File
@@ -13,12 +13,12 @@ export default class VermineCreatureSheetV2 extends VermineBaseActorSheet {
}
static PARTS = {
main: { template: "systems/vermine2047/templates/actor/appv2/creature-main.hbs" },
main: { template: "systems/vermine2047/templates/actor/appv2/creature-main.hbs", scrollable: [""] },
tabs: { template: "templates/generic/tab-navigation.hbs" },
info: { template: "systems/vermine2047/templates/actor/appv2/creature-info.hbs" },
stats: { template: "systems/vermine2047/templates/actor/appv2/creature-stats.hbs" },
combat: { template: "systems/vermine2047/templates/actor/appv2/creature-combat.hbs" },
effects: { template: "systems/vermine2047/templates/actor/appv2/creature-effects.hbs" }
info: { template: "systems/vermine2047/templates/actor/appv2/creature-info.hbs", scrollable: [""] },
stats: { template: "systems/vermine2047/templates/actor/appv2/creature-stats.hbs", scrollable: [""] },
combat: { template: "systems/vermine2047/templates/actor/appv2/creature-combat.hbs", scrollable: [""] },
effects: { template: "systems/vermine2047/templates/actor/appv2/creature-effects.hbs", scrollable: [""] }
}
tabGroups = { sheet: "info" }
@@ -94,24 +94,14 @@ export default class VermineCreatureSheetV2 extends VermineBaseActorSheet {
return context
}
/** @override - Les créatures n'ont pas de caractéristiques/compétences : on lance directement le pool d'attaque. */
/** @override - Les créatures n'ont pas de caractéristiques/compétences : on ouvre le dialogue d'attaque (pool calculé). */
async _onRoll(event) {
event.preventDefault()
const el = event.currentTarget
const type = el.dataset.type
if (type !== "creature-attack") return super._onRoll(event)
const pool = this.document.system.computed?.attack ?? 0
if (!pool) {
ui.notifications.warn(game.i18n.localize("VERMINE.error_select_ability"))
return
}
const difficulty = this.document.system.combatStatus?.difficulty ?? 7
const { VermineUtils } = await import("../../system/roll.mjs")
await VermineUtils.roll({
actor: this.document,
NoD: pool,
difficulty: parseInt(difficulty, 10),
rollLabel: game.i18n.localize("ADVERSITY.attack")
})
const { default: CombatDialog } = await import("../../system/dialogs/combatDialog.mjs")
const dialog = await CombatDialog.create({ actorId: this.document.id })
if (dialog) dialog.render(true)
}
}
+5 -5
View File
@@ -16,12 +16,12 @@ export default class VermineGroupSheetV2 extends VermineBaseActorSheet {
}
static PARTS = {
main: { template: "systems/vermine2047/templates/actor/appv2/group-main.hbs" },
main: { template: "systems/vermine2047/templates/actor/appv2/group-main.hbs", scrollable: [""] },
tabs: { template: "templates/generic/tab-navigation.hbs" },
info: { template: "systems/vermine2047/templates/actor/appv2/group-info.hbs" },
gear: { template: "systems/vermine2047/templates/actor/appv2/group-gear.hbs" },
road: { template: "systems/vermine2047/templates/actor/appv2/group-road.hbs" },
reserve: { template: "systems/vermine2047/templates/actor/appv2/group-reserve.hbs" }
info: { template: "systems/vermine2047/templates/actor/appv2/group-info.hbs", scrollable: [""] },
gear: { template: "systems/vermine2047/templates/actor/appv2/group-gear.hbs", scrollable: [""] },
road: { template: "systems/vermine2047/templates/actor/appv2/group-road.hbs", scrollable: [""] },
reserve: { template: "systems/vermine2047/templates/actor/appv2/group-reserve.hbs", scrollable: [""] }
}
tabGroups = { sheet: "info" }
+12 -12
View File
@@ -3,71 +3,71 @@ import { VermineBaseItemSheet } from "./base-item-sheet.mjs"
// ── Item générique ────────────────────────────────────────────────────
export class VermineItemSheetV2 extends VermineBaseItemSheet {
static DEFAULT_OPTIONS = { classes: ["item-gear"], position: { width: 520 } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-item-sheet.hbs" } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-item-sheet.hbs", scrollable: [""] } }
}
// ── Arme ──────────────────────────────────────────────────────────────
export class VermineWeaponSheetV2 extends VermineBaseItemSheet {
static DEFAULT_OPTIONS = { classes: ["weapon"], position: { width: 520 } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-weapon-sheet.hbs" } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-weapon-sheet.hbs", scrollable: [""] } }
}
// ── Défense ───────────────────────────────────────────────────────────
export class VermineDefenseSheetV2 extends VermineBaseItemSheet {
static DEFAULT_OPTIONS = { classes: ["defense"], position: { width: 520 } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-defense-sheet.hbs" } }
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" } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-vehicle-sheet.hbs", scrollable: [""] } }
}
// ── Capacité ──────────────────────────────────────────────────────────
export class VermineAbilitySheetV2 extends VermineBaseItemSheet {
static DEFAULT_OPTIONS = { classes: ["ability"], position: { width: 560 } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-ability-sheet.hbs" } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-ability-sheet.hbs", scrollable: [""] } }
}
// ── Spécialité ────────────────────────────────────────────────────────
export class VermineSpecialtySheetV2 extends VermineBaseItemSheet {
static DEFAULT_OPTIONS = { classes: ["specialty"], position: { width: 400 } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-specialty-sheet.hbs" } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-specialty-sheet.hbs", scrollable: [""] } }
}
// ── Historique ────────────────────────────────────────────────────────
export class VermineBackgroundSheetV2 extends VermineBaseItemSheet {
static DEFAULT_OPTIONS = { classes: ["background"], position: { width: 520 } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-background-sheet.hbs" } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-background-sheet.hbs", scrollable: [""] } }
}
// ── Traumatisme ───────────────────────────────────────────────────────
export class VermineTraumaSheetV2 extends VermineBaseItemSheet {
static DEFAULT_OPTIONS = { classes: ["trauma"], position: { width: 520 } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-trauma-sheet.hbs" } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-trauma-sheet.hbs", scrollable: [""] } }
}
// ── Évolution ─────────────────────────────────────────────────────────
export class VermineEvolutionSheetV2 extends VermineBaseItemSheet {
static DEFAULT_OPTIONS = { classes: ["evolution"], position: { width: 520 } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-evolution-sheet.hbs" } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-evolution-sheet.hbs", scrollable: [""] } }
}
// ── Rumeur ────────────────────────────────────────────────────────────
export class VermineRumorSheetV2 extends VermineBaseItemSheet {
static DEFAULT_OPTIONS = { classes: ["rumor"], position: { width: 520 } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-rumor-sheet.hbs" } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-rumor-sheet.hbs", scrollable: [""] } }
}
// ── Cible ─────────────────────────────────────────────────────────────
export class VermineTargetSheetV2 extends VermineBaseItemSheet {
static DEFAULT_OPTIONS = { classes: ["target"], position: { width: 520 } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-target-sheet.hbs" } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-target-sheet.hbs", scrollable: [""] } }
}
// ── Rite ──────────────────────────────────────────────────────────────
export class VermineRiteSheetV2 extends VermineBaseItemSheet {
static DEFAULT_OPTIONS = { classes: ["rite"], position: { width: 520 } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-rite-sheet.hbs" } }
static PARTS = { main: { template: "systems/vermine2047/templates/item/item-rite-sheet.hbs", scrollable: [""] } }
}
+15 -6
View File
@@ -13,13 +13,14 @@ export default class VermineNpcSheetV2 extends VermineBaseActorSheet {
}
static PARTS = {
main: { template: "systems/vermine2047/templates/actor/appv2/npc-main.hbs" },
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" },
skills: { template: "systems/vermine2047/templates/actor/appv2/npc-skills.hbs" },
threat: { template: "systems/vermine2047/templates/actor/appv2/npc-threat.hbs" },
combat: { template: "systems/vermine2047/templates/actor/appv2/npc-combat.hbs" },
notes: { template: "systems/vermine2047/templates/actor/appv2/npc-notes.hbs" }
characteristics: { template: "systems/vermine2047/templates/actor/appv2/npc-characteristics.hbs", scrollable: [""] },
skills: { template: "systems/vermine2047/templates/actor/appv2/npc-skills.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" }
@@ -28,6 +29,7 @@ export default class VermineNpcSheetV2 extends VermineBaseActorSheet {
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" },
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" }
@@ -61,11 +63,18 @@ export default class VermineNpcSheetV2 extends VermineBaseActorSheet {
case "skills":
context.tab = context.tabs.skills
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)
context.equippedDefenses = doc.itemTypes.defense.filter(i => i.system.equipped)
const { prepareActiveEffectCategories } = await import("../../system/effects.mjs")
context.effects = prepareActiveEffectCategories(doc.effects)
break