DAtaModels + Appv2 migration : OK

This commit is contained in:
2026-04-02 21:33:56 +02:00
parent 4def580296
commit a37ad2cc82
779 changed files with 391512 additions and 305 deletions

View File

@@ -0,0 +1,84 @@
import { MournbladeCYD2Utility } from "../mournblade-cyd2-utility.js";
/**
* Dialogue de jet de dé pour MournbladeCYD2 - Version DialogV2
*/
export class MournbladeCYD2RollDialog {
/**
* Create and display the roll dialog
* @param {MournbladeCYD2Actor} actor
* @param {Object} rollData
*/
static async create(actor, rollData) {
const context = {
...rollData,
difficulte: String(rollData.difficulte || 0),
img: actor.img,
name: actor.name,
config: game.system.mournbladecyd2.config
};
if (rollData.attrKey === "tochoose") {
context.selectableAttributes = actor.system.attributs;
}
const content = await foundry.applications.handlebars.renderTemplate(
"systems/fvtt-mournblade-cyd2/templates/roll-dialog-generic.hbs",
context
);
return foundry.applications.api.DialogV2.wait({
window: { title: "Test de Capacité", icon: "fa-solid fa-dice-d20" },
classes: ["mournblade-cyd2-roll-dialog"],
position: { width: 360 },
modal: false,
content,
buttons: [
{
action: "rolld10",
label: "Lancer 1d10",
icon: "fa-solid fa-dice-d10",
default: true,
callback: (event, button, dialog) => {
MournbladeCYD2RollDialog._updateRollDataFromForm(rollData, button.form.elements, actor);
rollData.mainDice = "1d10";
MournbladeCYD2Utility.rollMournbladeCYD2(rollData);
}
},
{
action: "rolld20",
label: "Lancer 1d20",
icon: "fa-solid fa-dice-d20",
callback: (event, button, dialog) => {
MournbladeCYD2RollDialog._updateRollDataFromForm(rollData, button.form.elements, actor);
rollData.mainDice = "1d20";
MournbladeCYD2Utility.rollMournbladeCYD2(rollData);
}
},
{
action: "cancel",
label: "Annuler",
icon: "fa-solid fa-times"
}
]
});
}
/* -------------------------------------------- */
static _updateRollDataFromForm(rollData, elements, actor) {
if (elements.modificateur) rollData.modificateur = Number(elements.modificateur.value);
if (elements.difficulte) rollData.difficulte = Number(elements.difficulte.value);
if (elements.attrKey) rollData.attrKey = String(elements.attrKey.value);
if (elements.attrKey2) rollData.attrKey2 = String(elements.attrKey2.value);
if (elements["select-maitrise"]) rollData.maitriseId = String(elements["select-maitrise"].value);
if (elements["competence-talents"]) {
const sel = elements["competence-talents"];
rollData.selectedTalents = Array.from(sel.selectedOptions).map(o => o.value);
}
if (elements["taille-cible"]) rollData.tailleCible = String(elements["taille-cible"].value);
if (elements["tireur-deplacement"]) rollData.tireurDeplacement = String(elements["tireur-deplacement"].value);
if (elements["cible-couvert"]) rollData.cibleCouvert = String(elements["cible-couvert"].value);
if (elements["distance-tir"]) rollData.distanceTir = String(elements["distance-tir"].value);
}
}

View File

@@ -0,0 +1,25 @@
/**
* Index des applications AppV2 pour Mournblade CYD 2.0
*/
// Fiches d'acteurs
export { default as MournbladeCYD2PersonnageSheet } from './mournblade-cyd2-personnage-sheet.mjs';
export { default as MournbladeCYD2CreatureSheet } from './mournblade-cyd2-creature-sheet.mjs';
// Fiches d'items
export { default as MournbladeCYD2ArmeSheet } from './mournblade-cyd2-arme-sheet.mjs';
export { default as MournbladeCYD2CompetenceSheet } from './mournblade-cyd2-competence-sheet.mjs';
export { default as MournbladeCYD2DonSheet } from './mournblade-cyd2-don-sheet.mjs';
export { default as MournbladeCYD2EquipementSheet } from './mournblade-cyd2-equipement-sheet.mjs';
export { default as MournbladeCYD2HistoriqueSheet } from './mournblade-cyd2-historique-sheet.mjs';
export { default as MournbladeCYD2MonnaieSheet } from './mournblade-cyd2-monnaie-sheet.mjs';
export { default as MournbladeCYD2PacteSheet } from './mournblade-cyd2-pacte-sheet.mjs';
export { default as MournbladeCYD2ProfilSheet } from './mournblade-cyd2-profil-sheet.mjs';
export { default as MournbladeCYD2ProtectionSheet } from './mournblade-cyd2-protection-sheet.mjs';
export { default as MournbladeCYD2RessourceSheet } from './mournblade-cyd2-ressource-sheet.mjs';
export { default as MournbladeCYD2RuneSheet } from './mournblade-cyd2-rune-sheet.mjs';
export { default as MournbladeCYD2RuneEffectSheet } from './mournblade-cyd2-runeeffect-sheet.mjs';
export { default as MournbladeCYD2TalentSheet } from './mournblade-cyd2-talent-sheet.mjs';
export { default as MournbladeCYD2TendanceSheet } from './mournblade-cyd2-tendance-sheet.mjs';
export { default as MournbladeCYD2TraitChaotiqueSheet } from './mournblade-cyd2-traitchaotique-sheet.mjs';
export { default as MournbladeCYD2TraitEspeceSheet } from './mournblade-cyd2-traitespece-sheet.mjs';

View File

@@ -0,0 +1,279 @@
const { HandlebarsApplicationMixin } = foundry.applications.api;
import { MournbladeCYD2Utility } from "../../mournblade-cyd2-utility.js";
export default class MournbladeCYD2ActorSheetV2 extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
static SHEET_MODES = { EDIT: 0, PLAY: 1 };
constructor(options = {}) {
super(options);
this.#dragDrop = this.#createDragDropHandlers();
this._sheetMode = this.constructor.SHEET_MODES.PLAY;
}
#dragDrop;
/** @override */
static DEFAULT_OPTIONS = {
classes: ["fvtt-mournblade-cyd2", "sheet", "actor"],
position: {
width: 640,
height: 720,
},
form: {
submitOnChange: true,
closeOnSubmit: false,
},
window: {
resizable: true,
},
tabs: [
{
navSelector: 'nav[data-group="primary"]',
contentSelector: "section.sheet-body",
initial: "stats",
},
],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
actions: {
editImage: MournbladeCYD2ActorSheetV2.#onEditImage,
toggleSheet: MournbladeCYD2ActorSheetV2.#onToggleSheet,
editItem: MournbladeCYD2ActorSheetV2.#onEditItem,
deleteItem: MournbladeCYD2ActorSheetV2.#onDeleteItem,
createItem: MournbladeCYD2ActorSheetV2.#onCreateItem,
equipItem: MournbladeCYD2ActorSheetV2.#onEquipItem,
modifyQuantity: MournbladeCYD2ActorSheetV2.#onModifyQuantity,
modifySante: MournbladeCYD2ActorSheetV2.#onModifySante,
modifyAme: MournbladeCYD2ActorSheetV2.#onModifyAme,
rollAttribut: MournbladeCYD2ActorSheetV2.#onRollAttribut,
rollCompetence: MournbladeCYD2ActorSheetV2.#onRollCompetence,
rollRune: MournbladeCYD2ActorSheetV2.#onRollRune,
rollArmeOffensif: MournbladeCYD2ActorSheetV2.#onRollArmeOffensif,
rollArmeSpecial: MournbladeCYD2ActorSheetV2.#onRollArmeSpecial,
rollArmeDegats: MournbladeCYD2ActorSheetV2.#onRollArmeDegats,
rollAssommer: MournbladeCYD2ActorSheetV2.#onRollAssommer,
rollImmobiliser: MournbladeCYD2ActorSheetV2.#onRollImmobiliser,
rollFuir: MournbladeCYD2ActorSheetV2.#onRollFuir,
},
};
get isPlayMode() {
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY;
return this._sheetMode === this.constructor.SHEET_MODES.PLAY;
}
get isEditMode() {
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY;
return this._sheetMode === this.constructor.SHEET_MODES.EDIT;
}
tabGroups = { primary: "stats" };
/** @override */
async _prepareContext() {
const actor = this.document;
return {
actor,
system: actor.system,
source: actor.toObject(),
fields: actor.schema.fields,
systemFields: actor.system.schema.fields,
isEditable: this.isEditable,
isEditMode: this.isEditMode,
isPlayMode: this.isPlayMode,
isGM: game.user.isGM,
config: game.system.mournbladecyd2.config,
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
actor.system.biodata?.description || "", { async: true }
),
enrichedHabitat: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
actor.system.biodata?.habitat || "", { async: true }
),
};
}
/** @override */
_onRender(context, options) {
super._onRender(context, options);
this.#dragDrop.forEach((d) => d.bind(this.element));
this.element.querySelectorAll('.edit-item-data').forEach(element => {
element.addEventListener('change', async (event) => {
const target = event.currentTarget;
const itemElement = target.closest('[data-item-id]');
if (!itemElement) return;
const itemId = itemElement.dataset.itemId;
const itemField = target.dataset.itemField;
const dataType = target.dataset.dtype;
const value = dataType === "Number" ? Number(target.value) : target.value;
const item = this.document.items.get(itemId);
if (item) await item.update({ [itemField]: value });
});
});
// Tab navigation
const nav = this.element.querySelector('nav.tabs[data-group]');
if (nav) {
const group = nav.dataset.group;
const activeTab = this.tabGroups[group] || "stats";
nav.querySelectorAll('[data-tab]').forEach(link => {
const tab = link.dataset.tab;
link.classList.toggle('active', tab === activeTab);
link.addEventListener('click', (event) => {
event.preventDefault();
this.tabGroups[group] = tab;
this.render();
});
});
this.element.querySelectorAll(`[data-group="${group}"][data-tab]`).forEach(content => {
content.classList.toggle('active', content.dataset.tab === activeTab);
});
}
}
#createDragDropHandlers() {
return this.options.dragDrop.map(d => {
d.permissions = {
dragstart: this._canDragStart.bind(this),
drop: this._canDragDrop.bind(this)
};
d.callbacks = {
dragstart: this._onDragStart.bind(this),
dragover: this._onDragOver.bind(this),
drop: this._onDrop.bind(this)
};
return new foundry.applications.ux.DragDrop.implementation(d);
});
}
_canDragStart(selector) { return this.isEditable; }
_canDragDrop(selector) { return this.isEditable; }
_onDragStart(event) {
const li = event.currentTarget.closest("[data-item-id]");
if (!li) return;
const item = this.document.items.get(li.dataset.itemId);
if (!item) return;
event.dataTransfer.setData("text/plain", JSON.stringify(item.toDragData()));
}
_onDragOver(event) { event.preventDefault(); }
async _onDrop(event) {
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
if (data?.type === "Item") return this._onDropItem(event, data);
if (data?.type === "Actor") return this._onDropActor(event, data);
}
async _onDropItem(event, data) {
if (!this.document.isOwner) return;
const item = await Item.fromDropData(data);
if (!item) return;
if (this.document.uuid === item.parent?.uuid) return;
return this.document.createEmbeddedDocuments("Item", [item.toObject()]);
}
async _onDropActor(event, data) {}
// #region Actions
static async #onEditImage(event) {
const fp = new FilePicker({
type: "image",
current: this.document.img,
callback: (path) => this.document.update({ img: path })
});
fp.browse();
}
static #onToggleSheet(event) {
this._sheetMode = this.isEditMode
? this.constructor.SHEET_MODES.PLAY
: this.constructor.SHEET_MODES.EDIT;
this.render();
}
static async #onEditItem(event, target) {
const li = target.closest(".item");
const item = this.document.items.get(li?.dataset.itemId);
item?.sheet.render(true);
}
static async #onDeleteItem(event, target) {
const li = target.closest(".item");
await MournbladeCYD2Utility.confirmDelete(this, li);
}
static async #onCreateItem(event, target) {
const itemType = target.dataset.type;
await this.document.createEmbeddedDocuments("Item", [{ name: `Nouveau ${itemType}`, type: itemType }], { renderSheet: true });
}
static async #onEquipItem(event, target) {
const li = target.closest(".item");
const item = this.document.items.get(li?.dataset.itemId);
if (item) await item.update({ "system.equipped": !item.system.equipped });
}
static async #onModifyQuantity(event, target) {
const li = target.closest('[data-item-id]');
const item = this.document.items.get(li?.dataset.itemId);
const value = Number.parseInt(target.dataset.quantiteValue);
if (item) {
const newQty = Math.max(0, (item.system.quantite || 0) + value);
await item.update({ "system.quantite": newQty });
}
}
static async #onModifySante(event, target) {
const type = target.dataset.type;
const value = Number.parseInt(target.dataset.value);
const current = this.document.system.sante[type] || 0;
await this.document.update({ [`system.sante.${type}`]: Math.max(0, current + value) });
}
static async #onModifyAme(event, target) {
const value = Number.parseInt(target.dataset.value);
const current = this.document.system.ame.nbame || 0;
await this.document.update({ "system.ame.nbame": Math.max(0, current + value) });
}
static async #onRollAttribut(event, target) {
await this.document.rollAttribut(target.dataset.attrKey);
}
static async #onRollCompetence(event, target) {
const li = target.closest('[data-item-id]');
await this.document.rollCompetence(target.dataset.attrKey, li?.dataset.itemId);
}
static async #onRollRune(event, target) {
const li = target.closest('[data-item-id]');
await this.document.rollRune(li?.dataset.itemId);
}
static async #onRollArmeOffensif(event, target) {
await this.document.rollArmeOffensif(target.dataset.armeId);
}
static async #onRollArmeSpecial(event, target) {
await this.document.rollArmeSpecial(target.dataset.armeId);
}
static async #onRollArmeDegats(event, target) {
await this.document.rollArmeDegats(target.dataset.armeId);
}
static async #onRollAssommer(event, target) {
await this.document.rollAssomer();
}
static async #onRollImmobiliser(event, target) {
await this.document.rollImmobiliser();
}
static async #onRollFuir(event, target) {
await this.document.rollFuir();
}
}

View File

@@ -0,0 +1,125 @@
const { HandlebarsApplicationMixin } = foundry.applications.api;
import { MournbladeCYD2Utility } from "../../mournblade-cyd2-utility.js";
export default class MournbladeCYD2ItemSheetV2 extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
constructor(options = {}) {
super(options);
this.#dragDrop = this.#createDragDropHandlers();
}
#dragDrop;
/** @override */
static DEFAULT_OPTIONS = {
classes: ["fvtt-mournblade-cyd2", "item"],
position: {
width: 620,
height: 600,
},
form: {
submitOnChange: true,
},
window: {
resizable: true,
},
tabs: [
{
navSelector: 'nav[data-group="primary"]',
contentSelector: "section.sheet-body",
initial: "description",
},
],
dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }],
actions: {
editImage: MournbladeCYD2ItemSheetV2.#onEditImage,
postItem: MournbladeCYD2ItemSheetV2.#onPostItem,
addPredilection: MournbladeCYD2ItemSheetV2.#onAddPredilection,
deletePredilection: MournbladeCYD2ItemSheetV2.#onDeletePredilection,
},
};
tabGroups = { primary: "description" };
/** @override */
async _prepareContext() {
return {
fields: this.document.schema.fields,
systemFields: this.document.system.schema.fields,
item: this.document,
system: this.document.system,
source: this.document.toObject(),
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
this.document.system.description || "", { async: true }
),
isEditMode: true,
isEditable: this.isEditable,
isGM: game.user.isGM,
config: game.system.mournbladecyd2.config,
};
}
/** @override */
_onRender(context, options) {
super._onRender(context, options);
this.#dragDrop.forEach((d) => d.bind(this.element));
// Tab navigation
const nav = this.element.querySelector('nav.tabs[data-group]');
if (nav) {
const group = nav.dataset.group;
const activeTab = this.tabGroups[group] || "description";
nav.querySelectorAll('[data-tab]').forEach(link => {
const tab = link.dataset.tab;
link.classList.toggle('active', tab === activeTab);
link.addEventListener('click', (event) => {
event.preventDefault();
this.tabGroups[group] = tab;
this.render();
});
});
this.element.querySelectorAll(`[data-group="${group}"][data-tab]`).forEach(content => {
content.classList.toggle('active', content.dataset.tab === activeTab);
});
}
}
#createDragDropHandlers() {
return this.options.dragDrop.map(d => {
d.permissions = { dragstart: () => this.isEditable };
d.callbacks = { dragstart: this._onDragStart.bind(this) };
return new foundry.applications.ux.DragDrop.implementation(d);
});
}
_onDragStart(event) {}
// #region Actions
static async #onEditImage(event) {
const fp = new FilePicker({
type: "image",
current: this.document.img,
callback: (path) => this.document.update({ img: path })
});
fp.browse();
}
static async #onPostItem(event) {
await this.document.toChat?.();
}
static async #onAddPredilection(event) {
const preds = foundry.utils.duplicate(this.document.system.predilections || []);
preds.push({ id: foundry.utils.randomID(), name: "Nouvelle prédilection", description: "", acquise: false, maitrise: false, used: false });
await this.document.update({ "system.predilections": preds });
}
static async #onDeletePredilection(event, target) {
const idx = Number(target.dataset.predilectionIndex);
const preds = foundry.utils.duplicate(this.document.system.predilections || []);
preds.splice(idx, 1);
await this.document.update({ "system.predilections": preds });
}
}

View File

@@ -0,0 +1,39 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2ArmeSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "arme"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.arme",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-arme-sheet.hbs",
},
};
#getTabs() {
const tabs = {
details: { id: "details", group: "primary", label: "Détails" },
description: { id: "description", group: "primary", label: "Description" }
};
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] === v.id;
v.cssClass = v.active ? "active" : "";
}
return tabs;
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
context.tabs = this.#getTabs();
return context;
}
}

View File

@@ -0,0 +1,39 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2CompetenceSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "competence"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.competence",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-competence-sheet.hbs",
},
};
#getTabs() {
const tabs = {
details: { id: "details", group: "primary", label: "Détails" },
description: { id: "description", group: "primary", label: "Description" }
};
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] === v.id;
v.cssClass = v.active ? "active" : "";
}
return tabs;
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
context.tabs = this.#getTabs();
return context;
}
}

View File

@@ -0,0 +1,42 @@
import MournbladeCYD2ActorSheetV2 from "./base-actor-sheet.mjs";
export default class MournbladeCYD2CreatureSheet extends MournbladeCYD2ActorSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Actor.creature",
},
};
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-mournblade-cyd2/templates/creature-sheet.hbs",
},
};
/** @override */
tabGroups = { primary: "stats" };
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
const actor = this.document;
context.skills = actor.getSkills?.() ?? [];
context.armes = foundry.utils.duplicate(actor.getWeapons?.() ?? []);
context.protections = foundry.utils.duplicate(actor.getArmors?.() ?? []);
context.runes = foundry.utils.duplicate(actor.getRunes?.() ?? []);
context.combat = actor.getCombatValues?.() ?? {};
context.equipements = foundry.utils.duplicate(actor.getEquipments?.() ?? []);
context.monnaies = foundry.utils.duplicate(actor.getMonnaies?.() ?? []);
context.talents = foundry.utils.duplicate(actor.getTalents?.() ?? []);
context.protectionTotal = actor.getProtectionTotal?.() ?? 0;
context.adversiteTotal = (actor.system.adversite?.bleue || 0) + (actor.system.adversite?.rouge || 0) + (actor.system.adversite?.noire || 0);
return context;
}
}

View File

@@ -0,0 +1,27 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2DonSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "don"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.don",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-don-sheet.hbs",
},
};
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
return context;
}
}

View File

@@ -0,0 +1,27 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2EquipementSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "equipement"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.equipement",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-equipement-sheet.hbs",
},
};
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
return context;
}
}

View File

@@ -0,0 +1,27 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2HistoriqueSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "historique"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.historique",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-historique-sheet.hbs",
},
};
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
return context;
}
}

View File

@@ -0,0 +1,27 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2MonnaieSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "monnaie"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.monnaie",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-monnaie-sheet.hbs",
},
};
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
return context;
}
}

View File

@@ -0,0 +1,27 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2PacteSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "pacte"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.pacte",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-pacte-sheet.hbs",
},
};
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
return context;
}
}

View File

@@ -0,0 +1,51 @@
import MournbladeCYD2ActorSheetV2 from "./base-actor-sheet.mjs";
export default class MournbladeCYD2PersonnageSheet extends MournbladeCYD2ActorSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Actor.personnage",
},
};
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-mournblade-cyd2/templates/actor-sheet.hbs",
},
};
/** @override */
tabGroups = { primary: "principal" };
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
const actor = this.document;
context.skills = actor.getSkills?.() ?? [];
context.armes = foundry.utils.duplicate(actor.getWeapons?.() ?? []);
context.protections = foundry.utils.duplicate(actor.getArmors?.() ?? []);
context.dons = foundry.utils.duplicate(actor.getDons?.() ?? []);
context.pactes = foundry.utils.duplicate(actor.getPactes?.() ?? []);
context.tendances = foundry.utils.duplicate(actor.getTendances?.() ?? []);
context.runes = foundry.utils.duplicate(actor.getRunes?.() ?? []);
context.traitsChaotiques = foundry.utils.duplicate(actor.getTraitsChaotiques?.() ?? []);
context.traitsEspeces = foundry.utils.duplicate(actor.getTraitsEspeces?.() ?? []);
context.profil = actor.getProfil?.() ?? null;
context.historiques = foundry.utils.duplicate(actor.getHistoriques?.() ?? []);
context.combat = actor.getCombatValues?.() ?? {};
context.equipements = foundry.utils.duplicate(actor.getEquipments?.() ?? []);
context.monnaies = foundry.utils.duplicate(actor.getMonnaies?.() ?? []);
context.runeEffects = foundry.utils.duplicate(actor.getRuneEffects?.() ?? []);
context.ressources = foundry.utils.duplicate(actor.getRessources?.() ?? []);
context.talents = foundry.utils.duplicate(actor.getTalents?.() ?? []);
context.protectionTotal = actor.getProtectionTotal?.() ?? 0;
context.adversiteTotal = (actor.system.adversite?.bleue || 0) + (actor.system.adversite?.rouge || 0) + (actor.system.adversite?.noire || 0);
return context;
}
}

View File

@@ -0,0 +1,27 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2ProfilSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "profil"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.profil",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-profil-sheet.hbs",
},
};
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
return context;
}
}

View File

@@ -0,0 +1,27 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2ProtectionSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "protection"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.protection",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-protection-sheet.hbs",
},
};
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
return context;
}
}

View File

@@ -0,0 +1,27 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2RessourceSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "ressource"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.ressource",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-ressource-sheet.hbs",
},
};
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
return context;
}
}

View File

@@ -0,0 +1,39 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2RuneSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "rune"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.rune",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-rune-sheet.hbs",
},
};
#getTabs() {
const tabs = {
details: { id: "details", group: "primary", label: "Détails" },
description: { id: "description", group: "primary", label: "Description" }
};
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] === v.id;
v.cssClass = v.active ? "active" : "";
}
return tabs;
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
context.tabs = this.#getTabs();
return context;
}
}

View File

@@ -0,0 +1,27 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2RuneEffectSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "runeeffect"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.runeeffect",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-runeeffect-sheet.hbs",
},
};
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
return context;
}
}

View File

@@ -0,0 +1,39 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2TalentSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "talent"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.talent",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-talent-sheet.hbs",
},
};
#getTabs() {
const tabs = {
details: { id: "details", group: "primary", label: "Détails" },
description: { id: "description", group: "primary", label: "Description" }
};
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] === v.id;
v.cssClass = v.active ? "active" : "";
}
return tabs;
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
context.tabs = this.#getTabs();
return context;
}
}

View File

@@ -0,0 +1,27 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2TendanceSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "tendance"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.tendance",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-tendance-sheet.hbs",
},
};
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
return context;
}
}

View File

@@ -0,0 +1,27 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2TraitChaotiqueSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "traitchaotique"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.traitchaotique",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-traitchaotique-sheet.hbs",
},
};
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
return context;
}
}

View File

@@ -0,0 +1,27 @@
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
export default class MournbladeCYD2TraitEspeceSheet extends MournbladeCYD2ItemSheetV2 {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes, "traitespece"],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.traitespece",
},
};
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade-cyd2/templates/item-traitespece-sheet.hbs",
},
};
/** @override */
async _prepareContext() {
const context = await super._prepareContext();
return context;
}
}

31
modules/models/arme.mjs Normal file
View File

@@ -0,0 +1,31 @@
/**
* Data model pour les armes MournbladeCYD2
*/
export default class ArmeDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
prixpo: new fields.NumberField({ initial: 0, integer: true }),
prixca: new fields.NumberField({ initial: 0, integer: true }),
prixsc: new fields.NumberField({ initial: 0, integer: true }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
quantite: new fields.NumberField({ initial: 1, integer: true }),
equipped: new fields.BooleanField({ initial: false }),
typearme: new fields.StringField({ initial: "" }),
armenaturelle: new fields.BooleanField({ initial: false }),
armefortune: new fields.BooleanField({ initial: false }),
bonusmaniementoff: new fields.NumberField({ initial: 0, integer: true }),
seuildefense: new fields.NumberField({ initial: 0, integer: true }),
onlevelonly: new fields.BooleanField({ initial: false }),
degats: new fields.StringField({ initial: "" }),
deuxmains: new fields.BooleanField({ initial: false }),
percearmure: new fields.BooleanField({ initial: false }),
percearmurevalue: new fields.NumberField({ initial: 0, integer: true }),
courte: new fields.NumberField({ initial: 0, integer: true }),
moyenne: new fields.NumberField({ initial: 0, integer: true }),
longue: new fields.NumberField({ initial: 0, integer: true }),
tr: new fields.NumberField({ initial: 0, integer: true })
};
}
}

View File

@@ -0,0 +1,11 @@
/**
* Data model de base pour les items MournbladeCYD2
*/
export default class BaseItemDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,42 @@
/**
* Data model pour les compétences MournbladeCYD2
* Prédilections enrichies (schema Hawkmoon CYD2)
*/
export default class CompetenceDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
niveau: new fields.NumberField({ initial: 0, integer: true }),
attribut1: new fields.StringField({ initial: "" }),
attribut2: new fields.StringField({ initial: "" }),
attribut3: new fields.StringField({ initial: "" }),
doublebonus: new fields.BooleanField({ initial: false }),
predilections: new fields.ArrayField(
new fields.SchemaField({
id: new fields.StringField({ initial: "" }),
name: new fields.StringField({ initial: "" }),
description: new fields.StringField({ initial: "" }),
acquise: new fields.BooleanField({ initial: false }),
maitrise: new fields.BooleanField({ initial: false }),
used: new fields.BooleanField({ initial: false })
}),
{ initial: [] }
)
};
}
static migrateData(source) {
if (Array.isArray(source.predilections)) {
source.predilections = source.predilections.map(pred => {
if (typeof pred === "string") return { id: "", name: pred, description: "", acquise: false, maitrise: false, used: false };
if (!("acquise" in pred)) pred.acquise = false;
if (!("maitrise" in pred)) pred.maitrise = false;
if (!("id" in pred)) pred.id = "";
if (!("description" in pred)) pred.description = "";
return pred;
});
}
return super.migrateData(source);
}
}

112
modules/models/creature.mjs Normal file
View File

@@ -0,0 +1,112 @@
/**
* Data model pour les créatures MournbladeCYD2
*/
export default class CreatureDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
// Template biodata
biodata: new fields.SchemaField({
name: new fields.StringField({ initial: "" }),
age: new fields.NumberField({ initial: 0, integer: true }),
poids: new fields.StringField({ initial: "" }),
taille: new fields.StringField({ initial: "" }),
cheveux: new fields.StringField({ initial: "" }),
sexe: new fields.StringField({ initial: "" }),
yeux: new fields.StringField({ initial: "" }),
description: new fields.HTMLField({ initial: "" }),
habitat: new fields.HTMLField({ initial: "" }),
notes: new fields.HTMLField({ initial: "" }),
statut: new fields.StringField({ initial: "" }),
gmnotes: new fields.HTMLField({ initial: "" }),
statutresistant: new fields.StringField({ initial: "commun" })
}),
// Template core
subactors: new fields.ArrayField(new fields.StringField(), { initial: [] }),
attributs: new fields.SchemaField({
adr: new fields.SchemaField({
label: new fields.StringField({ initial: "Adresse" }),
labelnorm: new fields.StringField({ initial: "adresse" }),
abbrev: new fields.StringField({ initial: "adr" }),
value: new fields.NumberField({ initial: 1, integer: true })
}),
pui: new fields.SchemaField({
label: new fields.StringField({ initial: "Puissance" }),
labelnorm: new fields.StringField({ initial: "puissance" }),
abbrev: new fields.StringField({ initial: "pui" }),
value: new fields.NumberField({ initial: 1, integer: true })
}),
cla: new fields.SchemaField({
label: new fields.StringField({ initial: "Clairvoyance" }),
labelnorm: new fields.StringField({ initial: "clairvoyance" }),
abbrev: new fields.StringField({ initial: "cla" }),
value: new fields.NumberField({ initial: 1, integer: true })
}),
pre: new fields.SchemaField({
label: new fields.StringField({ initial: "Présence" }),
labelnorm: new fields.StringField({ initial: "presence" }),
abbrev: new fields.StringField({ initial: "pre" }),
value: new fields.NumberField({ initial: 1, integer: true })
}),
tre: new fields.SchemaField({
label: new fields.StringField({ initial: "Trempe" }),
labelnorm: new fields.StringField({ initial: "trempe" }),
abbrev: new fields.StringField({ initial: "tre" }),
value: new fields.NumberField({ initial: 1, integer: true })
})
}),
bonneaventure: new fields.SchemaField({
base: new fields.NumberField({ initial: 0, integer: true }),
actuelle: new fields.NumberField({ initial: 0, integer: true })
}),
experience: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
eclat: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
sante: new fields.SchemaField({
vigueur: new fields.NumberField({ initial: 0, integer: true }),
etat: new fields.NumberField({ initial: 0, integer: true }),
vigueurmodifier: new fields.NumberField({ initial: 0, integer: true }),
nbcombativite: new fields.NumberField({ initial: 5, integer: true })
}),
ame: new fields.SchemaField({
seuilpouvoir: new fields.NumberField({ initial: 0, integer: true }),
etat: new fields.NumberField({ initial: 0, integer: true }),
seuilpouvoirmodifier: new fields.NumberField({ initial: 0, integer: true }),
nbame: new fields.NumberField({ initial: 7, integer: true }),
max: new fields.NumberField({ initial: 0, integer: true })
}),
adversite: new fields.SchemaField({
bleue: new fields.NumberField({ initial: 0, integer: true }),
rouge: new fields.NumberField({ initial: 0, integer: true }),
noire: new fields.NumberField({ initial: 0, integer: true })
}),
vitesse: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
combat: new fields.SchemaField({
initbonus: new fields.NumberField({ initial: 0, integer: true }),
vitessebonus: new fields.NumberField({ initial: 0, integer: true }),
bonusdegats: new fields.NumberField({ initial: 0, integer: true }),
attaquebonus: new fields.NumberField({ initial: 0, integer: true }),
defensebonus: new fields.NumberField({ initial: 0, integer: true }),
defensetotale: new fields.BooleanField({ initial: false }),
monte: new fields.BooleanField({ initial: false })
}),
balance: new fields.SchemaField({
loi: new fields.NumberField({ initial: 0, integer: true }),
chaos: new fields.NumberField({ initial: 0, integer: true }),
aspect: new fields.NumberField({ initial: 0, integer: true }),
marge: new fields.NumberField({ initial: 0, integer: true }),
pointschaos: new fields.NumberField({ initial: 0, integer: true }),
pointsloi: new fields.NumberField({ initial: 0, integer: true })
}),
// Spécifique aux créatures
ressources: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
})
};
}
}

14
modules/models/don.mjs Normal file
View File

@@ -0,0 +1,14 @@
/**
* Data model pour les dons MournbladeCYD2
*/
export default class DonDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
allegeance: new fields.StringField({ initial: "" }),
prerequis: new fields.StringField({ initial: "" }),
sacrifice: new fields.StringField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,17 @@
/**
* Data model pour les équipements MournbladeCYD2
*/
export default class EquipementDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
prixpo: new fields.NumberField({ initial: 0, integer: true }),
prixca: new fields.NumberField({ initial: 0, integer: true }),
prixsc: new fields.NumberField({ initial: 0, integer: true }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
quantite: new fields.NumberField({ initial: 1, integer: true }),
equipped: new fields.BooleanField({ initial: false })
};
}
}

View File

@@ -0,0 +1,12 @@
/**
* Data model pour les historiques MournbladeCYD2
*/
export default class HistoriqueDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
bonusmalus: new fields.StringField({ initial: "" })
};
}
}

26
modules/models/index.mjs Normal file
View File

@@ -0,0 +1,26 @@
/**
* Index des DataModels pour MournbladeCYD2
* Ce fichier centralise tous les exports des modèles de données
*/
// Modèles d'items
export { default as TalentDataModel } from './talent.mjs';
export { default as HistoriqueDataModel } from './historique.mjs';
export { default as ProfilDataModel } from './profil.mjs';
export { default as CompetenceDataModel } from './competence.mjs';
export { default as ArmeDataModel } from './arme.mjs';
export { default as ProtectionDataModel } from './protection.mjs';
export { default as MonnaieDataModel } from './monnaie.mjs';
export { default as EquipementDataModel } from './equipement.mjs';
export { default as RessourceDataModel } from './ressource.mjs';
export { default as DonDataModel } from './don.mjs';
export { default as PacteDataModel } from './pacte.mjs';
export { default as RuneDataModel } from './rune.mjs';
export { default as RuneEffectDataModel } from './runeeffect.mjs';
export { default as TendanceDataModel } from './tendance.mjs';
export { default as TraitChaotiqueDataModel } from './traitchaotique.mjs';
export { default as TraitEspeceDataModel } from './traitespece.mjs';
// Modèles d'acteurs
export { default as PersonnageDataModel } from './personnage.mjs';
export { default as CreatureDataModel } from './creature.mjs';

View File

@@ -0,0 +1,17 @@
/**
* Data model pour les monnaies MournbladeCYD2
*/
export default class MonnaieDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
prixpo: new fields.NumberField({ initial: 0, integer: true }),
prixca: new fields.NumberField({ initial: 0, integer: true }),
prixsc: new fields.NumberField({ initial: 0, integer: true }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
quantite: new fields.NumberField({ initial: 1, integer: true }),
equipped: new fields.BooleanField({ initial: false })
};
}
}

12
modules/models/pacte.mjs Normal file
View File

@@ -0,0 +1,12 @@
/**
* Data model pour les pactes MournbladeCYD2
*/
export default class PacteDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
allegeance: new fields.StringField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,108 @@
/**
* Data model pour les personnages MournbladeCYD2
*/
export default class PersonnageDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
// Template biodata
biodata: new fields.SchemaField({
name: new fields.StringField({ initial: "" }),
age: new fields.NumberField({ initial: 20, integer: true }),
poids: new fields.StringField({ initial: "" }),
taille: new fields.StringField({ initial: "" }),
cheveux: new fields.StringField({ initial: "" }),
sexe: new fields.StringField({ initial: "" }),
yeux: new fields.StringField({ initial: "" }),
description: new fields.HTMLField({ initial: "" }),
habitat: new fields.HTMLField({ initial: "" }),
notes: new fields.HTMLField({ initial: "" }),
statut: new fields.StringField({ initial: "" }),
gmnotes: new fields.HTMLField({ initial: "" }),
statutresistant: new fields.StringField({ initial: "commun" })
}),
// Template core
subactors: new fields.ArrayField(new fields.StringField(), { initial: [] }),
attributs: new fields.SchemaField({
adr: new fields.SchemaField({
label: new fields.StringField({ initial: "Adresse" }),
labelnorm: new fields.StringField({ initial: "adresse" }),
abbrev: new fields.StringField({ initial: "adr" }),
value: new fields.NumberField({ initial: 1, integer: true })
}),
pui: new fields.SchemaField({
label: new fields.StringField({ initial: "Puissance" }),
labelnorm: new fields.StringField({ initial: "puissance" }),
abbrev: new fields.StringField({ initial: "pui" }),
value: new fields.NumberField({ initial: 1, integer: true })
}),
cla: new fields.SchemaField({
label: new fields.StringField({ initial: "Clairvoyance" }),
labelnorm: new fields.StringField({ initial: "clairvoyance" }),
abbrev: new fields.StringField({ initial: "cla" }),
value: new fields.NumberField({ initial: 1, integer: true })
}),
pre: new fields.SchemaField({
label: new fields.StringField({ initial: "Présence" }),
labelnorm: new fields.StringField({ initial: "presence" }),
abbrev: new fields.StringField({ initial: "pre" }),
value: new fields.NumberField({ initial: 1, integer: true })
}),
tre: new fields.SchemaField({
label: new fields.StringField({ initial: "Trempe" }),
labelnorm: new fields.StringField({ initial: "trempe" }),
abbrev: new fields.StringField({ initial: "tre" }),
value: new fields.NumberField({ initial: 1, integer: true })
})
}),
bonneaventure: new fields.SchemaField({
base: new fields.NumberField({ initial: 0, integer: true }),
actuelle: new fields.NumberField({ initial: 0, integer: true })
}),
experience: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
eclat: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
sante: new fields.SchemaField({
vigueur: new fields.NumberField({ initial: 0, integer: true }),
etat: new fields.NumberField({ initial: 0, integer: true }),
vigueurmodifier: new fields.NumberField({ initial: 0, integer: true }),
nbcombativite: new fields.NumberField({ initial: 5, integer: true })
}),
ame: new fields.SchemaField({
seuilpouvoir: new fields.NumberField({ initial: 0, integer: true }),
etat: new fields.NumberField({ initial: 0, integer: true }),
seuilpouvoirmodifier: new fields.NumberField({ initial: 0, integer: true }),
nbame: new fields.NumberField({ initial: 7, integer: true }),
max: new fields.NumberField({ initial: 0, integer: true })
}),
adversite: new fields.SchemaField({
bleue: new fields.NumberField({ initial: 0, integer: true }),
rouge: new fields.NumberField({ initial: 0, integer: true }),
noire: new fields.NumberField({ initial: 0, integer: true })
}),
vitesse: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
combat: new fields.SchemaField({
initbonus: new fields.NumberField({ initial: 0, integer: true }),
vitessebonus: new fields.NumberField({ initial: 0, integer: true }),
bonusdegats: new fields.NumberField({ initial: 0, integer: true }),
attaquebonus: new fields.NumberField({ initial: 0, integer: true }),
defensebonus: new fields.NumberField({ initial: 0, integer: true }),
defensetotale: new fields.BooleanField({ initial: false }),
monte: new fields.BooleanField({ initial: false })
}),
balance: new fields.SchemaField({
loi: new fields.NumberField({ initial: 0, integer: true }),
chaos: new fields.NumberField({ initial: 0, integer: true }),
aspect: new fields.NumberField({ initial: 0, integer: true }),
marge: new fields.NumberField({ initial: 0, integer: true }),
pointschaos: new fields.NumberField({ initial: 0, integer: true }),
pointsloi: new fields.NumberField({ initial: 0, integer: true })
})
};
}
}

22
modules/models/profil.mjs Normal file
View File

@@ -0,0 +1,22 @@
/**
* Data model pour les profils MournbladeCYD2
*/
export default class ProfilDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
exemples: new fields.StringField({ initial: "" }),
attribut1: new fields.StringField({ initial: "" }),
attribut2: new fields.StringField({ initial: "" }),
attribut3: new fields.StringField({ initial: "" }),
competences: new fields.StringField({ initial: "" }),
talentsinitie: new fields.StringField({ initial: "" }),
prerequisaguerri: new fields.StringField({ initial: "" }),
talentsaguerri: new fields.StringField({ initial: "" }),
prerequismaitre: new fields.StringField({ initial: "" }),
talentsmaitre: new fields.StringField({ initial: "" }),
equipement: new fields.StringField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,19 @@
/**
* Data model pour les protections MournbladeCYD2
*/
export default class ProtectionDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
prixpo: new fields.NumberField({ initial: 0, integer: true }),
prixca: new fields.NumberField({ initial: 0, integer: true }),
prixsc: new fields.NumberField({ initial: 0, integer: true }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
quantite: new fields.NumberField({ initial: 1, integer: true }),
equipped: new fields.BooleanField({ initial: false }),
protection: new fields.NumberField({ initial: 0, integer: true }),
adversitepoids: new fields.NumberField({ initial: 0, integer: true })
};
}
}

View File

@@ -0,0 +1,12 @@
/**
* Data model pour les ressources MournbladeCYD2
*/
export default class RessourceDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
pointdev: new fields.NumberField({ initial: 0, integer: true })
};
}
}

15
modules/models/rune.mjs Normal file
View File

@@ -0,0 +1,15 @@
/**
* Data model pour les runes MournbladeCYD2
*/
export default class RuneDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
formule: new fields.StringField({ initial: "" }),
seuil: new fields.NumberField({ initial: 0, integer: true }),
prononcee: new fields.StringField({ initial: "" }),
tracee: new fields.StringField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,15 @@
/**
* Data model pour les effets de rune MournbladeCYD2
*/
export default class RuneEffectDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
rune: new fields.StringField({ initial: "" }),
mode: new fields.StringField({ initial: "" }),
duree: new fields.StringField({ initial: "" }),
pointame: new fields.NumberField({ initial: 0, integer: true })
};
}
}

30
modules/models/talent.mjs Normal file
View File

@@ -0,0 +1,30 @@
/**
* Data model pour les talents MournbladeCYD2
*/
export default class TalentDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
isautomated: new fields.BooleanField({ initial: false }),
automations: new fields.ArrayField(
new fields.SchemaField({
id: new fields.StringField({ initial: "" }),
eventtype: new fields.StringField({ initial: "on-drop" }),
name: new fields.StringField({ initial: "" }),
bonusname: new fields.StringField({ initial: "vigueur" }),
bonus: new fields.NumberField({ initial: 0, integer: true }),
competence: new fields.StringField({ initial: "" }),
minLevel: new fields.NumberField({ initial: 0, integer: true }),
baCost: new fields.NumberField({ initial: 0, integer: true })
}),
{ initial: [] }
),
talenttype: new fields.StringField({ initial: "" }),
utilisation: new fields.StringField({ initial: "" }),
prerequis: new fields.StringField({ initial: "" }),
resumebonus: new fields.StringField({ initial: "" }),
used: new fields.BooleanField({ initial: false })
};
}
}

View File

@@ -0,0 +1,12 @@
/**
* Data model pour les tendances MournbladeCYD2
*/
export default class TendanceDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
allegeance: new fields.StringField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,11 @@
/**
* Data model pour les traits chaotiques MournbladeCYD2
*/
export default class TraitChaotiqueDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,11 @@
/**
* Data model pour les traits d'espèce MournbladeCYD2
*/
export default class TraitEspeceDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" })
};
}
}

View File

@@ -14,7 +14,7 @@ export class MournbladeCYD2ActorSheet extends foundry.appv1.sheets.ActorSheet {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-mournblade-cyd2", "sheet", "actor"],
template: "systems/fvtt-mournblade-cyd2/templates/actor-sheet.html",
template: "systems/fvtt-mournblade-cyd2/templates/actor-sheet.hbs",
width: 640,
height: 720,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }],

View File

@@ -1,6 +1,6 @@
/* -------------------------------------------- */
import { MournbladeCYD2Utility } from "./mournblade-cyd2-utility.js";
import { MournbladeCYD2RollDialog } from "./mournblade-cyd2-roll-dialog.js";
import { MournbladeCYD2RollDialog } from "./applications/mournblade-cyd2-roll-dialog.mjs";
/* -------------------------------------------- */
const __degatsBonus = [-2, -2, -1, -1, 0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 8, 8, 9, 9, 10, 10]
@@ -858,9 +858,14 @@ export class MournbladeCYD2Actor extends Actor {
roll = await new Roll("1d10+" + arme.system.totalDegats + "+" + bonus + "+" + bonus2).roll()
}
await MournbladeCYD2Utility.showDiceSoNice(roll, game.settings.get("core", "rollMode"));
// CYD 2.0: dégâts ≥ SV → -2 combativité; ≥ 2×SV → -3 combativité
let nbEtatPerdus = 0
if (targetVigueur) {
nbEtatPerdus = Math.floor(roll.total / targetVigueur)
if (roll.total >= 2 * targetVigueur) {
nbEtatPerdus = 3
} else if (roll.total >= targetVigueur) {
nbEtatPerdus = 2
}
}
//console.log(roll)
let rollData = {
@@ -876,7 +881,7 @@ export class MournbladeCYD2Actor extends Actor {
nbEtatPerdus: nbEtatPerdus
}
MournbladeCYD2Utility.createChatWithRollMode(rollData.alias, {
content: await renderTemplate(`systems/fvtt-mournblade-cyd2/templates/chat-degats-result.html`, rollData)
content: await renderTemplate(`systems/fvtt-mournblade-cyd2/templates/chat-degats-result.hbs`, rollData)
})
if (rollDataInput?.defenderTokenId && nbEtatPerdus) {

View File

@@ -1,7 +1,7 @@
/* -------------------------------------------- */
import { MournbladeCYD2Utility } from "./mournblade-cyd2-utility.js";
import { MournbladeCYD2RollDialog } from "./mournblade-cyd2-roll-dialog.js";
import { MournbladeCYD2RollDialog } from "./applications/mournblade-cyd2-roll-dialog.mjs";
/* -------------------------------------------- */
export class MournbladeCYD2Commands {

View File

@@ -15,7 +15,7 @@ export class MournbladeCYD2CreatureSheet extends MournbladeCYD2ActorSheet {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-mournblade-cyd2", "sheet", "actor"],
template: "systems/fvtt-mournblade-cyd2/templates/creature-sheet.html",
template: "systems/fvtt-mournblade-cyd2/templates/creature-sheet.hbs",
width: 640,
height: 720,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }],

View File

@@ -24,7 +24,7 @@ export class MournbladeCYD2TokenHud {
const controlIconActions = $(html).find('.control-icon[data-action=combat]');
// initiative
await MournbladeCYD2TokenHud._configureSubMenu(controlIconActions, 'systems/fvtt-mournblade-cyd2/templates/hud-adversites.html', hudData,
await MournbladeCYD2TokenHud._configureSubMenu(controlIconActions, 'systems/fvtt-mournblade-cyd2/templates/hud-adversites.hbs', hudData,
(event) => {
let adversite = event.currentTarget.attributes['data-action-index'].value
let value = Number(event.currentTarget.attributes['data-action-value'].value)

View File

@@ -11,7 +11,7 @@ export class MournbladeCYD2ItemSheet extends foundry.appv1.sheets.ItemSheet {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-mournblade-cyd2", "sheet", "item"],
template: "systems/fvtt-mournblade-cyd2/templates/item-sheet.html",
template: "systems/fvtt-mournblade-cyd2/templates/item-sheet.hbs",
dragDrop: [{ dragSelector: null, dropSelector: null }],
width: 620,
height: 550,
@@ -105,7 +105,7 @@ export class MournbladeCYD2ItemSheet extends foundry.appv1.sheets.ItemSheet {
payload: chatData,
});
renderTemplate('systems/fvtt-mournblade-cyd2/templates/post-item.html', chatData).then(html => {
renderTemplate('systems/fvtt-mournblade-cyd2/templates/post-item.hbs', chatData).then(html => {
let chatOptions = MournbladeCYD2Utility.chatDataSetup(html);
ChatMessage.create(chatOptions)
});
@@ -217,7 +217,7 @@ export class MournbladeCYD2ItemSheet extends foundry.appv1.sheets.ItemSheet {
/* -------------------------------------------- */
get template() {
let type = this.item.type;
return `systems/fvtt-mournblade-cyd2/templates/item-${type}-sheet.html`;
return `systems/fvtt-mournblade-cyd2/templates/item-${type}-sheet.hbs`;
}
/* -------------------------------------------- */

View File

@@ -9,9 +9,7 @@
/* -------------------------------------------- */
// Import Modules
import { MournbladeCYD2Actor } from "./mournblade-cyd2-actor.js";
import { MournbladeCYD2ItemSheet } from "./mournblade-cyd2-item-sheet.js";
import { MournbladeCYD2ActorSheet } from "./mournblade-cyd2-actor-sheet.js";
import { MournbladeCYD2CreatureSheet } from "./mournblade-cyd2-creature-sheet.js";
import * as sheets from "./applications/sheets/_module.mjs";
import { MournbladeCYD2Utility } from "./mournblade-cyd2-utility.js";
import { MournbladeCYD2Combat } from "./mournblade-cyd2-combat.js";
import { MournbladeCYD2Item } from "./mournblade-cyd2-item.js";
@@ -19,6 +17,9 @@ import { MournbladeCYD2Automation } from "./mournblade-cyd2-automation.js";
import { MournbladeCYD2TokenHud } from "./mournblade-cyd2-hud.js";
import { MOURNBLADECYD2_CONFIG } from "./mournblade-cyd2-config.js";
// Import DataModels
import * as models from "./models/index.mjs";
/* -------------------------------------------- */
/* Foundry VTT Initialization */
/* -------------------------------------------- */
@@ -47,21 +48,57 @@ Hooks.once("init", async function () {
// Define custom Entity classes
CONFIG.Combat.documentClass = MournbladeCYD2Combat
CONFIG.Actor.documentClass = MournbladeCYD2Actor
CONFIG.Actor.dataModels = {
personnage: models.PersonnageDataModel,
creature: models.CreatureDataModel
}
CONFIG.Item.documentClass = MournbladeCYD2Item
CONFIG.Item.dataModels = {
talent: models.TalentDataModel,
historique: models.HistoriqueDataModel,
profil: models.ProfilDataModel,
competence: models.CompetenceDataModel,
arme: models.ArmeDataModel,
protection: models.ProtectionDataModel,
monnaie: models.MonnaieDataModel,
equipement: models.EquipementDataModel,
ressource: models.RessourceDataModel,
don: models.DonDataModel,
pacte: models.PacteDataModel,
rune: models.RuneDataModel,
runeeffect: models.RuneEffectDataModel,
tendance: models.TendanceDataModel,
traitchaotique: models.TraitChaotiqueDataModel,
traitespece: models.TraitEspeceDataModel
}
game.system.mournbladecyd2 = {
MournbladeCYD2Utility,
MournbladeCYD2Automation,
config: MOURNBLADECYD2_CONFIG
}
/* -------------------------------------------- */
// Regster sheet application classes
// Register sheet application classes (AppV2)
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
foundry.documents.collections.Actors.registerSheet("fvtt-mournblade-cyd2", MournbladeCYD2ActorSheet, { types: ["personnage"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("fvtt-mournblade-cyd2", MournbladeCYD2CreatureSheet, { types: ["creature"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2PersonnageSheet, { types: ["personnage"], makeDefault: true });
foundry.documents.collections.Actors.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2CreatureSheet, { types: ["creature"], makeDefault: true });
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", MournbladeCYD2ItemSheet, { makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2CompetenceSheet, { types: ["competence"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2TalentSheet, { types: ["talent"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2HistoriqueSheet, { types: ["historique"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2ProfilSheet, { types: ["profil"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2ArmeSheet, { types: ["arme"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2ProtectionSheet, { types: ["protection"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2MonnaieSheet, { types: ["monnaie"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2EquipementSheet, { types: ["equipement"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2RessourceSheet, { types: ["ressource"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2DonSheet, { types: ["don"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2PacteSheet, { types: ["pacte"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2RuneSheet, { types: ["rune"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2RuneEffectSheet, { types: ["runeeffect"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2TendanceSheet, { types: ["tendance"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2TraitChaotiqueSheet, { types: ["traitchaotique"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd2", sheets.MournbladeCYD2TraitEspeceSheet, { types: ["traitespece"], makeDefault: true });
MournbladeCYD2Utility.init()
MournbladeCYD2Automation.init()

View File

@@ -6,7 +6,7 @@ export class MournbladeCYD2RollDialog extends Dialog {
static async create(actor, rollData ) {
let options = { classes: ["MournbladeCYD2Dialog"], width: 320, height: 'fit-content', 'z-index': 99999 };
let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-mournblade-cyd2/templates/roll-dialog-generic.html', rollData);
let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-mournblade-cyd2/templates/roll-dialog-generic.hbs', rollData);
return new MournbladeCYD2RollDialog(actor, rollData, html, options );
}

View File

@@ -182,13 +182,13 @@ export class MournbladeCYD2Utility {
static async preloadHandlebarsTemplates() {
const templatePaths = [
'systems/fvtt-mournblade-cyd2/templates/editor-notes-gm.html',
'systems/fvtt-mournblade-cyd2/templates/partial-item-header.html',
'systems/fvtt-mournblade-cyd2/templates/partial-item-description.html',
'systems/fvtt-mournblade-cyd2/templates/partial-item-nav.html',
'systems/fvtt-mournblade-cyd2/templates/partial-item-prix.html',
'systems/fvtt-mournblade-cyd2/templates/partial-automation.html',
'systems/fvtt-mournblade-cyd2/templates/hud-adversites.html',
'systems/fvtt-mournblade-cyd2/templates/editor-notes-gm.hbs',
'systems/fvtt-mournblade-cyd2/templates/partial-item-header.hbs',
'systems/fvtt-mournblade-cyd2/templates/partial-item-description.hbs',
'systems/fvtt-mournblade-cyd2/templates/partial-item-nav.hbs',
'systems/fvtt-mournblade-cyd2/templates/partial-item-prix.hbs',
'systems/fvtt-mournblade-cyd2/templates/partial-automation.hbs',
'systems/fvtt-mournblade-cyd2/templates/hud-adversites.hbs',
]
return foundry.applications.handlebars.loadTemplates(templatePaths);
}
@@ -503,7 +503,7 @@ export class MournbladeCYD2Utility {
}
this.createChatWithRollMode(rollData.alias, {
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-mournblade-cyd2/templates/chat-generic-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-mournblade-cyd2/templates/chat-generic-result.hbs`, rollData)
}, rollData)
if ((rollData.coupBas || rollData.arme) && rollData.isSuccess && rollData.defenderTokenId) {
@@ -610,7 +610,7 @@ export class MournbladeCYD2Utility {
this.computeResultQuality(rollData)
this.createChatWithRollMode(rollData.alias, {
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-mournblade-cyd2/templates/chat-generic-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-mournblade-cyd2/templates/chat-generic-result.hbs`, rollData)
}, rollData)
}