feat: fiche PNJ (profil + niveaux) et passage du véhicule en acteur
Release Creation / build (release) Failing after 1m17s
Release Creation / build (release) Failing after 1m17s
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 } }
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
+75
-62
@@ -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é.
|
||||
*/
|
||||
|
||||
+34
-10
@@ -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: "" })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
+11
-4
@@ -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 });
|
||||
|
||||
+12
-10
@@ -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"
|
||||
]);
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user