Rework fiches, jets de dés et CSS

This commit is contained in:
2026-04-03 16:22:51 +02:00
parent e001ec0dc9
commit 1fb80f6abe
21 changed files with 3091 additions and 1316 deletions

View File

@@ -28,7 +28,7 @@ export class MournbladeCYD2RollDialog {
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 },
position: { width: 470 },
modal: false,
content,
buttons: [
@@ -38,8 +38,8 @@ export class MournbladeCYD2RollDialog {
icon: "fa-solid fa-dice-d10",
default: true,
callback: (event, button, dialog) => {
MournbladeCYD2RollDialog._updateRollDataFromForm(rollData, button.form.elements, actor);
rollData.mainDice = "1d10";
MournbladeCYD2RollDialog._updateRollDataFromForm(rollData, button.form, actor);
rollData.mainDice = "d10";
MournbladeCYD2Utility.rollMournbladeCYD2(rollData);
}
},
@@ -48,8 +48,8 @@ export class MournbladeCYD2RollDialog {
label: "Lancer 1d20",
icon: "fa-solid fa-dice-d20",
callback: (event, button, dialog) => {
MournbladeCYD2RollDialog._updateRollDataFromForm(rollData, button.form.elements, actor);
rollData.mainDice = "1d20";
MournbladeCYD2RollDialog._updateRollDataFromForm(rollData, button.form, actor);
rollData.mainDice = "d20";
MournbladeCYD2Utility.rollMournbladeCYD2(rollData);
}
},
@@ -63,19 +63,47 @@ export class MournbladeCYD2RollDialog {
}
/* -------------------------------------------- */
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"];
static _updateRollDataFromForm(rollData, form, actor) {
const el = form.elements;
const getVal = (name) => el[name]?.value;
const getChecked = (name) => {
const e = form.querySelector(`#${name}`);
return e ? e.checked : false;
};
if (el.modificateur) rollData.modificateur = Number(getVal("modificateur"));
if (el["bonus-malus-context"]) rollData.bonusMalusContext = Number(getVal("bonus-malus-context"));
if (el.difficulte) rollData.difficulte = Number(getVal("difficulte"));
if (el.attrKey) rollData.attrKey = String(getVal("attrKey"));
if (el.attrKey2) rollData.attrKey2 = String(getVal("attrKey2"));
if (el["select-maitrise"]) rollData.maitriseId = String(getVal("select-maitrise"));
if (el["competence-talents"]) {
const sel = el["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);
if (el["taille-cible"]) rollData.tailleCible = String(getVal("taille-cible"));
if (el["tireur-deplacement"]) rollData.tireurDeplacement = String(getVal("tireur-deplacement"));
if (el["cible-couvert"]) rollData.cibleCouvert = String(getVal("cible-couvert"));
if (el["distance-tir"]) rollData.distanceTir = String(getVal("distance-tir"));
if (el["soutiens"]) rollData.soutiens = Number(getVal("soutiens"));
if (el["runemode"]) rollData.runemode = String(getVal("runemode"));
if (el["runeame"]) rollData.runeame = Number(getVal("runeame"));
rollData.defenseurAuSol = getChecked("defenseur-au-sol");
rollData.defenseurAveugle = getChecked("defenseur-aveugle");
rollData.defenseurDeDos = getChecked("defenseur-de-dos");
rollData.defenseurRestreint = getChecked("defenseur-restreint");
rollData.defenseurImmobilise = getChecked("defenseur-immobilise");
rollData.attaquantsMultiples = getChecked("attaquants-multiple");
rollData.ambidextre1 = getChecked("ambidextre-1");
rollData.ambidextre2 = getChecked("ambidextre-2");
rollData.feinte = getChecked("feinte");
rollData.attaqueCharge = getChecked("attaque-charge");
rollData.chargeCavalerie = getChecked("charge-cavalerie");
rollData.contenir = getChecked("contenir");
rollData.attaqueDesarme = getChecked("attaque-desarme");
rollData.cibleDeplace = getChecked("tireur-cible-deplace");
rollData.cibleCaC = getChecked("cible-cac");
rollData.cibleconsciente = getChecked("cibleconsciente");
}
}

View File

@@ -113,7 +113,7 @@ export default class MournbladeCYD2ActorSheetV2 extends HandlebarsApplicationMix
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 });
if (item) await item.update({ [`system.${itemField}`]: value });
});
});

View File

@@ -1,211 +0,0 @@
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
import { MournbladeCYD2Utility } from "./mournblade-cyd2-utility.js";
import { MournbladeCYD2Automation } from "./mournblade-cyd2-automation.js";
/* -------------------------------------------- */
export class MournbladeCYD2ActorSheet extends foundry.appv1.sheets.ActorSheet {
/** @override */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-mournblade-cyd-2-0", "sheet", "actor"],
template: "systems/fvtt-mournblade-cyd-2-0/templates/actor-sheet.hbs",
width: 640,
height: 720,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
editScore: false
})
}
/* -------------------------------------------- */
async getData() {
const objectData = foundry.utils.duplicate(this.object)
let formData = {
title: this.title,
id: objectData.id,
type: objectData.type,
img: objectData.img,
name: objectData.name,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
system: objectData.system,
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
limited: this.object.limited,
skills: this.actor.getSkills(),
armes: foundry.utils.duplicate(this.actor.getWeapons()),
monnaies: foundry.utils.duplicate(this.actor.getMonnaies()),
protections: foundry.utils.duplicate(this.actor.getArmors()),
historiques: foundry.utils.duplicate(this.actor.getHistoriques() || []),
talents: foundry.utils.duplicate(this.actor.getTalents() || []),
dons: foundry.utils.duplicate(this.actor.getDons() || []),
pactes: foundry.utils.duplicate(this.actor.getPactes() || []),
tendances: foundry.utils.duplicate(this.actor.getTendances() || []),
runes: foundry.utils.duplicate(this.actor.getRunes() || []),
traitsChaotiques: foundry.utils.duplicate(this.actor.getTraitsChaotiques() || []),
traitsEspeces: foundry.utils.duplicate(this.actor.getTraitsEspeces() || []),
aspect: this.actor.getAspect(),
marge: this.actor.getMarge(),
profils: foundry.utils.duplicate(this.actor.getProfils() || []),
combat: this.actor.getCombatValues(),
equipements: foundry.utils.duplicate(this.actor.getEquipments()),
richesse: this.actor.computeRichesse(),
coupDevastateur: this.actor.items.find(it => it.type == "talent" && it.name.toLowerCase() == "coup devastateur" && !it.system.used),
valeurEquipement: this.actor.computeValeurEquipement(),
nbCombativite: this.actor.system.sante.nbcombativite,
combativiteList: MournbladeCYD2Utility.getCombativiteList(this.actor.system.sante.nbcombativite),
nbAme: this.actor.system.ame.nbame,
ameMax: this.actor.getAmeMax(),
ameList: MournbladeCYD2Utility.getAmeList(this.actor.system.ame.nbame, this.actor.getAmeMax()),
ameMaxList: MournbladeCYD2Utility.getAmeMaxList(this.actor.system.ame.nbame),
initiative: this.actor.getFlag("world", "last-initiative") || -1,
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.description, { async: true }),
habitat: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.habitat, { async: true }),
options: this.options,
owner: this.document.isOwner,
editScore: this.options.editScore,
isGM: game.user.isGM,
config: game.system.mournbladecyd2.config
}
this.formData = formData;
console.log("PC : ", formData, this.object);
return formData;
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
// Update Inventory Item
html.find('.item-edit').click(ev => {
const li = $(ev.currentTarget).parents(".item")
let itemId = li.data("item-id")
const item = this.actor.items.get(itemId)
item.sheet.render(true)
})
// Delete Inventory Item
html.find('.item-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item");
MournbladeCYD2Utility.confirmDelete(this, li);
})
html.find('.edit-item-data').change(ev => {
const li = $(ev.currentTarget).parents(".item")
let itemId = li.data("item-id")
let itemType = li.data("item-type")
let itemField = $(ev.currentTarget).data("item-field")
let dataType = $(ev.currentTarget).data("dtype")
let value = ev.currentTarget.value
this.actor.editItemField(itemId, itemType, itemField, dataType, value)
})
html.find('.adversite-modify').click(event => {
const li = $(event.currentTarget).parents(".item")
let adv = li.data("adversite")
let value = Number($(event.currentTarget).data("adversite-value"))
this.actor.incDecAdversite(adv, value)
})
html.find('.quantity-modify').click(event => {
const li = $(event.currentTarget).parents(".item")
const value = Number($(event.currentTarget).data("quantite-value"))
this.actor.incDecQuantity(li.data("item-id"), value);
})
html.find('.roll-initiative').click((event) => {
this.actor.rollAttribut("adr", true)
})
html.find('.roll-attribut').click((event) => {
const li = $(event.currentTarget).parents(".item")
let attrKey = li.data("attr-key")
this.actor.rollAttribut(attrKey, false)
})
html.find('.roll-competence').click((event) => {
const li = $(event.currentTarget).parents(".item")
let attrKey = $(event.currentTarget).data("attr-key")
let compId = li.data("item-id")
this.actor.rollCompetence(attrKey, compId)
})
html.find('.roll-arme-offensif').click((event) => {
const li = $(event.currentTarget).parents(".item")
let armeId = li.data("item-id")
this.actor.rollArmeOffensif(armeId)
})
html.find('.roll-assommer').click((event) => {
this.actor.rollAssommer()
})
html.find('.roll-coup-bas').click((event) => {
this.actor.rollCoupBas()
})
html.find('.roll-immobiliser').click((event) => {
this.actor.rollImmobiliser()
})
html.find('.roll-repousser').click((event) => {
this.actor.rollRepousser()
})
html.find('.roll-desengager').click((event) => {
this.actor.rollDesengager()
})
html.find('.roll-arme-degats').click((event) => {
const li = $(event.currentTarget).parents(".item")
let armeId = li.data("item-id")
this.actor.rollArmeDegats(armeId)
})
html.find('.item-add').click((event) => {
const itemType = $(event.currentTarget).data("type")
this.actor.createEmbeddedDocuments('Item', [{ name: `Nouveau ${itemType}`, type: itemType }], { renderSheet: true })
})
html.find('.lock-unlock-sheet').click((event) => {
this.options.editScore = !this.options.editScore;
this.render(true);
});
html.find('.item-equip').click(ev => {
const li = $(ev.currentTarget).parents(".item");
this.actor.equipItem(li.data("item-id"));
this.render(true);
});
}
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight);
return position;
}
/* -------------------------------------------- */
async _onDropItem(event, dragData) {
let data = event.dataTransfer.getData('text/plain')
let dataItem = JSON.parse(data)
let item = fromUuidSync(dataItem.uuid)
if (item.pack) {
item = await MournbladeCYD2Utility.searchItem(item)
}
let autoresult = MournbladeCYD2Automation.processAutomations("on-drop", item, this.actor)
if (autoresult.isValid) {
super._onDropItem(event, dragData)
} else {
ui.notifications.warn(autoresult.warningMessage)
}
}
}

View File

@@ -774,7 +774,7 @@ export class MournbladeCYD2Actor extends Actor {
/* -------------------------------------------- */
async rollAttribut(attrKey, isInit = false) {
let rollData = this.getCommonRollData(attrKey)
rollData.multiplier = (isInit) ? 1 : 2
rollData.multiplier = 1 // 1d10 + attr (optionally + attr2 if chosen in dialog)
rollData.isInit = isInit
await MournbladeCYD2RollDialog.create(this, rollData)
}
@@ -842,6 +842,33 @@ export class MournbladeCYD2Actor extends Actor {
await MournbladeCYD2RollDialog.create(this, rollData)
}
/* -------------------------------------------- */
subPointsAme(runeMode, value) {
let ame = foundry.utils.duplicate(this.system.ame)
if (runeMode == "prononcer") {
ame.etat += value
ame.etat = Math.min(ame.etat, ame.nbame)
} else {
ame.max = (ame.max || 0) + value
}
this.update({ 'system.ame': ame })
}
/* -------------------------------------------- */
async rollRune(runeId) {
let comp = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "savoir : runes")
if (!comp) {
ui.notifications.warn("La compétence « Savoir : Runes » n'a pas été trouvée sur ce personnage.")
return
}
let rollData = this.getCommonRollData("cla", comp.id)
rollData.rune = foundry.utils.duplicate(this.items.get(runeId) || {})
rollData.difficulte = rollData.rune?.system?.seuil || 0
rollData.runemode = "prononcer"
rollData.runeame = 1
await MournbladeCYD2RollDialog.create(this, rollData)
}
/* -------------------------------------------- */
async rollArmeDegats(armeId, targetVigueur = undefined, rollDataInput = undefined) {
let arme = this.items.get(armeId)
@@ -886,6 +913,7 @@ export class MournbladeCYD2Actor extends Actor {
//console.log(roll)
let rollData = {
arme: arme,
diceResult: roll.dice[0]?.total ?? roll.total,
finalResult: roll.total,
formula: roll.formula,
alias: this.name,

View File

@@ -52,9 +52,9 @@ export const MOURNBLADECYD2_CONFIG = {
{ key: "30", label: "Pure Folie (30)" }
],
optionsDistanceTir: [
{ key: "porteecourte", label: "Courte ({protectionDefenseur}+5)" },
{ key: "porteemoyenne", label: "Moyenne ({protectionDefenseur}+9)" },
{ key: "porteelongue", label: "Longue ({protectionDefenseur}+14)" }
{ key: "porteecourte", label: "Courte (base +5)" },
{ key: "porteemoyenne", label: "Moyenne (base +9)" },
{ key: "porteelongue", label: "Longue (base +14)" }
],
optionsBonusMalus: [
{ key: "-10", label: "-10" },

View File

@@ -1,26 +0,0 @@
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
import { MournbladeCYD2ActorSheet } from "./mournblade-cyd2-actor-sheet.js";
import { MournbladeCYD2Utility } from "./mournblade-cyd2-utility.js";
import { MournbladeCYD2Automation } from "./mournblade-cyd2-automation.js";
/* -------------------------------------------- */
export class MournbladeCYD2CreatureSheet extends MournbladeCYD2ActorSheet {
/** @override */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-mournblade-cyd-2-0", "sheet", "actor"],
template: "systems/fvtt-mournblade-cyd-2-0/templates/creature-sheet.hbs",
width: 640,
height: 720,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
editScore: false
})
}
}

View File

@@ -1,228 +0,0 @@
import { MournbladeCYD2Utility } from "./mournblade-cyd2-utility.js";
/**
* Extend the basic ItemSheet with some very simple modifications
* @extends {ItemSheet}
*/
export class MournbladeCYD2ItemSheet extends foundry.appv1.sheets.ItemSheet {
/** @override */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-mournblade-cyd-2-0", "sheet", "item"],
template: "systems/fvtt-mournblade-cyd-2-0/templates/item-sheet.hbs",
dragDrop: [{ dragSelector: null, dropSelector: null }],
width: 620,
height: 550,
tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description"}]
});
}
/* -------------------------------------------- */
_getHeaderButtons() {
let buttons = super._getHeaderButtons();
// Add "Post to chat" button
// We previously restricted this to GM and editable items only. If you ever find this comment because it broke something: eh, sorry!
buttons.unshift(
{
class: "post",
icon: "fas fa-comment",
onclick: ev => { }
})
return buttons
}
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight);
if (this.item.type.includes('weapon')) {
position.width = 640;
}
return position;
}
/* -------------------------------------------- */
async getData() {
const objectData = foundry.utils.duplicate(this.object)
let formData = {
title: this.title,
id: this.id,
type: objectData.type,
img: objectData.img,
name: objectData.name,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
attributs: MournbladeCYD2Utility.getAttributs(),
system: objectData.system,
limited: this.object.limited,
options: this.options,
owner: this.document.isOwner,
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.description, {async: true}),
mr: (this.object.type == 'specialisation'),
isGM: game.user.isGM,
config: game.system.mournbladecyd2.config
}
if ( objectData.type == "don") {
formData.sacrifice = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.sacrifice, {async: true})
}
//this.options.editable = !(this.object.origin == "embeddedItem");
console.log("ITEM DATA", formData, this);
return formData;
}
/* -------------------------------------------- */
_getHeaderButtons() {
let buttons = super._getHeaderButtons();
buttons.unshift({
class: "post",
icon: "fas fa-comment",
onclick: ev => this.postItem()
});
return buttons
}
/* -------------------------------------------- */
postItem() {
let chatData = foundry.utils.duplicate(MournbladeCYD2Utility.data(this.item));
if (this.actor) {
chatData.actor = { id: this.actor.id };
}
// Don't post any image for the item (which would leave a large gap) if the default image is used
if (chatData.img.includes("/blank.png")) {
chatData.img = null;
}
// JSON object for easy creation
chatData.jsondata = JSON.stringify(
{
compendium: "postedItem",
payload: chatData,
});
renderTemplate('systems/fvtt-mournblade-cyd-2-0/templates/post-item.hbs', chatData).then(html => {
let chatOptions = MournbladeCYD2Utility.chatDataSetup(html);
ChatMessage.create(chatOptions)
});
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
// Update Inventory Item
html.find('.item-edit').click(ev => {
const li = $(ev.currentTarget).parents(".item")
const item = this.object.options.actor.getOwnedItem(li.data("item-id"))
item.sheet.render(true);
});
html.find('.delete-subitem').click(ev => {
this.deleteSubitem(ev);
})
html.find('.edit-predilection').change(ev => {
const li = $(ev.currentTarget).parents(".prediction-item")
let index = li.data("prediction-index")
let pred = foundry.utils.duplicate(this.object.system.predilections)
pred[index].name = ev.currentTarget.value
pred[index].id = pred[index].id || randomID(16)
this.object.update( { 'system.predilections': pred })
})
html.find('.edit-predilection-description').change(ev => {
const li = $(ev.currentTarget).parents(".prediction-item")
let index = li.data("prediction-index")
let pred = foundry.utils.duplicate(this.object.system.predilections)
pred[index].description = ev.currentTarget.value
pred[index].id = pred[index].id || randomID(16)
this.object.update( { 'system.predilections': pred })
})
html.find('.predilection-acquise').change(ev => {
const li = $(ev.currentTarget).parents(".prediction-item")
let index = li.data("prediction-index")
let pred = foundry.utils.duplicate(this.object.system.predilections)
pred[index].acquise = ev.currentTarget.checked
pred[index].id = pred[index].id || randomID(16)
this.object.update( { 'system.predilections': pred })
})
html.find('.predilection-maitrise').change(ev => {
const li = $(ev.currentTarget).parents(".prediction-item")
let index = li.data("prediction-index")
let pred = foundry.utils.duplicate(this.object.system.predilections)
pred[index].maitrise = ev.currentTarget.checked
pred[index].id = pred[index].id || randomID(16)
this.object.update( { 'system.predilections': pred })
})
html.find('.predilection-used').change(ev => {
const li = $(ev.currentTarget).parents(".prediction-item")
let index = li.data("prediction-index")
let pred = foundry.utils.duplicate(this.object.system.predilections)
pred[index].used = ev.currentTarget.checked
pred[index].id = pred[index].id || randomID(16)
this.object.update( { 'system.predilections': pred })
})
html.find('#add-predilection').click(ev => {
let pred = foundry.utils.duplicate(this.object.system.predilections)
pred.push( { name: "Nouvelle prédilection", id: randomID(16), used: false })
this.object.update( { 'system.predilections': pred })
})
html.find('.delete-prediction').click(ev => {
const li = $(ev.currentTarget).parents(".prediction-item")
let index = li.data("prediction-index")
let pred = foundry.utils.duplicate(this.object.system.predilections)
pred.splice(index,1)
this.object.update( { 'system.predilections': pred })
})
html.find('#add-automation').click(ev => {
let autom = foundry.utils.duplicate(this.object.system.automations)
autom.push( { eventtype: "on-drop", name: "Automatisation 1", bonusname: "vigueur", bonus: 0, competence: "", minLevel: 0, baCost: 0, id: randomID(16) })
this.object.update( { 'system.automations': autom })
})
html.find('.delete-automation').click(ev => {
const li = $(ev.currentTarget).parents(".automation-item")
let index = li.data("automation-index")
let autom = foundry.utils.duplicate(this.object.system.automations)
autom.splice(index,1)
this.object.update( { 'system.automations': autom })
})
html.find('.automation-edit-field').change(ev => {
let index = $(ev.currentTarget).data("automation-index")
let field = $(ev.currentTarget).data("automation-field")
let auto = foundry.utils.duplicate(this.object.system.automations)
auto[index][field] = ev.currentTarget.value
auto[index].id = auto[index].id || randomID(16)
this.object.update( { 'system.automations': auto })
})
// Update Inventory Item
html.find('.item-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item");
let itemId = li.data("item-id");
let itemType = li.data("item-type");
});
}
/* -------------------------------------------- */
get template() {
let type = this.item.type;
return `systems/fvtt-mournblade-cyd-2-0/templates/item-${type}-sheet.hbs`;
}
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) {
return this.object.update(formData);
}
}

View File

@@ -111,12 +111,43 @@ function welcomeMessage() {
ChatMessage.create({
user: game.user.id,
whisper: [game.user.id],
content: `<div id="welcome-message-MournbladeCYD2"><span class="rdd-roll-part">
<strong>Bienvenue dans Mournblade CYD 2.0 !</strong>
<p>Les livres de Mournblade sont nécessaires pour jouer : https://www.titam-france.fr ainsi que le supplément de conversion de règle pour le CYD 2.0</p>
<p>Mournblade est un jeu de rôle publié par Titam France/Sombres projets, tous les droits leur appartiennent.</p>
<p>Système développé par LeRatierBretonnien, support sur le <a href="https://discord.gg/pPSDNJk">Discord FR de Foundry</a>.</p>
` });
content: `<div class="mournblade-welcome-message">
<div class="welcome-header">
<div class="welcome-icon"><i class="fas fa-sword"></i></div>
<h2 class="welcome-title">Mournblade CYD 2.0</h2>
<div class="welcome-subtitle">Système FoundryVTT — Bienvenue !</div>
</div>
<div class="welcome-content">
<div class="welcome-section">
<div class="section-icon"><i class="fas fa-book-open"></i></div>
<div class="section-text">
<strong>Livres nécessaires</strong>
<p>Les livres de Mournblade sont nécessaires pour jouer. Supplément de conversion CYD 2.0 requis.</p>
<a class="welcome-link" href="https://www.titam-france.fr" target="_blank"><i class="fas fa-external-link-alt"></i>titam-france.fr</a>
</div>
</div>
<div class="welcome-section">
<div class="section-icon"><i class="fas fa-copyright"></i></div>
<div class="section-text">
<strong>Droits</strong>
<p>Mournblade est un jeu publié par Titam France / Sombres Projets, tous les droits leur appartiennent.</p>
</div>
</div>
<div class="welcome-section">
<div class="section-icon"><i class="fab fa-discord"></i></div>
<div class="section-text">
<strong>Support</strong>
<p>Système développé par LeRatierBretonnien.</p>
<a class="welcome-link" href="https://discord.gg/pPSDNJk" target="_blank"><i class="fab fa-discord"></i>Discord FR Foundry</a>
</div>
</div>
</div>
<div class="welcome-footer">
<i class="fas fa-dice-d20"></i>
<span>Bonne partie !</span>
</div>
</div>`
});
}
/* -------------------------------------------- */

View File

@@ -1,142 +0,0 @@
import { MournbladeCYD2Utility } from "./mournblade-cyd2-utility.js";
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-cyd-2-0/templates/roll-dialog-generic.hbs', rollData);
return new MournbladeCYD2RollDialog(actor, rollData, html, options );
}
/* -------------------------------------------- */
constructor(actor, rollData, html, options, close = undefined) {
let conf = {
title: "Test de Capacité",
content: html,
buttons: {
rolld10: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d10",
callback: () => { this.roll("d10") }
},
rolld20: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d20",
callback: () => { this.roll("d20") }
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: "Annuler",
callback: () => { this.close() }
} },
close: close
}
super(conf, options);
this.actor = actor
this.rollData = rollData
}
/* -------------------------------------------- */
roll ( dice) {
this.rollData.mainDice = dice
MournbladeCYD2Utility.rollMournbladeCYD2( this.rollData )
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
var dialog = this;
function onLoad() {
}
$(function () { onLoad(); });
html.find('#modificateur').change(async (event) => {
this.rollData.modificateur = Number(event.currentTarget.value)
})
html.find('#difficulte').change( (event) => {
console.log("Difficulte: " + event.currentTarget.value)
this.rollData.difficulte = Number(event.currentTarget.value)
})
html.find('#attrKey').change(async (event) => {
this.rollData.attrKey = String(event.currentTarget.value)
})
html.find('#attrKey2').change(async (event) => {
this.rollData.attrKey2 = String(event.currentTarget.value)
})
html.find('#select-maitrise').change(async (event) => {
this.rollData.maitriseId = String(event.currentTarget.value)
})
html.find('#competence-talents').change((event) => {
this.rollData.selectedTalents = $('#competence-talents').val()
})
html.find('#taille-cible').change((event) => {
this.rollData.tailleCible = String(event.currentTarget.value)
})
html.find('#tireur-deplacement').change((event) => {
this.rollData.tireurDeplacement = String(event.currentTarget.value)
})
html.find('#cible-couvert').change((event) => {
this.rollData.cibleCouvert = String(event.currentTarget.value)
})
html.find('#distance-tir').change((event) => {
this.rollData.distanceTir = String(event.currentTarget.value)
})
html.find('#bonus-malus-context').change((event) => {
this.rollData.bonusMalusContext = Number(event.currentTarget.value)
})
html.find('#defenseur-au-sol').change((event) => {
this.rollData.defenseurAuSol = event.currentTarget.checked
})
html.find('#ambidextre-1').change((event) => {
this.rollData.ambidextre1 = event.currentTarget.checked
})
html.find('#ambidextre-2').change((event) => {
this.rollData.ambidextre2 = event.currentTarget.checked
})
html.find('#attaque-monte').change((event) => {
this.rollData.attqueMonte = event.currentTarget.checked
})
html.find('#defenseur-aveugle').change((event) => {
this.rollData.defenseurAveugle = event.currentTarget.checked
})
html.find('#defenseur-de-dos').change((event) => {
this.rollData.defenseurDeDos = event.currentTarget.checked
})
html.find('#defenseur-restreint').change((event) => {
this.rollData.defenseurRestreint = event.currentTarget.checked
})
html.find('#defenseur-immobilise').change((event) => {
this.rollData.defenseurImmobilise = event.currentTarget.checked
})
html.find('#attaque-charge').change((event) => {
this.rollData.attaqueCharge = event.currentTarget.checked
})
html.find('#charge-cavalerie').change((event) => {
this.rollData.chargeCavalerie = event.currentTarget.checked
})
html.find('#attaquants-multiple').change((event) => {
this.rollData.attaquantsMultiples = event.currentTarget.checked
})
html.find('#soutiens').change((event) => {
this.rollData.soutiens = Number(event.currentTarget.value)
})
html.find('#feinte').change((event) => {
this.rollData.feinte = event.currentTarget.checked
})
html.find('#contenir').change((event) => {
this.rollData.contenir = event.currentTarget.checked
})
html.find('#attaque-desarme').change((event) => {
this.rollData.attaqueDesarme = event.currentTarget.checked
})
}
}

View File

@@ -46,6 +46,11 @@ export class MournbladeCYD2Utility {
Handlebars.registerHelper('mul', function (a, b) {
return parseInt(a) * parseInt(b);
})
Handlebars.registerHelper('select', function(value, options) {
const html = options.fn(this);
const escaped = String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
return html.replace(new RegExp(`value="${escaped}"`, 'g'), `value="${value}" selected="selected"`);
})
game.settings.register("fvtt-mournblade-cyd-2-0", "mournblade-cyd2-pause-logo", {
name: "Logo de pause",
@@ -63,6 +68,7 @@ export class MournbladeCYD2Utility {
// Initialise les listes de sélection dès le hook init (avant le rendu des fiches)
game.system.mournbladecyd2.config.listeNiveauSkill = this.createDirectOptionList(0, 10)
game.system.mournbladecyd2.config.listeNiveauCreature = this.createDirectOptionList(0, 35)
game.system.mournbladecyd2.config.pointsAmeOptions = this.createDirectOptionList(1, 20)
}
@@ -151,7 +157,7 @@ export class MournbladeCYD2Utility {
static async chatListeners(html) {
$(html).on("click", '.predilection-reroll', async event => {
let predIdx = $(event.currentTarget).data("predilection-index")
let predIdx = event.currentTarget.dataset.predilectionIndex
let messageId = MournbladeCYD2Utility.findChatMessageId(event.currentTarget)
let message = game.messages.get(messageId)
let rollData = message.getFlag("world", "mournblade-cyd2-roll")
@@ -345,7 +351,7 @@ export class MournbladeCYD2Utility {
if (rollData.mainDice.includes("d20")) {
let diceValue = rollData.roll.terms[0].results[0].result
if (diceValue % 2 == 1) {
//console.log("PAIR/IMP2", diceValue)
rollData.isD20Impair = true
rollData.finalResult -= rollData.roll.terms[0].results[0].result // Substract value
if (diceValue == 1 || diceValue == 11) {
rollData.isDramatique = true
@@ -425,7 +431,8 @@ export class MournbladeCYD2Utility {
} else if (rollData.attr2) {
rollData.diceFormula += `+${rollData.attr.value}+${rollData.attr2.value}+${rollData.modificateur}+${rollData.bonusMalusContext}`
} else {
rollData.diceFormula += `+${rollData.attr.value}*${rollData.multiplier}+${rollData.modificateur}+${rollData.bonusMalusContext}`
const attrPart = rollData.multiplier > 1 ? `${rollData.attr.value}*${rollData.multiplier}` : `${rollData.attr.value}`
rollData.diceFormula += `+${attrPart}+${rollData.modificateur}+${rollData.bonusMalusContext}`
}
// Bonus arme naturelle en défense
@@ -491,6 +498,21 @@ export class MournbladeCYD2Utility {
rollData.finalResult = myRoll.total
this.computeResult(rollData)
// Rune post-roll: calculate duration and apply soul cost
if (rollData.rune) {
rollData.runeduree = Math.ceil(rollData.runeame / 3)
if (rollData.runemode == "inscrire") {
rollData.runeduree *= 2
}
let subAme = rollData.runeame
if (!rollData.isSuccess && !rollData.isDramatique) {
subAme = Math.ceil(rollData.runeame / 2)
}
rollData.runeAmeCout = subAme
actor.subPointsAme(rollData.runemode, subAme)
}
if (rollData.isInit) {
actor.setFlag("world", "last-initiative", rollData.finalResult)
}
@@ -779,7 +801,8 @@ export class MournbladeCYD2Utility {
/* -------------------------------------------- */
static applyBonneAventureRoll(li, changed, addedBonus) {
let msgId = $(li).data("message-id")
const el = li instanceof HTMLElement ? li : li[0];
let msgId = el.dataset.messageId ?? el.closest("[data-message-id]")?.dataset.messageId
let msg = game.messages.get(msgId)
if (msg) {
let rollData = msg.getFlag("world", "mournblade-cyd2-roll")
@@ -798,7 +821,8 @@ export class MournbladeCYD2Utility {
/* -------------------------------------------- */
static applyEclatRoll(li, changed, addedBonus) {
let msgId = $(li).data("message-id")
const el = li instanceof HTMLElement ? li : li[0];
let msgId = el.dataset.messageId ?? el.closest("[data-message-id]")?.dataset.messageId
let msg = game.messages.get(msgId)
if (msg) {
let rollData = msg.getFlag("world", "mournblade-cyd2-roll")
@@ -817,14 +841,19 @@ export class MournbladeCYD2Utility {
/* -------------------------------------------- */
static chatRollMenu(html, options) {
let canApply = li => canvas.tokens.controlled.length && li.find(".mournblade-cyd2-roll").length
let canApply = li => {
const el = li instanceof HTMLElement ? li : li[0];
return canvas.tokens.controlled.length && el.querySelector(".mournblade-cyd2-roll");
}
let getActor = function (li) {
let message = game.messages.get($(li).attr("data-message-id"))
const el = li instanceof HTMLElement ? li : li[0];
let message = game.messages.get(el.dataset.messageId)
let rollData = message.getFlag("world", "mournblade-cyd2-roll")
return MournbladeCYD2Utility.getActorFromRollData(rollData)
}
let getRollData = function (li) {
let message = game.messages.get($(li).attr("data-message-id"))
const el = li instanceof HTMLElement ? li : li[0];
let message = game.messages.get(el.dataset.messageId)
return message.getFlag("world", "mournblade-cyd2-roll")
}
let canApplyBA = function (li) {
@@ -884,7 +913,7 @@ export class MournbladeCYD2Utility {
/* -------------------------------------------- */
static async confirmDelete(actorSheet, li) {
let itemId = li.data("item-id");
let itemId = li.dataset?.itemId ?? li.dataset?.["item-id"];
let msgTxt = "<p>Etes vous certain de vouloir supprimer cet item ?";
let buttons = {
delete: {
@@ -892,7 +921,7 @@ export class MournbladeCYD2Utility {
label: "Oui !",
callback: () => {
actorSheet.actor.deleteEmbeddedDocuments("Item", [itemId]);
li.slideUp(200, () => actorSheet.render(false));
actorSheet.render(false);
}
},
cancel: {